Compare commits

...

8 Commits

Author SHA1 Message Date
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
915c5cd2a7 Switch the name of the disallow sleep flag 2026-05-29 02:17:32 +02:00
79d60e7201 Improve sound system thing in here 2026-05-29 02:16:58 +02:00
3de6c121a5 Add ALLOW_SLEEP flag to enable sleep mode in inactivity checks 2026-05-28 21:35:41 +02:00
f15ea8190f Update food select screen to use precompiler parameters 2026-05-28 21:35:00 +02:00
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
60c1659875 Enhance tft_drawText function to support background color 2026-05-28 21:33:56 +02:00
e158f50970 Add settings screen 2026-05-28 21:32:52 +02:00
33 changed files with 1034 additions and 476 deletions

View File

@ -30,6 +30,7 @@ build_flags =
-DBOARD_HAS_PSRAM -DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_CDC_ON_BOOT=0
-DDEV_UNIT -DDEV_UNIT
-DDISALLOW_SLEEP
-DDEBUG -DDEBUG
upload_port = COM8 upload_port = COM8
@ -49,6 +50,7 @@ build_flags =
-DBOARD_HAS_PSRAM -DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_CDC_ON_BOOT=1
-DARDUINO_USB_MODE=1 -DARDUINO_USB_MODE=1
-DDISALLOW_SLEEP
-DDEV_UNIT -DDEV_UNIT
board_build.partitions = default.csv board_build.partitions = default.csv

View File

