/*
 * sprite_anim — запустить кадровую авто-анимацию: кадры first..last
 * вдоль оси ленты (вертикальная; ANIM_HORIZ — вдоль X), смена раз в
 * speed кадров, mode = ANIM_LOOP / ANIM_PINGPONG / ANIM_ONCE.
 *
 * Всё дорогое считается ЗДЕСЬ один раз, чтобы тикеру осталась только
 * 16-бит арифметика указателя:
 *   an_step  — шаг кадра в БАЙТАХ src: fw (гориз. лента: следующий кадр
 *              правее на ширину кадра) или fh*stride (верт.: ниже на
 *              fh строк источника);
 *   an_src0  — готовый адрес кадра first (для wrap ANIM_LOOP: тикер
 *              прыгает указателем, ничего не пересчитывая).
 * Смена кадра тикером = s->src ± an_step; sx/sy тикер НЕ трогает
 * (см. sprite.h про кэш src).
 *
 * Ставит текущий кадр на first (через sprite_frame — единственную
 * точку пересчёта (sx,sy)→src), сбрасывает SPR_ANIM_DONE, подключает
 * тикер (_spr_tick_fn) — до первого вызова sprite_anim/sprite_moveto
 * код тикера в программу не линкуется.  Требование: индексы ≤ 127,
 * first ≤ last.  Move-статусы (SPR_MOVE_*) не трогаются.
 */
#include "../_bgi.h"
#include <sprite.h>

void sprite_anim(sprite_t *s, uint8_t first, uint8_t last,
                 uint8_t speed, uint8_t mode)
{
    uint8_t f = s->an_flags & (SPR_MOVE_ON | SPR_MOVE_DONE);
    uint8_t step_px = (mode & ANIM_HORIZ) ? s->w : s->h;
    int lo = 0;
    uint8_t i;

    for (i = 0; i < first; i++)
        lo += step_px;                    /* first*step без умножения */

    if (!speed)
        speed = 1;

    /* Ось — на кадр first (sprite_frame пересчитает кэш src + dirty). */
    if (mode & ANIM_HORIZ)
        sprite_frame(s, lo, s->sy);
    else
        sprite_frame(s, s->sx, lo);

    /* Байтовый шаг кадра и адрес first-кадра — всё, что нужно тикеру. */
    s->an_step  = (mode & ANIM_HORIZ)
                      ? s->w
                      : (uint16_t)s->h * s->stride;
    s->an_src0  = s->src;                 /* src уже стоит на first */
    s->an_first = first;
    s->an_last  = last;
    s->an_frame = first;
    s->an_speed = speed;
    s->an_timer = speed;

    f |= SPR_ANIM_ON;
    if (mode & ANIM_HORIZ)
        f |= _SPR_STRIP_HORZ;
    if ((mode & 0x03u) == ANIM_PINGPONG)
        f |= _SPR_ANIM_PP;
    if ((mode & 0x03u) == ANIM_ONCE)
        f |= _SPR_ANIM_ONCE;
    s->an_flags = f;

    _spr_tick_fn = _sprite_tick;
}
