diff --git a/scripts/redraw-readable-tactical-units.py b/scripts/redraw-readable-tactical-units.py new file mode 100644 index 0000000..030b392 --- /dev/null +++ b/scripts/redraw-readable-tactical-units.py @@ -0,0 +1,759 @@ +from __future__ import annotations + +import argparse +import math +from dataclasses import dataclass +from pathlib import Path + +from PIL import Image, ImageChops, ImageDraw +from PIL.PngImagePlugin import PngInfo + + +ROOT = Path(__file__).resolve().parents[1] +UNIT_DIR = ROOT / "src" / "assets" / "images" / "units" +PREVIEW_PATH = ROOT / "tmp" / "readable-tactical-unit-preview.png" + +FRAME_SIZE = 313 +DIRECTIONS = ("south", "east", "north", "west") +IDLE_FRAMES = 8 +WALK_FRAMES = 8 +BASE_FRAMES_PER_DIRECTION = IDLE_FRAMES + WALK_FRAMES +ACTION_ORDER = ("attack", "strategy", "item", "hurt", "celebrate") +ACTION_FRAME_COUNTS = { + "attack": 10, + "strategy": 8, + "item": 8, + "hurt": 4, + "celebrate": 6, +} +ACTION_COLUMN_OFFSETS = { + action: sum(ACTION_FRAME_COUNTS[previous] for previous in ACTION_ORDER[:index]) + for index, action in enumerate(ACTION_ORDER) +} +ACTION_FRAMES_PER_DIRECTION = sum(ACTION_FRAME_COUNTS.values()) +PROCESSING_VERSION = "readable-tactical-v1" + + +Color = tuple[int, int, int] +Rgba = tuple[int, int, int, int] + +INK: Color = (11, 10, 8) +DARK_INK: Color = (4, 4, 4) +HIGHLIGHT: Color = (245, 220, 132) +METAL: Color = (207, 213, 202) +METAL_DARK: Color = (92, 98, 91) +SKIN: Color = (201, 148, 94) +SKIN_DARK: Color = (126, 78, 49) + + +@dataclass(frozen=True) +class Palette: + primary: Color + dark: Color + light: Color + accent: Color + cloth: Color + armor: Color + horse: Color + + +@dataclass(frozen=True) +class UnitSpec: + stem: str + faction: str + role: str + weapon: str + palette: Palette + bulk: float + scale: float + rank: int + cape: bool + helmet: bool + banner: bool + shield: bool + turban: bool + hair: Color + skin: Color + + +@dataclass(frozen=True) +class Motion: + dx: float = 0 + dy: float = 0 + lean: float = 0 + arm: float = 0 + step: float = 0 + lunge: float = 0 + raise_arm: float = 0 + weapon_swing: float = 0 + hurt_shift: float = 0 + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Redraw tactical unit sprite sheets as bold, readable, original map sprites." + ) + parser.add_argument("--only", help="Comma-separated unit stems or file names to redraw.") + parser.add_argument("--preview", default=str(PREVIEW_PATH), help="Preview contact sheet path.") + parser.add_argument("--preview-only", action="store_true", help="Write only the preview contact sheet.") + args = parser.parse_args() + + only = normalize_only(args.only) + stems = discover_unit_stems(only) + rendered: dict[str, tuple[Image.Image, Image.Image]] = {} + + for stem in stems: + spec = unit_spec(stem) + base = draw_base_sheet(spec) + actions = draw_action_sheet(spec) + rendered[stem] = (base.copy(), actions.copy()) + if not args.preview_only: + save_sprite_sheet(base, UNIT_DIR / f"{stem}.png") + save_sprite_sheet(actions, UNIT_DIR / f"{stem}-actions.png") + + write_preview(rendered, Path(args.preview)) + verb = "Previewed" if args.preview_only else "Redrew" + print(f"{verb} {len(stems)} readable tactical unit definitions.") + print(f"Preview contact sheet: {Path(args.preview).resolve()}") + + +def normalize_only(raw: str | None) -> set[str]: + if not raw: + return set() + return { + entry.strip().removesuffix(".png").removesuffix("-actions") + for entry in raw.split(",") + if entry.strip() + } + + +def discover_unit_stems(only: set[str]) -> list[str]: + stems = [ + path.stem + for path in sorted(UNIT_DIR.glob("unit-*.png")) + if not path.name.endswith("-actions.png") + ] + if only: + stems = [stem for stem in stems if stem in only] + if not stems: + raise ValueError("No unit sprite sheets matched the requested selection.") + return stems + + +def unit_spec(stem: str) -> UnitSpec: + lower = stem.lower() + faction = faction_for(lower) + role = role_for(lower) + weapon = weapon_for(lower, role) + rank = 1 + int(any(token in lower for token in ("veteran", "guard", "elite", "warlord", "iron", "bronze"))) + rank += int(any(token in lower for token in ("lu-bu", "cao-cao", "zhao-yun", "ma-chao", "guan-yu", "zhang-fei"))) + palette = palette_for(stem, faction, role, rank) + cape = role in ("lord", "officer", "strategist") or any(token in lower for token in ("liu-bei", "cao-cao", "lu-bu")) + helmet = role not in ("strategist", "shaman") and "rebel-ragged" not in lower + banner = "banner" in lower or role == "lord" or "cao-cao" in lower + shield = "shield" in lower or role == "infantry" + turban = faction == "rebel" or "yellow" in lower + bulk = 1.0 + if role in ("spearman", "officer", "lord"): + bulk += 0.08 + if role == "cavalry": + bulk += 0.16 + if any(token in lower for token in ("zhang-fei", "meng-huo", "lu-bu", "warlord")): + bulk += 0.14 + if role in ("archer", "strategist", "shaman"): + bulk -= 0.06 + scale = 1.0 + min(rank - 1, 2) * 0.04 + hair = (44, 31, 23) + skin = SKIN + if faction == "nanman": + skin = (169, 96, 58) + hair = (30, 22, 18) + return UnitSpec( + stem=stem, + faction=faction, + role=role, + weapon=weapon, + palette=palette, + bulk=bulk, + scale=scale, + rank=rank, + cape=cape, + helmet=helmet, + banner=banner, + shield=shield, + turban=turban, + hair=hair, + skin=skin, + ) + + +def faction_for(lower: str) -> str: + if "nanman" in lower or "meng-huo" in lower: + return "nanman" + if "rebel" in lower: + return "rebel" + if "wei-" in lower or any(token in lower for token in ("cao-cao", "sima-yi")): + return "wei" + if "wu-" in lower or "lu-meng" in lower: + return "wu" + return "shu" + + +def role_for(lower: str) -> str: + if any(token in lower for token in ("zhuge", "sima", "strategist", "shaman", "fa-zheng", "ma-liang", "yi-ji", "pang-tong")): + return "strategist" + if any(token in lower for token in ("archer", "longbow", "crossbow", "huang-zhong")): + return "archer" + if any(token in lower for token in ("cavalry", "zhao-yun", "ma-chao", "ma-dai", "lu-bu")): + return "cavalry" + if any(token in lower for token in ("spearman", "guan-yu", "zhang-fei", "jiang-wei", "yan-yan", "wei-yan")): + return "spearman" + if "liu-bei" in lower: + return "lord" + if any(token in lower for token in ("officer", "leader", "cao-cao", "gong-zhi", "huang-quan", "li-yan", "wu-yi", "wang-ping")): + return "officer" + return "infantry" + + +def weapon_for(lower: str, role: str) -> str: + if "crossbow" in lower: + return "crossbow" + if role == "archer": + return "bow" + if role == "strategist": + return "fan" + if "guan-yu" in lower: + return "glaive" + if any(token in lower for token in ("spearman", "zhang-fei", "jiang-wei", "yan-yan", "wei-yan")): + return "spear" + if role == "cavalry": + return "lance" + if role == "infantry" and "shield" in lower: + return "sword" + if role == "infantry": + return "sword" + return "sword" + + +def palette_for(stem: str, faction: str, role: str, rank: int) -> Palette: + lower = stem.lower() + unique: dict[str, Palette] = { + "unit-liu-bei": Palette((45, 122, 74), (21, 61, 43), (94, 176, 112), (224, 178, 66), (205, 190, 134), (74, 96, 82), (108, 78, 48)), + "unit-guan-yu": Palette((27, 106, 58), (12, 54, 32), (70, 158, 88), (220, 174, 62), (42, 128, 70), (70, 86, 66), (88, 64, 45)), + "unit-zhang-fei": Palette((132, 43, 43), (63, 20, 24), (194, 73, 62), (226, 143, 48), (69, 44, 39), (87, 75, 67), (90, 55, 38)), + "unit-zhao-yun": Palette((218, 219, 205), (77, 92, 106), (246, 244, 224), (96, 151, 190), (108, 156, 184), (155, 164, 156), (210, 206, 190)), + "unit-zhuge-liang": Palette((88, 151, 136), (37, 73, 67), (160, 211, 186), (229, 205, 96), (212, 206, 164), (74, 91, 84), (114, 91, 66)), + "unit-cao-cao": Palette((62, 70, 145), (27, 32, 78), (116, 124, 202), (218, 166, 62), (67, 69, 94), (86, 92, 118), (80, 59, 49)), + "unit-lu-bu": Palette((150, 37, 46), (66, 16, 22), (216, 69, 76), (231, 164, 54), (73, 41, 45), (109, 92, 83), (84, 55, 45)), + "unit-meng-huo": Palette((167, 84, 42), (76, 40, 23), (222, 122, 57), (231, 173, 67), (96, 76, 43), (96, 73, 54), (90, 60, 43)), + } + if stem in unique: + return unique[stem] + + base = { + "shu": Palette((49, 126, 76), (21, 62, 42), (96, 178, 104), (218, 174, 64), (88, 120, 74), (76, 88, 76), (102, 76, 48)), + "wei": Palette((68, 78, 150), (28, 34, 83), (116, 128, 208), (216, 166, 68), (77, 82, 114), (87, 94, 125), (72, 58, 52)), + "wu": Palette((38, 129, 133), (18, 67, 73), (77, 182, 177), (224, 142, 66), (62, 121, 123), (75, 94, 93), (93, 64, 48)), + "rebel": Palette((154, 111, 49), (73, 50, 26), (213, 159, 67), (220, 179, 58), (139, 88, 47), (94, 73, 55), (97, 66, 43)), + "nanman": Palette((171, 84, 45), (76, 39, 25), (225, 126, 62), (217, 171, 64), (113, 92, 49), (90, 72, 54), (90, 62, 45)), + }[faction] + + if role == "strategist": + base = Palette( + lighten(base.primary, 0.14), + base.dark, + lighten(base.light, 0.1), + base.accent, + lighten(base.cloth, 0.2), + base.armor, + base.horse, + ) + if role == "cavalry" and "white" in lower: + base = Palette( + lighten(base.primary, 0.3), + base.dark, + (238, 236, 216), + base.accent, + lighten(base.cloth, 0.2), + base.armor, + (205, 199, 178), + ) + if rank > 1: + base = Palette( + lighten(base.primary, 0.06), + darken(base.dark, 0.05), + lighten(base.light, 0.06), + lighten(base.accent, 0.08), + base.cloth, + lighten(base.armor, 0.08), + base.horse, + ) + return base + + +def lighten(color: Color, amount: float) -> Color: + return tuple(min(255, round(channel + (255 - channel) * amount)) for channel in color) # type: ignore[return-value] + + +def darken(color: Color, amount: float) -> Color: + return tuple(max(0, round(channel * (1 - amount))) for channel in color) # type: ignore[return-value] + + +def draw_base_sheet(spec: UnitSpec) -> Image.Image: + sheet = Image.new("RGBA", (FRAME_SIZE * BASE_FRAMES_PER_DIRECTION, FRAME_SIZE * len(DIRECTIONS)), (0, 0, 0, 0)) + for row, direction in enumerate(DIRECTIONS): + for frame_index in range(IDLE_FRAMES): + frame = render_frame(spec, direction, "idle", frame_index, IDLE_FRAMES) + sheet.alpha_composite(frame, (frame_index * FRAME_SIZE, row * FRAME_SIZE)) + for frame_index in range(WALK_FRAMES): + frame = render_frame(spec, direction, "walk", frame_index, WALK_FRAMES) + sheet.alpha_composite(frame, ((IDLE_FRAMES + frame_index) * FRAME_SIZE, row * FRAME_SIZE)) + return sheet + + +def draw_action_sheet(spec: UnitSpec) -> Image.Image: + sheet = Image.new("RGBA", (FRAME_SIZE * ACTION_FRAMES_PER_DIRECTION, FRAME_SIZE * len(DIRECTIONS)), (0, 0, 0, 0)) + for row, direction in enumerate(DIRECTIONS): + for action in ACTION_ORDER: + frame_count = ACTION_FRAME_COUNTS[action] + start = ACTION_COLUMN_OFFSETS[action] + for frame_index in range(frame_count): + frame = render_frame(spec, direction, action, frame_index, frame_count) + sheet.alpha_composite(frame, ((start + frame_index) * FRAME_SIZE, row * FRAME_SIZE)) + return sheet + + +def render_frame(spec: UnitSpec, direction: str, action: str, frame_index: int, frame_count: int) -> Image.Image: + image = Image.new("RGBA", (FRAME_SIZE, FRAME_SIZE), (0, 0, 0, 0)) + draw = ImageDraw.Draw(image) + motion = motion_for(action, frame_index, frame_count) + cx = 156 + motion.dx + bottom = 282 + motion.dy + if direction == "east": + cx += motion.lunge + elif direction == "west": + cx -= motion.lunge + elif direction == "south": + bottom += motion.lunge * 0.35 + else: + bottom -= motion.lunge * 0.25 + + if action == "strategy": + draw_strategy_effect(draw, direction, cx, bottom, frame_index, frame_count, spec) + elif action == "item": + draw_item_effect(draw, cx, bottom, frame_index, frame_count, spec) + + if spec.role == "cavalry": + draw_cavalry(draw, spec, direction, cx, bottom, motion, action) + else: + draw_human(draw, spec, direction, cx, bottom, motion, action) + + if action == "attack": + draw_attack_effect(draw, spec, direction, cx, bottom, frame_index, frame_count) + elif action == "hurt": + draw_hurt_mark(draw, cx, bottom, frame_index) + elif action == "celebrate": + draw_celebrate_mark(draw, cx, bottom, frame_index, frame_count, spec) + + return flatten_alpha(image) + + +def motion_for(action: str, frame_index: int, frame_count: int) -> Motion: + phase = 2 * math.pi * frame_index / max(1, frame_count) + bob = math.sin(phase) * 3 + step = math.sin(phase) * 1 + if action == "walk": + return Motion(dy=bob, step=step, arm=-step) + if action == "attack": + t = frame_index / max(1, frame_count - 1) + lunge = 26 * math.sin(math.pi * t) + return Motion(dy=-4 * math.sin(math.pi * t), arm=1.0, lunge=lunge, weapon_swing=t) + if action == "strategy": + return Motion(dy=-2 + math.sin(phase) * 2, raise_arm=1.0) + if action == "item": + return Motion(dy=math.sin(phase) * 2, raise_arm=0.7) + if action == "hurt": + return Motion(dx=-9 if frame_index % 2 else 9, dy=2, hurt_shift=1.0) + if action == "celebrate": + return Motion(dy=-4 + math.sin(phase) * 3, raise_arm=1.0) + return Motion(dy=math.sin(phase) * 1.2) + + +def draw_human(draw: ImageDraw.ImageDraw, spec: UnitSpec, direction: str, cx: float, bottom: float, motion: Motion, action: str) -> None: + scale = spec.scale + bulk = spec.bulk + torso_top = bottom - 176 * scale + torso_bottom = bottom - 60 * scale + head_y = bottom - 207 * scale + shoulder = 50 * bulk * scale + waist = 42 * bulk * scale + side = 1 if direction == "east" else -1 if direction == "west" else 0 + back = direction == "north" + + if spec.banner: + draw_banner(draw, cx - 54 * scale if side == 0 else cx - side * 46 * scale, bottom - 190 * scale, spec) + + if spec.cape: + cape_points = [ + (cx - shoulder * 0.85, torso_top + 16), + (cx + shoulder * 0.85, torso_top + 16), + (cx + shoulder * 0.62, torso_bottom + 52), + (cx - shoulder * 0.62, torso_bottom + 52), + ] + draw_poly(draw, cape_points, darken(spec.palette.primary, 0.22), INK, 8) + + leg_color = darken(spec.palette.primary, 0.15) + draw_leg_pair(draw, cx, bottom, waist, scale, leg_color, motion.step, side) + + torso = [ + (cx - shoulder, torso_top), + (cx + shoulder, torso_top), + (cx + waist, torso_bottom), + (cx + waist * 0.6, torso_bottom + 34 * scale), + (cx - waist * 0.6, torso_bottom + 34 * scale), + (cx - waist, torso_bottom), + ] + draw_poly(draw, torso, spec.palette.primary, INK, 10) + draw_poly( + draw, + [ + (cx - shoulder * 0.54, torso_top + 8), + (cx + shoulder * 0.54, torso_top + 8), + (cx + waist * 0.42, torso_bottom - 4), + (cx - waist * 0.42, torso_bottom - 4), + ], + spec.palette.light if spec.role == "strategist" else spec.palette.armor, + INK, + 5, + ) + draw_rect(draw, (cx - waist, torso_bottom - 8, cx + waist, torso_bottom + 8), spec.palette.accent, INK, 5) + draw.line((cx, torso_top + 8, cx, torso_bottom - 8), fill=darken(spec.palette.primary, 0.24), width=5) + + arm_y = torso_top + 30 * scale + left_hand = (cx - shoulder - 18 * scale, arm_y + 48 * scale + motion.arm * 8) + right_hand = (cx + shoulder + 18 * scale, arm_y + 48 * scale - motion.arm * 8) + if side > 0: + right_hand = (cx + shoulder + 42 * scale, arm_y + 26 * scale - motion.arm * 4) + elif side < 0: + left_hand = (cx - shoulder - 42 * scale, arm_y + 26 * scale + motion.arm * 4) + if motion.raise_arm: + right_hand = (right_hand[0], right_hand[1] - 42 * motion.raise_arm) + left_hand = (left_hand[0], left_hand[1] - 22 * motion.raise_arm) + + draw_limb(draw, (cx - shoulder * 0.78, arm_y), left_hand, spec.palette.cloth, 16) + draw_limb(draw, (cx + shoulder * 0.78, arm_y), right_hand, spec.palette.cloth, 16) + draw_ellipse(draw, around(left_hand, 10), spec.skin, INK, 4) + draw_ellipse(draw, around(right_hand, 10), spec.skin, INK, 4) + + if spec.shield and direction != "north": + shield_x = left_hand[0] - 6 if side >= 0 else right_hand[0] + 6 + shield_y = (left_hand[1] + right_hand[1]) / 2 + 4 + draw_shield(draw, shield_x, shield_y, spec) + + draw_weapon(draw, spec, direction, left_hand, right_hand, cx, bottom, motion, action) + draw_head(draw, spec, direction, cx + side * 8 * scale, head_y, scale, back) + + +def draw_cavalry(draw: ImageDraw.ImageDraw, spec: UnitSpec, direction: str, cx: float, bottom: float, motion: Motion, action: str) -> None: + scale = spec.scale + side = 1 if direction == "east" else -1 if direction == "west" else 0 + horse_color = spec.palette.horse + horse_dark = darken(horse_color, 0.28) + if side: + body = (cx - 82 * scale, bottom - 112 * scale, cx + 78 * scale, bottom - 44 * scale) + draw_round(draw, body, horse_color, INK, 10, 26) + head_x = cx + side * 88 * scale + draw_ellipse(draw, (head_x - 28 * scale, bottom - 140 * scale, head_x + 28 * scale, bottom - 82 * scale), horse_color, INK, 9) + draw_poly(draw, [(head_x + side * 14 * scale, bottom - 138 * scale), (head_x + side * 40 * scale, bottom - 158 * scale), (head_x + side * 28 * scale, bottom - 118 * scale)], horse_color, INK, 7) + draw_limb(draw, (cx - 52 * scale, bottom - 48 * scale), (cx - 68 * scale + motion.step * 12, bottom - 4 * scale), horse_dark, 15) + draw_limb(draw, (cx - 18 * scale, bottom - 46 * scale), (cx - 8 * scale - motion.step * 16, bottom - 2 * scale), horse_dark, 15) + draw_limb(draw, (cx + 26 * scale, bottom - 46 * scale), (cx + 42 * scale + motion.step * 16, bottom - 3 * scale), horse_dark, 15) + draw_limb(draw, (cx + 58 * scale, bottom - 48 * scale), (cx + 66 * scale - motion.step * 12, bottom - 2 * scale), horse_dark, 15) + draw_limb(draw, (cx - side * 82 * scale, bottom - 92 * scale), (cx - side * 112 * scale, bottom - 126 * scale), spec.palette.dark, 13) + else: + body = (cx - 62 * scale, bottom - 128 * scale, cx + 62 * scale, bottom - 40 * scale) + draw_round(draw, body, horse_color, INK, 10, 28) + draw_ellipse(draw, (cx - 40 * scale, bottom - 164 * scale, cx + 40 * scale, bottom - 96 * scale), horse_color, INK, 9) + draw_limb(draw, (cx - 38 * scale, bottom - 48 * scale), (cx - 56 * scale, bottom - 2 * scale), horse_dark, 16) + draw_limb(draw, (cx + 38 * scale, bottom - 48 * scale), (cx + 56 * scale, bottom - 2 * scale), horse_dark, 16) + draw_limb(draw, (cx - 12 * scale, bottom - 46 * scale), (cx - 16 * scale, bottom - 2 * scale), horse_dark, 13) + draw_limb(draw, (cx + 12 * scale, bottom - 46 * scale), (cx + 16 * scale, bottom - 2 * scale), horse_dark, 13) + + rider_bottom = bottom - 88 * scale + rider_spec = UnitSpec( + **{ + **spec.__dict__, + "role": "officer", + "shield": False, + "banner": False, + "scale": spec.scale * 0.82, + "bulk": max(0.95, spec.bulk - 0.08), + } + ) + draw_human(draw, rider_spec, direction, cx, rider_bottom, motion, action) + + +def draw_leg_pair(draw: ImageDraw.ImageDraw, cx: float, bottom: float, waist: float, scale: float, color: Color, step: float, side: int) -> None: + if side: + draw_limb(draw, (cx - 18 * scale, bottom - 60 * scale), (cx - 34 * scale - step * 6, bottom - 7 * scale), color, 18) + draw_limb(draw, (cx + 20 * scale, bottom - 60 * scale), (cx + 36 * scale + step * 7, bottom - 7 * scale), color, 18) + else: + draw_limb(draw, (cx - waist * 0.45, bottom - 62 * scale), (cx - 36 * scale - step * 7, bottom - 8 * scale), color, 18) + draw_limb(draw, (cx + waist * 0.45, bottom - 62 * scale), (cx + 36 * scale + step * 7, bottom - 8 * scale), color, 18) + draw_ellipse(draw, (cx - 58 * scale, bottom - 18 * scale, cx - 16 * scale, bottom + 2 * scale), darken(color, 0.2), INK, 4) + draw_ellipse(draw, (cx + 16 * scale, bottom - 18 * scale, cx + 58 * scale, bottom + 2 * scale), darken(color, 0.2), INK, 4) + + +def draw_head(draw: ImageDraw.ImageDraw, spec: UnitSpec, direction: str, cx: float, cy: float, scale: float, back: bool) -> None: + r = 27 * scale + draw_ellipse(draw, (cx - r, cy - r, cx + r, cy + r), spec.skin, INK, 8) + if spec.turban: + draw_round(draw, (cx - r * 1.15, cy - r * 0.98, cx + r * 1.15, cy - r * 0.33), spec.palette.accent, INK, 5, 10) + draw.line((cx - r * 0.9, cy - r * 0.36, cx + r * 0.9, cy - r * 0.36), fill=darken(spec.palette.accent, 0.25), width=5) + elif spec.helmet: + draw_poly(draw, [(cx - r * 1.08, cy - r * 0.45), (cx, cy - r * 1.34), (cx + r * 1.08, cy - r * 0.45)], spec.palette.armor, INK, 6) + draw_rect(draw, (cx - r * 0.92, cy - r * 0.58, cx + r * 0.92, cy - r * 0.22), spec.palette.accent, INK, 4) + else: + draw_ellipse(draw, (cx - r * 1.08, cy - r * 1.1, cx + r * 1.08, cy - r * 0.1), spec.hair, INK, 5) + + if not back: + eye_y = cy - r * 0.04 + draw.line((cx - r * 0.52, eye_y, cx - r * 0.18, eye_y + 1), fill=DARK_INK, width=4) + draw.line((cx + r * 0.18, eye_y + 1, cx + r * 0.52, eye_y), fill=DARK_INK, width=4) + if spec.stem in ("unit-guan-yu", "unit-zhang-fei"): + draw.line((cx - r * 0.38, cy + r * 0.42, cx + r * 0.38, cy + r * 0.42), fill=spec.hair, width=8) + draw.line((cx, cy + r * 0.42, cx, cy + r * 1.05), fill=spec.hair, width=8) + + +def draw_weapon( + draw: ImageDraw.ImageDraw, + spec: UnitSpec, + direction: str, + left_hand: tuple[float, float], + right_hand: tuple[float, float], + cx: float, + bottom: float, + motion: Motion, + action: str, +) -> None: + side = 1 if direction == "east" else -1 if direction == "west" else 0 + hand = right_hand if direction != "west" else left_hand + if spec.weapon in ("spear", "glaive", "lance"): + if side: + start = (hand[0] - side * 32, hand[1] + 34) + end = (hand[0] + side * (106 + motion.lunge * 0.6), hand[1] - 54) + elif direction == "north": + start = (cx + 36, bottom - 48) + end = (cx - 32, bottom - 236) + else: + start = (cx + 45, bottom - 38) + end = (cx - 38, bottom - 238) + draw_limb(draw, start, end, (92, 59, 31), 11) + blade = 30 if spec.weapon != "glaive" else 42 + draw_poly( + draw, + [ + (end[0], end[1] - blade), + (end[0] + (18 if side >= 0 else -18), end[1] + 4), + (end[0], end[1] + 18), + (end[0] - (18 if side >= 0 else -18), end[1] + 4), + ], + METAL, + INK, + 5, + ) + if spec.weapon == "glaive": + draw_poly(draw, [(end[0] + 5, end[1] - 6), (end[0] + 40, end[1] + 22), (end[0] + 8, end[1] + 35)], METAL, INK, 5) + elif spec.weapon in ("bow", "crossbow"): + bow_cx = hand[0] + (side or 1) * 22 + bow_cy = hand[1] - 22 + if spec.weapon == "crossbow": + draw_limb(draw, (bow_cx - 44, bow_cy), (bow_cx + 44, bow_cy), (100, 57, 30), 12) + draw_limb(draw, (bow_cx, bow_cy - 32), (bow_cx, bow_cy + 32), (100, 57, 30), 9) + draw_limb(draw, (bow_cx - 64, bow_cy - 6), (bow_cx + 72, bow_cy - 6), METAL, 5) + else: + bbox = (bow_cx - 42, bow_cy - 72, bow_cx + 42, bow_cy + 72) + draw.arc(bbox, 255 if side < 0 else -75, 105 if side < 0 else 75, fill=INK, width=14) + draw.arc(bbox, 255 if side < 0 else -75, 105 if side < 0 else 75, fill=(118, 68, 34), width=7) + draw.line((bow_cx, bow_cy - 68, bow_cx, bow_cy + 68), fill=METAL_DARK, width=3) + draw_limb(draw, (bow_cx - 48 * (side or -1), bow_cy), (bow_cx + 62 * (side or 1), bow_cy - 8), METAL, 5) + elif spec.weapon == "fan": + fan_cx = hand[0] + fan_cy = hand[1] - 16 + fan_points = [ + (fan_cx, fan_cy), + (fan_cx + 56, fan_cy - 44), + (fan_cx + 78, fan_cy + 20), + (fan_cx + 10, fan_cy + 32), + ] + if direction == "west": + fan_points = [(2 * fan_cx - x, y) for x, y in fan_points] + draw_poly(draw, fan_points, (230, 220, 172), INK, 6) + for angle in (-36, -15, 8, 28): + dx = math.cos(math.radians(angle)) * 66 + dy = math.sin(math.radians(angle)) * 66 + if direction == "west": + dx *= -1 + draw.line((fan_cx, fan_cy, fan_cx + dx, fan_cy + dy), fill=darken(spec.palette.accent, 0.1), width=3) + else: + if side: + end = (hand[0] + side * (76 + motion.lunge * 0.4), hand[1] - 56) + elif direction == "north": + end = (hand[0] - 38, hand[1] - 72) + else: + end = (hand[0] + 52, hand[1] - 74) + draw_limb(draw, hand, end, METAL, 10) + draw_rect(draw, (hand[0] - 22, hand[1] - 8, hand[0] + 22, hand[1] + 8), spec.palette.accent, INK, 4) + + +def draw_shield(draw: ImageDraw.ImageDraw, cx: float, cy: float, spec: UnitSpec) -> None: + points = [(cx, cy - 42), (cx + 34, cy - 22), (cx + 24, cy + 38), (cx, cy + 54), (cx - 24, cy + 38), (cx - 34, cy - 22)] + draw_poly(draw, points, spec.palette.armor, INK, 7) + draw.line((cx, cy - 30, cx, cy + 38), fill=spec.palette.accent, width=5) + + +def draw_banner(draw: ImageDraw.ImageDraw, x: float, y: float, spec: UnitSpec) -> None: + draw_limb(draw, (x, y + 100), (x, y - 34), (89, 55, 30), 8) + flag = [(x, y - 34), (x + 58, y - 22), (x + 46, y + 28), (x, y + 18)] + draw_poly(draw, flag, spec.palette.accent, INK, 5) + draw.line((x + 11, y - 13, x + 42, y - 7), fill=darken(spec.palette.accent, 0.35), width=5) + + +def draw_attack_effect(draw: ImageDraw.ImageDraw, spec: UnitSpec, direction: str, cx: float, bottom: float, frame_index: int, frame_count: int) -> None: + t = frame_index / max(1, frame_count - 1) + if t < 0.28 or t > 0.82: + return + side = 1 if direction == "east" else -1 if direction == "west" else 0 + color = lighten(spec.palette.accent, 0.18) + if spec.weapon in ("bow", "crossbow", "fan"): + return + if side: + points = [(cx + side * 24, bottom - 190), (cx + side * 126, bottom - 132), (cx + side * 104, bottom - 72)] + elif direction == "north": + points = [(cx - 70, bottom - 142), (cx + 4, bottom - 238), (cx + 80, bottom - 154)] + else: + points = [(cx - 78, bottom - 168), (cx + 8, bottom - 72), (cx + 88, bottom - 166)] + draw.line(points, fill=INK, width=17, joint="curve") + draw.line(points, fill=color, width=9, joint="curve") + draw.line(points, fill=(250, 238, 180), width=4, joint="curve") + + +def draw_strategy_effect(draw: ImageDraw.ImageDraw, direction: str, cx: float, bottom: float, frame_index: int, frame_count: int, spec: UnitSpec) -> None: + if frame_index % 2: + return + center = (cx, bottom - 130) + radius = 62 + 5 * (frame_index % 3) + draw.ellipse((center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius), outline=INK, width=8) + draw.ellipse((center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius), outline=spec.palette.accent, width=4) + + +def draw_item_effect(draw: ImageDraw.ImageDraw, cx: float, bottom: float, frame_index: int, frame_count: int, spec: UnitSpec) -> None: + y = bottom - 226 - 4 * math.sin(frame_index / max(1, frame_count) * 2 * math.pi) + draw_ellipse(draw, (cx - 18, y - 18, cx + 18, y + 18), spec.palette.accent, INK, 5) + + +def draw_hurt_mark(draw: ImageDraw.ImageDraw, cx: float, bottom: float, frame_index: int) -> None: + color = (219, 52, 42) + for dx, dy in ((-52, -178), (55, -156), (-18, -220)): + draw.line((cx + dx - 10, bottom + dy - 10, cx + dx + 10, bottom + dy + 10), fill=INK, width=8) + draw.line((cx + dx + 10, bottom + dy - 10, cx + dx - 10, bottom + dy + 10), fill=INK, width=8) + draw.line((cx + dx - 10, bottom + dy - 10, cx + dx + 10, bottom + dy + 10), fill=color, width=4) + draw.line((cx + dx + 10, bottom + dy - 10, cx + dx - 10, bottom + dy + 10), fill=color, width=4) + + +def draw_celebrate_mark(draw: ImageDraw.ImageDraw, cx: float, bottom: float, frame_index: int, frame_count: int, spec: UnitSpec) -> None: + angle = frame_index / max(1, frame_count) * 2 * math.pi + for index in range(3): + x = cx + math.cos(angle + index * 2.1) * 62 + y = bottom - 214 + math.sin(angle + index * 2.1) * 22 + draw_poly(draw, [(x, y - 10), (x + 8, y), (x, y + 10), (x - 8, y)], spec.palette.accent, INK, 3) + + +def draw_limb(draw: ImageDraw.ImageDraw, start: tuple[float, float], end: tuple[float, float], fill: Color, width: int) -> None: + draw.line((start[0], start[1], end[0], end[1]), fill=INK, width=width + 8) + draw.line((start[0], start[1], end[0], end[1]), fill=fill, width=width) + + +def draw_poly(draw: ImageDraw.ImageDraw, points: list[tuple[float, float]], fill: Color, outline: Color, width: int) -> None: + draw.line(points + [points[0]], fill=outline, width=width, joint="curve") + draw.polygon(points, fill=fill) + draw.line(points + [points[0]], fill=outline, width=max(2, width // 2), joint="curve") + + +def draw_rect(draw: ImageDraw.ImageDraw, box: tuple[float, float, float, float], fill: Color, outline: Color, width: int) -> None: + draw.rectangle(box, fill=fill, outline=outline, width=width) + + +def draw_round(draw: ImageDraw.ImageDraw, box: tuple[float, float, float, float], fill: Color, outline: Color, width: int, radius: int) -> None: + draw.rounded_rectangle(box, radius=radius, fill=fill, outline=outline, width=width) + + +def draw_ellipse(draw: ImageDraw.ImageDraw, box: tuple[float, float, float, float], fill: Color, outline: Color, width: int) -> None: + draw.ellipse(box, fill=fill, outline=outline, width=width) + + +def around(point: tuple[float, float], radius: float) -> tuple[float, float, float, float]: + return (point[0] - radius, point[1] - radius, point[0] + radius, point[1] + radius) + + +def flatten_alpha(image: Image.Image) -> Image.Image: + image = image.convert("RGBA") + alpha = image.getchannel("A").point(lambda value: 0 if value < 8 else 255) + clear = Image.new("RGBA", image.size, (0, 0, 0, 0)) + image.putalpha(alpha) + return Image.composite(image, clear, alpha) + + +def save_sprite_sheet(image: Image.Image, path: Path) -> None: + image = flatten_alpha(image) + png_info = PngInfo() + png_info.add_text("heros_unit_sprite", PROCESSING_VERSION) + image.save(path, optimize=True, pnginfo=png_info) + + +def write_preview(rendered: dict[str, tuple[Image.Image, Image.Image]], path: Path) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + stems = list(rendered.keys()) + thumb = 64 + cols = 16 + rows_per_unit = 8 + label_h = 20 + width = cols * thumb + 190 + height = max(1, len(stems)) * (rows_per_unit * thumb + label_h) + preview = Image.new("RGBA", (width, height), (28, 32, 27, 255)) + draw = ImageDraw.Draw(preview) + for unit_index, stem in enumerate(stems): + y0 = unit_index * (rows_per_unit * thumb + label_h) + spec = unit_spec(stem) + draw.rectangle((0, y0, width, y0 + label_h), fill=(48, 57, 39)) + draw.text((8, y0 + 4), f"{stem} role={spec.role} weapon={spec.weapon}", fill=(232, 224, 190)) + base, actions = rendered[stem] + frames: list[Image.Image] = [] + for row in range(4): + for col in range(BASE_FRAMES_PER_DIRECTION): + frames.append(crop_frame(base, row, col)) + action_frames: list[Image.Image] = [] + for row in range(4): + for col in range(10): + action_frames.append(crop_frame(actions, row, col)) + sample_frames = frames[:64] + action_frames[:64] + for index, frame in enumerate(sample_frames[: rows_per_unit * cols]): + col = index % cols + row = index // cols + x = 190 + col * thumb + y = y0 + label_h + row * thumb + tile = Image.new("RGBA", (FRAME_SIZE, FRAME_SIZE), (80, 94, 58, 255)) + grid = ImageDraw.Draw(tile) + grid.line((0, 0, FRAME_SIZE, 0), fill=(23, 31, 24), width=8) + grid.line((0, 0, 0, FRAME_SIZE), fill=(23, 31, 24), width=8) + tile.alpha_composite(frame) + preview.alpha_composite(tile.resize((thumb, thumb), Image.Resampling.LANCZOS), (x, y)) + preview.save(path, optimize=True) + + +def crop_frame(sheet: Image.Image, row: int, col: int) -> Image.Image: + return sheet.crop((col * FRAME_SIZE, row * FRAME_SIZE, (col + 1) * FRAME_SIZE, (row + 1) * FRAME_SIZE)) + + +if __name__ == "__main__": + main() diff --git a/src/assets/images/units/unit-cao-cao-actions.png b/src/assets/images/units/unit-cao-cao-actions.png index 6a36710..d9d7481 100644 Binary files a/src/assets/images/units/unit-cao-cao-actions.png and b/src/assets/images/units/unit-cao-cao-actions.png differ diff --git a/src/assets/images/units/unit-cao-cao.png b/src/assets/images/units/unit-cao-cao.png index ba077df..a3908d2 100644 Binary files a/src/assets/images/units/unit-cao-cao.png and b/src/assets/images/units/unit-cao-cao.png differ diff --git a/src/assets/images/units/unit-fa-zheng-actions.png b/src/assets/images/units/unit-fa-zheng-actions.png index 6d4d0b4..e1d2470 100644 Binary files a/src/assets/images/units/unit-fa-zheng-actions.png and b/src/assets/images/units/unit-fa-zheng-actions.png differ diff --git a/src/assets/images/units/unit-fa-zheng.png b/src/assets/images/units/unit-fa-zheng.png index 66c2251..e30dcaf 100644 Binary files a/src/assets/images/units/unit-fa-zheng.png and b/src/assets/images/units/unit-fa-zheng.png differ diff --git a/src/assets/images/units/unit-gong-zhi-actions.png b/src/assets/images/units/unit-gong-zhi-actions.png index ac6a835..e84f1fc 100644 Binary files a/src/assets/images/units/unit-gong-zhi-actions.png and b/src/assets/images/units/unit-gong-zhi-actions.png differ diff --git a/src/assets/images/units/unit-gong-zhi.png b/src/assets/images/units/unit-gong-zhi.png index dd672ab..aff0c74 100644 Binary files a/src/assets/images/units/unit-gong-zhi.png and b/src/assets/images/units/unit-gong-zhi.png differ diff --git a/src/assets/images/units/unit-guan-yu-actions.png b/src/assets/images/units/unit-guan-yu-actions.png index 724f7df..ec83751 100644 Binary files a/src/assets/images/units/unit-guan-yu-actions.png and b/src/assets/images/units/unit-guan-yu-actions.png differ diff --git a/src/assets/images/units/unit-guan-yu.png b/src/assets/images/units/unit-guan-yu.png index 0bc6f34..320fa3d 100644 Binary files a/src/assets/images/units/unit-guan-yu.png and b/src/assets/images/units/unit-guan-yu.png differ diff --git a/src/assets/images/units/unit-huang-quan-actions.png b/src/assets/images/units/unit-huang-quan-actions.png index ac6a835..e84f1fc 100644 Binary files a/src/assets/images/units/unit-huang-quan-actions.png and b/src/assets/images/units/unit-huang-quan-actions.png differ diff --git a/src/assets/images/units/unit-huang-quan.png b/src/assets/images/units/unit-huang-quan.png index dd672ab..aff0c74 100644 Binary files a/src/assets/images/units/unit-huang-quan.png and b/src/assets/images/units/unit-huang-quan.png differ diff --git a/src/assets/images/units/unit-huang-zhong-actions.png b/src/assets/images/units/unit-huang-zhong-actions.png index 0b289cd..79b4235 100644 Binary files a/src/assets/images/units/unit-huang-zhong-actions.png and b/src/assets/images/units/unit-huang-zhong-actions.png differ diff --git a/src/assets/images/units/unit-huang-zhong.png b/src/assets/images/units/unit-huang-zhong.png index 3406210..635d222 100644 Binary files a/src/assets/images/units/unit-huang-zhong.png and b/src/assets/images/units/unit-huang-zhong.png differ diff --git a/src/assets/images/units/unit-jiang-wei-actions.png b/src/assets/images/units/unit-jiang-wei-actions.png index 0d08eff..da27601 100644 Binary files a/src/assets/images/units/unit-jiang-wei-actions.png and b/src/assets/images/units/unit-jiang-wei-actions.png differ diff --git a/src/assets/images/units/unit-jiang-wei.png b/src/assets/images/units/unit-jiang-wei.png index ddda0f6..91f0842 100644 Binary files a/src/assets/images/units/unit-jiang-wei.png and b/src/assets/images/units/unit-jiang-wei.png differ diff --git a/src/assets/images/units/unit-li-yan-actions.png b/src/assets/images/units/unit-li-yan-actions.png index ac6a835..e84f1fc 100644 Binary files a/src/assets/images/units/unit-li-yan-actions.png and b/src/assets/images/units/unit-li-yan-actions.png differ diff --git a/src/assets/images/units/unit-li-yan.png b/src/assets/images/units/unit-li-yan.png index dd672ab..aff0c74 100644 Binary files a/src/assets/images/units/unit-li-yan.png and b/src/assets/images/units/unit-li-yan.png differ diff --git a/src/assets/images/units/unit-liu-bei-actions.png b/src/assets/images/units/unit-liu-bei-actions.png index 6d0741a..1dd9abe 100644 Binary files a/src/assets/images/units/unit-liu-bei-actions.png and b/src/assets/images/units/unit-liu-bei-actions.png differ diff --git a/src/assets/images/units/unit-liu-bei.png b/src/assets/images/units/unit-liu-bei.png index a2a8758..10c2df7 100644 Binary files a/src/assets/images/units/unit-liu-bei.png and b/src/assets/images/units/unit-liu-bei.png differ diff --git a/src/assets/images/units/unit-lu-bu-actions.png b/src/assets/images/units/unit-lu-bu-actions.png index c110f78..38d3a8f 100644 Binary files a/src/assets/images/units/unit-lu-bu-actions.png and b/src/assets/images/units/unit-lu-bu-actions.png differ diff --git a/src/assets/images/units/unit-lu-bu.png b/src/assets/images/units/unit-lu-bu.png index a1ea62b..b42ecae 100644 Binary files a/src/assets/images/units/unit-lu-bu.png and b/src/assets/images/units/unit-lu-bu.png differ diff --git a/src/assets/images/units/unit-lu-meng-actions.png b/src/assets/images/units/unit-lu-meng-actions.png index 8c3888c..97b11ac 100644 Binary files a/src/assets/images/units/unit-lu-meng-actions.png and b/src/assets/images/units/unit-lu-meng-actions.png differ diff --git a/src/assets/images/units/unit-lu-meng.png b/src/assets/images/units/unit-lu-meng.png index 52c9ed6..f18c348 100644 Binary files a/src/assets/images/units/unit-lu-meng.png and b/src/assets/images/units/unit-lu-meng.png differ diff --git a/src/assets/images/units/unit-ma-chao-actions.png b/src/assets/images/units/unit-ma-chao-actions.png index 5cf9605..19b15c1 100644 Binary files a/src/assets/images/units/unit-ma-chao-actions.png and b/src/assets/images/units/unit-ma-chao-actions.png differ diff --git a/src/assets/images/units/unit-ma-chao.png b/src/assets/images/units/unit-ma-chao.png index 823b8fb..34e9552 100644 Binary files a/src/assets/images/units/unit-ma-chao.png and b/src/assets/images/units/unit-ma-chao.png differ diff --git a/src/assets/images/units/unit-ma-dai-actions.png b/src/assets/images/units/unit-ma-dai-actions.png index 4b8be11..2fa2f68 100644 Binary files a/src/assets/images/units/unit-ma-dai-actions.png and b/src/assets/images/units/unit-ma-dai-actions.png differ diff --git a/src/assets/images/units/unit-ma-dai.png b/src/assets/images/units/unit-ma-dai.png index 2c1ec61..17a32d6 100644 Binary files a/src/assets/images/units/unit-ma-dai.png and b/src/assets/images/units/unit-ma-dai.png differ diff --git a/src/assets/images/units/unit-ma-liang-actions.png b/src/assets/images/units/unit-ma-liang-actions.png index 6d4d0b4..e1d2470 100644 Binary files a/src/assets/images/units/unit-ma-liang-actions.png and b/src/assets/images/units/unit-ma-liang-actions.png differ diff --git a/src/assets/images/units/unit-ma-liang.png b/src/assets/images/units/unit-ma-liang.png index 66c2251..e30dcaf 100644 Binary files a/src/assets/images/units/unit-ma-liang.png and b/src/assets/images/units/unit-ma-liang.png differ diff --git a/src/assets/images/units/unit-meng-huo-actions.png b/src/assets/images/units/unit-meng-huo-actions.png index bdc7a1f..d18cd33 100644 Binary files a/src/assets/images/units/unit-meng-huo-actions.png and b/src/assets/images/units/unit-meng-huo-actions.png differ diff --git a/src/assets/images/units/unit-meng-huo.png b/src/assets/images/units/unit-meng-huo.png index ecb397f..1f79419 100644 Binary files a/src/assets/images/units/unit-meng-huo.png and b/src/assets/images/units/unit-meng-huo.png differ diff --git a/src/assets/images/units/unit-nanman-infantry-actions.png b/src/assets/images/units/unit-nanman-infantry-actions.png index 52163bc..85fc41a 100644 Binary files a/src/assets/images/units/unit-nanman-infantry-actions.png and b/src/assets/images/units/unit-nanman-infantry-actions.png differ diff --git a/src/assets/images/units/unit-nanman-infantry-jungle-actions.png b/src/assets/images/units/unit-nanman-infantry-jungle-actions.png index 52163bc..85fc41a 100644 Binary files a/src/assets/images/units/unit-nanman-infantry-jungle-actions.png and b/src/assets/images/units/unit-nanman-infantry-jungle-actions.png differ diff --git a/src/assets/images/units/unit-nanman-infantry-jungle.png b/src/assets/images/units/unit-nanman-infantry-jungle.png index 28b53a2..fe441c0 100644 Binary files a/src/assets/images/units/unit-nanman-infantry-jungle.png and b/src/assets/images/units/unit-nanman-infantry-jungle.png differ diff --git a/src/assets/images/units/unit-nanman-infantry-spear-actions.png b/src/assets/images/units/unit-nanman-infantry-spear-actions.png index 52163bc..85fc41a 100644 Binary files a/src/assets/images/units/unit-nanman-infantry-spear-actions.png and b/src/assets/images/units/unit-nanman-infantry-spear-actions.png differ diff --git a/src/assets/images/units/unit-nanman-infantry-spear.png b/src/assets/images/units/unit-nanman-infantry-spear.png index 28b53a2..fe441c0 100644 Binary files a/src/assets/images/units/unit-nanman-infantry-spear.png and b/src/assets/images/units/unit-nanman-infantry-spear.png differ diff --git a/src/assets/images/units/unit-nanman-infantry.png b/src/assets/images/units/unit-nanman-infantry.png index 28b53a2..fe441c0 100644 Binary files a/src/assets/images/units/unit-nanman-infantry.png and b/src/assets/images/units/unit-nanman-infantry.png differ diff --git a/src/assets/images/units/unit-nanman-officer-actions.png b/src/assets/images/units/unit-nanman-officer-actions.png index 7404b3d..4836ed7 100644 Binary files a/src/assets/images/units/unit-nanman-officer-actions.png and b/src/assets/images/units/unit-nanman-officer-actions.png differ diff --git a/src/assets/images/units/unit-nanman-officer-bronze-actions.png b/src/assets/images/units/unit-nanman-officer-bronze-actions.png index 7404b3d..9e8fd8a 100644 Binary files a/src/assets/images/units/unit-nanman-officer-bronze-actions.png and b/src/assets/images/units/unit-nanman-officer-bronze-actions.png differ diff --git a/src/assets/images/units/unit-nanman-officer-bronze.png b/src/assets/images/units/unit-nanman-officer-bronze.png index ca74a0b..e9f7fb7 100644 Binary files a/src/assets/images/units/unit-nanman-officer-bronze.png and b/src/assets/images/units/unit-nanman-officer-bronze.png differ diff --git a/src/assets/images/units/unit-nanman-officer-warlord-actions.png b/src/assets/images/units/unit-nanman-officer-warlord-actions.png index 7404b3d..6ef558e 100644 Binary files a/src/assets/images/units/unit-nanman-officer-warlord-actions.png and b/src/assets/images/units/unit-nanman-officer-warlord-actions.png differ diff --git a/src/assets/images/units/unit-nanman-officer-warlord.png b/src/assets/images/units/unit-nanman-officer-warlord.png index ca74a0b..827bc1f 100644 Binary files a/src/assets/images/units/unit-nanman-officer-warlord.png and b/src/assets/images/units/unit-nanman-officer-warlord.png differ diff --git a/src/assets/images/units/unit-nanman-officer.png b/src/assets/images/units/unit-nanman-officer.png index ca74a0b..877764d 100644 Binary files a/src/assets/images/units/unit-nanman-officer.png and b/src/assets/images/units/unit-nanman-officer.png differ diff --git a/src/assets/images/units/unit-nanman-shaman-actions.png b/src/assets/images/units/unit-nanman-shaman-actions.png index ca54c56..1361fdc 100644 Binary files a/src/assets/images/units/unit-nanman-shaman-actions.png and b/src/assets/images/units/unit-nanman-shaman-actions.png differ diff --git a/src/assets/images/units/unit-nanman-shaman-ember-actions.png b/src/assets/images/units/unit-nanman-shaman-ember-actions.png index ca54c56..1361fdc 100644 Binary files a/src/assets/images/units/unit-nanman-shaman-ember-actions.png and b/src/assets/images/units/unit-nanman-shaman-ember-actions.png differ diff --git a/src/assets/images/units/unit-nanman-shaman-ember.png b/src/assets/images/units/unit-nanman-shaman-ember.png index 452124c..6354e20 100644 Binary files a/src/assets/images/units/unit-nanman-shaman-ember.png and b/src/assets/images/units/unit-nanman-shaman-ember.png differ diff --git a/src/assets/images/units/unit-nanman-shaman-storm-actions.png b/src/assets/images/units/unit-nanman-shaman-storm-actions.png index ca54c56..1361fdc 100644 Binary files a/src/assets/images/units/unit-nanman-shaman-storm-actions.png and b/src/assets/images/units/unit-nanman-shaman-storm-actions.png differ diff --git a/src/assets/images/units/unit-nanman-shaman-storm.png b/src/assets/images/units/unit-nanman-shaman-storm.png index 452124c..6354e20 100644 Binary files a/src/assets/images/units/unit-nanman-shaman-storm.png and b/src/assets/images/units/unit-nanman-shaman-storm.png differ diff --git a/src/assets/images/units/unit-nanman-shaman.png b/src/assets/images/units/unit-nanman-shaman.png index 452124c..6354e20 100644 Binary files a/src/assets/images/units/unit-nanman-shaman.png and b/src/assets/images/units/unit-nanman-shaman.png differ diff --git a/src/assets/images/units/unit-pang-tong-actions.png b/src/assets/images/units/unit-pang-tong-actions.png index 6d4d0b4..e1d2470 100644 Binary files a/src/assets/images/units/unit-pang-tong-actions.png and b/src/assets/images/units/unit-pang-tong-actions.png differ diff --git a/src/assets/images/units/unit-pang-tong.png b/src/assets/images/units/unit-pang-tong.png index 66c2251..e30dcaf 100644 Binary files a/src/assets/images/units/unit-pang-tong.png and b/src/assets/images/units/unit-pang-tong.png differ diff --git a/src/assets/images/units/unit-rebel-actions.png b/src/assets/images/units/unit-rebel-actions.png index a8e2eca..0e529ff 100644 Binary files a/src/assets/images/units/unit-rebel-actions.png and b/src/assets/images/units/unit-rebel-actions.png differ diff --git a/src/assets/images/units/unit-rebel-archer-actions.png b/src/assets/images/units/unit-rebel-archer-actions.png index e2a27dd..2dca943 100644 Binary files a/src/assets/images/units/unit-rebel-archer-actions.png and b/src/assets/images/units/unit-rebel-archer-actions.png differ diff --git a/src/assets/images/units/unit-rebel-archer-fire-actions.png b/src/assets/images/units/unit-rebel-archer-fire-actions.png index e2a27dd..2dca943 100644 Binary files a/src/assets/images/units/unit-rebel-archer-fire-actions.png and b/src/assets/images/units/unit-rebel-archer-fire-actions.png differ diff --git a/src/assets/images/units/unit-rebel-archer-fire.png b/src/assets/images/units/unit-rebel-archer-fire.png index ef405fd..3b5afbe 100644 Binary files a/src/assets/images/units/unit-rebel-archer-fire.png and b/src/assets/images/units/unit-rebel-archer-fire.png differ diff --git a/src/assets/images/units/unit-rebel-archer-veteran-actions.png b/src/assets/images/units/unit-rebel-archer-veteran-actions.png index b14fcaf..477110b 100644 Binary files a/src/assets/images/units/unit-rebel-archer-veteran-actions.png and b/src/assets/images/units/unit-rebel-archer-veteran-actions.png differ diff --git a/src/assets/images/units/unit-rebel-archer-veteran.png b/src/assets/images/units/unit-rebel-archer-veteran.png index ab81945..f186a40 100644 Binary files a/src/assets/images/units/unit-rebel-archer-veteran.png and b/src/assets/images/units/unit-rebel-archer-veteran.png differ diff --git a/src/assets/images/units/unit-rebel-archer.png b/src/assets/images/units/unit-rebel-archer.png index ef405fd..3b5afbe 100644 Binary files a/src/assets/images/units/unit-rebel-archer.png and b/src/assets/images/units/unit-rebel-archer.png differ diff --git a/src/assets/images/units/unit-rebel-cavalry-actions.png b/src/assets/images/units/unit-rebel-cavalry-actions.png index 37f2eb0..33e4484 100644 Binary files a/src/assets/images/units/unit-rebel-cavalry-actions.png and b/src/assets/images/units/unit-rebel-cavalry-actions.png differ diff --git a/src/assets/images/units/unit-rebel-cavalry-veteran-actions.png b/src/assets/images/units/unit-rebel-cavalry-veteran-actions.png index 83d5e27..db25403 100644 Binary files a/src/assets/images/units/unit-rebel-cavalry-veteran-actions.png and b/src/assets/images/units/unit-rebel-cavalry-veteran-actions.png differ diff --git a/src/assets/images/units/unit-rebel-cavalry-veteran.png b/src/assets/images/units/unit-rebel-cavalry-veteran.png index c59a1d5..61f18ab 100644 Binary files a/src/assets/images/units/unit-rebel-cavalry-veteran.png and b/src/assets/images/units/unit-rebel-cavalry-veteran.png differ diff --git a/src/assets/images/units/unit-rebel-cavalry.png b/src/assets/images/units/unit-rebel-cavalry.png index d22183c..8900fb2 100644 Binary files a/src/assets/images/units/unit-rebel-cavalry.png and b/src/assets/images/units/unit-rebel-cavalry.png differ diff --git a/src/assets/images/units/unit-rebel-leader-actions.png b/src/assets/images/units/unit-rebel-leader-actions.png index bf276c9..1316ae7 100644 Binary files a/src/assets/images/units/unit-rebel-leader-actions.png and b/src/assets/images/units/unit-rebel-leader-actions.png differ diff --git a/src/assets/images/units/unit-rebel-leader-warlord-actions.png b/src/assets/images/units/unit-rebel-leader-warlord-actions.png index bf276c9..1c0a0f4 100644 Binary files a/src/assets/images/units/unit-rebel-leader-warlord-actions.png and b/src/assets/images/units/unit-rebel-leader-warlord-actions.png differ diff --git a/src/assets/images/units/unit-rebel-leader-warlord.png b/src/assets/images/units/unit-rebel-leader-warlord.png index 026b053..84f6aff 100644 Binary files a/src/assets/images/units/unit-rebel-leader-warlord.png and b/src/assets/images/units/unit-rebel-leader-warlord.png differ diff --git a/src/assets/images/units/unit-rebel-leader.png b/src/assets/images/units/unit-rebel-leader.png index 026b053..791925f 100644 Binary files a/src/assets/images/units/unit-rebel-leader.png and b/src/assets/images/units/unit-rebel-leader.png differ diff --git a/src/assets/images/units/unit-rebel-ragged-actions.png b/src/assets/images/units/unit-rebel-ragged-actions.png index 5edb3e3..0e529ff 100644 Binary files a/src/assets/images/units/unit-rebel-ragged-actions.png and b/src/assets/images/units/unit-rebel-ragged-actions.png differ diff --git a/src/assets/images/units/unit-rebel-ragged.png b/src/assets/images/units/unit-rebel-ragged.png index 9cd1875..b625efb 100644 Binary files a/src/assets/images/units/unit-rebel-ragged.png and b/src/assets/images/units/unit-rebel-ragged.png differ diff --git a/src/assets/images/units/unit-rebel.png b/src/assets/images/units/unit-rebel.png index 4073edc..b625efb 100644 Binary files a/src/assets/images/units/unit-rebel.png and b/src/assets/images/units/unit-rebel.png differ diff --git a/src/assets/images/units/unit-shu-archer-actions.png b/src/assets/images/units/unit-shu-archer-actions.png index 0b289cd..79b4235 100644 Binary files a/src/assets/images/units/unit-shu-archer-actions.png and b/src/assets/images/units/unit-shu-archer-actions.png differ diff --git a/src/assets/images/units/unit-shu-archer-longbow-actions.png b/src/assets/images/units/unit-shu-archer-longbow-actions.png index 0b289cd..79b4235 100644 Binary files a/src/assets/images/units/unit-shu-archer-longbow-actions.png and b/src/assets/images/units/unit-shu-archer-longbow-actions.png differ diff --git a/src/assets/images/units/unit-shu-archer-longbow.png b/src/assets/images/units/unit-shu-archer-longbow.png index 3406210..635d222 100644 Binary files a/src/assets/images/units/unit-shu-archer-longbow.png and b/src/assets/images/units/unit-shu-archer-longbow.png differ diff --git a/src/assets/images/units/unit-shu-archer-veteran-actions.png b/src/assets/images/units/unit-shu-archer-veteran-actions.png index 45431c3..e68a244 100644 Binary files a/src/assets/images/units/unit-shu-archer-veteran-actions.png and b/src/assets/images/units/unit-shu-archer-veteran-actions.png differ diff --git a/src/assets/images/units/unit-shu-archer-veteran.png b/src/assets/images/units/unit-shu-archer-veteran.png index 27de84a..d508b2f 100644 Binary files a/src/assets/images/units/unit-shu-archer-veteran.png and b/src/assets/images/units/unit-shu-archer-veteran.png differ diff --git a/src/assets/images/units/unit-shu-archer.png b/src/assets/images/units/unit-shu-archer.png index 3406210..635d222 100644 Binary files a/src/assets/images/units/unit-shu-archer.png and b/src/assets/images/units/unit-shu-archer.png differ diff --git a/src/assets/images/units/unit-shu-cavalry-actions.png b/src/assets/images/units/unit-shu-cavalry-actions.png index 4473a1e..2fa2f68 100644 Binary files a/src/assets/images/units/unit-shu-cavalry-actions.png and b/src/assets/images/units/unit-shu-cavalry-actions.png differ diff --git a/src/assets/images/units/unit-shu-cavalry-scout-actions.png b/src/assets/images/units/unit-shu-cavalry-scout-actions.png index 5bad1cd..2fa2f68 100644 Binary files a/src/assets/images/units/unit-shu-cavalry-scout-actions.png and b/src/assets/images/units/unit-shu-cavalry-scout-actions.png differ diff --git a/src/assets/images/units/unit-shu-cavalry-scout.png b/src/assets/images/units/unit-shu-cavalry-scout.png index 96599fc..17a32d6 100644 Binary files a/src/assets/images/units/unit-shu-cavalry-scout.png and b/src/assets/images/units/unit-shu-cavalry-scout.png differ diff --git a/src/assets/images/units/unit-shu-cavalry-white-actions.png b/src/assets/images/units/unit-shu-cavalry-white-actions.png index e9fef1f..2218432 100644 Binary files a/src/assets/images/units/unit-shu-cavalry-white-actions.png and b/src/assets/images/units/unit-shu-cavalry-white-actions.png differ diff --git a/src/assets/images/units/unit-shu-cavalry-white.png b/src/assets/images/units/unit-shu-cavalry-white.png index 4f47d79..61e926d 100644 Binary files a/src/assets/images/units/unit-shu-cavalry-white.png and b/src/assets/images/units/unit-shu-cavalry-white.png differ diff --git a/src/assets/images/units/unit-shu-cavalry.png b/src/assets/images/units/unit-shu-cavalry.png index e9b14b3..17a32d6 100644 Binary files a/src/assets/images/units/unit-shu-cavalry.png and b/src/assets/images/units/unit-shu-cavalry.png differ diff --git a/src/assets/images/units/unit-shu-infantry-actions.png b/src/assets/images/units/unit-shu-infantry-actions.png index 3810b7f..0dc311c 100644 Binary files a/src/assets/images/units/unit-shu-infantry-actions.png and b/src/assets/images/units/unit-shu-infantry-actions.png differ diff --git a/src/assets/images/units/unit-shu-infantry-banner-actions.png b/src/assets/images/units/unit-shu-infantry-banner-actions.png index 3810b7f..8022e32 100644 Binary files a/src/assets/images/units/unit-shu-infantry-banner-actions.png and b/src/assets/images/units/unit-shu-infantry-banner-actions.png differ diff --git a/src/assets/images/units/unit-shu-infantry-banner.png b/src/assets/images/units/unit-shu-infantry-banner.png index 67a7b30..2967d00 100644 Binary files a/src/assets/images/units/unit-shu-infantry-banner.png and b/src/assets/images/units/unit-shu-infantry-banner.png differ diff --git a/src/assets/images/units/unit-shu-infantry-guard-actions.png b/src/assets/images/units/unit-shu-infantry-guard-actions.png index 5c69291..32f031c 100644 Binary files a/src/assets/images/units/unit-shu-infantry-guard-actions.png and b/src/assets/images/units/unit-shu-infantry-guard-actions.png differ diff --git a/src/assets/images/units/unit-shu-infantry-guard.png b/src/assets/images/units/unit-shu-infantry-guard.png index 4adf088..ad66348 100644 Binary files a/src/assets/images/units/unit-shu-infantry-guard.png and b/src/assets/images/units/unit-shu-infantry-guard.png differ diff --git a/src/assets/images/units/unit-shu-infantry.png b/src/assets/images/units/unit-shu-infantry.png index 67a7b30..40d7780 100644 Binary files a/src/assets/images/units/unit-shu-infantry.png and b/src/assets/images/units/unit-shu-infantry.png differ diff --git a/src/assets/images/units/unit-shu-officer-actions.png b/src/assets/images/units/unit-shu-officer-actions.png index c5498c6..e84f1fc 100644 Binary files a/src/assets/images/units/unit-shu-officer-actions.png and b/src/assets/images/units/unit-shu-officer-actions.png differ diff --git a/src/assets/images/units/unit-shu-officer-council-actions.png b/src/assets/images/units/unit-shu-officer-council-actions.png index c5498c6..e84f1fc 100644 Binary files a/src/assets/images/units/unit-shu-officer-council-actions.png and b/src/assets/images/units/unit-shu-officer-council-actions.png differ diff --git a/src/assets/images/units/unit-shu-officer-council.png b/src/assets/images/units/unit-shu-officer-council.png index a162546..aff0c74 100644 Binary files a/src/assets/images/units/unit-shu-officer-council.png and b/src/assets/images/units/unit-shu-officer-council.png differ diff --git a/src/assets/images/units/unit-shu-officer-vanguard-actions.png b/src/assets/images/units/unit-shu-officer-vanguard-actions.png index c5498c6..1fac977 100644 Binary files a/src/assets/images/units/unit-shu-officer-vanguard-actions.png and b/src/assets/images/units/unit-shu-officer-vanguard-actions.png differ diff --git a/src/assets/images/units/unit-shu-officer-vanguard.png b/src/assets/images/units/unit-shu-officer-vanguard.png index a162546..0001d71 100644 Binary files a/src/assets/images/units/unit-shu-officer-vanguard.png and b/src/assets/images/units/unit-shu-officer-vanguard.png differ diff --git a/src/assets/images/units/unit-shu-officer.png b/src/assets/images/units/unit-shu-officer.png index a162546..aff0c74 100644 Binary files a/src/assets/images/units/unit-shu-officer.png and b/src/assets/images/units/unit-shu-officer.png differ diff --git a/src/assets/images/units/unit-shu-spearman-actions.png b/src/assets/images/units/unit-shu-spearman-actions.png index 0d08eff..da27601 100644 Binary files a/src/assets/images/units/unit-shu-spearman-actions.png and b/src/assets/images/units/unit-shu-spearman-actions.png differ diff --git a/src/assets/images/units/unit-shu-spearman-guard-actions.png b/src/assets/images/units/unit-shu-spearman-guard-actions.png index 142758a..a226cd6 100644 Binary files a/src/assets/images/units/unit-shu-spearman-guard-actions.png and b/src/assets/images/units/unit-shu-spearman-guard-actions.png differ diff --git a/src/assets/images/units/unit-shu-spearman-guard.png b/src/assets/images/units/unit-shu-spearman-guard.png index d242a68..0b91cd9 100644 Binary files a/src/assets/images/units/unit-shu-spearman-guard.png and b/src/assets/images/units/unit-shu-spearman-guard.png differ diff --git a/src/assets/images/units/unit-shu-spearman-veteran-actions.png b/src/assets/images/units/unit-shu-spearman-veteran-actions.png index 142758a..a226cd6 100644 Binary files a/src/assets/images/units/unit-shu-spearman-veteran-actions.png and b/src/assets/images/units/unit-shu-spearman-veteran-actions.png differ diff --git a/src/assets/images/units/unit-shu-spearman-veteran.png b/src/assets/images/units/unit-shu-spearman-veteran.png index d242a68..0b91cd9 100644 Binary files a/src/assets/images/units/unit-shu-spearman-veteran.png and b/src/assets/images/units/unit-shu-spearman-veteran.png differ diff --git a/src/assets/images/units/unit-shu-spearman.png b/src/assets/images/units/unit-shu-spearman.png index 7b666f7..91f0842 100644 Binary files a/src/assets/images/units/unit-shu-spearman.png and b/src/assets/images/units/unit-shu-spearman.png differ diff --git a/src/assets/images/units/unit-shu-strategist-actions.png b/src/assets/images/units/unit-shu-strategist-actions.png index 176e339..e1d2470 100644 Binary files a/src/assets/images/units/unit-shu-strategist-actions.png and b/src/assets/images/units/unit-shu-strategist-actions.png differ diff --git a/src/assets/images/units/unit-shu-strategist-field-actions.png b/src/assets/images/units/unit-shu-strategist-field-actions.png index 176e339..e1d2470 100644 Binary files a/src/assets/images/units/unit-shu-strategist-field-actions.png and b/src/assets/images/units/unit-shu-strategist-field-actions.png differ diff --git a/src/assets/images/units/unit-shu-strategist-field.png b/src/assets/images/units/unit-shu-strategist-field.png index 7f3c080..e30dcaf 100644 Binary files a/src/assets/images/units/unit-shu-strategist-field.png and b/src/assets/images/units/unit-shu-strategist-field.png differ diff --git a/src/assets/images/units/unit-shu-strategist-white-actions.png b/src/assets/images/units/unit-shu-strategist-white-actions.png index 176e339..e1d2470 100644 Binary files a/src/assets/images/units/unit-shu-strategist-white-actions.png and b/src/assets/images/units/unit-shu-strategist-white-actions.png differ diff --git a/src/assets/images/units/unit-shu-strategist-white.png b/src/assets/images/units/unit-shu-strategist-white.png index 7f3c080..e30dcaf 100644 Binary files a/src/assets/images/units/unit-shu-strategist-white.png and b/src/assets/images/units/unit-shu-strategist-white.png differ diff --git a/src/assets/images/units/unit-shu-strategist.png b/src/assets/images/units/unit-shu-strategist.png index 7f3c080..e30dcaf 100644 Binary files a/src/assets/images/units/unit-shu-strategist.png and b/src/assets/images/units/unit-shu-strategist.png differ diff --git a/src/assets/images/units/unit-sima-yi-actions.png b/src/assets/images/units/unit-sima-yi-actions.png index 6f94190..a58e9c0 100644 Binary files a/src/assets/images/units/unit-sima-yi-actions.png and b/src/assets/images/units/unit-sima-yi-actions.png differ diff --git a/src/assets/images/units/unit-sima-yi.png b/src/assets/images/units/unit-sima-yi.png index e13aaa9..54cd724 100644 Binary files a/src/assets/images/units/unit-sima-yi.png and b/src/assets/images/units/unit-sima-yi.png differ diff --git a/src/assets/images/units/unit-wang-ping-actions.png b/src/assets/images/units/unit-wang-ping-actions.png index 81669b9..e84f1fc 100644 Binary files a/src/assets/images/units/unit-wang-ping-actions.png and b/src/assets/images/units/unit-wang-ping-actions.png differ diff --git a/src/assets/images/units/unit-wang-ping.png b/src/assets/images/units/unit-wang-ping.png index 3372b1b..aff0c74 100644 Binary files a/src/assets/images/units/unit-wang-ping.png and b/src/assets/images/units/unit-wang-ping.png differ diff --git a/src/assets/images/units/unit-wei-archer-actions.png b/src/assets/images/units/unit-wei-archer-actions.png index c1a9a20..610755f 100644 Binary files a/src/assets/images/units/unit-wei-archer-actions.png and b/src/assets/images/units/unit-wei-archer-actions.png differ diff --git a/src/assets/images/units/unit-wei-archer-crossbow-actions.png b/src/assets/images/units/unit-wei-archer-crossbow-actions.png index c1a9a20..c55de5a 100644 Binary files a/src/assets/images/units/unit-wei-archer-crossbow-actions.png and b/src/assets/images/units/unit-wei-archer-crossbow-actions.png differ diff --git a/src/assets/images/units/unit-wei-archer-crossbow.png b/src/assets/images/units/unit-wei-archer-crossbow.png index 9692b01..0aad26b 100644 Binary files a/src/assets/images/units/unit-wei-archer-crossbow.png and b/src/assets/images/units/unit-wei-archer-crossbow.png differ diff --git a/src/assets/images/units/unit-wei-archer-veteran-actions.png b/src/assets/images/units/unit-wei-archer-veteran-actions.png index 6a07d34..2ed4013 100644 Binary files a/src/assets/images/units/unit-wei-archer-veteran-actions.png and b/src/assets/images/units/unit-wei-archer-veteran-actions.png differ diff --git a/src/assets/images/units/unit-wei-archer-veteran.png b/src/assets/images/units/unit-wei-archer-veteran.png index 10f7c2e..089d10a 100644 Binary files a/src/assets/images/units/unit-wei-archer-veteran.png and b/src/assets/images/units/unit-wei-archer-veteran.png differ diff --git a/src/assets/images/units/unit-wei-archer.png b/src/assets/images/units/unit-wei-archer.png index 9692b01..1fd15b1 100644 Binary files a/src/assets/images/units/unit-wei-archer.png and b/src/assets/images/units/unit-wei-archer.png differ diff --git a/src/assets/images/units/unit-wei-cavalry-actions.png b/src/assets/images/units/unit-wei-cavalry-actions.png index 204568e..d76c28d 100644 Binary files a/src/assets/images/units/unit-wei-cavalry-actions.png and b/src/assets/images/units/unit-wei-cavalry-actions.png differ diff --git a/src/assets/images/units/unit-wei-cavalry-elite-actions.png b/src/assets/images/units/unit-wei-cavalry-elite-actions.png index f663f81..3569f7e 100644 Binary files a/src/assets/images/units/unit-wei-cavalry-elite-actions.png and b/src/assets/images/units/unit-wei-cavalry-elite-actions.png differ diff --git a/src/assets/images/units/unit-wei-cavalry-elite.png b/src/assets/images/units/unit-wei-cavalry-elite.png index 857dbf5..cf7a1b6 100644 Binary files a/src/assets/images/units/unit-wei-cavalry-elite.png and b/src/assets/images/units/unit-wei-cavalry-elite.png differ diff --git a/src/assets/images/units/unit-wei-cavalry-iron-actions.png b/src/assets/images/units/unit-wei-cavalry-iron-actions.png index 204568e..3569f7e 100644 Binary files a/src/assets/images/units/unit-wei-cavalry-iron-actions.png and b/src/assets/images/units/unit-wei-cavalry-iron-actions.png differ diff --git a/src/assets/images/units/unit-wei-cavalry-iron.png b/src/assets/images/units/unit-wei-cavalry-iron.png index 4e78889..cf7a1b6 100644 Binary files a/src/assets/images/units/unit-wei-cavalry-iron.png and b/src/assets/images/units/unit-wei-cavalry-iron.png differ diff --git a/src/assets/images/units/unit-wei-cavalry.png b/src/assets/images/units/unit-wei-cavalry.png index 4e78889..081c3f2 100644 Binary files a/src/assets/images/units/unit-wei-cavalry.png and b/src/assets/images/units/unit-wei-cavalry.png differ diff --git a/src/assets/images/units/unit-wei-infantry-actions.png b/src/assets/images/units/unit-wei-infantry-actions.png index 0666471..28ad405 100644 Binary files a/src/assets/images/units/unit-wei-infantry-actions.png and b/src/assets/images/units/unit-wei-infantry-actions.png differ diff --git a/src/assets/images/units/unit-wei-infantry-shield-actions.png b/src/assets/images/units/unit-wei-infantry-shield-actions.png index 0666471..28ad405 100644 Binary files a/src/assets/images/units/unit-wei-infantry-shield-actions.png and b/src/assets/images/units/unit-wei-infantry-shield-actions.png differ diff --git a/src/assets/images/units/unit-wei-infantry-shield.png b/src/assets/images/units/unit-wei-infantry-shield.png index eb9bcbc..af80f14 100644 Binary files a/src/assets/images/units/unit-wei-infantry-shield.png and b/src/assets/images/units/unit-wei-infantry-shield.png differ diff --git a/src/assets/images/units/unit-wei-infantry-veteran-actions.png b/src/assets/images/units/unit-wei-infantry-veteran-actions.png index bfaf351..8cb8d14 100644 Binary files a/src/assets/images/units/unit-wei-infantry-veteran-actions.png and b/src/assets/images/units/unit-wei-infantry-veteran-actions.png differ diff --git a/src/assets/images/units/unit-wei-infantry-veteran.png b/src/assets/images/units/unit-wei-infantry-veteran.png index f7c98ca..d4aa1e3 100644 Binary files a/src/assets/images/units/unit-wei-infantry-veteran.png and b/src/assets/images/units/unit-wei-infantry-veteran.png differ diff --git a/src/assets/images/units/unit-wei-infantry.png b/src/assets/images/units/unit-wei-infantry.png index eb9bcbc..af80f14 100644 Binary files a/src/assets/images/units/unit-wei-infantry.png and b/src/assets/images/units/unit-wei-infantry.png differ diff --git a/src/assets/images/units/unit-wei-officer-actions.png b/src/assets/images/units/unit-wei-officer-actions.png index f403f61..08011a0 100644 Binary files a/src/assets/images/units/unit-wei-officer-actions.png and b/src/assets/images/units/unit-wei-officer-actions.png differ diff --git a/src/assets/images/units/unit-wei-officer-gate-actions.png b/src/assets/images/units/unit-wei-officer-gate-actions.png index f403f61..08011a0 100644 Binary files a/src/assets/images/units/unit-wei-officer-gate-actions.png and b/src/assets/images/units/unit-wei-officer-gate-actions.png differ diff --git a/src/assets/images/units/unit-wei-officer-gate.png b/src/assets/images/units/unit-wei-officer-gate.png index 0bb9af9..8007640 100644 Binary files a/src/assets/images/units/unit-wei-officer-gate.png and b/src/assets/images/units/unit-wei-officer-gate.png differ diff --git a/src/assets/images/units/unit-wei-officer-iron-actions.png b/src/assets/images/units/unit-wei-officer-iron-actions.png index f403f61..146f29a 100644 Binary files a/src/assets/images/units/unit-wei-officer-iron-actions.png and b/src/assets/images/units/unit-wei-officer-iron-actions.png differ diff --git a/src/assets/images/units/unit-wei-officer-iron.png b/src/assets/images/units/unit-wei-officer-iron.png index 0bb9af9..608cc14 100644 Binary files a/src/assets/images/units/unit-wei-officer-iron.png and b/src/assets/images/units/unit-wei-officer-iron.png differ diff --git a/src/assets/images/units/unit-wei-officer.png b/src/assets/images/units/unit-wei-officer.png index 0bb9af9..8007640 100644 Binary files a/src/assets/images/units/unit-wei-officer.png and b/src/assets/images/units/unit-wei-officer.png differ diff --git a/src/assets/images/units/unit-wei-strategist-actions.png b/src/assets/images/units/unit-wei-strategist-actions.png index 714a522..a58e9c0 100644 Binary files a/src/assets/images/units/unit-wei-strategist-actions.png and b/src/assets/images/units/unit-wei-strategist-actions.png differ diff --git a/src/assets/images/units/unit-wei-strategist-black-actions.png b/src/assets/images/units/unit-wei-strategist-black-actions.png index 714a522..a58e9c0 100644 Binary files a/src/assets/images/units/unit-wei-strategist-black-actions.png and b/src/assets/images/units/unit-wei-strategist-black-actions.png differ diff --git a/src/assets/images/units/unit-wei-strategist-black.png b/src/assets/images/units/unit-wei-strategist-black.png index fc041c1..54cd724 100644 Binary files a/src/assets/images/units/unit-wei-strategist-black.png and b/src/assets/images/units/unit-wei-strategist-black.png differ diff --git a/src/assets/images/units/unit-wei-strategist-blue-actions.png b/src/assets/images/units/unit-wei-strategist-blue-actions.png index 714a522..a58e9c0 100644 Binary files a/src/assets/images/units/unit-wei-strategist-blue-actions.png and b/src/assets/images/units/unit-wei-strategist-blue-actions.png differ diff --git a/src/assets/images/units/unit-wei-strategist-blue.png b/src/assets/images/units/unit-wei-strategist-blue.png index fc041c1..54cd724 100644 Binary files a/src/assets/images/units/unit-wei-strategist-blue.png and b/src/assets/images/units/unit-wei-strategist-blue.png differ diff --git a/src/assets/images/units/unit-wei-strategist.png b/src/assets/images/units/unit-wei-strategist.png index fc041c1..54cd724 100644 Binary files a/src/assets/images/units/unit-wei-strategist.png and b/src/assets/images/units/unit-wei-strategist.png differ diff --git a/src/assets/images/units/unit-wei-yan-actions.png b/src/assets/images/units/unit-wei-yan-actions.png index a74fad3..b3f7956 100644 Binary files a/src/assets/images/units/unit-wei-yan-actions.png and b/src/assets/images/units/unit-wei-yan-actions.png differ diff --git a/src/assets/images/units/unit-wei-yan.png b/src/assets/images/units/unit-wei-yan.png index adb55f9..cb4177d 100644 Binary files a/src/assets/images/units/unit-wei-yan.png and b/src/assets/images/units/unit-wei-yan.png differ diff --git a/src/assets/images/units/unit-wu-archer-actions.png b/src/assets/images/units/unit-wu-archer-actions.png index 6724aa6..4cb4bc5 100644 Binary files a/src/assets/images/units/unit-wu-archer-actions.png and b/src/assets/images/units/unit-wu-archer-actions.png differ diff --git a/src/assets/images/units/unit-wu-archer-naval-actions.png b/src/assets/images/units/unit-wu-archer-naval-actions.png index 6724aa6..4cb4bc5 100644 Binary files a/src/assets/images/units/unit-wu-archer-naval-actions.png and b/src/assets/images/units/unit-wu-archer-naval-actions.png differ diff --git a/src/assets/images/units/unit-wu-archer-naval.png b/src/assets/images/units/unit-wu-archer-naval.png index 161159b..1e60130 100644 Binary files a/src/assets/images/units/unit-wu-archer-naval.png and b/src/assets/images/units/unit-wu-archer-naval.png differ diff --git a/src/assets/images/units/unit-wu-archer-river-actions.png b/src/assets/images/units/unit-wu-archer-river-actions.png index 6724aa6..4cb4bc5 100644 Binary files a/src/assets/images/units/unit-wu-archer-river-actions.png and b/src/assets/images/units/unit-wu-archer-river-actions.png differ diff --git a/src/assets/images/units/unit-wu-archer-river.png b/src/assets/images/units/unit-wu-archer-river.png index 161159b..1e60130 100644 Binary files a/src/assets/images/units/unit-wu-archer-river.png and b/src/assets/images/units/unit-wu-archer-river.png differ diff --git a/src/assets/images/units/unit-wu-archer.png b/src/assets/images/units/unit-wu-archer.png index 161159b..1e60130 100644 Binary files a/src/assets/images/units/unit-wu-archer.png and b/src/assets/images/units/unit-wu-archer.png differ diff --git a/src/assets/images/units/unit-wu-cavalry-actions.png b/src/assets/images/units/unit-wu-cavalry-actions.png index a6b97db..bc205f0 100644 Binary files a/src/assets/images/units/unit-wu-cavalry-actions.png and b/src/assets/images/units/unit-wu-cavalry-actions.png differ diff --git a/src/assets/images/units/unit-wu-cavalry-elite-actions.png b/src/assets/images/units/unit-wu-cavalry-elite-actions.png index 27707b3..bd2415e 100644 Binary files a/src/assets/images/units/unit-wu-cavalry-elite-actions.png and b/src/assets/images/units/unit-wu-cavalry-elite-actions.png differ diff --git a/src/assets/images/units/unit-wu-cavalry-elite.png b/src/assets/images/units/unit-wu-cavalry-elite.png index b7f2961..bd9a122 100644 Binary files a/src/assets/images/units/unit-wu-cavalry-elite.png and b/src/assets/images/units/unit-wu-cavalry-elite.png differ diff --git a/src/assets/images/units/unit-wu-cavalry-river-actions.png b/src/assets/images/units/unit-wu-cavalry-river-actions.png index a6b97db..bc205f0 100644 Binary files a/src/assets/images/units/unit-wu-cavalry-river-actions.png and b/src/assets/images/units/unit-wu-cavalry-river-actions.png differ diff --git a/src/assets/images/units/unit-wu-cavalry-river.png b/src/assets/images/units/unit-wu-cavalry-river.png index d9ee2e5..819cc69 100644 Binary files a/src/assets/images/units/unit-wu-cavalry-river.png and b/src/assets/images/units/unit-wu-cavalry-river.png differ diff --git a/src/assets/images/units/unit-wu-cavalry.png b/src/assets/images/units/unit-wu-cavalry.png index d9ee2e5..819cc69 100644 Binary files a/src/assets/images/units/unit-wu-cavalry.png and b/src/assets/images/units/unit-wu-cavalry.png differ diff --git a/src/assets/images/units/unit-wu-infantry-actions.png b/src/assets/images/units/unit-wu-infantry-actions.png index 40b4371..97b11ac 100644 Binary files a/src/assets/images/units/unit-wu-infantry-actions.png and b/src/assets/images/units/unit-wu-infantry-actions.png differ diff --git a/src/assets/images/units/unit-wu-infantry-marine-actions.png b/src/assets/images/units/unit-wu-infantry-marine-actions.png index 40b4371..97b11ac 100644 Binary files a/src/assets/images/units/unit-wu-infantry-marine-actions.png and b/src/assets/images/units/unit-wu-infantry-marine-actions.png differ diff --git a/src/assets/images/units/unit-wu-infantry-marine.png b/src/assets/images/units/unit-wu-infantry-marine.png index f25081c..f18c348 100644 Binary files a/src/assets/images/units/unit-wu-infantry-marine.png and b/src/assets/images/units/unit-wu-infantry-marine.png differ diff --git a/src/assets/images/units/unit-wu-infantry-river-actions.png b/src/assets/images/units/unit-wu-infantry-river-actions.png index 40b4371..97b11ac 100644 Binary files a/src/assets/images/units/unit-wu-infantry-river-actions.png and b/src/assets/images/units/unit-wu-infantry-river-actions.png differ diff --git a/src/assets/images/units/unit-wu-infantry-river.png b/src/assets/images/units/unit-wu-infantry-river.png index f25081c..f18c348 100644 Binary files a/src/assets/images/units/unit-wu-infantry-river.png and b/src/assets/images/units/unit-wu-infantry-river.png differ diff --git a/src/assets/images/units/unit-wu-infantry.png b/src/assets/images/units/unit-wu-infantry.png index f25081c..f18c348 100644 Binary files a/src/assets/images/units/unit-wu-infantry.png and b/src/assets/images/units/unit-wu-infantry.png differ diff --git a/src/assets/images/units/unit-wu-officer-actions.png b/src/assets/images/units/unit-wu-officer-actions.png index 32964dd..ca32622 100644 Binary files a/src/assets/images/units/unit-wu-officer-actions.png and b/src/assets/images/units/unit-wu-officer-actions.png differ diff --git a/src/assets/images/units/unit-wu-officer-harbor-actions.png b/src/assets/images/units/unit-wu-officer-harbor-actions.png index 32964dd..ca32622 100644 Binary files a/src/assets/images/units/unit-wu-officer-harbor-actions.png and b/src/assets/images/units/unit-wu-officer-harbor-actions.png differ diff --git a/src/assets/images/units/unit-wu-officer-harbor.png b/src/assets/images/units/unit-wu-officer-harbor.png index 5612fbe..e3ab9df 100644 Binary files a/src/assets/images/units/unit-wu-officer-harbor.png and b/src/assets/images/units/unit-wu-officer-harbor.png differ diff --git a/src/assets/images/units/unit-wu-officer-river-actions.png b/src/assets/images/units/unit-wu-officer-river-actions.png index 32964dd..ca32622 100644 Binary files a/src/assets/images/units/unit-wu-officer-river-actions.png and b/src/assets/images/units/unit-wu-officer-river-actions.png differ diff --git a/src/assets/images/units/unit-wu-officer-river.png b/src/assets/images/units/unit-wu-officer-river.png index 5612fbe..e3ab9df 100644 Binary files a/src/assets/images/units/unit-wu-officer-river.png and b/src/assets/images/units/unit-wu-officer-river.png differ diff --git a/src/assets/images/units/unit-wu-officer.png b/src/assets/images/units/unit-wu-officer.png index 5612fbe..e3ab9df 100644 Binary files a/src/assets/images/units/unit-wu-officer.png and b/src/assets/images/units/unit-wu-officer.png differ diff --git a/src/assets/images/units/unit-wu-strategist-actions.png b/src/assets/images/units/unit-wu-strategist-actions.png index 2fb19c6..561d42d 100644 Binary files a/src/assets/images/units/unit-wu-strategist-actions.png and b/src/assets/images/units/unit-wu-strategist-actions.png differ diff --git a/src/assets/images/units/unit-wu-strategist-fire-actions.png b/src/assets/images/units/unit-wu-strategist-fire-actions.png index 2fb19c6..561d42d 100644 Binary files a/src/assets/images/units/unit-wu-strategist-fire-actions.png and b/src/assets/images/units/unit-wu-strategist-fire-actions.png differ diff --git a/src/assets/images/units/unit-wu-strategist-fire.png b/src/assets/images/units/unit-wu-strategist-fire.png index 71d2617..5a3328e 100644 Binary files a/src/assets/images/units/unit-wu-strategist-fire.png and b/src/assets/images/units/unit-wu-strategist-fire.png differ diff --git a/src/assets/images/units/unit-wu-strategist-river-actions.png b/src/assets/images/units/unit-wu-strategist-river-actions.png index 2fb19c6..561d42d 100644 Binary files a/src/assets/images/units/unit-wu-strategist-river-actions.png and b/src/assets/images/units/unit-wu-strategist-river-actions.png differ diff --git a/src/assets/images/units/unit-wu-strategist-river.png b/src/assets/images/units/unit-wu-strategist-river.png index 71d2617..5a3328e 100644 Binary files a/src/assets/images/units/unit-wu-strategist-river.png and b/src/assets/images/units/unit-wu-strategist-river.png differ diff --git a/src/assets/images/units/unit-wu-strategist.png b/src/assets/images/units/unit-wu-strategist.png index 71d2617..5a3328e 100644 Binary files a/src/assets/images/units/unit-wu-strategist.png and b/src/assets/images/units/unit-wu-strategist.png differ diff --git a/src/assets/images/units/unit-wu-yi-actions.png b/src/assets/images/units/unit-wu-yi-actions.png index e6665da..ca32622 100644 Binary files a/src/assets/images/units/unit-wu-yi-actions.png and b/src/assets/images/units/unit-wu-yi-actions.png differ diff --git a/src/assets/images/units/unit-wu-yi.png b/src/assets/images/units/unit-wu-yi.png index 9c3ddb2..e3ab9df 100644 Binary files a/src/assets/images/units/unit-wu-yi.png and b/src/assets/images/units/unit-wu-yi.png differ diff --git a/src/assets/images/units/unit-yan-yan-actions.png b/src/assets/images/units/unit-yan-yan-actions.png index 4f23bb5..da27601 100644 Binary files a/src/assets/images/units/unit-yan-yan-actions.png and b/src/assets/images/units/unit-yan-yan-actions.png differ diff --git a/src/assets/images/units/unit-yan-yan.png b/src/assets/images/units/unit-yan-yan.png index 7b666f7..91f0842 100644 Binary files a/src/assets/images/units/unit-yan-yan.png and b/src/assets/images/units/unit-yan-yan.png differ diff --git a/src/assets/images/units/unit-yi-ji-actions.png b/src/assets/images/units/unit-yi-ji-actions.png index 176e339..e1d2470 100644 Binary files a/src/assets/images/units/unit-yi-ji-actions.png and b/src/assets/images/units/unit-yi-ji-actions.png differ diff --git a/src/assets/images/units/unit-yi-ji.png b/src/assets/images/units/unit-yi-ji.png index 7f3c080..e30dcaf 100644 Binary files a/src/assets/images/units/unit-yi-ji.png and b/src/assets/images/units/unit-yi-ji.png differ diff --git a/src/assets/images/units/unit-zhang-fei-actions.png b/src/assets/images/units/unit-zhang-fei-actions.png index 3500f53..2dc4e99 100644 Binary files a/src/assets/images/units/unit-zhang-fei-actions.png and b/src/assets/images/units/unit-zhang-fei-actions.png differ diff --git a/src/assets/images/units/unit-zhang-fei.png b/src/assets/images/units/unit-zhang-fei.png index 07992e4..1c1f32c 100644 Binary files a/src/assets/images/units/unit-zhang-fei.png and b/src/assets/images/units/unit-zhang-fei.png differ diff --git a/src/assets/images/units/unit-zhao-yun-actions.png b/src/assets/images/units/unit-zhao-yun-actions.png index 52bcb0b..d177b8d 100644 Binary files a/src/assets/images/units/unit-zhao-yun-actions.png and b/src/assets/images/units/unit-zhao-yun-actions.png differ diff --git a/src/assets/images/units/unit-zhao-yun.png b/src/assets/images/units/unit-zhao-yun.png index 37d0041..9db9cdf 100644 Binary files a/src/assets/images/units/unit-zhao-yun.png and b/src/assets/images/units/unit-zhao-yun.png differ diff --git a/src/assets/images/units/unit-zhuge-liang-actions.png b/src/assets/images/units/unit-zhuge-liang-actions.png index 1aa3c75..1a2c021 100644 Binary files a/src/assets/images/units/unit-zhuge-liang-actions.png and b/src/assets/images/units/unit-zhuge-liang-actions.png differ diff --git a/src/assets/images/units/unit-zhuge-liang.png b/src/assets/images/units/unit-zhuge-liang.png index 9808a2f..2290b0a 100644 Binary files a/src/assets/images/units/unit-zhuge-liang.png and b/src/assets/images/units/unit-zhuge-liang.png differ diff --git a/src/game/scenes/BattleScene.ts b/src/game/scenes/BattleScene.ts index b5582a9..cf1cdba 100644 --- a/src/game/scenes/BattleScene.ts +++ b/src/game/scenes/BattleScene.ts @@ -9598,48 +9598,6 @@ export class BattleScene extends Phaser.Scene { private showFacingIndicator(unit: UnitData) { this.clearFacingIndicator(); this.facingIndicatorUnitId = unit.id; - - const view = this.unitViews.get(unit.id); - if (!view || unit.hp <= 0 || !this.isTileVisible(unit.x, unit.y)) { - return; - } - - const direction = this.currentUnitDirection(unit); - const vector = this.directionVector(direction); - const x = view.sprite.x + vector.x * this.layout.tileSize * 0.34; - const y = view.sprite.y + vector.y * this.layout.tileSize * 0.34 - this.layout.tileSize * 0.28; - const marker = this.add.circle(x, y, 13, 0x101820, 0.86); - marker.setStrokeStyle(1, palette.gold, 0.88); - marker.setDepth(34); - - const arrow = this.add.text(x, y - 1, this.directionSymbol(direction), { - fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '18px', - color: '#ffe28a', - fontStyle: '700', - stroke: '#05070a', - strokeThickness: 3 - }); - arrow.setOrigin(0.5); - arrow.setDepth(35); - - const label = this.add.text(x, y + 16, this.unitDirectionLabel(direction), { - fontFamily: '"Malgun Gothic", "Noto Sans KR", sans-serif', - fontSize: '10px', - color: '#f4dfad', - stroke: '#05070a', - strokeThickness: 3 - }); - label.setOrigin(0.5, 0); - label.setDepth(35); - - if (this.mapMask) { - marker.setMask(this.mapMask); - arrow.setMask(this.mapMask); - label.setMask(this.mapMask); - } - - this.facingIndicatorObjects = [marker, arrow, label]; } private clearFacingIndicator() {