@ -95,7 +95,7 @@ void animate_performAngryAnimation(TFT_eSprite &spr, struct SpriteData* spriteDa
} }
void animate_performHatchingAnimation(TFT_eSprite &spr, struct SpriteData* spriteData) { void animate_performHatchingAnimation(TFT_eSprite &spr, struct SpriteData* spriteData) {
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesHappy; currentAnimationFrame = (currentAnimationFrame + 1) % numFramesHatching;
draw_drawSprite( draw_drawSprite(
spr, spr,
hatchingAnimationPositions[currentAnimationFrame], hatchingAnimationPositions[currentAnimationFrame],
@ -104,4 +104,4 @@ void animate_performHatchingAnimation(TFT_eSprite &spr, struct SpriteData* sprit
0, 0,
false false
); );
} }

View File

@ -1,4 +1,5 @@
#include "defs/defs.h" #include "defs/defs.h"
#include "defs/sounds.h"
#include "defs/chara_data.h" #include "defs/chara_data.h"
#include "defs/screen_defs.h" #include "defs/screen_defs.h"
#include "buttons.h" #include "buttons.h"
@ -16,9 +17,11 @@ bool k4_prev = HIGH;
void buttons_checkInactivity() { void buttons_checkInactivity() {
uint64_t currentTime = esp_timer_get_time(); 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); digitalWrite(BL_PIN, LOW);
screenKey = OFF_SCREEN; screenKey = OFF_SCREEN;
#endif
} else if (currentTime - lastPressedButtonTime > LAST_PRESSED_BUTTON_THRESHOLD_TIME_US && !inactive) { } else if (currentTime - lastPressedButtonTime > LAST_PRESSED_BUTTON_THRESHOLD_TIME_US && !inactive) {
screenKey = MAIN_SCREEN; screenKey = MAIN_SCREEN;
@ -40,7 +43,7 @@ uint8_t buttons_getPressedButtons() {
); );
if (retV != 0) { 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(); lastPressedButtonTime = esp_timer_get_time();
inactive = false; inactive = false;
screenOff = false; screenOff = false;

View File

@ -125,6 +125,10 @@
// TRAINING MODES // TRAINING MODES
#define TRAINING_SCREEN_1 30 #define TRAINING_SCREEN_1 30
// SETTINGS SUBSCREENS
#define BACKGROUND_CHANGE_SCREEN 40
#define RESET_DATA_SCREEN 41
// SMALL UI ICONS (UI.BIN) // SMALL UI ICONS (UI.BIN)
#define POOP_ICON 0 #define POOP_ICON 0
#define FOOD_ICON 1 #define FOOD_ICON 1
@ -217,4 +221,8 @@ extern bool isSamplingSteps;
extern uint64_t sampleStartTime; extern uint64_t sampleStartTime;
extern uint16_t initialSteps; extern uint16_t initialSteps;
#endif // Settings screen options
extern bool soundEnabled;
extern bool alwaysOnEnabled;
#endif

121
src/defs/sounds.h Normal file
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

View File

@ -2,6 +2,8 @@
#include "defs/screen_defs.h" #include "defs/screen_defs.h"
#include "defs/defs.h" #include "defs/defs.h"
#include <TFT_eSPI.h>
int xPos = 0; int xPos = 0;
int yPos = 0; int yPos = 0;
@ -59,9 +61,15 @@ void tft_drawCenteredText(const char* text, int size, int yGlobal) {
composite.drawString(text, x, 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.setTextSize(size);
composite.setTextColor(color);
if (bgColor != TFT_TRANSPARENT) {
composite.setTextColor(color, bgColor);
} else {
composite.setTextColor(color);
}
composite.drawString(text, x, y); composite.drawString(text, x, y);
} }

View File

@ -12,7 +12,7 @@ void tft_drawBuffer();
void tft_clearBuffer(TFT_eSprite &buffer, uint16_t color = TFT_WHITE); void tft_clearBuffer(TFT_eSprite &buffer, uint16_t color = TFT_WHITE);
void tft_clearBuffer(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_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); void tft_drawRectangle(int x, int y, int w, int h, uint16_t color = TFT_BLACK);
#endif #endif

View File

@ -15,6 +15,8 @@
#include "driver/rtc_io.h" #include "driver/rtc_io.h"
#include "loop/loop.h" #include "loop/loop.h"
#include "menu/training/training_screens.h" #include "menu/training/training_screens.h"
#include "defs/sounds.h"
#include "sound/sound.h"
const char* TAG = "[MAIN]"; const char* TAG = "[MAIN]";
@ -67,6 +69,11 @@ int currentBackground = 0;
// Tasks // Tasks
TaskHandle_t secondLoop = NULL; TaskHandle_t secondLoop = NULL;
// Settings
bool soundEnabled = true;
bool alwaysOnEnabled = false;
// Background step counting
bool isSamplingSteps = false; bool isSamplingSteps = false;
uint64_t sampleStartTime = 0; uint64_t sampleStartTime = 0;
uint16_t initialSteps = 0; uint16_t initialSteps = 0;
@ -89,6 +96,8 @@ void setup() {
tft_initDisplay(tft, TFT_BLACK); tft_initDisplay(tft, TFT_BLACK);
tft_initScreenBuffer(TFT_TRANSPARENT); tft_initScreenBuffer(TFT_TRANSPARENT);
sound_init();
storage_init(); storage_init();
@ -103,6 +112,8 @@ void setup() {
pinMode(K4_PIN, BUTTON_MODE); pinMode(K4_PIN, BUTTON_MODE);
xTaskCreatePinnedToCore(secondCoreTask, "VPET_EVAL", 4096, NULL, 0, &secondLoop, 0); xTaskCreatePinnedToCore(secondCoreTask, "VPET_EVAL", 4096, NULL, 0, &secondLoop, 0);
sound_playMelody(SOUND_BOOT, SOUND_NOTE_COUNT(SOUND_BOOT));
lines_initLineStorage(); lines_initLineStorage();
@ -216,6 +227,18 @@ void loop() {
case FROZEN_SCREEN: case FROZEN_SCREEN:
menu_drawFridgeScreen(bg, sprite, &mainCharacterSprites, &menuElementsData); menu_drawFridgeScreen(bg, sprite, &mainCharacterSprites, &menuElementsData);
break; 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) { if (screenKey == IDLE_SCREEN || screenKey == OFF_SCREEN) {
@ -244,7 +267,6 @@ void loop2() {
stepCounter += approximatedSteps; stepCounter += approximatedSteps;
printf("[STEPS] Sampled %d steps in 10s, added %d approximated steps for sleep period.\n", sampledSteps, approximatedSteps); printf("[STEPS] Sampled %d steps in 10s, added %d approximated steps for sleep period.\n", sampledSteps, approximatedSteps);
energy_startLightSleep(); energy_startLightSleep();
} }
} else { } else {
@ -253,10 +275,12 @@ void loop2() {
} else { } else {
isSamplingSteps = false; isSamplingSteps = false;
} }
sound_update();
} }
void secondCoreTask(void*) { void secondCoreTask(void*) {
for (;;) { for (;;) {
loop2(); loop2();
} }
} }

View File

@ -4,43 +4,39 @@
#include "display/display.h" #include "display/display.h"
#include "draw/draw.h" #include "draw/draw.h"
#include "animations/animations.h" #include "animations/animations.h"
#include "defs/sounds.h"
void menu_drawAngryScreen( void menu_drawAngryScreen(
TFT_eSprite& bg, TFT_eSprite &sprite, TFT_eSprite& bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements 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;
vTaskResume(secondLoop); 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;
return; return;
} }
draw_drawBackground(bg, 90, 90, 3); 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); tft_clearBuffer(sprite, TFT_TRANSPARENT);
animate_performAngryAnimation(sprite, spriteData); draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
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;
} }
frameCounter++;
lastUpdateTime = currentTime;
tft_drawBuffer(); tft_drawBuffer();
} }
} }

View File

