Compare commits

...
20 Commits
Author SHA1 Message Date
nacabaro 4b869f22f3 Update gitignore 2026-06-01 11:51:57 +02:00
nacabaro cde99fc554 Add partition table for the supermini 2026-06-01 11:50:21 +02:00
nacabaro 91e00bea43 Change button mappings 2026-05-29 22:46:12 +02:00
nacabaro 94c4543b59 A few things:
- Add a way to reset data from the device itself
- Fix bug in the background selector screen
- Remove blocking methods, make everything non-blocking, should improve stability in general
- Change sound effects, and put them together in the same file, using the new system, instead of doing multiple calls to the tone function
- Fix overlapping icons in the status screen, need to continue this and fix the overlapping text
2026-05-29 02:21:41 +02:00
nacabaro 915c5cd2a7 Switch the name of the disallow sleep flag 2026-05-29 02:17:32 +02:00
nacabaro 79d60e7201 Improve sound system thing in here 2026-05-29 02:16:58 +02:00
nacabaro 3de6c121a5 Add ALLOW_SLEEP flag to enable sleep mode in inactivity checks 2026-05-28 21:35:41 +02:00
nacabaro f15ea8190f Update food select screen to use precompiler parameters 2026-05-28 21:35:00 +02:00
nacabaro 9c4520e4e0 Fix issue with the background select screen
- Has a non existent background and also does not render first time
2026-05-28 21:34:35 +02:00
nacabaro 60c1659875 Enhance tft_drawText function to support background color 2026-05-28 21:33:56 +02:00
nacabaro e158f50970 Add settings screen 2026-05-28 21:32:52 +02:00
nacabaro f8f7c7a9b6 Fix egg upscale issues 2026-05-28 19:32:04 +02:00
nacabaro 24ebd8a5af Add a way to switch backgrounds 2026-05-28 19:12:27 +02:00
nacabaro 82a7d76b92 Add upscaling on the egg screen 2026-05-28 01:32:10 +02:00
nacabaro 2ae5bc8bd4 Move sprite scale to the defs 2026-05-28 01:31:21 +02:00
nacabaro dc44a695be Create upscale sprite function 2026-05-28 01:31:03 +02:00
nacabaro 0b5c56b5e3 Add support with light sleep and step sensing 2026-05-27 21:01:15 +02:00
nacabaro 55749ba2a8 Update reference file of the display properties. 2026-05-27 21:00:37 +02:00
nacabaro 9e23682068 Update env to support multiple ESP32 types 2026-05-27 21:00:23 +02:00
nacabaro 56ce03f34e Fix issue when cleaning poop 2026-05-27 21:00:04 +02:00
51 changed files with 1567 additions and 616 deletions
+5
View File
@@ -9,6 +9,11 @@
*.egg
*.cm
*.png
*.jpg
*.webp
*.adv
*.coli
ideas/
__pycache__/
venv/
sprites/
+5 -5
View File
@@ -2,17 +2,17 @@
#define USE_HSPI_PORT
#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
#define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
#define TFT_RGB_ORDER TFT_BGR // Colour order Red-Green-Blue
#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
#define TFT_HEIGHT 240 // ST7789 240 x 240
#define TFT_BL 1 // LED back-light control pin
#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
#define TFT_MOSI 1
#define TFT_MOSI 11
#define TFT_MISO -1
#define TFT_SCLK 2
#define TFT_DC 4
#define TFT_RST 3
#define TFT_SCLK 12
#define TFT_DC 5
#define TFT_RST 6
#define TOUCH_CS -1
+4
View File
@@ -0,0 +1,4 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x7000,
app0, app, factory, 0x10000, 0xA0000,
spiffs, data, spiffs, 0xB0000, 0x350000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x7000
3 app0 app factory 0x10000 0xA0000
4 spiffs data spiffs 0xB0000 0x350000
+32 -20
View File
@@ -8,40 +8,52 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
;[env:alt]
;platform = espressif32
;board = 4d_systems_esp32s3_gen4_r8n16
;framework = arduino
;lib_deps = TFT_eSPI, fbiego/ESP32Time@^2.0.6, electroniccats/MPU6050@^1.4.3
;monitor_filters = esp32_exception_decoder
;monitor_speed = 115200
;
;build_flags =
; -DBOARD_HAS_PSRAM
; -mfix-esp32-psram-cache-issue
; ; These ensure the N16R8 uses the fast Octal (OPI) mode
; -DARDUINO_USB_CDC_ON_BOOT=1
; -DDEV_UNIT
; -DDEBUG
[env:s3-full]
platform = espressif32
board = 4d_systems_esp32s3_gen4_r8n16
framework = arduino
monitor_filters = esp32_exception_decoder
monitor_speed = 115200
[env:alt]
lib_deps =
TFT_eSPI
fbiego/ESP32Time@^2.0.6
electroniccats/MPU6050@^1.4.3
board_build.arduino.psram = enabled
board_upload.flash_size = 16MB
board_build.partitions = default_16MB.csv
board_build.flash_mode = dio
board_build.arduino.memory_type = dio_opi
build_flags =
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=0
-DDEV_UNIT
-DDISALLOW_SLEEP
-DDEBUG
upload_port = COM8
monitor_port = COM8
[env:s3-supermini]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
; Flash and PSRAM settings for 4MB Flash / 2MB PSRAM (Quad SPI)
board_upload.flash_size = 4MB
board_build.arduino.memory_type = qio_qspi
board_build.flash_mode = qio
board_build.psram_type = qio
; Required flag to enable PSRAM in code
build_flags =
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=1
-DARDUINO_USB_MODE=1
-DDISALLOW_SLEEP
-DDEV_UNIT
; Ensure partition table fits 4MB
board_build.partitions = default.csv
board_build.partitions = partitions_4MB.csv
lib_deps = TFT_eSPI, fbiego/ESP32Time@^2.0.6, electroniccats/MPU6050@^1.4.3
upload_port = COM5
monitor_port = COM5
+1 -1
View File
@@ -95,7 +95,7 @@ void animate_performAngryAnimation(TFT_eSprite &spr, struct SpriteData* spriteDa
}
void animate_performHatchingAnimation(TFT_eSprite &spr, struct SpriteData* spriteData) {
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesHappy;
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesHatching;
draw_drawSprite(
spr,
hatchingAnimationPositions[currentAnimationFrame],
+5 -2
View File
@@ -1,4 +1,5 @@
#include "defs/defs.h"
#include "defs/sounds.h"
#include "defs/chara_data.h"
#include "defs/screen_defs.h"
#include "buttons.h"
@@ -16,9 +17,11 @@ bool k4_prev = HIGH;
void buttons_checkInactivity() {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US && !screenOff) {
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US && !screenOff && !alwaysOnEnabled) {
#ifdef DISALLOW_SLEEP
digitalWrite(BL_PIN, LOW);
screenKey = OFF_SCREEN;
#endif
} else if (currentTime - lastPressedButtonTime > LAST_PRESSED_BUTTON_THRESHOLD_TIME_US && !inactive) {
screenKey = MAIN_SCREEN;
@@ -40,7 +43,7 @@ uint8_t buttons_getPressedButtons() {
);
if (retV != 0) {
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
sound_playMelody(SOUND_BUTTON_BEEP, SOUND_NOTE_COUNT(SOUND_BUTTON_BEEP));
lastPressedButtonTime = esp_timer_get_time();
inactive = false;
screenOff = false;
+2
View File
@@ -3,6 +3,8 @@
#include <stdint.h>
extern int currentBackground;
struct BackgroundData {
uint8_t backgroundWidth;
uint8_t backgroundHeight;
+17 -3
View File
@@ -40,9 +40,9 @@
// SPEAKER PINOUT
#define SPK_PIN 7
// MPU6050 PINOUT
#define MPU_SCL_PIN 9
#define MPU_SDA_PIN 8
// I2C PINOUT
#define I2C_SCL_PIN 9
#define I2C_SDA_PIN 8
// SPECIAL SCREEN THAT OPENS WHEN TIMERS ARE DONE
// RECEIVES AN EXTRA PARAMETER (INTERRUPTKEY)
@@ -125,6 +125,10 @@
// TRAINING MODES
#define TRAINING_SCREEN_1 30
// SETTINGS SUBSCREENS
#define BACKGROUND_CHANGE_SCREEN 40
#define RESET_DATA_SCREEN 41
// SMALL UI ICONS (UI.BIN)
#define POOP_ICON 0
#define FOOD_ICON 1
@@ -164,6 +168,8 @@
#define CHARA_COUNT_IN_DEVICE 5
#define SPRITE_SCALE 6
extern int screenKey;
extern int menuKey;
extern int submenuKey;
@@ -211,4 +217,12 @@ extern struct CharacterData* charaData;
extern struct SpriteData mainCharacterSprites;
extern bool isSamplingSteps;
extern uint64_t sampleStartTime;
extern uint16_t initialSteps;
// Settings screen options
extern bool soundEnabled;
extern bool alwaysOnEnabled;
#endif
+121
View File
@@ -0,0 +1,121 @@
#ifndef SOUNDS_H
#define SOUNDS_H
#include "defs/defs.h"
#include "sound/sound.h"
#define SOUND_NOTE_COUNT(melody) (sizeof(melody) / sizeof((melody)[0]))
static const Note SOUND_BUTTON_BEEP[] = {
{BEEP_FREQ_HZ, BEEP_LEN_MS},
};
static const Note SOUND_BOOT[] = {
{1800, 55},
{0, 20},
{2600, 55},
{0, 20},
{3400, 70},
{0, 35},
{4600, 95},
};
static const Note SOUND_CARE_ALERT[] = {
{1800, 80},
{0, 35},
{1800, 80},
{0, 35},
{5200, 120},
};
static const Note SOUND_HAPPY[] = {
{2200, 45},
{3300, 45},
{4400, 55},
{6600, 80},
{0, 25},
{5200, 60},
};
static const Note SOUND_ANGRY[] = {
{900, 70},
{0, 25},
{700, 90},
{0, 25},
{520, 150},
};
static const Note SOUND_POOP_DROP[] = {
{4200, 35},
{3200, 35},
{2200, 45},
{0, 25},
{900, 85},
};
static const Note SOUND_REFUSE[] = {
{2600, 70},
{0, 35},
{1500, 80},
{0, 30},
{900, 120},
};
static const Note SOUND_EVOLUTION_WOBBLE[] = {
{3200, 60},
{3900, 60},
{3000, 60},
{4300, 60},
{3400, 60},
{4700, 70},
};
static const Note SOUND_EVOLUTION_COMPLETE[] = {
{1600, 90},
{2200, 90},
{3000, 100},
{4000, 110},
{5200, 130},
{6400, 220},
{0, 60},
{5200, 100},
{6400, 180},
};
static const Note SOUND_TRAINING_START[] = {
{3100, 55},
{0, 25},
{4100, 85},
};
static const Note SOUND_TRAINING_ATTACK[] = {
{5200, 18},
{0, 8},
{4600, 18},
{0, 8},
{3900, 22},
{0, 12},
{3000, 28},
};
static const Note SOUND_HATCH[] = {
{2200, 45},
{0, 20},
{2600, 45},
{0, 20},
{3000, 45},
{0, 20},
{3400, 45},
{0, 20},
{3800, 50},
{0, 25},
{4300, 55},
{0, 30},
{5000, 75},
{0, 45},
{3600, 55},
{4300, 55},
{5200, 110},
};
#endif
+10 -2
View File
@@ -2,6 +2,8 @@
#include "defs/screen_defs.h"
#include "defs/defs.h"
#include <TFT_eSPI.h>
int xPos = 0;
int yPos = 0;
@@ -59,9 +61,15 @@ void tft_drawCenteredText(const char* text, int size, int yGlobal) {
composite.drawString(text, x, yGlobal);
}
void tft_drawText(const char* text, int size, int x, int y, uint16_t color) {
void tft_drawText(const char* text, int size, int x, int y, uint16_t color, uint16_t bgColor) {
composite.setTextSize(size);
composite.setTextColor(color);
if (bgColor != TFT_TRANSPARENT) {
composite.setTextColor(color, bgColor);
} else {
composite.setTextColor(color);
}
composite.drawString(text, x, y);
}
+1 -1
View File
@@ -12,7 +12,7 @@ void tft_drawBuffer();
void tft_clearBuffer(TFT_eSprite &buffer, uint16_t color = TFT_WHITE);
void tft_clearBuffer(uint16_t color = TFT_WHITE);
void tft_drawCenteredText(const char* text, int factor, int y);
void tft_drawText(const char* text, int size, int x, int y, uint16_t color = TFT_BLACK);
void tft_drawText(const char* text, int size, int x, int y, uint16_t color = TFT_BLACK, uint16_t bgColor = TFT_TRANSPARENT);
void tft_drawRectangle(int x, int y, int w, int h, uint16_t color = TFT_BLACK);
#endif
-1
View File
@@ -2,6 +2,5 @@
#define ENERGY_H
void energy_startLightSleep();
void energy_setUpLightSleep();
#endif
+39 -15
View File
@@ -1,5 +1,7 @@
#include "energy.h"
#include <Arduino.h>
#include <esp_sleep.h>
#include <driver/gpio.h>
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sprite_data.h"
@@ -11,14 +13,27 @@
#define SLEEP_TIME_US 60000000ull // 60 seconds periodic wakeup
void energy_setUpLightSleep() {
// Left as a placeholder for backward compatibility
}
void energy_startLightSleep() {
printf("[ENERGY] Entering light sleep...\n");
// 1. Configure wake-up sources
// Keep RTC peripherals powered on during sleep so internal pullups/pulldowns stay active
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
// EXT1 wakeup uses the RTC IO subsystem. We must explicitly configure the RTC pull resistors
// so the pins do not float and cause immediate wake-ups.
// NOTE: We must initialize the pins as RTC GPIOs using rtc_gpio_init() first!
#if BUTTON_MODE == INPUT_PULLUP
rtc_gpio_init((gpio_num_t)K1_PIN); rtc_gpio_pullup_en((gpio_num_t)K1_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K1_PIN);
rtc_gpio_init((gpio_num_t)K2_PIN); rtc_gpio_pullup_en((gpio_num_t)K2_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K2_PIN);
rtc_gpio_init((gpio_num_t)K3_PIN); rtc_gpio_pullup_en((gpio_num_t)K3_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K3_PIN);
rtc_gpio_init((gpio_num_t)K4_PIN); rtc_gpio_pullup_en((gpio_num_t)K4_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K4_PIN);
#else
rtc_gpio_init((gpio_num_t)K1_PIN); rtc_gpio_pulldown_en((gpio_num_t)K1_PIN); rtc_gpio_pullup_dis((gpio_num_t)K1_PIN);
rtc_gpio_init((gpio_num_t)K2_PIN); rtc_gpio_pulldown_en((gpio_num_t)K2_PIN); rtc_gpio_pullup_dis((gpio_num_t)K2_PIN);
rtc_gpio_init((gpio_num_t)K3_PIN); rtc_gpio_pulldown_en((gpio_num_t)K3_PIN); rtc_gpio_pullup_dis((gpio_num_t)K3_PIN);
rtc_gpio_init((gpio_num_t)K4_PIN); rtc_gpio_pulldown_en((gpio_num_t)K4_PIN); rtc_gpio_pullup_dis((gpio_num_t)K4_PIN);
#endif
esp_sleep_enable_timer_wakeup(SLEEP_TIME_US);
uint64_t mask = (1ULL << K1_PIN) | (1ULL << K2_PIN) | (1ULL << K3_PIN) | (1ULL << K4_PIN);
@@ -32,18 +47,24 @@ void energy_startLightSleep() {
esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ANY_HIGH);
#endif
// 2. Start light sleep (powers down CPU core and clocks, keeps RAM and state)
digitalWrite(48, LOW);
esp_light_sleep_start();
// 3. Woken up! Let's check why
digitalWrite(48, HIGH);
// Release the pins from RTC control after waking up so digitalRead works normally
rtc_gpio_deinit((gpio_num_t)K1_PIN);
rtc_gpio_deinit((gpio_num_t)K2_PIN);
rtc_gpio_deinit((gpio_num_t)K3_PIN);
rtc_gpio_deinit((gpio_num_t)K4_PIN);
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
printf("[ENERGY] Woken up. Cause: %d\n", cause);
// 4. Force immediate simulation update
runVpetTasks = true;
vpet_runVpetTasks();
// 5. Evaluate the current character's state to see if any alert/event was triggered
if (cause == ESP_SLEEP_WAKEUP_TIMER) {
bool hasAlert = (
charaData[currentCharacter].hunger == 0 ||
@@ -53,8 +74,7 @@ void energy_startLightSleep() {
);
if (hasAlert) {
// Wake up display and backlight to notify the user
printf("[ENERGY] Periodic wakeup triggered a critical alert! Waking up completely.\n");
printf("[ENERGY] Periodic wakeup triggered, maybe care mistake.\n");
digitalWrite(BL_PIN, HIGH);
screenOff = false;
inactive = false;
@@ -62,16 +82,20 @@ void energy_startLightSleep() {
screenKey = TIMER_FINISHED_SCREEN;
}
} else {
// Background checkpoint save, then let the loop put the CPU back to sleep
printf("[ENERGY] Periodic simulation update successful. No alerts. Saving state...\n");
printf("[ENERGY] Periodic wake up triggered, no alerts. Sampling steps...\n");
isSamplingSteps = true;
sampleStartTime = esp_timer_get_time();
initialSteps = stepCounter;
storage_saveState();
}
} else if (cause == ESP_SLEEP_WAKEUP_EXT1) {
// Woken up by a user button press
printf("[ENERGY] User button press detected. Restoring UI...\n");
printf("[ENERGY] User button press detected.\n");
digitalWrite(BL_PIN, HIGH);
screenOff = false;
inactive = false;
screenKey = MAIN_SCREEN;
} else {
// Fallback for other wake-up causes to prevent high-speed loop thrashing
delay(200);
}
}
+65 -5
View File
@@ -15,6 +15,8 @@
#include "driver/rtc_io.h"
#include "loop/loop.h"
#include "menu/training/training_screens.h"
#include "defs/sounds.h"
#include "sound/sound.h"
const char* TAG = "[MAIN]";
@@ -61,29 +63,50 @@ uint32_t dayUnixTime = 0;
Egg_t* eggSelection = NULL;
uint8_t eggNumber = 0;
// Background stuff
int currentBackground = 0;
// Tasks
TaskHandle_t secondLoop = NULL;
// Settings
bool soundEnabled = true;
bool alwaysOnEnabled = false;
// Background step counting
bool isSamplingSteps = false;
uint64_t sampleStartTime = 0;
uint16_t initialSteps = 0;
void loop2();
void secondCoreTask(void*);
void setup() {
Serial.begin(115200);
while (!Serial) { }
//delay(10000);
//Wire.begin(MPU_SDA_PIN, MPU_SCL_PIN); // I2C init before MPU6050
//mpu.initialize();
pinMode(48, OUTPUT);
digitalWrite(48, HIGH);
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); // I2C init before MPU6050
mpu.initialize();
tft_initDisplay(tft, TFT_BLACK);
tft_initScreenBuffer(TFT_TRANSPARENT);
tft.setRotation(2);
sound_init();
storage_init();
storage_readFile("/menu.bin", &menuElementsData);
storage_readFile("/ui.bin", &uiElementsData);
storage_initBackground("/bg2.bin", bg);
storage_initBackground(currentBackground, bg);
pinMode(K1_PIN, BUTTON_MODE);
pinMode(K2_PIN, BUTTON_MODE);
@@ -92,6 +115,8 @@ void setup() {
xTaskCreatePinnedToCore(secondCoreTask, "VPET_EVAL", 4096, NULL, 0, &secondLoop, 0);
sound_playMelody(SOUND_BOOT, SOUND_NOTE_COUNT(SOUND_BOOT));
lines_initLineStorage();
storage_loadState();
@@ -204,10 +229,22 @@ void loop() {
case FROZEN_SCREEN:
menu_drawFridgeScreen(bg, sprite, &mainCharacterSprites, &menuElementsData);
break;
case SETTINGS_SCREEN:
menu_settingsScreen(bg, sprite, &uiElementsData);
break;
case BACKGROUND_CHANGE_SCREEN:
menu_changeBackgroundScreen(bg, sprite, &uiElementsData);
break;
case RESET_DATA_SCREEN:
menu_resetDataScreen(bg);
break;
}
if (screenKey == IDLE_SCREEN || screenKey == OFF_SCREEN) {
//steps_countSteps();
steps_countSteps();
}
}
@@ -218,7 +255,30 @@ void loop2() {
getLocalTime(&timeInfo, 50);
dayUnixTime = mktime(&timeInfo) % SECONDS_IN_DAY;
if (screenOff) { energy_startLightSleep(); }
if (screenOff) {
if (isSamplingSteps) {
uint64_t currentTime = esp_timer_get_time();
if ((currentTime - sampleStartTime) > 10000000) {
isSamplingSteps = false;
uint16_t sampledSteps = stepCounter - initialSteps;
uint16_t approximatedSteps = sampledSteps * 6;
stepCounter += approximatedSteps;
printf("[STEPS] Sampled %d steps in 10s, added %d approximated steps for sleep period.\n", sampledSteps, approximatedSteps);
energy_startLightSleep();
}
} else {
energy_startLightSleep();
}
} else {
isSamplingSteps = false;
}
sound_update();
}
void secondCoreTask(void*) {
+24 -28
View File
@@ -4,43 +4,39 @@
#include "display/display.h"
#include "draw/draw.h"
#include "animations/animations.h"
#include "defs/sounds.h"
void menu_drawAngryScreen(
TFT_eSprite& bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements
) {
uint8_t frameCounter = 0;
static uint8_t frameCounter = 0;
while (true) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
if (frameCounter > 3) {
screenKey = MAIN_SCREEN; // TODO: Change for while battling
menuKey = STATUS_SCREEN;
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
if (frameCounter > 3) {
frameCounter = 0;
screenKey = MAIN_SCREEN; // TODO: Change for while battling
menuKey = STATUS_SCREEN;
vTaskResume(secondLoop);
return;
}
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
animate_performAngryAnimation(sprite, spriteData);
if (frameCounter % 2 == 0) {
tone(SPK_PIN, 1000, 100);
tone(SPK_PIN, 1000, 200);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
}
frameCounter++;
lastUpdateTime = currentTime;
return;
}
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
animate_performAngryAnimation(sprite, spriteData);
if (frameCounter % 2 == 0) {
sound_playMelody(SOUND_ANGRY, SOUND_NOTE_COUNT(SOUND_ANGRY));
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
}
frameCounter++;
lastUpdateTime = currentTime;
tft_drawBuffer();
}
}
+2 -2
View File
@@ -3,6 +3,7 @@
#include "animations/animations.h"
#include "display/display.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "draw/draw.h"
uint64_t lastBeepTime = esp_timer_get_time();
@@ -13,8 +14,7 @@ void menu_careMistakeScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteD
uint8_t pressedButtons = buttons_getPressedButtons();
if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) {
tone(SPK_PIN, 2500, 100);
tone(SPK_PIN, 5000, 100);
sound_playMelody(SOUND_CARE_ALERT, SOUND_NOTE_COUNT(SOUND_CARE_ALERT));
lastBeepTime = currentTime;
+108 -50
View File
@@ -2,17 +2,22 @@
#include "draw/draw.h"
#include "display/display.h"
#include "defs/screen_defs.h"
#include "defs/sounds.h"
#include "vpet/evolution/evolution.h"
#include "loop/loop.h"
struct SpriteData* checkerboardPattern;
void menu_createCheckerboard() {
if (checkerboardPattern != NULL) {
return;
}
const uint8_t SCALE = 6;
const uint8_t logicalW = 34;
const uint8_t logicalH = 1;
const uint16_t scaledW = logicalW * SCALE; // 204
const uint16_t scaledH = logicalH * SCALE; // 6
const uint16_t scaledW = logicalW * SCALE;
const uint16_t scaledH = logicalH * SCALE;
const uint32_t bufferSize = scaledW * scaledH;
checkerboardPattern = (SpriteData*) malloc(sizeof(SpriteData));
@@ -36,126 +41,178 @@ void menu_createCheckerboard() {
}
void menu_freeCheckerboard() {
if (checkerboardPattern == NULL) {
return;
}
free(checkerboardPattern->spriteData[0]);
free(checkerboardPattern->spriteData);
free(checkerboardPattern);
checkerboardPattern = NULL;
}
// Don't worry, I hate this too
void menu_evolutionScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* mainCharacterSprites) {
menu_createCheckerboard();
TFT_eSprite checkerboard = TFT_eSprite(&tft);
enum EvolutionPhase {
EVOLUTION_INIT,
EVOLUTION_WOBBLE,
EVOLUTION_RED_FILL,
EVOLUTION_BLACK_FILL,
EVOLUTION_APPLY_CHANGE,
EVOLUTION_GREEN_REVEAL,
EVOLUTION_FINAL_REVEAL,
EVOLUTION_DONE
};
bool checkerboardShift = false;
static EvolutionPhase phase = EVOLUTION_INIT;
static TFT_eSprite checkerboard = TFT_eSprite(&tft);
static bool checkerboardShift = false;
static int frameIndex = 0;
tft_clearBuffer(sprite, TFT_TRANSPARENT);
sound_update();
for (int i = 0; i < 5;) {
uint64_t currentTime = esp_timer_get_time();
uint64_t currentTime = esp_timer_get_time();
if (phase == EVOLUTION_INIT) {
menu_createCheckerboard();
checkerboardShift = false;
frameIndex = 0;
tft_clearBuffer(sprite, TFT_TRANSPARENT);
lastUpdateTime = 0;
phase = EVOLUTION_WOBBLE;
return;
}
if (phase == EVOLUTION_WOBBLE) {
if (frameIndex >= 5) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
frameIndex = 0;
lastUpdateTime = 0;
phase = EVOLUTION_RED_FILL;
return;
}
if (currentTime - lastUpdateTime > 500000) {
tone(SPK_PIN, 4100, 50);
tone(SPK_PIN, 3500, 50);
sound_playMelody(SOUND_EVOLUTION_WOBBLE, SOUND_NOTE_COUNT(SOUND_EVOLUTION_WOBBLE));
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72 + ((i % 2 == 0) * 6), 72, mainCharacterSprites, 6);
draw_drawSprite(sprite, 72 + ((frameIndex % 2 == 0) * 6), 72, mainCharacterSprites, 6);
tft_drawBuffer();
i++;
frameIndex++;
lastUpdateTime = currentTime;
}
return;
}
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7);
if (phase == EVOLUTION_RED_FILL) {
if (frameIndex >= 16) {
frameIndex = 0;
lastUpdateTime = 0;
phase = EVOLUTION_BLACK_FILL;
return;
}
tft_clearBuffer(sprite, TFT_TRANSPARENT);
for (int i = 0; i < 16;) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6);
uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_RED);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift);
tft_drawBuffer();
checkerboardShift = !checkerboardShift;
i++;
frameIndex++;
lastUpdateTime = currentTime;
}
return;
}
for (int i = 0; i < 16;) {
uint64_t currentTime = esp_timer_get_time();
if (phase == EVOLUTION_BLACK_FILL) {
if (frameIndex >= 16) {
frameIndex = 15;
lastUpdateTime = 0;
phase = EVOLUTION_APPLY_CHANGE;
return;
}
if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6);
uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_BLACK);
tft_drawBuffer();
checkerboardShift = !checkerboardShift;
i++;
frameIndex++;
lastUpdateTime = currentTime;
}
return;
}
change_onChangeComplete();
if (phase == EVOLUTION_APPLY_CHANGE) {
change_onChangeComplete();
lastUpdateTime = 0;
phase = EVOLUTION_GREEN_REVEAL;
return;
}
if (phase == EVOLUTION_GREEN_REVEAL) {
if (frameIndex < 0) {
frameIndex = 15;
lastUpdateTime = 0;
phase = EVOLUTION_FINAL_REVEAL;
return;
}
for (int i = 15; i >= 0;) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6);
uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_GREEN);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift);
tft_drawBuffer();
checkerboardShift = !checkerboardShift;
i--;
frameIndex--;
lastUpdateTime = currentTime;
}
return;
}
for (int i = 15; i >= 0;) {
uint64_t currentTime = esp_timer_get_time();
if (phase == EVOLUTION_FINAL_REVEAL) {
if (frameIndex < 0) {
phase = EVOLUTION_DONE;
return;
}
if (currentTime - lastUpdateTime > 100000) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7);
uint8_t rectHeight = (6 * i);
uint8_t rectHeight = 6 * frameIndex;
tft_drawRectangle(18, 72, 204, rectHeight, TFT_GREEN);
for (int j = 0; j < i; j++) {
for (int j = 0; j < frameIndex; j++) {
uint8_t rectYPos = 72 + (6 * j);
draw_drawSprite(checkerboard, 18, rectYPos, checkerboardPattern, 0, checkerboardShift);
checkerboardShift = !checkerboardShift;
}
tft_drawBuffer();
i--;
frameIndex--;
lastUpdateTime = currentTime;
}
return;
}
tone(SPK_PIN, 2100, 100);
tone(SPK_PIN, 3500, 100);
tone(SPK_PIN, 4100, 100);
tone(SPK_PIN, 4650, 200);
sound_playMelody(SOUND_EVOLUTION_COMPLETE, SOUND_NOTE_COUNT(SOUND_EVOLUTION_COMPLETE));
lastPressedButtonTime = esp_timer_get_time();
@@ -163,7 +220,8 @@ void menu_evolutionScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteDat
vTaskResume(secondLoop);
phase = EVOLUTION_INIT;
screenKey = MAIN_SCREEN;
lastUpdateTime = 0; // Un pequeño empujoncito
lastUpdateTime = 0;
}
+91
View File
@@ -0,0 +1,91 @@
#include "menu.h"
#include "defs/sprite_data.h"
#include "buttons/buttons.h"
#include "draw/draw.h"
#include "storage/storage.h"
#include "display/display.h"
#include "defs/screen_defs.h"
void menu_changeBackgroundScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSpriteData
) {
static bool initialized = false;
static int8_t selectedBackground = 0;
static int8_t selectedPreviousBackground = -1;
static uint8_t backgrounds = 0;
static uint64_t screenLastActionTime = 0;
uint64_t currentTime = esp_timer_get_time();
if (!initialized) {
fs::File bgFolder = SPIFFS.open("/bg");
fs::File background = bgFolder.openNextFile();
backgrounds = 0;
while (background) {
if (!background.isDirectory()) {
backgrounds++;
}
background = bgFolder.openNextFile();
}
selectedBackground = currentBackground;
selectedPreviousBackground = -1;
screenLastActionTime = currentTime;
initialized = true;
printf("[BACKGROUNDS] numBackgrounds=%i\n", backgrounds);
}
uint8_t buttonsPressed = buttons_getPressedButtons();
switch (buttonsPressed) {
case K1_PRESSED:
selectedBackground--;
if (selectedBackground < 0) {
selectedBackground = backgrounds - 1;
}
storage_initBackground(selectedBackground, bg);
screenLastActionTime = currentTime;
break;
case K2_PRESSED:
selectedBackground++;
if (selectedBackground >= backgrounds) {
selectedBackground = 0;
}
storage_initBackground(selectedBackground, bg);
screenLastActionTime = currentTime;
break;
case K3_PRESSED:
currentBackground = selectedBackground;
initialized = false;
screenKey = MAIN_SCREEN;
return;
case K4_PRESSED:
storage_initBackground(currentBackground, bg);
initialized = false;
screenKey = MAIN_SCREEN;
return;
default:
break;
}
if (selectedPreviousBackground != selectedBackground) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON);
tft_drawBuffer();
selectedPreviousBackground = selectedBackground;
}
if (currentTime - screenLastActionTime > INACTIVITY_THRESHOLD_TIME_US) {
printf("[BACKGROUND] Returning home cuz yes\n");
storage_initBackground(currentBackground, bg);
initialized = false;
screenKey = MAIN_SCREEN;
}
}
+71 -65
View File
@@ -9,83 +9,89 @@
void menu_changeCharaScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* mainSpriteData, struct SpriteData* uiSpriteData) {
vTaskSuspend(secondLoop);
static bool initialized = false;
static uint8_t selectedChara = 0;
static CharacterData* selectedCharaData = NULL;
static bool updateScreen = true;
uint8_t selectedChara = currentCharacter;
CharacterData* selectedCharaData = &charaData[selectedChara];
if (!initialized) {
selectedChara = currentCharacter;
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
initialized = true;
}
bool updateScreen = true;
for (;;) {
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
selectedChara++;
if (selectedChara >= CHARA_COUNT_IN_DEVICE) {
selectedChara = 0;
}
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
break;
case K2_PRESSED:
currentCharacter = selectedChara;
vTaskResume(secondLoop);
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
break;
case K3_PRESSED:
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(fileName, mainSpriteData);
vTaskResume(secondLoop);
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
break;
default:
break;
}
delay(15);
if (updateScreen) {
draw_drawBackground(bg, 90, 90, 3);
if (selectedCharaData->hatched) {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", selectedCharaData->idChara);
storage_readFile(fileName, mainSpriteData);
draw_drawSprite(sprite, 18, 72, mainSpriteData, 0);
} else {
tft_drawCenteredText("EMPTY", 4, 120);
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
selectedChara--;
if (selectedChara < 0) {
selectedChara = CHARA_COUNT_IN_DEVICE - 1;
}
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
break;
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON);
case K2_PRESSED:
selectedChara++;
if (selectedChara >= CHARA_COUNT_IN_DEVICE) {
selectedChara = 0;
}
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
break;
tft_drawBuffer();
case K3_PRESSED:
currentCharacter = selectedChara;
initialized = false;
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
updateScreen = false;
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US) {
case K4_PRESSED: {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(fileName, mainSpriteData);
vTaskResume(secondLoop);
initialized = false;
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
}
default:
break;
}
if (updateScreen) {
draw_drawBackground(bg, 90, 90, 3);
if (selectedCharaData->hatched) {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", selectedCharaData->idChara);
storage_readFile(fileName, mainSpriteData);
draw_drawSprite(sprite, 18, 72, mainSpriteData, 0);
} else {
tft_drawCenteredText("EMPTY", 4, 120);
}
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON);
tft_drawBuffer();
updateScreen = false;
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US) {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(fileName, mainSpriteData);
initialized = false;
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
}
}
+8 -1
View File
@@ -9,7 +9,14 @@
void menu_drawClock(TFT_eSprite& bg) {
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K2_PRESSED | K3_PRESSED:
screenKey = CLOCK_EDIT_SCREEN;
break;
case K1_PRESSED:
case K2_PRESSED:
case K3_PRESSED:
case K4_PRESSED:
draw_drawBackground(bg, 90, 90, 3);
screenKey = MAIN_SCREEN;
break;
@@ -48,7 +55,7 @@ void menu_drawClockEdit(TFT_eSprite& bg) {
clockMinuteCount = (clockMinuteCount + 1) % 60;
break;
case K3_PRESSED:
case K4_PRESSED:
// Es un dia random, nada significativo, ya pondre mas adelante que tenga dia del año
rtc.setTime(0, clockMinuteCount, clockHourCount, 1, 11, 2024);
srand(time(NULL));
+4 -3
View File
@@ -12,18 +12,19 @@ void menu_drawDeathScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteDat
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
case K4_PRESSED:
lines_getAvailableLines();
screenKey = EGG_SELECT_SCREEN;
return;
break;
case K2_PRESSED:
case K3_PRESSED:
screenKey = CLOCK_SCREEN;
return;
break;
case K3_PRESSED:
case K1_PRESSED:
case K2_PRESSED:
lastUpdateTime = currentTime;
frameCounter = 0;
+63 -30
View File
@@ -8,14 +8,28 @@
#include "animations/animations.h"
#include "vpet/vpet/vpet.h"
#include "vpet/lines/lines.h"
#include "defs/sounds.h"
const uint64_t HATCH_ANIMATION_FRAME_TIME_US = 100000;
const uint64_t HATCH_COMPLETE_HOLD_TIME_US = 2000000;
void menu_eggHatchScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* uiBigSprite, struct SpriteData* uiSmallSprite) {
static bool eggSpriteFrame = false;
static bool hatchSoundStarted = false;
static uint8_t hatchingFrame = 0;
static uint64_t hatchHoldStartTime = 0;
static uint64_t hatchAnimationLastFrameTime = 0;
sound_update();
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K2_PRESSED:
screenKey = CLOCK_SCREEN;
hatchSoundStarted = false;
hatchingFrame = 0;
hatchHoldStartTime = 0;
hatchAnimationLastFrameTime = 0;
break;
default:
@@ -23,39 +37,58 @@ void menu_eggHatchScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
if (charaData[currentCharacter].hatchTimer <= currentLine[currentCharacter]->hatchTime) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, eggSpriteFrame);
eggSpriteFrame = !eggSpriteFrame;
lastUpdateTime = currentTime;
tft_drawBuffer();
} else if (charaData[currentCharacter].hatchTimer > currentLine[currentCharacter]->hatchTime && !charaData[currentCharacter].hatched) {
for (int i = 0; i < 30; i++) {
tone(SPK_PIN, 4100, 35);
tone(SPK_PIN, 3500, 35);
draw_drawBackground(bg, 90, 90, 3);
animate_performHatchingAnimation(sprite, &currentEgg->eggSprite);
tft_drawBuffer();
}
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, 2);
tft_drawBuffer();
delay(2000);
if (hatchHoldStartTime > 0) {
if (currentTime - hatchHoldStartTime > HATCH_COMPLETE_HOLD_TIME_US) {
hatchHoldStartTime = 0;
hatchSoundStarted = false;
hatchingFrame = 0;
hatchAnimationLastFrameTime = 0;
lines_onHatchComplete();
}
return;
}
if (charaData[currentCharacter].hatchTimer > currentLine[currentCharacter]->hatchTime && !charaData[currentCharacter].hatched) {
if (!hatchSoundStarted) {
sound_playMelody(SOUND_HATCH, SOUND_NOTE_COUNT(SOUND_HATCH));
hatchSoundStarted = true;
hatchAnimationLastFrameTime = 0;
}
if (hatchingFrame < 30 && currentTime - hatchAnimationLastFrameTime > HATCH_ANIMATION_FRAME_TIME_US) {
draw_drawBackground(bg, 90, 90, 3);
animate_performHatchingAnimation(sprite, &currentEgg->eggSprite);
tft_drawBuffer();
hatchingFrame++;
hatchAnimationLastFrameTime = currentTime;
return;
}
if (hatchingFrame < 30) {
return;
}
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, 2);
tft_drawBuffer();
hatchHoldStartTime = currentTime;
return;
}
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, eggSpriteFrame);
eggSpriteFrame = !eggSpriteFrame;
lastUpdateTime = currentTime;
tft_drawBuffer();
}
}
+5 -1
View File
@@ -15,10 +15,14 @@ void menu_lineSwitcher(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData*
uint8_t buttonsPressed = buttons_getPressedButtons();
switch(buttonsPressed) {
case K1_PRESSED:
eggCounter = (eggCounter + 1) % eggNumber;
eggCounter = (eggCounter - 1) % eggNumber;
break;
case K2_PRESSED:
eggCounter = (eggCounter + 1) % eggNumber;
break;
case K4_PRESSED:
menu_reloadEggs(eggCounter);
eggCounter = 0;
screenKey = EGG_HATCH_SCREEN;
+25 -13
View File
@@ -3,36 +3,48 @@
#include "display/display.h"
#include "draw/draw.h"
#include "menu.h"
#include "defs/sounds.h"
#include "vpet/vpet/vpet.h"
void menu_foodScreen(TFT_eSprite &bg, TFT_eSprite &mainChara,
struct SpriteData *spriteData) {
if (charaData[currentCharacter].sleepy) {
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
delay(100);
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
sound_playMelody(SOUND_BUTTON_BEEP, SOUND_NOTE_COUNT(SOUND_BUTTON_BEEP));
screenKey = MENU_SCREEN;
return;
}
static uint8_t arrowPosition = 0;
static int8_t arrowPosition = 0;
const int numItems = 2;
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 8:
arrowPosition = (arrowPosition + 1) % 2;
break;
case K1_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition--;
if (arrowPosition < 0) {
arrowPosition = numItems - 1;
}
break;
case 2:
screenKey = MENU_SCREEN;
break;
case K2_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition++;
if (arrowPosition >= numItems) {
arrowPosition = 0;
}
break;
default:
break;
case K3_PRESSED:
screenKey = MENU_SCREEN;
break;
default:
break;
}
if (pressedButtons == 4) {
if (pressedButtons == K4_PRESSED) {
lastUpdateTime = 0;
switch (arrowPosition) {
case 0:
+2 -1
View File
@@ -7,11 +7,12 @@ void menu_drawFridgeScreen(TFT_eSprite &bg, TFT_eSprite& sprite, struct SpriteDa
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
menuKey = STATUS_SCREEN_MENU;
break;
case K2_PRESSED:
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
+24 -28
View File
@@ -4,43 +4,39 @@
#include "display/display.h"
#include "draw/draw.h"
#include "animations/animations.h"
#include "defs/sounds.h"
void menu_drawHappyScreen(
TFT_eSprite& bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements, const int returnScreen
) {
uint8_t frameCounter = 0;
static uint8_t frameCounter = 0;
while (true) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
if (frameCounter > 3) {
screenKey = returnScreen; // TODO: Change for while battling
menuKey = STATUS_SCREEN;
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
if (frameCounter > 3) {
frameCounter = 0;
screenKey = returnScreen; // TODO: Change for while battling
menuKey = STATUS_SCREEN;
return;
}
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
animate_performHappyAnimation(sprite, spriteData);
if (frameCounter % 2 == 0) {
tone(SPK_PIN, 7500, 50);
tone(SPK_PIN, 5000, 50);
tone(SPK_PIN, 2500, 50);
tone(SPK_PIN, 1000, 50);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
}
frameCounter++;
lastUpdateTime = currentTime;
return;
}
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
animate_performHappyAnimation(sprite, spriteData);
if (frameCounter % 2 == 0) {
sound_playMelody(SOUND_HAPPY, SOUND_NOTE_COUNT(SOUND_HAPPY));
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
}
frameCounter++;
lastUpdateTime = currentTime;
tft_drawBuffer();
}
}
+2 -1
View File
@@ -12,11 +12,12 @@ void menu_drawIdleScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
menuKey = STATUS_SCREEN_MENU;
break;
case K2_PRESSED:
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
+6 -1
View File
@@ -53,11 +53,16 @@ void menu_drawAngryScreen(
struct SpriteData* spriteData, struct SpriteData* smallUiElements
);
void menu_drawFridgeScreen(TFT_eSprite &bg, TFT_eSprite& sprite, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements);
void training_screenTraining2(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
);
void menu_changeBackgroundScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSpriteData
);
void menu_settingsScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData *spriteData);
void menu_settingsScreen_drawEntry(uint8_t entryId, const char *textEntry);
void menu_resetDataScreen(TFT_eSprite &bg);
void menu_sleepScreen_sleepAction();
void menu_sleepScreen_recalculateSleep();
+17 -1
View File
@@ -22,6 +22,13 @@ void menu_drawCurrentMenuOption(TFT_eSprite& bg, TFT_eSprite &icon, struct Sprit
menuKey++;
break;
case K2_PRESSED:
menuKey--;
if (menuKey < 0) {
menuKey = FREEZE_SCREEN_MENU;
}
break;
case K3_PRESSED:
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN_MENU;
@@ -33,7 +40,10 @@ void menu_drawCurrentMenuOption(TFT_eSprite& bg, TFT_eSprite &icon, struct Sprit
}
// Separaíto mas guapito
if (pressedButtons == K2_PRESSED) {
if (pressedButtons == K4_PRESSED) {
const uint64_t currentTime = esp_timer_get_time();
lastUpdateTime = currentTime;
switch (menuKey) {
case STATUS_SCREEN_MENU:
screenKey = STATUS_SCREEN;
@@ -73,6 +83,12 @@ void menu_drawCurrentMenuOption(TFT_eSprite& bg, TFT_eSprite &icon, struct Sprit
return;
break;
case SETTINGS_SCREEN_MENU:
menuKey = STATUS_SCREEN;
screenKey = SETTINGS_SCREEN;
return;
break;
default:
break;
}
+22 -27
View File
@@ -9,34 +9,34 @@
void menu_clearPoopScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements
) {
printf("[AAAAAAA] pausing loop...\n");
static bool initialized = false;
static int cleanerXPos = 174;
vTaskSuspend(secondLoop);
if (!initialized) {
cleanerXPos = 174;
lastUpdateTime = 0;
printf("[AAAAAAA] loop paused...\n");
draw_drawBackground(bg, 90, 90, 3);
uint8_t offsetX = menu_poopOverlay(bg, sprite, smallUiElements);
int cleanerXPos = 174;
animate_performAnimation(sprite, spriteData, offsetX);
menu_uiOverlay(sprite, bigUiElements);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
lastUpdateTime = 0;
initialized = true;
}
printf("[AAAAAAA] drawing idle screen...\n");
if (cleanerXPos <= 18 - 48) {
screenKey = HAPPY_SCREEN;
menuKey = -1;
charaData[currentCharacter].poopNumber = 0;
initialized = false;
draw_drawBackground(bg, 90, 90, 3);
uint8_t offsetX = menu_poopOverlay(bg, sprite, smallUiElements);
return;
}
printf("[AAAAAAA] drawing animation...\n");
animate_performAnimation(sprite, spriteData, offsetX);
printf("[AAAAAAA] drawing overlay...\n");
menu_uiOverlay(sprite, bigUiElements);
printf("[AAAAAAA] idle screen down...\n");
tft_clearBuffer(sprite, TFT_TRANSPARENT);
while (cleanerXPos > 18 - 48) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 50000) {
draw_drawBackgroundSection(bg, cleanerXPos + 6, 72, 48, 96);
draw_drawSprite(sprite, cleanerXPos, 72, smallUiElements, CLEANER_ICON);
@@ -47,11 +47,6 @@ void menu_clearPoopScreen(
tft_drawBuffer();
cleanerXPos -= 6;
lastUpdateTime = currentTime;
}
screenKey = HAPPY_SCREEN;
menuKey = -1;
charaData[currentCharacter].poopNumber = 0;
return;
}
+50 -56
View File
@@ -4,78 +4,72 @@
#include "display/display.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
void menu_poopScreen(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements
) {
uint8_t animationFrame = 0;
bool animationPosition = 0;
static uint8_t animationFrame = 0;
static bool animationPosition = 0;
static bool beepedAlready = false;
bool beepedAlready = false;
uint64_t currentTime = esp_timer_get_time();
while (1) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 4) {
draw_drawBackground(bg, 90, 90, 3);
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 4) {
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72 + (animationPosition * 6), 72, spriteData, 6);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72 + (animationPosition * 6), 72, spriteData, 6);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
animationFrame++;
animationPosition = !animationPosition;
animationFrame++;
animationPosition = !animationPosition;
lastUpdateTime = currentTime;
tft_drawBuffer();
lastUpdateTime = currentTime;
} else if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 6) {
if (!beepedAlready) {
sound_playMelody(SOUND_POOP_DROP, SOUND_NOTE_COUNT(SOUND_POOP_DROP));
} else if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 6) {
if (!beepedAlready) {
tone(SPK_PIN, 2500, 50);
tone(SPK_PIN, 5000, 50);
tone(SPK_PIN, 2500, 50);
tone(SPK_PIN, 5000, 50);
beepedAlready = true;
}
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 174, 120, smallUiElements, POOP_ICON);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72, 72, spriteData, 7);
animationFrame++;
animationPosition = !animationPosition;
lastUpdateTime = currentTime;
} else if (animationFrame >= 6) {
if (
(charaData[currentCharacter].hunger == 0 && !charaData[currentCharacter].hungerCareMistakeObtained) ||
(charaData[currentCharacter].strength == 0 && !charaData[currentCharacter].strengthCareMistakeObtained) ||
(charaData[currentCharacter].sleepy && !charaData[currentCharacter].asleep && !charaData[currentCharacter].sleepCareMistakeObtained)
) {
screenKey = CARE_MISTAKE_SCREEN;
} else {
screenKey = MAIN_SCREEN;
}
menuKey = -1;
animationFrame = 0;
animationPosition = 0;
break;
beepedAlready = true;
}
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 174, 120, smallUiElements, POOP_ICON);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72, 72, spriteData, 7);
animationFrame++;
animationPosition = !animationPosition;
lastUpdateTime = currentTime;
tft_drawBuffer();
} else if (animationFrame >= 6) {
if (
(charaData[currentCharacter].hunger == 0 && !charaData[currentCharacter].hungerCareMistakeObtained) ||
(charaData[currentCharacter].strength == 0 && !charaData[currentCharacter].strengthCareMistakeObtained) ||
(charaData[currentCharacter].sleepy && !charaData[currentCharacter].asleep && !charaData[currentCharacter].sleepCareMistakeObtained)
) {
screenKey = CARE_MISTAKE_SCREEN;
} else {
screenKey = MAIN_SCREEN;
}
menuKey = -1;
animationFrame = 0;
animationPosition = 0;
beepedAlready = false;
}
}
+6 -4
View File
@@ -3,6 +3,7 @@
#include "draw/draw.h"
#include "display/display.h"
#include "defs/defs.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
#include "animations/animations.h"
@@ -13,8 +14,10 @@ void menu_refuseScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteDat
uint64_t currentTime = esp_timer_get_time();
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 8:
case 4:
case K1_PRESSED:
case K2_PRESSED:
case K3_PRESSED:
case K4_PRESSED:
currentAnimationFrame = 0;
screenKey = FOOD_SCREEN;
soundPlayed = false;
@@ -34,8 +37,7 @@ void menu_refuseScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteDat
}
if (!soundPlayed) {
tone(SPK_PIN, 3000, 100);
tone(SPK_PIN, 1000, 100);
sound_playMelody(SOUND_REFUSE, SOUND_NOTE_COUNT(SOUND_REFUSE));
soundPlayed = true;
}
+69
View File
@@ -0,0 +1,69 @@
#include <Arduino.h>
#include "buttons/buttons.h"
#include "defs/defs.h"
#include "display/display.h"
#include "draw/draw.h"
#include "menu.h"
#include "storage/storage.h"
void menu_resetDataScreen(TFT_eSprite &bg) {
static uint8_t selectedOption = 0;
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
selectedOption = (selectedOption - 1) % 2;
break;
case K2_PRESSED:
selectedOption = (selectedOption + 1) % 2;
break;
case K4_PRESSED:
if (selectedOption == 1) {
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("RESETTING", 3, 104);
tft_drawBuffer();
if (storage_deleteState()) {
ESP.restart();
}
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("FAILED", 4, 95);
tft_drawBuffer();
return;
}
selectedOption = 0;
screenKey = SETTINGS_SCREEN;
return;
case K3_PRESSED:
selectedOption = 0;
screenKey = SETTINGS_SCREEN;
return;
default:
break;
}
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("RESET DATA?", 3, 35);
const char* labels[] = { "NO", "YES" };
const int startX = 72;
const int startY = 95;
const int spacingY = 42;
for (uint8_t i = 0; i < 2; i++) {
bool selected = (i == selectedOption);
int y = startY + (i * spacingY);
tft_drawText(labels[i], 4, startX, y, selected ? TFT_BLACK : TFT_WHITE, selected ? TFT_WHITE : TFT_TRANSPARENT);
}
tft_drawBuffer();
}
+112
View File
@@ -0,0 +1,112 @@
#include "buttons/buttons.h"
#include "defs/chara_data.h"
#include "defs/defs.h"
#include "display/display.h"
#include "draw/draw.h"
#include "menu.h"
#include "vpet/vpet/vpet.h"
enum SettingsItemType {
SETTINGS_SUBMENU,
SETTINGS_ACTION
};
struct SettingsMenuItem {
const char* label;
SettingsItemType type;
uint8_t targetScreen;
void (*actionFunction)();
bool* stateValue;
};
void switchSoundState() {
if (soundEnabled) {
pinMode(SPK_PIN, INPUT);
} else {
pinMode(SPK_PIN, OUTPUT);
}
soundEnabled = !soundEnabled;
printf("[SETTINGS] soundEnabled=%i\n", soundEnabled);
}
void switchScreenState() {
alwaysOnEnabled = !alwaysOnEnabled;
printf("[SETTINGS] alwaysOnEnabled=%i\n", alwaysOnEnabled);
}
void menu_settingsScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData *spriteData)
{
static int8_t arrowPosition = 0;
static SettingsMenuItem menuItems[] = {
{ "BG", SETTINGS_SUBMENU, BACKGROUND_CHANGE_SCREEN, nullptr, nullptr },
{ "SOUND", SETTINGS_ACTION, 0, switchSoundState, &soundEnabled },
{ "AOD", SETTINGS_ACTION, 0, switchScreenState, &alwaysOnEnabled },
{ "RESET", SETTINGS_SUBMENU, RESET_DATA_SCREEN, nullptr, nullptr }
};
const uint8_t numItems = sizeof(menuItems) / sizeof(menuItems[0]);
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition--;
if (arrowPosition < 0) {
arrowPosition = numItems - 1;
}
break;
case K2_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition++;
if (arrowPosition >= numItems) {
arrowPosition = 0;
}
break;
case K3_PRESSED:
screenKey = MENU_SCREEN;
return;
case K4_PRESSED:
lastUpdateTime = 0;
if (menuItems[arrowPosition].type == SETTINGS_ACTION) {
if (menuItems[arrowPosition].actionFunction != nullptr) {
menuItems[arrowPosition].actionFunction();
}
} else if (menuItems[arrowPosition].type == SETTINGS_SUBMENU) {
screenKey = menuItems[arrowPosition].targetScreen;
return;
}
break;
default:
break;
}
draw_drawBackground(bg, 90, 90, 3);
const int startX = 20;
const int startY = 10;
const int spacingY = 40;
for (uint8_t i = 0; i < numItems; i++) {
bool selected = (i == arrowPosition);
int y = startY + (i * spacingY);
tft_drawText(menuItems[i].label, 4, startX, y, selected ? TFT_BLACK : TFT_WHITE, selected ? TFT_WHITE : TFT_TRANSPARENT);
if (menuItems[i].stateValue != nullptr) {
const char* stateText = (*menuItems[i].stateValue) ? "ON" : "OFF";
tft_drawText(stateText, 4, 150, y, selected ? TFT_BLACK : TFT_WHITE, selected ? TFT_WHITE : TFT_TRANSPARENT);
}
}
tft_drawBuffer();
}
+6 -4
View File
@@ -5,6 +5,7 @@
#include "buttons/buttons.h"
#include "animations/animations.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* charaSprites, struct SpriteData* uiSprites) {
if (!charaData[currentCharacter].asleep && !charaData[currentCharacter].sleepy) {
@@ -18,10 +19,12 @@ void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
uint64_t currentTime = esp_timer_get_time();
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 8:
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
break;
case 4:
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
@@ -45,8 +48,7 @@ void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
}
if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) {
tone(SPK_PIN, 2500, 100);
tone(SPK_PIN, 5000, 100);
sound_playMelody(SOUND_CARE_ALERT, SOUND_NOTE_COUNT(SOUND_CARE_ALERT));
lastBeepTime = currentTime;
+3 -2
View File
@@ -23,11 +23,12 @@ void menu_sleepingScreen(
uint8_t buttonsPressed = buttons_getPressedButtons();
switch (buttonsPressed) {
case 8:
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
break;
case 4:
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
+2 -2
View File
@@ -13,7 +13,7 @@ void menu_statusScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 2:
case K3_PRESSED:
screenKey = MENU_SCREEN;
break;
@@ -41,7 +41,7 @@ void menu_statusScreen_drawStat(TFT_eSprite &sprite, struct SpriteData* spriteDa
draw_drawSprite(
sprite,
15 + (i * 32),
15 + (i * 48),
y + 30,
spriteData,
icon,
+7 -3
View File
@@ -6,11 +6,16 @@
void menu_drawTitle(TFT_eSprite &bg, TFT_eSprite &composite) {
uint8_t pressedButtons = buttons_getPressedButtons();
if (pressedButtons == 8 || pressedButtons == 4) {
if (pressedButtons != 0) {
screenKey = CLOCK_EDIT_SCREEN;
return;
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime < 200000) {
return;
}
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("NacaPet", 4, 40);
@@ -18,6 +23,5 @@ void menu_drawTitle(TFT_eSprite &bg, TFT_eSprite &composite) {
tft_drawCenteredText(VERSION, 2, 80);
tft_drawBuffer();
delay(200);
lastUpdateTime = currentTime;
}
+2 -2
View File
@@ -1,6 +1,7 @@
#include "vpet/training/training.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
#include "buttons/buttons.h"
#include "display/display.h"
@@ -16,8 +17,7 @@ void training_screenTraining1(
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, mainCharaData, 11);
tone(SPK_PIN, 4100, 100);
tone(SPK_PIN, 3500, 100);
sound_playMelody(SOUND_TRAINING_START, SOUND_NOTE_COUNT(SOUND_TRAINING_START));
tft_drawBuffer();
+68 -56
View File
@@ -2,6 +2,7 @@
#include "vpet/training/training.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "draw/draw.h"
#include "display/display.h"
#include "buttons/buttons.h"
@@ -10,56 +11,59 @@ void training_screenTraining2(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
) {
vTaskSuspend(secondLoop);
enum TrainingState {
TRAINING_INIT,
TRAINING_WAIT_INPUT,
TRAINING_SHOW_BOTH,
TRAINING_SHOW_HIT
};
draw_drawBackground(bg, 90, 90 ,3);
static TrainingState state = TRAINING_INIT;
static uint64_t inactivityTimer = 0;
static uint64_t stageStartTime = 0;
static uint8_t randomPosition = 0;
static uint8_t projectilePosition = 0;
// Player
draw_drawSprite(sprite, 174, 72, mainCharaData, 0, false);
draw_drawBackgroundSection(bg, 222, 72, 18, 96);
uint64_t currentTime = esp_timer_get_time();
// Opponent
draw_drawSprite(sprite, -30, 72, mainCharaData, 0, true);
draw_drawBackgroundSection(bg, 0, 72, 18, 96);
if (state == TRAINING_INIT) {
draw_drawBackground(bg, 90, 90 ,3);
tft_drawBuffer();
// Player
draw_drawSprite(sprite, 174, 72, mainCharaData, 0, false);
draw_drawBackgroundSection(bg, 222, 72, 18, 96);
uint64_t inactivityTimer = esp_timer_get_time();
while (true) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 500000) {
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
lastUpdateTime = currentTime;
}
// Opponent
draw_drawSprite(sprite, -30, 72, mainCharaData, 0, true);
draw_drawBackgroundSection(bg, 0, 72, 18, 96);
tft_drawBuffer();
inactivityTimer = currentTime;
state = TRAINING_WAIT_INPUT;
return;
}
if (currentTime - lastUpdateTime > 500000) {
sound_playMelody(SOUND_BUTTON_BEEP, SOUND_NOTE_COUNT(SOUND_BUTTON_BEEP));
lastUpdateTime = currentTime;
}
if (state == TRAINING_WAIT_INPUT) {
if (currentTime - inactivityTimer > 3000000) {
screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU;
vTaskResume(secondLoop);
state = TRAINING_INIT;
return;
}
uint8_t randomPosition = rand() % 2;
uint8_t projectilePosition = 0;
uint8_t pressedButtons = buttons_getPressedButtons();
if (pressedButtons == K1_PRESSED || pressedButtons == K2_PRESSED) {
projectilePosition = pressedButtons >> 3; // pressedButtons >> 4 == 1 => K1; != 1 => K2
if (pressedButtons == K3_PRESSED || pressedButtons == K4_PRESSED) {
randomPosition = rand() % 2;
projectilePosition = pressedButtons >> 1; // pressedButtons >> 4 == 1 => K1; != 1 => K2
printf("[TRAIN] projectilePosition=%i\n", projectilePosition);
} else if (pressedButtons == K3_PRESSED) {
screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU;
vTaskResume(secondLoop);
return;
}
if (pressedButtons != 0) {
inactivityTimer = esp_timer_get_time();
inactivityTimer = currentTime;
// Player attack
draw_drawSprite(sprite, 126, 72 + 48 * projectilePosition, attackSprites, POOP_ICON);
@@ -69,28 +73,36 @@ void training_screenTraining2(
tft_drawBuffer();
if (projectilePosition != randomPosition) {
delay(500);
stageStartTime = currentTime;
state = TRAINING_SHOW_BOTH;
draw_drawBackgroundSection(bg, 126, 72 + 48 * projectilePosition, 48, 48);
draw_drawSprite(sprite, 66, 72 + 48 * projectilePosition, attackSprites, POOP_ICON);
tft_drawBuffer();
delay(500);
} else {
delay(500);
}
draw_drawBackgroundSection(bg, 66, 72, 108, 96);
if (projectilePosition != randomPosition) {
charaData[currentCharacter].strength++;
menu_drawHappyScreen(bg, sprite, mainCharaData, attackSprites);
} else {
printf("[TRAIN] Train failed\n");
menu_drawAngryScreen(bg, sprite, mainCharaData, attackSprites);
}
} else if (pressedButtons == K3_PRESSED) {
screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU;
state = TRAINING_INIT;
return;
}
} else if (state == TRAINING_SHOW_BOTH && currentTime - stageStartTime > 500000) {
if (projectilePosition != randomPosition) {
draw_drawBackgroundSection(bg, 126, 72 + 48 * projectilePosition, 48, 48);
draw_drawSprite(sprite, 66, 72 + 48 * projectilePosition, attackSprites, POOP_ICON);
tft_drawBuffer();
stageStartTime = currentTime;
state = TRAINING_SHOW_HIT;
} else {
draw_drawBackgroundSection(bg, 66, 72, 108, 96);
tft_drawBuffer();
printf("[TRAIN] Train failed\n");
screenKey = ANGRY_SCREEN;
state = TRAINING_INIT;
}
} else if (state == TRAINING_SHOW_HIT && currentTime - stageStartTime > 500000) {
draw_drawBackgroundSection(bg, 66, 72, 108, 96);
tft_drawBuffer();
charaData[currentCharacter].strength++;
screenKey = HAPPY_SCREEN;
state = TRAINING_INIT;
}
}
+98
View File
@@ -0,0 +1,98 @@
#include "sound.h"
#include "defs/defs.h"
static const Note* currentMelody = nullptr;
static uint16_t melodyLength = 0;
static uint16_t currentNote = 0;
static bool playing = false;
static unsigned long nextNoteTime = 0;
void sound_init() {
pinMode(SPK_PIN, OUTPUT);
}
void sound_playTone(uint16_t frequency, uint16_t duration) {
if (!soundEnabled) { return; }
currentMelody = nullptr;
melodyLength = 0;
currentNote = 0;
if (frequency == 0) {
noTone(SPK_PIN);
} else {
tone(SPK_PIN, frequency, duration);
}
playing = true;
nextNoteTime = millis() + duration;
}
void sound_playMelody(const Note* melody, uint16_t noteCount) {
if (!soundEnabled) { return; }
if (melody == nullptr || noteCount == 0) {
return;
}
currentMelody = melody;
melodyLength = noteCount;
currentNote = 0;
playing = true;
nextNoteTime = 0;
}
void sound_stop() {
noTone(SPK_PIN);
playing = false;
currentMelody = nullptr;
melodyLength = 0;
currentNote = 0;
}
bool sound_isPlaying() {
return playing;
}
void sound_update() {
if (!soundEnabled) {
sound_stop();
return;
}
if (!playing) {
return;
}
if (currentMelody == nullptr) {
if (millis() >= nextNoteTime) {
sound_stop();
}
return;
}
if (millis() < nextNoteTime) {
return;
}
if (currentNote >= melodyLength) {
sound_stop();
return;
}
const Note& note = currentMelody[currentNote];
if (note.frequency == 0) {
noTone(SPK_PIN);
} else {
tone(SPK_PIN, note.frequency, note.duration);
}
nextNoteTime = millis() + note.duration;
currentNote++;
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <Arduino.h>
struct Note {
uint16_t frequency;
uint16_t duration;
};
void sound_init();
void sound_update();
void sound_playTone(uint16_t frequency, uint16_t duration);
void sound_playMelody(const Note* melody, uint16_t noteCount);
void sound_stop();
bool sound_isPlaying();
+124
View File
@@ -0,0 +1,124 @@
#include "storage.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "utils/utils.h"
const char* TAG_SR = "[STORAGE]";
void storage_readFile(const char* path, struct SpriteData* spriteData) {
File file = SPIFFS.open(path, "r");
if (!file) {
printf("%s Failed to open file for reading\n", TAG_SR);
return;
}
uint8_t width, height, spriteNumber;
file.read(&width, 1);
file.read(&height, 1);
file.read(&spriteNumber, 1);
if (spriteData->spriteData != NULL) {
memory_free(spriteData);
}
const uint8_t scaledW = width * SPRITE_SCALE;
const uint8_t scaledH = height * SPRITE_SCALE;
uint16_t** scaled =
(uint16_t**) ps_malloc(spriteNumber * sizeof(uint16_t*));
if (!scaled) {
printf("%s PSRAM alloc failed for pointer table\n", TAG_SR);
file.close();
return;
}
for (uint8_t i = 0; i < spriteNumber; i++) {
scaled[i] =
(uint16_t*) ps_malloc(scaledW * scaledH * sizeof(uint16_t));
if (!scaled[i]) {
printf("%s PSRAM alloc failed for sprite %d\n", TAG_SR, i);
for (uint8_t j = 0; j < i; j++) {
free(scaled[j]);
}
free(scaled);
file.close();
return;
}
}
uint16_t* spriteBuf =
(uint16_t*) malloc(width * height * sizeof(uint16_t));
if (!spriteBuf) {
printf("%s scratch alloc failed\n", TAG_SR);
for (uint8_t i = 0; i < spriteNumber; i++) {
free(scaled[i]);
}
free(scaled);
file.close();
return;
}
printf(
"%s Read header: width=%d, height=%d, numSprites=%d -> scaled to %dx%d\n",
TAG_SR,
width,
height,
spriteNumber,
scaledW,
scaledH
);
for (int sprN = 0; sprN < spriteNumber; sprN++) {
// Read original sprite into temporary buffer
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uint8_t hi, lo;
file.read(&hi, 1);
file.read(&lo, 1);
spriteBuf[y * width + x] =
(lo << 8) | hi;
}
}
// Upscale sprite
utils_upscaleSprite(
spriteBuf,
width,
height,
scaled[sprN]
);
}
free(spriteBuf);
file.close();
spriteData->spriteWidth = scaledW;
spriteData->spriteHeight = scaledH;
spriteData->spriteNumber = spriteNumber;
spriteData->spriteData = scaled;
printf(
"%s Loaded & upscaled %s (%d sprites, each %dx%d px)\n",
TAG_SR,
path,
spriteNumber,
scaledW,
scaledH
);
}
+20 -89
View File
@@ -8,8 +8,6 @@
const char* TAG_S = "[STORAGE]";
#define SPRITE_SCALE 6
void storage_init() {
if (!SPIFFS.begin(true)) {
printf("%s Failed to mount file system\n", TAG_S);
@@ -19,95 +17,11 @@ void storage_init() {
}
void storage_readFile(const char* path, struct SpriteData* spriteData) {
File file = SPIFFS.open(path, "r");
if (!file) {
printf("%s Failed to open file for reading\n", TAG_S);
return;
}
void storage_initBackground(const int id, TFT_eSprite& bg) {
char path[15];
uint8_t width, height, spriteNumber;
snprintf(path, 15, "/bg/%i.bin", id);
file.read(&width, 1);
file.read(&height, 1);
file.read(&spriteNumber, 1);
if (spriteData->spriteData != NULL) {
memory_free(spriteData);
}
const uint8_t scaledW = width * SPRITE_SCALE;
const uint8_t scaledH = height * SPRITE_SCALE;
uint16_t** scaled = (uint16_t**) ps_malloc(spriteNumber * sizeof(uint16_t*));
if (!scaled) {
printf("%s PSRAM alloc failed for pointer table\n", TAG_S);
file.close();
return;
}
for (uint8_t i = 0; i < spriteNumber; i++) {
scaled[i] = (uint16_t*) ps_malloc(scaledW * scaledH * sizeof(uint16_t));
if (!scaled[i]) {
printf("%s PSRAM alloc failed for sprite %d\n", TAG_S, i);
for (uint8_t j = 0; j < i; j++) free(scaled[j]);
free(scaled);
file.close();
return;
}
}
uint16_t* rowBuf = (uint16_t*) malloc(width * sizeof(uint16_t));
if (!rowBuf) {
printf("%s scratch alloc failed\n", TAG_S);
for (uint8_t i = 0; i < spriteNumber; i++) free(scaled[i]);
free(scaled);
file.close();
return;
}
printf(
"%s Read header: width=%d, height=%d, numSprites=%d -> scaled to %dx%d\n",
TAG_S, width, height, spriteNumber, scaledW, scaledH
);
for (int sprN = 0; sprN < spriteNumber; sprN++) {
uint16_t* dst = scaled[sprN];
for (int srcY = 0; srcY < height; srcY++) {
for (int srcX = 0; srcX < width; srcX++) {
uint8_t hi, lo;
file.read(&hi, 1);
file.read(&lo, 1);
rowBuf[srcX] = (lo << 8) | hi;
}
for (int dy = 0; dy < SPRITE_SCALE; dy++) {
uint16_t* dstRow = dst + (srcY * SPRITE_SCALE + dy) * scaledW;
for (int srcX = 0; srcX < width; srcX++) {
uint16_t color = rowBuf[srcX];
uint16_t* dstPixel = dstRow + srcX * SPRITE_SCALE;
for (int dx = 0; dx < SPRITE_SCALE; dx++) {
dstPixel[dx] = color;
}
}
}
}
}
free(rowBuf);
file.close();
spriteData->spriteWidth = scaledW;
spriteData->spriteHeight = scaledH;
spriteData->spriteNumber = spriteNumber;
spriteData->spriteData = scaled;
printf("%s Loaded & upscaled %s (%d sprites, each %dx%d px)\n",
TAG_S, path, spriteNumber, scaledW, scaledH);
}
void storage_initBackground(const char* path, TFT_eSprite& bg) {
File file = SPIFFS.open(path, "r");
if (!file) {
printf("%s Failed to open file for reading\n", TAG_S);
@@ -305,3 +219,20 @@ void storage_loadState() {
printf("%s Load completed!\n", TAG_S);
}
bool storage_deleteState() {
const char* savePath = "/save.bin";
if (!SPIFFS.exists(savePath)) {
printf("%s Save file already deleted.\n", TAG_S);
return true;
}
if (!SPIFFS.remove(savePath)) {
printf("%s Failed to delete save file.\n", TAG_S);
return false;
}
printf("%s Save file deleted.\n", TAG_S);
return true;
}
+2 -1
View File
@@ -9,9 +9,10 @@
void storage_init();
void storage_readFile(const char* path, struct SpriteData* spriteData);
void storage_initBackground(const char* path, TFT_eSprite &bg);
void storage_initBackground(const int id, TFT_eSprite &bg);
void storage_saveState();
void storage_loadState();
bool storage_deleteState();
#endif
+41
View File
@@ -0,0 +1,41 @@
#include "utils.h"
#include "defs/defs.h"
/**
* Upscale a sprite using nearest-neighbor scaling.
*
* @param src Pointer to source sprite pixels
* @param srcWidth Original sprite width
* @param srcHeight Original sprite height
* @param dst Destination buffer for upscaled sprite
*/
void utils_upscaleSprite(
const uint16_t* src,
uint8_t srcWidth,
uint8_t srcHeight,
uint16_t* dst
) {
const uint8_t scaledW = srcWidth * SPRITE_SCALE;
for (int srcY = 0; srcY < srcHeight; srcY++) {
for (int dy = 0; dy < SPRITE_SCALE; dy++) {
uint16_t* dstRow =
dst + ((srcY * SPRITE_SCALE + dy) * scaledW);
for (int srcX = 0; srcX < srcWidth; srcX++) {
uint16_t color = src[srcY * srcWidth + srcX];
uint16_t* dstPixel =
dstRow + (srcX * SPRITE_SCALE);
for (int dx = 0; dx < SPRITE_SCALE; dx++) {
dstPixel[dx] = color;
}
}
}
}
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef UTILS_H
#define UTILS_H
#include <Arduino.h>
void utils_upscaleSprite(
const uint16_t* src,
uint8_t srcWidth,
uint8_t srcHeight,
uint16_t* dst
);
#endif
+46 -15
View File
@@ -1,6 +1,7 @@
#include "lines.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "utils/utils.h"
#include <FS.h>
#include <SPIFFS.h>
@@ -40,39 +41,69 @@ void lines_getAvailableLines() {
lineFile = root.openNextFile("r");
while (lineFile) {
uint16_t bytesRead = lineFile.readBytes(header, headerSize);
uint16_t bytesRead = 0;
bytesRead += lineFile.readBytes(header, headerSize);
bytesRead += lineFile.read(&availableLines[allocCount].id, 1);
bytesRead += lineFile.readBytes(availableLines[allocCount].name, 16);
bytesRead += lineFile.read(&availableLines[allocCount].eggSprite.spriteWidth, 1);
bytesRead += lineFile.read(&availableLines[allocCount].eggSprite.spriteHeight, 1);
bytesRead += lineFile.read(&availableLines[allocCount].eggSprite.spriteNumber, 1); // Se coloca el cursor al principio de los datos de sprite
uint8_t originalWidth;
uint8_t originalHeight;
uint8_t spriteCount;
availableLines[allocCount].eggSprite.spriteNumber = 1; // Inutil, pero es que necesito hacer la lectura
bytesRead += lineFile.read(&originalWidth, 1);
bytesRead += lineFile.read(&originalHeight, 1);
bytesRead += lineFile.read(&spriteCount, 1);
availableLines[allocCount].eggSprite.spriteData = memory_allocate(
availableLines[allocCount].eggSprite.spriteNumber,
availableLines[allocCount].eggSprite.spriteWidth,
availableLines[allocCount].eggSprite.spriteHeight
);
const uint8_t scaledWidth = originalWidth * SPRITE_SCALE;
const uint8_t scaledHeight = originalHeight * SPRITE_SCALE;
availableLines[allocCount].eggSprite.spriteWidth = scaledWidth;
availableLines[allocCount].eggSprite.spriteHeight = scaledHeight;
availableLines[allocCount].eggSprite.spriteNumber = 1;
availableLines[allocCount].eggSprite.spriteData = memory_allocate(1, scaledWidth, scaledHeight);
uint16_t* spriteBuffer =
(uint16_t*) malloc(
originalWidth *
originalHeight *
sizeof(uint16_t)
);
if (!spriteBuffer) {
printf("[LINES] Failed to allocate sprite buffer\n");
lineFile.close();
lineFile = root.openNextFile();
continue;
}
uint8_t highByte;
uint8_t lowByte;
for (int i = 0; i < availableLines[allocCount].eggSprite.spriteWidth * availableLines[allocCount].eggSprite.spriteHeight; i++) {
bytesRead += lineFile.read(&highByte, 1);
for (int i = 0; i < originalWidth * originalHeight; i++) {
bytesRead += lineFile.read(&lowByte, 1);
bytesRead += lineFile.read(&highByte, 1);
uint16_t pixel = (highByte << 8) | lowByte;
availableLines[allocCount].eggSprite.spriteData[0][i] = pixel;
spriteBuffer[i] = (highByte << 8) | lowByte;
}
utils_upscaleSprite(
spriteBuffer,
originalWidth,
originalHeight,
availableLines[allocCount].eggSprite.spriteData[0]
);
free(spriteBuffer);
strcpy(availableLines[allocCount].fileName, lineFile.name());
lineFile.close();
allocCount++;
lineFile = root.openNextFile();
}
+53 -13
View File
@@ -1,6 +1,7 @@
#include "lines.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "utils/utils.h"
#include <FS.h>
#include <SPIFFS.h>
@@ -40,37 +41,76 @@ void lines_getSingleLine(const char* fileName) {
currentLine[currentCharacter] = selectedLine;
currentEgg = selectedEgg;
}
void lines_getSingleEggSprites(fs::File &lineFile, Egg_t* selectedEgg) {
// Importante tener el nombre de archivo del huevo en todo momento
strcpy(selectedEgg->fileName, lineFile.name());
// Ahora se lee los datos
lineFile.read(&(selectedEgg->eggSprite.spriteWidth), 1);
lineFile.read(&(selectedEgg->eggSprite.spriteHeight), 1);
// Leer dimensiones originales
uint8_t originalWidth;
uint8_t originalHeight;
lineFile.read(&originalWidth, 1);
lineFile.read(&originalHeight, 1);
lineFile.read(&(selectedEgg->eggSprite.spriteNumber), 1);
const uint8_t scaledWidth = originalWidth * SPRITE_SCALE;
const uint8_t scaledHeight = originalHeight * SPRITE_SCALE;
// Guardar dimensiones escaladas
selectedEgg->eggSprite.spriteWidth = scaledWidth;
selectedEgg->eggSprite.spriteHeight = scaledHeight;
// Reservar memoria para sprites escalados
selectedEgg->eggSprite.spriteData = memory_allocate(
selectedEgg->eggSprite.spriteNumber,
selectedEgg->eggSprite.spriteWidth,
selectedEgg->eggSprite.spriteHeight
scaledWidth,
scaledHeight
);
uint16_t size = selectedEgg->eggSprite.spriteWidth * selectedEgg->eggSprite.spriteHeight;
const uint16_t originalSize =
originalWidth * originalHeight;
// Buffer temporal en SRAM
uint16_t* spriteBuffer =
(uint16_t*) malloc(
originalSize * sizeof(uint16_t)
);
if (!spriteBuffer) {
printf("[LINES] Failed to allocate sprite buffer\n");
return;
}
uint8_t highByte;
uint8_t lowByte;
for (int spr = 0; spr < selectedEgg->eggSprite.spriteNumber; spr++) {
for (int i= 0; i < size; i++) {
lineFile.read(&highByte, 1);
for (
int spr = 0;
spr < selectedEgg->eggSprite.spriteNumber;
spr++
) {
// Leer sprite original
for (int i = 0; i < originalSize; i++) {
lineFile.read(&lowByte, 1);
lineFile.read(&highByte, 1);
uint16_t pixel = (highByte << 8) | lowByte;
selectedEgg->eggSprite.spriteData[spr][i] = pixel;
spriteBuffer[i] =
(highByte << 8) | lowByte;
}
// Escalar sprite
utils_upscaleSprite(
spriteBuffer,
originalWidth,
originalHeight,
selectedEgg->eggSprite.spriteData[spr]
);
}
free(spriteBuffer);
}
// Son las 22:35, que estoy haciendo?
+1 -1
View File
@@ -22,7 +22,7 @@ void steps_countSteps() {
float dyn = mag - gravity;
unsigned long now = esp_timer_get_time();
if (dyn > thresh && (now - lastStepTime) > 250000) {
if (dyn > thresh && (now - lastStepTime) > 350000) {
stepCounter++;
lastStepTime = now;
}
+2 -16
View File
@@ -2,6 +2,7 @@
#include "draw/draw.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
#include "display/display.h"
@@ -100,20 +101,5 @@ void training_displayTrainingResult(
// nOT FANCY
void training_trainingAttackSounds() {
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
sound_playMelody(SOUND_TRAINING_ATTACK, SOUND_NOTE_COUNT(SOUND_TRAINING_ATTACK));
}