/*
   2024-07-17
   core code:李溫
   action code:王宥芸(Kinsey)
*/

#include "config.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "_sprite.h"
#include "_zoom.h"
#include "DigiLink.h"

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

char isExit = 0;
int jp1 = 0;             //加速狀態,預設0
int dgm = 1;             //1=幼年期1,2=幼年期2,3=成長期,4=究極體
int poo = 0;             //當前便便數量
int win_rate = 50;       //戰鬥勝率
int evo_rate = 50;       //對戰時進化機率
int battletime = 20000;  //對戰等待時間
volatile int battle_cnt = 0;
int outcome = 0;

void setup() {
  Serial.begin(9600);
  Serial.println(F("Start!"));
  pinMode(Signal_READ, INPUT);
  pinMode(Signal_SEND, OUTPUT);
  digitalWrite(Signal_SEND, HIGH);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.invertDisplay(1);
  delay(50);
  randomSeed(analogRead(23));  //初始化隨機種子,參考引腳23
  // pinMode(2, OUTPUT);  //tone實驗
  // Interrupt
  pinMode(BTN1, INPUT_PULLUP);                                             // 內部上拉,無須電阻。
  attachInterrupt(digitalPinToInterrupt(BTN1), ButtonInterrupt, BTNTYPE);  // 設置中斷服務函式。
  pinMode(BTN_JP1, INPUT_PULLUP);                                          // 內部上拉,無須電阻。
  attachInterrupt(digitalPinToInterrupt(BTN_JP1), SpeedChange, BTNTYPE);   // 設置中斷服務函式。
}

void loop() {
  Serial.println(F("loop"));
  isExit = 0;
  if (battle_cnt == 0) {
    hatch_action1();
    random_action();
    evo_action1();
    random_action();
    // armor_evo_action1();
  }
  isExit = 0;
  if (battle_cnt == 1) {
    Serial.println(F("checkbattle"));
    checkbattle(battletime);  // 等待10秒,需輸入500的倍數。
    battle_cnt = 0;
    outcome = 0;
    display.clearDisplay();
    //    display.display();
  }
}

char speedX = 10;

void delayAndClear(int x) {
  if (isExit == 0) {
    display.display();
    long Duration = millis() + ((jp1 == 0) ? x : (x / speedX));
    while (millis() < Duration) {}
  }
  display.clearDisplay();
}

int myDelay(int x) {
  long Duration = millis() + ((jp1 == 0) ? x : (x / speedX));
  while (millis() < Duration) {}
}

// Button Interrupt
IRAM_ATTR void ButtonInterrupt() {
  Serial.println(F("ButtonInterrupt"));
  isExit = 1;
  if (dgm >= 3) {
    battle_cnt = 1;
  }
  //  while (digitalRead(BTN1) == LOW) {};
}
IRAM_ATTR void SpeedChange() {
  Serial.println(F("SpeedChange"));
  jp1 = (jp1 == 0) ? 1 : 0;
}

void checkbattle(int timeout) {
  detachInterrupt(digitalPinToInterrupt(BTN1));
  for (int i = 0; i < (timeout / 500); i++) {
    set96x48(16, 1, 0 + i % 2);
    display.display();
    waiting(500);
    Serial.println((i + 1) * 500);
    if (outcome != 0) {
      break;
    }
  }
  attachInterrupt(digitalPinToInterrupt(BTN1), ButtonInterrupt, BTNTYPE);
}

void waiting(int timeout) {
  long Duration = millis() + ((jp1 == 0) ? timeout : (timeout / speedX));
  while (millis() < Duration) {
    char count = 0;
    while (digitalRead(Signal_READ) == LOW) {  // 計算訊號的LOW長度 。
      delay(1);
      count++;
      if (count >= 100) {
        break;
      }
    }
    if (count > 50 and count < 70) {  // 如果訊號的LOW長度,類似於Start的LOW長度,就在一秒後,重新嘗試發送戰鬥訊號。
      delay(1000);
      tryBattle();    // 發送戰鬥訊號。
      showOutcome();  // 分析接收到的訊號,並顯示結果。
    }
  }
}

