"""第143〜147話の冒頭の動き（2026-11-08）。話ごとに違う動き（138〜142・134 とも重ねない）
143 右からまっすぐ突っ込んできて、ピタッと急停止（前のめりに揺れる）→「止マレ／マス」→ 得意げ
144 右から来て、左へスーッと通り過ぎかけ → 気づいてバックで戻る → 小さくおじぎ「ドウゾ」
145 来て止まり、大声でぴょんぴょん「オ薬／デス！」→ 縮こまって小さくなり、目が点で静かに待つ「…」
146 待っているところを左から小突かれ（ガクン・画面がゆれる）→ ×目 →「衝撃／検知」→ 右の空いた所へ移る
147 しゃがんで力をためる → 左へ猛ダッシュ（スピード線）→ 戻ってきて、しょんぼり「先ヲ／越サレ…」"""
import sys
import numpy as np
import motion30
import hakobu_motion as M
from hakobu_motion import T, ease, _approach

class Stop143:
    dur = 3.6; empty = True
    HIT = 0.7
    def motion(self, t):
        if t < self.HIT: return dict(dx=360 * (1 - t / self.HIT), dy=-6 * abs(np.sin(2 * np.pi * 5 * t)), rot=-3)
        v = t - self.HIT                               # ピタッ：前のめりに揺れて止まる
        k = np.exp(-v * 8) * np.cos(2 * np.pi * 4 * v)
        return dict(rot=-7 * k, dx=-6 * k)
    def face(self, t):
        if t < self.HIT: return ("open", "open"), None, "mid"
        if t < 1.5: return ("big", "big"), None, "o"
        if t < 2.6: return T("止マレ", "マス")
        return ("happy", "happy"), None, "closed"
    def ring(self, t): return 1.0 if self.HIT <= t < 1.0 else 0.6
    def blur(self, t): return t < self.HIT
    def dim(self, t): return 1.0
    def cam(self, t):
        v = t - self.HIT
        return (int(8 * np.exp(-v * 10) * np.sin(2 * np.pi * 18 * v)), 0) if 0 <= v < 0.35 else (0, 0)

class Back144:
    dur = 3.6; empty = True
    def motion(self, t):
        if t < 1.1: return dict(dx=260 - 520 * ease(t / 1.1), dy=-4 * abs(np.sin(2 * np.pi * 4 * t)))   # 左へ通り過ぎかける
        if t < 1.5: return dict(dx=-260, rot=2 * np.sin(2 * np.pi * 6 * (t - 1.1)))                       # 気づく
        if t < 2.4:                                                                                         # バックで戻る（小刻み）
            v = (t - 1.5) / 0.9
            return dict(dx=-260 + 230 * ease(v), dy=-2 * abs(np.sin(2 * np.pi * 6 * t)))
        v = t - 2.4                                                                                         # おじぎ
        nod = 0.05 * max(0.0, np.sin(np.pi * min(1, v / 0.6)))
        return dict(dx=-30, sy=1 - nod, dy=6 * nod / 0.05)
    def face(self, t):
        if t < 1.1: return ("open", "open"), None, "mid"
        if t < 1.5: return ("big", "big"), None, "o"
        if t < 2.4: return ("down", "down"), "trouble", "wave" if int(t * 8) % 2 else "wave2"
        return T("ドウゾ")
    def ring(self, t): return 0.6
    def blur(self, t): return t < 1.1
    def dim(self, t): return 1.0
    def cam(self, t): return (0, 0)

