// Dino: any key = jump over the cacti. The game speeds up with the distance.
#pragma once

const int16_t DINO_GROUND = 58;
const int16_t DINO_X = 12;

struct Cactus {
  int16_t x;
  uint8_t w, h;
};

struct DinoState {
  int16_t y16, vy16;                         // dino height, 1/16 px
  uint32_t dist;
  uint8_t speed, frame;
  uint16_t gap;                              // pixels of road until the next cactus
  Cactus cactus[3];
};

void dino_init(DinoState &g) {
  memset(&g, 0, sizeof g);
  g.speed = 3;
  g.gap = 60;

  for (uint8_t i = 0; i < 3; i++) {
    g.cactus[i].x = -100;
  }
}

void dino_update(DinoState &g) {
  bool on_ground = g.y16 == 0;

  if (on_ground && (any_tap() || key_down[KEY_M])) {
    g.vy16 = 85;
  }

  g.y16 += g.vy16;
  g.vy16 -= 9;

  if (g.y16 <= 0) {
    g.y16 = 0;
    g.vy16 = 0;
  }

  g.frame++;
  g.dist += g.speed;
  score = g.dist / 8;
  g.speed = 3 + score / 150;

  if (g.speed > 7) {
    g.speed = 7;
  }

  for (uint8_t i = 0; i < 3; i++) {
    if (g.cactus[i].x > -100) {              // a cactus that has left the screen waits at -100
      g.cactus[i].x -= g.speed;
    }
  }

  // the next cactus comes after `gap` pixels of road: always more than one jump, so every cactus can be jumped
  if (g.gap > g.speed) {
    g.gap -= g.speed;
  } else {
    for (uint8_t i = 0; i < 3; i++) {
      if (g.cactus[i].x + g.cactus[i].w < 0) {
        static const uint8_t widths[3] = {5, 9, 13};
        g.cactus[i].x = 128;
        g.cactus[i].w = widths[random(3)];
        g.cactus[i].h = 9 + random(6);
        g.gap = g.speed * 22 + random(g.speed * 14);
        break;
      }
    }
  }

  int16_t top = DINO_GROUND - 14 - g.y16 / 16;

  for (uint8_t i = 0; i < 3; i++) {
    Cactus &c = g.cactus[i];

    if (hit(DINO_X + 2, top + 2, 8, 11, c.x + 1, DINO_GROUND - c.h, c.w - 2, c.h)) {
      end_game();
    }
  }
}

void dino_draw(DinoState &g) {
  int16_t y = DINO_GROUND - 14 - g.y16 / 16;
  box(DINO_X + 6, y, 7, 6);
  box(DINO_X + 2, y + 5, 8, 6);
  box(DINO_X, y + 6, 3, 3);
  box(DINO_X + 2, y + 11, 2, 3);
  box(DINO_X + 6, y + 11, 2, (g.y16 == 0 && (g.frame / 3) & 1) ? 2 : 3);
  oled.setDrawColor(0);
  oled.drawPixel(DINO_X + 10, y + 1);
  oled.setDrawColor(1);
  oled.drawHLine(0, DINO_GROUND, 128);

  for (uint8_t i = 0; i < 6; i++) {
    int16_t x = (i * 29 - (int16_t)g.dist) % 128;

    if (x < 0) {
      x += 128;
    }

    oled.drawPixel(x, DINO_GROUND + 2 + (i & 1) * 2);
  }

  for (uint8_t i = 0; i < 3; i++) {
    Cactus &c = g.cactus[i];

    for (uint8_t k = 0; k + 3 <= c.w; k += 5) {
      uint8_t h = (k / 5) & 1 ? c.h - 3 : c.h;
      box(c.x + k + 1, DINO_GROUND - h, 3, h);
      box(c.x + k, DINO_GROUND - h + 3, 1, 3);
      box(c.x + k + 4, DINO_GROUND - h + 4, 1, 3);
    }
  }

  oled.setFont(u8g2_font_5x7_tr);
  oled.drawStr(70, 7, "HI");
  draw_number(best, 102, 7, true);
  draw_number(score, 127, 7, true);
}