void tryBattle() {
  if (random(100) < win_rate) {  // 隨機發送輸或贏的戰鬥訊號(50%)
    PacketSend(SendPacket_win, 2);
  } else {
    PacketSend(SendPacket_lose, 2);
  }
}

void showOutcome() {
  // 分析回傳的第二段訊號,是否符合規則。
  unsigned int OXXX = ReceivePacket[1] / 0x1000;
  unsigned int OOXX = ReceivePacket[1] / 0x0100;
  unsigned int XXOO = ReceivePacket[1] % 0x0100;
  unsigned int XXXO = ReceivePacket[1] % 0x0010;
  unsigned int XOXX = OOXX % 0x0010;
  unsigned int XXOX = XXOO / 0x0010;
  if ((OOXX + XXOO) == 0x00FF) {
    if (XXXO == 0x0002) {
      outcome = 1;  // Vpet Lose!
    } else if (XXXO == 0x0001) {
      outcome = 2;  // Vpet Win!
    } else {
      outcome = 3;
    }
  } else {
    outcome = 4;
  }
  if ((outcome > 0) and (outcome < 3)) {
    display.clearDisplay();
    if (random(100) < evo_rate) {
      // evo_action2();
      armor_evo_action1();
      ok(2);
    } else {
      ready(4, dgm);
      delay(250);
      ok(1);
    }
    for (int i = 0; i < 3; i++) {
      attack1(1, dgm, 1);
      attack2(1, dgm, 1);
    }
    if (outcome == 1) {
      attack1(1, dgm, 2);
      attack6(1, dgm, 1);
      win(1, dgm);
    } else if (outcome == 2) {
      attack1(1, dgm, 1);
      attack2(1, dgm, 2);
      lose(1, dgm);
    }
  }
  dgm = 3;
}


void hatch_action1() {
  int r_hatch1 = random(3);
  if (dgm == 1) {
    int random_hatch = random(2);
    switch (random_hatch) {
      case 0:
        {
          egg1(8, 0, 1);
          hatch1(1, 0);
          break;
        }

      case 1:
        {
          egg1(8, 2, 4);
          hatch1(1, 2);
          break;
        }
    }
  }
  walk2(r_hatch1, dgm, poo);
}

void evo_action1() {
  if (dgm < 4) {
    evo5(4, dgm);
    evo6(17, dgm, 0);
    dgm++;
    evo7(2, dgm);
  }
}

void evo_action2() {
    evo5(4, dgm);
    evo6(17, dgm, 0);
    dgm++;
    evo7(2, dgm);
}

void armor_evo_action1() {
  if (dgm == 3) {
    evo5(4, dgm);
    evo6(17, dgm, 1);
    dgm++;
    evo7(1, dgm);
  }
}

void random_action() {
  int r_ac1 = random(100);
  r_ac1 = (r_ac1 < 30) ? 0 : r_ac1 % 10;
  int r_walk1 = random(2, 11);
  int r_sleep = random(10, 31);
  switch (r_ac1) {
    case 0:
      {
        walk2(r_walk1, dgm, poo);
        break;
      }
    case 1:
      {
        eating2(1, dgm, 2, 3, 5, poo);
        break;
      }
    case 2:
      {
        eating2(1, dgm, 6, 7, 9, poo);
        break;
      }
    case 3:
      {
        train1(1, dgm, 1);
        train2(1, dgm, 0);
        unhappy(2, dgm);
        break;
      }
    case 4:
      {
        train1(1, dgm, 2);
        train2(1, dgm, 1);
        happy(2, dgm);
        break;
      }
    case 5:
      {
        if (poo != 8) {
          poo++;
          poop2(1, dgm, poo);
          break;
        }
      }
    case 6:
      {
        if (poo != 0) {
          wash2(1, dgm, poo);
          happy(2, dgm);
          poo = 0;
          break;
        }
      }
    case 7:
      {
        sleep2(r_sleep, dgm, 1, 1, poo);
        break;
      }
    case 8:
      {
        sleep2(r_sleep, dgm, 1, 0, poo);
        break;
      }
    case 9:
      {
        sleep2(r_sleep, dgm, 0, 0, poo);
        break;
      }
  }
}

