Add files via upload

This commit is contained in:
Gus
2025-07-22 11:41:33 -03:00
committed by GitHub
parent 2829ac1f13
commit 6b4e4992d7
2 changed files with 1025 additions and 0 deletions

301
bitmaps.h Normal file
View File

@@ -0,0 +1,301 @@
#pragma once
#include <Arduino.h>
//================================================================
//============================= 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
};

724
virtua_pet_R1.ino Normal file
View File

@@ -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 <GyverOLED.h>
#include "bitmaps.h"
GyverOLED<SSH1106_128x64> 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 8pixel 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();
}
}