class Hush145:
    dur = 3.6; empty = True
    def motion(self, t):
        if t < 0.7: return _approach(t, 0.7, 220)
        if t < 2.0:                                    # 大声でぴょんぴょん
            v = t - 0.7
            return dict(dy=-26 * abs(np.sin(2 * np.pi * 2.2 * v)), sy=1 + 0.03 * np.sin(2 * np.pi * 4.4 * v))
        v = min(1, (t - 2.0) / 0.4)                    # 縮こまって静かに待つ
        return dict(sx=1 - 0.06 * ease(v), sy=1 - 0.1 * ease(v), dy=12 * ease(v))
    def face(self, t):
        if t < 0.7: return ("open", "open"), None, "mid"
        if t < 2.0: return T("オ薬", "デス！")
        if t < 2.6: return ("down", "down"), "trouble", "frown"
        return T("…")
    def ring(self, t): return 1.0 if 0.7 <= t < 2.0 else 0.4
    def blur(self, t): return t < 0.7
    def dim(self, t): return 1.0
    def cam(self, t):
        return (int(4 * np.sin(2 * np.pi * 15 * t)), 0) if 0.7 <= t < 2.0 else (0, 0)

class Poke146:
    dur = 3.6; empty = True
    HIT = 0.9
    def motion(self, t):
        if t < self.HIT: return dict(dy=-2 * abs(np.sin(2 * np.pi * 0.8 * t)))           # じっと待つ
        v = t - self.HIT
        if v < 0.8:                                                                       # 左から小突かれてガクン
            k = np.exp(-v * 7) * np.cos(2 * np.pi * 4 * v)
            return dict(dx=30 * (1 - np.exp(-v * 12)), rot=8 * k)
        if t < 2.7: return dict(dx=30)
        w = min(1, (t - 2.7) / 0.6)                                                       # 右の空いた所へ移る
        return dict(dx=30 + 220 * ease(w), dy=-3 * abs(np.sin(2 * np.pi * 4 * t)))
    def face(self, t):
        if t < self.HIT: return T("受ケ取リ", "待チ")
        if t < self.HIT + 0.8: return ("x", "x"), None, "o"
        if t < 2.7: return T("衝撃", "検知")
        return ("open", "open"), None, "mid"
    def ring(self, t): return 1.0 if self.HIT <= t < self.HIT + 0.5 else 0.6
    def blur(self, t): return t >= 2.7
    def dim(self, t): return 1.0
    def cam(self, t):
        v = t - self.HIT
        return (int(12 * np.exp(-v * 9) * np.sin(2 * np.pi * 20 * v)), 0) if 0 <= v < 0.4 else (0, 0)

class Race147:
    dur = 3.6; empty = True
    def motion(self, t):
        if t < 0.8:                                    # しゃがんで力をためる（小刻みにふるえる）
            v = ease(t / 0.8)
            return dict(sy=1 - 0.08 * v, dy=10 * v, dx=3 * np.sin(2 * np.pi * 12 * t))
        if t < 1.3: return dict(dx=-700 * ease((t - 0.8) / 0.5), sx=1.06, sy=0.96)      # 左へ猛ダッシュ
        if t < 1.9: return dict(dx=-700)                                                  # いなくなる
        if t < 2.6: return dict(dx=-700 + 700 * ease((t - 1.9) / 0.7), dy=-3 * abs(np.sin(2 * np.pi * 3 * t)))   # とぼとぼ戻る
        v = min(1, (t - 2.6) / 0.4)                                                       # しょんぼり沈む
        return dict(dy=10 * ease(v), sy=1 - 0.04 * ease(v))
    def face(self, t):
        if t < 0.8: return T("ヨーイ")
        if t < 1.9: return ("open", "open"), None, "o"
        if t < 2.6: return ("down", "down"), "trouble", "frown"
        return T("先ヲ", "越サレ…")
    def ring(self, t): return 1.0 if 0.8 <= t < 1.3 else 0.6
    def blur(self, t): return 0.8 <= t < 1.3
    def dim(self, t): return 1.0
    def cam(self, t): return (0, 0)

M.PATTERNS.update(ep143=Stop143, ep144=Back144, ep145=Hush145, ep146=Poke146, ep147=Race147)
if __name__ == "__main__":
    for arg in sys.argv[1:]:
        nm, _, kv = arg.partition(":")
        pat = M.PATTERNS[nm]()
        for item in filter(None, kv.split(",")):
            k, v = item.split("=", 1)
            if k in motion30.STR: setattr(pat, k, v)
            else: setattr(pat, k, float(v))
        M.render(pat, f"ハコブくん_{nm}.mp4")