void walk2(int cnt, int mon, int poo) {
  //  set48x48(64, 1, 0, IDLE1, 0); // X座標, Y座標(會自動*8), 腳色編號, 動作編號/名稱, 是否鏡像
  //  set24x24(16, 1, 0, 1);        // X座標, Y座標(會自動*8), 小圖編號, 是否鏡像
  //  set96x48(15, 1, 0);           // X座標, Y座標(會自動*8), 背景編號
  for (int i = 0; i < cnt; i++) {
    for (int j = 0; j < 32; j++) {
      set48x48(16 + walk_x1[j] * 3 - poo_x1[poo], 1, mon, walk_act[j], walk_ismirror[j]);
      poo_cnt1(poo, 0, j % 2);
      delayAndClear(500);
    }
  }
}

void poop2(int cnt, int mon, int poo) {
  for (int i = 0; i < cnt; i++) {
    for (int j = 0; j < 5; j++) {
      for (int k = 0; k < 2; k++) {
        set48x48(128 / 2 - p_shake_x[k] - poo_x2[poo], 1, mon, 10, 0);
        poo_cnt1(poo - 1, 0, 0);
        delayAndClear(200);
      }
    }
    set48x48(128 / 2 - 24 - poo_x2[poo], 1, mon, 2, 0);
    poo_cnt1(poo, 0, 0);
    delayAndClear(500);
  }
  set48x48(128 / 2 - 24 - poo_x2[poo], 1, mon, 0, 0);
  poo_cnt1(poo, 0, 0);
  delayAndClear(500);
}

void poop3(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    for (int j = 0; j < 5; j++) {
      for (int k = 0; k < 2; k++) {
        set48x48(128 / 2 - p_shake_x[k] - 16, 1, mon, 10, 0);
        delayAndClear(200);
      }
    }
    set48x48(128 / 2 - 24 - 16, 1, mon, 2, 0);
    set48x48(128 / 2 - 24 + 32, 1, 0, 9, 0);
    delayAndClear(500);
  }
  set48x48(40, 1, mon, 0, 0);
  delayAndClear(500);
}

void wash2(int cnt, int mon, int poo) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 - 24 - poo_x2[poo], 1, mon, 2, 0);
    poo_cnt1(poo, 0, 0);
    delayAndClear(500);
    for (int j = 0; j < 33; j++) {
      set48x48(128 / 2 - 24 - poo_x2[poo] - j * 6, 1, mon, 2, 0);
      poo_cnt1(poo, j * 6, 0);
      for (int k = 1; k < 5; k += 3) {
        set24x24(128 - j * 6, k, 21, 0);
      }
      delayAndClear(0);
    }
  }
}

void wash3(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 - 24 - 16, 1, mon, 2, 0);
    set48x48(128 / 2 - 24 + 32, 1, 0, 9, 0);
    delayAndClear(500);
    for (int j = 0; j < 33; j++) {
      set48x48(128 / 2 - 24 - 16 - j * 6, 1, mon, 2, 0);
      set48x48(128 / 2 - 24 + 32 - j * 6, 1, 0, 9, 0);
      for (int k = 1; k < 5; k += 3) {
        set24x24(128 - j * 6, k, 21, 0);
      }
      delayAndClear(0);
    }
  }
}

