#include <vectrex.h>
// does not work with any -O options.  Immediately obvious when using button 1

#define abs(x) (x < 0 ? -x:x)
#define sgn(x) (x < 0 ? -1:1)

#define LAST_STAR 32
static int sx[LAST_STAR], sy[LAST_STAR];
static unsigned int sz[LAST_STAR];

static unsigned long rseed = 12345L;
static int rand (void) { // silliness.
  int i = (int)Random();
  if (i&16) return (int) (rseed = (rseed * 2053UL) + 13849UL);
  return i;
}

int main(void) {
  unsigned int star;
  int x, y, x_rot_val, y_rot_val;
  long tmp;
  unsigned int z;
  // x,y are as screen, z is 0 at a distance, 255 close-up.
  int band;

  for (x = 0; x < LAST_STAR; x++) {
    sx[x] = (int)rand(); sy[x] = (int)rand(); sz[x] = (unsigned int)rand();
  }

  for (;;) {
    Wait_Recal();
    Reset0Ref();
    VIA_t1_cnt_lo = (0x80);
    Joy_Analog();
    x_rot_val = Vec_Joy_1_X>>4;
    y_rot_val = Vec_Joy_1_Y>>4;
    star = 0;
    Read_Btns();
    for (star = 0; star < LAST_STAR; star++) {

      x = sx[star]; y = sy[star]; z = sz[star];

      if ((Vec_Btn_State&1) != 0) {
        unsigned int oz = z;
        // backward - stars converge into center
        x = (int)(((long)x * 15L) >> 4L);
        y = (int)(((long)y * 15L) >> 4L);
        if ((abs(x) <= 31) && (abs(y) <= 31)) {
          if (rand()&32) {
            x = rand();
            y = 127 * (rand()&8 ? 1 : -1);
          } else {
            x = 127 * (rand()&8 ? 1 : -1);
            y = rand();
          }
          z = 254;
        } else {
          z -= 8;
          if (sgn((int)oz) != sgn((int)z)) {
            x = rand(); y = rand();
          }
        }
      }

      if ((Vec_Btn_State&2) != 0) {
        unsigned int oz = z;
        // forward - stars spread out away from center
        tmp = ((long)x * 17L) >>4;
        if (abs(tmp) > 127L) {
          x = rand(); // (rand()&31)*sgn(tmp);
          do {y = rand();} while (abs(y)<32); // sgn(y)*32;
          z = 0;
        } else {
          x = (int)tmp;
          z += 4;
        }
        tmp = ((long)y * 17L) >>4;
        if (abs(tmp) > 127L) {
          do {x = rand();} while (abs(x)<32); // sgn(x)*32;
          y = rand(); // (rand()&31)*sgn(tmp);
          z = 0;
        } else {
          y = (int)tmp;
          z += 4;
        }
        if (sgn((int)oz) != sgn((int)z)) {
          x = rand(); y = rand();
        }
      }

      if ((Vec_Btn_State&4) != 0) {
        // rotate clockwise
        int from[2], to[2];
        from[0] = y; from[1] = x;
        Rot_VL_ab(1, 1, from, to);
        y = to[0]; x = to[1];
      }

      if ((Vec_Btn_State&8) != 0) {
        // rotate anti-clockwise
        int from[2], to[2];
        from[0] = y; from[1] = x;
        Rot_VL_ab((unsigned int)-1, 1, from, to);
        y = to[0]; x = to[1];
      }

      // movement in x or y is proportional to distance - nearer (higher 'z') = more
      band = (int)((z>>5U)+1U); // 1..8
      // still to modify this by analog value of joystick...
      {int ox=x, oy=y;
      if (x_rot_val > 4) {
        x+=band;
        if ((sgn(ox)>0) && (sgn(x)<0)) { y=rand(); z=(unsigned int)rand(); }
      }
      if (x_rot_val < -4) {
        x-=band;
        if ((sgn(ox)<0) && (sgn(x)>0)) { y=rand(); z=(unsigned int)rand(); }
      }
      if (y_rot_val > 4) {
        y+=band;
        if ((sgn(oy)>0) && (sgn(y)<0)) { x=rand(); z=(unsigned int)rand(); }
      }
      if (y_rot_val < -4) {
        y-=band;
        if ((sgn(oy)<0) && (sgn(y)>0)) { x=rand(); z=(unsigned int)rand(); }
      }
      }

      sx[star] = x;
      sy[star] = y;
      sz[star] = z;

      Reset0Ref();
      VIA_t1_cnt_lo = (0x80);
      Intensity_a(0x10+(unsigned int)(z>>2U)); // nearer (higher 'z') is brighter
      Dot_d(y, x);

    }
  }
  return 0;
}