@ -3,6 +3,7 @@
#include "animations/animations.h" #include "animations/animations.h"
#include "display/display.h" #include "display/display.h"
#include "defs/chara_data.h" #include "defs/chara_data.h"
#include "defs/sounds.h"
#include "draw/draw.h" #include "draw/draw.h"
uint64_t lastBeepTime = esp_timer_get_time(); 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(); uint8_t pressedButtons = buttons_getPressedButtons();
if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) { if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) {
tone(SPK_PIN, 2500, 100); sound_playMelody(SOUND_CARE_ALERT, SOUND_NOTE_COUNT(SOUND_CARE_ALERT));
tone(SPK_PIN, 5000, 100);
lastBeepTime = currentTime; lastBeepTime = currentTime;
@ -39,4 +39,4 @@ void menu_careMistakeScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteD
} }
tft_drawBuffer(); tft_drawBuffer();
} }

View File

@ -2,17 +2,22 @@
#include "draw/draw.h" #include "draw/draw.h"
#include "display/display.h" #include "display/display.h"
#include "defs/screen_defs.h" #include "defs/screen_defs.h"
#include "defs/sounds.h"
#include "vpet/evolution/evolution.h" #include "vpet/evolution/evolution.h"
#include "loop/loop.h" #include "loop/loop.h"
struct SpriteData* checkerboardPattern; struct SpriteData* checkerboardPattern;
void menu_createCheckerboard() { void menu_createCheckerboard() {
if (checkerboardPattern != NULL) {
return;
}
const uint8_t SCALE = 6; const uint8_t SCALE = 6;
const uint8_t logicalW = 34; const uint8_t logicalW = 34;
const uint8_t logicalH = 1; const uint8_t logicalH = 1;
const uint16_t scaledW = logicalW * SCALE; // 204 const uint16_t scaledW = logicalW * SCALE;
const uint16_t scaledH = logicalH * SCALE; // 6 const uint16_t scaledH = logicalH * SCALE;
const uint32_t bufferSize = scaledW * scaledH; const uint32_t bufferSize = scaledW * scaledH;
checkerboardPattern = (SpriteData*) malloc(sizeof(SpriteData)); checkerboardPattern = (SpriteData*) malloc(sizeof(SpriteData));
@ -36,126 +41,178 @@ void menu_createCheckerboard() {
} }
void menu_freeCheckerboard() { void menu_freeCheckerboard() {
if (checkerboardPattern == NULL) {
return;
}
free(checkerboardPattern->spriteData[0]); free(checkerboardPattern->spriteData[0]);
free(checkerboardPattern->spriteData); free(checkerboardPattern->spriteData);
free(checkerboardPattern); free(checkerboardPattern);
checkerboardPattern = NULL;
} }
// Don't worry, I hate this too
void menu_evolutionScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* mainCharacterSprites) { void menu_evolutionScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* mainCharacterSprites) {
menu_createCheckerboard(); enum EvolutionPhase {
TFT_eSprite checkerboard = TFT_eSprite(&tft); 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) { if (currentTime - lastUpdateTime > 500000) {
tone(SPK_PIN, 4100, 50); sound_playMelody(SOUND_EVOLUTION_WOBBLE, SOUND_NOTE_COUNT(SOUND_EVOLUTION_WOBBLE));
tone(SPK_PIN, 3500, 50);
draw_drawBackground(bg, 90, 90, 3); 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(); tft_drawBuffer();
i++; frameIndex++;
lastUpdateTime = currentTime; lastUpdateTime = currentTime;
} }
return;
} }
draw_drawBackground(bg, 90, 90, 3); if (phase == EVOLUTION_RED_FILL) {
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7); 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) { if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6); uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_RED); tft_drawRectangle(18, startYPos, 204, 6, TFT_RED);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift); draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift);
tft_drawBuffer(); tft_drawBuffer();
checkerboardShift = !checkerboardShift; checkerboardShift = !checkerboardShift;
frameIndex++;
i++;
lastUpdateTime = currentTime; lastUpdateTime = currentTime;
} }
return;
} }
for (int i = 0; i < 16;) { if (phase == EVOLUTION_BLACK_FILL) {
uint64_t currentTime = esp_timer_get_time(); if (frameIndex >= 16) {
frameIndex = 15;
lastUpdateTime = 0;
phase = EVOLUTION_APPLY_CHANGE;
return;
}
if (currentTime - lastUpdateTime > 100000) { 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_drawRectangle(18, startYPos, 204, 6, TFT_BLACK);
tft_drawBuffer(); tft_drawBuffer();
checkerboardShift = !checkerboardShift; checkerboardShift = !checkerboardShift;
frameIndex++;
i++;
lastUpdateTime = currentTime; 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) { if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6); uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_GREEN); tft_drawRectangle(18, startYPos, 204, 6, TFT_GREEN);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift); draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift);
tft_drawBuffer(); tft_drawBuffer();
checkerboardShift = !checkerboardShift; checkerboardShift = !checkerboardShift;
frameIndex--;
i--;
lastUpdateTime = currentTime; lastUpdateTime = currentTime;
} }
return;
} }
for (int i = 15; i >= 0;) { if (phase == EVOLUTION_FINAL_REVEAL) {
uint64_t currentTime = esp_timer_get_time(); if (frameIndex < 0) {
phase = EVOLUTION_DONE;
return;
}
if (currentTime - lastUpdateTime > 100000) { if (currentTime - lastUpdateTime > 100000) {
draw_drawBackground(bg, 90, 90, 3); draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7); 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); 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); uint8_t rectYPos = 72 + (6 * j);
draw_drawSprite(checkerboard, 18, rectYPos, checkerboardPattern, 0, checkerboardShift); draw_drawSprite(checkerboard, 18, rectYPos, checkerboardPattern, 0, checkerboardShift);
checkerboardShift = !checkerboardShift; checkerboardShift = !checkerboardShift;
} }
tft_drawBuffer(); tft_drawBuffer();
i--; frameIndex--;
lastUpdateTime = currentTime; lastUpdateTime = currentTime;
} }
return;
} }
tone(SPK_PIN, 2100, 100); sound_playMelody(SOUND_EVOLUTION_COMPLETE, SOUND_NOTE_COUNT(SOUND_EVOLUTION_COMPLETE));
tone(SPK_PIN, 3500, 100);
tone(SPK_PIN, 4100, 100);
tone(SPK_PIN, 4650, 200);
lastPressedButtonTime = esp_timer_get_time(); lastPressedButtonTime = esp_timer_get_time();
@ -163,7 +220,8 @@ void menu_evolutionScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteDat
vTaskResume(secondLoop); vTaskResume(secondLoop);
phase = EVOLUTION_INIT;
screenKey = MAIN_SCREEN; screenKey = MAIN_SCREEN;
lastUpdateTime = 0; // Un pequeño empujoncito lastUpdateTime = 0;
} }