void poo_cnt1(int cnt, int xx, int img) {
  int _poo = cnt;
  switch (_poo) {
    case 0:
      {
        break;
      }
    case 1:
      {
        set24x24(128 / 2 - -24 - xx, 4, 14 + img, 0);
        break;
      }
    case 2:
      {
        for (int y = 4; y > 0; y -= 3) {
          set24x24(128 / 2 - -24 - xx, y, 14 + img, 0);
        }
        break;
      }
    case 3:
      {
        for (int y = 4; y > 0; y -= 3) {
          set24x24(128 / 2 - -24 - xx, y, 14 + img, 0);
        }
        set24x24(128 / 2 - 0 - xx, 4, 14 + img, 0);
        break;
      }
    case 4:
      {
        for (int y = 4; y > 0; y -= 3) {
          for (int x = -24; x < 1; x += 24) {
            set24x24(128 / 2 - x - xx, y, 14 + img, 0);
          }
        }
        break;
      }
    case 5:
      {
        for (int y = 4; y > 0; y -= 3) {
          for (int x = -24; x < 1; x += 24) {
            set24x24(128 / 2 - x - xx, y, 14 + img, 0);
          }
        }
        set24x24(128 / 2 - 24 - xx, 4, 14 + img, 0);
        break;
      }
    case 6:
      {
        for (int y = 4; y > 0; y -= 3) {
          for (int x = -24; x < 25; x += 24) {
            set24x24(128 / 2 - x - xx, y, 14 + img, 0);
          }
        }
        break;
      }
    case 7:
      {
        for (int y = 4; y > 0; y -= 3) {
          for (int x = -24; x < 25; x += 24) {
            set24x24(128 / 2 - x - xx, y, 14 + img, 0);
          }
        }
        set24x24(128 / 2 - 48 - xx, 4, 14 + img, 0);
        break;
      }
    case 8:
      {
        for (int y = 4; y > 0; y -= 3) {
          for (int x = -24; x < 49; x += 24) {
            set24x24(128 / 2 - x - xx, y, 14 + img, 0);
          }
        }
        break;
      }
  }
}

void dance(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40 + 32, 1, mon, IDLE1 + i % 2, 0);
    set48x48(40 - 32, 1, mon, IDLE1 + i % 2, 1);
    delayAndClear(250);
  }
}


void egg1(int cnt, int img1, int img2) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 - 24, 1, 0, i % 2 == 0 ? img1 : img2, 0);
    delayAndClear(500);
  }
}

void hatch1(int cnt, int img1) {
  for (int i = 0; i < cnt; i++) {
    for (int j = 0; j < 8; j++) {
      for (int k = 0; k < 4; k++) {
        set48x48(128 / 2 - h_shake_x[k], 1, 0, img1, 0);
        delayAndClear(50);
      }
    }
    set48x48(128 / 2 - 24, 1, 0, 5, 0);
    delayAndClear(500);
  }
  delay(500);
}

void pc1(int cnt) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 - 24, 1, 0, 6, 0);
    delayAndClear(500);
  }
}

void attack1(int cnt, int mon, int f) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 8, 1, mon, 6, 0);
    delayAndClear(250);
    delay(900);
    for (int j = 0; j < 25; j++) {
      set48x48(128 / 2 + 8, 1, mon, 7, 0);
      int cond = f % 2 == 0 ? 5 : 2;
      for (int k = 1; k < cond; k += 3) {
        set24x24(128 / 2 - 16 - j * 3, k, 23, 0);
      }
      delayAndClear(6);
    }
  }
}

void attack2(int cnt, int mon, int f) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 8, 1, mon, 1, 0);
    delayAndClear(250);
    for (int j = 0; j < 24; j++) {
      set48x48(128 / 2 + 8, 1, mon, 1, 0);
      int cond = f % 2 == 0 ? 5 : 2;
      for (int k = 1; k < cond; k += 3) {
        set24x24(-21 + j * 3, k, 23, 1);
      }
      delayAndClear(6);
    }
    behit1(8);
  }
}

void attack3(int cnt, int pac) {
  for (int i = 0; i < cnt; i++) {
    for (int j = 1; j < 6; j++) {
      set96x48(128 + 10 - j * 21, 1, pac);
      delayAndClear(0);
    }
    delay(600);
  }
}

void attack4(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 8, 1, mon, 6, 0);
    delayAndClear(250);
    for (int j = 0; j < 25; j++) {
      set48x48(128 / 2 + 8, 1, mon, 7, 0);
      set48x48(128 / 2 - 42 - j * 3, 1, 0, 13, 0);
      delayAndClear(0);
    }
  }
}

void attack5(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 8, 1, mon, 6, 0);
    delayAndClear(250);
    for (int j = 0; j < 25; j++) {
      set48x48(128 / 2 + 8, 1, mon, 6, 0);
      set48x48(-48 + j * 3, 1, 0, 13, 1);
      delayAndClear(0);
    }
  }
  behit2(2);
}

