diff --git a/Assets/Data/OutGame/skill_effects.csv b/Assets/Data/OutGame/skill_effects.csv index c9fd17f6..24614629 100644 --- a/Assets/Data/OutGame/skill_effects.csv +++ b/Assets/Data/OutGame/skill_effects.csv @@ -4,7 +4,7 @@ liubei_a,counter_taken_pct,,,1,-1,,,1턴 반격 안 받음,받는 반격 피해 liubei_p,atk_pct,camp:shu,,0,0.2,,,,공격력 증가 · 대상: 촉 진영 유닛,공격력 +비율(0.2 = +20 %),, liubei_p,revive,,,0,1.0,1,0,HP 비율·횟수(전투당)·조건 HP 비율,쓰러지면 부활,부활 HP 비율(1.0 = 100 %),전투당 횟수,맞기 전 HP 가 이 비율 이상일 때만(0 = 조건 없음) guanyu_a,aoe_strike,,,0,3,2.5,1,반경·공격 배율·밀기,자신 주위 적 전원 공격·밀침,반경,피해 = 공격력 × 배수(0 = 피해 없음),바깥으로 밀기 거리 -guanyu_a,hit_bleed,,,0,2,0.5,1,턴(기본값)·이동 비례·확률,명중한 적 출혈(움직인 거리에 비례해 생명력 감소),출혈 턴,슬링 최대 거리만큼 움직일 때 최대 HP × 비율,확률 +guanyu_a,hit_bleed,,,0,1,0.5,1,턴(미기재 → 1 · PD 결정 ④)·이동 비례·확률,명중한 적 출혈(움직인 거리에 비례해 생명력 감소),출혈 턴,슬링 최대 거리만큼 움직일 때 최대 HP × 비율,확률 guanyu_p,counter_dmg_pct,camp:shu,,0,0.5,,,,주는 반격 피해 증가 · 대상: 촉 진영 유닛,반격 피해 +비율(0.5 = +50 % · 1.0 = 2배),, guanyu_p,counter_taken_pct,,,0,-1,,,,받는 반격 피해 증감,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, guanyu_p,kill_stack_atk,,,0,0.1,1.0,,처치당·최대,적 처치마다 공격력 누적(전투 동안),처치 1기당 공격 +비율,최대 누적 비율, @@ -18,7 +18,7 @@ zhaoyun_a,sling_dist_pct,,,0,1.0,,,,이동(슬링) 거리 증가,이동 거리 + zhaoyun_a,dmg_pct,,,0,0.5,,,,주는 피해 증가,피해 +비율(0.5 = +50 %),, zhaoyun_p,counter_taken_pct,,,0,-1,,,,받는 반격 피해 증감,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, zhaoyun_p,return_on_hit,,,0,1,0,,복귀 중 피해·쓸어 감,피해를 입히면 출발 위치로 복귀,1 = 복귀하며 경로 위 적에게도 피해,1 = 복귀 경로의 유닛을 함께 쓸어 감, -huangzhong_a,shot_giant,,,0,0.5,5.0,,화살 반지름(기본값)·공격 배율 · 사거리 무관,사거리 무관 거대 화살 — 첫 적에게 큰 피해,화살 반지름,피해 = 공격력 × 배수, +huangzhong_a,shot_giant,,,0,0.5,5.0,,화살 반지름(PD 확정)·공격 배율 · 사거리 무관,사거리 무관 거대 화살 — 첫 적에게 큰 피해,화살 반지름,피해 = 공격력 × 배수, huangzhong_a,hit_stun,,,0,1,,,,명중한 적 기절(다음 자기 턴 행동 불가),기절 턴,, huangzhong_p,arrow_pass_allies,,,0,1,1,,p2 1 = 장애물도 통과,화살이 아군을 통과,1 = 켬,1 = 장애물도 통과, huangzhong_p,crit_chance,,,0,0.2,,,,치명타 확률 증가,확률 +(0.2 = +20 %p),, @@ -35,7 +35,7 @@ guanping_a,guard_radius_mult,,,2,2,,,,호위·반격 반경 배율 · 2턴 지 guanping_a,guard_dr,,,2,-0.5,,,,호위로 대신 받는 피해 감소 · 2턴 지속,받는 비율(−0.5 = 반감),, guanping_p,counter_dmg_pct,,,0,0.5,,,,주는 반격 피해 증가,반격 피해 +비율(0.5 = +50 % · 1.0 = 2배),, guanping_p,guard,,,0,2,1.0,,반경·대신 받는 비율,호위 — 반경 안 아군 피해를 대신 받음,호위 반경,대신 받는 비율(1.0 = 전부), -xushu_a,shot_blast,,,0,1.5,2.5,,폭발 반경(기본값 = 책사 광역)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, +xushu_a,shot_blast,,,0,1.5,2.5,,폭발 반경(PD 확정 · 책사 광역과 같게)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, xushu_a,hit_burn,,,0,3,0.05,1,,명중한 적 화상(불태우기 · 턴 시작마다 생명력 감소),화상 턴,1회 최대 HP × 비율,확률 xushu_p,range_mult,,,0,1.5,,,,공격 사거리 배율,사거리 ×배율(1.5 = +50 %),, xushu_p,splash_ally_ratio,,,0,0,,,,자신의 광역이 아군에게 주는 피해 비율,아군 피해 비율(0 = 아군 피해 없음),, @@ -58,7 +58,7 @@ pangtong_p,turn_end_cleanse,,,0,3,1,,반경·인원,턴 종료 시 주위 아군 jiangwei_a,heal_self_pct,,,0,0.5,,,,자신 생명력 회복,최대 HP × 비율,, jiangwei_a,guard_radius_mult,,,3,1.5,,,,호위·반격 반경 배율 · 3턴 지속,반경 ×배율,, jiangwei_p,counter_dmg_pct,,,0,0.5,,,,주는 반격 피해 증가,반격 피해 +비율(0.5 = +50 % · 1.0 = 2배),, -jiangwei_p,guard_counter,,,0,2,1.0,,반격 범위(기본값 = 관평 호위 2)·대신 받는 비율,호위 반격 — 반경 안 아군 피해를 대신 받고 공격자에게 반격,반격(호위) 반경,대신 받는 비율, +jiangwei_p,guard_counter,,,0,2,1.0,,반격 범위(PD 확정 · 관평 호위 2)·대신 받는 비율,호위 반격 — 반경 안 아군 피해를 대신 받고 공격자에게 반격,반격(호위) 반경,대신 받는 비율, liufeng_a,atk_ratio,,,0,1.85,,,,이 공격의 피해 = 공격력의 배수,공격력 배수(1.8 = 180 %),, liufeng_a,hit_confuse,,,0,1,0.5,1,턴·이동 배율·확률,명중한 적 혼란(이동 거리 감소),혼란 턴,이동 거리 배율(0.5 = 반감),확률 liufeng_p,counter_taken_pct,,vs_confused,0,-1,,,,받는 반격 피해 증감 · 조건: 상대가 혼란일 때,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, @@ -67,7 +67,7 @@ jianyong_a,ally_hit_heal,,,0,0.8,,,,자신의 공격이 아군에 맞으면 피 jianyong_a,hit_stun,,,0,1,,,,명중한 적 기절(다음 자기 턴 행동 불가),기절 턴,, jianyong_p,heal_cleanse,,,0,1,,,,자신이 회복시킨 대상의 상태 이상 제거,1 = 켬,, jianyong_p,on_attacked_stun,,,0,1,3,,기절 턴·재충전 턴,자신을 공격한 대상 기절(재충전),기절 턴,재충전 턴, -sunqian_a,splash_heal,,,0,0.6,,,명중 대상 주위 광역 = 회복(적 포함),책사 광역이 피해 대신 회복(적 포함),회복 = 공격력 × 배수,, +sunqian_a,splash_heal,,,0,0.6,,,명중 대상 포함 범위 안 전원 회복(적 포함) · 피해 없음(PD 결정 ⑧),책사 사격이 피해 없이 명중 대상 포함 범위 안 전원 회복(적 포함),회복 = 공격력 × 배수,, sunqian_p,sling_dist_pct,radius:3,,0,0.3,,,,이동(슬링) 거리 증가 · 대상: 자신 주위 3 안 아군,이동 거리 +비율(1.0 = 2배),, mizhu_a,sling_dist_pct,range,,1,0.5,,,,이동(슬링) 거리 증가 · 대상: 시전 순간 행동 반경 안 아군 · 1턴 지속,이동 거리 +비율(1.0 = 2배),, mizhu_a,counter_taken_pct,range,,1,-0.5,,,,받는 반격 피해 증감 · 대상: 시전 순간 행동 반경 안 아군 · 1턴 지속,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, @@ -91,7 +91,7 @@ zhangliao_a,drag_back,,,0,1,,,명중 적을 출발 위치로 끌고 옴,관통 zhangliao_a,hit_confuse,,,0,1,0.5,1,,명중한 적 혼란(이동 거리 감소),혼란 턴,이동 거리 배율(0.5 = 반감),확률 zhangliao_p,atk_pct,,vs_status,0,0.5,,,,공격력 증가 · 조건: 상대가 상태 이상일 때,공격력 +비율(0.2 = +20 %),, zhangliao_p,counter_taken_pct,,vs_status,0,-1,,,,받는 반격 피해 증감 · 조건: 상대가 상태 이상일 때,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, -xuhuang_a,axe_aura,,,3,1.2,0.8,2,도끼 반경(기본값)·공격 배율·튕김 배율,주위를 도는 도끼 — 자신을 친 근접 유닛에게 반격 피해 + 그 유닛이 더 멀리 튕김 · 3턴 지속,도끼 반경,반격 피해 = 공격력 × 배수,공격자 튕김 거리 배율 +xuhuang_a,axe_aura,,,3,1.2,0.8,2,도끼 반경(PD 확정)·공격 배율·튕김 배율,주위를 도는 도끼 — 자신을 친 근접 유닛에게 반격 피해 + 그 유닛이 더 멀리 튕김 · 3턴 지속,도끼 반경,반격 피해 = 공격력 × 배수,공격자 튕김 거리 배율 xuhuang_p,hit_bleed,,,0,3,0.5,0.3,,명중한 적 출혈(움직인 거리에 비례해 생명력 감소),출혈 턴,슬링 최대 거리만큼 움직일 때 최대 HP × 비율,확률 xuhuang_p,hit_bleed,,crit,0,3,0.5,1,,명중한 적 출혈(움직인 거리에 비례해 생명력 감소) · 조건: 치명타일 때,출혈 턴,슬링 최대 거리만큼 움직일 때 최대 HP × 비율,확률 zhanghe_a,teleport,,,0,5,,,,반경 안 원하는 곳으로 이동(대상 무시 · 지점 탭),이동 반경,, @@ -110,14 +110,14 @@ simayi_a,aoe_drain,,,0,1.5,0.6,,공격 배율·피해 → 아군 회복 비율, simayi_p,splash_radius_mult,camp:wei:strategist,,0,1.5,,,,책사 광역 범위 배율 · 대상: 위 진영 책사 유닛,광역 반경 ×배율,, simayi_p,range_mult,,,0,1.5,,,,공격 사거리 배율,사거리 ×배율(1.5 = +50 %),, simayi_p,drain_aura,,,0,0.3,,,,행동 반경 안 적이 입은 피해만큼 자신 회복,그 피해 × 비율 회복,, -xiahouyuan_a,shot_fan,,,0,5,3,60,발 수·연속 횟수·부채꼴 각(기본값),부채꼴 연속 사격,한 번에 쏘는 화살 수,연속 횟수,부채꼴 전체 각도(도) -xiahouyuan_p,multishot,,,0,3,30,,발 수·부채꼴 각(기본값),일반 사격이 부채꼴 여러 발(멀티샷),화살 수,부채꼴 전체 각도(도), +xiahouyuan_a,shot_fan,,,0,5,3,60,발 수·연속 횟수·부채꼴 각(PD 확정),부채꼴 연속 사격,한 번에 쏘는 화살 수,연속 횟수,부채꼴 전체 각도(도) +xiahouyuan_p,multishot,,,0,3,30,,발 수·부채꼴 각(PD 확정),일반 사격이 부채꼴 여러 발(멀티샷),화살 수,부채꼴 전체 각도(도), guojia_a,dmg_pct,range,,2,0.3,,,,주는 피해 증가 · 대상: 시전 순간 행동 반경 안 아군 · 2턴 지속,피해 +비율(0.5 = +50 %),, guojia_a,grant_reaction,,,0,1,,,,이미 행동한 다른 아군에게 재행동 부여(없으면 다른 아군이 행동 뒤 재행동),인원,, guojia_p,kill_in_range_reward,,,0,1,0.3,,쿨 −턴·최대 HP 회복,자신의 행동 반경 안에서 적을 처치한 아군 보상,액티브 쿨 −턴,최대 HP × 비율 회복, -jiaxu_a,shot_blast,,,0,1.5,2.2,,독구름 반경(기본값)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, +jiaxu_a,shot_blast,,,0,1.5,2.2,,독구름 반경(PD 확정)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, jiaxu_a,hit_poison,,,0,5,0.02,1,,명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 -jiaxu_p,hit_poison,,,0,5,0.02,1,턴(기본값 = 독계),명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 +jiaxu_p,hit_poison,,,0,1,0.02,1,턴(미기재 → 1 · PD 결정 ④),명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 jiaxu_p,poison_stack,,,0,5,,,,중독 중첩 허용,최대 중첩,, dianwei_a,dmg_pct,,,0,1.0,,,,주는 피해 증가,피해 +비율(0.5 = +50 %),, dianwei_a,push_mult,,,0,2,,,,밀치는 거리 배율,밀기 ×배율(2 = 2배),, @@ -137,13 +137,14 @@ xiahouen_a,first_hit_bonus,,,0,0.5,,,,이 행동에서 처음 맞힌 대상에 xiahouen_p,hp_max_pct,,,0,0.1,,,,최대 생명력 증가,최대 HP +비율,, sunjian_a,atk_pct,,,0,0.5,,,,공격력 증가,공격력 +비율(0.2 = +20 %),, sunjian_a,pierce_through,,,0,1,,,1 = 아군도 통과,보병·창병도 기병처럼 적을 관통하며 경로 위 적 전원 피해,1 = 아군도 통과 · 0 = 아군 앞 정지,, -sunjian_a,hit_bleed,,,0,2,0.5,1,,명중한 적 출혈(움직인 거리에 비례해 생명력 감소),출혈 턴,슬링 최대 거리만큼 움직일 때 최대 HP × 비율,확률 +sunjian_a,hit_bleed,,,0,1,0.5,1,턴(미기재 → 1 · PD 결정 ④),명중한 적 출혈(움직인 거리에 비례해 생명력 감소),출혈 턴,슬링 최대 거리만큼 움직일 때 최대 HP × 비율,확률 sunjian_a,invuln,,,1,1,,,행동 끝 뒤 1턴 피해 무효,무적 — 모든 피해 무효(행동 중이 아닌 동안) · 1턴 지속,1 = 켬,, sunjian_p,atk_pct,camp:wu,,0,0.2,,,,공격력 증가 · 대상: 오 진영 유닛,공격력 +비율(0.2 = +20 %),, sunjian_p,kill_reaction,,,0,1,,,턴당,적 처치 시 재행동(턴당 1회),1 = 켬,, -zhouyu_a,shot_blast,,,0,2.5,3.5,,운석 반경(기본값)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, -zhouyu_a,hit_burn,,,0,3,0.05,1,,명중한 적 화상(불태우기 · 턴 시작마다 생명력 감소),화상 턴,1회 최대 HP × 비율,확률 -zhouyu_a,fire_zone,,,0,1.5,3,1.0,불꽃 반경·턴·닿을 때 공격 배율,폭발 자리에 불꽃 지대 — 닿는 적 피해 + 화상,지대 반경,유지 턴,닿을 때 피해 = 공격력 × 배수 +zhouyu_a,shot_blast,,,0,2.5,3.5,,운석 반경(PD 확정)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, +zhouyu_a,hit_burn,,,0,1,0.05,1,운석 불태우기 턴(미기재 → 1 · PD 결정 ④),명중한 적 화상(불태우기 · 턴 시작마다 생명력 감소),화상 턴,1회 최대 HP × 비율,확률 +zhouyu_a,fire_zone,,,0,1.5,1,1.0,불꽃 반경(PD 확정)·불꽃 유지 턴(미기재 → 1)·닿을 때 공격 배율,폭발 자리에 불꽃 지대 — 닿는 적 피해 + 화상,지대 반경,유지 턴,닿을 때 피해 = 공격력 × 배수 +zhouyu_a,zone_burn,,,0,3,0.05,,불꽃에 닿으면 3턴 화상(원문),지대(불꽃)에 닿으면 거는 화상(없으면 그 스킬 hit_burn),화상 턴,1회 최대 HP × 비율, zhouyu_p,skill_hp_cost,,,0,0.05,,,,액티브 스킬 시전 시 생명력 소모,최대 HP × 비율 소모(쓰러지지는 않음),, zhouyu_p,skill_power_low_hp,,,0,0.1,0.1,,HP p2 잃을 때마다 스킬 위력 +p1,생명력이 낮을수록 스킬 위력 증가,단계당 스킬 위력 +비율,단계 = 잃은 HP 비율(0.1 = 10 %마다), zhouyu_p,melee_penalty_off,,,0,1,,,,궁병·책사 근접 전투 패널티 없음,1 = 켬,, @@ -167,8 +168,8 @@ sunce_a,wall_bounce,,,0,1,,,,전장 가장자리에 닿으면 핀볼처럼 튕 sunce_p,sling_dist_pct,camp:wu,,0,0.3,,,,이동(슬링) 거리 증가 · 대상: 오 진영 유닛,이동 거리 +비율(1.0 = 2배),, sunce_p,counter_taken_pct,,,0,-1,,,,받는 반격 피해 증감,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, sunce_p,return_on_hit,,,0,0,0,,,피해를 입히면 출발 위치로 복귀,1 = 복귀하며 경로 위 적에게도 피해,1 = 복귀 경로의 유닛을 함께 쓸어 감, -sunce_p,dash_dmg_pct,,,0,1.0,,,최대(기본값 = 장비·여포),돌진(슬링) 거리에 비례해 공격력 증가,슬링 최대 거리로 당겼을 때 공격 +비율(최대),, -sunquan_a,shot_blast,,,0,1.5,1.8,,화살비 반경(기본값)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, +sunce_p,dash_dmg_pct,,,0,1.0,,,최대(PD 확정 · 장비·여포),돌진(슬링) 거리에 비례해 공격력 증가,슬링 최대 거리로 당겼을 때 공격 +비율(최대),, +sunquan_a,shot_blast,,,0,1.5,1.8,,화살비 반경(PD 확정)·공격 배율,투사체가 첫 적 자리에서 폭발 — 반경 안 적 전원 피해,폭발 반경,피해 = 공격력 × 배수, sunquan_a,hit_confuse,,,0,1,0.5,1,,명중한 적 혼란(이동 거리 감소),혼란 턴,이동 거리 배율(0.5 = 반감),확률 sunquan_p,range_mult,camp:wu:archer,,0,1.5,,,,공격 사거리 배율 · 대상: 오 진영 궁병 유닛,사거리 ×배율(1.5 = +50 %),, sunquan_p,arrow_pass_allies,,,0,1,0,,,화살이 아군을 통과,1 = 켬,1 = 장애물도 통과, @@ -181,11 +182,12 @@ lvmeng_a,reaction_on_hit,,,0,1,3,,재행동·최대,이 행동으로 적에게 lvmeng_a,reaction_on_kill,,,0,1,3,,,이 행동으로 적을 처치하면 재행동(연쇄),처치 시 재행동 수,연쇄 최대 재행동, lvmeng_p,counter_taken_pct,,,0,-0.3,,,,받는 반격 피해 증감,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, lvmeng_p,reaction_atk_stack,,,0,0.2,,,,이번 턴 재행동할 때마다 공격력 증가(2배씩 · 턴마다 초기화),첫 재행동 공격 +비율(다음은 2배 · 4배),, -luxun_a,shot_firewall,,,0,0.6,3,3.0,장벽 반폭(기본값)·턴·닿을 때 공격 배율,진행 방향 불 장벽(지대) — 닿는 적 피해 + 화상,장벽 반폭,유지 턴,닿을 때 피해 = 공격력 × 배수 +luxun_a,shot_firewall,,,0,0.6,3,3.0,장벽 반폭(PD 확정)·턴·닿을 때 공격 배율,진행 방향 불 장벽(지대) — 닿는 적 피해 + 화상,장벽 반폭,유지 턴,닿을 때 피해 = 공격력 × 배수 luxun_a,hit_burn,,,0,3,0.05,1,,명중한 적 화상(불태우기 · 턴 시작마다 생명력 감소),화상 턴,1회 최대 HP × 비율,확률 +luxun_a,zone_hits_allies,,,0,1,,,아군도 피해(PD 결정 ⑬),지대·장벽이 아군에게도 피해·화상,1 = 켬,, luxun_p,dmg_pct,camp:wu,vs_status,0,0.5,,,,주는 피해 증가 · 대상: 오 진영 유닛 · 조건: 상대가 상태 이상일 때,피해 +비율(0.5 = +50 %),, luxun_p,hit_confuse,,,0,1,0.5,1,,명중한 적 혼란(이동 거리 감소),혼란 턴,이동 거리 배율(0.5 = 반감),확률 -sunshangxiang_a,volley,,,0,1.0,1.0,,공격 배율(기본값)·밀기(기본값),사거리 안 적 전원에게 화살 — 피해·밀침(치명타 판정),피해 = 공격력 × 배수,밀기 거리, +sunshangxiang_a,volley,,,0,1.0,1.0,,공격 배율(PD 확정)·밀기(PD 확정),사거리 안 적 전원에게 화살 — 피해·밀침(치명타 판정),피해 = 공격력 × 배수,밀기 거리, sunshangxiang_a,hit_bleed,,crit,0,2,0.5,1,,명중한 적 출혈(움직인 거리에 비례해 생명력 감소) · 조건: 치명타일 때,출혈 턴,슬링 최대 거리만큼 움직일 때 최대 HP × 비율,확률 sunshangxiang_p,dmg_pct,,vs_male_hero,0,0.5,,,,주는 피해 증가 · 조건: 상대가 남성 영웅일 때,피해 +비율(0.5 = +50 %),, sunshangxiang_p,melee_penalty_off,,,0,1,,,,궁병·책사 근접 전투 패널티 없음,1 = 켬,, @@ -196,10 +198,10 @@ xiaoqiao_p,ally_hit_heal,,,0,0.5,,,,자신의 공격이 아군에 맞으면 피 lingtong_a,aoe_strike,,,0,3,1.5,1,,자신 주위 적 전원 공격·밀침,반경,피해 = 공격력 × 배수(0 = 피해 없음),바깥으로 밀기 거리 lingtong_p,atk_pct,,,0,0.15,,,,공격력 증가,공격력 +비율(0.2 = +20 %),, lingtong_p,push_mult,,,0,1.3,,,,밀치는 거리 배율,밀기 ×배율(2 = 2배),, -zhoutai_a,shot_pierce,,,0,1.8,1,1.0,검기 · 아군도 피해 · 밀기(기본값),직선 관통 사격 — 경로 위 유닛 전원(장애물 무시),피해 = 공격력 × 배수,아군 처리(0 통과 · 1 피해 · 2 회복),밀기 거리(0 = 없음) +zhoutai_a,shot_pierce,,,0,1.8,1,1.0,검기 · 아군도 피해 · 밀기(PD 확정),직선 관통 사격 — 경로 위 유닛 전원(장애물 무시),피해 = 공격력 × 배수,아군 처리(0 통과 · 1 피해 · 2 회복),밀기 거리(0 = 없음) zhoutai_p,hit_confuse,,crit,0,1,0.5,1,,명중한 적 혼란(이동 거리 감소) · 조건: 치명타일 때,혼란 턴,이동 거리 배율(0.5 = 반감),확률 zhoutai_p,crit_always,,vs_type:spear,0,1,,,,무조건 치명타 · 조건: 상대가 창병일 때,1 = 켬,, -zhugejin_a,shot_whirl,,,0,1.0,3.0,0,회오리 반폭(기본값)·밀기(기본값)·공격 배율(피해 없음),회오리 — 직선 위 적을 진행 방향으로 크게 밀침,회오리 반폭,밀기 거리,피해 = 공격력 × 배수(0 = 없음) +zhugejin_a,shot_whirl,,,0,1.0,3.0,1.0,회오리 반폭·밀기(PD 확정)·공격 배율(PD 결정 ⑭ = 100 %),회오리 — 직선 위 적을 진행 방향으로 크게 밀침,회오리 반폭,밀기 거리,피해 = 공격력 × 배수(0 = 없음) zhugejin_a,hit_confuse,,,0,1,0.5,1,,명중한 적 혼란(이동 거리 감소),혼란 턴,이동 거리 배율(0.5 = 반감),확률 zhugejin_p,splash_ally_ratio,,,0,0,,,,자신의 광역이 아군에게 주는 피해 비율,아군 피해 비율(0 = 아군 피해 없음),, dongxi_a,atk_ratio,,,0,1.5,,,,이 공격의 피해 = 공격력의 배수,공격력 배수(1.8 = 180 %),, @@ -214,7 +216,7 @@ lvbu_p,matchup_floor,,,0,1.0,,,,상성 무시(불리한 상성만 무시 · 유 lvbu_p,dash_dmg_pct,,,0,1.0,,,,돌진(슬링) 거리에 비례해 공격력 증가,슬링 최대 거리로 당겼을 때 공격 +비율(최대),, zhangjiao_a,invuln,,,1,1,,,,무적 — 모든 피해 무효(행동 중이 아닌 동안) · 1턴 지속,1 = 켬,, zhangjiao_p,dmg_taken_from_archer_pct,,,0,-0.3,,,,적 궁병에게 받는 피해 증감,받는 피해 비율(−0.3 = 30 % 감소),, -zhangjiao_p,hit_poison,,,0,5,0.02,0.5,턴(기본값)·확률,명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 +zhangjiao_p,hit_poison,,,0,1,0.02,0.5,턴(미기재 → 1 · PD 결정 ④)·확률,명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 huaxiong_a,dmg_pct,,,0,1.0,,,,주는 피해 증가,피해 +비율(0.5 = +50 %),, huaxiong_a,counter_taken_pct,,,0,-1,,,,받는 반격 피해 증감,받는 반격 비율(−1 = 반격 안 받음 · −0.5 = 반감),, huaxiong_p,atk_pct,,turn_le:3,0,0.5,,,,공격력 증가 · 조건: 전투 3턴까지,공격력 +비율(0.2 = +20 %),, @@ -231,11 +233,11 @@ gongsunzan_a,lifesteal,,,0,0.5,,,,입힌 피해만큼 회복(흡혈),입힌 피 gongsunzan_a,return_always,,,0,0,,,,공격 후 항상 출발 위치로 복귀,1 = 복귀하며 경로 위 적에게도 피해,, gongsunzan_p,dmg_pct,,vs_type:archer,0,1.0,,,,주는 피해 증가 · 조건: 상대가 궁병일 때,피해 +비율(0.5 = +50 %),, gongsunzan_p,heal_on_kill,,,0,0.3,,,,적 처치 시 생명력 회복,최대 HP × 비율 회복,, -dongzhuo_a,rampage,,,0,3,1.5,,돌진 초·밀치기 거리(기본값),일정 시간 직진 난동 — 닿는 유닛 전원 밀침(적 = 피해) · 가장자리 튕김 · 자신은 튕기지 않음,돌진 시간(초 · 이동 속도 × 초 = 거리),옆으로 밀치는 거리, +dongzhuo_a,rampage,,,0,3,1.5,,돌진 초·밀치기 거리(PD 확정),일정 시간 직진 난동 — 닿는 유닛 전원 밀침(적 = 피해) · 가장자리 튕김 · 자신은 튕기지 않음,돌진 시간(초 · 이동 속도 × 초 = 거리),옆으로 밀치는 거리, dongzhuo_p,dmg_taken_pct,camp:other,,0,-0.1,,,,받는 피해 증감 · 대상: 군웅 진영 유닛,받는 피해 비율(−0.3 = 30 % 감소 · +0.15 = 15 % 증가),, dongzhuo_p,lifesteal,,,0,0.3,0.05,,p2 = 아군 1기 줄 때마다 +,입힌 피해만큼 회복(흡혈),입힌 피해 × 비율 회복,아군 1기 줄 때마다 비율 +, -lijue_a,splash_heal_lowest,,,0,0.5,2,,광역 피해 비율·인접 반경(기본값),광역으로 준 피해만큼 인접한 가장 약한 아군 회복,광역 피해 × 비율 회복,인접 반경, -lijue_p,action_end_sacrifice,,,0,0.1,0.5,2,HP 소모·공격 %·인접 반경(기본값),행동 끝 = 생명력 소모 후 인접 아군 공격력 강화(대상 없으면 발동 안 함),HP 소모 비율(HP 10 % 이하면 소모 없이),인접 아군 공격 +비율(1턴),인접 반경 +lijue_a,splash_heal_lowest,,,0,0.5,2,,광역 피해 비율·인접 반경(PD 확정),광역으로 준 피해만큼 인접한 가장 약한 아군 회복,광역 피해 × 비율 회복,인접 반경, +lijue_p,action_end_sacrifice,,,0,0.1,0.5,2,HP 소모·공격 %·인접 반경(PD 확정),행동 끝 = 생명력 소모 후 인접 아군 공격력 강화(대상 없으면 발동 안 함),HP 소모 비율(HP 10 % 이하면 소모 없이),인접 아군 공격 +비율(1턴),인접 반경 yuanshao_a,sling_dist_pct,range,,1,0.5,,,,이동(슬링) 거리 증가 · 대상: 시전 순간 행동 반경 안 아군 · 1턴 지속,이동 거리 +비율(1.0 = 2배),, yuanshao_a,crit_dmg_pct,range,,1,0.5,,,,치명타 피해량 증가 · 대상: 시전 순간 행동 반경 안 아군 · 1턴 지속,치명타 피해 +비율(0.5 = +50 %),, yuanshao_a,crit_chance,range,,1,0.2,,,,치명타 확률 증가 · 대상: 시전 순간 행동 반경 안 아군 · 1턴 지속,확률 +(0.2 = +20 %p),, @@ -253,7 +255,7 @@ diaochan_p,multi_male_stun,,,0,2,0.5,1,남성 수·확률·턴,한 행동으로 diaochan_p,dmg_taken_pct,,vs_male,0,-0.3,,,,받는 피해 증감 · 조건: 상대가 남성일 때,받는 피해 비율(−0.3 = 30 % 감소 · +0.15 = 15 % 증가),, zhurong_a,shot_as_archer,,,0,1,,,,근접 병종이 궁병처럼 원거리 사격,1 = 켬,, zhurong_a,atk_ratio,,,0,2.2,,,,이 공격의 피해 = 공격력의 배수,공격력 배수(1.8 = 180 %),, -zhurong_a,hit_poison,,,0,5,0.02,1,,명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 +zhurong_a,hit_poison,,,0,1,0.02,1,턴(미기재 → 1 · PD 결정 ④),명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 zhurong_p,lifesteal,,,0,0.2,,,,입힌 피해만큼 회복(흡혈),입힌 피해 × 비율 회복,, zhurong_p,counter_dmg_pct,,,0,0.5,,,,주는 반격 피해 증가,반격 피해 +비율(0.5 = +50 % · 1.0 = 2배),, zhurong_p,terrain_immune,,,0,1,,,,지형(늪·고지) 이동 감소 무시,1 = 켬,, @@ -267,8 +269,8 @@ gaoshun_a,hit_stun,,,0,1,1,1,p2 1 = 밀린 아군·지형 피해도,명중한 gaoshun_p,push_continue,,,0,1,,,,아군·지형 오브젝트를 밀친 뒤 남은 이동 거리로 재행동,1 = 켬,, zhanglu_a,shot_single,,,0,1,,,,책사 사격이 광역 없는 직선 투사체,1 = 켬,, zhanglu_a,atk_ratio,,,0,2.5,,,,이 공격의 피해 = 공격력의 배수,공격력 배수(1.8 = 180 %),, -zhanglu_a,hit_poison,,,0,5,0.02,1,,명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 -zhanglu_a,poison_zone,,,0,1.0,1,,반경(기본값)·턴,명중 자리에 독 지대 — 닿는 적 중독,지대 반경,유지 턴, +zhanglu_a,hit_poison,,,0,1,0.02,1,턴(미기재 → 1 · PD 결정 ④),명중한 적 중독(턴 시작·행동 끝마다 생명력 감소),중독 턴,1회 최대 HP × 비율(중첩 수만큼 곱),확률 +zhanglu_a,poison_zone,,,0,1.0,1,,반경(PD 확정)·턴,명중 자리에 독 지대 — 닿는 적 중독,지대 반경,유지 턴, zhanglu_p,zombie,,,0,1,,,되살린 HP,처치한 적이 같은 편 망령으로 되살아나 1번 공격(조작 불가 · 다음 턴 소멸),망령 HP,, yanbaihu_a,atk_pct,,,0,0.3,,,,공격력 증가,공격력 +비율(0.2 = +20 %),, yanbaihu_a,crit_chance,,,0,0.15,,,,치명타 확률 증가,확률 +(0.2 = +20 %p),, diff --git a/Assets/Data/OutGame/skills.csv b/Assets/Data/OutGame/skills.csv index df5e0c64..cfd35500 100644 --- a/Assets/Data/OutGame/skills.csv +++ b/Assets/Data/OutGame/skills.csv @@ -71,7 +71,7 @@ xiahouen_a,xiahouen,active,청강검 발도,靑釭劍拔刀,next_action,first_hi xiahouen_p,xiahouen,passive,보검의 광채,,always,hp_max_pct,,,,0,5,0.1,최대 생명력 +10%,0 sunjian_a,sunjian,active,강동의 호랑이,,next_action,atk_pct;pierce_through;hit_bleed;invuln,,,,3,5,0.1,다음 행동 시 공격력이 50% 증가하고 · 모든 유닛을 통과하며 공격할 수 있으며 경로 상 피격 된 모든 적에게 출혈 피해를 입힘 · 행동 종료 후 1턴간 모든 피해를 무효화함(튕겨질 순 있고 · 반격 피해는 입힐 수 있음),0 sunjian_p,sunjian,passive,파로,破虜,always,atk_pct;kill_reaction,,,,0,5,0.1,모든 오군 진영 공격력 +20% 증가하고 · 자신의 공격으로 적을 처치할 경우 재행동 기회 1회 부여(턴 당 1회),0 -zhouyu_a,zhouyu,active,적벽의 불비,赤壁火雨,next_action,shot_blast;hit_burn;fire_zone,,,,4,5,0.1,다음 행동 시 명중한 대상 주위에 운석을 소환해 넓은 범위에 공격력의 350%의 피해를 입히고 · 피격 된 대상을 불태우기 상태에 빠뜨리며 · 운석이 낙하한 장소에 불꽃을 생성(닿는 적에게 즉시 공격력의 100%의 피해를 입히고 · 3턴간 유지되는 화상 효과를 입힘),0 +zhouyu_a,zhouyu,active,적벽의 불비,赤壁火雨,next_action,shot_blast;hit_burn;fire_zone;zone_burn,,,,4,5,0.1,다음 행동 시 명중한 대상 주위에 운석을 소환해 넓은 범위에 공격력의 350%의 피해를 입히고 · 피격 된 대상을 불태우기 상태에 빠뜨리며 · 운석이 낙하한 장소에 불꽃을 생성(닿는 적에게 즉시 공격력의 100%의 피해를 입히고 · 3턴간 유지되는 화상 효과를 입힘),0 zhouyu_p,zhouyu,passive,대도독,大都督,always,skill_hp_cost;skill_power_low_hp;melee_penalty_off;range_mult,,,,0,5,0.1,스킬 시전 시 생명력이 5% 감소하지만 · 생명이 낮아질 때마다 스킬의 위력이 10%씩 증가하며 · 자신은 근접 유닛과의 전투에 패널티를 받지 않고 · 스킬 사거리가 50% 증가,0 huanggai_a,huanggai,active,고육계,苦肉計,instant,dmg_taken_pct;damage_to_atk;heal_on_kill,,,,3,5,0.1,즉시: 1턴간 자신의 받는 피해가 30% 감소되며 · 자신이 이번 턴에 받은 피해가 다음 턴의 공격력에 추가되며 · 적을 처치한 경우 생명력 100% 회복,0 huanggai_p,huanggai,passive,노장,老將,always,dmg_taken_pct;low_hp_taken,,,,0,5,0.1,자신의 받는 피해 -15 % · 생명력이 낮아질수록 받는 피해가 0.2%씩 증가하고 반격 피해가 1%씩 증가,0 @@ -87,7 +87,7 @@ lusu_a,lusu,active,녹각진,鹿角陣,next_action,shot_barricade,,,,3,5,0.1,다 lusu_p,lusu,passive,동맹의 깃발,同盟之旗,always,atk_per_ally_range;turn_start_heal_range;death_banner,,,,0,5,0.1,자신의 행동 범위 내 아군 1기당 공격력이 5%씩 증가하고 · 매턴 시작 시 행동 범위 내 아군의 생명력을 10% 회복시킬 수 있으며 · 사망할 경우 쓰러진 장소에 5턴간 효과를 유지하는 깃발을 남겨 자신의 패시브 효과를 전장에 남김,0 lvmeng_a,lvmeng,active,백의도강,白衣渡江,next_action,reaction_on_hit;reaction_on_kill,,,,4,5,0.1,다음 행동으로 적에게 피해를 입힌 경우 · 한번 더 행동할 수 있으며 적을 처치한 경우 한번 더 행동 가능(최대 3회),0 lvmeng_p,lvmeng,passive,괄목상대,刮目相對,always,counter_taken_pct;reaction_atk_stack,,,,0,5,0.1,반격 피해를 30% 반감하며 · 매턴 재행동이 발생할 때마다 추가 공격력이 20% 부여되며 · 추가 공격력은 재행동 횟수에 비례해 2배씩 증가(20%→40%→80%) (추가 공격력은 턴마다 초기화),0 -luxun_a,luxun,active,이릉의 화공,夷陵火攻,next_action,shot_firewall;hit_burn,,,,4,5,0.1,다음 행동으로 지정한 방향으로 모든 유닛에게 피해를 입히는 불 장벽을 생성해 3턴간 전장에 유지되며 · 닿는 적에게는 즉시 300%의 피해를 입히고 · 3턴간 화상 효과를 입힘,0 +luxun_a,luxun,active,이릉의 화공,夷陵火攻,next_action,shot_firewall;hit_burn;zone_hits_allies,,,,4,5,0.1,다음 행동으로 지정한 방향으로 모든 유닛에게 피해를 입히는 불 장벽을 생성해 3턴간 전장에 유지되며 · 닿는 적에게는 즉시 300%의 피해를 입히고 · 3턴간 화상 효과를 입힘,0 luxun_p,luxun,passive,백면서생,白面書生,always,dmg_pct;hit_confuse,,,,0,5,0.1,모든 오군이 상태이상 효과에 걸린 적 공격 시 피해량이 50% 증가하며 · 자신의 공격에 피격 된 대상은 1턴간 혼란에 빠뜨림 (혼란 : 이동 속도 50% 감소),0 sunshangxiang_a,sunshangxiang,active,궁요희,弓腰姬,instant,volley;hit_bleed,,,,3,5,0.1,즉시: 행동 범위 내 모든 적에게 화살을 발사해 피해를 입히고 · 밀쳐내며 치명타 발생 시 2턴간 출혈 효과를 유발함,0 sunshangxiang_p,sunshangxiang,passive,효희,梟姬,always,dmg_pct;melee_penalty_off,,,,0,5,0.1,남성 영웅에 대한 피해량이 50% 증가하고 · 근접 피해 패널티를 받지 않음.(반격 피해에도 피해량 50% 증가 적용),0 diff --git a/Assets/Resources/OutGame/SkillInfoDb.asset b/Assets/Resources/OutGame/SkillInfoDb.asset index ee988c08..ffa11071 100644 --- a/Assets/Resources/OutGame/SkillInfoDb.asset +++ b/Assets/Resources/OutGame/SkillInfoDb.asset @@ -1380,7 +1380,7 @@ MonoBehaviour: \uC801\uC5D0\uAC8C \uC989\uC2DC \uACF5\uACA9\uB825\uC758 100%\uC758 \uD53C\uD574\uB97C \uC785\uD788\uACE0 \xB7 3\uD134\uAC04 \uC720\uC9C0\uB418\uB294 \uD654\uC0C1 \uD6A8\uACFC\uB97C \uC785\uD798)" - effectKey: shot_blast;hit_burn;fire_zone + effectKey: shot_blast;hit_burn;fire_zone;zone_burn p1: 0 p2: 0 p3: 0 @@ -1699,7 +1699,7 @@ MonoBehaviour: \uC720\uC9C0\uB418\uBA70 \xB7 \uB2FF\uB294 \uC801\uC5D0\uAC8C\uB294 \uC989\uC2DC 300%\uC758 \uD53C\uD574\uB97C \uC785\uD788\uACE0 \xB7 3\uD134\uAC04 \uD654\uC0C1 \uD6A8\uACFC\uB97C \uC785\uD798" - effectKey: shot_firewall;hit_burn + effectKey: shot_firewall;hit_burn;zone_hits_allies p1: 0 p2: 0 p3: 0 @@ -2791,11 +2791,12 @@ MonoBehaviour: target: cond: dur: 0 - p1: 2 + p1: 1 p2: 0.5 p3: 1 pMask: 7 - note: "\uD134(\uAE30\uBCF8\uAC12)\xB7\uC774\uB3D9 \uBE44\uB840\xB7\uD655\uB960" + note: "\uD134(\uBBF8\uAE30\uC7AC \u2192 1 \xB7 PD \uACB0\uC815 \u2463)\xB7\uC774\uB3D9 + \uBE44\uB840\xB7\uD655\uB960" - skillId: guanyu_p key: counter_dmg_pct target: camp:shu @@ -2935,7 +2936,7 @@ MonoBehaviour: p2: 5 p3: 0 pMask: 3 - note: "\uD654\uC0B4 \uBC18\uC9C0\uB984(\uAE30\uBCF8\uAC12)\xB7\uACF5\uACA9 \uBC30\uC728 + note: "\uD654\uC0B4 \uBC18\uC9C0\uB984(PD \uD655\uC815)\xB7\uACF5\uACA9 \uBC30\uC728 \xB7 \uC0AC\uAC70\uB9AC \uBB34\uAD00" - skillId: huangzhong_a key: hit_stun @@ -3106,8 +3107,8 @@ MonoBehaviour: p2: 2.5 p3: 0 pMask: 3 - note: "\uD3ED\uBC1C \uBC18\uACBD(\uAE30\uBCF8\uAC12 = \uCC45\uC0AC \uAD11\uC5ED)\xB7\uACF5\uACA9 - \uBC30\uC728" + note: "\uD3ED\uBC1C \uBC18\uACBD(PD \uD655\uC815 \xB7 \uCC45\uC0AC \uAD11\uC5ED\uACFC + \uAC19\uAC8C)\xB7\uACF5\uACA9 \uBC30\uC728" - skillId: xushu_a key: hit_burn target: @@ -3338,7 +3339,7 @@ MonoBehaviour: p2: 1 p3: 0 pMask: 3 - note: "\uBC18\uACA9 \uBC94\uC704(\uAE30\uBCF8\uAC12 = \uAD00\uD3C9 \uD638\uC704 + note: "\uBC18\uACA9 \uBC94\uC704(PD \uD655\uC815 \xB7 \uAD00\uD3C9 \uD638\uC704 2)\xB7\uB300\uC2E0 \uBC1B\uB294 \uBE44\uC728" - skillId: liufeng_a key: atk_ratio @@ -3429,8 +3430,9 @@ MonoBehaviour: p2: 0 p3: 0 pMask: 1 - note: "\uBA85\uC911 \uB300\uC0C1 \uC8FC\uC704 \uAD11\uC5ED = \uD68C\uBCF5(\uC801 - \uD3EC\uD568)" + note: "\uBA85\uC911 \uB300\uC0C1 \uD3EC\uD568 \uBC94\uC704 \uC548 \uC804\uC6D0 + \uD68C\uBCF5(\uC801 \uD3EC\uD568) \xB7 \uD53C\uD574 \uC5C6\uC74C(PD \uACB0\uC815 + \u2467)" - skillId: sunqian_p key: sling_dist_pct target: radius:3 @@ -3672,7 +3674,7 @@ MonoBehaviour: p2: 0.8 p3: 2 pMask: 7 - note: "\uB3C4\uB07C \uBC18\uACBD(\uAE30\uBCF8\uAC12)\xB7\uACF5\uACA9 \uBC30\uC728\xB7\uD295\uAE40 + note: "\uB3C4\uB07C \uBC18\uACBD(PD \uD655\uC815)\xB7\uACF5\uACA9 \uBC30\uC728\xB7\uD295\uAE40 \uBC30\uC728" - skillId: xuhuang_p key: hit_bleed @@ -3865,7 +3867,8 @@ MonoBehaviour: p2: 3 p3: 60 pMask: 7 - note: "\uBC1C \uC218\xB7\uC5F0\uC18D \uD69F\uC218\xB7\uBD80\uCC44\uAF34 \uAC01(\uAE30\uBCF8\uAC12)" + note: "\uBC1C \uC218\xB7\uC5F0\uC18D \uD69F\uC218\xB7\uBD80\uCC44\uAF34 \uAC01(PD + \uD655\uC815)" - skillId: xiahouyuan_p key: multishot target: @@ -3875,7 +3878,7 @@ MonoBehaviour: p2: 30 p3: 0 pMask: 3 - note: "\uBC1C \uC218\xB7\uBD80\uCC44\uAF34 \uAC01(\uAE30\uBCF8\uAC12)" + note: "\uBC1C \uC218\xB7\uBD80\uCC44\uAF34 \uAC01(PD \uD655\uC815)" - skillId: guojia_a key: dmg_pct target: range @@ -3915,7 +3918,7 @@ MonoBehaviour: p2: 2.2 p3: 0 pMask: 3 - note: "\uB3C5\uAD6C\uB984 \uBC18\uACBD(\uAE30\uBCF8\uAC12)\xB7\uACF5\uACA9 \uBC30\uC728" + note: "\uB3C5\uAD6C\uB984 \uBC18\uACBD(PD \uD655\uC815)\xB7\uACF5\uACA9 \uBC30\uC728" - skillId: jiaxu_a key: hit_poison target: @@ -3931,11 +3934,11 @@ MonoBehaviour: target: cond: dur: 0 - p1: 5 + p1: 1 p2: 0.02 p3: 1 pMask: 7 - note: "\uD134(\uAE30\uBCF8\uAC12 = \uB3C5\uACC4)" + note: "\uD134(\uBBF8\uAE30\uC7AC \u2192 1 \xB7 PD \uACB0\uC815 \u2463)" - skillId: jiaxu_p key: poison_stack target: @@ -4132,11 +4135,11 @@ MonoBehaviour: target: cond: dur: 0 - p1: 2 + p1: 1 p2: 0.5 p3: 1 pMask: 7 - note: + note: "\uD134(\uBBF8\uAE30\uC7AC \u2192 1 \xB7 PD \uACB0\uC815 \u2463)" - skillId: sunjian_a key: invuln target: @@ -4176,28 +4179,39 @@ MonoBehaviour: p2: 3.5 p3: 0 pMask: 3 - note: "\uC6B4\uC11D \uBC18\uACBD(\uAE30\uBCF8\uAC12)\xB7\uACF5\uACA9 \uBC30\uC728" + note: "\uC6B4\uC11D \uBC18\uACBD(PD \uD655\uC815)\xB7\uACF5\uACA9 \uBC30\uC728" - skillId: zhouyu_a key: hit_burn target: cond: dur: 0 - p1: 3 + p1: 1 p2: 0.05 p3: 1 pMask: 7 - note: + note: "\uC6B4\uC11D \uBD88\uD0DC\uC6B0\uAE30 \uD134(\uBBF8\uAE30\uC7AC \u2192 + 1 \xB7 PD \uACB0\uC815 \u2463)" - skillId: zhouyu_a key: fire_zone target: cond: dur: 0 p1: 1.5 - p2: 3 + p2: 1 p3: 1 pMask: 7 - note: "\uBD88\uAF43 \uBC18\uACBD\xB7\uD134\xB7\uB2FF\uC744 \uB54C \uACF5\uACA9 - \uBC30\uC728" + note: "\uBD88\uAF43 \uBC18\uACBD(PD \uD655\uC815)\xB7\uBD88\uAF43 \uC720\uC9C0 + \uD134(\uBBF8\uAE30\uC7AC \u2192 1)\xB7\uB2FF\uC744 \uB54C \uACF5\uACA9 \uBC30\uC728" + - skillId: zhouyu_a + key: zone_burn + target: + cond: + dur: 0 + p1: 3 + p2: 0.05 + p3: 0 + pMask: 3 + note: "\uBD88\uAF43\uC5D0 \uB2FF\uC73C\uBA74 3\uD134 \uD654\uC0C1(\uC6D0\uBB38)" - skillId: zhouyu_p key: skill_hp_cost target: @@ -4437,7 +4451,7 @@ MonoBehaviour: p2: 0 p3: 0 pMask: 1 - note: "\uCD5C\uB300(\uAE30\uBCF8\uAC12 = \uC7A5\uBE44\xB7\uC5EC\uD3EC)" + note: "\uCD5C\uB300(PD \uD655\uC815 \xB7 \uC7A5\uBE44\xB7\uC5EC\uD3EC)" - skillId: sunquan_a key: shot_blast target: @@ -4447,7 +4461,7 @@ MonoBehaviour: p2: 1.8 p3: 0 pMask: 3 - note: "\uD654\uC0B4\uBE44 \uBC18\uACBD(\uAE30\uBCF8\uAC12)\xB7\uACF5\uACA9 \uBC30\uC728" + note: "\uD654\uC0B4\uBE44 \uBC18\uACBD(PD \uD655\uC815)\xB7\uACF5\uACA9 \uBC30\uC728" - skillId: sunquan_a key: hit_confuse target: @@ -4577,8 +4591,8 @@ MonoBehaviour: p2: 3 p3: 3 pMask: 7 - note: "\uC7A5\uBCBD \uBC18\uD3ED(\uAE30\uBCF8\uAC12)\xB7\uD134\xB7\uB2FF\uC744 - \uB54C \uACF5\uACA9 \uBC30\uC728" + note: "\uC7A5\uBCBD \uBC18\uD3ED(PD \uD655\uC815)\xB7\uD134\xB7\uB2FF\uC744 \uB54C + \uACF5\uACA9 \uBC30\uC728" - skillId: luxun_a key: hit_burn target: @@ -4589,6 +4603,16 @@ MonoBehaviour: p3: 1 pMask: 7 note: + - skillId: luxun_a + key: zone_hits_allies + target: + cond: + dur: 0 + p1: 1 + p2: 0 + p3: 0 + pMask: 1 + note: "\uC544\uAD70\uB3C4 \uD53C\uD574(PD \uACB0\uC815 \u246C)" - skillId: luxun_p key: dmg_pct target: camp:wu @@ -4618,7 +4642,7 @@ MonoBehaviour: p2: 1 p3: 0 pMask: 3 - note: "\uACF5\uACA9 \uBC30\uC728(\uAE30\uBCF8\uAC12)\xB7\uBC00\uAE30(\uAE30\uBCF8\uAC12)" + note: "\uACF5\uACA9 \uBC30\uC728(PD \uD655\uC815)\xB7\uBC00\uAE30(PD \uD655\uC815)" - skillId: sunshangxiang_a key: hit_bleed target: @@ -4728,7 +4752,8 @@ MonoBehaviour: p2: 1 p3: 1 pMask: 7 - note: "\uAC80\uAE30 \xB7 \uC544\uAD70\uB3C4 \uD53C\uD574 \xB7 \uBC00\uAE30(\uAE30\uBCF8\uAC12)" + note: "\uAC80\uAE30 \xB7 \uC544\uAD70\uB3C4 \uD53C\uD574 \xB7 \uBC00\uAE30(PD + \uD655\uC815)" - skillId: zhoutai_p key: hit_confuse target: @@ -4756,10 +4781,10 @@ MonoBehaviour: dur: 0 p1: 1 p2: 3 - p3: 0 + p3: 1 pMask: 7 - note: "\uD68C\uC624\uB9AC \uBC18\uD3ED(\uAE30\uBCF8\uAC12)\xB7\uBC00\uAE30(\uAE30\uBCF8\uAC12)\xB7\uACF5\uACA9 - \uBC30\uC728(\uD53C\uD574 \uC5C6\uC74C)" + note: "\uD68C\uC624\uB9AC \uBC18\uD3ED\xB7\uBC00\uAE30(PD \uD655\uC815)\xB7\uACF5\uACA9 + \uBC30\uC728(PD \uACB0\uC815 \u246D = 100 %)" - skillId: zhugejin_a key: hit_confuse target: @@ -4905,11 +4930,11 @@ MonoBehaviour: target: cond: dur: 0 - p1: 5 + p1: 1 p2: 0.02 p3: 0.5 pMask: 7 - note: "\uD134(\uAE30\uBCF8\uAC12)\xB7\uD655\uB960" + note: "\uD134(\uBBF8\uAE30\uC7AC \u2192 1 \xB7 PD \uACB0\uC815 \u2463)\xB7\uD655\uB960" - skillId: huaxiong_a key: dmg_pct target: @@ -5079,7 +5104,7 @@ MonoBehaviour: p2: 1.5 p3: 0 pMask: 3 - note: "\uB3CC\uC9C4 \uCD08\xB7\uBC00\uCE58\uAE30 \uAC70\uB9AC(\uAE30\uBCF8\uAC12)" + note: "\uB3CC\uC9C4 \uCD08\xB7\uBC00\uCE58\uAE30 \uAC70\uB9AC(PD \uD655\uC815)" - skillId: dongzhuo_p key: dmg_taken_pct target: camp:other @@ -5109,7 +5134,8 @@ MonoBehaviour: p2: 2 p3: 0 pMask: 3 - note: "\uAD11\uC5ED \uD53C\uD574 \uBE44\uC728\xB7\uC778\uC811 \uBC18\uACBD(\uAE30\uBCF8\uAC12)" + note: "\uAD11\uC5ED \uD53C\uD574 \uBE44\uC728\xB7\uC778\uC811 \uBC18\uACBD(PD + \uD655\uC815)" - skillId: lijue_p key: action_end_sacrifice target: @@ -5119,7 +5145,7 @@ MonoBehaviour: p2: 0.5 p3: 2 pMask: 7 - note: "HP \uC18C\uBAA8\xB7\uACF5\uACA9 %\xB7\uC778\uC811 \uBC18\uACBD(\uAE30\uBCF8\uAC12)" + note: "HP \uC18C\uBAA8\xB7\uACF5\uACA9 %\xB7\uC778\uC811 \uBC18\uACBD(PD \uD655\uC815)" - skillId: yuanshao_a key: sling_dist_pct target: range @@ -5295,11 +5321,11 @@ MonoBehaviour: target: cond: dur: 0 - p1: 5 + p1: 1 p2: 0.02 p3: 1 pMask: 7 - note: + note: "\uD134(\uBBF8\uAE30\uC7AC \u2192 1 \xB7 PD \uACB0\uC815 \u2463)" - skillId: zhurong_p key: lifesteal target: @@ -5435,11 +5461,11 @@ MonoBehaviour: target: cond: dur: 0 - p1: 5 + p1: 1 p2: 0.02 p3: 1 pMask: 7 - note: + note: "\uD134(\uBBF8\uAE30\uC7AC \u2192 1 \xB7 PD \uACB0\uC815 \u2463)" - skillId: zhanglu_a key: poison_zone target: @@ -5449,7 +5475,7 @@ MonoBehaviour: p2: 1 p3: 0 pMask: 3 - note: "\uBC18\uACBD(\uAE30\uBCF8\uAC12)\xB7\uD134" + note: "\uBC18\uACBD(PD \uD655\uC815)\xB7\uD134" - skillId: zhanglu_p key: zombie target: diff --git a/Assets/Scripts/Runtime/ActionResolver.Skills.cs b/Assets/Scripts/Runtime/ActionResolver.Skills.cs index e96b9538..1cd8b8ae 100644 --- a/Assets/Scripts/Runtime/ActionResolver.Skills.cs +++ b/Assets/Scripts/Runtime/ActionResolver.Skills.cs @@ -114,7 +114,7 @@ namespace TKS var hit = Combat.FirstUnitOnArrow(u, from, dir, range, cfg.arrowRadius, u.Faction, out travel, out g); Vector2 center = hit != null ? hit.Position : from + dir * travel; yield return Fx.Arrow(from, center, u.Type == UnitType.Strategist ? Fx.StrategistShotColor : Fx.ArrowColor); - float r = e.P; + float r = e.P * SkillMods.Product(u, SkillKeys.SplashRadiusMult, true); // 사마의 응시낭고·보물 광역 배율도(Fable 검토 B3) Fx.Burst(center, r, ExplosionColor); o.ShotHit = hit; foreach (var t in Combat.UnitsInCircle(center, r, u, null)) @@ -125,7 +125,7 @@ namespace TKS var fz = SkillMods.First(u, SkillKeys.FireZone); var sys = SkillSystem.Current; if (fz != null && sys != null && sys.Of(u) != null) - sys.AddZone(sys.Of(u), center, center, fz.P, Mathf.RoundToInt(fz.Get(1, 1f)), fz.Get(2), SkillMods.First(u, SkillKeys.HitBurn), new Color(1f, 0.45f, 0.1f, 0.35f)); + sys.AddZone(sys.Of(u), center, center, fz.P, Mathf.RoundToInt(fz.Get(1, 1f)), fz.Get(2), ZoneStatus(u), new Color(1f, 0.45f, 0.1f, 0.35f), SkillMods.Has(u, SkillKeys.ZoneHitsAllies)); } /// 하후연 전광 연사: 부채꼴(p3 도) p1 발 × p2 번 · 화살마다 일반 사격 규칙(첫 유닛 · 아군 오사). @@ -249,17 +249,31 @@ namespace TKS Vector2 b = u.Position + dir * Mathf.Max(u.Radius + e.P, Combat.WallTravel(u, u.Position, dir, range)); yield return Fx.Arrow(u.Position, b, new Color(1f, 0.45f, 0.1f)); var sys = SkillSystem.Current; + bool allies = SkillMods.Has(u, SkillKeys.ZoneHitsAllies); // 육손 = 아군도(PD #1112 결정 ⑬) SkillZone z = null; if (sys != null && sys.Of(u) != null) - z = sys.AddZone(sys.Of(u), a, b, e.P, Mathf.RoundToInt(e.Get(1, 1f)), e.Get(2, 1f), SkillMods.First(u, SkillKeys.HitBurn), new Color(1f, 0.4f, 0.05f, 0.35f)); - foreach (var t in battle.AliveUnits(u.Faction == Faction.Player ? Faction.Enemy : Faction.Player)) + z = sys.AddZone(sys.Of(u), a, b, e.P, Mathf.RoundToInt(e.Get(1, 1f)), e.Get(2, 1f), ZoneStatus(u), new Color(1f, 0.4f, 0.05f, 0.35f), allies); + foreach (var t in new List(battle.Units)) { + if (t == null || !t.IsAlive || t == u || (t.Faction == u.Faction && !allies)) continue; if (Combat.SegmentPointDistance(a, b, t.Position) > e.P + t.Radius) continue; if (z != null) z.Touched.Add(t); - ShotDamage(u, t, Combat.SkillDamage(cfg, u, t, e.Get(2, 1f), rng), false, o); + int dmg = Combat.SkillDamage(cfg, u, t, e.Get(2, 1f), rng); // 아군도 같은 피해(PD 결정 ⑬ · Fable 검토 C4) + ShotDamage(u, t, dmg, false, o); + if (t.Faction == u.Faction && t.IsAlive && sys != null) + { + var bs = ZoneStatus(u); + if (bs != null) sys.ApplyBurn(t, Mathf.RoundToInt(bs.P), bs.Get(1, 0.05f)); // 아군도 화상(명중 상태 이상은 적에게만 붙으므로 직접) + } } } + /// 지대가 거는 화상 = zone_burn(주유 불꽃 3턴) · 없으면 그 스킬의 hit_burn(육손 장벽). + static SkillEffect ZoneStatus(Unit u) + { + return SkillMods.First(u, SkillKeys.ZoneBurn) ?? SkillMods.First(u, SkillKeys.HitBurn); + } + /// 일반 사격 덧붙임: 하후연 삼연시(멀티샷 · 좌우 화살) · 감녕 도탄(맞은 유닛과 가까운 n 기 · 아군 포함) · 장로 독지대. IEnumerator ExtraArrows(Unit u, ShotPlan p, ActionOutcome o) { diff --git a/Assets/Scripts/Runtime/ActionResolver.cs b/Assets/Scripts/Runtime/ActionResolver.cs index 077f6ef7..d0fb75ea 100644 --- a/Assets/Scripts/Runtime/ActionResolver.cs +++ b/Assets/Scripts/Runtime/ActionResolver.cs @@ -92,7 +92,7 @@ namespace TKS if (skills != null) { skills.BeginAction(u, moveOnly, o, dir, slingDist); // 예약 액티브 장착 + 발동 연출 · 돌진 거리 비율(만인지적·강동의 호걸·적토마) - if (skills.Ctx != null && (aimed - target).sqrMagnitude > 1e-4f) skills.Ctx.HitTerrain = true; // 이동 감소 지형을 지남(맹획 남만왕) + if (skills.Ctx != null && CrossesSlowTerrain(u, origin, aimed)) skills.Ctx.HitTerrain = true; // 이동 감소 지형(늪·고지)을 지남(맹획 남만왕 · 조인 철벽 감속은 제외 · Fable 검토 C6) } // 슬링샷 돌진 중 = 병종 돌진 포즈 1프레임 고정 · 끝나면 대기 (PD 2026-11-05 #1084) if (u.View != null) u.View.SetCharging(true); @@ -127,7 +127,7 @@ namespace TKS yield return RampageRoutine(u, origin, dir, o); yield break; } - if (!moveOnly && SkillMods.Has(u, SkillKeys.ShotAsArcher)) + if (!moveOnly && (SkillMods.Has(u, SkillKeys.ShotAsArcher) || HasSpecialShot(u))) // 축융 비도 · 주태 검기(보병의 특수 사격 · Fable 검토 A1) { yield return ArcherRoutine(u, origin, dir, dist, target, moveOnly, o); yield break; @@ -315,7 +315,6 @@ namespace TKS DashEnd(u); // 슬링샷 직진 끝 = 돌진 이펙트 소멸(튕김은 반응 · PD 2026-11-10) float remaining = Mathf.Max(0f, dist - hitDist); bool enemy = first.Faction != u.Faction; - bool isFinal = enemy && Combat.EnemyAtPoint(u, target, cfg.finalHitTolerance) == first; int impact = 0; if (enemy) @@ -352,13 +351,7 @@ namespace TKS } if (!enemy && first.IsAlive) yield return PushedAllyAttack(first, o, u); if (!enemy) PushContinue(u, remaining); // 고순: 아군을 밀친 뒤 남은 이동력으로 재행동 - - if (isFinal && u.IsAlive) - { - o.BonusMove = true; - o.BonusMoves = 1; - o.BonusAttack = false; - } + // 목표점 명중 추가 이동 = 제거(PD 2026-11-10 #1112 결정 ⑱ · 보병 특징 = 알까기·연쇄 · 재행동은 스킬로만) } /// 고순 함진 돌파(push_continue): 아군·지형 오브젝트를 밀친 뒤 남은 이동 거리만큼 재행동 1회(슬링 상한 = 남은 거리). @@ -439,7 +432,7 @@ namespace TKS { bool pushedDone = false; Fx.Run(Track(Push(first, dir, push, u, o), () => pushedDone = true)); - float recoil = Reach(u, u.Position, -dir, push * cfg.spearRecoilRatio); + float recoil = Reach(u, u.Position, -dir, push * cfg.spearRecoilRatio * (enemy ? SkillMods.AxeBounce(first) : 1f)); // 서황 대부 = 창병 반작용도 ×(Fable 검토 C5) if (recoil > 0.01f && u.IsAlive) { // 반작용: 벽·유닛·장애물에 닿으면 정지 · 피해 없음 · 보는 방향은 유지(밀친 쪽을 본 채 물러남) @@ -853,7 +846,7 @@ namespace TKS if (p.Target == null) return p; // 사거리 안이면 제자리 · 밖이면 가장자리가 사거리에 들어올 만큼만 다가간다(접근 허용 거리 상한 · 늪·고지 이동 비용 반영 PD #1097) - float need = Mathf.Clamp(hitDist - range, 0f, Reach(u, origin, dir, u.ArcherMoveAllow)); + float need = Mathf.Clamp(hitDist - range, 0f, MoveReach(u, origin, dir, u.ArcherMoveAllow)); p.Approach = need > 0.01f ? Combat.FreeTravel(u, origin, dir, need, true) : 0f; p.From = origin + dir * p.Approach; p.To = p.From; @@ -917,7 +910,7 @@ namespace TKS if (p == null || p.Target == null) { // 공격 가능 범위에 적이 없으면 목표점까지 이동 · 쏘지 않는다 (PD 2026-11-04 2차 지시 · #1087 ⑥ 유지) · 장애물 = 튕김 · 늪·고지 = 이동 비용(PD #1097) - if (p == null || p.Teleport <= 0.01f) yield return MoveOrHit(u, origin, dir, Reach(u, origin, dir, dist), o); + if (p == null || p.Teleport <= 0.01f) yield return MoveOrHit(u, origin, dir, MoveReach(u, origin, dir, dist), o); yield break; } @@ -954,9 +947,15 @@ namespace TKS } Vector2 center = p.HasSplash ? p.SplashCenter : p.To; + float healAll = SkillMods.Sum(u, SkillKeys.SplashHeal, true); // 손건 화친 = 피해 없이 회복만(PD #1112 결정 ⑧) if (p.Hit != null) { - if (p.Hit.Faction == u.Faction && AllyHitSpecial(u, p.Hit, p.From, o)) + if (healAll > 0f) + { + var hs = SkillSystem.Current; + if (hs != null) hs.Heal(p.Hit, Mathf.RoundToInt(SkillSystem.AtkOf(u) * healAll), u); + } + else if (p.Hit.Faction == u.Faction && AllyHitSpecial(u, p.Hit, p.From, o)) { // 아군 명중 = 회복·버프(순욱·소교·간옹·미축) · 감녕 = 아군 곁으로 이동 후 재공격 — 피해 없음 } @@ -968,15 +967,13 @@ namespace TKS { yield return SplashGimmicks(u, p, o); // 덤불 제거 · 수레 파괴 · 화공 불(PD #1097) Fx.Burst(center, p.SplashRadius, Fx.SplashColor); - float heal = SkillMods.Sum(u, SkillKeys.SplashHeal, true); - if (heal > 0f) + if (healAll > 0f) { - // 손건 화친: 광역 = 피해 대신 회복(적 포함) - int amt = Mathf.RoundToInt(SkillSystem.AtkOf(u) * heal); + // 손건 화친: 광역 = 피해 대신 회복(적 포함 · 명중 대상은 위에서 회복) + int amt = Mathf.RoundToInt(SkillSystem.AtkOf(u) * healAll); var sys = SkillSystem.Current; foreach (var s in p.Splash) if (s.IsAlive && sys != null) sys.Heal(s, amt, u); - if (p.Hit != null && p.Hit.IsAlive && p.Hit.Faction == u.Faction && sys != null) sys.Heal(p.Hit, amt, u); } else { diff --git a/Assets/Scripts/Runtime/Gimmicks/ActionResolver.Gimmicks.cs b/Assets/Scripts/Runtime/Gimmicks/ActionResolver.Gimmicks.cs index 54647eb9..3be601f1 100644 --- a/Assets/Scripts/Runtime/Gimmicks/ActionResolver.Gimmicks.cs +++ b/Assets/Scripts/Runtime/Gimmicks/ActionResolver.Gimmicks.cs @@ -44,6 +44,22 @@ namespace TKS return Gim ? Layer.CostReach(u, origin, dir, budget) : budget; } + /// 조준 경로가 지형 이동 감소(늪·고지 오르기)에 걸리는가(맹획 남만왕 재행동 · 지형 무시 유닛도 지형은 「지남」으로 봄). + static bool CrossesSlowTerrain(Unit u, Vector2 origin, Vector2 aimed) + { + if (!Gim || u == null) return false; + Vector2 d = aimed - origin; + float dist = d.magnitude; + if (dist < 0.001f) return false; + return Layer.CostReach(u, origin, d / dist, dist) < dist - 1e-3f; + } + + /// 자기 행동 이동(궁·책 접근·이동만) = 조인 철벽 감속 → 지형 이동 비용(Fable 검토 B2 · 근접 병종은 ReachPoint). + static float MoveReach(Unit u, Vector2 origin, Vector2 dir, float budget) + { + return Reach(u, origin, dir, SlowZoneReach(u, origin, dir, budget)); + } + /// 조인 철벽(zone_slow): 상대 시전자의 행동 반경(기본 슬링 거리) 안을 지나는 구간 = 이동 비용 × (1 + p1). static float SlowZoneReach(Unit u, Vector2 origin, Vector2 dir, float budget) { diff --git a/Assets/Scripts/Runtime/Skills/SkillKeys.cs b/Assets/Scripts/Runtime/Skills/SkillKeys.cs index 92f60421..f5739fd5 100644 --- a/Assets/Scripts/Runtime/Skills/SkillKeys.cs +++ b/Assets/Scripts/Runtime/Skills/SkillKeys.cs @@ -138,6 +138,8 @@ namespace TKS public const string ShotFirewall = "shot_firewall"; public const string ShotAsArcher = "shot_as_archer"; public const string FireZone = "fire_zone"; + public const string ZoneBurn = "zone_burn"; + public const string ZoneHitsAllies = "zone_hits_allies"; public const string PoisonZone = "poison_zone"; public const string SplashHeal = "splash_heal"; public const string SplashHealLowest = "splash_heal_lowest"; @@ -200,7 +202,7 @@ namespace TKS { ReturnAim, Fix }, { WallBounce, Fix }, { Rampage, Fix }, { RepeatAction, Fix }, { ArrowPassAllies, Fix }, { ShotGiant, I(SkillScale.Mult, 1) }, { ShotPierce, I(SkillScale.Mult) }, { ShotBlast, I(SkillScale.Mult, 1) }, { ShotFan, Fix }, { Multishot, Fix }, { ShotRicochet, I(SkillScale.Value, 1) }, { ShotSingle, Fix }, { ShotWhirl, Fix }, - { ShotBarricade, Fix }, { ShotFirewall, I(SkillScale.Mult, 2) }, { ShotAsArcher, Fix }, { FireZone, Fix }, { PoisonZone, Fix }, + { ShotBarricade, Fix }, { ShotFirewall, I(SkillScale.Mult, 2) }, { ShotAsArcher, Fix }, { FireZone, Fix }, { ZoneBurn, I(SkillScale.Value, 1) }, { ZoneHitsAllies, Fix }, { PoisonZone, Fix }, { SplashHeal, I(SkillScale.Value) }, { SplashHealLowest, I(SkillScale.Value) }, { AoeStrike, I(SkillScale.Mult, 1) }, { AoeDrain, I(SkillScale.Mult) }, { Volley, I(SkillScale.Mult) }, { CharmPull, Fix }, { HealAtk, I(SkillScale.Value) }, { HealSelfPct, I(SkillScale.Value) }, { Cleanse, Fix }, { Teleport, Fix }, { GrantReaction, Fix }, diff --git a/Assets/Scripts/Runtime/Skills/SkillSystem.cs b/Assets/Scripts/Runtime/Skills/SkillSystem.cs index 197bec99..659fc5c4 100644 --- a/Assets/Scripts/Runtime/Skills/SkillSystem.cs +++ b/Assets/Scripts/Runtime/Skills/SkillSystem.cs @@ -155,8 +155,15 @@ namespace TKS public string StatusKey; public SkillEffect Status; public GameObject View; + /// 같은 편도 닿으면 피해·상태 이상(육손 불 장벽 · PD 2026-11-10 #1112 결정 ⑬). + public bool HitsAllies; public readonly HashSet Touched = new HashSet(); + public bool Affects(Unit u) + { + return u != null && (u.Faction != Faction || HitsAllies); + } + public float Distance(Vector2 p) { return Combat.SegmentPointDistance(A, B, p); @@ -568,6 +575,16 @@ namespace TKS s.AtkFlatRounds = 0; } + // 지속 회복(방통 봉추의 계) = 라운드 감소·만료 전에 — dur n 이면 n 번 회복(Fable 검토 B1) + foreach (var t in TimedEffects) + { + if (t.E.Key != SkillKeys.Hot || t.Faction != side || t.Owner == null || t.Owner.Unit == null) continue; + int amt = Mathf.RoundToInt(AtkOf(t.Owner.Unit) * t.E.P); + foreach (var u in battle.AliveUnits(side)) + if (t.Targets == null ? u == t.Owner.Unit : t.Targets.Contains(u)) + if (Heal(u, amt, t.Owner.Unit) > 0) any = true; + } + for (int i = TimedEffects.Count - 1; i >= 0; i--) { var t = TimedEffects[i]; @@ -603,12 +620,14 @@ namespace TKS if (bank != null && !s.MovedThisRound) s.Bank = Mathf.Min(Mathf.Max(0, Mathf.RoundToInt(bank.P) - 1), s.Bank + 1); s.MovedThisRound = false; } - if (summons.Contains(u)) gone.Add(u); } + foreach (var z in summons) + if (z == null || z.Faction == side) gone.Add(z); // 망령(스킬 항목 없음)은 소환 목록에서 직접 foreach (var z in gone) { + if (z != null && z.IsAlive) yield return ZombieAct(z); // 망령 = 자기 턴 시작에 1번 공격 후 소멸(PD #1112 결정 ⑩) summons.Remove(z); - battle.RemoveUnit(z); + if (z != null) battle.RemoveUnit(z); any = true; } @@ -641,14 +660,6 @@ namespace TKS float regen = SkillMods.Sum(u, SkillKeys.RegenPct, true); if (regen > 0f && Heal(u, Mathf.RoundToInt(u.MaxHp * regen), u) > 0) any = true; } - foreach (var t in TimedEffects) - { - if (t.E.Key != SkillKeys.Hot || t.Faction != side || t.Owner == null || t.Owner.Unit == null) continue; - int amt = Mathf.RoundToInt(AtkOf(t.Owner.Unit) * t.E.P); - foreach (var u in battle.AliveUnits(side)) - if (t.Targets == null ? u == t.Owner.Unit : t.Targets.Contains(u)) - if (Heal(u, amt, t.Owner.Unit) > 0) any = true; - } foreach (var s in entries) { var src = s.Unit; @@ -673,7 +684,7 @@ namespace TKS Zones.RemoveAt(i); continue; } - if (z.Faction == side) continue; + if (z.Faction == side && !z.HitsAllies) continue; z.Touched.Clear(); foreach (var u in battle.AliveUnits(side)) if (z.Distance(u.Position) <= z.Radius + u.Radius * 0.5f) @@ -1003,7 +1014,8 @@ namespace TKS if (ctx != null && ctx.ZombieFrom.Count > 0 && !Sim.Active) foreach (var dead in ctx.ZombieFrom) - yield return ZombieRoutine(u, dead); + SpawnZombie(u, dead); + yield return null; Ctx = null; battle.NotifyChanged(); @@ -1184,7 +1196,7 @@ namespace TKS Text(d, "무적", SkillFx.GuardColor); return 0; } - if (kind != HitKind.Self && kind != HitKind.Dot && ds != null && ds.PassiveEffects != null) + if (kind != HitKind.Self && ds != null && ds.PassiveEffects != null) // 조범 처세 「어떤 피해든」 = 상태 이상·지대 피해 포함(Fable 검토 C3) { var ng = Find(ds.PassiveEffects, SkillKeys.NegateHits); if (ng != null && ds.NegateUsed < Mathf.RoundToInt(ng.P)) @@ -1226,7 +1238,13 @@ namespace TKS if (ds != null && dmg > 0 && HasTimed(ds, SkillKeys.DamageToAtk)) ds.DmgTakenRound += Mathf.Min(dmg, d.Hp); int before = d.Hp; - if (dmg >= d.Hp && TryRevive(d, ds, before)) return before; + if (dmg >= d.Hp && TryRevive(d, ds, before)) + { + // 부활을 부른 타격도 준 쪽 효과(흡혈·첫 명중·연속 기절·명중 상태 이상) · 맞은 쪽 반응 — 처치는 아님(Fable 검토 C7) + if (by != null && by.Faction != d.Faction) OnDealt(by, d, before, kind, crit); + if (d.IsAlive && by != null && by.IsAlive && by.Faction != d.Faction && kind == HitKind.Attack) OnAttacked(d, by); + return before; + } d.TakeDamage(dmg); int dealt = before - d.Hp; if (by != null && by.Faction != d.Faction) OnDealt(by, d, dealt, kind, crit); @@ -1384,14 +1402,22 @@ namespace TKS ApplyBleedStatus(d, Mathf.RoundToInt(h.E.P), h.E.Get(1, 0.5f)); NoteHit(h); } + // 중독 = 한 번 명중에 1회만(액티브·패시브가 함께 걸려도 중첩 +1 · 가장 긴 턴·큰 비율 · Fable 검토 C1) + int pTurns = 0; + float pPct = 0f; foreach (var h in SkillMods.Get(by, SkillKeys.HitPoison, d, crit)) if (Roll(h.E.Get(2, 1f))) { - int max = 1; - foreach (var ps in SkillMods.Get(by, SkillKeys.PoisonStack)) max = Mathf.Max(max, Mathf.RoundToInt(ps.E.P)); - ApplyPoison(d, Mathf.RoundToInt(h.E.P), h.E.Get(1, 0.02f), max); + pTurns = Mathf.Max(pTurns, Mathf.RoundToInt(h.E.P)); + pPct = Mathf.Max(pPct, h.E.Get(1, 0.02f)); NoteHit(h); } + if (pTurns > 0) + { + int max = 1; + foreach (var ps in SkillMods.Get(by, SkillKeys.PoisonStack)) max = Mathf.Max(max, Mathf.RoundToInt(ps.E.P)); + ApplyPoison(d, pTurns, pPct, max); + } foreach (var h in SkillMods.Get(by, SkillKeys.HitBurn, d, crit)) if (Roll(h.E.Get(2, 1f))) { @@ -1497,22 +1523,33 @@ namespace TKS if (ctx != null && ctx.Actor == by && Eff(s, SkillKeys.Zombie) != null && !Sim.Active) ctx.ZombieFrom.Add(d); } - /// 장로 한중의 교주: 처치한 적이 체력 1 로 같은 편이 되어 가장 가까운 상대를 1번 공격(조작 불가) · 그 진영 다음 턴 시작에 사라짐. - IEnumerator ZombieRoutine(Unit owner, Unit dead) + /// + /// 장로 한중의 교주: 처치한 적이 체력 1 로 같은 편 망령이 된다(조작 불가 · 상대 턴 동안 공격받을 수 있음) → + /// 그 진영 다음 턴 시작(TurnBegin)에 가장 가까운 상대를 1번 공격하고 사라짐(PD 2026-11-10 #1112 결정 ⑩). + /// + void SpawnZombie(Unit owner, Unit dead) { - if (owner == null || dead == null || battle.Board == null) yield break; + if (owner == null || dead == null || battle.Board == null) return; var s = Of(owner); var e = Eff(s, SkillKeys.Zombie); var z = battle.SpawnUnit(dead.Type, owner.Faction, dead.Position, "망령 " + dead.DisplayName, 1f, 1f, false, dead.ArtId); z.Atk = dead.Atk; z.Hp = Mathf.Max(1, Mathf.RoundToInt(e != null ? e.P : 1f)); + z.MarkActed(); summons.Add(z); if (z.View != null) z.View.Refresh(); Text(z, "망령", SkillFx.NameColor); if (s != null) NotePassive(s, s.Passive); + AddLog("망령 " + dead.DisplayName + " — 다음 턴 시작에 1번 공격 후 소멸"); + } + + /// 망령의 자동 공격 1회(가장 가까운 상대 쪽으로 슬링 최대 거리까지). + IEnumerator ZombieAct(Unit z) + { + if (z == null || !z.IsAlive || battle.Board == null) yield break; Unit foe = null; float best = float.MaxValue; - foreach (var t in battle.AliveUnits(Other(owner.Faction))) + foreach (var t in battle.AliveUnits(Other(z.Faction))) { float dd = Vector2.Distance(z.Position, t.Position); if (dd < best) @@ -1529,7 +1566,6 @@ namespace TKS if (aim.magnitude > max) aim = aim.normalized * max; var o = new ActionOutcome(); yield return battle.Resolver.Resolve(z, battle.Board.ClampInside(z.Position + aim, z.Radius), false, o); - z.MarkActed(); Ctx = prevCtx; } @@ -1692,9 +1728,9 @@ namespace TKS // ---------- 지대(주유 불꽃 · 육손 불 장벽 · 장로 독지대) ---------- - public SkillZone AddZone(UnitSkills owner, Vector2 a, Vector2 b, float radius, int rounds, float ratio, SkillEffect status, Color color) + public SkillZone AddZone(UnitSkills owner, Vector2 a, Vector2 b, float radius, int rounds, float ratio, SkillEffect status, Color color, bool hitsAllies = false) { - var z = new SkillZone { Owner = owner, Faction = owner.Unit.Faction, A = a, B = b, Radius = Mathf.Max(0.2f, radius), RoundsLeft = Mathf.Max(1, rounds), Ratio = ratio, Status = status, StatusKey = status != null ? status.Key : null }; + var z = new SkillZone { Owner = owner, Faction = owner.Unit.Faction, A = a, B = b, Radius = Mathf.Max(0.2f, radius), RoundsLeft = Mathf.Max(1, rounds), Ratio = ratio, Status = status, StatusKey = status != null ? status.Key : null, HitsAllies = hitsAllies }; if (!Sim.Active) { var root = new GameObject("SkillZone"); @@ -1722,17 +1758,17 @@ namespace TKS /// 지대 닿음: 상대 = 주인 공격력 × 배율 피해 + 지대 상태 이상(행동마다 · 턴마다 1번). void ZoneTouch(SkillZone z, Unit u) { - if (u == null || !u.IsAlive || u.Faction == z.Faction || !z.Touched.Add(u)) return; + if (u == null || !u.IsAlive || !z.Affects(u) || !z.Touched.Add(u)) return; var src = z.Owner != null ? z.Owner.Unit : null; if (z.Ratio > 0f && src != null) { - int d = Mathf.Max(1, Mathf.RoundToInt(Combat.SkillDamage(Cfg, src, u, z.Ratio, battle.Rng))); + int d = Mathf.Max(1, Mathf.RoundToInt(Combat.SkillDamage(Cfg, src, u, z.Ratio, battle.Rng))); // 아군도 같은 피해(PD 결정 ⑬) d = Hit(u, d, src, HitKind.Dot); Text(u, (z.StatusKey == SkillKeys.HitPoison ? "독지대 −" : "불꽃 −") + d, new Color(1f, 0.55f, 0.25f)); } if (z.Status != null && u.IsAlive) { - if (z.StatusKey == SkillKeys.HitBurn) ApplyBurn(u, Mathf.RoundToInt(z.Status.P), z.Status.Get(1, 0.05f)); + if (z.StatusKey == SkillKeys.HitBurn || z.StatusKey == SkillKeys.ZoneBurn) ApplyBurn(u, Mathf.RoundToInt(z.Status.P), z.Status.Get(1, 0.05f)); else if (z.StatusKey == SkillKeys.HitPoison) ApplyPoison(u, Mathf.RoundToInt(z.Status.P), z.Status.Get(1, 0.02f), 1); } } @@ -1750,7 +1786,7 @@ namespace TKS foreach (var kv in segs) { var u = kv.Key; - if (u == null || !u.IsAlive || u.Faction == z.Faction) continue; + if (u == null || !u.IsAlive || !z.Affects(u)) continue; var s = kv.Value; if (SegSegDistance(new Vector2(s.x, s.y), new Vector2(s.z, s.w), z.A, z.B) <= z.Radius + u.Radius * 0.5f) ZoneTouch(z, u); } @@ -1803,7 +1839,7 @@ namespace TKS s.ReadyTurn = battle.TurnNumber + CooldownOf(s); s.Casting = true; var prevCtx = Ctx; - Ctx = new ActionCtx { Actor = u, Origin = u.Position, Seq = ++s.ActionSeq }; + Ctx = new ActionCtx { Actor = u, Origin = u.Position, Seq = s.ActionSeq }; // 즉시형은 행동 번호를 올리지 않음(장비 연속 판정 · Fable 검토 C2) var moved = new Dictionary(); foreach (var e in s.ActiveEffects) { @@ -1934,7 +1970,7 @@ namespace TKS void AoeDrain(UnitSkills s, SkillEffect e) { var u = s.Unit; - float r = SkillMods.BaseReach(u); + float r = SkillMods.BaseReach(u) * SkillMods.Product(u, SkillKeys.SplashRadiusMult, true); // 응시낭고 광역 배율(Fable 검토 B3) int total = 0; Fx.Burst(u.Position, r, Fx.SplashColor); foreach (var t in battle.AliveUnits(Other(u.Faction))) @@ -2019,7 +2055,7 @@ namespace TKS var pick = pool[battle.Rng.Next(pool.Count)]; pool.Remove(pick); if (pick.ActedThisTurn) pick.GrantReAction(); - else Of(pick).ReactCredits++; + else Ensure(pick).ReactCredits++; // 스킬 없는 병사도(Fable 검토 A2) Text(pick, "재행동", SkillFx.NameColor); } } diff --git a/Assets/Tests/PlayMode/BattleFlowTests.cs b/Assets/Tests/PlayMode/BattleFlowTests.cs index cd672a3c..6960d748 100644 --- a/Assets/Tests/PlayMode/BattleFlowTests.cs +++ b/Assets/Tests/PlayMode/BattleFlowTests.cs @@ -95,7 +95,7 @@ namespace TKS.Tests // ---------- 보병 ---------- [UnityTest] - public IEnumerator Infantry_HitsEnemy_StopsAtContact_PushesIt_BonusMoveOnFinalHit() + public IEnumerator Infantry_HitsEnemy_StopsAtContact_PushesIt_NoBonusMove() { yield return Fresh(); var inf = bm.SpawnUnit(UnitType.Infantry, Faction.Player, new Vector2(0f, -3f), "보병"); @@ -106,7 +106,7 @@ namespace TKS.Tests Assert.Contains(foe, o.Attacked); Assert.Less(foe.Hp, foe.MaxHp, "부딪힌 적을 공격"); - Assert.IsTrue(o.BonusMove, "최종 목표점 명중 → 추가 이동"); + Assert.IsFalse(o.BonusMove, "목표점 명중 추가 이동 = 제거(PD #1112 결정 ⑱)"); float remaining = CastContact(inf, foe); // 당긴 거리 3 − 접촉까지 거리 = 남은 힘 Assert.AreEqual(contactY - remaining * cfg.collisionSelfBounceRatio, inf.Position.y, 0.1f, "보병 자신도 반대 방향으로 튕긴다(PD #1081 · 남은 힘 × 비율)"); Assert.Contains(foe, o.Pushed, "부딪힌 유닛은 밀려난다"); diff --git a/Assets/Tests/PlayMode/SkillTests.cs b/Assets/Tests/PlayMode/SkillTests.cs index 5277dade..8c148278 100644 --- a/Assets/Tests/PlayMode/SkillTests.cs +++ b/Assets/Tests/PlayMode/SkillTests.cs @@ -412,6 +412,138 @@ namespace TKS.Tests Assert.Greater(bm.Skills.StatusOf(b).BurnTurns, 0, "화상"); } + // ---------- PD 결정 반영(2026-11-10 #1112 · ⑧ ⑩ ⑬ ⑭) ---------- + + [UnityTest] + public IEnumerator Firewall_HitsAlliesToo() + { + yield return Fresh(); + var lx = Spawn(UnitType.Strategist, Faction.Player, 0f, -5f, "육손"); + Give(lx, "luxun"); + var ally = Spawn(UnitType.Infantry, Faction.Player, 0f, -3f, "아군"); + var foe = Spawn(UnitType.Infantry, Faction.Enemy, 0f, -1f, "적"); + Begin(); + int a0 = ally.Hp, f0 = foe.Hp; + var o = new ActionOutcome(); + yield return ActArmed(lx, lx.Position + Vector2.up * 2f, o); + Assert.Less(foe.Hp, f0, "적 피해"); + Assert.Less(ally.Hp, a0, "아군도 피해(결정 ⑬)"); + Assert.Greater(bm.Skills.StatusOf(ally).BurnTurns, 0, "아군도 화상"); + Assert.AreEqual(1, bm.Skills.Zones.Count, "장벽 지대"); + Assert.IsTrue(bm.Skills.Zones[0].HitsAllies); + } + + [UnityTest] + public IEnumerator SplashHeal_HealsTargetWithoutDamage() + { + yield return Fresh(); + var sq = Spawn(UnitType.Strategist, Faction.Player, 0f, -4f, "손건"); + Give(sq, "sunqian"); + var foe = Spawn(UnitType.Infantry, Faction.Enemy, 0f, -1f, "적"); + Begin(); + foe.Hp = foe.MaxHp / 2; + int f0 = foe.Hp; + var o = new ActionOutcome(); + yield return ActArmed(sq, foe.Position, o); + Assert.Greater(foe.Hp, f0, "명중 대상도 피해 없이 회복(결정 ⑧)"); + Assert.AreEqual(0, o.DamageDealt); + } + + [UnityTest] + public IEnumerator Whirl_DealsDamageAndPushes() + { + yield return Fresh(); + var zj = Spawn(UnitType.Strategist, Faction.Player, 0f, -5f, "제갈근"); + Give(zj, "zhugejin"); + var foe = Spawn(UnitType.Infantry, Faction.Enemy, 0f, -2f, "적"); + Begin(); + int f0 = foe.Hp; + float y0 = foe.Position.y; + var o = new ActionOutcome(); + yield return ActArmed(zj, zj.Position + Vector2.up * 2f, o); + Assert.Less(foe.Hp, f0, "공격력 × p3 피해(결정 ⑭)"); + Assert.Greater(foe.Position.y, y0 + 0.5f, "진행 방향으로 밀림"); + Assert.IsTrue(SkillStatus.Confused(foe), "혼란"); + } + + [UnityTest] + public IEnumerator Zombie_ActsAtNextOwnTurnThenVanishes() + { + yield return Fresh(); + var zl = Spawn(UnitType.Strategist, Faction.Player, 0f, -5f, "장로"); + Give(zl, "zhanglu"); + var victim = Spawn(UnitType.Infantry, Faction.Enemy, 0f, -2f, "약한 적"); + var other = Spawn(UnitType.Infantry, Faction.Enemy, 3f, 1f, "다른 적"); + Begin(); + victim.Hp = 1; + int other0 = other.Hp; + var o = new ActionOutcome(); + yield return Act(zl, victim.Position, o); + Assert.IsFalse(victim.IsAlive); + Unit zombie = null; + foreach (var u in bm.Units) + if (u != null && u.IsAlive && SkillSystem.IsSummon(u)) zombie = u; + Assert.IsNotNull(zombie, "망령 생성"); + Assert.AreEqual(Faction.Player, zombie.Faction); + Assert.AreEqual(other0, other.Hp, "처치 직후에는 공격하지 않음(결정 ⑩)"); + yield return bm.Skills.TurnBegin(Faction.Player); + Assert.IsFalse(SkillSystem.IsSummon(zombie) && zombie != null && zombie.IsAlive, "자기 턴 시작에 1번 행동 후 소멸"); + } + + // ---------- Fable 검토 지적 수정(2026-11-10 · A1 · A2 · B1) ---------- + + [UnityTest] + public IEnumerator Infantry_SwordWave_PiercesLine() + { + yield return Fresh(); + var zt = Spawn(UnitType.Infantry, Faction.Player, 0f, -5f, "주태"); + Give(zt, "zhoutai"); + var a = Spawn(UnitType.Infantry, Faction.Enemy, 0f, -3f, "적1"); + var b = Spawn(UnitType.Infantry, Faction.Enemy, 0f, -1.5f, "적2"); + Begin(); + Vector2 start = zt.Position; + int a0 = a.Hp, b0 = b.Hp; + var o = new ActionOutcome(); + yield return ActArmed(zt, zt.Position + Vector2.up * 2f, o); + Assert.IsTrue(o.Fired, "보병 검기 = 사격"); + Assert.Less(a.Hp, a0); + Assert.Less(b.Hp, b0, "직선 위 전원"); + Assert.Less(Vector2.Distance(zt.Position, start), 0.05f, "주태는 제자리"); + } + + [UnityTest] + public IEnumerator GrantReaction_ToSoldierWithoutSkills() + { + yield return Fresh(); + var gj = Spawn(UnitType.Strategist, Faction.Player, 0f, -3f, "곽가"); + var s = Give(gj, "guojia"); + var soldier = Spawn(UnitType.Infantry, Faction.Player, 1.5f, -3f, "병사"); + Begin(); + Assert.IsNull(bm.Skills.Of(soldier), "스킬 없는 병사"); + yield return bm.Skills.Instant(s); + Assert.IsTrue(bm.Skills.TakeReaction(soldier), "행동 안 한 병사 = 행동 뒤 재행동"); + } + + [UnityTest] + public IEnumerator Hot_HealsEveryRoundForDuration() + { + yield return Fresh(); + var pt = Spawn(UnitType.Strategist, Faction.Player, 0f, -3f, "방통"); + var s = Give(pt, "pangtong"); + var ally = Spawn(UnitType.Infantry, Faction.Player, 1.5f, -3f, "아군"); + Begin(); + int rounds = Eff("pangtong_a", SkillKeys.Hot).Dur; + yield return bm.Skills.Instant(s); + int heals = 0; + for (int i = 0; i < rounds + 1; i++) + { + ally.Hp = 1; + yield return bm.Skills.TurnBegin(Faction.Player); + if (ally.Hp > 1) heals++; + } + Assert.AreEqual(rounds, heals, "지속 턴 수만큼 회복"); + } + // ---------- 회복 · 정화 ---------- [UnityTest] diff --git a/CLAUDE.md b/CLAUDE.md index e2bb5216..ea3a3291 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -45,7 +45,7 @@ Unity.exe -projectPath -executeMethod TKS.EditorTools.ProjectSetup.AutoPl - 전투 수치 SOT = `Assets/Resources/BalanceConfig.asset`(Inspector 조정 · 최초 시드만 `Assets/Scripts/Editor/BalanceDefaults.cs`). 코드·테스트에 수치를 직접 적지 않는다(C45). - **아웃게임 SOT = `Assets/Data/OutGame/*.csv`(12장 · 기획 `공유/기획팀_산출물/삼국지슬링샷/tables/` 사본 · utf-8-sig · 2026-11-05 #1093 A)** — 영웅·병사(`heroes.csv` · 구 `BalanceConfig.heroes[]` 대체) · 레벨·승급·진화·장비·뽑기·보상·재화·신규 유저 초기값(`economy.csv` start_*). 고친 뒤 메뉴 `TKS/Import OutGame Data (아웃게임 데이터 임포트)`(`Editor/DataImporter` · 오류 시 자산 불변) → `Resources/OutGame/` 9 자산. 표를 바꾸면 기획 `tables/` 도 같이. -- **스킬(2026-11-10 #1112 전면 개편 · PD 엑셀 「장수 목록」 새 기획 144개)** — 수치 SOT = **`Assets/Data/OutGame/skill_effects.csv`(효과 1줄 = `skill_id · key · target · cond · dur · p1~p3` + 한글 주석 열 `effect_ko · p1_ko~p3_ko` = 밸런싱용 · 게임은 안 읽음)** · `skills.csv` = 이름·발동(next_action|instant|always)·쿨·설명 · `effect_key` = 효과 키 목록(p 칸 비움) · `heroes.csv gender`(m|f = 남성·여성 조건). 원본 = 기획 `tables/`(생성기 `_tables_t1.py` SKILL_EFFECTS · KEY_DOC 주석 사전 · 이름·설명 = `영웅_리스트_스킬.md` · 실행 뒤 `economy.csv`·`gacha.csv` 는 git 되돌림 = 생성기보다 손으로 늘린 판이 최신). 처리기 = `Runtime/Skills/`: `SkillKeys`(121종 · 레벨 계수 칸) · `SkillMods`(대상 칸 자신/allies/camp/radius/range/aura · 조건 칸 crit/vs_*/turn_le/armed · 공격·피해·치명타·반격·슬링 질의) · `SkillSystem`(쿨·예약 · 시한 효과 = 라운드(주인 진영 턴 시작마다 −1) · 피해 적용 `Hit(d, dmg, by, HitKind)` = 무적→무효화→호위→부활→흡혈·명중 상태 이상→처치 보상 · 재행동 `ReactCredits` · 즉시형 · `TurnBegin(side)` = 상대 턴 끝 회복·정화 + 중독·화상·회복·지대 · 행동 중 탭 `WaitTap`(조조·하후돈 · 테스트 `AutoTap`) · 지대 `SkillZone`) · `SkillStatus`(혼란·출혈·중독·화상 · 기절 = 기믹 `GimmickLayer.Stun` 재사용) · 특수 이동 = `ActionResolver`(관통·핀볼·복귀·교환·끌어오기·난동·반복) · 특수 사격 = `ActionResolver.Skills.cs`. 가상 실행 = `SkillSystem.TakeState/RestoreState`(Sim). 「1 m」 = 전장 1 칸 · 「행동 반경」 = 기본 슬링 거리(PD 확인 대상). 테스트 = `Tests/PlayMode/SkillTests`(효과 묶음 19). 캡처 = `-executeMethod TKS.EditorTools.DataImporter.CaptureSkills -skillDir `. +- **스킬(2026-11-10 #1112 전면 개편 · PD 엑셀 「장수 목록」 새 기획 144개)** — 수치 SOT = **`Assets/Data/OutGame/skill_effects.csv`(효과 1줄 = `skill_id · key · target · cond · dur · p1~p3` + 한글 주석 열 `effect_ko · p1_ko~p3_ko` = 밸런싱용 · 게임은 안 읽음)** · `skills.csv` = 이름·발동(next_action|instant|always)·쿨·설명 · `effect_key` = 효과 키 목록(p 칸 비움) · `heroes.csv gender`(m|f = 남성·여성 조건). 원본 = 기획 `tables/`(생성기 `_tables_t1.py` SKILL_EFFECTS · KEY_DOC 주석 사전 · 이름·설명 = `영웅_리스트_스킬.md` · 실행 뒤 `economy.csv`·`gacha.csv` 는 git 되돌림 = 생성기보다 손으로 늘린 판이 최신). 처리기 = `Runtime/Skills/`: `SkillKeys`(121종 · 레벨 계수 칸) · `SkillMods`(대상 칸 자신/allies/camp/radius/range/aura · 조건 칸 crit/vs_*/turn_le/armed · 공격·피해·치명타·반격·슬링 질의) · `SkillSystem`(쿨·예약 · 시한 효과 = 라운드(주인 진영 턴 시작마다 −1) · 피해 적용 `Hit(d, dmg, by, HitKind)` = 무적→무효화→호위→부활→흡혈·명중 상태 이상→처치 보상 · 재행동 `ReactCredits` · 즉시형 · `TurnBegin(side)` = 상대 턴 끝 회복·정화 + 중독·화상·회복·지대 · 행동 중 탭 `WaitTap`(조조·하후돈 · 테스트 `AutoTap`) · 지대 `SkillZone`) · `SkillStatus`(혼란·출혈·중독·화상 · 기절 = 기믹 `GimmickLayer.Stun` 재사용) · 특수 이동 = `ActionResolver`(관통·핀볼·복귀·교환·끌어오기·난동·반복) · 특수 사격 = `ActionResolver.Skills.cs`. 가상 실행 = `SkillSystem.TakeState/RestoreState`(Sim). PD 결정 18건(2026-11-10 · 대화로그 `2026-11-10_스킬구현.md`): 「1 m」 = 전장 1 칸 · 「행동 반경」 = 기본 슬링 거리 · 기획에 없는 지속 턴 = 1 · 출혈 = 슬링 최대 거리 이동 시 최대 HP 50 % · 망령 = 다음 자기 턴 시작에 1번 공격 후 소멸 · 육손 불 장벽 = 아군도 · 손건 화친 = 피해 없이 회복만 · 보병 목표점 추가 이동 제거. 테스트 = `Tests/PlayMode/SkillTests`(효과 묶음 26 · PD 결정·Fable 검토 반영 포함). 캡처 = `-executeMethod TKS.EditorTools.DataImporter.CaptureSkills -skillDir `. - **아웃게임 2차(2026-11-05~06 #1093 C)** — 표 10장 추가(`training` · `training_ranks` · `patrol` · `dev_tree` · `treasures` · `treasure_sets` · `chests`(+ iron/buy 열) · `tower` · `dungeons`(+ reward_amount) · `arena`(+ 상점 키)) + `economy.csv` C 키 24 → 임포트 자산 18(A 9 + C 9 · `OutGameTables.C.cs` 검증). 코드 = `OutGame/Domestic/`(`TrainingRules` 훈련 · `PatrolRules` 순찰 · `DevRules` 개발 효과 키 → 적용 지점 · `DomesticScreen`) · `OutGame/Treasure/`(`TreasureRules` 보유·세트·강화·조건 카운터·상자 · `TreasureScreen`) · `OutGame/Arena/`(`ArenaRules` 탑·던전·투기장·적장 · `ArenaScreen`). 스탯 = §3-2 × (1 + 훈련(병종·항목)) × (1 + 보물(항목)) = `HeroRules.Compute(…, save)` · 보물 crit/range/splash = `BattleManager.SideEffectsProvider` → `SkillMods.Get` 진영 효과(`side_crit_pct` · `range_mult` · `splash_radius_mult`) · 조건 효과 카운터 = `Runtime/BattleEvents.Raise`(전투 코드 1줄씩 · 아군만) · 연무장 전투 = `BattleManager.StartMode(BattleMode)`(적 편성 · 제한 턴 · 결과 탭 = `onExit`) → `OutGameSession.OnModeEnd`. 테스트 = `Tests/PlayMode/OutGameCTests`. 캡처 = `-executeMethod TKS.EditorTools.DataImporter.CaptureC -cDir `(사본 · 10장). - **영웅 72명(PD #1108 · 2026-11-10)** — heroes 87행(영웅 72 + 병사 15) · skills 144 · skill_effects 288 · 옛 키 체계(51+4종 · 견제·관통 배율 등)는 #1112 에서 폐기. - **지형 기믹 레이어(PD #1097 · 2026-11-06 세션 D)** — SOT = `Assets/Data/Gimmicks/{gimmicks,stage_gimmicks,tutorial_tips}.csv`(기획 `tables/` 사본 · utf-8-sig) → 메뉴 `TKS/Import Gimmicks (기믹 임포트)`(`Editor/GimmickImporter` · 오류 시 자산 불변 · `ai_weights.csv` 도 함께) → `Resources/Gimmicks/GimmickDb`·`StageGimmickTable` · `Resources/AI/AiWeights`. 전투 시작 = `GimmickLayer.Build(stage)`(장-번호 배치 · 배경 위 · 유닛 아래 · 장애물 = 콜라이더 + `GimmickBody` · 지대 = 모양 스윕 · 강 = 늪처럼 통과하는 지대(강 안 ×p3 · 다리 구간 = 효과 없음 · 강가·다리에서 밀려 강물에 들면 빠짐 · PD 2026-11-06 개정) · 겹친 유닛은 빈 자리로). 전투 코드는 질의만: `Combat.FreeTravel`(장애물 = 벽 · 숨은 함정 정지) · `FirstUnitOnArrow`(pass/block/destroy) · `Combat.Damage`(군기 공 · 고지 근접 피격 · 안개 원거리 피격 ×p1 · 책사 광역이 그 반경 안개를 걷음) · `SkillMods.Range`(고지 사거리) · `BattleManager` 턴 시작 `TurnStart`(군기·중독·불·행동 불가). 충돌 반응·폭발·굴림·미끄러짐·지대 = `Gimmicks/ActionResolver.Gimmicks.cs`(partial). 배치 도구 = `TKS/Gimmick Painter (기믹 배치)`. 테스트 = `Tests/PlayMode/GimmickTests` · 캡처 = `-executeMethod TKS.EditorTools.GimmickImporter.Capture -gimmickDir `(사본). @@ -84,7 +84,7 @@ UI 를 새로 만들거나 고칠 때 **반드시** 이 구조를 따른다(어 - **IB(쿠로네코) 이펙트 시험(현재 기본 공격 · PD 2026-11-10 「내가 원한 비주얼은 이런게 아니야(이노센트베인 영상) → 우선 IB 이펙트를 그대로 써서 확인 · 나중에 구조에 맞게 새로 그림(화풍 통일)」)**: IB 슬링샷 발사 `UnitVisualEffectControl.ShowBoosterFX()` 와 같은 구성 — `ef_booster`(앞 빛 물결 2장 + 가시 · 0.2초 반복 맥동 · 유닛 위 · 이동 끝에 바로 지움 = IB Breaking 때 Kill) · `ef_speed_tail`(꼬리 0.6초 + 화살표 입자 · 유닛 아래 · 끝나면 꼬리가 줄며 사라짐 — `SkillVfx.Stop` 이 트레일 길이만큼 기다림) · `ef_booster_dust`(출발 먼지 1번) · 타격 `ef_normal_hit`. 원본 = `Assets/VFX/IB/`(쿠로네코 `E:\NerdNavis\Kuroneko\KuronekoClient` 에서 `Tools/wl_vfx_import.py copy … --wl <쿠로네코> --dest Assets/VFX/IB --skip-scripts` · GUID 유지 · 무수정) · 사본 = `Resources/Fx/TKS_Fx_IB_*`(`Tools/make_ib_fx_copies.cs` — IB 전용 스크립트 부품 제거 · 정렬 레이어 Default · 방향 있는 것은 감싸는 루트 + 안쪽 Z −90°(IB 정면 +Y → 이 게임 +X) · 소리 이벤트 받는 곳 `IbFxAnimEvents`(아무것도 안 함 · 없으면 재생마다 콘솔 오류)). 셰이더 = `Fingar/Additive`(더하기 섞기 · 빌트인 그대로). 2D 돌진 3차 행은 표에 `#` 주석(되돌리기). **진영색(PD 「진영 색을 입히고」)** = `TKS_Fx_IB_Booster_<진영>`(스프라이트 색의 색상만 진영색 · 채도·밝기 유지) · `TKS_Fx_IB_SpeedTail_<진영>`(꼬리 그림 `Assets/VFX/IB/_TKS/Tail_Basic02_<진영>.png` = `Tools/make_ib_camp_textures.py` · 재질 같은 폴더 · 화살표 입자 색) — 둘 다 `make_ib_fx_copies.cs` 가 `Tools/dash2d_camps.csv` 로 만듦 · 원색 사본 `TKS_Fx_IB_Booster` · `SpeedTail` 은 비교용으로 남음(표에서 안 씀). **사라지는 시점(PD 「멈춘 이후 뒤늦게 이펙트가 사라짐 · 위치 안 맞음」)** = 속도 꼬리 `f_fade` 0.12 — 멈춘 자리에서 꼬리째 흐려짐(`SkillVfxFade` 가 트레일 색 그러데이션 불투명도도 낮춤 · 전에는 0.6초 꼬리 머리가 기병 돌격 끝자리에 남아 복귀 중에도 보였음). **타격** = 현재 없음(PD 2026-11-10 「적이 피격되었을 때 히트 이펙트는 제거 · 어떤 히트 이펙트를 쓸지 알려줄게」 · IB NormalHit · BounceHit 행은 표에 `#` 주석). **기준점 `e_anchor` = dash**(빛 물결 · 꼬리 · PD 「복귀할 때 이펙트가 캐릭터보다 위쪽에 생겨 안 보임 → 유닛 바닥에」) = 위·옆으로 갈 때 몸 가운데 · 아래로 갈수록 발 쪽(곧장 아래 = 발). **흙먼지** = WL 창 돌진 흙먼지 `TKS_Fx_SpearRushDust`(0.15초마다 발밑 · PD 「복귀할 때 흙먼지가 너무 세서 뭉개짐 → WL 흙먼지로」 · IB 출발 먼지 행은 `#` 주석). - **방향 결정 UI = IB 이식(PD 2026-11-10 「IB 와 같이 슬링샷 조작 시 방향 결정 UI 등을 그대로 이식」)**: `TKS.IbAimArrow`(IB `GameTouchArrow` 동작 · 프리팹 `Resources/Fx/TKS_Fx_IB_GameArrow` = 원본 `Assets/VFX/IB/AssetResources/Game/GameArrow` 사본) — 누르면 유닛 둘레 고리 + 퍼지는 고리 3개(3초 · 1초 간격) · 당기면 하늘색 화살표가 쏠 방향으로 돌고 당긴 세기만큼 길어짐(0.5~1.5 · 최소 당김 → 슬링샷 최대 거리) · 화살 끝이 전장 밖이면 안으로 · 놓으면 숨김. 전에 쓰던 조준선 · 당김선은 끔(`SlingshotInput.ShowPreview` · IbAimArrow 가 없을 때만 예전 선). 목표 고리 · 강조 · 궁병 화살 경로선 · 기믹 예상 궤적은 그대로. 화살표 색 = IB 공격 종류 3(하늘색) 하나. - **여포 크기(PD 2026-11-10 「왜 여포는 다른 기병보다 작지?」)**: 말 탄 유닛은 머리 끝 상한(BalanceConfig.mountedArtMaxTop 1.3 × 표준 키)에 맞춰 줄어드는데, `dz_boss_lvbu` 의 몸 높이(`meta.json` bodyHeightPx · `art_size.csv` body_px)가 머리 깃털 끝까지 819 px 라 몸 전체가 더 줄었음 → 왕관 끝 ~ 발 718 px(front_idle 실측 · 깃털 제외 · 다른 기병의 투구 끝 기준과 같은 규칙)로 고침 → 배율 0.2381 → 0.2716(+14 %). 원본 백업 = 세션 scratchpad. **다른 PC 에서 그림을 다시 export 하면 819 로 되돌아갈 수 있음**(export 규칙 = 불투명 폭 30 % 행 — 깃털이 넓어서 안 걸러짐). -- **근접 3병종 특징 = 한 줄 정의(PD 2026-11-10 직접 지시)**: **보병** = 적을 밀치고 튕겨나며 튕기면서 다른 적을 추가로 공격(알까기 + 연쇄 · #1098 그대로 · 목표점 명중 추가 이동 1회는 유지 = PD 확인 대상) · **창병** = 적을 크게 밀치지만 자신은 적게 밀림(`spearPushRatio` 1.5 > 보병 `collisionPushRatio` 1.0 · 반작용 남은 거리 × 0.3 < 보병 자기 튕김 0.5) · **창병 대기(견제) 제거**(「유저가 인지하기 어려움」 · 목표점 명중해도 `SetOverwatch` 안 함 · HUD 「견제 반경·대기 중」 문구 삭제) · **기병** = 적을 관통해 이동 · **목표점 명중 시 제자리 복귀 제거**(「유저가 인지하기 어려움」 · `PreviewCavalryReturn` · 조준 때 복귀 영역 `ShowReturnZones` 삭제 · AI 가중치 `cav_return`·`cav_stranded` 삭제). 견제·복귀 스킬 = #1112 PD 새 기획으로 전부 재설계(견제 없음 · 복귀는 스킬 효과 `return_on_hit`·`return_always`·`return_aim` 으로만) · `SkillMods.Overwatch*` 삭제 · `BattleManager.ApplyOverwatch` · `Unit.Overwatch` 는 스킬 확장 없이 남음(대기 유닛이 없어 실행 안 됨). +- **근접 3병종 특징 = 한 줄 정의(PD 2026-11-10 직접 지시)**: **보병** = 적을 밀치고 튕겨나며 튕기면서 다른 적을 추가로 공격(알까기 + 연쇄 · #1098 그대로 · 목표점 명중 추가 이동 = 제거(PD #1112 결정 ⑱)) · **창병** = 적을 크게 밀치지만 자신은 적게 밀림(`spearPushRatio` 1.5 > 보병 `collisionPushRatio` 1.0 · 반작용 남은 거리 × 0.3 < 보병 자기 튕김 0.5) · **창병 대기(견제) 제거**(「유저가 인지하기 어려움」 · 목표점 명중해도 `SetOverwatch` 안 함 · HUD 「견제 반경·대기 중」 문구 삭제) · **기병** = 적을 관통해 이동 · **목표점 명중 시 제자리 복귀 제거**(「유저가 인지하기 어려움」 · `PreviewCavalryReturn` · 조준 때 복귀 영역 `ShowReturnZones` 삭제 · AI 가중치 `cav_return`·`cav_stranded` 삭제). 견제·복귀 스킬 = #1112 PD 새 기획으로 전부 재설계(견제 없음 · 복귀는 스킬 효과 `return_on_hit`·`return_always`·`return_aim` 으로만) · `SkillMods.Overwatch*` 삭제 · `BattleManager.ApplyOverwatch` · `Unit.Overwatch` 는 스킬 확장 없이 남음(대기 유닛이 없어 실행 안 됨). - **IB 크기 · 캐릭터 연출(PD 2026-11-10 「IB 와 화살표 크기도 다르고 선택된 캐릭터 주위 연출도 누락」)**: 값 표 `Resources/Skills/ib_ui.csv`(`TKS.IbUi`) — IB 유닛 반지름 0.496(ExportCharacter size 8 × 0.062) 기준 배율 = 이 게임 유닛 반지름 / 0.496 → 고리 지름 = 반지름 × 5.4 · 화살표 세기 s = IB 월드 당김 × 0.6(0.5~1.5) · IB 취소 거리 0.5. **`TKS.IbUnitMarks`** = 선택한 행동 가능 아군 발밑 도는 원(`TKS_Fx_IB_TargetCircle` · IB ShowUserTurnMark) + 몸 둘레 빛(`TKS_Fx_IB_AttackReady`) · 조준 중(누름 ~ 놓음) 모든 유닛 속성 방울(`TKS_Fx_IB_Attribute_<속성>` · IB SetActiveBarrierVisualEffect · 진영 → 속성 = 표 element_*: 위 물 · 촉 나무 · 오 불 · 군·진영 없음 어둠). - **타격감(PD 2026-11-10 「화면 흔들림 등도 IB 를 참고해서」)**: `TKS.HitFeel` + 표 `Resources/Skills/hit_feel.csv`(행동 중 유닛이 상대에게 처음 피해를 준 순간 · `SkillSystem.Hit` · 흔들림 = `CameraController.Shake`(추적 위치는 그대로 두고 흔들림만 더함) · 히트 스톱 칸 있음(현재 0)). **IB 실측**: 흔들림 함수 6종은 스킬·궁극기·기믹 이펙트 애니메이션 이벤트로만 불리고 본문이 디컴파일에서 비어 있어 값 없음 · 일반 타격·벽 튕김엔 흔들림 없음 · 히트 스톱 없음 → 표 값(hit 0.15초 · 키 10 % / 기병 0.18초 · 13 %)은 추정. - **2D 돌진(PD 2026-11-10 「기본 공격(돌진) 이펙트가 너무 3D 느낌 → 2D 처럼」 · MSFX 혜성 행은 표에 `#` 주석으로 남김 = 되돌리기)**: **3차(현재 · PD 2026-11-10 「검기는 이전 형태가 더 나음 · 대쉬 이펙트는 캐릭터 몸을 벗어나지 않도록 · 첨부 같은 느낌으로 몸을 뒤덮는 연출을 스킬용 시험」)** = 초승달 `Head` = 1차 그림 `dash2d_crescent`(검정 외곽선 · 진영색 곱) · 대쉬 층(꼬리 0.04초 · 바람 줄기 · 알갱이 · 흙먼지) = 유닛을 따라 움직이는 Local 공간 · 몸 기준점 반경 0.45 키 안(실측 그림 경계 좌우 ±0.56 · 아래 −0.60 ~ 위 +0.59 키) · 바람 줄기 `Lines` · 알갱이 `Dots` = 유닛 위 반투명(표 `s_over` = `Head;Lines;Dots` · 유닛 아래면 몸에 다 가려 안 보임 · PD 「몸의 대쉬 효과가 왜 안 보이나」) · 꼬리 · 흙먼지 = 유닛 아래 · **기병 복귀 = 돌아서서 감**(`UnitView.TurnAround` · 복귀 방향으로 보기 + 곧장 위·아래면 좌우 반전 · 도착 뒤에도 마지막 이동 방향 PD #1082) · **몸 뒤덮는 기운(시험)** = `TKS_Fx_Aura2D_<진영>`(혜성 기운 `aura_comet_<진영>` 겹쳐 깜빡임 · 불꽃 혀 `aura_wisp` · 반짝임 = 유닛 아래 · 옅은 막 `Veil` · 앞 테 `Rim`(2차 검기 그림) = 유닛 위) · 표 키 `test_aura` · 테스트 씬 「기운 시험」 스위치(`SkillVfx.TestTravelKey` · 켜면 슬링샷 공격 돌진에 함께 · 실제 전투 = 늘 빈칸). 2차 = 외곽선 없음 · 그림 `Assets/VFX/TKS2D/`(만들기 = `python -I -X utf8 Tools/make_dash2d_textures.py` · 진영색 원본 = `Tools/dash2d_camps.csv`) → 프리팹 `Resources/Fx/TKS_Fx_Dash2D_`(검기 초승달 `Head` = 진영별 그림 `dash2d_slash_<진영>` · 유닛 위 · 반투명 꼬리 `Trail`(앞 0.7 → 0) · 흰 바람 줄기 `Lines` · 알갱이 `Dots` = 유닛 아래 · 수명 동안 투명해짐) + `TKS_Fx_Dust2D`(부드러운 반투명 흙먼지 · 모든 진영) · 다시 만들기 = `unity command … script eval --file Tools/build_dash2d.cs`(값을 바꾸면 이 파일과 프리팹을 함께). 1차(검정 외곽선 셀 그림)의 `dash2d_crescent.png` · `dash2d_highlight.png` 는 안 씀. 표 `b_flat` = 1 이면 화면 안에서 진행 방향으로만 돌림(기울기·팩 루트 회전 무시 · `SkillVfx.FlatRotation`) · 크기 단위 = 유닛 키 1(`f_scale` 1) · 끝 소멸 = `f_fade` 0.12(`SkillVfxFade` 가 스프라이트 불투명도도 낮춤).