View File

@ -9,69 +9,83 @@
void menu_changeBackgroundScreen( void menu_changeBackgroundScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSpriteData TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSpriteData
) { ) {
int8_t selectedBackground = currentBackground; static bool initialized = false;
static int8_t selectedBackground = 0;
fs::File bgFolder = SPIFFS.open("/bg"); static int8_t selectedPreviousBackground = -1;
fs::File background = bgFolder.openNextFile(); static uint8_t backgrounds = 0;
static uint64_t screenLastActionTime = 0;
uint8_t backgrounds = 0;
uint64_t currentTime = esp_timer_get_time(); uint64_t currentTime = esp_timer_get_time();
int8_t selectedPreviousBackground = 0; if (!initialized) {
fs::File bgFolder = SPIFFS.open("/bg");
fs::File background = bgFolder.openNextFile();
while (background) { backgrounds = 0;
if (!background.isDirectory()) { while (background) {
backgrounds++; if (!background.isDirectory()) {
backgrounds++;
}
background = bgFolder.openNextFile();
} }
background = background.openNextFile(); selectedBackground = currentBackground;
selectedPreviousBackground = -1;
screenLastActionTime = currentTime;
initialized = true;
printf("[BACKGROUNDS] numBackgrounds=%i\n", backgrounds);
} }
for (;;) { uint8_t buttonsPressed = buttons_getPressedButtons();
uint8_t buttonsPressed = buttons_getPressedButtons();
currentTime = esp_timer_get_time();
switch (buttonsPressed) { switch (buttonsPressed) {
case K1_PRESSED: case K1_PRESSED:
selectedBackground++; selectedBackground++;
if (selectedBackground > backgrounds) { if (selectedBackground >= backgrounds) {
selectedBackground = 0; selectedBackground = 0;
} }
storage_initBackground(selectedBackground, bg); storage_initBackground(selectedBackground, bg);
lastUpdateTime = currentTime; screenLastActionTime = currentTime;
break; break;
case K2_PRESSED: case K2_PRESSED:
selectedBackground--; selectedBackground--;
if (selectedBackground < 0) { if (selectedBackground < 0) {
selectedBackground = backgrounds - 1; selectedBackground = backgrounds - 1;
} }
storage_initBackground(selectedBackground, bg); storage_initBackground(selectedBackground, bg);
lastUpdateTime = currentTime; screenLastActionTime = currentTime;
break; break;
case K3_PRESSED:
currentBackground = selectedBackground;
lastUpdateTime = currentTime;
return;
case K4_PRESSED:
storage_initBackground(currentBackground, bg);
lastUpdateTime = currentTime;
return;
}
if (selectedPreviousBackground != selectedBackground) { case K3_PRESSED:
draw_drawBackground(bg, 90, 90, 3); currentBackground = selectedBackground;
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON); initialized = false;
tft_drawBuffer(); screenKey = MAIN_SCREEN;
}
if (currentTime - lastUpdateTime > INACTIVITY_THRESHOLD_TIME_US) {
storage_initBackground(currentBackground, bg);
return; 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;
}
}

View File

@ -9,83 +9,80 @@
void menu_changeCharaScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* mainSpriteData, struct SpriteData* uiSpriteData) { 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; if (!initialized) {
CharacterData* selectedCharaData = &charaData[selectedChara]; selectedChara = currentCharacter;
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
initialized = true;
}
bool updateScreen = true; uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
for (;;) { case K1_PRESSED:
uint8_t pressedButtons = buttons_getPressedButtons(); selectedChara++;
switch (pressedButtons) { if (selectedChara >= CHARA_COUNT_IN_DEVICE) {
case K1_PRESSED: selectedChara = 0;
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);
} }
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
break;
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON); case K2_PRESSED:
currentCharacter = selectedChara;
tft_drawBuffer(); initialized = false;
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
updateScreen = false; case K3_PRESSED: {
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US) {
char fileName[20]; char fileName[20];
sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara); sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(fileName, mainSpriteData); storage_readFile(fileName, mainSpriteData);
vTaskResume(secondLoop); initialized = false;
screenKey = MAIN_SCREEN; screenKey = MAIN_SCREEN;
menuKey = STATUS_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;
}
}