void train1(int cnt, int mon, int f) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 10, 1, mon, 6, 0);
    set48x48(0, 1, 0, 7, 0);
    delayAndClear(250);
    for (int j = 0; j < 10; j++) {
      set48x48(128 / 2 + 10, 1, mon, 7, 0);
      set48x48(0, 1, 0, 7, 0);
      int cond = f % 2 == 0 ? 5 : 2;
      for (int k = 1; k < cond; k += 3) {
        set24x24(128 / 2 + 10 - 24 - j * 3, k, 23, 0);
      }
      delayAndClear(0);
    }
    behit1(4);
  }
}

void train2(int cnt, int mon, int img) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 10, 1, mon, 6, 0);
    set48x48(0, 1, 0, 7 + img, 0);
    delayAndClear(500);
  }
}

void attack6(int cnt, int mon, int f) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 8, 1, mon, 1, 0);
    delayAndClear(250);
    for (int j = 0; j < 24; j++) {
      set48x48(128 / 2 + 8, 1, mon, 1, 0);
      int cond = f % 2 == 0 ? 5 : 2;
      for (int k = 1; k < cond; k += 3) {
        set24x24(-21 + j * 3, k, 23, 1);
      }
      delayAndClear(5);
    }
    avoid1(8, mon);
  }
  delay(500);
}

void eating2(int cnt, int mon, int img1, int img2, int img3, int poo) {
  for (int i = 0; i < cnt; i++) {
    for (int j = 0; j < 2; j++) {
      set48x48(128 / 2 - 24 - poo_x1[poo], 1, mon, (j % 2 == 0) ? 8 : 9, 0);
      set24x24(128 / 2 - 50 - poo_x1[poo], 1 + j * 3, img1, 0);
      poo_cnt1(poo, 0, j % 2);
      delayAndClear(500);
    }
    for (int j = img2; j < img3; j++) {
      for (int k = 8; k < 10; k++) {
        set48x48(128 / 2 - 24 - poo_x1[poo], 1, mon, k, 0);
        set24x24(128 / 2 - 50 - poo_x1[poo], 4, j, 0);
        poo_cnt1(poo, 0, k % 2);
        delayAndClear(500);
      }
    }
    set48x48(128 / 2 - 24 - poo_x1[poo], 1, mon, 8, 0);
    set24x24(128 / 2 - 50 - poo_x1[poo], 4, img3, 0);
    poo_cnt1(poo, 0, 0);
    delayAndClear(500);
  }
}

void win(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, mon, 1, 0);
    delayAndClear(500);
    for (int j = 0; j < 3; j++) {
      set48x48(40, 1, mon, 2, 0);
      for (int y = 1; y < 5; y += 3) {
        set24x24(128 / 2 + 26, y, 11, 0);
        set24x24(128 / 2 - 50, y, 11, 0);
      }
      delayAndClear(500);
      set48x48(40, 1, mon, 2, 0);
      delayAndClear(500);
    }
  }
  set48x48(40, 1, mon, 0, 0);
  delayAndClear(500);
}

void lose(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, mon, 0, 0);
    delayAndClear(500);
    for (int j = 0; j < 2; j++) {
      set48x48(40, 1, mon, 13, 0);
      for (int y = 1; y < 5; y += 3) {
        set24x24(128 / 2 + 26, y, 22, 0);
        set24x24(128 / 2 - 50, y, 22, 0);
      }
      delayAndClear(500);
      set48x48(40, 1, mon, 13, 0);
      delayAndClear(500);
    }

    set48x48(40, 1, mon, 13, 0);
    for (int y = 1; y < 5; y += 3) {
      set24x24(128 / 2 + 26, y, 22, 0);
      set24x24(128 / 2 - 50, y, 22, 0);
    }
    delayAndClear(500);

    for (int x = 0; x < 33; x++) {
      set48x48(40 - x * 6, 1, mon, 13, 0);
      for (int y = 1; y < 5; y += 3) {
        set24x24(128 / 2 + 26 - x * 6, y, 22, 0);
        set24x24(128 / 2 - 50 - x * 6, y, 22, 0);
        set24x24(128 - x * 6, y, 21, 0);
      }
      delayAndClear(0);
    }
  }
  set48x48(40, 1, mon, 0, 0);
  delayAndClear(500);
}

