From 6b4e4992d7bd4989552d0129fb5ef8e07018e030 Mon Sep 17 00:00:00 2001 From: Gus <85527977+gusocosta@users.noreply.github.com> Date: Tue, 22 Jul 2025 11:41:33 -0300 Subject: [PATCH] Add files via upload --- bitmaps.h | 301 +++++++++++++++++++ virtua_pet_R1.ino | 724 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1025 insertions(+) create mode 100644 bitmaps.h create mode 100644 virtua_pet_R1.ino diff --git a/bitmaps.h b/bitmaps.h new file mode 100644 index 0000000..6120e81 --- /dev/null +++ b/bitmaps.h @@ -0,0 +1,301 @@ +#pragma once +#include + +//================================================================ +//============================= Pets ============================= +//================================================================ + +//================================================================ +//============================== Egg ============================= +//================================================================ +// 'egg', 12x13px +const unsigned char egg [] PROGMEM = { + 0xc0, 0x30, 0x8c, 0x82, 0x01, 0x01, 0x39, 0x45, 0x42, 0x4c, 0x30, 0xc0, 0x03, 0x07, 0x0c, 0x14, + 0x13, 0x10, 0x10, 0x10, 0x10, 0x08, 0x04, 0x03 +}; + +//================================================================ +//============================ Slime ============================= +//================================================================ +// 'slime_bot1', 12x2px +const unsigned char slime_bot1 [] PROGMEM = { + 0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x00 +}; +// 'slime_eye1', 12x3px +const unsigned char slime_eye1 [] PROGMEM = { + 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07 +}; +// 'slime_eye_h1', 12x3px +const unsigned char slime_eye_h1 [] PROGMEM = { + 0x07, 0x00, 0x04, 0x02, 0x04, 0x00, 0x00, 0x04, 0x02, 0x04, 0x00, 0x07 +}; +// 'slime_eye_h2', 12x3px +const unsigned char slime_eye_h2 [] PROGMEM = { + 0x07, 0x00, 0x02, 0x01, 0x02, 0x00, 0x00, 0x02, 0x01, 0x02, 0x00, 0x07 +}; +// 'slime_eye_n1', 12x3px +const unsigned char slime_eye_n1 [] PROGMEM = { + 0x07, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x07 +}; +// 'slime_eye_n2', 12x3px +const unsigned char slime_eye_n2 [] PROGMEM = { + 0x07, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07 +}; +// 'slime_eye_s1', 12x3px +const unsigned char slime_eye_s1 [] PROGMEM = { + 0x07, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x07 +}; +// 'slime_eye_s2', 12x3px +const unsigned char slime_eye_s2 [] PROGMEM = { + 0x07, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x07 +}; +// 'slime_up1', 12x4px +const unsigned char slime_up1 [] PROGMEM = { + 0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x08, 0x00 +}; +// 'slime_up2', 12x4px +const unsigned char slime_up2 [] PROGMEM = { + 0x08, 0x04, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x08 +}; + +//================================================================ +//============================ Bunny ============================= +//================================================================ +// 'bunny_bot_h1', 16x7px +const unsigned char bunny_bot_h1 [] PROGMEM = { + 0x00, 0x0c, 0x12, 0x3f, 0x40, 0x50, 0x52, 0x5c, 0x51, 0x62, 0x4a, 0x52, 0x66, 0x2a, 0x31, 0x00 +}; +// 'bunny_bot_h2', 16x7px +const unsigned char bunny_bot_h2 [] PROGMEM = { + 0x06, 0x09, 0x3f, 0x40, 0x50, 0x52, 0x5d, 0x52, 0x74, 0x14, 0x14, 0x24, 0x2c, 0x36, 0x15, 0x18 +}; +// 'bunny_bot_n1', 16x7px +const unsigned char bunny_bot_n1 [] PROGMEM = { + 0x00, 0x0c, 0x12, 0x3f, 0x40, 0x50, 0x52, 0x5c, 0x51, 0x62, 0x4a, 0x52, 0x66, 0x2a, 0x31, 0x00 +}; +// 'bunny_bot_n2', 16x7px +const unsigned char bunny_bot_n2 [] PROGMEM = { + 0x00, 0x06, 0x09, 0x3f, 0x40, 0x50, 0x52, 0x5d, 0x52, 0x64, 0x4c, 0x54, 0x6c, 0x2c, 0x32, 0x01 +}; +// 'bunny_up1', 16x6px +const unsigned char bunny_up_n1 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x21, 0x06, 0x08, 0x06, 0x01, 0x11, 0x2e, 0x00 +}; +// 'bunny_up2', 16x6px +const unsigned char bunny_up_n2 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x02, 0x0c, 0x10, 0x0c, 0x02, 0x22, 0x1c, 0x00 +}; +// 'bunny_uph1', 16x6px +const unsigned char bunny_up_h1 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x22, 0x22, 0x0c, 0x08, 0x10, 0x1e, 0x01, 0x01, 0x3e, 0x00 +}; +// 'bunny_uph2', 16x6px +const unsigned char bunny_up_h2 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x04, 0x18, 0x10, 0x20, 0x30, 0x0c, 0x02, 0x32, 0x0c, 0x00 +}; +// 'bunny_eye_h1', 16x3px +const unsigned char bunny_eye_h1 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x07, 0x02, 0x01, 0x02, 0x00, 0x02, 0x01, 0x02, 0x07 +}; +// 'bunny_eye_h2', 16x3px +const unsigned char bunny_eye_h2 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x04, 0x02, 0x03, 0x07, 0x04, 0x02, 0x04, 0x00, 0x04, 0x02, 0x05, 0x06, 0x00 +}; +// 'bunny_eye_n1', 16x3px +const unsigned char bunny_eye_n1 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x07, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x07 +}; +// 'bunny_eye_n2', 16x3px +const unsigned char bunny_eye_n2 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x06, 0x01, 0x00, 0x06, 0x00, 0x06, 0x00, 0x01, 0x06 +}; +// 'bunny_eye_s1', 16x3px +const unsigned char bunny_eye_s1 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x07, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x07 +}; +// 'bunny_eye_s2', 16x3px +const unsigned char bunny_eye_s2 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x02, 0x06, 0x01, 0x04, 0x04, 0x00, 0x04, 0x04, 0x01, 0x06 +}; + +//================================================================ +//============================= Dino ============================= +//================================================================ + +// 'dino_back1', 16x16px +const unsigned char dino_back1 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x88, 0x04, 0x04, 0x04, 0xc4, 0x34, + 0x00, 0x00, 0x00, 0x0c, 0x12, 0x24, 0x23, 0x70, 0xc0, 0xa0, 0xc0, 0xa1, 0xce, 0x30, 0x43, 0x84 +}; +// 'dino_back2', 16x16px +const unsigned char dino_back2 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x88, 0x04, 0x04, 0xc4, 0x34, 0x08, + 0x00, 0x00, 0x04, 0x0a, 0x12, 0x22, 0x21, 0x70, 0xc0, 0xa0, 0xc0, 0xa1, 0xce, 0x33, 0x44, 0x84 +}; +// 'dino_bot1', 16x6px +const unsigned char dino_bot1 [] PROGMEM = { + 0x21, 0x36, 0x2a, 0x14, 0x24, 0x34, 0x28, 0x38, 0x0a, 0x0a, 0x0a, 0x05, 0x09, 0x05, 0x02, 0x01 +}; +// 'dino_bot2', 16x6px +const unsigned char dino_bot2 [] PROGMEM = { + 0x22, 0x36, 0x2c, 0x14, 0x14, 0x28, 0x38, 0x2a, 0x3a, 0x0a, 0x05, 0x09, 0x05, 0x02, 0x01, 0x00 +}; +// 'dino_up1', 16x7px +const unsigned char dino_up1 [] PROGMEM = { + 0x08, 0x44, 0x24, 0x02, 0x32, 0x49, 0x45, 0x23, 0x1d, 0x01, 0x02, 0x04, 0x18, 0x68, 0x24, 0x3c +}; +// 'dino_up2', 16x7px +const unsigned char dino_up2 [] PROGMEM = { + 0x44, 0x24, 0x02, 0x32, 0x49, 0x45, 0x23, 0x1d, 0x01, 0x02, 0x04, 0x18, 0x68, 0x24, 0x3c, 0x00 +}; +// 'dino_eye_h1', 16x3px +const unsigned char dino_eye_h1 [] PROGMEM = { + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x02, 0x00, 0x06, 0x01, 0x00, 0x07, 0x04 +}; +// 'dino_eye_h2', 16x3px +const unsigned char dino_eye_h2 [] PROGMEM = { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x04, 0x00, 0x06, 0x01, 0x00, 0x07, 0x04, 0x00 +}; +// 'dino_eye_n1', 16x3px +const unsigned char dino_eye_n1 [] PROGMEM = { + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, 0x01, 0x00, 0x07, 0x04 +}; +// 'dino_eye_n2', 16x3px +const unsigned char dino_eye_n2 [] PROGMEM = { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x07, 0x04, 0x00 +}; +// 'dino_eye_s1', 16x3px +const unsigned char dino_eye_s1 [] PROGMEM = { + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x06, 0x01, 0x00, 0x07, 0x04 +}; +// 'dino_eye_s2', 16x3px +const unsigned char dino_eye_s2 [] PROGMEM = { + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x06, 0x01, 0x00, 0x07, 0x04, 0x00 +}; + +//================================================================ +//============================ T-Rex ============================= +//================================================================ +// 'trex_back1', 16x16px +const unsigned char trex_back1 [] PROGMEM = { + 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xa0, 0x60, 0x40, 0x60, 0x50, 0x20, 0x30, 0x28, 0xbe, 0x05, + 0x06, 0x0b, 0x0a, 0x09, 0x08, 0x08, 0x10, 0x10, 0x10, 0x70, 0x89, 0x81, 0xa2, 0xfe, 0x58, 0x6b +}; +// 'trex_back2', 16x16px +const unsigned char trex_back2 [] PROGMEM = { + 0x80, 0xc0, 0xa0, 0x60, 0x40, 0x60, 0x50, 0x60, 0x40, 0x60, 0x50, 0x20, 0x30, 0x28, 0x10, 0xbe, + 0x01, 0x02, 0x02, 0x04, 0x04, 0x04, 0x08, 0x08, 0x10, 0x70, 0x89, 0x81, 0xa2, 0xfe, 0x58, 0x68 +}; +// 'trex_bot1', 16x9px +const unsigned char trex_bot1 [] PROGMEM = { + 0x08, 0x10, 0x10, 0x20, 0x20, 0x22, 0x20, 0x10, 0x12, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_bot2', 16x9px +const unsigned char trex_bot2 [] PROGMEM = { + 0x16, 0x08, 0x10, 0x20, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_up1', 16x4px +const unsigned char trex_up1 [] PROGMEM = { + 0x05, 0x02, 0x05, 0x05, 0x09, 0x06, 0x02, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_up2', 16x4px +const unsigned char trex_up2 [] PROGMEM = { + 0x05, 0x05, 0x02, 0x05, 0x05, 0x09, 0x06, 0x02, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_eye_h1', 16x3px +const unsigned char trex_eye_h1 [] PROGMEM = { + 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_eye_h2', 16x3px +const unsigned char trex_eye_h2 [] PROGMEM = { + 0x00, 0x00, 0x04, 0x02, 0x04, 0x00, 0x04, 0x02, 0x04, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_eye_n1', 16x3px +const unsigned char trex_eye_n1 [] PROGMEM = { + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_eye_n2', 16x3px +const unsigned char trex_eye_n2 [] PROGMEM = { + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_eye_s1', 16x3px +const unsigned char trex_eye_s1 [] PROGMEM = { + 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +// 'trex_eye_s2', 16x3px +const unsigned char trex_eye_s2 [] PROGMEM = { + 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04, 0x04, 0x00, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + + +//================================================================ +//============================ Icons ============================= +//================================================================ + +// 'icon_sleep', 8x8px +const unsigned char icon_sleep [] PROGMEM = { + 0xc8, 0xa8, 0x98, 0x00, 0x1a, 0x16, 0x00, 0x01 +}; +// 'icon_clean', 8x8px +const unsigned char icon_clean [] PROGMEM = { + 0x08, 0x1c, 0x08, 0x00, 0x02, 0x20, 0x70, 0x20 +}; +// 'icon_hand', 8x8px +const unsigned char icon_hand [] PROGMEM = { + 0x38, 0x4e, 0x81, 0x8f, 0x81, 0x8f, 0x41, 0x3e +}; +// 'icon_stat', 8x8px +const unsigned char icon_stat [] PROGMEM = { + 0xf0, 0xf0, 0x00, 0xfe, 0xfe, 0x00, 0xfc, 0xfc +}; +// 'icon_tomato1', 8x8px +const unsigned char icon_tomato [] PROGMEM = { + 0x00, 0x70, 0xf8, 0xfa, 0xec, 0xd8, 0x70, 0x00 +}; +// 'icon_carrot1', 8x8px +const unsigned char icon_carrot [] PROGMEM = { + 0x1c, 0x04, 0x1e, 0x3d, 0x3d, 0x78, 0xe0, 0xc0 +}; +// 'icon_mushroom1', 8x8px +const unsigned char icon_mushroom [] PROGMEM = { + 0x0c, 0x1e, 0xdf, 0xff, 0x7f, 0x1d, 0x12, 0x0c +}; +// 'icon_chickenleg1', 8x8px +const unsigned char icon_chickenleg [] PROGMEM = { + 0x1e, 0x3f, 0x3f, 0x3d, 0x3a, 0x7c, 0xe0, 0x40 +}; +// 'icon_candy1', 8x8px +const unsigned char icon_candy [] PROGMEM = { + 0x38, 0x7c, 0xfe, 0xff, 0x9f, 0x4d, 0x22, 0x1c +}; +// 'icon_happiness', 8x8px +const unsigned char icon_happiness [] PROGMEM = { + 0x3c, 0x42, 0x95, 0xa1, 0xa1, 0x95, 0x42, 0x3c +}; +// 'icon_health', 8x8px +const unsigned char icon_health [] PROGMEM = { + 0x00, 0x18, 0x18, 0x7e, 0x7e, 0x18, 0x18, 0x00 +}; +// 'icon_fem', 8x8px +const unsigned char icon_fem [] PROGMEM = { + 0x00, 0x0e, 0x51, 0xf1, 0x51, 0x0e, 0x00, 0x00 +}; +// 'icon_male', 8x8px +const unsigned char icon_male [] PROGMEM = { + 0x70, 0x88, 0x88, 0x88, 0x79, 0x05, 0x03, 0x0f +}; +// 'icon_x', 8x8px +const unsigned char icon_x [] PROGMEM = { + 0xc6, 0xee, 0x7c, 0x38, 0x7c, 0xee, 0xc6, 0x00 +}; +// 'icon_poop', 8x8px +const unsigned char icon_poop [] PROGMEM = { + 0x00, 0x60, 0x78, 0x74, 0x6c, 0x7a, 0x60, 0x00 +}; +// 'icon_dead', 8x8px +const unsigned char icon_dead [] PROGMEM = { + 0x00, 0x0c, 0x0c, 0xff, 0xff, 0x0c, 0x0c, 0x00 +}; diff --git a/virtua_pet_R1.ino b/virtua_pet_R1.ino new file mode 100644 index 0000000..1c702bd --- /dev/null +++ b/virtua_pet_R1.ino @@ -0,0 +1,724 @@ +/* ==================================== Virtua Pet R1 ================================ +Hi. This is a tiny little project I made to get my own Virtual Pet. I hope you like it +as much as I do. +The code can receive some optimiztion, so feel free to change it as you like. +All the bitmap images are on the bitmap.h file. +I would be glade to see your project too if you choose to make one pet by yourself. +Thank you! + +HARDWARE: +- STM32 F103C8T6 (Blue Pill); (It demands at least 3.5KB RAM and 32KB ROM) +- 1.3" OLED I2C Screen 128x64; +- 4 push buttons (with 1n4148 diode to prevent debounce); + +by Gus Costa +(GitHub: gusocosta) +(Reddit: gu-ocosta) +====================================================================================== +*/ + +#include +#include "bitmaps.h" +GyverOLED oled; + +//Peripheral constants +const uint8_t bt_down = PA9; +const uint8_t bt_right = PA10; +const uint8_t bt_up = PA11; +const uint8_t bt_left = PA12; + +//Time vars and const +const uint8_t check_pet_time = 5; //in sec +uint32_t draw_tick = 0; +uint8_t draw_tick_max = 100; +uint16_t act_time[4] = {0,0,0,0}; +uint32_t current_millis = 0; +uint32_t previous_millis = 0; +uint32_t ani_tick = 0; +uint32_t ani_tick_previous = 0; +uint32_t ani_tick_previous_millis = 0; +uint32_t screen_tick = 0; +uint32_t screen_tick_previous = 0; +uint32_t buttom_cooldown_millis = 0; +uint8_t buttom_cooldown = 200; + +uint32_t doing_tick = 0; +uint32_t doing_cooldown = 2000; +uint32_t sleeping_time = 0; +bool ani_icon_playing = false; + +//Pet vars and const +uint8_t pet_species = 0; +byte pet_sex = 0; +uint8_t pet_lvl = 0; +const uint8_t species_amount = 5; +String pet_all_species[species_amount] = {"Egg", "Slime", "Bunny", "Dino", "T-Rex"}; +uint8_t pet_size[species_amount] = {24, 24, 32, 64, 64}; +int pet_eating_vars[species_amount][5][5] ={ //[species][food][status change] + //food> 0: eating tomato, 1: eating carrot, 2: eating mushroom, 3: eating chicken, 4: eating candy + //status> 0: health, 1: hungry, 2: chean, 3: happy, 4: sleep + {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}}, //egg + {{2,10,0,-5,0},{2,10,0,-5,0},{2,15,0,0,0},{2,15,0,10,0},{-10,25,0,20,0}}, //slime + {{2,10,0,5,0},{2,25,0,15,0},{2,15,0,0,0},{-10,5,0,-5,0},{-10,20,0,10,0}}, //bunny + {{2,25,0,15,0},{2,10,0,0,0},{2,15,0,0,0},{-2,5,0,-5,0},{-10,20,0,10,0}}, //dino + {{-2,5,0,-5,0},{-2,5,0,-5,0},{-2,5,0,-5,0},{20,20,0,15,0},{-10,20,0,10,0}}}; //t_rex +String pet_age = "0m"; +typedef struct { + uint8_t health; //0-100 + uint8_t hungry; //0-100 + uint8_t clean; //0-100 + uint8_t happy; //0-100 + uint16_t sleep; //0-200 +} pet_stats; +pet_stats pet = {100,80,80,80,200}; +uint8_t pet_mood = 0; //0: normal, 1: happy, 2: sleep, 3:dead +uint8_t pet_doing = 0; //0: nothing, 1: eating tomato, 2: eating carrot, 3: eating mushroom, 4: eating chicken, 5: eating candy, 6: cleaning, 7: petting, 8: sleeping, 9: dead +bool pet_alive = true; +bool pet_sleeping = false; +bool pet_poop = false; +uint8_t pet_ani = 0; +uint8_t food_check[5] = {0,0,0,0,0}; +bool happy_fail = false; //vars to check for evolution +bool health_fail = false; //vars to check for evolution + +//UI vars and consts +uint32_t rng_comp = 0; +int rng_dir = 1; +uint8_t screen = 1; //0: name, 1: main, 2: status +uint8_t sel = 0; +uint8_t food_sel = 0; //0: tomato, 1: carrot, 2: mushroom, 3: chicken, 4: candy +const uint8_t bottom_bar_size = 5; +uint8_t bottom_bar_sel_size = 0; +uint8_t bottom_bar_pos[bottom_bar_size] ={}; +uint8_t explosion_rad = 0; +bool evolve_ani = false; + + +//Sprite arrays for the animations +const unsigned char* bottom_bar_icons[bottom_bar_size-1] = {icon_hand, icon_clean, icon_sleep, icon_stat}; +const unsigned char* bottom_bar_food[5] = {icon_tomato, icon_carrot, icon_mushroom, icon_chickenleg, icon_candy}; +const unsigned char* icon_popup[9] = {icon_tomato, icon_carrot, icon_mushroom, icon_chickenleg, icon_candy, icon_clean, icon_hand, icon_sleep, icon_dead}; + +const unsigned char* slime_bot[1][1] = {{slime_bot1}}; +const unsigned char* slime_up[1][2] = {{slime_up1, slime_up2}}; +const unsigned char* slime_eyes[3][2] = {{slime_eye_n1, slime_eye_n2},{slime_eye_h1, slime_eye_h2},{slime_eye_s1, slime_eye_s2}}; + +const unsigned char* bunny_bot[2][2] = {{bunny_bot_n1, bunny_bot_n2},{bunny_bot_h1, bunny_bot_h2}}; +const unsigned char* bunny_up[2][2] = {{bunny_up_n1, bunny_up_n2},{bunny_up_h1, bunny_up_h2}}; +const unsigned char* bunny_eyes[3][2] = {{bunny_eye_n1, bunny_eye_n2},{bunny_eye_h1, bunny_eye_h2},{bunny_eye_s1, bunny_eye_s2}}; + +const unsigned char* dino_back[1][2] = {{dino_back1, dino_back2}}; +const unsigned char* dino_bot[1][2] = {{dino_bot1, dino_bot2}}; +const unsigned char* dino_up[1][2] = {{dino_up1, dino_up2}}; +const unsigned char* dino_eyes[3][2] = {{dino_eye_n1, dino_eye_n2},{dino_eye_h1, dino_eye_h2},{dino_eye_s1, dino_eye_s2}}; + +const unsigned char* trex_back[1][2] = {{trex_back1, trex_back2}}; +const unsigned char* trex_bot[1][2] = {{trex_bot1, trex_bot2}}; +const unsigned char* trex_up[1][2] = {{trex_up1, trex_up2}}; +const unsigned char* trex_eyes[3][2] = {{trex_eye_n1, trex_eye_n2},{trex_eye_h1, trex_eye_h2},{trex_eye_s1, trex_eye_s2}}; + +void setup() { + Serial.begin(9600); + pinMode(bt_left, INPUT_PULLUP); + pinMode(bt_right, INPUT_PULLUP); + pinMode(bt_up, INPUT_PULLUP); + pinMode(bt_down, INPUT_PULLUP); + //pinMode(buzz, OUTPUT); + + oled.init(); + oled.clear(); + bottom_bar_gen(); + age_gen(); + + rng_comp = int(millis()+analogRead(PA0)); + if (rng_comp % 2 == 0){pet_sex = 1;} +} + +// Generates the bottom bar +void bottom_bar_gen(){ + bottom_bar_sel_size = 127 / bottom_bar_size; + for(uint8_t i = 0; i < bottom_bar_size; i++){ + bottom_bar_pos[i] = (i* bottom_bar_sel_size) + ((bottom_bar_sel_size - 8)/2); + } +} + +// Make the age string on the status screen +void age_gen(){ + if (pet_alive == true){ + if (act_time[3]!=0){ + pet_age = String(act_time[3]) + "D"; + } + else if (act_time[2]!=0){ + pet_age = String(act_time[2]) + "H"; + } + else if (act_time[1]!=0){ + pet_age = String(act_time[1]) + "m"; + } + else{ + pet_age = "0m"; + } + } +} +//======================================================================== +//============================= Time Function ============================ +//======================================================================== +void time_check(){ + current_millis = millis(); + //Check animation tick + if (current_millis - ani_tick_previous_millis >= 500){ //check seconds + ani_tick_previous_millis = current_millis; + ani_tick += 1; + + //Do Action + if (current_millis > doing_tick){ + if(pet_doing < 8){ + pet_doing = 0; + if(pet_mood == 1){ + pet_mood = 0; + } + } + } + } + + //Check time change + if (current_millis - previous_millis >= 1000){ //check seconds + rng_comp = int(analogRead(PA0)) * rng_dir; + rng_dir *= -1; + + previous_millis = current_millis; + act_time[0] += 1; + if (act_time[0] == 5 && pet_lvl == 0){ + evolve_ani = true; + } + + if (act_time[0] >= 60){ //check minutes + act_time[0] = 0; + act_time[1] += 1; + if (act_time[1] % check_pet_time == 0){ + check_pet(); + } + + if (act_time[1] >= 60){ //check hours + act_time[1] = 0; + act_time[2] += 1; + if (act_time[1] >= 24){ //check days + act_time[2] = 0; + act_time[3] += 1; + if (pet_lvl == 1){ + evolve_ani = true; + } + } + } + } + } +} + +void check_bt(){ + //======================================================================== + //=============================== Button Up ============================== + //======================================================================== + if (digitalRead(bt_up) == LOW){ + rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; + rng_dir *= -1; + + if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce + buttom_cooldown_millis = millis(); + + //Main Screen + if (screen == 1){ + if (pet_alive == true && doing_tick < millis()){ + if (sel == 0){ //Eating + if (pet.hungry < 100){ + pet_doing = food_sel + 1; + //diferent stats per food + + pet.health += pet_eating_vars[pet_species][food_sel][0]; + pet.hungry += pet_eating_vars[pet_species][food_sel][1]; + pet.clean += pet_eating_vars[pet_species][food_sel][2]; + pet.happy += pet_eating_vars[pet_species][food_sel][3]; + pet.sleep += pet_eating_vars[pet_species][food_sel][4]; + + food_check[food_sel] += 1; + pet_mood = 1; + pet_sleeping = false; + } + } + + else if (sel == 1){ //Peting + if (pet.happy < 100){ + pet_doing = 7; + pet.happy += 10; + pet_mood = 1; + pet_sleeping = false; + } + } + + else if (sel == 2){ //Cleaning + if (pet_poop == true){ + pet_poop = false; + } + if (pet.clean < 100){ + pet_doing = 6; + pet.clean = 100; + pet_mood = 1; + pet_sleeping = false; + } + } + else if (sel == 3){ //Sleeping + if (pet_doing == 0 && pet_sleeping == false){ + pet_mood = 2; + pet_doing = 8; + pet_sleeping = true; + } + else if (pet_doing == 8){ + pet_mood = 0; + pet_doing = 0; + pet_sleeping = false; + } + } + else if (sel == 4){ //status + age_gen(); + screen = 2; + sel = 0; + } + doing_tick = millis() + doing_cooldown; + } + } + //Status Screen + else if (screen == 2){ + screen = 1; + } + clamp_pet(); + } + } + + //======================================================================== + //============================== Button Down ============================= + //======================================================================== + if (digitalRead(bt_down) == LOW){ + rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; + rng_dir *= -1; + + if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce + buttom_cooldown_millis = millis(); + + if (screen == 1){ + if (pet_alive == true && doing_tick < millis()){ + if (sel == 0){ //Eating + food_sel = func_select(food_sel, 4, 1); + + } + } + } + + } + } + + //======================================================================== + //============================== Button Left ============================= + //======================================================================== + if (digitalRead(bt_left) == LOW){ + rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; + rng_dir *= -1; + if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce + buttom_cooldown_millis = millis(); + + //Main Screen + if (screen == 1){ + sel = func_select(sel, bottom_bar_size-1, 0); + } + + //Status Screen + else if (screen == 2){ + screen = 1; + } + } + } + + //======================================================================== + //============================= Button Right ============================= + //======================================================================== + if (digitalRead(bt_right) == LOW){ + rng_comp += int(buttom_cooldown_millis - millis()) * rng_dir; + rng_dir *= -1; + if(millis() > buttom_cooldown_millis + buttom_cooldown){ //debounce + buttom_cooldown_millis = millis(); + + //Main Screen + if (screen == 1){ + sel = func_select(sel, bottom_bar_size - 1, 1); + } + + //Status Screen + else if (screen == 2){ + + } + } + } +} + +uint8_t func_select(uint8_t var, uint8_t max, uint8_t dir){ + if(dir > 0){ + if(var < max){var += 1;} + else{var = 0;} + } + else{ + if(var > 0){var -= 1;} + else{var = max;} + } + return var; +} + +//======================================================================== +//======================= Physiological Functions ======================== +//======================================================================== +void check_pet(){ + if (pet_alive == true){ + //awake + if (pet_sleeping == false){ + pet.sleep -= 1; + pet.hungry -= 2; + pet.clean -= 1; + if (sleeping_time >= 10){sleeping_time -= 10;} + else{sleeping_time = 0;} + + //Random Events + if (int(rng_comp % 3) == 0){pet.hungry -= 2;} + if (int(rng_comp % 4) == 0){ + pet.clean -= 1; + pet.happy -= 2; + } + //poop + if (int(rng_comp % 10) == 0){ + pet_poop = true; + } + } + //sleeping + else{ + sleeping_time += 5; + if (sleeping_time > 480){ + pet.hungry -= 2; + pet.clean -= 2; + pet.health -= 1; + } + pet.sleep += 5; + if (int(rng_comp % 3) == 0){pet.hungry -= 1;} + } + + if (pet_poop == true){ + pet.health -= 2; + pet.clean -= 3; + pet.happy -= 2; + } + + + //happiness calc + pet.happy -= ((100 - pet.health) + (100 - pet.clean) + (200 - pet.sleep) + (100 - pet.hungry))/40; + + //health calc + if((pet.happy + pet.clean + (pet.sleep/2) + pet.hungry)/4 > 80){ + pet.health += 5; + } + else if((pet.happy + pet.clean + (pet.sleep/2) + pet.hungry)/4 > 50){ + pet.health -= 1; + } + else if((pet.happy + pet.clean + (pet.sleep/2) + pet.hungry)/4 > 30){ + pet.health -= 3; + } + + //check death + if (pet.health <=0 || pet.hungry <=0 || pet.sleep <= 0 || pet.clean <=0){ + pet_alive= false; + pet_doing = 9; + pet_mood = 3; + } + } + + if (pet.health <= 50){ + health_fail = true; + } + if (pet.happy <= 70){ + happy_fail = true; + } + + clamp_pet(); +} + +void evolve(){ + switch (pet_lvl){ + case 0: + pet_species = 1; + break; + case 1: + pet_species = 2; //evolve to Bunny + if (happy_fail == false && food_check[0] == 0 && food_check[1] == 0 && food_check[2] == 0){ //evolve to T-Rex + pet_species = 4; + } + else if (health_fail == false && food_check[0] > 0 && food_check[1] > 0 && food_check[2] > 0 && food_check[3] == 0){ //evolve to Dino + pet_species = 3; + } + break; + } + pet_lvl += 1; +} + +void clamp_pet(){ + if(pet.health > 100){pet.health = 100;} + if(pet.hungry > 100){pet.hungry = 100;} + if(pet.clean > 100){pet.clean = 100;} + if(pet.happy > 100){pet.happy = 100;} + if(pet.sleep > 200){pet.sleep = 200;} +} + +void ani_check(){ + if (pet_mood == 0) { + pet_ani = ani_tick % 2; + } + else if (pet_mood == 1) { + pet_ani = 2 + (ani_tick % 2); + } + else if (pet_mood == 2) { + pet_ani = 4 + (ani_tick % 2); + } + else if (pet_mood == 3) { + pet_ani = 5; + } +} + +void resize(const uint8_t* bmp, uint16_t w, uint16_t h, int16_t x0, int16_t y0, uint8_t scale) { + if (!scale) return; // avoid divide-by-zero + + for (uint16_t sy = 0; sy < h; sy++) { + uint16_t pageOffset = (sy >> 3) * w; // which 8‑pixel row page + uint8_t mask = 1 << (sy & 7); // bit inside that page + + for (uint16_t sx = 0; sx < w; sx++) { + uint8_t b = pgm_read_byte(bmp + pageOffset + sx); + if (b & mask) { + int16_t dx = x0 + sx * scale; + int16_t dy = y0 + sy * scale; + + // draw the scale×scale block + for (uint8_t yy = 0; yy < scale; yy++) { + int16_t py = dy + yy; + if (py < 0 || py >= 64) continue; + for (uint8_t xx = 0; xx < scale; xx++) { + int16_t px = dx + xx; + if (px < 0 || px >= 128) continue; + oled.dot(px, py); + } + } + } + } + } +} +//======================================================================== +//=========================== Draw Function ============================== +//======================================================================== +void draw(){ + oled.clear(); + oled.invertText(false); + + //print time + oled.setCursorXY(2, 0); + oled.print("Day:"); + oled.print(act_time[3]); + + oled.setCursorXY(96, 0); + if (act_time[2] < 10){oled.print("0");} + oled.print(act_time[2]); + oled.print(":"); + if (act_time[1] < 10){oled.print("0");} + oled.print(act_time[1]); + + //print R.I.P. + if (pet_alive == false){ + oled.setCursorXY(48, 0); + oled.print("R.I.P."); + } + + //print upper bar + oled.setCursorXY(0, 0); + oled.line(0, 10, 127, 10); + + //======================================================================== + //===============================Main Screen============================== + //======================================================================== + if (screen == 1){ + //print char + + ani_check(); + draw_pet(); + + //draw icon + if (pet_doing > 0){ + if (pet_alive == true){ + //0: nothing, 1: eating tomato, 2: eating carrot, 3: eating mushroom, 4: eating chicken, 5: eating candy, 6: petting, 7: cleaning, 8: sleeping, 9: dead + resize(icon_popup[pet_doing-1], 8, 8, (68 + (pet_size[pet_species]/2) + (ani_tick % 2)), (16 + ((ani_tick % 2)*2)), 2); //const uint8_t* bmp, uint16_t w, uint16_t h, int16_t x0, int16_t y0, uint8_t scale + } + else{ + resize(icon_popup[8],8 ,8 ,68 + (pet_size[pet_species]/2) + (ani_tick % 2), 16 + ((ani_tick % 2)*2), 2); + } + } + + if (pet_poop == true){ + resize(icon_poop, 8, 8, 112, 32, 2); //bmp, w, h, x0, y0, scale + } + + //draw bottom bar + for (uint8_t i = 0; i < bottom_bar_size; i++){ + uint8_t invert_sprite = 0; + //print selection + if (i == sel){ + oled.rect((i*bottom_bar_sel_size), 54, ((i+1)*bottom_bar_sel_size), 63); + invert_sprite = 1; + } + if (i == 0 ){ + oled.drawBitmap(bottom_bar_pos[i], 55, bottom_bar_food[food_sel], 8, 8, 0, invert_sprite); + } + else{ + oled.drawBitmap(bottom_bar_pos[i], 55, bottom_bar_icons[i-1], 8, 8, 0, invert_sprite); + } + } + } + + //======================================================================== + //=============================Status Screen============================== + //======================================================================== + else if(screen == 2){ + //Draw Infos + if (pet_sex == 0) {oled.drawBitmap(1, 16, icon_fem, 8, 8);} + else {oled.drawBitmap(1, 16, icon_male, 8, 8);} + oled.setCursorXY(12, 16); + oled.print(pet_all_species[pet_species]); + oled.setCursorXY(1, 28); + oled.print("Age: "); + oled.print(pet_age); + oled.setCursorXY(1, 40); + oled.print("Lvl: "); + if(pet_lvl < 2){oled.print(pet_lvl);} + else{oled.print("MAX");} + + //Draw graffics + for (uint8_t i = 0; i < 5; i++){ + oled.rect(64 + (i*13), 16, 72 + (i*13), 54,2); + if(i==0){ + oled.drawBitmap(64 + (i*13), 56, icon_health, 8, 8); + oled.rect(66 + (i*13), 18 + (34 - (34 * pet.health)/100), 70 + (i*13), 52); + } + else if(i==1){ + oled.drawBitmap(64 + (i*13), 56, icon_sleep, 8, 8); + oled.rect(66 + (i*13), 18 + (34 - (34 * pet.sleep)/200), 70 + (i*13), 52); + } + else if(i==2){ + oled.drawBitmap(64 + (i*13), 56, icon_chickenleg, 8, 8); + oled.rect(66 + (i*13), 18 + (34 - (34 * pet.hungry)/100), 70 + (i*13), 52); + } + else if(i==3){ + oled.drawBitmap(64 + (i*13), 56, icon_clean, 8, 8); + oled.rect(66 + (i*13), 18 + (34 - (34 * pet.clean)/100), 70 + (i*13), 52); + } + else if(i==4){ + oled.drawBitmap(64 + (i*13), 56, icon_happiness, 8, 8); + oled.rect(66 + (i*13), 18 + (34 - (34 * pet.happy)/100), 70 + (i*13), 52); + } + } + + //Draw Back Button + oled.rect(0, 55, 6, 63); + oled.setCursor(1, 7); + oled.invertText(true); + oled.print("<"); + oled.invertText(false); + } + + if (evolve_ani == true){ + draw_explosion(); + } + oled.update(); +} + +//Solving the sprite puzzle +void draw_pet(){ + uint8_t animation_eyes; + uint8_t animation_body; + if (pet_alive == true){ + animation_eyes = pet_mood; + animation_body = ani_tick%2; + } + else{ + animation_eyes = 3; + animation_body = 0; + } + + switch (pet_species){ + //Egg + case 0: + resize(egg,12,13,52,22,2); //bmp, w, h, x0, y0, scale + break; + //Slime + case 1: + resize(slime_up[0][animation_body],12,4,52,30,2); //bmp, w, h, x0, y0, scale + resize(slime_eyes[animation_eyes][animation_body],12,3,52,38,2); + resize(slime_bot[0][0],12,2,52,44,2); + break; + //Bunny + case 2: + if (pet_alive == true){ + if(pet_mood != 1){ + resize(bunny_up[0][animation_body],16,6,48,16,2); + resize(bunny_bot[0][animation_body],16,7,48,34,2); + } + else{ + resize(bunny_up[1][animation_body],16,6,48,16,2); + resize(bunny_bot[1][animation_body],16,7,48,34,2); + } + resize(bunny_eyes[animation_eyes][animation_body],16,3,48,28,2); + } + break; + //Dino + case 3: + resize(dino_back[0][animation_body],16,16,32,16,2); //bmp, w, h, x0, y0, scale + resize(dino_up[0][animation_body],16,7,64,16,2); + resize(dino_eyes[animation_eyes][animation_body],16,3,64,30,2); + resize(dino_bot[0][animation_body],16,6,64,36,2); + + break; + //Dino + case 4: + resize(trex_back[0][animation_body],16,16,32,16,2); //bmp, w, h, x0, y0, scale + resize(trex_up[0][animation_body],16,4,64,16,2); + resize(trex_eyes[animation_eyes][animation_body],16,3,64,24,2); + resize(trex_bot[0][animation_body],16,9,64,30,2); + break; + + } +} + +//Explosion animation and evolve call +void draw_explosion(){ + explosion_rad += 3; + if (explosion_rad < 85){ + draw_tick_max = 0; + oled.circle(64, 32, explosion_rad + 10, 2); + oled.circle(64, 32, explosion_rad + 3, 2); + oled.circle(64, 32, explosion_rad, 1); + oled.circle(64, 32, explosion_rad -10, 0); + } + else{ + draw_tick_max = 100; + evolve_ani = false; + evolve(); + explosion_rad = 0; + } +} + +void loop() { + check_bt(); + time_check(); + + if(millis() > draw_tick + draw_tick_max){ //controls the screens refresh to save some battery + draw_tick = millis(); + draw(); + } +} \ No newline at end of file