View File

@ -8,14 +8,28 @@
#include "animations/animations.h" #include "animations/animations.h"
#include "vpet/vpet/vpet.h" #include "vpet/vpet/vpet.h"
#include "vpet/lines/lines.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) { void menu_eggHatchScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* uiBigSprite, struct SpriteData* uiSmallSprite) {
static bool eggSpriteFrame = false; 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(); uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) { switch (pressedButtons) {
case K2_PRESSED: case K2_PRESSED:
screenKey = CLOCK_SCREEN; screenKey = CLOCK_SCREEN;
hatchSoundStarted = false;
hatchingFrame = 0;
hatchHoldStartTime = 0;
hatchAnimationLastFrameTime = 0;
break; break;
default: default:
@ -23,39 +37,58 @@ void menu_eggHatchScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData
} }
uint64_t currentTime = esp_timer_get_time(); uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) { if (hatchHoldStartTime > 0) {
if (charaData[currentCharacter].hatchTimer <= currentLine[currentCharacter]->hatchTime) { if (currentTime - hatchHoldStartTime > HATCH_COMPLETE_HOLD_TIME_US) {
draw_drawBackground(bg, 90, 90, 3); hatchHoldStartTime = 0;
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, eggSpriteFrame); hatchSoundStarted = false;
hatchingFrame = 0;
eggSpriteFrame = !eggSpriteFrame; hatchAnimationLastFrameTime = 0;
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);
lines_onHatchComplete(); 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; 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();
}
}

View File

@ -3,14 +3,13 @@
#include "display/display.h" #include "display/display.h"
#include "draw/draw.h" #include "draw/draw.h"
#include "menu.h" #include "menu.h"
#include "defs/sounds.h"
#include "vpet/vpet/vpet.h" #include "vpet/vpet/vpet.h"
void menu_foodScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, void menu_foodScreen(TFT_eSprite &bg, TFT_eSprite &mainChara,
struct SpriteData *spriteData) { struct SpriteData *spriteData) {
if (charaData[currentCharacter].sleepy) { if (charaData[currentCharacter].sleepy) {
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS); sound_playMelody(SOUND_BUTTON_BEEP, SOUND_NOTE_COUNT(SOUND_BUTTON_BEEP));
delay(100);
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
screenKey = MENU_SCREEN; screenKey = MENU_SCREEN;
return; return;
@ -20,19 +19,19 @@ void menu_foodScreen(TFT_eSprite &bg, TFT_eSprite &mainChara,
uint8_t pressedButtons = buttons_getPressedButtons(); uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) { switch (pressedButtons) {
case 8: case K1_PRESSED:
arrowPosition = (arrowPosition + 1) % 2; arrowPosition = (arrowPosition + 1) % 2;
break; break;
case 2: case K3_PRESSED:
screenKey = MENU_SCREEN; screenKey = MENU_SCREEN;
break; break;
default: default:
break; break;
} }
if (pressedButtons == 4) { if (pressedButtons == K2_PRESSED) {
lastUpdateTime = 0; lastUpdateTime = 0;
switch (arrowPosition) { switch (arrowPosition) {
case 0: case 0:
@ -91,4 +90,4 @@ void menu_foodScreen_drawEntry(TFT_eSprite &mainChara,
tft_clearBuffer(mainChara, TFT_TRANSPARENT); tft_clearBuffer(mainChara, TFT_TRANSPARENT);
draw_drawSprite(mainChara, 45, (entryId * 34) + 5, spriteData, spriteNumber); draw_drawSprite(mainChara, 45, (entryId * 34) + 5, spriteData, spriteNumber);
tft_drawText(textEntry, 4, 80, (entryId * 34) + 5); tft_drawText(textEntry, 4, 80, (entryId * 34) + 5);
} }

View File

@ -4,43 +4,39 @@
#include "display/display.h" #include "display/display.h"
#include "draw/draw.h" #include "draw/draw.h"
#include "animations/animations.h" #include "animations/animations.h"
#include "defs/sounds.h"
void menu_drawHappyScreen( void menu_drawHappyScreen(
TFT_eSprite& bg, TFT_eSprite &sprite, TFT_eSprite& bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements, const int returnScreen 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;
return; 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;
draw_drawBackground(bg, 90, 90, 3); 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); tft_clearBuffer(sprite, TFT_TRANSPARENT);
animate_performHappyAnimation(sprite, spriteData); draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
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;
} }
frameCounter++;
lastUpdateTime = currentTime;
tft_drawBuffer(); tft_drawBuffer();
} }
} }