void happy(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, mon, 1, 0);
    delayAndClear(500);
    set48x48(40, 1, mon, 2, 0);
    set24x24(128 / 2 + 26, 1, 11, 0);
    delayAndClear(500);
  }
  set48x48(40, 1, mon, 0, 0);
  delayAndClear(500);
}

void unhappy(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, mon, 4, 0);
    set24x24(128 / 2 + 26, 1, 13, 0);
    delayAndClear(500);
    set48x48(40, 1, mon, 3, 0);
    set24x24(128 / 2 + 26, 1, 12, 0);
    delayAndClear(500);
  }
  set48x48(40, 1, mon, 0, 0);
  delayAndClear(500);
}

void battle(int cnt) {
  for (int i = 0; i < cnt; i++) {
    set96x48(16, 1, 0 + i % 2);
    delayAndClear(250);
  }
}

void behit1(int cnt) {
  for (int i = 0; i < cnt; i++) {
    set96x48(16, 1, 2 + i % 2);
    delayAndClear(100);
  }
}

void behit2(int cnt) {
  for (int i = 0; i < cnt; i++) {
    for (int img = 11; img < 13; img++) {
      set48x48(128 / 2 + 8, 1, 0, img, 0);
      delayAndClear(50);
    }
  }
}

void avoid1(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(128 / 2 + 8, 1, mon, 1, 1);
    delayAndClear(50);
  }
}

void ok(int cnt) {
  for (int i = 0; i < cnt; i++) {
    set96x48(16, 1, 4);
    delayAndClear(250);
  }
}

void ready(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, mon, (i % 2) * 3, 0);
    delayAndClear(500);
  }
  set48x48(40, 1, mon, 0, 0);
  delayAndClear(250);
}

void sleep2(int cnt, int mon, int mod1, int mod2, int poo) {
  for (int i = 0; i < cnt; i++) {
    for (int img = 11; img <= 12; img++) {
      if (mod1 == 0) {
        set24x24(128 / 2, 1, img + 5, 0);
      } else {
        set48x48(128 / 2 - 24 - poo_x1[poo], 1, mon, img, 0);
        set24x24(128 / 2 + 24 - poo_x1[poo], 1, img % 2 == 0 ? 16 : 17, 0);
        poo_cnt1(poo, 0, img % 2);
      }
      if (mod2 == 0) {
        display.invertDisplay(0);
      } else {
        display.invertDisplay(1);
      }
      delayAndClear(500);
    }
  }
  display.invertDisplay(1);
}

void evo_a(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    for (int j = 0; j < 12; j++) {
      set48x48(128 / 2 - 112 + j * 6, 1, mon, 9, 1);
      set48x48(128 / 2 + 64 - j * 6, 1, 0, 14, 0);
      delayAndClear(0);
    }
  }
}

void evo2(int cnt, int t) {
  for (int i = 0; i < cnt; i++) {
    for (int img = 6; img < 14; img++) {
      set96x48(16, 1, img);
      display.invertDisplay(0);
      delayAndClear(t);
    }
    set96x48(16, 1, 6);
    display.invertDisplay(0);
    delayAndClear(t);
  }
}

void evo5(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, mon, (i % 2) * 3, 0);
    delayAndClear(100 + i * 50);
  }
}

void evo6(int cnt, int mon, int dgmtl) {
  if (dgmtl == 0) {
    evo2(1, 50);
  } else {
    evo_a(1, mon);
  }
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, (i < 8) ? mon : mon + 1, 3, 0);
    display.invertDisplay((i % 2 == 0) ? 1 : 0);
    delayAndClear(50 - i);
  }
}

void evo7(int cnt, int mon) {
  for (int i = 0; i < cnt; i++) {
    set48x48(40, 1, mon, (i % 2) * 3, 0);
    delayAndClear(250);
  }
}

/* Functions */

