#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <stdlib.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
const uint8_t tamagoshie_oeuf_casser[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x18,
0x18,
0x00,
0x00,
0x1c,
0x38,
0x00,
0x00,
0x02,
0x40,
0x00,
0x00,
0x07,
0xe0,
0x00,
0x00,
0x18,
0x18,
0x00,
0x00,
0x20,
0x04,
0x00,
0x00,
0x26,
0x04,
0x00,
0x00,
0x3e,
0x38,
0x00,
0x00,
0x5e,
0x78,
0x00,
0x00,
0x5e,
0x78,
0x00,
0x00,
0xc4,
0x21,
0x00,
0x00,
0xa1,
0x83,
0x00,
0x00,
0x9a,
0x25,
0x00,
0x00,
0x85,
0x59,
0x00,
0x00,
0x80,
0x81,
0x00,
0x00,
0xc0,
0x83,
0x00,
0x00,
0x40,
0x06,
0x00,
0x06,
0x40,
0x0e,
0x60,
0x09,
0x20,
0x1c,
0x90,
0x0f,
0x9c,
0x39,
0xe0,
0x00,
0x03,
0xc2,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t tamagoshie_oeuf[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x18,
0x18,
0x00,
0x00,
0x1c,
0x38,
0x00,
0x00,
0x03,
0xc0,
0x00,
0x00,
0x04,
0x20,
0x00,
0x00,
0x10,
0x10,
0x00,
0x00,
0x20,
0x0c,
0x00,
0x00,
0x20,
0x04,
0x00,
0x00,
0x20,
0x04,
0x00,
0x00,
0x40,
0x02,
0x00,
0x00,
0x4c,
0x22,
0x00,
0x00,
0x5e,
0x7a,
0x00,
0x00,
0x5e,
0x7a,
0x00,
0x00,
0x4c,
0x32,
0x00,
0x00,
0x42,
0x42,
0x00,
0x00,
0x41,
0x82,
0x00,
0x00,
0x41,
0x86,
0x00,
0x00,
0x40,
0x06,
0x00,
0x00,
0x20,
0x04,
0x00,
0x00,
0x18,
0x18,
0x00,
0x00,
0x07,
0xe0,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t tamagotchi_pomme[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x04,
0x00,
0x01,
0x00,
0x03,
0x80,
0x07,
0xe0,
0x08,
0x30,
0x08,
0x70,
0x08,
0x70,
0x00,
0xf0,
0x01,
0xe0,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t tamagotchi_dort[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0xc0,
0x00,
0x00,
0x00,
0x40,
0x00,
0x60,
0x18,
0x80,
0x00,
0x60,
0x39,
0xc0,
0x00,
0x10,
0x20,
0x00,
0x00,
0x18,
0x63,
0x00,
0x00,
0x1f,
0xe1,
0x00,
0x00,
0x67,
0xdb,
0x00,
0x00,
0x80,
0x00,
0x00,
0x01,
0x00,
0x0c,
0x00,
0x02,
0x00,
0x0a,
0x00,
0x02,
0x00,
0x0d,
0x00,
0x04,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x80,
0x00,
0x38,
0x71,
0x00,
0x00,
0x38,
0x71,
0x80,
0x02,
0x03,
0x01,
0x00,
0x00,
0x00,
0x03,
0x00,
0x02,
0x00,
0x03,
0x00,
0x01,
0x00,
0x06,
0x00,
0x00,
0x80,
0x0c,
0x00,
0x00,
0x70,
0x38,
0x00,
0x00,
0xff,
0xfc,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t tamagotchi_bouche_ouverte[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x40,
0x02,
0x00,
0x00,
0xa0,
0x05,
0x00,
0x00,
0x60,
0x06,
0x00,
0x00,
0x30,
0x0c,
0x00,
0x00,
0x18,
0x08,
0x00,
0x00,
0x38,
0xb0,
0x00,
0x00,
0x5c,
0x2c,
0x00,
0x00,
0xc0,
0x06,
0x00,
0x00,
0x80,
0x00,
0x00,
0x01,
0x00,
0x01,
0x80,
0x02,
0x00,
0x00,
0x40,
0x02,
0x18,
0x18,
0xc0,
0x00,
0x3c,
0x3c,
0x00,
0x04,
0x3c,
0x3c,
0x60,
0x00,
0x1c,
0x18,
0x20,
0x00,
0x01,
0x80,
0x60,
0x04,
0x07,
0xe0,
0x20,
0x04,
0x07,
0xe0,
0x40,
0x04,
0x07,
0xe0,
0x40,
0x02,
0x07,
0xe0,
0x20,
0x01,
0x03,
0xc0,
0x80,
0x01,
0x80,
0x01,
0x80,
0x00,
0x80,
0x03,
0x00,
0x00,
0x78,
0x06,
0x00,
0x00,
0x3e,
0xdc,
0x00,
0x00,
0x79,
0xbe,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t tamagotchi_sad[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x20,
0x05,
0x00,
0x00,
0x60,
0x06,
0x00,
0x00,
0x30,
0x0c,
0x00,
0x00,
0x10,
0x08,
0x00,
0x00,
0x0d,
0x58,
0x00,
0x00,
0x3b,
0xb4,
0x00,
0x00,
0xc0,
0x06,
0x00,
0x00,
0x80,
0x01,
0x80,
0x02,
0x00,
0x01,
0x80,
0x03,
0x00,
0x00,
0xc0,
0x04,
0x00,
0x00,
0xc0,
0x06,
0x04,
0x10,
0x00,
0x04,
0x1c,
0x18,
0x60,
0x04,
0x3c,
0x1c,
0x20,
0x0c,
0x18,
0x1c,
0x20,
0x04,
0x02,
0x40,
0x60,
0x04,
0x00,
0x00,
0x20,
0x04,
0x00,
0x00,
0x40,
0x02,
0x00,
0x00,
0x00,
0x07,
0x00,
0x00,
0x80,
0x01,
0x00,
0x00,
0x80,
0x01,
0x80,
0x03,
0x00,
0x00,
0xf0,
0x06,
0x00,
0x00,
0x1c,
0xbc,
0x00,
0x00,
0x3f,
0xfc,
0x00,
0x00,
0x30,
0x0e,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t tamagotchi_general[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0xa0,
0x05,
0x00,
0x00,
0x60,
0x05,
0x00,
0x00,
0x30,
0x0c,
0x00,
0x00,
0x12,
0x28,
0x00,
0x00,
0x05,
0x48,
0x00,
0x00,
0x3f,
0xb4,
0x00,
0x01,
0xc0,
0x14,
0x00,
0x00,
0x80,
0x00,
0x80,
0x02,
0x00,
0x00,
0x80,
0x07,
0x00,
0x00,
0x80,
0x04,
0x00,
0x00,
0xc0,
0x06,
0x18,
0x18,
0x00,
0x04,
0x34,
0x14,
0x60,
0x04,
0x3c,
0x1c,
0x20,
0x08,
0x38,
0x18,
0x20,
0x04,
0x01,
0x80,
0x60,
0x02,
0x00,
0x00,
0x20,
0x04,
0x00,
0x00,
0x00,
0x02,
0x00,
0x00,
0x80,
0x07,
0x00,
0x00,
0xc0,
0x00,
0x80,
0x01,
0x80,
0x00,
0x80,
0x03,
0x00,
0x00,
0xd0,
0x04,
0x00,
0x00,
0x74,
0x0c,
0x00,
0x00,
0x3f,
0xfc,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t tamagotchi_happy[] PROGMEM = {
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x20,
0x05,
0x00,
0x00,
0x60,
0x06,
0x00,
0x00,
0x30,
0x04,
0x00,
0x00,
0x10,
0x08,
0x00,
0x00,
0x0d,
0x48,
0x00,
0x00,
0x3b,
0xb4,
0x00,
0x00,
0xc0,
0x04,
0x00,
0x00,
0x80,
0x01,
0x80,
0x02,
0x00,
0x01,
0x80,
0x03,
0x00,
0x00,
0xc0,
0x00,
0x00,
0x00,
0x40,
0x06,
0x18,
0x38,
0x00,
0x00,
0x3c,
0x3c,
0x60,
0x04,
0x3c,
0x3c,
0x00,
0x0c,
0x38,
0x18,
0x20,
0x04,
0x00,
0x00,
0x60,
0x04,
0x01,
0x80,
0x20,
0x04,
0x00,
0x00,
0x40,
0x02,
0x00,
0x00,
0x40,
0x07,
0x00,
0x00,
0x80,
0x01,
0x00,
0x00,
0x80,
0x01,
0x80,
0x03,
0x00,
0x00,
0x50,
0x06,
0x00,
0x00,
0x1c,
0xbc,
0x00,
0x00,
0x3f,
0xfc,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
const uint8_t coincoin[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x04, 0x00,
0x00, 0x20, 0x0c, 0x00,
0x00, 0x18, 0x18, 0x00,
0x00, 0x0c, 0x20, 0x00,
0x00, 0x0e, 0x20, 0x00,
0x00, 0x08, 0x10, 0x00,
0x00, 0x10, 0x08, 0x00,
0x00, 0x20, 0x04, 0x00,
0x00, 0x40, 0x02, 0x00,
0x00, 0x88, 0x32, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x8b, 0xb2, 0x00,
0x00, 0x07, 0xe0, 0x00,
0x00, 0x03, 0xc0, 0x00,
0x00, 0x40, 0x06, 0x00,
0x00, 0x80, 0x03, 0x00,
0x00, 0xc0, 0x02, 0x00,
0x00, 0x40, 0x06, 0x00,
0x00, 0x60, 0x04, 0x00,
0x00, 0x10, 0x08, 0x00,
0x00, 0x0f, 0x70, 0x00,
0x00, 0x0c, 0x30, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const uint8_t coincoin_happy[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x04, 0x00,
0x00, 0x20, 0x0c, 0x00,
0x00, 0x10, 0x18, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x18, 0x10, 0x00,
0x00, 0x30, 0x08, 0x00,
0x00, 0x00, 0x04, 0x00,
0x00, 0x40, 0x00, 0x00,
0x00, 0x0c, 0x30, 0x00,
0x00, 0x9c, 0x3a, 0x00,
0x00, 0x9c, 0x38, 0x00,
0x00, 0x0d, 0xb0, 0x00,
0x00, 0x87, 0xe2, 0x00,
0x00, 0x43, 0xc4, 0x00,
0x00, 0x60, 0x04, 0x00,
0x00, 0x80, 0x02, 0x00,
0x00, 0xc0, 0x02, 0x00,
0x00, 0x40, 0x02, 0x00,
0x00, 0x00, 0x04, 0x00,
0x00, 0x20, 0x08, 0x00,
0x00, 0x1c, 0xb0, 0x00,
0x00, 0x0c, 0x20, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const uint8_t coincoin_sad[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x08, 0x00,
0x00, 0x60, 0x0c, 0x00,
0x00, 0x10, 0x10, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x18, 0x10, 0x00,
0x00, 0x20, 0x08, 0x00,
0x00, 0x20, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x40, 0x00,
0x00, 0x9c, 0x72, 0x00,
0x00, 0x1c, 0x70, 0x00,
0x00, 0x19, 0xb0, 0x00,
0x00, 0x87, 0xc2, 0x00,
0x00, 0x45, 0x84, 0x00,
0x00, 0x60, 0x04, 0x00,
0x00, 0x80, 0x02, 0x00,
0x00, 0x00, 0x02, 0x00,
0x00, 0xc0, 0x02, 0x00,
0x00, 0x00, 0x04, 0x00,
0x00, 0x20, 0x08, 0x00,
0x00, 0x1c, 0xb0, 0x00,
0x00, 0x0c, 0x30, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const uint8_t coincoin_dort[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x08, 0x00,
0x00, 0x20, 0x0c, 0x00,
0x00, 0x10, 0x10, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x18, 0x10, 0x00,
0x00, 0x30, 0x08, 0x00,
0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x02, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x01, 0x80, 0x00,
0x00, 0x86, 0x42, 0x00,
0x00, 0x43, 0xc4, 0x00,
0x00, 0x60, 0x06, 0x00,
0x00, 0x80, 0x02, 0x00,
0x00, 0x80, 0x00, 0x00,
0x00, 0x40, 0x06, 0x00,
0x00, 0x40, 0x00, 0x00,
0x00, 0x20, 0x04, 0x00,
0x00, 0x1c, 0x38, 0x00,
0x00, 0x0c, 0x30, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const uint8_t coincoin_manger[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x0c, 0x00,
0x00, 0x30, 0x1c, 0x00,
0x00, 0x08, 0x30, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x0a, 0x20, 0x00,
0x00, 0x10, 0x10, 0x00,
0x00, 0x20, 0x08, 0x00,
0x00, 0x40, 0x04, 0x00,
0x00, 0x80, 0x02, 0x00,
0x00, 0x88, 0x31, 0x00,
0x00, 0x1c, 0x39, 0x00,
0x00, 0x1c, 0x38, 0x00,
0x00, 0x09, 0x91, 0x00,
0x00, 0x07, 0xc0, 0x00,
0x00, 0x87, 0xc2, 0x00,
0x00, 0x46, 0xc6, 0x00,
0x00, 0x41, 0x02, 0x00,
0x00, 0x80, 0x01, 0x00,
0x00, 0x80, 0x01, 0x00,
0x00, 0xc0, 0x03, 0x00,
0x00, 0x40, 0x00, 0x00,
0x00, 0x20, 0x0c, 0x00,
0x00, 0x1d, 0x30, 0x00,
0x00, 0x0c, 0x30, 0x00,
0x00, 0x1c, 0x38, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const uint8_t tamagoshie_malade[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x00, 0x00,
0x00, 0x60, 0x0c, 0x00,
0x00, 0x30, 0x10, 0x00,
0x00, 0x18, 0x10, 0x00,
0x00, 0x08, 0xa0, 0x00,
0x00, 0x10, 0xa8, 0x00,
0x00, 0x40, 0x04, 0x00,
0x00, 0x80, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x80,
0x02, 0x00, 0x02, 0x00,
0x00, 0x3c, 0x3e, 0x40,
0x00, 0x3c, 0x78, 0x40,
0x04, 0x38, 0x38, 0x00,
0x00, 0x10, 0x30, 0x60,
0x04, 0x01, 0x00, 0x00,
0x00, 0x0e, 0xe0, 0x40,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80,
0x00, 0x00, 0x01, 0x00,
0x00, 0x80, 0x02, 0x00,
0x00, 0x60, 0x04, 0x00,
0x00, 0x3d, 0x38, 0x00,
0x00, 0x18, 0x38, 0x00,
0x00, 0x7c, 0x3c, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const uint8_t coincoin_malade[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x04, 0x00,
0x00, 0x20, 0x0c, 0x00,
0x00, 0x10, 0x18, 0x00,
0x00, 0x08, 0x20, 0x00,
0x00, 0x0a, 0x20, 0x00,
0x00, 0x18, 0x10, 0x00,
0x00, 0x20, 0x08, 0x00,
0x00, 0x40, 0x04, 0x00,
0x00, 0x00, 0x02, 0x00,
0x00, 0x0c, 0x30, 0x00,
0x00, 0x9c, 0x3a, 0x00,
0x00, 0x1c, 0x38, 0x00,
0x00, 0x0c, 0x30, 0x00,
0x00, 0x83, 0xe2, 0x00,
0x00, 0x67, 0xe4, 0x00,
0x00, 0x7f, 0xfc, 0x00,
0x00, 0xff, 0xb6, 0x00,
0x00, 0x47, 0xfe, 0x00,
0x00, 0xc0, 0x1e, 0x00,
0x00, 0x40, 0x1c, 0x00,
0x00, 0x20, 0x1c, 0x00,
0x00, 0x1c, 0xb0, 0x00,
0x00, 0x0c, 0x20, 0x00,
0x00, 0x1c, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
// Pour un cycle réaliste sur 24h :
// - faim baisse 1 unité toutes les 8h (3 repas/jour)
// - bonheur baisse 1 unité toutes les 8h (2-3 jeux/jour)
// - fatigue monte 1 unité toutes les 3h (8h éveillé, 8h sommeil, 8h éveillé)
// - sommeil dure 8h (28800000 ms)
const unsigned long hungerDecayInterval = 8UL * 60 * 60 * 1000; // 8h
const unsigned long happinessDecayInterval = 8UL * 60 * 60 * 1000; // 8h
const unsigned long fatigueIncreaseInterval = 3UL * 60 * 60 * 1000; // 3h
const unsigned long sleepDuration = 8UL * 60 * 60 * 1000; // 8h
#define BTN_LEFT 12
#define BTN_RIGHT 14
#define BTN_OK 27
int bonheur = 8; // 0 (triste) à 10 (très heureux)
int faim = 8; // 0 (affamé) à 10 (rassasié)
int fatigue = 5; // 0 (reposé) à 10 (très fatigué)
struct MenuItem
{
const char *name;
enum Type
{
ACTION,
QUIT
} type;
};
MenuItem menu[] = {
{"Jouer", MenuItem::ACTION},
{"Manger", MenuItem::ACTION},
{"Dormir", MenuItem::ACTION},
{"Reveiller", MenuItem::ACTION}, // Action pour réveiller
{"Soigner", MenuItem::ACTION}, // Ajout du soin
{"Quitter", MenuItem::QUIT}};
const int menuLength = sizeof(menu) / sizeof(MenuItem);
int currentIndex = 0;
// Pour éviter le rebond bouton
bool menuActive = false;
unsigned long lastBtnLeft = 0, lastBtnRight = 0, lastBtnOK = 0;
const unsigned long debounceDelay = 200; // ms
unsigned long btnOkPressTime = 0;
const unsigned long longPressDuration = 1000;
int currentState = 0;
// Ajout de l'énumération pour le cycle de vie
enum LifeStage
{
EGG,
EGG_CRACKED,
CREATURE,
DEAD
};
LifeStage lifeStage = EGG;
unsigned long eggStartTime = 0;
unsigned long eggCrackDelay = 240000; // sera défini aléatoirement dans setup()
const unsigned long eggHatchDelay = 3000; // 3s après cassé, la créature apparaît
// Animation œuf qui oscille autour du centre
const int eggCenterX = (SCREEN_WIDTH - 32) / 2;
int eggAnimStep = 0; // 0 = centre, 1 = droite, 2 = gauche
const int eggAnimMax = 8; // décalage max en px
unsigned long lastEggMove = 0;
unsigned long nextEggMoveDelay = 1000; // ms, sera aléatoire entre 1 et 5s
bool isSleeping = false;
unsigned long sleepStartTime = 0;
// Ajout : type de créature (canard ou classique)
bool isDuck = false; // true = canard, false = tamagotchi
bool isSick = false; // true = malade, false = en bonne santé
const uint8_t tombe[] PROGMEM = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0xe0, 0x00,
0x00, 0x0f, 0xf0, 0x00,
0x00, 0x18, 0x38, 0x00,
0x00, 0x20, 0x1c, 0x00,
0x00, 0xc0, 0x0e, 0x00,
0x00, 0xc0, 0x06, 0x00,
0x00, 0xc0, 0x02, 0x00,
0x00, 0xdd, 0xf2, 0x00,
0x00, 0xdd, 0xfa, 0x00,
0x00, 0xdd, 0xfa, 0x00,
0x00, 0xdd, 0xf2, 0x00,
0x00, 0xdf, 0xfe, 0x00,
0x00, 0xc0, 0x02, 0x00,
0x00, 0xc0, 0x0e, 0x00,
0x00, 0xc0, 0x0e, 0x00,
0x00, 0xc0, 0x1e, 0x00,
0x00, 0xc3, 0x1e, 0x60,
0x02, 0xdf, 0xfe, 0xe0,
0x07, 0xff, 0xfe, 0xf0,
0x07, 0xff, 0xff, 0xf0,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
// Variables pour la gestion de la mort
unsigned long criticalStateTimer = 0;
unsigned long sickStateTimer = 0;
const unsigned long criticalStateDuration = 2UL * 60 * 60 * 1000; // 2h en état critique = mort
const unsigned long sickStateDuration = 4UL * 60 * 60 * 1000; // 4h malade sans soin = mort
void drawGauges() {
// Largeur et position des jauges
int x = 4;
int y = 2;
int w = 36;
int h = 5;
int spacing = 10;
// Bonheur
display.drawRect(x, y, w, h, SSD1306_WHITE);
int fillW = map(bonheur, 0, 10, 0, w-2);
display.fillRect(x+1, y+1, fillW, h-2, SSD1306_WHITE);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(x+w+2, y);
display.print("B");
// Faim
y += h + spacing;
display.drawRect(x, y, w, h, SSD1306_WHITE);
fillW = map(faim, 0, 10, 0, w-2);
display.fillRect(x+1, y+1, fillW, h-2, SSD1306_WHITE);
display.setCursor(x+w+2, y);
display.print("F");
// Fatigue
y += h + spacing;
display.drawRect(x, y, w, h, SSD1306_WHITE);
fillW = map(10-fatigue, 0, 10, 0, w-2); // Inversé : plus rempli = reposé
display.fillRect(x+1, y+1, fillW, h-2, SSD1306_WHITE);
display.setCursor(x+w+2, y);
display.print("Z");
}
void showHome()
{
display.clearDisplay();
drawGauges();
int offset = 0;
if (lifeStage == EGG || lifeStage == EGG_CRACKED)
{
if (eggAnimStep == 1)
offset = eggAnimMax;
else if (eggAnimStep == 2)
offset = -eggAnimMax;
}
// Affiche le sprite selon le stade de vie :
if (lifeStage == EGG)
{
display.drawBitmap(eggCenterX + offset, 6, tamagoshie_oeuf, 32, 32, SSD1306_WHITE);
}
else if (lifeStage == EGG_CRACKED)
{
display.drawBitmap(eggCenterX + offset, 6, tamagoshie_oeuf_casser, 32, 32, SSD1306_WHITE);
}
else if (lifeStage == DEAD)
{
// Affiche la tombe
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, tombe, 32, 32, SSD1306_WHITE);
// Affiche "RIP" en dessous
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor((SCREEN_WIDTH - 30) / 2, 42);
display.print("RIP");
}
else if (isSleeping)
{
// Affiche le canard ou le tamagotchi qui dort
if (isDuck)
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, coincoin_dort, 32, 32, SSD1306_WHITE);
else
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, tamagotchi_dort, 32, 32, SSD1306_WHITE);
// Affiche un Z qui monte
int zX = (SCREEN_WIDTH - 32) / 2 + 28;
int zY = 10 + ((millis() / 400) % 3) * -4;
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(zX, zY);
display.print("Z");
}
else
{
// Affiche la créature selon l'état :
const unsigned char *sprite;
if (isSick) {
sprite = isDuck ? coincoin_malade : tamagoshie_malade;
} else if (isDuck) {
if (fatigue >= 8)
sprite = coincoin_sad;
else if (bonheur >= 7 && faim >= 7 && fatigue <= 3)
sprite = coincoin_happy;
else if (bonheur <= 3 || faim <= 3)
sprite = coincoin_sad;
else
sprite = coincoin;
} else {
if (fatigue >= 8)
sprite = tamagotchi_sad;
else if (bonheur >= 7 && faim >= 7 && fatigue <= 3)
sprite = tamagotchi_happy;
else if (bonheur <= 3 || faim <= 3)
sprite = tamagotchi_sad;
else
sprite = tamagotchi_general;
}
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, sprite, 32, 32, SSD1306_WHITE);
}
display.display();
}
void showSelectedAction(const char *action)
{
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 28);
display.print(action);
display.display();
delay(2000); // Affiche le texte pendant 2 secondes
showHome(); // Réaffiche la créature après
}
// Fonction pour obtenir le menu selon l'état
void getActiveMenu(MenuItem* activeMenu, int* activeMenuLength) {
int index = 0;
if (lifeStage == DEAD) {
// Menu quand le personnage est mort
activeMenu[index++] = {"Quitter", MenuItem::QUIT};
} else if (isSleeping) {
// Menu quand le personnage dort
activeMenu[index++] = {"Reveiller", MenuItem::ACTION};
if (isSick) {
activeMenu[index++] = {"Soigner", MenuItem::ACTION};
}
activeMenu[index++] = {"Quitter", MenuItem::QUIT};
} else {
// Menu quand le personnage est éveillé
activeMenu[index++] = {"Jouer", MenuItem::ACTION};
activeMenu[index++] = {"Manger", MenuItem::ACTION};
activeMenu[index++] = {"Dormir", MenuItem::ACTION};
if (isSick) {
activeMenu[index++] = {"Soigner", MenuItem::ACTION};
}
activeMenu[index++] = {"Quitter", MenuItem::QUIT};
}
*activeMenuLength = index;
}
void drawMenu()
{
MenuItem activeMenu[6];
int activeMenuLength;
getActiveMenu(activeMenu, &activeMenuLength);
// Assure-toi que l'index est valide
if (currentIndex >= activeMenuLength) {
currentIndex = 0;
}
display.setTextSize(0); // Texte plus petit
display.setTextColor(SSD1306_WHITE);
display.fillRect(0, 52, SCREEN_WIDTH, 12, SSD1306_BLACK); // Efface la zone menu en bas
// Menu déroulant : affiche l'option sélectionnée au centre, les autres à gauche/droite sans flèches
int menuY = 54;
int center = SCREEN_WIDTH / 2;
int16_t x1, y1;
uint16_t w, h;
// Option sélectionnée (centrée)
display.getTextBounds(activeMenu[currentIndex].name, 0, 0, &x1, &y1, &w, &h);
int selX = center - w / 2;
display.fillRect(selX - 2, menuY - 2, w + 4, 12, SSD1306_WHITE);
display.setTextColor(SSD1306_BLACK, SSD1306_WHITE);
display.setCursor(selX, menuY);
display.print(activeMenu[currentIndex].name);
// Option précédente (à gauche, sans flèche)
int prev = (currentIndex - 1 + activeMenuLength) % activeMenuLength;
display.setTextColor(SSD1306_WHITE, SSD1306_BLACK);
display.getTextBounds(activeMenu[prev].name, 0, 0, &x1, &y1, &w, &h);
int prevX = 2;
display.setCursor(prevX, menuY);
display.print(activeMenu[prev].name);
// Option suivante (à droite, sans flèche)
int next = (currentIndex + 1) % activeMenuLength;
display.getTextBounds(activeMenu[next].name, 0, 0, &x1, &y1, &w, &h);
int nextX = SCREEN_WIDTH - w - 2;
display.setCursor(nextX, menuY);
display.print(activeMenu[next].name);
display.setTextColor(SSD1306_WHITE);
display.display();
}
void setup()
{
pinMode(BTN_LEFT, INPUT_PULLUP);
pinMode(BTN_RIGHT, INPUT_PULLUP);
pinMode(BTN_OK, INPUT_PULLUP);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(200);
randomSeed(analogRead(0));
// Délai d'éclosion aléatoire entre 1 et 4 minutes
eggCrackDelay = random(60000, 240001); // 60 000 à 240 000 ms
eggStartTime = millis(); // Démarre le timer d'œuf
eggAnimStep = 0;
lastEggMove = millis();
nextEggMoveDelay = random(1000, 5001); // 1 à 5s
showHome();
}
void loop()
{
// Animation œuf qui frétille (tant que pas éclos)
if (lifeStage == EGG || lifeStage == EGG_CRACKED)
{
if (millis() - lastEggMove > nextEggMoveDelay || eggAnimStep != 0)
{
eggAnnimation();
lastEggMove = millis();
nextEggMoveDelay = random(5000, 10001); // 1 à 5s
showHome();
}
}
// Gestion du cycle de vie
if (lifeStage == EGG && millis() - eggStartTime > eggCrackDelay)
{
lifeStage = EGG_CRACKED;
showHome();
eggStartTime = millis(); // Redémarre le timer pour l'œuf cassé
return;
}
if (lifeStage == EGG_CRACKED && millis() - eggStartTime > eggHatchDelay)
{
lifeStage = CREATURE;
isDuck = random(2) == 0; // 1 chance sur 2 d'être un canard
// Réinitialise les stats à la naissance
bonheur = 8;
faim = 8;
fatigue = 3;
showHome();
return;
}
// --- Gestion du menu (doit rester accessible même si la créature dort) ---
// Si menu non actif, appui long sur OK pour ouvrir le menu
static unsigned long btnOkPressTime = 0;
if (!menuActive && digitalRead(BTN_OK) == LOW)
{
if (btnOkPressTime == 0)
btnOkPressTime = millis();
else if (millis() - btnOkPressTime > 800)
{ // 0,8s pour ouvrir menu
menuActive = true;
currentIndex = currentState; // Optionnel : démarrer menu sur état courant
drawMenu();
while (digitalRead(BTN_OK) == LOW)
delay(10); // Attend relâchement bouton
btnOkPressTime = 0;
lastBtnOK = millis();
return;
}
}
else if (!menuActive)
{
btnOkPressTime = 0;
}
if (menuActive)
{
MenuItem activeMenu[6];
int activeMenuLength;
getActiveMenu(activeMenu, &activeMenuLength);
if (millis() - lastBtnLeft > debounceDelay && digitalRead(BTN_LEFT) == LOW)
{
currentIndex = (currentIndex - 1 + activeMenuLength) % activeMenuLength;
drawMenu();
lastBtnLeft = millis();
}
if (millis() - lastBtnRight > debounceDelay && digitalRead(BTN_RIGHT) == LOW)
{
currentIndex = (currentIndex + 1) % activeMenuLength;
drawMenu();
lastBtnRight = millis();
}
if (millis() - lastBtnOK > debounceDelay && digitalRead(BTN_OK) == LOW)
{
if (activeMenu[currentIndex].type == MenuItem::QUIT)
{
menuActive = false;
showHome();
}
else if (activeMenu[currentIndex].type == MenuItem::ACTION)
{
if (strcmp(activeMenu[currentIndex].name, "Jouer") == 0)
{
if (!isSick) {
bonheur = min(bonheur + 2, 10);
fatigue = min(fatigue + 2, 10); // Jouer fatigue
showPlayAnimation(); // Animation jouer
}
}
if (strcmp(activeMenu[currentIndex].name, "Manger") == 0)
{
if (!isSick) {
faim = min(faim + 3, 10);
showEatAnimation(); // Animation manger (plus de texte)
}
}
if (strcmp(activeMenu[currentIndex].name, "Dormir") == 0)
{
if (!isSleeping && !isSick) {
isSleeping = true;
sleepStartTime = millis();
showHome();
}
return;
}
if (strcmp(activeMenu[currentIndex].name, "Reveiller") == 0)
{
if (isSleeping) {
isSleeping = false;
showSelectedAction("Réveillé !");
} else {
showSelectedAction("Pas endormi");
}
}
if (strcmp(activeMenu[currentIndex].name, "Soigner") == 0)
{
if (isSick) {
isSick = false;
sickStateTimer = 0; // Réinitialise le timer de mort par maladie
showSelectedAction("Soigné !");
} else {
showSelectedAction("Pas malade");
}
}
// Feedback
if (strcmp(activeMenu[currentIndex].name, "Manger") != 0 && strcmp(activeMenu[currentIndex].name, "Dormir") != 0 && strcmp(activeMenu[currentIndex].name, "Jouer") != 0 && strcmp(activeMenu[currentIndex].name, "Soigner") != 0 && strcmp(activeMenu[currentIndex].name, "Reveiller") != 0)
{
showSelectedAction(activeMenu[currentIndex].name);
}
drawMenu();
}
lastBtnOK = millis();
}
}
// --- Gestion du sommeil (après le menu, pour ne pas bloquer le menu) ---
// Réveil automatique après 8h de sommeil
if (isSleeping && millis() - sleepStartTime > sleepDuration) {
isSleeping = false;
fatigue = max(fatigue - 5, 0); // Récupère de la fatigue en dormant
showHome();
}
// --- Gestion de la mort ---
if (lifeStage == CREATURE) {
// Si en état critique pendant 2h, le tamagotchi meurt
if (faim <= 0 || bonheur <= 0 || fatigue >= 10) {
if (criticalStateTimer == 0) criticalStateTimer = millis();
else if (millis() - criticalStateTimer > criticalStateDuration) {
lifeStage = DEAD;
showHome();
return;
}
} else {
criticalStateTimer = 0;
}
// Si malade pendant 4h sans soin, le tamagotchi meurt
if (isSick) {
if (sickStateTimer == 0) sickStateTimer = millis();
else if (millis() - sickStateTimer > sickStateDuration) {
lifeStage = DEAD;
showHome();
return;
}
} else {
sickStateTimer = 0;
}
}
if (lifeStage == CREATURE && isSick)
{
// Si malade, jauges baissent 2x plus vite
static unsigned long lastSickDecay = 0;
if (millis() - lastSickDecay > 0.5 * hungerDecayInterval) {
faim = max(faim - 1, 0);
bonheur = max(bonheur - 1, 0);
fatigue = min(fatigue + 1, 10);
lastSickDecay = millis();
showHome();
}
// On peut toujours ouvrir le menu pour soigner
// On bloque les autres actions
return;
}
// Si la créature n'est pas née ou est morte, on bloque le menu
if (lifeStage != CREATURE)
{
return;
}
// Endormissement automatique si très fatigué
if (!isSleeping && fatigue >= 10)
{
isSleeping = true;
sleepStartTime = millis();
showHome();
return;
}
// Décroissance faim, bonheur, montée fatigue selon rythme 24h
static unsigned long lastHungerDecay = 0;
static unsigned long lastHappinessDecay = 0;
static unsigned long lastFatigueIncrease = 0;
if (millis() - lastHungerDecay > hungerDecayInterval)
{
faim = max(faim - 1, 0);
lastHungerDecay = millis();
showHome();
}
if (millis() - lastHappinessDecay > happinessDecayInterval)
{
bonheur = max(bonheur - 1, 0);
lastHappinessDecay = millis();
showHome();
}
if (millis() - lastFatigueIncrease > fatigueIncreaseInterval && !isSleeping)
{
fatigue = min(fatigue + 1, 10);
lastFatigueIncrease = millis();
showHome();
}
// --- Déclenchement de la maladie ---
static unsigned long sickTimer = 0;
if (!isSick && (faim <= 2 || bonheur <= 2 || fatigue >= 9)) {
if (sickTimer == 0) sickTimer = millis();
else if (millis() - sickTimer > 60000) { // 1 min dans un état critique
isSick = true;
showHome();
}
} else {
sickTimer = 0;
}
}
void showEatAnimation()
{
// 1. Affiche la créature normale + pomme à droite (ou canard + pomme)
const unsigned char *sprite;
if (isDuck) {
if (fatigue >= 8)
sprite = coincoin_sad;
else if (bonheur >= 7 && faim >= 7 && fatigue <= 3)
sprite = coincoin_happy;
else if (bonheur <= 3 || faim <= 3)
sprite = coincoin_sad;
else
sprite = coincoin;
} else {
if (fatigue >= 8)
sprite = tamagotchi_sad;
else if (bonheur >= 7 && faim >= 7 && fatigue <= 3)
sprite = tamagotchi_happy;
else if (bonheur <= 3 || faim <= 3)
sprite = tamagotchi_sad;
else
sprite = tamagotchi_general;
}
display.clearDisplay();
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, sprite, 32, 32, SSD1306_WHITE);
// Pomme à droite de la tête
int pommeX = (SCREEN_WIDTH - 32) / 2 + 32 + 4;
int pommeY = 18;
if (isDuck)
display.drawBitmap(pommeX, pommeY, tamagotchi_pomme, 12, 12, SSD1306_WHITE); // ou un autre sprite si tu veux
else
display.drawBitmap(pommeX, pommeY, tamagotchi_pomme, 12, 12, SSD1306_WHITE);
display.display();
delay(1000); // Attend 1 seconde
// 2. Pomme disparait, il mâche 3 fois
for (int i = 0; i < 3; i++)
{
display.clearDisplay();
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, sprite, 32, 32, SSD1306_WHITE);
display.display();
delay(120);
display.clearDisplay();
if (isDuck)
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, coincoin_manger, 32, 32, SSD1306_WHITE);
else
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, tamagotchi_bouche_ouverte, 32, 32, SSD1306_WHITE);
display.display();
delay(120);
}
// Fin sur l'état normal
display.clearDisplay();
display.drawBitmap((SCREEN_WIDTH - 32) / 2, 6, sprite, 32, 32, SSD1306_WHITE);
display.display();
}
void showPlayAnimation()
{
// Animation jouer : la créature saute 3 fois
const unsigned char *sprite;
if (isDuck) {
if (fatigue >= 8)
sprite = coincoin_sad;
else if (bonheur >= 7 && faim >= 7 && fatigue <= 3)
sprite = coincoin_happy;
else if (bonheur <= 3 || faim <= 3)
sprite = coincoin_sad;
else
sprite = coincoin;
} else {
if (fatigue >= 8)
sprite = tamagotchi_sad;
else if (bonheur >= 7 && faim >= 7 && fatigue <= 3)
sprite = tamagotchi_happy;
else if (bonheur <= 3 || faim <= 3)
sprite = tamagotchi_sad;
else
sprite = tamagotchi_general;
}
int baseY = 6;
for (int i = 0; i < 3; i++)
{
// Saut vers le haut
display.clearDisplay();
display.drawBitmap((SCREEN_WIDTH - 32) / 2, baseY - 8, sprite, 32, 32, SSD1306_WHITE);
display.display();
delay(120);
// Redescend
display.clearDisplay();
display.drawBitmap((SCREEN_WIDTH - 32) / 2, baseY, sprite, 32, 32, SSD1306_WHITE);
display.display();
delay(120);
}
// Fin sur la position normale
display.clearDisplay();
display.drawBitmap((SCREEN_WIDTH - 32) / 2, baseY, sprite, 32, 32, SSD1306_WHITE);
display.display();
}
// Fonction d'animation de l'œuf (oscillation droite-gauche)
void eggAnnimation() {
// eggAnimStep: 0 = centre, 1 = droite, 2 = gauche
if (eggAnimStep == 0) {
eggAnimStep = 1;
} else if (eggAnimStep == 1) {
eggAnimStep = 2;
} else {
eggAnimStep = 0;
}
}