View File

@ -60,9 +60,12 @@ void training_screenTraining2(
void menu_changeBackgroundScreen( void menu_changeBackgroundScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSpriteData 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_sleepAction();
void menu_sleepScreen_recalculateSleep(); void menu_sleepScreen_recalculateSleep();
void menu_freezeScreen_alternateFreeze(); void menu_freezeScreen_alternateFreeze();
#endif #endif

View File

@ -34,6 +34,9 @@ void menu_drawCurrentMenuOption(TFT_eSprite& bg, TFT_eSprite &icon, struct Sprit
// Separaíto mas guapito // Separaíto mas guapito
if (pressedButtons == K2_PRESSED) { if (pressedButtons == K2_PRESSED) {
const uint64_t currentTime = esp_timer_get_time();
lastUpdateTime = currentTime;
switch (menuKey) { switch (menuKey) {
case STATUS_SCREEN_MENU: case STATUS_SCREEN_MENU:
screenKey = STATUS_SCREEN; screenKey = STATUS_SCREEN;
@ -73,6 +76,12 @@ void menu_drawCurrentMenuOption(TFT_eSprite& bg, TFT_eSprite &icon, struct Sprit
return; return;
break; break;
case SETTINGS_SCREEN_MENU:
menuKey = STATUS_SCREEN;
screenKey = SETTINGS_SCREEN;
return;
break;
default: default:
break; break;
} }

View File

@ -9,51 +9,44 @@
void menu_clearPoopScreen( void menu_clearPoopScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements 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;
draw_drawBackground(bg, 90, 90, 3); menuKey = -1;
uint8_t offsetX = menu_poopOverlay(bg, sprite, smallUiElements); charaData[currentCharacter].poopNumber = 0;
initialized = false;
printf("[AAAAAAA] drawing animation...\n");
animate_performAnimation(sprite, spriteData, offsetX); return;
}
printf("[AAAAAAA] drawing overlay...\n"); uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 50000) {
menu_uiOverlay(sprite, bigUiElements);
printf("[AAAAAAA] idle screen down...\n");
tft_clearBuffer(sprite, TFT_TRANSPARENT);
while (cleanerXPos > 18 - 48) {
draw_drawBackgroundSection(bg, cleanerXPos + 6, 72, 48, 96); draw_drawBackgroundSection(bg, cleanerXPos + 6, 72, 48, 96);
draw_drawSprite(sprite, cleanerXPos, 72, smallUiElements, CLEANER_ICON); draw_drawSprite(sprite, cleanerXPos, 72, smallUiElements, CLEANER_ICON);
draw_drawSprite(sprite, cleanerXPos, 120, smallUiElements, CLEANER_ICON); draw_drawSprite(sprite, cleanerXPos, 120, smallUiElements, CLEANER_ICON);
draw_drawBackgroundSection(bg, 0, 72, 18, 96); draw_drawBackgroundSection(bg, 0, 72, 18, 96);
tft_drawBuffer(); tft_drawBuffer();
cleanerXPos -= 6; cleanerXPos -= 6;
lastUpdateTime = currentTime;
} }
}
screenKey = HAPPY_SCREEN;
menuKey = -1;
charaData[currentCharacter].poopNumber = 0;
vTaskResume(secondLoop);
return;
}

View File

@ -4,78 +4,72 @@
#include "display/display.h" #include "display/display.h"
#include "defs/defs.h" #include "defs/defs.h"
#include "defs/chara_data.h" #include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h" #include "defs/sprite_data.h"
void menu_poopScreen( void menu_poopScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements struct SpriteData* spriteData, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements
) { ) {
uint8_t animationFrame = 0; static uint8_t animationFrame = 0;
bool animationPosition = 0; static bool animationPosition = 0;
static bool beepedAlready = false;
bool beepedAlready = false; uint64_t currentTime = esp_timer_get_time();
while (1) { if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 4) {
uint64_t currentTime = esp_timer_get_time(); draw_drawBackground(bg, 90, 90, 3);
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 4) { tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawBackground(bg, 90, 90, 3); 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); tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements); menu_uiOverlay(sprite, bigUiElements);
animationFrame++;
animationPosition = !animationPosition;
lastUpdateTime = currentTime; animationFrame++;
animationPosition = !animationPosition;
} else if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 6) { lastUpdateTime = currentTime;
if (!beepedAlready) { tft_drawBuffer();
tone(SPK_PIN, 2500, 50);
tone(SPK_PIN, 5000, 50);
tone(SPK_PIN, 2500, 50);
tone(SPK_PIN, 5000, 50);
beepedAlready = true; } else if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 6) {
} if (!beepedAlready) {
sound_playMelody(SOUND_POOP_DROP, SOUND_NOTE_COUNT(SOUND_POOP_DROP));
draw_drawBackground(bg, 90, 90, 3); beepedAlready = true;
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;
} }
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(); 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;
} }
} }

