diff --git a/docs/unit-sprite-art-sources/archer-strategist-master.png b/docs/unit-sprite-art-sources/archer-strategist-master.png new file mode 100644 index 0000000..6cbe326 Binary files /dev/null and b/docs/unit-sprite-art-sources/archer-strategist-master.png differ diff --git a/docs/unit-sprite-art-sources/cavalry-master.png b/docs/unit-sprite-art-sources/cavalry-master.png new file mode 100644 index 0000000..74f44d3 Binary files /dev/null and b/docs/unit-sprite-art-sources/cavalry-master.png differ diff --git a/docs/unit-sprite-art-sources/commander-master.png b/docs/unit-sprite-art-sources/commander-master.png new file mode 100644 index 0000000..5112a70 Binary files /dev/null and b/docs/unit-sprite-art-sources/commander-master.png differ diff --git a/docs/unit-sprite-art-sources/infantry-spearman-master.png b/docs/unit-sprite-art-sources/infantry-spearman-master.png new file mode 100644 index 0000000..7858979 Binary files /dev/null and b/docs/unit-sprite-art-sources/infantry-spearman-master.png differ diff --git a/docs/unit-sprite-art-sources/nanman-master.png b/docs/unit-sprite-art-sources/nanman-master.png new file mode 100644 index 0000000..e2df77c Binary files /dev/null and b/docs/unit-sprite-art-sources/nanman-master.png differ diff --git a/docs/unit-sprite-art-sources/rebel-master.png b/docs/unit-sprite-art-sources/rebel-master.png new file mode 100644 index 0000000..f248422 Binary files /dev/null and b/docs/unit-sprite-art-sources/rebel-master.png differ diff --git a/docs/unit-sprite-battle-first-battle-v1.png b/docs/unit-sprite-battle-first-battle-v1.png new file mode 100644 index 0000000..5bd5e73 Binary files /dev/null and b/docs/unit-sprite-battle-first-battle-v1.png differ diff --git a/docs/unit-sprite-battle-redcliffs-v1.png b/docs/unit-sprite-battle-redcliffs-v1.png new file mode 100644 index 0000000..90f47aa Binary files /dev/null and b/docs/unit-sprite-battle-redcliffs-v1.png differ diff --git a/docs/unit-sprite-raster-actual-size-v1.png b/docs/unit-sprite-raster-actual-size-v1.png new file mode 100644 index 0000000..fe04637 Binary files /dev/null and b/docs/unit-sprite-raster-actual-size-v1.png differ diff --git a/docs/unit-sprite-raster-contact-sheet-v1.png b/docs/unit-sprite-raster-contact-sheet-v1.png new file mode 100644 index 0000000..798ff3f Binary files /dev/null and b/docs/unit-sprite-raster-contact-sheet-v1.png differ diff --git a/docs/unit-sprite-raster-pipeline-v1.md b/docs/unit-sprite-raster-pipeline-v1.md new file mode 100644 index 0000000..13d78b2 --- /dev/null +++ b/docs/unit-sprite-raster-pipeline-v1.md @@ -0,0 +1,96 @@ +# Unit Sprite Raster Pipeline v1 + +This pass replaces the active 91 battle unit sheets with raster source art derived from the approved v1 sprite art direction. + +## Inputs + +- `docs/unit-sprite-quality-contact-sheet-v1.png` +- `docs/unit-sprite-quality-actual-size-v1.png` +- `docs/unit-sprite-art-sources/infantry-spearman-master.png` +- `docs/unit-sprite-art-sources/archer-strategist-master.png` +- `docs/unit-sprite-art-sources/cavalry-master.png` +- `docs/unit-sprite-art-sources/rebel-master.png` +- `docs/unit-sprite-art-sources/nanman-master.png` +- `docs/unit-sprite-art-sources/commander-master.png` + +The art source sheets are hand-painted-style raster generations created for this project. They are not traced from or copied out of existing copyrighted game assets. + +## Build Script + +`scripts/build-raster-unit-sprites.py` packs the generated raster sources into the runtime sprite sheet format. + +The script uses PIL for production processing only: + +- crop source cells from the raster source sheets +- remove source-sheet backgrounds +- place sprites on a fixed transparent 313x313 canvas +- keep a shared bottom anchor +- create faction and rank color variants +- add small frame offsets for idle, move, attack, hurt, strategy, item, and celebrate timing +- palette-optimize generated PNGs to 192 colors while preserving alpha +- save sprite sheets and preview sheets + +It does not draw unit bodies from procedural shapes. + +## Runtime Format + +The generated files keep the existing Phaser mapping intact. + +- Frame size: `313x313` +- Base sheet size: `5008x1252` +- Base row order: `south`, `east`, `north`, `west` +- Base columns per direction: 8 idle frames, then 8 move frames +- Action sheet size: `11268x1252` +- Action row order: `south`, `east`, `north`, `west` +- Action columns per direction: + - attack: 10 frames + - strategy: 8 frames + - item: 8 frames + - hurt: 4 frames + - celebrate: 6 frames + +## Outputs + +- `src/assets/images/units/unit-*.png` +- `src/assets/images/units/unit-*-actions.png` +- `docs/unit-sprite-raster-contact-sheet-v1.png` +- `docs/unit-sprite-raster-actual-size-v1.png` + +The representative contact sheet covers 12 units across commander, infantry, spearman, archer, strategist, cavalry, rebel, Wei, Wu, and Nanman styles. + +## Commands + +Preview only: + +```powershell +python scripts\build-raster-unit-sprites.py --preview-only +``` + +Rebuild all active unit sheets: + +```powershell +python scripts\build-raster-unit-sprites.py +``` + +Rebuild selected unit stems: + +```powershell +python scripts\build-raster-unit-sprites.py --only unit-liu-bei,unit-zhao-yun +``` + +## Verification Performed + +- Rebuilt all 91 active unit definitions. +- Verified every base sheet is `5008x1252`. +- Verified every action sheet is `11268x1252`. +- Reduced the generated runtime unit PNG set from roughly 452 MB to roughly 91 MB with palette PNG encoding. +- Ran `pnpm build`. +- Browser-verified the first battle and Red Cliffs vanguard battle at desktop canvas size. +- Confirmed idle frame changes within the running battle scene. +- Confirmed attack, hurt, and celebrate poses resolve to `-actions` sheets. +- Confirmed no browser console errors during the verification run. + +Verification screenshots: + +- `docs/unit-sprite-battle-first-battle-v1.png` +- `docs/unit-sprite-battle-redcliffs-v1.png` diff --git a/scripts/build-raster-unit-sprites.py b/scripts/build-raster-unit-sprites.py new file mode 100644 index 0000000..bba623f --- /dev/null +++ b/scripts/build-raster-unit-sprites.py @@ -0,0 +1,682 @@ +from __future__ import annotations + +import argparse +import colorsys +import hashlib +import math +from collections import deque +from dataclasses import dataclass +from pathlib import Path + +from PIL import Image, ImageEnhance, ImageFilter, ImageOps + + +ROOT = Path(__file__).resolve().parents[1] +UNIT_DIR = ROOT / "src" / "assets" / "images" / "units" +SOURCE_DIR = ROOT / "docs" / "unit-sprite-art-sources" +CONTACT_PATH = ROOT / "docs" / "unit-sprite-raster-contact-sheet-v1.png" +ACTUAL_SIZE_PATH = ROOT / "docs" / "unit-sprite-raster-actual-size-v1.png" + +FRAME_SIZE = 313 +PNG_PALETTE_COLORS = 192 +DIRECTIONS = ("south", "east", "north", "west") +IDLE_FRAME_COUNT = 8 +MOVE_FRAME_COUNT = 8 +BASE_FRAMES_PER_DIRECTION = IDLE_FRAME_COUNT + MOVE_FRAME_COUNT +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()) + + +@dataclass(frozen=True) +class SourceGrid: + name: str + file: str + x_lines: tuple[int, ...] + y_lines_by_section: tuple[tuple[int, ...], tuple[int, ...]] + attack_col: int + + @property + def base_cols(self) -> int: + return max(4, min(6, self.attack_col)) + + +@dataclass(frozen=True) +class UnitStyle: + source: str + section: int + faction: str + role: str + rank: int + target: tuple[int, int, int] + secondary: tuple[int, int, int] + scale: float + bulk: float + + +SOURCES: dict[str, SourceGrid] = { + "infantry": SourceGrid( + "infantry", + "infantry-spearman-master.png", + (134, 326, 518, 710, 902, 1094, 1289), + ((9, 140, 254, 370, 483), (498, 627, 743, 862, 981)), + 5, + ), + "ranged": SourceGrid( + "ranged", + "archer-strategist-master.png", + (161, 320, 477, 631, 785, 937, 1091, 1243), + ((18, 149, 268, 389, 510), (523, 655, 779, 904, 1011)), + 6, + ), + "cavalry": SourceGrid( + "cavalry", + "cavalry-master.png", + (34, 193, 352, 510, 670, 828, 991), + ((25, 205, 380, 559, 735), (768, 954, 1129, 1308, 1484)), + 5, + ), + "rebel": SourceGrid( + "rebel", + "rebel-master.png", + (160, 346, 535, 723, 912, 1100, 1289), + ((17, 138, 263, 390, 504), (518, 647, 769, 893, 1017)), + 5, + ), + "nanman": SourceGrid( + "nanman", + "nanman-master.png", + (18, 180, 343, 506, 667, 833, 997), + ((13, 183, 353, 519, 687), (711, 913, 1110, 1303, 1485)), + 5, + ), + "commander": SourceGrid( + "commander", + "commander-master.png", + (16, 174, 330, 486, 642, 795, 948), + ((9, 201, 389, 571, 757), (783, 977, 1162, 1347, 1510)), + 5, + ), +} + +REPRESENTATIVE_UNITS = ( + "unit-liu-bei", + "unit-guan-yu", + "unit-zhang-fei", + "unit-shu-archer", + "unit-shu-strategist", + "unit-zhao-yun", + "unit-rebel", + "unit-rebel-archer", + "unit-rebel-cavalry", + "unit-wei-infantry", + "unit-wu-cavalry", + "unit-nanman-shaman", +) + +FACTION_TARGETS = { + "shu": ((49, 124, 79), (219, 179, 76)), + "wei": ((67, 83, 156), (213, 171, 77)), + "wu": ((36, 132, 140), (219, 148, 76)), + "rebel": ((143, 103, 55), (196, 143, 62)), + "nanman": ((158, 84, 47), (210, 148, 66)), +} + +SIGNATURE_TARGETS = { + "unit-liu-bei": ((48, 130, 78), (229, 190, 83)), + "unit-guan-yu": ((32, 118, 64), (225, 181, 75)), + "unit-zhang-fei": ((137, 47, 45), (222, 163, 68)), + "unit-zhao-yun": ((89, 142, 184), (237, 230, 202)), + "unit-zhuge-liang": ((82, 148, 136), (234, 229, 196)), + "unit-cao-cao": ((63, 75, 150), (214, 174, 78)), + "unit-lu-bu": ((145, 38, 50), (224, 164, 66)), + "unit-meng-huo": ((170, 82, 43), (224, 157, 62)), + "unit-ma-chao": ((98, 144, 186), (231, 219, 170)), + "unit-ma-dai": ((83, 129, 164), (220, 200, 146)), +} + + +def main() -> None: + parser = argparse.ArgumentParser(description="Build final unit sprite sheets from generated raster source sheets.") + parser.add_argument("--only", help="Comma-separated unit stems to rebuild.") + parser.add_argument("--preview-only", action="store_true", help="Only write representative contact sheets.") + args = parser.parse_args() + + stems = list(REPRESENTATIVE_UNITS) if args.preview_only and not args.only else discover_unit_stems(normalize_only(args.only)) + library = RasterLibrary() + + rendered: dict[str, tuple[Image.Image, Image.Image]] = {} + for stem in stems: + style = unit_style(stem) + base_sheet = build_base_sheet(library, style) + action_sheet = build_action_sheet(library, style) + if stem in REPRESENTATIVE_UNITS: + rendered[stem] = (base_sheet.copy(), action_sheet.copy()) + if not args.preview_only: + save_png(base_sheet, UNIT_DIR / f"{stem}.png") + save_png(action_sheet, UNIT_DIR / f"{stem}-actions.png") + + for stem in REPRESENTATIVE_UNITS: + if stem not in rendered: + style = unit_style(stem) + rendered[stem] = (build_base_sheet(library, style), build_action_sheet(library, style)) + + write_contact_sheet(rendered, CONTACT_PATH) + write_actual_size_preview(rendered, ACTUAL_SIZE_PATH) + print(f"Raster-built {len(stems)} unit sprite definitions.") + print(f"Representative contact sheet: {CONTACT_PATH}") + print(f"Actual-size preview: {ACTUAL_SIZE_PATH}") + + +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 + + +class RasterLibrary: + def __init__(self) -> None: + self.sources = { + name: Image.open(SOURCE_DIR / grid.file).convert("RGB") + for name, grid in SOURCES.items() + } + self.cell_cache: dict[tuple[str, int, str, int], Image.Image] = {} + self.frame_cache: dict[tuple[UnitStyle, str, int], Image.Image] = {} + + def frame(self, style: UnitStyle, direction: str, col: int) -> Image.Image: + frame_key = (style, direction, col) + if frame_key in self.frame_cache: + return self.frame_cache[frame_key].copy() + key = (style.source, style.section, direction, col) + if key not in self.cell_cache: + self.cell_cache[key] = self.extract_cell(SOURCES[style.source], style.section, direction, col) + cell = self.cell_cache[key].copy() + cell = apply_unit_variant(cell, style) + frame = place_on_canvas(cell, style, direction) + self.frame_cache[frame_key] = frame + return frame.copy() + + def extract_cell(self, grid: SourceGrid, section: int, direction: str, col: int) -> Image.Image: + image = self.sources[grid.name] + row = DIRECTIONS.index(direction) + y_lines = grid.y_lines_by_section[section] + x0 = grid.x_lines[col] + 2 + x1 = grid.x_lines[col + 1] - 2 + y0 = y_lines[row] + 2 + y1 = y_lines[row + 1] - 2 + crop = image.crop((x0, y0, x1, y1)) + transparent = remove_cell_background(crop) + bbox = transparent.getbbox() + if bbox: + transparent = transparent.crop(bbox) + return transparent + + +def build_base_sheet(library: RasterLibrary, style: UnitStyle) -> Image.Image: + sheet = Image.new("RGBA", (FRAME_SIZE * BASE_FRAMES_PER_DIRECTION, FRAME_SIZE * len(DIRECTIONS)), (0, 0, 0, 0)) + grid = SOURCES[style.source] + idle_seq = idle_sequence(grid.base_cols) + move_seq = move_sequence(grid.base_cols) + for row, direction in enumerate(DIRECTIONS): + for frame_index, col in enumerate(idle_seq): + frame = library.frame(style, direction, col) + frame = motion_adjust(frame, style, "idle", frame_index, len(idle_seq), direction) + sheet.alpha_composite(frame, (frame_index * FRAME_SIZE, row * FRAME_SIZE)) + for frame_index, col in enumerate(move_seq): + frame = library.frame(style, direction, col) + frame = motion_adjust(frame, style, "move", frame_index, len(move_seq), direction) + sheet.alpha_composite(frame, ((IDLE_FRAME_COUNT + frame_index) * FRAME_SIZE, row * FRAME_SIZE)) + return sheet + + +def build_action_sheet(library: RasterLibrary, style: UnitStyle) -> Image.Image: + sheet = Image.new("RGBA", (FRAME_SIZE * ACTION_FRAMES_PER_DIRECTION, FRAME_SIZE * len(DIRECTIONS)), (0, 0, 0, 0)) + grid = SOURCES[style.source] + for row, direction in enumerate(DIRECTIONS): + for action in ACTION_ORDER: + seq = action_sequence(action, grid) + start_col = ACTION_COLUMN_OFFSETS[action] + for frame_index, source_col in enumerate(seq): + frame = library.frame(style, direction, source_col) + frame = motion_adjust(frame, style, action, frame_index, len(seq), direction) + sheet.alpha_composite(frame, ((start_col + frame_index) * FRAME_SIZE, row * FRAME_SIZE)) + return sheet + + +def idle_sequence(base_cols: int) -> list[int]: + if base_cols >= 6: + return [0, 1, 2, 3, 4, 5, 4, 2] + return [0, 1, 2, 3, 4, 3, 2, 1] + + +def move_sequence(base_cols: int) -> list[int]: + if base_cols >= 6: + return [1, 2, 3, 4, 5, 4, 2, 0] + return [1, 2, 3, 4, 3, 2, 1, 0] + + +def action_sequence(action: str, grid: SourceGrid) -> list[int]: + attack = grid.attack_col + ready = max(0, attack - 1) + if action == "attack": + return [0, 1, ready, attack, attack, ready, 2, 1, 0, 0] + if action == "strategy": + return [0, 1, ready, attack, attack, ready, 1, 0] + if action == "item": + return [0, 1, 2, ready, attack, ready, 1, 0] + if action == "hurt": + return [0, 1, 1, 0] + return [0, 1, 2, ready, attack, 1] + + +def motion_adjust(frame: Image.Image, style: UnitStyle, action: str, index: int, count: int, direction: str) -> Image.Image: + result = frame.copy() + phase = math.sin((index / max(1, count)) * math.tau) + if action == "idle": + return offset_frame(result, 0, -1 if phase > 0.55 else 0) + if action == "move": + stride = 3 if style.role == "cavalry" else 2 + dx, dy = direction_delta(direction) + return offset_frame(result, int(dx * stride * phase), int(dy * stride * phase) - abs(int(phase))) + if action == "attack": + dx, dy = direction_delta(direction) + lunge = max(0, math.sin((index / max(1, count - 1)) * math.pi)) * (9 if style.role == "cavalry" else 6) + return offset_frame(result, int(dx * lunge), int(dy * lunge * 0.45)) + if action == "hurt": + result = tint_rgba(result, (180, 55, 45), 0.2 + index * 0.04) + dx, _ = direction_delta(direction) + return offset_frame(result, int(-dx * (index + 1) * 2), -1) + if action == "celebrate": + lift = 4 if index in (2, 3) else 0 + return offset_frame(result, 0, -lift) + if action in ("strategy", "item"): + return brighten_frame(result, 1.0 + (0.05 if index in (3, 4) else 0)) + return result + + +def direction_delta(direction: str) -> tuple[int, int]: + return { + "south": (0, 1), + "east": (1, 0), + "north": (0, -1), + "west": (-1, 0), + }[direction] + + +def offset_frame(image: Image.Image, dx: int, dy: int) -> Image.Image: + if dx == 0 and dy == 0: + return image + result = Image.new("RGBA", image.size, (0, 0, 0, 0)) + result.alpha_composite(image, (dx, dy)) + return result + + +def brighten_frame(image: Image.Image, factor: float) -> Image.Image: + rgb = ImageEnhance.Brightness(image.convert("RGB")).enhance(factor) + rgb.putalpha(image.getchannel("A")) + return rgb + + +def remove_cell_background(image: Image.Image) -> Image.Image: + rgb = image.convert("RGB") + w, h = rgb.size + border_samples: list[tuple[int, int, int]] = [] + for x in range(w): + border_samples.append(rgb.getpixel((x, 0))) + border_samples.append(rgb.getpixel((x, h - 1))) + for y in range(h): + border_samples.append(rgb.getpixel((0, y))) + border_samples.append(rgb.getpixel((w - 1, y))) + bg = tuple(sorted(channel)[len(channel) // 2] for channel in zip(*border_samples)) + visited = bytearray(w * h) + alpha = bytearray([255] * (w * h)) + queue: deque[tuple[int, int]] = deque() + for x in range(w): + queue.append((x, 0)) + queue.append((x, h - 1)) + for y in range(h): + queue.append((0, y)) + queue.append((w - 1, y)) + tolerance = 48 + while queue: + x, y = queue.popleft() + if x < 0 or y < 0 or x >= w or y >= h: + continue + index = y * w + x + if visited[index]: + continue + visited[index] = 1 + pixel = rgb.getpixel((x, y)) + if color_distance(pixel, bg) > tolerance and not is_background_shadow(pixel, bg): + continue + alpha[index] = 0 + queue.append((x + 1, y)) + queue.append((x - 1, y)) + queue.append((x, y + 1)) + queue.append((x, y - 1)) + + rgba = rgb.convert("RGBA") + rgba.putalpha(Image.frombytes("L", (w, h), bytes(alpha)).filter(ImageFilter.GaussianBlur(0.35))) + return rgba + + +def is_background_shadow(pixel: tuple[int, int, int], bg: tuple[int, int, int]) -> bool: + pr, pg, pb = pixel + br, bgc, bb = bg + return pr < br + 18 and pg < bgc + 18 and pb < bb + 18 and max(pixel) - min(pixel) < 35 + + +def color_distance(a: tuple[int, int, int], b: tuple[int, int, int]) -> float: + return math.sqrt(sum((left - right) ** 2 for left, right in zip(a, b))) + + +def apply_unit_variant(image: Image.Image, style: UnitStyle) -> Image.Image: + seed = stable_int(f"{style.source}:{style.section}:{style.role}:{style.faction}:{style.rank}") + strength = 0.26 + (style.rank * 0.04) + if style.faction in {"rebel", "nanman"}: + strength += 0.08 + if style.source == "commander": + strength *= 0.72 + shifted = shift_hue(image, ((seed % 13) - 6) / 240.0) + tinted = tint_rgba(shifted, style.target, strength) + rgb = ImageEnhance.Contrast(tinted.convert("RGB")).enhance(1.04 + style.rank * 0.035) + rgb = ImageEnhance.Brightness(rgb).enhance(1.12 + style.rank * 0.025) + rgb.putalpha(tinted.getchannel("A")) + return rgb + + +def tint_rgba(image: Image.Image, color: tuple[int, int, int], strength: float) -> Image.Image: + rgba = image.convert("RGBA") + pixels = rgba.load() + target = color + for y in range(rgba.height): + for x in range(rgba.width): + r, g, b, a = pixels[x, y] + if a == 0: + continue + if max(r, g, b) - min(r, g, b) < 18 and r > 160: + continue + lum = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 + local_strength = strength * (0.55 + 0.35 * (1 - lum)) + pixels[x, y] = ( + clamp(r * (1 - local_strength) + target[0] * local_strength), + clamp(g * (1 - local_strength) + target[1] * local_strength), + clamp(b * (1 - local_strength) + target[2] * local_strength), + a, + ) + return rgba + + +def shift_hue(image: Image.Image, amount: float) -> Image.Image: + if abs(amount) < 0.001: + return image.copy() + rgba = image.convert("RGBA") + pixels = rgba.load() + for y in range(rgba.height): + for x in range(rgba.width): + r, g, b, a = pixels[x, y] + if a == 0: + continue + h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255) + if s < 0.12 or v > 0.88: + continue + h = (h + amount) % 1.0 + nr, ng, nb = colorsys.hsv_to_rgb(h, s, v) + pixels[x, y] = (round(nr * 255), round(ng * 255), round(nb * 255), a) + return rgba + + +def place_on_canvas(sprite: Image.Image, style: UnitStyle, direction: str) -> Image.Image: + bbox = sprite.getbbox() + if bbox: + sprite = sprite.crop(bbox) + max_w, max_h = target_bounds(style, direction) + scale = min(max_w / sprite.width, max_h / sprite.height) * style.scale + scale = min(scale, max_w / sprite.width, max_h / sprite.height) + new_size = (max(1, round(sprite.width * scale)), max(1, round(sprite.height * scale))) + sprite = sprite.resize(new_size, Image.Resampling.LANCZOS) + canvas = Image.new("RGBA", (FRAME_SIZE, FRAME_SIZE), (0, 0, 0, 0)) + x = (FRAME_SIZE - sprite.width) // 2 + if direction == "east": + x += 4 + elif direction == "west": + x -= 4 + bottom = 294 if style.role != "cavalry" else 296 + y = bottom - sprite.height + canvas.alpha_composite(sprite, (x, y)) + return canvas + + +def target_bounds(style: UnitStyle, direction: str) -> tuple[int, int]: + if style.role == "cavalry": + if direction in {"east", "west"}: + return (304, 262) + return (252, 276) + if style.role == "strategist": + return (190, 260) + if style.role == "archer": + return (198, 252) + if style.role in {"lord", "officer"}: + return (220, 268) + if style.role == "spearman": + return (226, 266) + return (208, 258) + + +def unit_style(stem: str) -> UnitStyle: + lower = stem.lower() + faction = infer_faction(lower) + role = infer_role(lower) + rank = infer_rank(lower) + target, secondary = SIGNATURE_TARGETS.get(stem, FACTION_TARGETS[faction]) + source, section = source_for(stem, faction, role, rank) + scale = 1.0 + bulk = 1.0 + if role == "strategist": + scale *= 0.96 + bulk *= 0.9 + elif role == "archer": + scale *= 0.98 + elif role == "cavalry": + scale *= 1.0 + elif role in {"lord", "officer"}: + scale *= 1.04 + if "ragged" in lower or "scout" in lower: + scale *= 0.96 + if "veteran" in lower or "elite" in lower or "warlord" in lower: + scale *= 1.03 + rank = max(rank, 1) + if rank >= 2: + scale *= 1.04 + return UnitStyle(source, section, faction, role, rank, target, secondary, scale, bulk) + + +def source_for(stem: str, faction: str, role: str, rank: int) -> tuple[str, int]: + lower = stem.lower() + if faction == "nanman": + if role == "strategist" or "shaman" in lower: + return "nanman", 1 + return "nanman", 0 + if faction == "rebel": + if role in {"archer", "strategist"}: + return "rebel", 1 + return "rebel", 0 + if role == "cavalry": + return "cavalry", 1 if any(token in lower for token in ("zhao-yun", "ma-chao", "ma-dai", "white", "elite")) else 0 + if role == "archer": + return "ranged", 0 + if role == "strategist": + return "ranged", 1 + if role in {"lord", "officer"} or rank >= 2: + if any(token in lower for token in ("guan-yu", "zhang-fei", "wei-yan")): + return "commander", 1 + return "commander", 0 + if role == "spearman": + return "infantry", 1 + return "infantry", 0 + + +def infer_faction(lower: str) -> str: + if "nanman" in lower or "meng-huo" in lower: + return "nanman" + if lower.startswith("unit-wu-") or "lu-meng" in lower: + return "wu" + if lower.startswith("unit-wei-") or any(token in lower for token in ("cao-cao", "sima-yi")): + return "wei" + if "rebel" in lower or "yellow" in lower or "bandit" in lower: + return "rebel" + return "shu" + + +def infer_role(lower: str) -> str: + if "cavalry" in lower or any(token in lower for token in ("zhao-yun", "ma-chao", "ma-dai", "lu-bu")): + return "cavalry" + if "archer" in lower or "crossbow" in lower or "longbow" in lower or "huang-zhong" in lower: + return "archer" + if any(token in lower for token in ("strategist", "shaman", "zhuge", "sima", "fa-zheng", "ma-liang", "yi-ji", "pang-tong")): + return "strategist" + if "spearman" in lower or any(token in lower for token in ("guan-yu", "zhang-fei", "jiang-wei", "yan-yan")): + return "spearman" + if any(token in lower for token in ("liu-bei", "cao-cao")): + return "lord" + if "leader" in lower or "officer" in lower or any(token in lower for token in ("meng-huo", "wei-yan", "wang-ping", "wu-yi", "li-yan", "huang-quan", "gong-zhi")): + return "officer" + return "infantry" + + +def infer_rank(lower: str) -> int: + if any(token in lower for token in ("liu-bei", "guan-yu", "zhang-fei", "zhao-yun", "cao-cao", "lu-bu", "zhuge", "sima", "ma-chao", "meng-huo")): + return 2 + if any(token in lower for token in ("officer", "leader", "veteran", "elite", "guard", "warlord")): + return 1 + return 0 + + +def stable_int(value: str) -> int: + return int(hashlib.sha256(value.encode("utf-8")).hexdigest()[:8], 16) + + +def clamp(value: float) -> int: + return max(0, min(255, round(value))) + + +def save_png(image: Image.Image, path: Path) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + output = image + if image.mode == "RGBA": + output = image.quantize(colors=PNG_PALETTE_COLORS, method=Image.Quantize.FASTOCTREE) + temporary_path = path.with_name(f".{path.stem}.tmp.png") + output.save(temporary_path, optimize=True) + temporary_path.replace(path) + + +def write_contact_sheet(rendered: dict[str, tuple[Image.Image, Image.Image]], path: Path) -> None: + cell = 66 + label_w = 148 + gap = 14 + rows_per_unit = 8 + width = label_w + cell * 10 + 36 + height = 34 + len(REPRESENTATIVE_UNITS) * (rows_per_unit * cell + gap) + 12 + sheet = Image.new("RGB", (width, height), (30, 36, 28)) + y = 18 + for stem in REPRESENTATIVE_UNITS: + base, action = rendered[stem] + draw_label(sheet, stem, 12, y + 8) + for direction_index, direction in enumerate(DIRECTIONS): + row_y = y + direction_index * cell + draw_label(sheet, f"idle {direction}", 12, row_y + 28, small=True) + for col in range(6): + frame = base.crop((col * FRAME_SIZE, direction_index * FRAME_SIZE, (col + 1) * FRAME_SIZE, (direction_index + 1) * FRAME_SIZE)) + paste_thumb(sheet, frame, label_w + col * cell, row_y, cell) + action_y = y + 4 * cell + for direction_index, direction in enumerate(DIRECTIONS): + row_y = action_y + direction_index * cell + draw_label(sheet, f"atk {direction}", 12, row_y + 28, small=True) + for col in range(6): + frame_index = ACTION_COLUMN_OFFSETS["attack"] + col + 2 + frame = action.crop((frame_index * FRAME_SIZE, direction_index * FRAME_SIZE, (frame_index + 1) * FRAME_SIZE, (direction_index + 1) * FRAME_SIZE)) + paste_thumb(sheet, frame, label_w + col * cell, row_y, cell) + y += rows_per_unit * cell + gap + save_png(sheet, path) + + +def write_actual_size_preview(rendered: dict[str, tuple[Image.Image, Image.Image]], path: Path) -> None: + tile = 82 + cols = 6 + rows = math.ceil(len(REPRESENTATIVE_UNITS) / cols) + width = 72 + cols * 150 + height = 72 + rows * 126 + image = Image.new("RGB", (width, height), (28, 36, 29)) + for x in range(0, width, tile): + for y in range(height): + image.putpixel((x, y), (50, 61, 48)) + for y in range(0, height, tile): + for x in range(width): + image.putpixel((x, y), (50, 61, 48)) + draw_label(image, "Actual tactical scale preview", 24, 18) + for index, stem in enumerate(REPRESENTATIVE_UNITS): + base, _ = rendered[stem] + col = index % cols + row = index // cols + x = 40 + col * 150 + y = 58 + row * 126 + frame = base.crop((0, 0, FRAME_SIZE, FRAME_SIZE)) + paste_thumb(image, frame, x, y, 86) + draw_label(image, stem.replace("unit-", ""), x, y + 88, small=True) + save_png(image, path) + + +def paste_thumb(sheet: Image.Image, frame: Image.Image, x: int, y: int, cell: int) -> None: + frame = frame.copy() + frame.thumbnail((cell - 6, cell - 6), Image.Resampling.LANCZOS) + box = Image.new("RGB", (cell - 2, cell - 2), (43, 51, 39)) + sheet.paste(box, (x + 1, y + 1)) + px = x + (cell - frame.width) // 2 + py = y + cell - frame.height - 3 + sheet.paste(frame, (px, py), frame) + + +def draw_label(image: Image.Image, text: str, x: int, y: int, small: bool = False) -> None: + from PIL import ImageDraw, ImageFont + + draw = ImageDraw.Draw(image) + font_size = 11 if small else 15 + font = None + for candidate in (r"C:\Windows\Fonts\malgun.ttf", r"C:\Windows\Fonts\arial.ttf"): + try: + font = ImageFont.truetype(candidate, font_size) + break + except OSError: + continue + draw.text((x, y), text, fill=(223, 212, 169), font=font) + + +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 4e427df..5a7b4f4 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 1da722a..31fe7ee 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 59f7f16..04050d7 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 f42e4e8..0e17f67 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 3d7854d..c1f8860 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 3937e3a..e566dcb 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 9a4dcab..ecd4381 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 395874e..3f5b784 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 b3e35dd..c1f8860 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 2570160..e566dcb 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 1e5eff4..2b18eda 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 b5cc612..40bdc3b 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 6962c2b..29fc69b 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 869c9eb..64c8c76 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 ed01f71..c1f8860 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 e1504b0..e566dcb 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 50f5855..7c94c0f 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 9428380..4a6d2b4 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 e518167..b1a0a7e 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 b3e3cee..a046715 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 24aef4d..8aa8bf4 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 4d8fb5e..4644094 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 222b1fa..1e649f2 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 e3d6107..713547e 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 2175bc2..8ab8a6c 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 7858f25..d8831b0 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 d8920a1..04050d7 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 a778acc..0e17f67 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 a5c2ee9..4ab154f 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 0512c38..a5e2ada 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 c7d7e89..bb5e845 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 0ab844f..bb5e845 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 90cac11..767bb9f 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 3e3c46e..bb5e845 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 10b98ee..767bb9f 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 0b4a682..767bb9f 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 4b75b50..2f0acbc 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 5621ac9..2f0acbc 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 5aeb7cf..275be67 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 fecc3a3..2f0acbc 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 07eb97d..275be67 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 8cfecb6..275be67 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 d25e817..873762a 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 d348a75..873762a 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 d6adcb2..754f683 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 9ca1967..873762a 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 d742747..754f683 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 5b2083a..754f683 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 a9a09cf..04050d7 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 230a22e..0e17f67 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 269ff7a..c2d0917 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 077d922..fe69396 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 ff7ff83..fe69396 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 8cd24a0..c0518c7 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 0b45f84..ce22276 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 4596dce..5c1c609 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 dc81661..c0518c7 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 df00687..b0bf1c5 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 3c5c3c8..366a12c 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 3f52c4f..f71ac86 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 8ea3f9b..6261ae0 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 28384b2..ab78564 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 d40f9a0..ab78564 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 65085af..bba9a62 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 9931a59..bba9a62 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 8301b24..06c044e 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 08521c5..27c2a02 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 beef145..3e2c2fd 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 56146c0..2b18eda 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 c5258c3..2b18eda 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 1fc881a..40bdc3b 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 7d3b789..ab3bfc1 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 0527560..6a49c72 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 88cf638..40bdc3b 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 c54dc2c..9e12d2e 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 a20c880..bcd349a 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 5024863..a583f4a 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 969d993..d150104 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 029be2e..182bff0 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 b2ce18c..d1624fb 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 49b4966..d5f6033 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 5e4e6f5..d5f6033 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 d8ddaf1..3fd5a1d 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 2874e8c..4599cc0 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 fd9f3de..73acc76 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 6f33710..3fd5a1d 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 f4bf6cc..f0676dc 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 8a70598..f0676dc 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 92aeb59..b743dc6 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 aef6709..f0676dc 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 508c241..b743dc6 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 a0b4f59..b743dc6 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 94841dc..29fc69b 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 db98b10..7bc8afe 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 e6ec794..ad7c16c 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 c22ddfd..7bc8afe 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 47a1cd8..ad7c16c 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 c04b97b..64c8c76 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 7bb78b0..04050d7 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 9723cdb..04050d7 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 6d8bb4f..0e17f67 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 4874082..04050d7 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 4a21738..0e17f67 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 7bdd019..0e17f67 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 9b697f8..2fd3037 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 88344de..178352f 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 3a2b1fa..c1f8860 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 05bf157..e566dcb 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 ad7178c..e4aa9d0 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 bbadb21..e4aa9d0 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 79c1c6d..129505d 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 8510e35..c311454 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 1a3a3bd..2fcfdd1 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 22c92b6..129505d 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 038ff85..1ab5233 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 e445820..de3eb76 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 a501d72..d8741d0 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 2f5538d..1ab5233 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 3beaf12..6a10356 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 19c7a04..6a10356 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 bc59a69..a0feb9e 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 de44694..a0feb9e 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 fa9e727..96033d5 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 8608790..638f24c 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 1daf51d..100bbff 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 0a59566..96033d5 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 cebd874..d690569 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 b1be2d6..d690569 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 be808de..eae21b7 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 ca1cb2d..d690569 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 8c7b160..eae21b7 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 f1c9cf9..eae21b7 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 71817e4..527e591 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 bfd1c5b..527e591 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 d15e5eb..2b741eb 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 ee6812b..527e591 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 518561c..2b741eb 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 7515488..2b741eb 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 5e74bd2..ffd4ecd 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 b84be73..d2fc766 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 ba1a126..6f88cd2 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 87a83dd..6f88cd2 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 17bb1ec..6e152f6 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 9c8758d..6f88cd2 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 8bf22a5..6e152f6 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 bcbe97a..6e152f6 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 3df9468..76cc70e 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 7a18a45..957507e 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 7b9f4ab..b062838 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 0b3f14c..76cc70e 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 6ed4bd0..db78b13 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 39aa78a..db78b13 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 af3f625..8aa8bf4 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 10a46e8..8aa8bf4 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 d221a44..4644094 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 00132d5..8aa8bf4 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 382f1e4..4644094 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 e15f55c..4644094 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 421a759..27b810b 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 cb32174..27b810b 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 09d93d4..1285236 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 960bb65..27b810b 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 ad9fbca..1285236 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 14fee46..1285236 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 0ff9adf..184c9f9 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 536ccc4..184c9f9 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 dd6049c..8ff135b 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 53948c8..184c9f9 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 731bb3b..8ff135b 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 e8db00e..8ff135b 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 8cfd277..a115b6c 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 5bf8779..67a6596 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 5bf5493..29fc69b 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 eb590c8..64c8c76 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 561e362..04050d7 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 e496375..0e17f67 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 aa0f238..ba27761 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 1d5c647..3c3ff7d 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 01d78e4..ceffcbc 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 39f3b95..17f7894 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 5689f21..b801186 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 fc27036..f8767e9 100644 Binary files a/src/assets/images/units/unit-zhuge-liang.png and b/src/assets/images/units/unit-zhuge-liang.png differ