void set16x16(int x, int y, int mon, int act, int mirror) {
  readData_16x16(mon, act);  // 讀取資料到 16x16暫存區
  if (mirror != 0) {         // 判斷是否鏡像
    SRAM_16to16_R(SRAM_16);  // 鏡像 16x16暫存區
  }
  ssd1306_writeBuffer_16(x, y, SRAM_16);  //將 16x16暫存區 的資料寫入 螢幕的緩衝區
}

void set24x24(int x, int y, int num, int mirror) {
  readData_08x08(num);       // 讀取資料到 8x8暫存區
  if (mirror != 0) {         // 判斷是否鏡像
    SRAM_08to08_R(SRAM_08);  // 鏡像 8x8暫存區
  }
  SRAM_08to24(SRAM_08);                    // 將 8x8暫存區 的資料 放大3倍放到 24x24暫存區 中
  ssd1306_writeBuffer(24, x, y, SRAM_24);  //將 24x24暫存區 的資料寫入 螢幕的緩衝區
}

void set48x48(int x, int y, int mon, int act, int mirror) {
  readData_16x16(mon, act);  // 讀取資料到 16x16暫存區
  if (mirror != 0) {         // 判斷是否鏡像
    SRAM_16to16_R(SRAM_16);  // 鏡像 16x16暫存區
  }
  SRAM_16to48(SRAM_16);                    // 將 16x16暫存區 的資料 放大3倍放到 48x48暫存區 中
  ssd1306_writeBuffer(48, x, y, SRAM_48);  //將 48x48暫存區 的資料寫入 螢幕的緩衝區
}

void set96x48(int x, int y, int bg) {
  readData_96x48(bg * 2);                       // 讀取資料到 16x16暫存區
  SRAM_16to48(SRAM_16);                         // 將 16x16暫存區 的資料 放大3倍放到 48x48暫存區 中
  ssd1306_writeBuffer(48, x, y, SRAM_48);       //將 48x48暫存區 的資料寫入 螢幕的緩衝區
  readData_96x48(bg * 2 + 1);                   // 讀取資料到 16x16暫存區
  SRAM_16to48(SRAM_16);                         // 將 16x16暫存區 的資料 放大3倍放到 48x48暫存區 中
  ssd1306_writeBuffer(48, x + 48, y, SRAM_48);  //將 48x48暫存區 的資料寫入 螢幕的緩衝區 X座標+48
}

void ssd1306_writeBuffer_16(int x, int y, char inarr[]) {  // x座標, y座標*8, 暫存區陣列名稱
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 16; j++) {
      display.getBuffer()[j + i * 128 + x + y * 128] = inarr[i * 16 + j];
    }
  }
}

void ssd1306_writeBuffer(int size, int x, int y, char inarr[]) {  // 比例, x座標, y座標*8, 暫存區陣列名稱
  char BufferX = size;
  int BufferAdd;
  int tempX = x;
  tempX = (x < -48) ? -48 : x;
  tempX = (tempX > 128) ? 128 : tempX;
  for (int i = 0; i < (BufferX / 8); i++) {
    for (int j = 0; j < BufferX; j++) {
      BufferAdd = j + i * 128 + tempX + y * 128;
      if ((tempX == -48) || tempX == 128) {
      } else if (BufferAdd < 0) {
      } else if (tempX < 0) {
        if ((j + i * 128 + x + y * 128) % 128 < 63) {
          display.getBuffer()[BufferAdd] = inarr[i * BufferX + j];
        }
      } else if (tempX > 79) {
        if ((j + i * 128 + x + y * 128) % 128 >= 63) {
          display.getBuffer()[BufferAdd] = inarr[i * BufferX + j];
        }
      } else {
        display.getBuffer()[BufferAdd] = inarr[i * BufferX + j];
      }
    }
  }
}
esp:0
esp:2
esp:4
esp:5
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:21
esp:22
esp:23
esp:25
esp:26
esp:27
esp:32
esp:33
esp:34
esp:35
esp:3V3
esp:EN
esp:VP
esp:VN
esp:GND.1
esp:D2
esp:D3
esp:CMD
esp:5V
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:D1
esp:D0
esp:CLK
oled1:GND
oled1:VCC
oled1:SCL
oled1:SDA
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
r1:1
r1:2
r2:1
r2:2