View File

@ -3,6 +3,7 @@
#include "draw/draw.h" #include "draw/draw.h"
#include "display/display.h" #include "display/display.h"
#include "defs/defs.h" #include "defs/defs.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h" #include "defs/sprite_data.h"
#include "animations/animations.h" #include "animations/animations.h"
@ -34,8 +35,7 @@ void menu_refuseScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteDat
} }
if (!soundPlayed) { if (!soundPlayed) {
tone(SPK_PIN, 3000, 100); sound_playMelody(SOUND_REFUSE, SOUND_NOTE_COUNT(SOUND_REFUSE));
tone(SPK_PIN, 1000, 100);
soundPlayed = true; soundPlayed = true;
} }
@ -47,4 +47,4 @@ void menu_refuseScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteDat
} }
tft_drawBuffer(); tft_drawBuffer();
} }

View File

@ -0,0 +1,65 @@
#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:
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();
}

View File

@ -0,0 +1,102 @@
#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 uint8_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 maxItems = sizeof(menuItems) / sizeof(menuItems[0]);
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
arrowPosition = (arrowPosition + 1) % maxItems;
printf("[SETTINGS] arrowPosition=%i\n", arrowPosition);
break;
case K3_PRESSED:
screenKey = MENU_SCREEN;
return;
case K2_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 < maxItems; 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();
}

View File

@ -5,6 +5,7 @@
#include "buttons/buttons.h" #include "buttons/buttons.h"
#include "animations/animations.h" #include "animations/animations.h"
#include "defs/chara_data.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) { void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* charaSprites, struct SpriteData* uiSprites) {
if (!charaData[currentCharacter].asleep && !charaData[currentCharacter].sleepy) { if (!charaData[currentCharacter].asleep && !charaData[currentCharacter].sleepy) {
@ -45,8 +46,7 @@ void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
} }
if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) { if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) {
tone(SPK_PIN, 2500, 100); sound_playMelody(SOUND_CARE_ALERT, SOUND_NOTE_COUNT(SOUND_CARE_ALERT));
tone(SPK_PIN, 5000, 100);
lastBeepTime = currentTime; lastBeepTime = currentTime;

View File

@ -41,7 +41,7 @@ void menu_statusScreen_drawStat(TFT_eSprite &sprite, struct SpriteData* spriteDa
draw_drawSprite( draw_drawSprite(
sprite, sprite,
15 + (i * 32), 15 + (i * 48),
y + 30, y + 30,
spriteData, spriteData,
icon, icon,

View File

@ -11,6 +11,11 @@ void menu_drawTitle(TFT_eSprite &bg, TFT_eSprite &composite) {
return; return;
} }
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime < 200000) {
return;
}
draw_drawBackground(bg, 90, 90, 3); draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("NacaPet", 4, 40); tft_drawCenteredText("NacaPet", 4, 40);
@ -18,6 +23,5 @@ void menu_drawTitle(TFT_eSprite &bg, TFT_eSprite &composite) {
tft_drawCenteredText(VERSION, 2, 80); tft_drawCenteredText(VERSION, 2, 80);
tft_drawBuffer(); tft_drawBuffer();
lastUpdateTime = currentTime;
delay(200); }
}

View File

@ -1,6 +1,7 @@
#include "vpet/training/training.h" #include "vpet/training/training.h"
#include "defs/defs.h" #include "defs/defs.h"
#include "defs/chara_data.h" #include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h" #include "defs/sprite_data.h"
#include "buttons/buttons.h" #include "buttons/buttons.h"
#include "display/display.h" #include "display/display.h"
@ -15,9 +16,8 @@ void training_screenTraining1(
draw_drawBackground(bg, 90, 90, 3); draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, mainCharaData, 11); draw_drawSpriteCentered(sprite, mainCharaData, 11);
tone(SPK_PIN, 4100, 100); sound_playMelody(SOUND_TRAINING_START, SOUND_NOTE_COUNT(SOUND_TRAINING_START));
tone(SPK_PIN, 3500, 100);
tft_drawBuffer(); tft_drawBuffer();
@ -76,4 +76,4 @@ void training_screenTraining1(
} }
training_displayTrainingResult(bg, sprite, mainCharaData, attackSprites, attackResult); training_displayTrainingResult(bg, sprite, mainCharaData, attackSprites, attackResult);
} }

