/*
 * sprite_moveto — запустить tween-перемещение к (tx,ty): раз в interval
 * кадров тикер делает до max_step шагов вдоль ГЛАВНОЙ оси (большая
 * |дельта|); минорная ось подтягивается DDA-аккумулятором — нелинейные
 * 2/3/2/3 сами собой, деления нет.  Пример: (0,0)→(100,50), max_step 5,
 * interval 4 → 20 порций × 4 кадра = 80 кадров (1.6 с).
 *
 * Всё дорогое (выбор главной оси, |дельты|, знаки) считается здесь один
 * раз; тикеру остаётся БЕЗЗНАКОВАЯ арифметика (см. sprite.h: acc/rem —
 * на Z80 беззнаковое 16-бит сравнение в разы дешевле знаковых сравнений
 * классического Брезенхэма, ради этого и переформулировано 2026-07-14).
 * За mv_dmaj шагов главной оси минорная получает ровно mv_dmin шагов
 * (аккумулятор со стартом dmaj/2 — симметричное округление), так что
 * обе координаты приходят в цель одновременно; «приехали» = mv_rem == 0.
 *
 * Если цель == текущая позиция — сразу SPR_MOVE_DONE (тикер не
 * включается).  Кадровые статусы (SPR_ANIM_*) не трогаются.
 */
#include "../_bgi.h"
#include <sprite.h>

void sprite_moveto(sprite_t *s, int tx, int ty,
                   uint8_t max_step, uint8_t interval)
{
    int dx = tx - s->x;
    int dy = ty - s->y;
    int8_t sgnx = 1, sgny = 1;

    if (dx < 0) { dx = -dx; sgnx = -1; }
    if (dy < 0) { dy = -dy; sgny = -1; }

    s->an_flags &= (uint8_t)~SPR_MOVE_DONE;
    if (dx == 0 && dy == 0) {
        s->an_flags = (s->an_flags & (uint8_t)~SPR_MOVE_ON) | SPR_MOVE_DONE;
        return;
    }

    s->mv_tx = tx;
    s->mv_ty = ty;

    /* Главная ось — с большей |дельтой| (при равенстве — X, диагональ
     * ровная в обе стороны). */
    if ((uint16_t)dy > (uint16_t)dx) {
        s->mv_ymaj   = 1;
        s->mv_dmaj   = (uint16_t)dy;
        s->mv_dmin   = (uint16_t)dx;
        s->mv_sgnmaj = sgny;
        s->mv_sgnmin = sgnx;
    } else {
        s->mv_ymaj   = 0;
        s->mv_dmaj   = (uint16_t)dx;
        s->mv_dmin   = (uint16_t)dy;
        s->mv_sgnmaj = sgnx;
        s->mv_sgnmin = sgny;
    }
    s->mv_rem = s->mv_dmaj;          /* шагов до цели                  */
    s->mv_acc = s->mv_dmaj >> 1;     /* симметричное округление minor  */

    if (!max_step) max_step = 1;
    if (!interval) interval = 1;
    s->mv_step  = max_step;
    s->mv_speed = interval;
    s->mv_timer = interval;

    s->an_flags |= SPR_MOVE_ON;
    _spr_tick_fn = _sprite_tick;
}
