384 lines
20 KiB
C#
384 lines
20 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
|
||
namespace TKS
|
||
{
|
||
/// <summary>
|
||
/// 스킬 특수 사격(2026-11-10 #1112 · 효과 표 skill_effects.csv · 수치 = 표 p 칸):
|
||
/// shot_giant(황충 거대 화살 · 사거리 무관 · 첫 적) · shot_pierce(직선 관통 · 아군 통과/피해/회복 · 밀기) · shot_blast(투사체 → 첫 적 자리 폭발 · 불꽃 지대) ·
|
||
/// shot_fan(부채꼴 n 발 × 연속) · shot_whirl(회오리 = 직선 안 적 밀기) · shot_barricade(목책 세우기) · shot_firewall(불 장벽 지대) ·
|
||
/// 일반 사격 덧붙임 = multishot(멀티샷) · shot_ricochet(도탄) · poison_zone(독지대) · 아군 명중 = 회복·버프·이동(ally_hit_*).
|
||
/// </summary>
|
||
public partial class ActionResolver
|
||
{
|
||
static readonly string[] ShotKeys =
|
||
{
|
||
SkillKeys.ShotGiant, SkillKeys.ShotPierce, SkillKeys.ShotBlast, SkillKeys.ShotFan, SkillKeys.ShotWhirl, SkillKeys.ShotBarricade, SkillKeys.ShotFirewall
|
||
};
|
||
|
||
static bool HasSpecialShot(Unit u)
|
||
{
|
||
foreach (var k in ShotKeys)
|
||
if (SkillMods.Has(u, k)) return true;
|
||
return false;
|
||
}
|
||
|
||
IEnumerator SpecialShot(Unit u, Vector2 origin, Vector2 dir, Vector2 target, ActionOutcome o)
|
||
{
|
||
o.Fired = true;
|
||
Face(u, dir);
|
||
if (u.View != null) u.View.PlayAttack();
|
||
if (u.Type == UnitType.Strategist) BattleEvents.Raise(BattleEvents.StrategistShots, u);
|
||
SkillEffect e;
|
||
if ((e = SkillMods.First(u, SkillKeys.ShotGiant)) != null) yield return GiantArrow(u, dir, e, o);
|
||
else if ((e = SkillMods.First(u, SkillKeys.ShotPierce)) != null) yield return PierceShot(u, dir, e, o);
|
||
else if ((e = SkillMods.First(u, SkillKeys.ShotBlast)) != null) yield return BlastShot(u, dir, e, o);
|
||
else if ((e = SkillMods.First(u, SkillKeys.ShotFan)) != null) yield return FanShot(u, dir, e, o);
|
||
else if ((e = SkillMods.First(u, SkillKeys.ShotWhirl)) != null) yield return WhirlShot(u, dir, e, o);
|
||
else if ((e = SkillMods.First(u, SkillKeys.ShotBarricade)) != null) yield return Barricade(u, dir, target, e, o);
|
||
else if ((e = SkillMods.First(u, SkillKeys.ShotFirewall)) != null) yield return Firewall(u, dir, e, o);
|
||
battle.NotifyChanged();
|
||
yield return Fx.Wait(0.2f);
|
||
}
|
||
|
||
/// <summary>황충 백발백중: 사거리 무관 · 반지름 p1 거대 화살 → 아군·장애물 통과 · 첫 적 = 공격력 × p2.</summary>
|
||
IEnumerator GiantArrow(Unit u, Vector2 dir, SkillEffect e, ActionOutcome o)
|
||
{
|
||
Vector2 from = u.Position;
|
||
float far = battle.Board != null ? 200f : 60f;
|
||
float travel;
|
||
GimmickInstance g;
|
||
Combat.ArrowIgnoreGimmicks = true;
|
||
Unit hit;
|
||
try
|
||
{
|
||
hit = Combat.FirstUnitOnArrow(u, from, dir, far, Mathf.Max(cfg.arrowRadius, e.P), u.Faction, out travel, out g);
|
||
}
|
||
finally
|
||
{
|
||
Combat.ArrowIgnoreGimmicks = false;
|
||
}
|
||
Vector2 to = from + dir * travel;
|
||
yield return Fx.Arrow(from, to, new Color(1f, 0.85f, 0.4f));
|
||
if (hit != null)
|
||
{
|
||
o.ShotHit = hit;
|
||
ShotDamage(u, hit, Combat.SkillDamage(cfg, u, hit, e.Get(1, 1f), rng), false, o);
|
||
}
|
||
}
|
||
|
||
/// <summary>직선 관통(태사자·장임·왕랑·조범·주태 검기): 사거리 안 직선 위 유닛 전원(장애물 무시) · 적 = 공격력 × p1 · 아군 = p2(0 통과 · 1 피해 · 2 회복) · p3 = 밀기.</summary>
|
||
IEnumerator PierceShot(Unit u, Vector2 dir, SkillEffect e, ActionOutcome o)
|
||
{
|
||
Vector2 from = u.Position;
|
||
float range = SkillMods.Range(u) + u.Radius;
|
||
float travel = Combat.WallTravel(u, from, dir, range);
|
||
var dists = new List<float>();
|
||
var units = Combat.UnitsOnPath(u, from, dir, travel, dists);
|
||
yield return Fx.Arrow(from, from + dir * travel, u.Type == UnitType.Strategist ? Fx.StrategistShotColor : new Color(0.75f, 0.95f, 1f));
|
||
int allyMode = Mathf.RoundToInt(e.Get(1));
|
||
var pushed = new List<Unit>();
|
||
foreach (var t in units)
|
||
{
|
||
if (!t.IsAlive) continue;
|
||
if (t.Faction == u.Faction)
|
||
{
|
||
if (allyMode == 0) continue;
|
||
if (allyMode == 2)
|
||
{
|
||
AllyHitSpecial(u, t, from, o, true);
|
||
continue;
|
||
}
|
||
}
|
||
if (o.ShotHit == null) o.ShotHit = t;
|
||
ShotDamage(u, t, Combat.SkillDamage(cfg, u, t, e.P, rng), false, o);
|
||
if (t.IsAlive) pushed.Add(t);
|
||
}
|
||
float push = e.Get(2);
|
||
if (push > 0.01f)
|
||
{
|
||
pushed.Reverse(); // 먼 쪽부터 밀어 서로 막히지 않게
|
||
foreach (var t in pushed)
|
||
if (t.IsAlive) yield return Push(t, dir, push * SkillMods.KnockbackTakenMult(t, true), u, o);
|
||
}
|
||
}
|
||
|
||
/// <summary>폭발 사격(서서 화염구 · 가후 독구름 · 주유 운석 · 손권 화살비): 투사체 → 사거리 안 첫 적(아군 너머) 자리 · 반경 p1 안 적 전원 = 공격력 × p2 · 주유 = 불꽃 지대.</summary>
|
||
IEnumerator BlastShot(Unit u, Vector2 dir, SkillEffect e, ActionOutcome o)
|
||
{
|
||
Vector2 from = u.Position;
|
||
float range = SkillMods.Range(u) + u.Radius;
|
||
float travel;
|
||
GimmickInstance g;
|
||
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 * 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))
|
||
{
|
||
if (!t.IsAlive || t.Faction == u.Faction) continue;
|
||
ShotDamage(u, t, Combat.SkillDamage(cfg, u, t, e.Get(1, 1f), rng), false, o);
|
||
}
|
||
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), ZoneStatus(u), new Color(1f, 0.45f, 0.1f, 0.35f), SkillMods.Has(u, SkillKeys.ZoneHitsAllies));
|
||
}
|
||
|
||
/// <summary>하후연 전광 연사: 부채꼴(p3 도) p1 발 × p2 번 · 화살마다 일반 사격 규칙(첫 유닛 · 아군 오사).</summary>
|
||
IEnumerator FanShot(Unit u, Vector2 dir, SkillEffect e, ActionOutcome o)
|
||
{
|
||
int n = Mathf.Max(1, Mathf.RoundToInt(e.P));
|
||
int volleys = Mathf.Max(1, Mathf.RoundToInt(e.Get(1, 1f)));
|
||
float spread = e.Get(2, 30f);
|
||
for (int v = 0; v < volleys && u.IsAlive; v++)
|
||
{
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
float ang = n > 1 ? -spread * 0.5f + spread * i / (n - 1) : 0f;
|
||
FireOne(u, Rotate(dir, ang), o, 1f);
|
||
}
|
||
battle.NotifyChanged();
|
||
yield return Fx.Wait(0.18f);
|
||
}
|
||
}
|
||
|
||
static Vector2 Rotate(Vector2 v, float deg)
|
||
{
|
||
float r = deg * Mathf.Deg2Rad;
|
||
float c = Mathf.Cos(r), s = Mathf.Sin(r);
|
||
return new Vector2(v.x * c - v.y * s, v.x * s + v.y * c);
|
||
}
|
||
|
||
/// <summary>화살 1발(일반 사격 규칙 · 아군 통과 패시브 반영 · 아군 명중 = 회복류 또는 오사) — 부채꼴 · 멀티샷.</summary>
|
||
void FireOne(Unit u, Vector2 d, ActionOutcome o, float ratio)
|
||
{
|
||
float range = SkillMods.Range(u) + u.Radius;
|
||
bool obstacles;
|
||
var pass = ArrowPass(u, out obstacles);
|
||
float travel;
|
||
GimmickInstance g;
|
||
Combat.ArrowIgnoreGimmicks = obstacles;
|
||
Unit hit;
|
||
try
|
||
{
|
||
hit = Combat.FirstUnitOnArrow(u, u.Position, d, range, cfg.arrowRadius, pass, out travel, out g);
|
||
}
|
||
finally
|
||
{
|
||
Combat.ArrowIgnoreGimmicks = false;
|
||
}
|
||
Fx.Run(Fx.Arrow(u.Position, u.Position + d * (hit != null ? travel + cfg.arrowRadius : travel)));
|
||
if (hit == null) return;
|
||
if (o.ShotHit == null) o.ShotHit = hit;
|
||
if (hit.Faction == u.Faction && AllyHitSpecial(u, hit, u.Position, o, true)) return;
|
||
ShotDamage(u, hit, ratio >= 0.999f && ratio <= 1.001f ? Combat.Damage(cfg, u, hit, false, rng, false) : Combat.SkillDamage(cfg, u, hit, ratio, rng), false, o);
|
||
}
|
||
|
||
/// <summary>제갈근 선풍계: 사거리 안 폭 p1 직선 위 적 전원을 진행 방향으로 p2 밀침(먼 쪽부터) · 피해 = 공격력 × p3(0 = 없음) · 명중 상태 이상(혼란).</summary>
|
||
IEnumerator WhirlShot(Unit u, Vector2 dir, SkillEffect e, ActionOutcome o)
|
||
{
|
||
Vector2 from = u.Position;
|
||
float range = SkillMods.Range(u) + u.Radius;
|
||
float travel = Combat.WallTravel(u, from, dir, range);
|
||
Vector2 to = from + dir * travel;
|
||
yield return Fx.Arrow(from, to, new Color(0.7f, 1f, 0.85f));
|
||
var targets = new List<Unit>();
|
||
foreach (var t in battle.AliveUnits(u.Faction == Faction.Player ? Faction.Enemy : Faction.Player))
|
||
if (Combat.SegmentPointDistance(from, to, t.Position) <= e.P + t.Radius) targets.Add(t);
|
||
targets.Sort((a, b) => Vector2.Distance(from, b.Position).CompareTo(Vector2.Distance(from, a.Position)));
|
||
var sys = SkillSystem.Current;
|
||
foreach (var t in targets)
|
||
{
|
||
if (!t.IsAlive) continue;
|
||
if (e.Get(2) > 0f) ShotDamage(u, t, Combat.SkillDamage(cfg, u, t, e.Get(2), rng), false, o);
|
||
else
|
||
{
|
||
o.Attacked.Add(t);
|
||
if (sys != null) sys.ApplyHitStatuses(u, t, false, HitKind.Skill);
|
||
}
|
||
if (t.IsAlive) yield return Push(t, dir, e.Get(1, 1f) * SkillMods.KnockbackTakenMult(t, true), u, o);
|
||
}
|
||
if (o.Attacked.Count == 0) o.MovedOnly = true;
|
||
}
|
||
|
||
/// <summary>노숙 녹각진: 슬링 목표점(사거리 안)에 진행 방향에 수직으로 목책 p1 칸(칸 지름 p3) · 그 자리 적 = 목책 충돌 피해(기믹 표 자기 피해 %)·p2 밀기 · 아군 = 밀기만.</summary>
|
||
IEnumerator Barricade(Unit u, Vector2 dir, Vector2 target, SkillEffect e, ActionOutcome o)
|
||
{
|
||
int n = Mathf.Max(1, Mathf.RoundToInt(e.P));
|
||
float size = Mathf.Max(0.3f, e.Get(2, 1f));
|
||
float range = SkillMods.Range(u) + u.Radius;
|
||
Vector2 c = target;
|
||
if (Vector2.Distance(u.Position, c) > range) c = u.Position + dir * range;
|
||
c = battle.Board.ClampInside(c, size * 0.5f);
|
||
Vector2 perp = new Vector2(-dir.y, dir.x);
|
||
var layer = GimmickLayer.Current;
|
||
var def = GimmickTables.Db != null ? GimmickTables.Db.Get(GimmickIds.Palisade) : null;
|
||
float pct = def != null ? Mathf.Max(def.cavSelfPct, def.bouncePct) : 0f;
|
||
yield return Fx.Arrow(u.Position, c, Fx.StrategistShotColor);
|
||
var sys = SkillSystem.Current;
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
Vector2 p = c + perp * ((i - (n - 1) * 0.5f) * size);
|
||
p = battle.Board.ClampInside(p, size * 0.5f);
|
||
foreach (var t in Combat.UnitsInCircle(p, size * 0.5f, null, null))
|
||
{
|
||
if (!t.IsAlive) continue;
|
||
if (t.Faction != u.Faction && pct > 0f && sys != null)
|
||
{
|
||
int d = sys.Hit(t, Mathf.Max(1, Mathf.RoundToInt(t.MaxHp * pct)), u, HitKind.Skill);
|
||
o.Attacked.Add(t);
|
||
o.DamageDealt += d;
|
||
Fx.Popup(t.Position, d + " 목책", new Color(1f, 0.75f, 0.4f));
|
||
}
|
||
if (t.IsAlive) yield return Push(t, dir, Mathf.Max(e.Get(1, 1f), size), u, o);
|
||
}
|
||
if (layer != null) layer.Spawn(GimmickIds.Palisade, GimmickShape.Circle(p, size * 0.5f));
|
||
}
|
||
o.Notes.Add("목책 " + n + "칸");
|
||
}
|
||
|
||
/// <summary>육손 이릉의 화공: 진행 방향 사거리까지 반폭 p1 불 장벽(p2 턴) · 그 안 적 = 공격력 × p3 + 화상 · 장벽 = 닿는 적마다 같은 피해·화상(지대).</summary>
|
||
IEnumerator Firewall(Unit u, Vector2 dir, SkillEffect e, ActionOutcome o)
|
||
{
|
||
Vector2 a = u.Position + dir * (u.Radius + e.P);
|
||
float range = SkillMods.Range(u) + u.Radius;
|
||
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), ZoneStatus(u), new Color(1f, 0.4f, 0.05f, 0.35f), allies);
|
||
foreach (var t in new List<Unit>(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);
|
||
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)); // 아군도 화상(명중 상태 이상은 적에게만 붙으므로 직접)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>지대가 거는 화상 = zone_burn(주유 불꽃 3턴) · 없으면 그 스킬의 hit_burn(육손 장벽).</summary>
|
||
static SkillEffect ZoneStatus(Unit u)
|
||
{
|
||
return SkillMods.First(u, SkillKeys.ZoneBurn) ?? SkillMods.First(u, SkillKeys.HitBurn);
|
||
}
|
||
|
||
/// <summary>일반 사격 덧붙임: 하후연 삼연시(멀티샷 · 좌우 화살) · 감녕 도탄(맞은 유닛과 가까운 n 기 · 아군 포함) · 장로 독지대.</summary>
|
||
IEnumerator ExtraArrows(Unit u, ShotPlan p, ActionOutcome o)
|
||
{
|
||
var ms = SkillMods.First(u, SkillKeys.Multishot, true);
|
||
if (ms != null && u.Type == UnitType.Archer)
|
||
{
|
||
int n = Mathf.Max(1, Mathf.RoundToInt(ms.P));
|
||
float spread = ms.Get(1, 30f);
|
||
Vector2 d = (p.To - p.From).sqrMagnitude > 1e-6f ? (p.To - p.From).normalized : Vector2.up;
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
float ang = n > 1 ? -spread * 0.5f + spread * i / (n - 1) : 0f;
|
||
if (Mathf.Abs(ang) < 0.01f) continue; // 가운데 = 본 화살
|
||
FireOne(u, Rotate(d, ang), o, 1f);
|
||
}
|
||
}
|
||
var rc = SkillMods.First(u, SkillKeys.ShotRicochet);
|
||
if (rc != null && p.Hit != null)
|
||
{
|
||
var near = new List<Unit>();
|
||
foreach (var t in battle.Units)
|
||
if (t != null && t.IsAlive && t != u && t != p.Hit) near.Add(t);
|
||
Vector2 c = p.Hit.Position;
|
||
near.Sort((a, b) => Vector2.Distance(c, a.Position).CompareTo(Vector2.Distance(c, b.Position)));
|
||
int cnt = Mathf.Max(0, Mathf.RoundToInt(rc.P));
|
||
for (int i = 0; i < near.Count && i < cnt; i++)
|
||
{
|
||
var t = near[i];
|
||
Fx.Run(Fx.Arrow(c, t.Position));
|
||
ShotDamage(u, t, Combat.SkillDamage(cfg, u, t, rc.Get(1, 0.5f), rng), false, o);
|
||
}
|
||
if (cnt > 0) o.Notes.Add("도탄");
|
||
}
|
||
var pz = SkillMods.First(u, SkillKeys.PoisonZone);
|
||
var sys = SkillSystem.Current;
|
||
if (pz != null && sys != null && sys.Of(u) != null && (p.Hit != null || p.HitGimmick != null))
|
||
sys.AddZone(sys.Of(u), p.To, p.To, pz.P, Mathf.RoundToInt(pz.Get(1, 1f)), 0f, SkillMods.First(u, SkillKeys.HitPoison), new Color(0.6f, 0.3f, 0.9f, 0.3f));
|
||
yield return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 자신의 사격이 아군에 맞음: 감녕 백기습영 = 그 아군 곁으로 이동(피해 없음) + 남은 행동 범위로 재행동 · 순욱·소교·간옹·조범 = 공격력 × p 회복 ·
|
||
/// 미축·순욱 = 이동·공격 버프(지속 턴). 처리했으면 true(피해 없음) · 효과가 없으면 false(오사).
|
||
/// </summary>
|
||
bool AllyHitSpecial(Unit u, Unit ally, Vector2 from, ActionOutcome o, bool splash = false)
|
||
{
|
||
var sys = SkillSystem.Current;
|
||
if (sys == null || ally == null || ally == u) return false;
|
||
bool any = false;
|
||
float heal = SkillMods.Sum(u, SkillKeys.AllyHitHeal, true);
|
||
if (heal > 0f)
|
||
{
|
||
sys.Heal(ally, Mathf.RoundToInt(SkillSystem.AtkOf(u) * heal), u);
|
||
any = true;
|
||
}
|
||
foreach (var h in SkillMods.Get(u, SkillKeys.AllyHitBuff))
|
||
{
|
||
if (h.Owner == null) continue;
|
||
int rounds = Mathf.Max(1, h.E.Dur);
|
||
if (h.E.P > 0f) sys.AddBuff(h.Owner, ally, SkillKeys.SlingDistPct, h.E.P, rounds);
|
||
if (h.E.Get(1) > 0f) sys.AddBuff(h.Owner, ally, SkillKeys.AtkPct, h.E.Get(1), rounds);
|
||
if (h.Passive) sys.NotePassive(h.Owner, h.Def);
|
||
any = true;
|
||
}
|
||
if (!splash && SkillMods.Has(u, SkillKeys.AllyHitWarp, true))
|
||
{
|
||
var s = sys.Of(u);
|
||
Vector2 d = ally.Position - u.Position;
|
||
d = d.sqrMagnitude > 1e-6f ? d.normalized : Vector2.up;
|
||
Vector2 spot = battle.Board.ClampInside(ally.Position - d * (u.Radius + ally.Radius + 0.05f), u.Radius);
|
||
float used = Vector2.Distance(o.Path.Count > 0 ? o.Path[0] : u.Position, spot);
|
||
Vector2 start = u.Position;
|
||
if (!Sim.Active)
|
||
{
|
||
u.transform.position = new Vector3(start.x, start.y, 0f);
|
||
Fx.Run(Fx.MoveAlong(u.transform, start, spot, cfg.moveSpeed * 2f, null));
|
||
}
|
||
u.Position = spot;
|
||
o.Path.Add(spot);
|
||
float left = SkillMods.SlingMax(u) - used;
|
||
if (s != null && left >= cfg.minDragDistance)
|
||
{
|
||
s.ReactCredits++;
|
||
s.ReactLimit = left;
|
||
}
|
||
o.Notes.Add(ally.DisplayName + " 곁으로");
|
||
any = true;
|
||
}
|
||
return any;
|
||
}
|
||
|
||
/// <summary>이각 약탈: 이번 광역으로 준 피해 × p1 → 자신과 인접(p2)한 가장 HP 비율이 낮은 다른 아군 회복.</summary>
|
||
void SplashHealLowest(Unit u, int total)
|
||
{
|
||
var e = SkillMods.First(u, SkillKeys.SplashHealLowest, true);
|
||
var sys = SkillSystem.Current;
|
||
if (e == null || total <= 0 || sys == null) return;
|
||
Unit pick = null;
|
||
foreach (var a in battle.AliveUnits(u.Faction))
|
||
{
|
||
if (a == u || !SkillMods.Within(u, a, e.Get(1, 2f))) continue;
|
||
if (pick == null || (float)a.Hp / a.MaxHp < (float)pick.Hp / pick.MaxHp) pick = a;
|
||
}
|
||
if (pick != null) sys.Heal(pick, Mathf.RoundToInt(total * e.P), u);
|
||
}
|
||
}
|
||
}
|