View File

@ -2,6 +2,7 @@
#include "vpet/training/training.h" #include "vpet/training/training.h"
#include "defs/defs.h" #include "defs/defs.h"
#include "defs/chara_data.h" #include "defs/chara_data.h"
#include "defs/sounds.h"
#include "draw/draw.h" #include "draw/draw.h"
#include "display/display.h" #include "display/display.h"
#include "buttons/buttons.h" #include "buttons/buttons.h"
@ -10,87 +11,98 @@ void training_screenTraining2(
TFT_eSprite &bg, TFT_eSprite &sprite, TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* mainCharaData, struct SpriteData* attackSprites 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;
// Player static uint64_t stageStartTime = 0;
draw_drawSprite(sprite, 174, 72, mainCharaData, 0, false); static uint8_t randomPosition = 0;
draw_drawBackgroundSection(bg, 222, 72, 18, 96); static uint8_t projectilePosition = 0;
// Opponent uint64_t currentTime = esp_timer_get_time();
draw_drawSprite(sprite, -30, 72, mainCharaData, 0, true);
draw_drawBackgroundSection(bg, 0, 72, 18, 96);
tft_drawBuffer(); if (state == TRAINING_INIT) {
draw_drawBackground(bg, 90, 90 ,3);
uint64_t inactivityTimer = esp_timer_get_time(); // Player
while (true) { draw_drawSprite(sprite, 174, 72, mainCharaData, 0, false);
uint64_t currentTime = esp_timer_get_time(); draw_drawBackgroundSection(bg, 222, 72, 18, 96);
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) { if (currentTime - inactivityTimer > 3000000) {
screenKey = MAIN_SCREEN; screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU; submenuKey = STATUS_SCREEN_MENU;
state = TRAINING_INIT;
vTaskResume(secondLoop);
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
printf("[TRAIN] projectilePosition=%i\n", projectilePosition);
} else if (pressedButtons == K3_PRESSED) {
screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU;
vTaskResume(secondLoop);
return; return;
} }
if (pressedButtons != 0) { uint8_t pressedButtons = buttons_getPressedButtons();
inactivityTimer = esp_timer_get_time(); if (pressedButtons == K1_PRESSED || pressedButtons == K2_PRESSED) {
randomPosition = rand() % 2;
projectilePosition = pressedButtons >> 3; // pressedButtons >> 4 == 1 => K1; != 1 => K2
printf("[TRAIN] projectilePosition=%i\n", projectilePosition);
inactivityTimer = currentTime;
// Player attack // Player attack
draw_drawSprite(sprite, 126, 72 + 48 * projectilePosition, attackSprites, POOP_ICON); draw_drawSprite(sprite, 126, 72 + 48 * projectilePosition, attackSprites, POOP_ICON);
// Opponent attack // Opponent attack
draw_drawSprite(sprite, 66, 72 + 48 * randomPosition, attackSprites, FOOD_ICON); draw_drawSprite(sprite, 66, 72 + 48 * randomPosition, attackSprites, FOOD_ICON);
tft_drawBuffer(); tft_drawBuffer();
if (projectilePosition != randomPosition) { stageStartTime = currentTime;
delay(500); state = TRAINING_SHOW_BOTH;
draw_drawBackgroundSection(bg, 126, 72 + 48 * projectilePosition, 48, 48); } else if (pressedButtons == K3_PRESSED) {
draw_drawSprite(sprite, 66, 72 + 48 * projectilePosition, attackSprites, POOP_ICON); screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU;
tft_drawBuffer(); state = TRAINING_INIT;
return;
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 (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
src/sound/sound.cpp Normal file
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
src/sound/sound.h Normal file
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();

View File

@ -218,4 +218,21 @@ void storage_loadState() {
storage_readFile(spriteFileName, &mainCharacterSprites); storage_readFile(spriteFileName, &mainCharacterSprites);
printf("%s Load completed!\n", TAG_S); 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;
}

View File

@ -13,5 +13,6 @@ void storage_initBackground(const int id, TFT_eSprite &bg);
void storage_saveState(); void storage_saveState();
void storage_loadState(); void storage_loadState();
bool storage_deleteState();
#endif #endif

View File

@ -2,6 +2,7 @@
#include "draw/draw.h" #include "draw/draw.h"
#include "defs/defs.h" #include "defs/defs.h"
#include "defs/chara_data.h" #include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h" #include "defs/sprite_data.h"
#include "display/display.h" #include "display/display.h"
@ -100,20 +101,5 @@ void training_displayTrainingResult(
// nOT FANCY // nOT FANCY
void training_trainingAttackSounds() { void training_trainingAttackSounds() {
tone(SPK_PIN, 4100, 25); sound_playMelody(SOUND_TRAINING_ATTACK, SOUND_NOTE_COUNT(SOUND_TRAINING_ATTACK));
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);
}