mirror of
https://github.com/nacabaro/nacapet.git
synced 2026-09-30 23:21:37 +00:00
Initial commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
#ifndef ANIMATIONS_H
|
||||
#define ANIMATIONS_H
|
||||
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
const int numFrames = 39;
|
||||
const int numFramesAngry = 2;
|
||||
const int numFramesEating = 2;
|
||||
const int numFramesHappy = 2;
|
||||
const int numFramesRefuse = 4;
|
||||
const int numFramesSleepy = 2;
|
||||
|
||||
// TODO: Cambiar a una animación mas atractiva
|
||||
const int animationFrames[numFrames] = {
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 7, 3, 7,
|
||||
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 7, 3, 7,
|
||||
1, 0, 1, 0, 1, 0, 1
|
||||
};
|
||||
// Asumiendo que el buffer es 240x240, dejando margen y los sprites son 96x96 (6 de factor)
|
||||
const int animationPositions[] = {
|
||||
72, 66, 60, 54, 48, 42, 36, 30, 24, 18, 24, 18,
|
||||
24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 120, 126,
|
||||
114, 108, 102, 96, 90, 84, 78
|
||||
};
|
||||
|
||||
const bool animationFlipSprites[numFrames] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
const int angryAnimationFrames[] = {
|
||||
8, 9
|
||||
};
|
||||
|
||||
const int eatingAnimationFrames[] = {
|
||||
3, 7
|
||||
};
|
||||
|
||||
const int refuseAnimationFrames[] = {
|
||||
6, 6, 6, 6
|
||||
};
|
||||
|
||||
const int refuseAnimationFlips[] = {
|
||||
0, 1, 0, 1
|
||||
};
|
||||
|
||||
const int sleepyAnimationFrames[] = {
|
||||
4, 5
|
||||
};
|
||||
|
||||
const int happyAnimationFrames[] = {
|
||||
3, 7
|
||||
};
|
||||
|
||||
void animate_performAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData, uint8_t offsetX);
|
||||
void animate_performAttentionAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData);
|
||||
void animate_performEatingAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData);
|
||||
void animate_performRefuseAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData);
|
||||
void animate_performSleepyAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData);
|
||||
void animate_performHappyAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "animations.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
#include "defs/sprite_data.h"
|
||||
|
||||
const char* TAG_A = "[ANIMATION]";
|
||||
const int spriteHeightOnScreen = 72;
|
||||
|
||||
int currentAnimationFrame = 0;
|
||||
|
||||
void animate_performAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData, uint8_t offsetX) {
|
||||
draw_drawSprite(
|
||||
buffer,
|
||||
spr,
|
||||
animationPositions[currentAnimationFrame] - offsetX,
|
||||
spriteHeightOnScreen,
|
||||
spriteData,
|
||||
animationFrames[currentAnimationFrame],
|
||||
6,
|
||||
animationFlipSprites[currentAnimationFrame]
|
||||
);
|
||||
|
||||
currentAnimationFrame = (currentAnimationFrame + 1) % numFrames;
|
||||
}
|
||||
|
||||
void animate_performAttentionAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData) {
|
||||
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesAngry;
|
||||
draw_drawSprite(
|
||||
buffer,
|
||||
spr,
|
||||
spriteHeightOnScreen,
|
||||
spriteHeightOnScreen,
|
||||
spriteData,
|
||||
angryAnimationFrames[currentAnimationFrame],
|
||||
6,
|
||||
animationFlipSprites[currentAnimationFrame]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void animate_performEatingAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData) {
|
||||
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesEating;
|
||||
draw_drawSprite(
|
||||
buffer,
|
||||
spr,
|
||||
spriteHeightOnScreen,
|
||||
spriteHeightOnScreen,
|
||||
spriteData,
|
||||
eatingAnimationFrames[currentAnimationFrame],
|
||||
6,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
void animate_performRefuseAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData) {
|
||||
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesRefuse;
|
||||
draw_drawSprite(
|
||||
buffer,
|
||||
spr,
|
||||
spriteHeightOnScreen,
|
||||
spriteHeightOnScreen,
|
||||
spriteData,
|
||||
refuseAnimationFrames[currentAnimationFrame],
|
||||
6,
|
||||
refuseAnimationFlips[currentAnimationFrame]
|
||||
);
|
||||
}
|
||||
|
||||
void animate_performSleepyAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData) {
|
||||
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesSleepy;
|
||||
draw_drawSprite(
|
||||
buffer,
|
||||
spr,
|
||||
spriteHeightOnScreen,
|
||||
spriteHeightOnScreen,
|
||||
spriteData,
|
||||
sleepyAnimationFrames[currentAnimationFrame],
|
||||
6,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
void animate_performHappyAnimation(TFT_eSprite &buffer, TFT_eSprite &spr, struct SpriteData* spriteData) {
|
||||
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesHappy;
|
||||
draw_drawSprite(
|
||||
buffer,
|
||||
spr,
|
||||
spriteHeightOnScreen,
|
||||
spriteHeightOnScreen,
|
||||
spriteData,
|
||||
happyAnimationFrames[currentAnimationFrame],
|
||||
6,
|
||||
false
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include "defs/defs.h"
|
||||
#include "buttons.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
uint64_t lastPressedButtonTime = esp_timer_get_time();
|
||||
|
||||
bool inactive = false;
|
||||
bool screenOff = false;
|
||||
|
||||
bool k1_prev = HIGH;
|
||||
bool k2_prev = HIGH;
|
||||
bool k3_prev = HIGH;
|
||||
bool k4_prev = HIGH;
|
||||
|
||||
void buttons_checkInactivity() {
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US && !screenOff) {
|
||||
digitalWrite(BL_PIN, LOW);
|
||||
screenKey = OFF_SCREEN;
|
||||
screenOff = true;
|
||||
|
||||
} else if (currentTime - lastPressedButtonTime > LAST_PRESSED_BUTTON_THRESHOLD_TIME_US && !inactive) {
|
||||
screenKey = IDLE_SCREEN;
|
||||
inactive = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t buttons_getPressedButtons() {
|
||||
bool k1_current = digitalRead(K1_PIN);
|
||||
bool k2_current = digitalRead(K2_PIN);
|
||||
bool k3_current = digitalRead(K3_PIN);
|
||||
bool k4_current = digitalRead(K4_PIN);
|
||||
|
||||
uint8_t retV = (
|
||||
(k1_prev == HIGH && k1_current == LOW) << 3 |
|
||||
(k2_prev == HIGH && k2_current == LOW) << 2 |
|
||||
(k3_prev == HIGH && k3_current == LOW) << 1 |
|
||||
(k4_prev == HIGH && k4_current == LOW)
|
||||
);
|
||||
|
||||
if (retV != 0) {
|
||||
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
|
||||
lastPressedButtonTime = esp_timer_get_time();
|
||||
inactive = false;
|
||||
screenOff = false;
|
||||
}
|
||||
|
||||
k1_prev = k1_current;
|
||||
k2_prev = k2_current;
|
||||
k3_prev = k3_current;
|
||||
k4_prev = k4_current;
|
||||
|
||||
delay(15);
|
||||
|
||||
return retV;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef BUTTONS_H
|
||||
#define BUTTONS_H
|
||||
|
||||
uint8_t buttons_getPressedButtons();
|
||||
void buttons_checkInactivity();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "debug.h"
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
|
||||
void debug_printFreeMemory() {
|
||||
size_t freeMemory = esp_get_free_heap_size();
|
||||
printf("[DEBUG] Free memory: %zu bytes\n", freeMemory);
|
||||
}
|
||||
|
||||
void debug_printAllSprites(uint16_t** sprite, uint8_t numSprites, uint8_t width, uint8_t height) {
|
||||
for (uint8_t i = 0; i < numSprites; i++) {
|
||||
printf("[DEBUG] Sprite %d:\n", i);
|
||||
for (uint8_t y = 0; y < height; y++) {
|
||||
printf("[DEBUG] Row %d: ", y);
|
||||
for (uint8_t x = 0; x < width; x++) {
|
||||
printf("%04X ", sprite[i][y * width + x]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void debug_printFreeMemory();
|
||||
void debug_printAllSprites(uint16_t** sprite, uint8_t numSprites, uint8_t width, uint8_t height);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef BACKGROUND_DATA_H
|
||||
#define BACKGROUND_DATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct BackgroundData {
|
||||
uint8_t backgroundWidth;
|
||||
uint8_t backgroundHeight;
|
||||
uint8_t scaleFactor;
|
||||
uint16_t* backgroundData;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef CHARA_DATA_H
|
||||
#define CHARA_DATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct CharacterData {
|
||||
// Calculated at runtime
|
||||
uint8_t hunger;
|
||||
uint8_t strength;
|
||||
uint8_t effort;
|
||||
uint8_t careMistakes;
|
||||
uint8_t weight;
|
||||
uint8_t age;
|
||||
uint8_t poopNumber;
|
||||
|
||||
int32_t sleepCareMistakeCounter = 0;
|
||||
int32_t evoLeftTimer;
|
||||
int16_t hungerCareMistakeTimer;
|
||||
int16_t strengthCareMistakeTimer;
|
||||
|
||||
bool gotLifeYearAdded = false;
|
||||
bool hungerCareMistakeObtained = false;
|
||||
bool strengthCareMistakeObtained = false;
|
||||
bool sleepCareMistakeObtained = false;
|
||||
bool careMistakeCallLight = false;
|
||||
|
||||
bool sleepy = false;
|
||||
bool asleep = false;
|
||||
bool injured = false;
|
||||
bool dead = false;
|
||||
|
||||
// Obtained from structure
|
||||
uint8_t idLine;
|
||||
uint8_t idChara;
|
||||
char charaName[40];
|
||||
uint8_t hp;
|
||||
uint8_t ap;
|
||||
uint8_t bp;
|
||||
uint8_t stage;
|
||||
uint8_t attribute;
|
||||
|
||||
uint32_t sleepTime = 75600;
|
||||
uint32_t wakeupTime = 25200;
|
||||
|
||||
uint32_t evoTime;
|
||||
|
||||
uint16_t initialStatsReductionTime = 600;
|
||||
};
|
||||
|
||||
#endif
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
#ifndef DEFS_H
|
||||
#define DEFS_H
|
||||
|
||||
#include <ESP32Time.h>
|
||||
#include <MPU6050.h>
|
||||
|
||||
#include "defs/background_data.h"
|
||||
#include "defs/sprite_data.h"
|
||||
|
||||
#define VERSION "Alpha v0.1"
|
||||
|
||||
// SCREEN PINOUT
|
||||
#define SCL_PIN 34
|
||||
#define SDA_PIN 35
|
||||
#define RST_PIN 32
|
||||
#define BL_PIN 25
|
||||
|
||||
// BUTTONS PINOUT
|
||||
#define K1_PIN 33
|
||||
#define K2_PIN 35
|
||||
#define K3_PIN 34
|
||||
#define K4_PIN 32
|
||||
|
||||
// SPEAKER PINOUT
|
||||
#define SPK_PIN 21
|
||||
|
||||
// MPU6050 PINOUT
|
||||
#define MPU_SCL_PIN 4
|
||||
#define MPU_SDA_PIN 16
|
||||
#define MPU_INT_PIN 12
|
||||
|
||||
// SPECIAL SCREEN THAT OPENS WHEN TIMERS ARE DONE
|
||||
// RECEIVES AN EXTRA PARAMETER (INTERRUPTKEY)
|
||||
#define TIMER_FINISHED_SCREEN 999
|
||||
|
||||
// ANIMATION FRAMERATE DEFINITION IN µS
|
||||
#define ANIMATION_THRESHOLD_TIME_US 500000
|
||||
#define ANIMATION_SLEEPY_THRESHOLD_TIME_US 2500000
|
||||
|
||||
// INACTIVITY TIMERS (LAST TIME A BUTTON WAS PRESSED)
|
||||
#define LAST_PRESSED_BUTTON_THRESHOLD_TIME_US 10000000
|
||||
#define INACTIVITY_THRESHOLD_TIME_US 30000000
|
||||
|
||||
// RTC TIMEOUT WHEN TIME NOT DEFINED
|
||||
#define RTC_TIMEOUT_THRESHOLD_TIME_MS 100
|
||||
|
||||
// STANDARD BEEP WHEN PRESSING BUTTON
|
||||
#define BEEP_FREQ_HZ 3000
|
||||
#define BEEP_LEN_MS 50
|
||||
|
||||
// MENU ENTRIES
|
||||
#define STATUS_SCREEN_MENU 0
|
||||
#define FOOD_SCREEN_MENU 1
|
||||
#define TRAIN_SCREEN_MENU 2
|
||||
#define BATTLE_SCREEN_MENU 3
|
||||
#define POOP_SCREEN_MENU 4
|
||||
#define MEDICAL_SCREEN_MENU 5
|
||||
#define SLEEP_SCREEN_MENU 6
|
||||
#define SETTINGS_SCREEN_MENU 7
|
||||
|
||||
// SCREENS THAT OPEN AFTER CLICKING ON A MENU ENTRY
|
||||
#define STATUS_SCREEN 10
|
||||
#define FOOD_SCREEN 11
|
||||
#define TRAIN_SCREEN 12
|
||||
#define BATTLE_SCREEN 13
|
||||
#define CLEAR_POOP_SCREEN 14
|
||||
#define MEDICAL_SCREEN 15
|
||||
#define SLEEP_SCREEN 16
|
||||
#define SETTINGS_SCREEN 17
|
||||
|
||||
// ICONS FOR EACH MENU ENTRY (MENU.BIN)
|
||||
#define STATUS_SCREEN_ICON 0
|
||||
#define FOOD_SCREEN_ICON 1
|
||||
#define TRAIN_SCREEN_ICON 2
|
||||
#define BATTLE_SCREEN_ICON 3
|
||||
#define CLEAR_POOP_ICON 4
|
||||
#define MEDICAL_SCREEN_ICON 5
|
||||
#define SLEEP_SCREEN_ICON 6
|
||||
#define SETTINGS_SCREEN_ICON 7
|
||||
#define CARE_MISTAKE_CALL_LIGHT 8
|
||||
#define BED_SPRITE 9
|
||||
|
||||
// SCREENS
|
||||
#define OFF_SCREEN -1
|
||||
#define TITLE_SCREEN 0
|
||||
#define CLOCK_EDIT_SCREEN 1
|
||||
#define CLOCK_SCREEN 2
|
||||
#define IDLE_SCREEN 3
|
||||
#define MENU_SCREEN 4
|
||||
#define FEEDING_SCREEN 20
|
||||
#define REFUSING_SCREEN 21
|
||||
#define SLEEPY_SCREEN 22
|
||||
#define CARE_MISTAKE_SCREEN 23
|
||||
#define POOPING_SCREEN 24
|
||||
#define HAPPY_SCREEN 25
|
||||
|
||||
// SMALL UI ICONS (UI.BIN)
|
||||
#define POOP_ICON 0
|
||||
#define FOOD_ICON 1
|
||||
#define PILL_ICON 2
|
||||
#define ZZZ_ICON 3
|
||||
#define AGE_ICON 4
|
||||
#define SCALE_ICON 5
|
||||
#define ARROW_ICON 6
|
||||
#define FIREWORKS_ICON 7
|
||||
#define COMPLAIN_ICON 8
|
||||
#define FULL_HEART_ICON 9
|
||||
#define EMPTY_HEART_ICON 10
|
||||
#define CLEANER_ICON 11
|
||||
|
||||
// STANDARD VPET PARAMETER (CARE MISTAKES)
|
||||
#define CARE_MISTAKE_COUNTER_MAX 60
|
||||
#define SLEEP_CARE_MISTAKE_COUNTER_MAX 60
|
||||
#define SLEEP_COUNTER_MAX 120
|
||||
|
||||
// ATTACK PATTERNS
|
||||
#define ATTACK_PATTERN_MEDIOCRE 0
|
||||
#define ATTACK_PATTERN_BAD 1
|
||||
#define ATTACK_PATTERN_GOOD 2
|
||||
#define ATTACK_PATTERN_GREAT 3
|
||||
#define ATTACK_PATTERN_EXCELLENT 4
|
||||
|
||||
// BUTTON PRESSES DEFINITIONS
|
||||
#define K1_PRESSED 8
|
||||
#define K2_PRESSED 4
|
||||
#define K3_PRESSED 2
|
||||
#define K4_PRESSED 1
|
||||
#define NONE_PRESSED 0
|
||||
|
||||
extern int screenKey;
|
||||
extern int menuKey;
|
||||
extern int submenuKey;
|
||||
extern int interruptKey;
|
||||
|
||||
extern bool k1_prev;
|
||||
extern bool k2_prev;
|
||||
extern bool k3_prev;
|
||||
extern bool k4_prev;
|
||||
|
||||
extern bool inactive;
|
||||
extern bool screenOff;
|
||||
|
||||
extern uint64_t lastPressedButtonTime;
|
||||
extern uint64_t lastUpdateTime;
|
||||
extern uint64_t lastBeepTime;
|
||||
|
||||
extern struct CharacterData charaData;
|
||||
extern struct tm timeInfo;
|
||||
extern uint32_t dayUnixTime;
|
||||
|
||||
extern ESP32Time rtc;
|
||||
extern MPU6050 mpu;
|
||||
|
||||
extern hw_timer_t *actionTimerDelta;
|
||||
|
||||
extern bool runVpetTasks;
|
||||
|
||||
extern uint8_t beepCounter;
|
||||
|
||||
extern uint16_t stepCounter;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef EVO_DATA_H
|
||||
#define EVO_DATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct EvoData {
|
||||
uint8_t charaId;
|
||||
uint8_t charaNextId;
|
||||
uint8_t maxCareMistakes;
|
||||
uint8_t maxSleepInterruptions;
|
||||
uint8_t maxOverfeed;
|
||||
uint8_t minWonBattles;
|
||||
uint8_t minTotalBattles;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef SPRITE_DATA_H
|
||||
#define SPRITE_DATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct SpriteData {
|
||||
uint8_t spriteWidth;
|
||||
uint8_t spriteHeight;
|
||||
uint8_t spriteNumber;
|
||||
uint16_t** spriteData;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "display.h"
|
||||
|
||||
void tft_initDisplay(TFT_eSPI &tft, uint16_t color) {
|
||||
tft.init();
|
||||
tft.setRotation(0);
|
||||
tft.fillScreen(TFT_RED);
|
||||
}
|
||||
|
||||
void tft_initScreenBuffer(TFT_eSprite &buffer, uint16_t color) {
|
||||
buffer.createSprite(SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
|
||||
buffer.fillSprite(color);
|
||||
buffer.setTextColor(TFT_BLACK);
|
||||
buffer.setTextSize(4);
|
||||
buffer.pushSprite(0, 0);
|
||||
}
|
||||
|
||||
void tft_drawBuffer(TFT_eSprite &buffer) {
|
||||
buffer.pushSprite(0, 0);
|
||||
}
|
||||
|
||||
void tft_clearBuffer(TFT_eSprite &buffer, uint16_t color) {
|
||||
buffer.fillSprite(color);
|
||||
}
|
||||
|
||||
void tft_drawCenteredText(TFT_eSprite &buffer, const char* text, int factor, int y) {
|
||||
size_t textWidth = strlen(text) * factor * 6;
|
||||
int x = (SCREEN_WIDTH - textWidth) / 2;
|
||||
buffer.setTextSize(factor);
|
||||
buffer.drawString(text, x, y);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
const int SCREEN_WIDTH = 240;
|
||||
const int SCREEN_HEIGHT = 240;
|
||||
|
||||
void tft_initDisplay(TFT_eSPI &tft, uint16_t color = TFT_WHITE);
|
||||
void tft_initScreenBuffer(TFT_eSprite &spr, uint16_t color = TFT_WHITE);
|
||||
void tft_drawBuffer(TFT_eSprite &buffer);
|
||||
void tft_clearBuffer(TFT_eSprite &buffer, uint16_t color = TFT_WHITE);
|
||||
void tft_drawCenteredText(TFT_eSprite &buffer, const char* text, int factor, int y);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef DRAW_H
|
||||
#define DRAW_H
|
||||
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
void draw_drawSprite(
|
||||
TFT_eSprite &buffer, TFT_eSprite &tft,
|
||||
int x, int y,
|
||||
struct SpriteData* spriteData, uint8_t spriteNumber,
|
||||
uint8_t factor, bool flipHorizontal = false
|
||||
);
|
||||
void draw_drawBackground(TFT_eSprite &buffer, TFT_eSprite &bg, int spr_w, int spr_h, int factor);
|
||||
void draw_drawSpriteCentered(
|
||||
TFT_eSprite &buffer, TFT_eSprite &spr,
|
||||
struct SpriteData* spriteData, uint8_t spriteNumber, uint8_t factor, bool flipped = false, int y = -1
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "draw.h"
|
||||
|
||||
const char* TAG_DB = "[DRAW BG]";
|
||||
|
||||
|
||||
void draw_drawBackground(TFT_eSprite &buffer, TFT_eSprite &bg, int spr_w, int spr_h, int factor) {
|
||||
int scaledWidth = spr_w * factor;
|
||||
int scaledHeight = spr_h * factor;
|
||||
|
||||
for (int sy = 0; sy < scaledHeight; sy++) {
|
||||
for (int sx = 0; sx < scaledWidth; sx++) {
|
||||
int srcX = sx / factor;
|
||||
int srcY = sy / factor;
|
||||
|
||||
uint16_t color = bg.readPixel(srcX, srcY);
|
||||
buffer.drawPixel(sx, sy, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "draw.h"
|
||||
|
||||
#include "defs/sprite_data.h"
|
||||
|
||||
const char* TAG_D = "[DRAW]";
|
||||
|
||||
void draw_drawSprite(
|
||||
TFT_eSprite &buffer, TFT_eSprite &spr, int x, int y,
|
||||
struct SpriteData* spriteData, uint8_t spriteNumber, uint8_t factor, bool flipHorizontal
|
||||
) {
|
||||
int scaledWidth = spriteData->spriteWidth * factor;
|
||||
int scaledHeight = spriteData->spriteHeight * factor;
|
||||
|
||||
spr.createSprite(scaledWidth, scaledHeight);
|
||||
|
||||
for (int sy = 0; sy < scaledHeight; sy++) {
|
||||
for (int sx = 0; sx < scaledWidth; sx++) {
|
||||
int srcX = sx / factor;
|
||||
if (flipHorizontal) {
|
||||
srcX = (spriteData->spriteWidth - 1) - srcX;
|
||||
}
|
||||
|
||||
int srcY = sy / factor;
|
||||
|
||||
uint16_t color = spriteData->spriteData
|
||||
[spriteNumber]
|
||||
[srcY * spriteData->spriteWidth + srcX];
|
||||
|
||||
spr.drawPixel(sx, sy, color);
|
||||
}
|
||||
}
|
||||
|
||||
spr.pushToSprite(&buffer, x, y, TFT_TRANSPARENT);
|
||||
|
||||
//printf("%s: Sprite %d drawn at (%d, %d) %s\n", TAG_D, spriteNumber, x, y, (flipHorizontal ? "flipped" : ""));
|
||||
}
|
||||
|
||||
void draw_drawSpriteCentered(
|
||||
TFT_eSprite &buffer, TFT_eSprite &spr,
|
||||
struct SpriteData* spriteData, uint8_t spriteNumber, uint8_t factor, bool flipped, int y
|
||||
) {
|
||||
int x = (TFT_WIDTH - (spriteData->spriteWidth * factor)) / 2;
|
||||
int new_y;
|
||||
if (y == -1) {
|
||||
new_y = (TFT_HEIGHT - (spriteData->spriteHeight * factor)) / 2;
|
||||
} else {
|
||||
new_y = y;
|
||||
}
|
||||
|
||||
draw_drawSprite(
|
||||
buffer, spr, x, new_y,
|
||||
spriteData, spriteNumber, factor, flipped
|
||||
);
|
||||
}
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
#include <Arduino.h>
|
||||
#include "display/display.h"
|
||||
#include "memory/memory.h"
|
||||
#include "storage/storage.h"
|
||||
#include "animations/animations.h"
|
||||
#include "debug/debug.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "menu/menu.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "vpet/vpet.h"
|
||||
#include "vpet/steps/steps.h"
|
||||
|
||||
const char* TAG = "[MAIN]";
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite composite = TFT_eSprite(&tft);
|
||||
TFT_eSprite sprite = TFT_eSprite(&tft);
|
||||
TFT_eSprite bg = TFT_eSprite(&tft);
|
||||
|
||||
struct BackgroundData backgroundData;
|
||||
struct SpriteData mainCharacterSprites;
|
||||
struct SpriteData menuElementsData;
|
||||
struct SpriteData uiElementsData;
|
||||
|
||||
struct CharacterData charaData;
|
||||
|
||||
int screenKey = TITLE_SCREEN;
|
||||
int menuKey = STATUS_SCREEN_MENU;
|
||||
int submenuKey = -1;
|
||||
|
||||
uint32_t dayUnixTime = 0;
|
||||
uint16_t stepCounter = 0;
|
||||
|
||||
struct tm timeInfo;
|
||||
|
||||
MPU6050 mpu;
|
||||
ESP32Time rtc(0);
|
||||
TaskHandle_t secondLoop = NULL;
|
||||
|
||||
void loop2();
|
||||
void secondCoreTask(void*);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(100); // Give MPU6050 and ESP32 time to power up
|
||||
|
||||
Wire.begin(MPU_SDA_PIN, MPU_SCL_PIN); // I2C init before MPU6050
|
||||
mpu.initialize();
|
||||
|
||||
tft_initDisplay(tft, TFT_BLACK);
|
||||
tft_initScreenBuffer(composite, TFT_BLACK);
|
||||
|
||||
storage_init();
|
||||
|
||||
storage_readFile("/sprite.bin", &mainCharacterSprites);
|
||||
storage_readFile("/menu.bin", &menuElementsData);
|
||||
storage_readFile("/ui.bin", &uiElementsData);
|
||||
|
||||
storage_initBackground("/bg.bin", bg);
|
||||
|
||||
debug_printFreeMemory();
|
||||
|
||||
pinMode(K1_PIN, INPUT_PULLUP);
|
||||
pinMode(K2_PIN, INPUT_PULLUP);
|
||||
pinMode(K3_PIN, INPUT_PULLUP);
|
||||
pinMode(K4_PIN, INPUT_PULLUP);
|
||||
|
||||
charaData.hunger = 4;
|
||||
charaData.strength = 4;
|
||||
charaData.effort = 4;
|
||||
|
||||
charaData.evoLeftTimer = 60;
|
||||
charaData.hungerCareMistakeTimer = 60;
|
||||
charaData.strengthCareMistakeTimer = 60;
|
||||
|
||||
xTaskCreatePinnedToCore(secondCoreTask, "VPET_EVAL", 4096, NULL, 0, &secondLoop, 0);
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
switch (screenKey) {
|
||||
case TITLE_SCREEN:
|
||||
menu_drawTitle(composite, bg);
|
||||
break;
|
||||
|
||||
case CLOCK_EDIT_SCREEN:
|
||||
menu_drawClockEdit(composite, bg);
|
||||
break;
|
||||
|
||||
case CLOCK_SCREEN:
|
||||
menu_drawClock(composite, bg, menuKey);
|
||||
break;
|
||||
|
||||
case IDLE_SCREEN:
|
||||
menu_drawIdleScreen(composite, bg, sprite, &mainCharacterSprites, &menuElementsData, &uiElementsData);
|
||||
break;
|
||||
|
||||
case MENU_SCREEN:
|
||||
menu_drawCurrentMenuOption(composite, bg, sprite, &menuElementsData);
|
||||
break;
|
||||
|
||||
case STATUS_SCREEN:
|
||||
menu_statusScreen(composite, bg, sprite, &uiElementsData, &charaData);
|
||||
break;
|
||||
|
||||
case OFF_SCREEN:
|
||||
menu_offScreen(composite);
|
||||
break;
|
||||
|
||||
case TIMER_FINISHED_SCREEN:
|
||||
menu_timerFinishedScreen(composite, bg, sprite, &mainCharacterSprites);
|
||||
break;
|
||||
|
||||
case FOOD_SCREEN:
|
||||
menu_foodScreen(composite, bg, sprite, &uiElementsData);
|
||||
break;
|
||||
|
||||
case FEEDING_SCREEN:
|
||||
menu_feedingScreen(composite, bg, sprite, &uiElementsData, &mainCharacterSprites, submenuKey);
|
||||
break;
|
||||
|
||||
case REFUSING_SCREEN:
|
||||
menu_refuseScreen(composite, bg, sprite, &mainCharacterSprites);
|
||||
break;
|
||||
|
||||
case SLEEPY_SCREEN:
|
||||
menu_sleepyScreen(composite, bg, sprite, &mainCharacterSprites, &menuElementsData);
|
||||
break;
|
||||
|
||||
case SLEEP_SCREEN:
|
||||
menu_sleepingScreen(composite, bg, sprite, &mainCharacterSprites, &menuElementsData, &uiElementsData);
|
||||
break;
|
||||
|
||||
case CARE_MISTAKE_SCREEN:
|
||||
menu_careMistakeScreen(composite, bg, sprite, &mainCharacterSprites, &menuElementsData);
|
||||
break;
|
||||
|
||||
case POOPING_SCREEN:
|
||||
menu_poopScreen(composite, bg, sprite, &mainCharacterSprites, &uiElementsData, &menuElementsData);
|
||||
break;
|
||||
|
||||
case CLEAR_POOP_SCREEN:
|
||||
menu_clearPoopScreen(composite, bg, sprite, &mainCharacterSprites, &menuElementsData, &uiElementsData);
|
||||
break;
|
||||
|
||||
case HAPPY_SCREEN:
|
||||
menu_drawHappyScreen(composite, bg, sprite, &mainCharacterSprites, &uiElementsData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void loop2() {
|
||||
steps_countSteps();
|
||||
buttons_checkInactivity();
|
||||
vpet_runVpetTasks();
|
||||
}
|
||||
|
||||
void secondCoreTask(void*) {
|
||||
for (;;) { loop2(); }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "memory.h"
|
||||
|
||||
const char* TAG_M = "[MEMORY]";
|
||||
|
||||
|
||||
uint16_t** memory_allocate(uint8_t numSprite, uint8_t width, uint8_t height) {
|
||||
uint16_t** ptr = (uint16_t**) malloc(numSprite * sizeof(uint16_t*));
|
||||
if (ptr == NULL) {
|
||||
printf("%s Memory allocation failed\n", TAG_M);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < numSprite; i++) {
|
||||
ptr[i] = (uint16_t*) malloc(width * height * sizeof(uint16_t));
|
||||
|
||||
if (ptr[i] == NULL) {
|
||||
printf("%s Memory allocation failed for sprite %d\n", TAG_M, i);
|
||||
for (uint8_t j = 0; j < i; j++) {
|
||||
free(ptr[j]);
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s Allocated %zu bytes at %p\n", TAG_M, numSprite * (width * height * 2), ptr);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void memory_free(uint8_t* ptr) {
|
||||
if (ptr != NULL) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
} else {
|
||||
printf("%s Pointer is already NULL\n", TAG_M);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct spriteData {
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
uint8_t number;
|
||||
uint16_t** data;
|
||||
};
|
||||
|
||||
uint16_t** memory_allocate(uint8_t numSprite, uint8_t width, uint8_t height);
|
||||
void memory_free(uint8_t* ptr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "menu.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "animations/animations.h"
|
||||
#include "display/display.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "draw/draw.h"
|
||||
|
||||
uint64_t lastBeepTime = esp_timer_get_time();
|
||||
uint8_t beepCounter = 0;
|
||||
|
||||
void menu_careMistakeScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* uiSpritesBig) {
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
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);
|
||||
|
||||
lastBeepTime = currentTime;
|
||||
|
||||
beepCounter++;
|
||||
}
|
||||
|
||||
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
animate_performAttentionAnimation(composite, sprite, spriteData);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
menu_uiOverlay(composite, sprite, uiSpritesBig);
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
}
|
||||
|
||||
if (pressedButtons != 0) {
|
||||
screenKey = IDLE_SCREEN;
|
||||
beepCounter = 0;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "menu.h"
|
||||
#include "defs/defs.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "vpet/vpet.h"
|
||||
|
||||
void menu_drawClock(TFT_eSprite &composite, TFT_eSprite &bg, int menuOption) {
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
switch (pressedButtons) {
|
||||
case 4:
|
||||
screenKey = IDLE_SCREEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
char hourBuffer[6];
|
||||
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
snprintf(hourBuffer, 6, "%02d:%02d", timeInfo.tm_hour, timeInfo.tm_min);
|
||||
composite.setTextSize(4);
|
||||
composite.drawString(hourBuffer, 40, 90);
|
||||
|
||||
sniprintf(hourBuffer, 3, "%02d", timeInfo.tm_sec);
|
||||
composite.setTextSize(2);
|
||||
composite.drawString(hourBuffer, 170, 104);
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
|
||||
}
|
||||
|
||||
void menu_drawClockEdit(TFT_eSprite &composite, TFT_eSprite &bg) {
|
||||
char textBuffer[6];
|
||||
|
||||
static int clockHourCount = 0;
|
||||
static int clockMinuteCount = 0;
|
||||
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
lastPressedButtonTime = esp_timer_get_time();
|
||||
|
||||
switch (pressedButtons) {
|
||||
case 8:
|
||||
clockHourCount = (clockHourCount + 1) % 24;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
clockMinuteCount = (clockMinuteCount + 1) % 60;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rtc.setTime(0, clockMinuteCount, clockHourCount, 1, 11, 2024);
|
||||
getLocalTime(&timeInfo, 50);
|
||||
dayUnixTime = mktime(&timeInfo) % 86400;
|
||||
|
||||
screenKey = CLOCK_SCREEN;
|
||||
onActionTimerDelta();
|
||||
vpet_initTimer();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
snprintf(textBuffer, 6, "%02d:%02d", clockHourCount, clockMinuteCount);
|
||||
|
||||
composite.setTextSize(4);
|
||||
composite.drawString(textBuffer, 40, 90);
|
||||
composite.drawString("SET", 40, 122);
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "menu.h"
|
||||
#include "animations/animations.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
|
||||
void menu_feedingScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &charaSprite,
|
||||
struct SpriteData* uiSpriteData, struct SpriteData* charaSpriteData, uint8_t item
|
||||
) {
|
||||
static int currentAnimationFrame = 0;
|
||||
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
switch (pressedButtons) {
|
||||
case 8:
|
||||
case 4:
|
||||
screenKey = FOOD_SCREEN;
|
||||
currentAnimationFrame = 0;
|
||||
lastPressedButtonTime = currentTime;
|
||||
submenuKey = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(charaSprite, TFT_TRANSPARENT);
|
||||
animate_performEatingAnimation(composite, charaSprite, charaSpriteData);
|
||||
|
||||
tft_clearBuffer(charaSprite, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, charaSprite, 24, 120, uiSpriteData, item, 6);
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
currentAnimationFrame++;
|
||||
}
|
||||
|
||||
if (currentAnimationFrame > 6) {
|
||||
screenKey = FOOD_SCREEN;
|
||||
lastPressedButtonTime = currentTime;
|
||||
currentAnimationFrame = 0;
|
||||
submenuKey = -1;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "menu.h"
|
||||
#include "display/display.h"
|
||||
#include "draw/draw.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "vpet/vpet.h"
|
||||
|
||||
void menu_foodScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData* spriteData) {
|
||||
if (charaData.sleepy) {
|
||||
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
|
||||
delay(100);
|
||||
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
|
||||
screenKey = MENU_SCREEN;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static uint8_t arrowPosition = 0;
|
||||
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
switch (pressedButtons) {
|
||||
case 8:
|
||||
arrowPosition = (arrowPosition + 1) % 2;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
screenKey = MENU_SCREEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pressedButtons == 4) {
|
||||
switch(arrowPosition) {
|
||||
case 0:
|
||||
if (charaData.hunger < 8) {
|
||||
charaData.weight++;
|
||||
charaData.hunger++;
|
||||
screenKey = FEEDING_SCREEN;
|
||||
submenuKey = FOOD_ICON;
|
||||
} else {
|
||||
screenKey = REFUSING_SCREEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (charaData.strength < 8) {
|
||||
charaData.strength++;
|
||||
charaData.weight += 2;
|
||||
screenKey = FEEDING_SCREEN;
|
||||
submenuKey = PILL_ICON;
|
||||
} else {
|
||||
screenKey = REFUSING_SCREEN;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
vpet_computeCallLight();
|
||||
}
|
||||
|
||||
composite.setTextSize(4);
|
||||
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
menu_foodScreen_drawEntry(composite, mainChara, spriteData, 0, FOOD_ICON, "Meat");
|
||||
menu_foodScreen_drawEntry(composite, mainChara, spriteData, 1, PILL_ICON, "Pill");
|
||||
|
||||
draw_drawSprite(composite, mainChara, 5, (arrowPosition * 34) + 5, spriteData, ARROW_ICON, 4);
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
|
||||
void menu_foodScreen_drawEntry(
|
||||
TFT_eSprite &composite, TFT_eSprite &mainChara, struct SpriteData* spriteData,
|
||||
uint8_t entryId, uint8_t spriteNumber, const char* textEntry
|
||||
) {
|
||||
tft_clearBuffer(mainChara, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, mainChara, 45, (entryId * 34) + 5, spriteData, spriteNumber, 4);
|
||||
composite.drawString(textEntry, 80, (entryId * 34) + 5);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "menu.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/sprite_data.h"
|
||||
#include "display/display.h"
|
||||
#include "draw/draw.h"
|
||||
#include "animations/animations.h"
|
||||
|
||||
void menu_drawHappyScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* spriteData, struct SpriteData* smallUiElements
|
||||
) {
|
||||
uint8_t frameCounter = 0;
|
||||
|
||||
while (true) {
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
|
||||
if (frameCounter > 3) {
|
||||
screenKey = IDLE_SCREEN; // TODO: Change for while battling
|
||||
menuKey = STATUS_SCREEN;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
animate_performHappyAnimation(composite, 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(composite, sprite, 18, 72, smallUiElements, FIREWORKS_ICON, 6);
|
||||
draw_drawSprite(composite, sprite, 174, 72, smallUiElements, FIREWORKS_ICON, 6);
|
||||
}
|
||||
|
||||
frameCounter++;
|
||||
lastUpdateTime = currentTime;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "menu.h"
|
||||
#include "draw/draw.h"
|
||||
#include "defs/defs.h"
|
||||
#include "display/display.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "animations/animations.h"
|
||||
#include "defs/chara_data.h"
|
||||
|
||||
uint64_t lastUpdateTime = esp_timer_get_time();
|
||||
|
||||
void menu_drawIdleScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements) {
|
||||
if (charaData.sleepy && !charaData.asleep) {
|
||||
screenKey = SLEEPY_SCREEN;
|
||||
return;
|
||||
} else if ((charaData.sleepy && charaData.asleep) || charaData.asleep) {
|
||||
screenKey = SLEEP_SCREEN;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
|
||||
switch (pressedButtons) {
|
||||
case 8:
|
||||
screenKey = MENU_SCREEN;
|
||||
menuKey = 0;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
screenKey = CLOCK_SCREEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
|
||||
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
uint8_t offsetX = menu_poopOverlay(composite, sprite, smallUiElements);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
animate_performAnimation(composite, sprite, spriteData, offsetX);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
menu_uiOverlay(composite, sprite, bigUiElements);
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef MENU_H
|
||||
#define MENU_H
|
||||
|
||||
#include <TFT_eSPI.h>
|
||||
#include "defs/defs.h"
|
||||
|
||||
void menu_drawCurrentMenuOption(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &icon, struct SpriteData* spriteData);
|
||||
void menu_drawClock(TFT_eSprite &composite, TFT_eSprite &bg, int menuOption);
|
||||
void menu_drawClockEdit(TFT_eSprite &composite, TFT_eSprite &bg);
|
||||
void menu_drawTitle(TFT_eSprite &composite, TFT_eSprite &bg);
|
||||
void menu_drawIdleScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements);
|
||||
void menu_offScreen(TFT_eSprite &buffer);
|
||||
void menu_statusScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct CharacterData* charaData);
|
||||
void menu_statusScreen_drawStat(TFT_eSprite &composite, TFT_eSprite &sprite, struct SpriteData* spriteData, int x, int y, const char* text, uint8_t statValue);
|
||||
void menu_timerFinishedScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData);
|
||||
void menu_uiOverlay(TFT_eSprite &composite, TFT_eSprite &charSprite, struct SpriteData* uiElements);
|
||||
void menu_foodScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData* spriteData);
|
||||
void menu_foodScreen_drawEntry(
|
||||
TFT_eSprite &composite, TFT_eSprite &mainChara, struct SpriteData* spriteData,
|
||||
uint8_t entryId, uint8_t spriteNumber, const char* textEntry
|
||||
);
|
||||
void menu_feedingScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &charaSprite,
|
||||
struct SpriteData* uiSpriteData, struct SpriteData* charaSpriteData, uint8_t item
|
||||
);
|
||||
void menu_refuseScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData* spriteData);
|
||||
void menu_sleepyScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* charaSprites, struct SpriteData* uiSprites);
|
||||
void menu_careMistakeScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* uiSpritesBig);
|
||||
void menu_sleepingScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* mainCharaData, struct SpriteData* bigUiElements, struct SpriteData* smallUIElements
|
||||
);
|
||||
void menu_poopScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* spriteData, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements
|
||||
);
|
||||
uint8_t menu_poopOverlay(TFT_eSprite &composite, TFT_eSprite &sprite, struct SpriteData* smallUiElements);
|
||||
void menu_clearPoopScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements);
|
||||
void menu_drawHappyScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* spriteData, struct SpriteData* smallUiElements
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
#include "menu.h"
|
||||
#include "display/display.h"
|
||||
#include "draw/draw.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/sprite_data.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "vpet/vpet.h"
|
||||
#include <string.h>
|
||||
|
||||
const int textXPos = 10;
|
||||
const int textYPos = 180;
|
||||
|
||||
void menu_drawCurrentMenuOption(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &icon, struct SpriteData* spriteData) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
|
||||
switch (pressedButtons) {
|
||||
case 8:
|
||||
menuKey++;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
screenKey = IDLE_SCREEN;
|
||||
menuKey = STATUS_SCREEN_MENU;
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (pressedButtons == 4) {
|
||||
switch (menuKey) {
|
||||
case STATUS_SCREEN_MENU:
|
||||
screenKey = STATUS_SCREEN;
|
||||
break;
|
||||
|
||||
case FOOD_SCREEN_MENU:
|
||||
screenKey = FOOD_SCREEN;
|
||||
break;
|
||||
|
||||
case SLEEP_SCREEN_MENU:
|
||||
charaData.asleep = true;
|
||||
vpet_computeCallLight();
|
||||
menuKey = STATUS_SCREEN;
|
||||
screenKey = SLEEP_SCREEN;
|
||||
break;
|
||||
|
||||
case POOP_SCREEN_MENU:
|
||||
menuKey = STATUS_SCREEN;
|
||||
screenKey = CLEAR_POOP_SCREEN;
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
composite.setTextSize(4);
|
||||
draw_drawSpriteCentered(composite, icon, spriteData, menuKey % 8, 6);
|
||||
|
||||
switch(menuKey % 9) {
|
||||
case STATUS_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Status", 4, textYPos);
|
||||
break;
|
||||
|
||||
case FOOD_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Food", 4, textYPos);
|
||||
break;
|
||||
|
||||
case TRAIN_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Train", 4, textYPos);
|
||||
break;
|
||||
|
||||
case BATTLE_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Battle", 4, textYPos);
|
||||
break;
|
||||
|
||||
case POOP_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Cleanup", 4, textYPos);
|
||||
break;
|
||||
|
||||
case MEDICAL_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Medical", 4, textYPos);
|
||||
break;
|
||||
|
||||
case SLEEP_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Sleep", 4, textYPos);
|
||||
break;
|
||||
|
||||
case SETTINGS_SCREEN_MENU:
|
||||
tft_drawCenteredText(composite, "Settings", 4, textYPos);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
menuKey = 0;
|
||||
screenKey = IDLE_SCREEN;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
menu_uiOverlay(composite, icon, spriteData);
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "menu.h"
|
||||
#include "defs/defs.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "display/display.h"
|
||||
|
||||
void menu_offScreen(TFT_eSprite &buffer) {
|
||||
uint8_t buttons = buttons_getPressedButtons();
|
||||
if (buttons != 0) {
|
||||
tft_drawBuffer(buffer);
|
||||
digitalWrite(BL_PIN, HIGH);
|
||||
screenKey = IDLE_SCREEN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "menu.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "defs/sprite_data.h"
|
||||
|
||||
void menu_clearPoopScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements
|
||||
) {
|
||||
int cleanerXPos = 174;
|
||||
|
||||
menu_drawIdleScreen(composite, bg, sprite, spriteData, bigUiElements, smallUiElements);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
while (cleanerXPos > 18) {
|
||||
draw_drawSprite(composite, sprite, cleanerXPos, 72, smallUiElements, CLEANER_ICON, 6);
|
||||
draw_drawSprite(composite, sprite, cleanerXPos, 120, smallUiElements, CLEANER_ICON, 6);
|
||||
tft_drawBuffer(composite);
|
||||
cleanerXPos -= 6;
|
||||
delay(50);
|
||||
}
|
||||
|
||||
screenKey = HAPPY_SCREEN;
|
||||
charaData.poopNumber = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "menu.h"
|
||||
#include "draw/draw.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/sprite_data.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "display/display.h"
|
||||
|
||||
uint8_t menu_poopOverlay(TFT_eSprite &composite, TFT_eSprite &sprite, struct SpriteData* smallUiElements) {
|
||||
static bool poopFlip = false;
|
||||
const uint8_t poopStartY = 120;
|
||||
uint8_t poopStartX = 174;
|
||||
bool poopTop = false;
|
||||
|
||||
for (int i = 0; i < charaData.poopNumber; i++) {
|
||||
draw_drawSprite(composite, sprite, poopStartX, poopStartY - (48 * poopTop), smallUiElements, POOP_ICON, 6, poopFlip);
|
||||
poopStartX -= (i % 2) * 48;
|
||||
poopTop = !poopTop;
|
||||
}
|
||||
|
||||
poopFlip = !poopFlip;
|
||||
|
||||
return 222 - (poopStartX + ((charaData.poopNumber % 2 == 0) * 48));
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#include "menu.h"
|
||||
#include "draw/draw.h"
|
||||
#include "animations/animations.h"
|
||||
#include "display/display.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "defs/sprite_data.h"
|
||||
|
||||
void menu_poopScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* spriteData, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements
|
||||
) {
|
||||
uint8_t animationFrame = 0;
|
||||
bool animationPosition = 0;
|
||||
|
||||
bool beepedAlready = false;
|
||||
|
||||
while (1) {
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
|
||||
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 4) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, sprite, 72 + (animationPosition * 6), 72, spriteData, 6, 6);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
menu_uiOverlay(composite, sprite, bigUiElements);
|
||||
|
||||
animationFrame++;
|
||||
animationPosition = !animationPosition;
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
|
||||
} 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(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, sprite, 174, 120, smallUiElements, POOP_ICON, 6);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
menu_uiOverlay(composite, sprite, bigUiElements);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, sprite, 72, 72, spriteData, 7, 6);
|
||||
|
||||
animationFrame++;
|
||||
animationPosition = !animationPosition;
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
|
||||
} else if (animationFrame >= 6) {
|
||||
if (
|
||||
(charaData.hunger == 0 && !charaData.hungerCareMistakeObtained) ||
|
||||
(charaData.strength == 0 && !charaData.strengthCareMistakeObtained) ||
|
||||
(charaData.sleepy && !charaData.asleep && !charaData.sleepCareMistakeObtained)
|
||||
) {
|
||||
screenKey = CARE_MISTAKE_SCREEN;
|
||||
} else {
|
||||
screenKey = IDLE_SCREEN;
|
||||
}
|
||||
|
||||
menuKey = 0;
|
||||
animationFrame = 0;
|
||||
animationPosition = 0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "menu.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/sprite_data.h"
|
||||
#include "animations/animations.h"
|
||||
|
||||
void menu_refuseScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData* spriteData) {
|
||||
static uint8_t currentAnimationFrame = 0;
|
||||
static bool soundPlayed = false;
|
||||
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
switch (pressedButtons) {
|
||||
case 8:
|
||||
case 4:
|
||||
currentAnimationFrame = 0;
|
||||
screenKey = FOOD_SCREEN;
|
||||
soundPlayed = false;
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
animate_performRefuseAnimation(composite, mainChara, spriteData);
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
currentAnimationFrame++;
|
||||
}
|
||||
|
||||
if (!soundPlayed) {
|
||||
tone(SPK_PIN, 3000, 100);
|
||||
tone(SPK_PIN, 1000, 100);
|
||||
|
||||
soundPlayed = true;
|
||||
}
|
||||
|
||||
if (currentAnimationFrame > 4) {
|
||||
currentAnimationFrame = 0;
|
||||
soundPlayed = false;
|
||||
screenKey = IDLE_SCREEN;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "menu.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
#include "defs/defs.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "animations/animations.h"
|
||||
#include "defs/chara_data.h"
|
||||
|
||||
void menu_sleepyScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* charaSprites, struct SpriteData* uiSprites) {
|
||||
if (!charaData.asleep && !charaData.sleepy) {
|
||||
screenKey = IDLE_SCREEN;
|
||||
return;
|
||||
} else if (charaData.asleep && charaData.sleepy) {
|
||||
screenKey = SLEEP_SCREEN;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
switch (pressedButtons) {
|
||||
case 8:
|
||||
screenKey = MENU_SCREEN;
|
||||
break;
|
||||
case 4:
|
||||
screenKey = CLOCK_SCREEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentTime - lastUpdateTime > ANIMATION_SLEEPY_THRESHOLD_TIME_US) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
animate_performSleepyAnimation(composite, sprite, charaSprites);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
menu_uiOverlay(composite, sprite, uiSprites);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
menu_uiOverlay(composite, sprite, uiSprites);
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
}
|
||||
|
||||
if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) {
|
||||
tone(SPK_PIN, 2500, 100);
|
||||
tone(SPK_PIN, 5000, 100);
|
||||
|
||||
lastBeepTime = currentTime;
|
||||
|
||||
beepCounter++;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "menu.h"
|
||||
#include "defs/defs.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "animations/animations.h"
|
||||
#include "defs/chara_data.h"
|
||||
|
||||
void menu_sleepingScreen(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* mainCharaData, struct SpriteData* bigUiElements, struct SpriteData* smallUIElements
|
||||
) {
|
||||
if (charaData.sleepy && !charaData.asleep) {
|
||||
screenKey = SLEEPY_SCREEN;
|
||||
return;
|
||||
} else if (!charaData.sleepy && !charaData.asleep) {
|
||||
screenKey = IDLE_SCREEN;
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
static uint8_t frameCounter = 0;
|
||||
|
||||
uint8_t buttonsPressed = buttons_getPressedButtons();
|
||||
switch (buttonsPressed) {
|
||||
case 8:
|
||||
screenKey = MENU_SCREEN;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
screenKey = CLOCK_SCREEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentTime - lastUpdateTime > ANIMATION_SLEEPY_THRESHOLD_TIME_US) {
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
animate_performSleepyAnimation(composite, sprite, mainCharaData);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, sprite, 72, 72, bigUiElements, BED_SPRITE, 6);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, sprite, 172, 72, smallUIElements, ZZZ_ICON, 6);
|
||||
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
menu_uiOverlay(composite, sprite, bigUiElements);
|
||||
|
||||
lastUpdateTime = currentTime;
|
||||
}
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "menu.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/sprite_data.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "buttons/buttons.h"
|
||||
#include "display/display.h"
|
||||
#include "draw/draw.h"
|
||||
|
||||
void menu_statusScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct CharacterData* charaData) {
|
||||
tft_clearBuffer(sprite, TFT_TRANSPARENT);
|
||||
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
switch (pressedButtons) {
|
||||
case 2:
|
||||
screenKey = MENU_SCREEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
composite.setTextSize(4);
|
||||
|
||||
menu_statusScreen_drawStat(composite, sprite, spriteData, 10, 10, "Hunger", charaData->hunger);
|
||||
menu_statusScreen_drawStat(composite, sprite, spriteData, 10, 80, "Strength", charaData->strength);
|
||||
menu_statusScreen_drawStat(composite, sprite, spriteData, 10, 150, "Effort", charaData->effort);
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
|
||||
void menu_statusScreen_drawStat(TFT_eSprite &composite, TFT_eSprite &sprite, struct SpriteData* spriteData, int x, int y, const char* text, uint8_t statValue) {
|
||||
uint8_t icon;
|
||||
|
||||
composite.drawString(text, x, y);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i < statValue) { icon = FULL_HEART_ICON; }
|
||||
else { icon = EMPTY_HEART_ICON; }
|
||||
|
||||
draw_drawSprite(
|
||||
composite,
|
||||
sprite,
|
||||
15 + (i * 32),
|
||||
y + 30,
|
||||
spriteData,
|
||||
icon,
|
||||
4,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "menu.h"
|
||||
|
||||
int interruptKey = -1;
|
||||
|
||||
void menu_timerFinishedScreen(TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData) {
|
||||
lastPressedButtonTime = esp_timer_get_time();
|
||||
digitalWrite(BL_PIN, HIGH);
|
||||
|
||||
screenOff = false;
|
||||
inactive = false;
|
||||
|
||||
beepCounter = 0;
|
||||
|
||||
screenKey = interruptKey;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "menu.h"
|
||||
#include "display/display.h"
|
||||
#include "draw/draw.h"
|
||||
#include "defs/defs.h"
|
||||
#include "buttons/buttons.h"
|
||||
|
||||
void menu_drawTitle(TFT_eSprite &composite, TFT_eSprite &bg) {
|
||||
uint8_t pressedButtons = buttons_getPressedButtons();
|
||||
lastPressedButtonTime = esp_timer_get_time();
|
||||
|
||||
if (pressedButtons == 8 || pressedButtons == 4) {
|
||||
screenKey = CLOCK_EDIT_SCREEN;
|
||||
}
|
||||
|
||||
draw_drawBackground(composite, bg, 90, 90, 3);
|
||||
|
||||
composite.setTextSize(4);
|
||||
tft_drawCenteredText(composite, "NacaPet", 4, 40);
|
||||
|
||||
composite.setTextSize(2);
|
||||
tft_drawCenteredText(composite, VERSION, 2, 80);
|
||||
|
||||
tft_drawBuffer(composite);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "menu.h"
|
||||
#include "draw/draw.h"
|
||||
#include "display/display.h"
|
||||
#include "defs/chara_data.h"
|
||||
|
||||
void menu_uiOverlay(TFT_eSprite &composite, TFT_eSprite &charSprite, struct SpriteData* uiElements) {
|
||||
struct tm timeInfo;
|
||||
char hourBuffer[6];
|
||||
|
||||
composite.setTextSize(2);
|
||||
composite.setTextColor(TFT_WHITE);
|
||||
composite.fillRect(0, 0, 240, 24, TFT_BLACK);
|
||||
|
||||
getLocalTime(&timeInfo, RTC_TIMEOUT_THRESHOLD_TIME_MS);
|
||||
snprintf(hourBuffer, 6, "%02d:%02d", timeInfo.tm_hour, timeInfo.tm_min);
|
||||
|
||||
composite.drawString(hourBuffer, 4, 4);
|
||||
|
||||
snprintf(hourBuffer, 6, "%05d", stepCounter);
|
||||
|
||||
composite.drawString(hourBuffer, 176, 4);
|
||||
|
||||
composite.setTextColor(TFT_BLACK);
|
||||
if (charaData.careMistakeCallLight) {
|
||||
tft_clearBuffer(charSprite, TFT_TRANSPARENT);
|
||||
draw_drawSprite(composite, charSprite, 192, 192, uiElements, CARE_MISTAKE_CALL_LIGHT, 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "storage.h"
|
||||
#include "memory/memory.h"
|
||||
#include "defs/sprite_data.h"
|
||||
|
||||
const char* TAG_S = "[STORAGE]";
|
||||
|
||||
void storage_init() {
|
||||
if (!SPIFFS.begin(true)) {
|
||||
printf("%s Failed to mount file system\n", TAG_S);
|
||||
} else {
|
||||
printf("%s File system mounted successfully\n", TAG_S);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t bytesRead = 0;
|
||||
size_t fileSize = file.size();
|
||||
|
||||
bytesRead += file.read(&spriteData->spriteWidth, 1);
|
||||
bytesRead += file.read(&spriteData->spriteHeight, 1);
|
||||
bytesRead += file.read(&spriteData->spriteNumber, 1);
|
||||
|
||||
printf("%s Read header: width=%d, height=%d, numSprites=%d\n",
|
||||
TAG_S, spriteData->spriteWidth, spriteData->spriteHeight, spriteData->spriteNumber);
|
||||
|
||||
fileSize = (fileSize - 3) / sizeof(uint16_t);
|
||||
|
||||
spriteData->spriteData = memory_allocate(spriteData->spriteNumber, spriteData->spriteWidth, spriteData->spriteHeight);
|
||||
|
||||
size_t bufferSize = spriteData->spriteNumber * spriteData->spriteWidth * spriteData->spriteHeight;
|
||||
|
||||
uint8_t highByte;
|
||||
uint8_t lowByte;
|
||||
|
||||
for (int sprN = 0; sprN < spriteData->spriteNumber; sprN++) {
|
||||
for (int i = 0; i < spriteData->spriteWidth * spriteData->spriteHeight; i++) {
|
||||
bytesRead += file.read(&highByte, 1);
|
||||
bytesRead += file.read(&lowByte, 1);
|
||||
|
||||
uint16_t pixel = (highByte << 8) | lowByte;
|
||||
|
||||
if (i < bufferSize) {
|
||||
(spriteData->spriteData)[sprN][i] = pixel;
|
||||
} else {
|
||||
printf("%s Buffer overflow, skipping pixel\n", TAG_S);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s Read %zu bytes from file %s\n", TAG_S, bytesRead, path);
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t bytesRead = 0;
|
||||
|
||||
size_t fileSize = file.size();
|
||||
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
|
||||
bytesRead += file.read(&width, 1);
|
||||
bytesRead += file.read(&height, 1);
|
||||
|
||||
printf("%s Read header: width=%d, height=%d\n", TAG_S, width, height);
|
||||
|
||||
fileSize = (fileSize - 2) / sizeof(uint16_t);
|
||||
|
||||
bg.createSprite(width, height);
|
||||
|
||||
for(int i = 0; i < width * height; i++) {
|
||||
uint8_t highByte;
|
||||
uint8_t lowByte;
|
||||
|
||||
bytesRead += file.read(&highByte, 1);
|
||||
bytesRead += file.read(&lowByte, 1);
|
||||
|
||||
uint16_t pixel = (highByte << 8) | lowByte;
|
||||
|
||||
if (i < fileSize) {
|
||||
bg.drawPixel(i % width, i / width, pixel);
|
||||
} else {
|
||||
printf("%s Buffer overflow, skipping pixel\n", TAG_S);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s Read %zu bytes from file %s\n", TAG_S, bytesRead, path);
|
||||
|
||||
file.close();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef STORAGE_H
|
||||
#define STORAGE_H
|
||||
|
||||
#include <SPIFFS.h>
|
||||
#include <stdio.h>
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
#include "defs/sprite_data.h"
|
||||
|
||||
void storage_init();
|
||||
void storage_readFile(const char* path, struct SpriteData* spriteData);
|
||||
void storage_initBackground(const char* path, TFT_eSprite& bg);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "steps.h"
|
||||
#include "defs/defs.h"
|
||||
|
||||
float gravity = 0.0;
|
||||
const float alpha = 0.99;
|
||||
const float thresh = 0.80;
|
||||
uint64_t lastStepTime = esp_timer_get_time();
|
||||
|
||||
|
||||
void steps_countSteps() {
|
||||
int16_t ax, ay, az;
|
||||
mpu.getAcceleration(&ax, &ay, &az);
|
||||
|
||||
float axg = ax / 16384.0;
|
||||
float ayg = ay / 16384.0;
|
||||
float azg = az / 16384.0;
|
||||
|
||||
float mag = sqrt(axg*axg + ayg*ayg + azg*azg);
|
||||
|
||||
gravity = alpha * gravity + (1 - alpha) * mag;
|
||||
|
||||
float dyn = mag - gravity;
|
||||
|
||||
unsigned long now = esp_timer_get_time();
|
||||
if (dyn > thresh && (now - lastStepTime) > 500000) {
|
||||
stepCounter++;
|
||||
lastStepTime = now;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef STEPS_H
|
||||
#define STEPS_H
|
||||
|
||||
void steps_countSteps();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef TRAINING_H
|
||||
#define TRAINING_H
|
||||
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
void training_screenTraining1(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "training.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/chara_data.h"
|
||||
#include "defs/sprite_data.h"
|
||||
#include "buttons/buttons.h"
|
||||
|
||||
void training_screenTraining1(
|
||||
TFT_eSprite &composite, TFT_eSprite &bg, TFT_eSprite &sprite,
|
||||
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
|
||||
) {
|
||||
uint8_t attackPower = 0;
|
||||
|
||||
while (true) {
|
||||
uint8_t buttonsRead = buttons_getPressedButtons();
|
||||
switch (buttonsRead)
|
||||
{
|
||||
case 8:
|
||||
attackPower++;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
screenKey = IDLE_SCREEN;
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t currentTime = esp_timer_get_time();
|
||||
if (currentTime - lastUpdateTime > 10000000) {
|
||||
// Display attack animation...
|
||||
// NOT YET SLOW DOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "vpet.h"
|
||||
#include "defs/defs.h"
|
||||
#include "defs/chara_data.h"
|
||||
|
||||
hw_timer_t *actionTimerDelta = NULL;
|
||||
bool runVpetTasks = false;
|
||||
|
||||
void vpet_initTimer() {
|
||||
printf("[TIMER] Timer Init.\n");
|
||||
actionTimerDelta = timerBegin(0, 80, true);
|
||||
timerAttachInterrupt(actionTimerDelta, &onActionTimerDelta, true);
|
||||
timerAlarmWrite(actionTimerDelta, 1000000, true);
|
||||
timerAlarmEnable(actionTimerDelta);
|
||||
}
|
||||
|
||||
void vpet_computeCallLight() {
|
||||
charaData.careMistakeCallLight = (
|
||||
(charaData.hunger == 0 && !charaData.hungerCareMistakeObtained) ||
|
||||
(charaData.strength == 0 && !charaData.strengthCareMistakeObtained) ||
|
||||
(charaData.sleepy && !charaData.asleep && !charaData.sleepCareMistakeObtained)
|
||||
);
|
||||
}
|
||||
|
||||
bool vpet_evalSleep() {
|
||||
// Se devuelve true si quieres pausar los otros contadores
|
||||
// False ejecutara los contadores correspondientes
|
||||
if (
|
||||
dayUnixTime < charaData.sleepTime &&
|
||||
dayUnixTime > charaData.wakeupTime &&
|
||||
charaData.sleepy
|
||||
// Esto se ejecuta cuando ya es hora de despertarse
|
||||
// Resultado el personaje se despierta
|
||||
) {
|
||||
charaData.sleepCareMistakeCounter = 0;
|
||||
charaData.sleepCareMistakeObtained = false;
|
||||
charaData.gotLifeYearAdded = false;
|
||||
|
||||
charaData.sleepy = false;
|
||||
charaData.asleep = false;
|
||||
|
||||
return false;
|
||||
|
||||
} else if (
|
||||
dayUnixTime < charaData.sleepTime &&
|
||||
dayUnixTime > charaData.wakeupTime &&
|
||||
charaData.asleep &&
|
||||
charaData.sleepCareMistakeCounter < 60
|
||||
// Esto se ejecuta cuando mandamos a dormir al personaje
|
||||
// durante el dia.
|
||||
// Resultado, el personaje deberia de dormir una siesta
|
||||
) {
|
||||
charaData.sleepCareMistakeCounter++;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (
|
||||
dayUnixTime < charaData.sleepTime &&
|
||||
dayUnixTime > charaData.wakeupTime &&
|
||||
charaData.asleep &&
|
||||
charaData.sleepCareMistakeCounter >= 60
|
||||
// Esto se ejecuta cuando la siesta del personaje acaba
|
||||
// Resultado, el personaje se despierta
|
||||
) {
|
||||
charaData.sleepCareMistakeCounter = 0;
|
||||
charaData.asleep = false;
|
||||
|
||||
return false;
|
||||
|
||||
} else if (
|
||||
(
|
||||
dayUnixTime > charaData.sleepTime ||
|
||||
dayUnixTime < charaData.wakeupTime
|
||||
) &&
|
||||
!charaData.sleepy
|
||||
// Esto se ejecuta cuando la hora actual del sistema
|
||||
// está en el intervalo temporal de las horas el las que el
|
||||
// personaje duerme
|
||||
// Resultado: el personaje se duerme, y se llama a la pantalla
|
||||
// de se acabo el temporizador, ademas activa la call light
|
||||
) {
|
||||
charaData.sleepy = true;
|
||||
charaData.careMistakeCallLight = true;
|
||||
|
||||
screenKey = TIMER_FINISHED_SCREEN;
|
||||
interruptKey = SLEEPY_SCREEN;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (
|
||||
charaData.sleepy && !charaData.asleep &&
|
||||
charaData.sleepCareMistakeCounter < 60 &&
|
||||
!charaData.sleepCareMistakeObtained
|
||||
// Esto se ejecuta cuando el personaje debería de estar durmiendo
|
||||
// pero no se le ha mandado a dormir, empieza a contar para pasar
|
||||
// un care mistake
|
||||
) {
|
||||
charaData.sleepCareMistakeCounter++;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (
|
||||
charaData.sleepy && !charaData.asleep &&
|
||||
charaData.sleepCareMistakeCounter >= 60 &&
|
||||
!charaData.sleepCareMistakeObtained
|
||||
// Esto se ejecuta cuando el personaje deberia de estar durmiendo
|
||||
// pero no se le ha mandado a dormir, y el contador ya ha llegado
|
||||
// al tiempo maximo
|
||||
// Resultado: se añade el care mistake y se activa la flag para
|
||||
// evitar otro care mistake
|
||||
) {
|
||||
charaData.sleepCareMistakeObtained = true;
|
||||
charaData.careMistakes++;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (
|
||||
!charaData.gotLifeYearAdded &&
|
||||
dayUnixTime < 1 // This stinks
|
||||
// Esto se ejecuta cuando es media noche.
|
||||
// Resultado: se incrementa la edad por 1
|
||||
) {
|
||||
charaData.age++;
|
||||
charaData.gotLifeYearAdded = true;
|
||||
|
||||
return true;
|
||||
|
||||
} else if (
|
||||
charaData.sleepy
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void vpet_evalTimers() {
|
||||
if (charaData.hungerCareMistakeTimer >= 0) {
|
||||
charaData.hungerCareMistakeTimer -= 1;
|
||||
}
|
||||
|
||||
if (charaData.strengthCareMistakeTimer >= 0) {
|
||||
charaData.strengthCareMistakeTimer -= 1;
|
||||
}
|
||||
|
||||
if (
|
||||
charaData.hungerCareMistakeTimer < 0 ||
|
||||
charaData.strengthCareMistakeTimer < 0
|
||||
) {
|
||||
if (charaData.hunger > 0) {
|
||||
charaData.hunger--;
|
||||
screenKey = TIMER_FINISHED_SCREEN;
|
||||
interruptKey = POOPING_SCREEN;
|
||||
charaData.poopNumber++;
|
||||
charaData.hungerCareMistakeTimer = 60;
|
||||
}
|
||||
|
||||
if (!charaData.hungerCareMistakeObtained) {
|
||||
if (
|
||||
charaData.hunger == 0 &&
|
||||
charaData.hungerCareMistakeTimer < 0
|
||||
) {
|
||||
charaData.careMistakes++;
|
||||
charaData.hungerCareMistakeObtained = true;
|
||||
|
||||
} else if (charaData.hunger == 0) {
|
||||
interruptKey = POOPING_SCREEN;
|
||||
screenKey = TIMER_FINISHED_SCREEN;
|
||||
charaData.poopNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
if (charaData.strength > 0) {
|
||||
charaData.strength--;
|
||||
charaData.strengthCareMistakeTimer = 60;
|
||||
}
|
||||
|
||||
if (!charaData.strengthCareMistakeObtained) {
|
||||
if (
|
||||
charaData.strength == 0 &&
|
||||
charaData.strengthCareMistakeTimer < 0
|
||||
) {
|
||||
charaData.careMistakes++;
|
||||
charaData.strengthCareMistakeObtained = true;
|
||||
|
||||
} else if(charaData.strength == 0) {
|
||||
if (interruptKey != POOPING_SCREEN) {
|
||||
interruptKey = CARE_MISTAKE_SCREEN;
|
||||
screenKey = TIMER_FINISHED_SCREEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR onActionTimerDelta() {
|
||||
runVpetTasks = true;
|
||||
}
|
||||
|
||||
void vpet_runVpetTasks() {
|
||||
if (runVpetTasks) {
|
||||
vpet_computeCallLight();
|
||||
if (!vpet_evalSleep()) {
|
||||
vpet_evalTimers();
|
||||
}
|
||||
printf("[MAIN]: Hunger timer %d, hunger %d\n", charaData.hungerCareMistakeTimer, charaData.hunger);
|
||||
printf("[MAIN]: Strength timer %d, strength %d\n", charaData.strengthCareMistakeTimer, charaData.strength);
|
||||
printf("[MAIN]: Evo timer %d\n", charaData.evoLeftTimer);
|
||||
printf("[MAIN]: RTC time is %d\n", dayUnixTime);
|
||||
printf("[MAIN]: Sleep counter is %d\n", charaData.sleepCareMistakeCounter);
|
||||
printf("[MAIN]: Care mistake count is %d\n", charaData.careMistakes);
|
||||
printf("[MAIN]: Is sleep care mistake tripped? %d\n", charaData.sleepCareMistakeObtained);
|
||||
|
||||
runVpetTasks = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef VPET_H
|
||||
#define VPET_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
void IRAM_ATTR onActionTimerDelta();
|
||||
void vpet_initTimer();
|
||||
void vpet_computeCallLight();
|
||||
bool vpet_evalSleep();
|
||||
void vpet_evalTimers();
|
||||
void vpet_runVpetTasks();
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user