Compare commits

..
23 Commits
Author SHA1 Message Date
nacabaro 4b869f22f3 Update gitignore 2026-06-01 11:51:57 +02:00
nacabaro cde99fc554 Add partition table for the supermini 2026-06-01 11:50:21 +02:00
nacabaro 91e00bea43 Change button mappings 2026-05-29 22:46:12 +02:00
nacabaro 94c4543b59 A few things:
- Add a way to reset data from the device itself
- Fix bug in the background selector screen
- Remove blocking methods, make everything non-blocking, should improve stability in general
- Change sound effects, and put them together in the same file, using the new system, instead of doing multiple calls to the tone function
- Fix overlapping icons in the status screen, need to continue this and fix the overlapping text
2026-05-29 02:21:41 +02:00
nacabaro 915c5cd2a7 Switch the name of the disallow sleep flag 2026-05-29 02:17:32 +02:00
nacabaro 79d60e7201 Improve sound system thing in here 2026-05-29 02:16:58 +02:00
nacabaro 3de6c121a5 Add ALLOW_SLEEP flag to enable sleep mode in inactivity checks 2026-05-28 21:35:41 +02:00
nacabaro f15ea8190f Update food select screen to use precompiler parameters 2026-05-28 21:35:00 +02:00
nacabaro 9c4520e4e0 Fix issue with the background select screen
- Has a non existent background and also does not render first time
2026-05-28 21:34:35 +02:00
nacabaro 60c1659875 Enhance tft_drawText function to support background color 2026-05-28 21:33:56 +02:00
nacabaro e158f50970 Add settings screen 2026-05-28 21:32:52 +02:00
nacabaro f8f7c7a9b6 Fix egg upscale issues 2026-05-28 19:32:04 +02:00
nacabaro 24ebd8a5af Add a way to switch backgrounds 2026-05-28 19:12:27 +02:00
nacabaro 82a7d76b92 Add upscaling on the egg screen 2026-05-28 01:32:10 +02:00
nacabaro 2ae5bc8bd4 Move sprite scale to the defs 2026-05-28 01:31:21 +02:00
nacabaro dc44a695be Create upscale sprite function 2026-05-28 01:31:03 +02:00
nacabaro 0b5c56b5e3 Add support with light sleep and step sensing 2026-05-27 21:01:15 +02:00
nacabaro 55749ba2a8 Update reference file of the display properties. 2026-05-27 21:00:37 +02:00
nacabaro 9e23682068 Update env to support multiple ESP32 types 2026-05-27 21:00:23 +02:00
nacabaro 56ce03f34e Fix issue when cleaning poop 2026-05-27 21:00:04 +02:00
nacabaro ce23c44077 Mierda 2026-05-27 14:38:10 +02:00
nacabaro 595faaf946 Merge branch 'main' of github.com:nacabaro/nacapet 2026-05-27 14:32:43 +02:00
nacabaro 570d7f8bc4 Let's get this up to date, i'll update the readme later on 2026-05-27 14:30:33 +02:00
69 changed files with 2254 additions and 1288 deletions
+6
View File
@@ -8,6 +8,12 @@
*.line
*.egg
*.cm
*.png
*.jpg
*.webp
*.adv
*.coli
ideas/
__pycache__/
venv/
sprites/
+13 -365
View File
@@ -1,311 +1,26 @@
// USER DEFINED SETTINGS
// Set driver type, fonts to be loaded, pins used and SPI control method etc.
//
// See the User_Setup_Select.h file if you wish to be able to define multiple
// setups and then easily select which setup file is used by the compiler.
//
// If this file is edited correctly then all the library example sketches should
// run without the need to make any more changes for a particular hardware setup!
// Note that some sketches are designed for a particular TFT pixel width/height
// User defined information reported by "Read_User_Setup" test & diagnostics example
#define USER_SETUP_INFO "User_Setup"
#define USE_HSPI_PORT
// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
//#define DISABLE_ALL_LIBRARY_WARNINGS
// ##################################################################################
//
// Section 1. Call up the right driver file and any options for it
//
// ##################################################################################
// Define STM32 to invoke optimised processor support (only for STM32)
//#define STM32
// Defining the STM32 board allows the library to optimise the performance
// for UNO compatible "MCUfriend" style shields
//#define NUCLEO_64_TFT
//#define NUCLEO_144_TFT
// STM32 8-bit parallel only:
// If STN32 Port A or B pins 0-7 are used for 8-bit parallel data bus bits 0-7
// then this will improve rendering performance by a factor of ~8x
//#define STM_PORTA_DATA_BUS
//#define STM_PORTB_DATA_BUS
// Tell the library to use parallel mode (otherwise SPI is assumed)
//#define TFT_PARALLEL_8_BIT
//#defined TFT_PARALLEL_16_BIT // **** 16-bit parallel ONLY for RP2040 processor ****
// Display type - only define if RPi display
//#define RPI_DISPLAY_TYPE // 20MHz maximum SPI
// Only define one driver, the other ones must be commented out
//#define ILI9341_DRIVER // Generic driver for common displays
//#define ILI9341_2_DRIVER // Alternative ILI9341 driver, see https://github.com/Bodmer/TFT_eSPI/issues/1172
//#define ST7735_DRIVER // Define additional parameters below for this display
//#define ILI9163_DRIVER // Define additional parameters below for this display
//#define S6D02A1_DRIVER
//#define RPI_ILI9486_DRIVER // 20MHz maximum SPI
//#define HX8357D_DRIVER
//#define ILI9481_DRIVER
//#define ILI9486_DRIVER
//#define ILI9488_DRIVER // WARNING: Do not connect ILI9488 display SDO to MISO if other devices share the SPI bus (TFT SDO does NOT tristate when CS is high)
#define ST7789_DRIVER // Full configuration option, define additional parameters below for this display
//#define ST7789_2_DRIVER // Minimal configuration option, define additional parameters below for this display
//#define R61581_DRIVER
//#define RM68140_DRIVER
//#define ST7796_DRIVER
//#define SSD1351_DRIVER
//#define SSD1963_480_DRIVER
//#define SSD1963_800_DRIVER
//#define SSD1963_800ALT_DRIVER
//#define ILI9225_DRIVER
//#define GC9A01_DRIVER
// Some displays support SPI reads via the MISO pin, other displays have a single
// bi-directional SDA pin and the library will try to read this via the MOSI line.
// To use the SDA line for reading data from the TFT uncomment the following line:
// #define TFT_SDA_READ // This option is for ESP32 ONLY, tested with ST7789 and GC9A01 display only
// For ST7735, ST7789 and ILI9341 ONLY, define the colour order IF the blue and red are swapped on your display
// Try ONE option at a time to find the correct colour order for your display
//#define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
#define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
// For M5Stack ESP32 module with integrated ILI9341 display ONLY, remove // in line below
// #define M5STACK
// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
// #define TFT_WIDTH 80
//#define TFT_WIDTH 128
// #define TFT_WIDTH 172 // ST7789 172 x 320
// #define TFT_WIDTH 170 // ST7789 170 x 320
#define TFT_RGB_ORDER TFT_BGR // Colour order Red-Green-Blue
#define TFT_WIDTH 240 // ST7789 240 x 240 and 240 x 320
///#define TFT_HEIGHT 160
// #define TFT_HEIGHT 128
#define TFT_HEIGHT 240 // ST7789 240 x 240
// #define TFT_HEIGHT 320 // ST7789 240 x 320
// #define TFT_HEIGHT 240 // GC9A01 240 x 240
// For ST7735 ONLY, define the type of display, originally this was based on the
// colour of the tab on the screen protector film but this is not always true, so try
// out the different options below if the screen does not display graphics correctly,
// e.g. colours wrong, mirror images, or stray pixels at the edges.
// Comment out ALL BUT ONE of these options for a ST7735 display driver, save this
// this User_Setup file, then rebuild and upload the sketch to the board again:
// #define ST7735_INITB
// #define ST7735_GREENTAB
// #define ST7735_GREENTAB2
// #define ST7735_GREENTAB3
// #define ST7735_GREENTAB128 // For 128 x 128 display
// #define ST7735_GREENTAB160x80 // For 160 x 80 display (BGR, inverted, 26 offset)
// #define ST7735_ROBOTLCD // For some RobotLCD Arduino shields (128x160, BGR, https://docs.arduino.cc/retired/getting-started-guides/TFT)
//#define ST7735_REDTAB
// #define ST7735_BLACKTAB
// #define ST7735_REDTAB160x80 // For 160 x 80 display with 24 pixel offset
// If colours are inverted (white shows as black) then uncomment one of the next
// 2 lines try both options, one of the options should correct the inversion.
// #define TFT_INVERSION_ON
// #define TFT_INVERSION_OFF
// ##################################################################################
//
// Section 2. Define the pins that are used to interface with the display here
//
// ##################################################################################
// If a backlight control signal is available then define the TFT_BL pin in Section 2
// below. The backlight will be turned ON when tft.begin() is called, but the library
// needs to know if the LEDs are ON with the pin HIGH or LOW. If the LEDs are to be
// driven with a PWM signal or turned OFF/ON then this must be handled by the user
// sketch. e.g. with digitalWrite(TFT_BL, LOW);
#define TFT_BL 25 // LED back-light control pin
#define TFT_BL 1 // LED back-light control pin
#define TFT_BACKLIGHT_ON HIGH // Level to turn ON back-light (HIGH or LOW)
#define TFT_MOSI 11
#define TFT_MISO -1
#define TFT_SCLK 12
#define TFT_DC 5
#define TFT_RST 6
#define TOUCH_CS -1
// We must use hardware SPI, a minimum of 3 GPIO pins is needed.
// Typical setup for ESP8266 NodeMCU ESP-12 is :
//
// Display SDO/MISO to NodeMCU pin D6 (or leave disconnected if not reading TFT)
// Display LED to NodeMCU pin VIN (or 5V, see below)
// Display SCK to NodeMCU pin D5
// Display SDI/MOSI to NodeMCU pin D7
// Display DC (RS/AO)to NodeMCU pin D3
// Display RESET to NodeMCU pin D4 (or RST, see below)
// Display CS to NodeMCU pin D8 (or GND, see below)
// Display GND to NodeMCU pin GND (0V)
// Display VCC to NodeMCU 5V or 3.3V
//
// The TFT RESET pin can be connected to the NodeMCU RST pin or 3.3V to free up a control pin
//
// The DC (Data Command) pin may be labelled AO or RS (Register Select)
//
// With some displays such as the ILI9341 the TFT CS pin can be connected to GND if no more
// SPI devices (e.g. an SD Card) are connected, in this case comment out the #define TFT_CS
// line below so it is NOT defined. Other displays such at the ST7735 require the TFT CS pin
// to be toggled during setup, so in these cases the TFT_CS line must be defined and connected.
//
// The NodeMCU D0 pin can be used for RST
//
//
// Note: only some versions of the NodeMCU provide the USB 5V on the VIN pin
// If 5V is not available at a pin you can use 3.3V but backlight brightness
// will be lower.
#define TFT_SPI_PORT SPI2_HOST
#define SPI_FREQUENCY 27000000
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######
// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
//#define TFT_MISO PIN_D6 // Automatically assigned with ESP8266 if not defined
#define TFT_MOSI 23 // Automatically assigned with ESP8266 if not defined
#define TFT_SCLK 18 // Automatically assigned with ESP8266 if not defined
#define TFT_CS 15 // Chip select control pin D8
#define TFT_DC 17 // Data Command control pin
#define TFT_RST 19 // Reset pin (could connect to NodeMCU RST, see next line)
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
//#define TFT_BL PIN_D1 // LED back-light (only for ST7789 with backlight control pin)
#define TOUCH_CS -1 // Chip select pin (T_CS) of touch screen
//#define TFT_WR PIN_D2 // Write strobe for modified Raspberry Pi TFT only
// ###### FOR ESP8266 OVERLAP MODE EDIT THE PIN NUMBERS IN THE FOLLOWING LINES ######
// Overlap mode shares the ESP8266 FLASH SPI bus with the TFT so has a performance impact
// but saves pins for other functions. It is best not to connect MISO as some displays
// do not tristate that line when chip select is high!
// Note: Only one SPI device can share the FLASH SPI lines, so a SPI touch controller
// cannot be connected as well to the same SPI signals.
// On NodeMCU 1.0 SD0=MISO, SD1=MOSI, CLK=SCLK to connect to TFT in overlap mode
// On NodeMCU V3 S0 =MISO, S1 =MOSI, S2 =SCLK
// In ESP8266 overlap mode the following must be defined
//#define TFT_SPI_OVERLAP
// In ESP8266 overlap mode the TFT chip select MUST connect to pin D3
//#define TFT_CS PIN_D3
//#define TFT_DC PIN_D5 // Data Command control pin
//#define TFT_RST PIN_D4 // Reset pin (could connect to NodeMCU RST, see next line)
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V
// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP ######
// For ESP32 Dev board (only tested with ILI9341 display)
// The hardware SPI can be mapped to any pins
//#define TFT_MISO 19
//#define TFT_MOSI 23
//#define TFT_SCLK 18
//#define TFT_CS 15 // Chip select control pin
//#define TFT_DC 2 // Data Command control pin
//#define TFT_RST 4 // Reset pin (could connect to RST pin)
//#define TFT_RST -1 // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST
// For ESP32 Dev board (only tested with GC9A01 display)
// The hardware SPI can be mapped to any pins
//#define TFT_MOSI 15 // In some display driver board, it might be written as "SDA" and so on.
//#define TFT_SCLK 14
//#define TFT_CS 5 // Chip select control pin
//#define TFT_DC 27 // Data Command control pin
//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
//#define TFT_BL 22 // LED back-light
//#define TOUCH_CS 21 // Chip select pin (T_CS) of touch screen
//#define TFT_WR 22 // Write strobe for modified Raspberry Pi TFT only
// For the M5Stack module use these #define lines
//#define TFT_MISO 19
//#define TFT_MOSI 23
//#define TFT_SCLK 18
//#define TFT_CS 14 // Chip select control pin
//#define TFT_DC 27 // Data Command control pin
//#define TFT_RST 33 // Reset pin (could connect to Arduino RESET pin)
//#define TFT_BL 32 // LED back-light (required for M5Stack)
// ###### EDIT THE PINs BELOW TO SUIT YOUR ESP32 PARALLEL TFT SETUP ######
// The library supports 8-bit parallel TFTs with the ESP32, the pin
// selection below is compatible with ESP32 boards in UNO format.
// Wemos D32 boards need to be modified, see diagram in Tools folder.
// Only ILI9481 and ILI9341 based displays have been tested!
// Parallel bus is only supported for the STM32 and ESP32
// Example below is for ESP32 Parallel interface with UNO displays
// Tell the library to use 8-bit parallel mode (otherwise SPI is assumed)
//#define TFT_PARALLEL_8_BIT
// The ESP32 and TFT the pins used for testing are:
//#define TFT_CS 33 // Chip select control pin (library pulls permanently low
//#define TFT_DC 15 // Data Command control pin - must use a pin in the range 0-31
//#define TFT_RST 32 // Reset pin, toggles on startup
//#define TFT_WR 4 // Write strobe control pin - must use a pin in the range 0-31
//#define TFT_RD 2 // Read strobe control pin
//#define TFT_D0 12 // Must use pins in the range 0-31 for the data bus
//#define TFT_D1 13 // so a single register write sets/clears all bits.
//#define TFT_D2 26 // Pins can be randomly assigned, this does not affect
//#define TFT_D3 25 // TFT screen update performance.
//#define TFT_D4 17
//#define TFT_D5 16
//#define TFT_D6 27
//#define TFT_D7 14
// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
// The TFT can be connected to SPI port 1 or 2
//#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
//#define TFT_MOSI PA7
//#define TFT_MISO PA6
//#define TFT_SCLK PA5
//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
//#define TFT_MOSI PB15
//#define TFT_MISO PB14
//#define TFT_SCLK PB13
// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
//#define TFT_CS D5 // Chip select control pin to TFT CS
//#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
//#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
// OR alternatively, we can use STM32 port reference names PXnn
//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
// Use an Arduino pin for initial testing as connecting to processor reset
// may not work (pulse too short at power up?)
// ##################################################################################
//
// Section 3. Define the fonts that are to be used here
//
// ##################################################################################
// Comment out the #defines below with // to stop that font being loaded
// The ESP8366 and ESP32 have plenty of memory so commenting out fonts is not
// normally necessary. If all fonts are loaded the extra FLASH space required is
// about 17Kbytes. To save FLASH space only enable the fonts you need!
#define TFT_USE_DMA false
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
@@ -316,77 +31,10 @@
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT
#define SPI_FREQUENCY 27000000
// ##################################################################################
//
// Section 4. Other options
//
// ##################################################################################
// For RP2040 processor and SPI displays, uncomment the following line to use the PIO interface.
//#define RP2040_PIO_SPI // Leave commented out to use standard RP2040 SPI port interface
// For RP2040 processor and 8 or 16-bit parallel displays:
// The parallel interface write cycle period is derived from a division of the CPU clock
// speed so scales with the processor clock. This means that the divider ratio may need
// to be increased when overclocking. It may also need to be adjusted dependant on the
// display controller type (ILI94341, HX8357C etc.). If RP2040_PIO_CLK_DIV is not defined
// the library will set default values which may not suit your display.
// The display controller data sheet will specify the minimum write cycle period. The
// controllers often work reliably for shorter periods, however if the period is too short
// the display may not initialise or graphics will become corrupted.
// PIO write cycle frequency = (CPU clock/(4 * RP2040_PIO_CLK_DIV))
//#define RP2040_PIO_CLK_DIV 1 // 32ns write cycle at 125MHz CPU clock
//#define RP2040_PIO_CLK_DIV 2 // 64ns write cycle at 125MHz CPU clock
//#define RP2040_PIO_CLK_DIV 3 // 96ns write cycle at 125MHz CPU clock
// For the RP2040 processor define the SPI port channel used (default 0 if undefined)
//#define TFT_SPI_PORT 1 // Set to 0 if SPI0 pins are used, or 1 if spi1 pins used
// For the STM32 processor define the SPI port channel used (default 1 if undefined)
//#define TFT_SPI_PORT 2 // Set to 1 for SPI port 1, or 2 for SPI port 2
// Define the SPI clock frequency, this affects the graphics rendering speed. Too
// fast and the TFT driver will not keep up and display corruption appears.
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
// With an ILI9163 display 27 MHz works OK.
// #define SPI_FREQUENCY 1000000
// #define SPI_FREQUENCY 5000000
// #define SPI_FREQUENCY 10000000
// #define SPI_FREQUENCY 20000000
// #define SPI_FREQUENCY 27000000
#define SPI_FREQUENCY 40000000
// #define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
// #define SPI_FREQUENCY 80000000
// Optional reduced SPI frequency for reading TFT
#define SPI_READ_FREQUENCY 20000000
// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
#define SPI_TOUCH_FREQUENCY 2500000
// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
// then uncomment the following line:
//#define USE_HSPI_PORT
// Comment out the following #define if "SPI Transactions" do not need to be
// supported. When commented out the code size will be smaller and sketches will
// run slightly faster, so leave it commented out unless you need it!
// Transaction support is needed to work with SD library but not needed with TFT_SdFat
// Transaction support is required if other SPI devices are connected.
// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
// so changing it here has no effect
// #define SUPPORT_TRANSACTIONS
#define USE_DMA_TO_TFT
+4
View File
@@ -0,0 +1,4 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x7000,
app0, app, factory, 0x10000, 0xA0000,
spiffs, data, spiffs, 0xB0000, 0x350000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x7000
3 app0 app factory 0x10000 0xA0000
4 spiffs data spiffs 0xB0000 0x350000
+45 -5
View File
@@ -8,12 +8,52 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32dev]
[env:s3-full]
platform = espressif32
board = esp32dev
board = 4d_systems_esp32s3_gen4_r8n16
framework = arduino
monitor_speed = 115200
monitor_port = /dev/ttyUSB0
monitor_filters = esp32_exception_decoder
monitor_speed = 115200
lib_deps =
TFT_eSPI
fbiego/ESP32Time@^2.0.6
electroniccats/MPU6050@^1.4.3
board_build.arduino.psram = enabled
board_upload.flash_size = 16MB
board_build.partitions = default_16MB.csv
board_build.flash_mode = dio
board_build.arduino.memory_type = dio_opi
build_flags =
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=0
-DDEV_UNIT
-DDISALLOW_SLEEP
-DDEBUG
upload_port = COM8
monitor_port = COM8
[env:s3-supermini]
platform = espressif32
board = esp32-s3-devkitc-1
framework = arduino
board_upload.flash_size = 4MB
board_build.arduino.memory_type = qio_qspi
board_build.flash_mode = qio
board_build.psram_type = qio
build_flags =
-DBOARD_HAS_PSRAM
-DARDUINO_USB_CDC_ON_BOOT=1
-DARDUINO_USB_MODE=1
-DDISALLOW_SLEEP
-DDEV_UNIT
board_build.partitions = partitions_4MB.csv
lib_deps = TFT_eSPI, fbiego/ESP32Time@^2.0.6, electroniccats/MPU6050@^1.4.3
build_flags = -Wl,-Map,output.map
upload_port = COM5
monitor_port = COM5
+10 -19
View File
@@ -11,11 +11,10 @@ int currentAnimationFrame = 0;
void animate_performAnimation(TFT_eSprite &spr, struct SpriteData* spriteData, uint8_t offsetX) {
draw_drawSprite(
spr,
animationPositions[currentAnimationFrame] - offsetX,
spriteHeightOnScreen,
spriteData,
animationFrames[currentAnimationFrame],
6,
animationPositions[currentAnimationFrame] - offsetX,
spriteHeightOnScreen,
spriteData,
animationFrames[currentAnimationFrame],
animationFlipSprites[currentAnimationFrame]
);
@@ -26,14 +25,12 @@ void animate_performAttentionAnimation(TFT_eSprite &spr, struct SpriteData* spri
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesAngry;
draw_drawSprite(
spr,
spriteHeightOnScreen,
spriteHeightOnScreen,
spriteData,
angryAnimationFrames[currentAnimationFrame],
6,
spriteHeightOnScreen,
spriteHeightOnScreen,
spriteData,
angryAnimationFrames[currentAnimationFrame],
animationFlipSprites[currentAnimationFrame]
);
}
void animate_performEatingAnimation(TFT_eSprite &spr, struct SpriteData* spriteData) {
@@ -44,7 +41,6 @@ void animate_performEatingAnimation(TFT_eSprite &spr, struct SpriteData* spriteD
spriteHeightOnScreen,
spriteData,
eatingAnimationFrames[currentAnimationFrame],
6,
false
);
}
@@ -57,7 +53,6 @@ void animate_performRefuseAnimation(TFT_eSprite &spr, struct SpriteData* spriteD
spriteHeightOnScreen,
spriteData,
refuseAnimationFrames[currentAnimationFrame],
6,
refuseAnimationFlips[currentAnimationFrame]
);
}
@@ -70,7 +65,6 @@ void animate_performSleepyAnimation(TFT_eSprite &spr, struct SpriteData* spriteD
spriteHeightOnScreen,
spriteData,
sleepyAnimationFrames[currentAnimationFrame],
6,
false
);
}
@@ -83,7 +77,6 @@ void animate_performHappyAnimation(TFT_eSprite &spr, struct SpriteData* spriteDa
spriteHeightOnScreen,
spriteData,
happyAnimationFrames[currentAnimationFrame],
6,
false
);
}
@@ -97,20 +90,18 @@ void animate_performAngryAnimation(TFT_eSprite &spr, struct SpriteData* spriteDa
spriteHeightOnScreen,
spriteData,
angryAnimationFrames[currentAnimationFrame],
6,
false
);
}
void animate_performHatchingAnimation(TFT_eSprite &spr, struct SpriteData* spriteData) {
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesHappy;
currentAnimationFrame = (currentAnimationFrame + 1) % numFramesHatching;
draw_drawSprite(
spr,
hatchingAnimationPositions[currentAnimationFrame],
spriteHeightOnScreen,
spriteData,
0,
6,
false
);
}
}
+9 -6
View File
@@ -1,4 +1,5 @@
#include "defs/defs.h"
#include "defs/sounds.h"
#include "defs/chara_data.h"
#include "defs/screen_defs.h"
#include "buttons.h"
@@ -16,9 +17,11 @@ bool k4_prev = HIGH;
void buttons_checkInactivity() {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US && !screenOff) {
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US && !screenOff && !alwaysOnEnabled) {
#ifdef DISALLOW_SLEEP
digitalWrite(BL_PIN, LOW);
screenKey = OFF_SCREEN;
#endif
} else if (currentTime - lastPressedButtonTime > LAST_PRESSED_BUTTON_THRESHOLD_TIME_US && !inactive) {
screenKey = MAIN_SCREEN;
@@ -33,14 +36,14 @@ uint8_t buttons_getPressedButtons() {
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)
(k1_prev == LOW && k1_current == HIGH) << 3 |
(k2_prev == LOW && k2_current == HIGH) << 2 |
(k3_prev == LOW && k3_current == HIGH) << 1 |
(k4_prev == LOW && k4_current == HIGH)
);
if (retV != 0) {
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
sound_playMelody(SOUND_BUTTON_BEEP, SOUND_NOTE_COUNT(SOUND_BUTTON_BEEP));
lastPressedButtonTime = esp_timer_get_time();
inactive = false;
screenOff = false;
+2
View File
@@ -1,6 +1,8 @@
#ifndef BUTTONS_H
#define BUTTONS_H
#include <Arduino.h>
uint8_t buttons_getPressedButtons();
void buttons_checkInactivity();
+2
View File
@@ -3,6 +3,8 @@
#include <stdint.h>
extern int currentBackground;
struct BackgroundData {
uint8_t backgroundWidth;
uint8_t backgroundHeight;
+2 -1
View File
@@ -46,7 +46,8 @@ struct CharacterData {
bool asleep = false;
bool injured = false;
bool dead = false;
bool traited = true;
bool traited = false;
bool frozen = false;
// Usado para recalcular cuantos dias van a tardar en recuperarse, max 5 pls
uint8_t dynamicSleepDists;
+50 -17
View File
@@ -11,24 +11,38 @@
#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 35
#define K2_PIN 13
#define K3_PIN 33
#define K4_PIN 14
#ifdef DEV_UNIT
#define K1_PIN 1
#define K2_PIN 2
#define K3_PIN 3
#define K4_PIN 4
#define BUTTON_MODE INPUT_PULLDOWN
#define BL_PIN 10
#endif
#ifdef ANDREW_UNIT
#define K1_PIN 39
#define K2_PIN 8
#define K3_PIN 9
#define K4_PIN 38
#define BUTTON_MODE INPUT_PULLUP
#define BL_PIN 42
#endif
// SPEAKER PINOUT
#define SPK_PIN 21
#define SPK_PIN 7
// MPU6050 PINOUT
#define MPU_SCL_PIN 4
#define MPU_SDA_PIN 16
#define MPU_INT_PIN 12
// I2C PINOUT
#define I2C_SCL_PIN 9
#define I2C_SDA_PIN 8
// SPECIAL SCREEN THAT OPENS WHEN TIMERS ARE DONE
// RECEIVES AN EXTRA PARAMETER (INTERRUPTKEY)
@@ -59,6 +73,7 @@
#define SLEEP_SCREEN_MENU 6
#define CHANGE_SCREEN_MENU 7
#define SETTINGS_SCREEN_MENU 8
#define FREEZE_SCREEN_MENU 9
// SCREENS THAT OPEN AFTER CLICKING ON A MENU ENTRY
#define STATUS_SCREEN 10
@@ -80,9 +95,11 @@
#define MEDICAL_SCREEN_ICON 5
#define SLEEP_SCREEN_ICON 6
#define SETTINGS_SCREEN_ICON 8
#define CARE_MISTAKE_CALL_LIGHT 9
#define FRIDGE_DOOR 9
#define BED_SPRITE 10
#define EMPTY_EGG 11
#define CARE_MISTAKE_CALL_LIGHT 12
// SCREENS
#define OFF_SCREEN -1
@@ -98,6 +115,7 @@
#define FEEDING_SCREEN 20
#define REFUSING_SCREEN 21
#define SLEEPY_SCREEN 22
#define FROZEN_SCREEN 28
#define CARE_MISTAKE_SCREEN 23
#define POOPING_SCREEN 24
#define HAPPY_SCREEN 25
@@ -107,6 +125,10 @@
// TRAINING MODES
#define TRAINING_SCREEN_1 30
// SETTINGS SUBSCREENS
#define BACKGROUND_CHANGE_SCREEN 40
#define RESET_DATA_SCREEN 41
// SMALL UI ICONS (UI.BIN)
#define POOP_ICON 0
#define FOOD_ICON 1
@@ -146,6 +168,8 @@
#define CHARA_COUNT_IN_DEVICE 5
#define SPRITE_SCALE 6
extern int screenKey;
extern int menuKey;
extern int submenuKey;
@@ -163,7 +187,6 @@ extern uint64_t lastPressedButtonTime;
extern uint64_t lastUpdateTime;
extern uint64_t lastBeepTime;
extern struct CharacterData* charaData;
extern struct tm timeInfo;
extern uint32_t dayUnixTime;
@@ -179,17 +202,27 @@ extern uint8_t beepCounter;
extern uint16_t stepCounter;
extern bool coldBoot;
extern bool timeSet;
extern uint8_t eggNumber;
extern Egg_t* eggSelection;
extern uint8_t currentCharacter;
// Rescatar
extern Egg_t* currentEgg;
extern LineCare_t** currentLineCareInstr;
extern Line_t** currentLine;
extern struct CharacterData* charaData;
extern struct SpriteData mainCharacterSprites;
#endif
extern bool isSamplingSteps;
extern uint64_t sampleStartTime;
extern uint16_t initialSteps;
// Settings screen options
extern bool soundEnabled;
extern bool alwaysOnEnabled;
#endif
+1 -2
View File
@@ -4,8 +4,7 @@
#include <TFT_eSPI.h>
extern TFT_eSPI tft;
extern TFT_eSprite composite1;
extern TFT_eSprite composite2;
extern TFT_eSprite composite;
// ALTAMENTE TEMPORAL
extern int xPos;
+121
View File
@@ -0,0 +1,121 @@
#ifndef SOUNDS_H
#define SOUNDS_H
#include "defs/defs.h"
#include "sound/sound.h"
#define SOUND_NOTE_COUNT(melody) (sizeof(melody) / sizeof((melody)[0]))
static const Note SOUND_BUTTON_BEEP[] = {
{BEEP_FREQ_HZ, BEEP_LEN_MS},
};
static const Note SOUND_BOOT[] = {
{1800, 55},
{0, 20},
{2600, 55},
{0, 20},
{3400, 70},
{0, 35},
{4600, 95},
};
static const Note SOUND_CARE_ALERT[] = {
{1800, 80},
{0, 35},
{1800, 80},
{0, 35},
{5200, 120},
};
static const Note SOUND_HAPPY[] = {
{2200, 45},
{3300, 45},
{4400, 55},
{6600, 80},
{0, 25},
{5200, 60},
};
static const Note SOUND_ANGRY[] = {
{900, 70},
{0, 25},
{700, 90},
{0, 25},
{520, 150},
};
static const Note SOUND_POOP_DROP[] = {
{4200, 35},
{3200, 35},
{2200, 45},
{0, 25},
{900, 85},
};
static const Note SOUND_REFUSE[] = {
{2600, 70},
{0, 35},
{1500, 80},
{0, 30},
{900, 120},
};
static const Note SOUND_EVOLUTION_WOBBLE[] = {
{3200, 60},
{3900, 60},
{3000, 60},
{4300, 60},
{3400, 60},
{4700, 70},
};
static const Note SOUND_EVOLUTION_COMPLETE[] = {
{1600, 90},
{2200, 90},
{3000, 100},
{4000, 110},
{5200, 130},
{6400, 220},
{0, 60},
{5200, 100},
{6400, 180},
};
static const Note SOUND_TRAINING_START[] = {
{3100, 55},
{0, 25},
{4100, 85},
};
static const Note SOUND_TRAINING_ATTACK[] = {
{5200, 18},
{0, 8},
{4600, 18},
{0, 8},
{3900, 22},
{0, 12},
{3000, 28},
};
static const Note SOUND_HATCH[] = {
{2200, 45},
{0, 20},
{2600, 45},
{0, 20},
{3000, 45},
{0, 20},
{3400, 45},
{0, 20},
{3800, 50},
{0, 25},
{4300, 55},
{0, 30},
{5000, 75},
{0, 45},
{3600, 55},
{4300, 55},
{5200, 110},
};
#endif
+38 -44
View File
@@ -2,6 +2,8 @@
#include "defs/screen_defs.h"
#include "defs/defs.h"
#include <TFT_eSPI.h>
int xPos = 0;
int yPos = 0;
@@ -10,75 +12,67 @@ static const int BUF_H = 120;
void tft_initDisplay(TFT_eSPI &tft, uint16_t color) {
tft.begin();
tft.initDMA();
#ifdef ANDREW_UNIT
pinMode(BL_PIN, OUTPUT);
digitalWrite(BL_PIN, HIGH);
#endif
tft.init();
tft.setRotation(0);
tft.fillScreen(TFT_RED);
tft.fillScreen(color);
}
void tft_initScreenBuffer(uint16_t color) {
bool status = composite1.createSprite(240, 120);
composite1.fillSprite(TFT_BLUE);
composite1.setTextColor(TFT_BLACK);
composite1.setTextSize(4);
composite1.pushSprite(0, 0);
composite.setAttribute(PSRAM_ENABLE, true);
status = composite2.createSprite(240, 120);
composite2.fillSprite(TFT_BLUE);
composite2.setTextColor(TFT_BLACK);
composite2.setTextSize(4);
composite2.pushSprite(0, 120);
if (composite.createSprite(240, 240)) {
printf("SUCCESS: Composite sprite created.\n");
composite.fillSprite(TFT_RED);
} else {
printf("FATAL: Composite sprite failed! No RAM/PSRAM.\n");
return;
}
composite.setFreeFont(NULL);
composite.setTextFont(1);
composite.setTextColor(TFT_BLUE);
composite.setTextSize(4);
composite.pushSprite(0, 0);
}
void tft_drawBuffer() {
tft.startWrite();
composite1.pushSprite(0, 0);
composite2.pushSprite(0, 0 + BUF_H);
tft.endWrite();
composite.pushSprite(0, 0, TFT_TRANSPARENT);
}
/*void tft_drawBuffer() {
tft.startWrite();
tft.pushImageDMA(0, 0, 240, 120, (uint16_t*) composite1.getPointer());
tft.pushImageDMA(0, 120, 240, 120, (uint16_t*) composite2.getPointer());
tft.endWrite();
}*/
void tft_clearBuffer(TFT_eSprite &composite, uint16_t color) {
composite.fillSprite(color);
}
void tft_clearBuffer(uint16_t color) {
composite1.fillSprite(color);
composite2.fillSprite(color);
composite.fillSprite(color);
}
void tft_drawCenteredText(const char* text, int size, int yGlobal) {
int textW = strlen(text) * size * 6;
int x = (SCREEN_WIDTH - textW) / 2;
composite1.setTextSize(size);
composite1.setTextColor(TFT_BLACK);
composite1.drawString(text, x, yGlobal);
// only bottom half, adjust local Y
int yLocal = yGlobal - BUF_H;
composite2.setTextSize(size);
composite2.setTextColor(TFT_BLACK);
composite2.drawString(text, x, yLocal);
composite.setTextSize(size);
composite.setTextColor(TFT_BLACK);
composite.drawString(text, x, yGlobal);
}
void tft_drawText(const char* text, int size, int x, int y, uint16_t color) {
composite1.setTextSize(size);
composite1.setTextColor(color);
composite1.drawString(text, x, y);
void tft_drawText(const char* text, int size, int x, int y, uint16_t color, uint16_t bgColor) {
composite.setTextSize(size);
composite2.setTextSize(size);
composite2.setTextColor(color);
composite2.drawString(text, x, y - BUF_H);
if (bgColor != TFT_TRANSPARENT) {
composite.setTextColor(color, bgColor);
} else {
composite.setTextColor(color);
}
composite.drawString(text, x, y);
}
void tft_drawRectangle(int x, int y, int w, int h, uint16_t color) {
composite1.fillRect(x, y, w, h, color);
composite2.fillRect(x, y - BUF_H, w, h, color);
composite.fillRect(x, y, w, h, color);
}
+1 -1
View File
@@ -12,7 +12,7 @@ void tft_drawBuffer();
void tft_clearBuffer(TFT_eSprite &buffer, uint16_t color = TFT_WHITE);
void tft_clearBuffer(uint16_t color = TFT_WHITE);
void tft_drawCenteredText(const char* text, int factor, int y);
void tft_drawText(const char* text, int size, int x, int y, uint16_t color = TFT_BLACK);
void tft_drawText(const char* text, int size, int x, int y, uint16_t color = TFT_BLACK, uint16_t bgColor = TFT_TRANSPARENT);
void tft_drawRectangle(int x, int y, int w, int h, uint16_t color = TFT_BLACK);
#endif
+8 -6
View File
@@ -2,17 +2,19 @@
#define DRAW_H
#include <TFT_eSPI.h>
#include "defs/sprite_data.h"
void draw_drawSprite(
TFT_eSprite &tft, int x, int y,
TFT_eSprite &tft, int x, int y,
struct SpriteData* spriteData, uint8_t spriteNumber,
uint8_t factor, bool flipHorizontal = false
bool flipHorizontal = false
);
void draw_drawBackground(TFT_eSprite &bg, int spr_w, int spr_h, int factor);
void draw_drawBackgroundSection(TFT_eSprite &bg, int spr_w, int spr_h, int tft_x, int tft_y, int tft_w, int tft_h, int factor);
void draw_drawBackground(TFT_eSprite& bg, int spr_w, int spr_h, int factor);
void draw_drawBackgroundSection(TFT_eSprite& bg, int x, int y, int w, int h);
void draw_drawSpriteCentered(
TFT_eSprite &spr, struct SpriteData* spriteData, uint8_t spriteNumber, uint8_t factor, bool flipped = false, int y = -1
TFT_eSprite &spr, struct SpriteData* spriteData, uint8_t spriteNumber,
bool flipped = false, int y = -1
);
void draw_drawAttacks(TFT_eSprite &sprite, struct SpriteData* attackSpriteData, int x, int y, uint8_t attackType, uint8_t attackSprite, uint8_t factor, bool flipped = false);
void draw_drawAttacks(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* attackSpriteData, int x, int y, uint8_t attackType, uint8_t attackSprite, bool flipped = false);
#endif
+8 -5
View File
@@ -2,16 +2,19 @@
#include "defs/sprite_data.h"
void draw_drawAttacks(TFT_eSprite &sprite, struct SpriteData* attackSpriteData, int x, int y, uint8_t attackType, uint8_t attackSprite, uint8_t factor, bool flipped) {
void draw_drawAttacks(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* attackSpriteData, int x, int y, uint8_t attackType, uint8_t attackSprite, bool flipped) {
int cleanWidth = attackSpriteData->spriteWidth + 6;
draw_drawBackgroundSection(bg, x, y, cleanWidth, attackSpriteData->spriteHeight * 2);
switch(attackType) {
case 1:
draw_drawSprite(sprite, x, y, attackSpriteData, attackSprite, factor, flipped);
draw_drawSprite(sprite, x, y + 48, attackSpriteData, attackSprite, factor, flipped);
draw_drawSprite(sprite, x, y, attackSpriteData, attackSprite, flipped);
draw_drawSprite(sprite, x, y + 48, attackSpriteData, attackSprite, flipped);
break;
case 0:
default:
draw_drawSprite(sprite, x, y, attackSpriteData, attackSprite, factor, flipped);
draw_drawSprite(sprite, x, y, attackSpriteData, attackSprite, flipped);
break;
}
}
+10 -73
View File
@@ -1,83 +1,20 @@
#include "draw.h"
#include "defs/sprite_data.h"
#include "defs/screen_defs.h"
const char* TAG_DB = "[DRAW BG]";
void draw_drawBackground(TFT_eSprite &bg, int spr_w, int spr_h, int factor) {
// spr_w, spr_h = dimensions of the source sprite “bg”
// factor = integer scale factor
for (int srcY = 0; srcY < spr_h; srcY++) {
// Compute the top row in the scaled image that corresponds to srcY
int destRowBase = srcY * factor;
// For each “vertical tile” row within [0 .. factor-1]:
for (int dy = 0; dy < factor; dy++) {
int outY1 = destRowBase + dy; // Y in composite1
int outY2 = outY1 - 120; // Y in composite2
// Now loop over each source column
for (int srcX = 0; srcX < spr_w; srcX++) {
// Fetch the color exactly once for this source pixel
uint16_t color = bg.readPixel(srcX, srcY);
// Compute the leftmost column in the scaled image that corresponds to srcX
int destColBase = srcX * factor;
// For each “horizontal tile” column within [0 .. factor-1]:
for (int dx = 0; dx < factor; dx++) {
int outX = destColBase + dx;
composite1.drawPixel(outX, outY1, color);
composite2.drawPixel(outX, outY2, color);
}
}
}
}
void draw_drawBackground(TFT_eSprite& bg, int spr_w, int spr_h, int factor) {
bg.pushToSprite(&composite, 0, 0, TFT_TRANSPARENT);
}
// USO FUTURO
void draw_drawBackgroundSection(TFT_eSprite &bg, int spr_w, int spr_h, int tft_x, int tft_y, int tft_w, int tft_h, int factor) {
int srcX_start = tft_x / factor;
int srcX_end = (tft_x + tft_w - 1) / factor;
int srcY_start = tft_y / factor;
int srcY_end = (tft_y + tft_h - 1) / factor;
void draw_drawBackgroundSection(TFT_eSprite& bg, int x, int y, int w, int h) {
uint16_t* bgPtr = (uint16_t*)bg.getPointer();
int bgStride = bg.width();
if (srcX_start < 0) srcX_start = 0;
if (srcY_start < 0) srcY_start = 0;
if (srcX_end >= spr_w) srcX_end = spr_w - 1;
if (srcY_end >= spr_h) srcY_end = spr_h - 1;
if (srcX_start > srcX_end || srcY_start > srcY_end) return;
for (int srcY = srcY_start; srcY <= srcY_end; srcY++) {
int destY_base = srcY * factor;
int blockY0 = destY_base;
int blockY1 = destY_base + (factor - 1);
int y0 = (blockY0 < tft_y) ? tft_y : blockY0;
int y1 = (blockY1 > (tft_y + tft_h - 1)) ? (tft_y + tft_h - 1) : blockY1;
if (y0 > y1) continue;
for (int srcX = srcX_start; srcX <= srcX_end; srcX++) {
int destX_base = srcX * factor;
int blockX0 = destX_base;
int blockX1 = destX_base + (factor - 1);
int x0 = (blockX0 < tft_x) ? tft_x : blockX0;
int x1 = (blockX1 > (tft_x + tft_w - 1)) ? (tft_x + tft_w - 1) : blockX1;
if (x0 > x1) continue;
uint16_t color = bg.readPixel(srcX, srcY);
for (int y = y0; y <= y1; y++) {
for (int x = x0; x <= x1; x++) {
composite1.drawPixel(x, y, color);
composite2.drawPixel(x, y - 120, color);
}
}
}
for (int row = 0; row < h; row++) {
uint16_t* rowSrc = bgPtr + ((y + row) * bgStride) + x;
composite.pushImage(x, y + row, w, 1, rowSrc);
}
}
}
+23 -76
View File
@@ -9,106 +9,53 @@
const char* TAG_D = "[DRAW]";
/*void draw_drawSprite(
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(&composite1, x, y, TFT_TRANSPARENT);
spr.pushToSprite(&composite2, x, y - 120, TFT_TRANSPARENT);
spriteData->lastX = x;
spriteData->lastY = y;
spriteData->lastW = scaledWidth;
spriteData->lastH = scaledWidth;
//printf("%s: Sprite %d drawn at (%d, %d) %s\n", TAG_D, spriteNumber, x, y, (flipHorizontal ? "flipped" : ""));
}*/
void draw_drawSprite(
TFT_eSprite &spr,
int x, int y,
struct SpriteData* spriteData,
uint8_t spriteNumber,
uint8_t factor,
bool flipHorizontal
) {
int srcW = spriteData->spriteWidth;
int srcH = spriteData->spriteHeight;
int scaledW = srcW * factor;
int scaledH = srcH * factor;
const int W = spriteData->spriteWidth;
const int H = spriteData->spriteHeight;
if (spr.width() != scaledW || spr.height() != scaledH) {
if (spr.width() != W || spr.height() != H) {
spr.deleteSprite();
spr.createSprite(scaledW, scaledH);
spr.createSprite(W, H);
}
uint16_t *sprBuf = (uint16_t *)spr.getPointer();
uint16_t *srcBuf = spriteData->spriteData[spriteNumber];
uint16_t* sprBuf = (uint16_t*) spr.getPointer();
uint16_t* srcBuf = spriteData->spriteData[spriteNumber];
for (int srcY = 0; srcY < srcH; srcY++) {
int destYBase = srcY * factor;
for (int srcX = 0; srcX < srcW; srcX++) {
int useX = flipHorizontal ? (srcW - 1 - srcX) : srcX;
uint16_t raw = srcBuf[srcY * srcW + useX];
uint16_t color = (raw << 8) | (raw >> 8);
int destXBase = srcX * factor;
for (int dy = 0; dy < factor; dy++) {
int rowStart = (destYBase + dy) * scaledW + destXBase;
for (int dx = 0; dx < factor; dx++) {
sprBuf[rowStart + dx] = color;
}
if (!flipHorizontal) {
memcpy(sprBuf, srcBuf, W * H * sizeof(uint16_t));
} else {
for (int row = 0; row < H; row++) {
const uint16_t* src = srcBuf + row * W;
uint16_t* dst = sprBuf + row * W;
for (int col = 0; col < W; col++) {
dst[col] = src[W - 1 - col];
}
}
}
spr.pushToSprite(&composite1, x, y, TFT_TRANSPARENT);
spr.pushToSprite(&composite2, x, y - 120, TFT_TRANSPARENT);
spr.pushToSprite(&composite, x, y, TFT_TRANSPARENT);
spriteData->lastX = x;
spriteData->lastY = y;
spriteData->lastW = scaledW;
spriteData->lastH = scaledH;
spriteData->lastW = W;
spriteData->lastH = H;
}
void draw_drawSpriteCentered(
TFT_eSprite &spr,
struct SpriteData* spriteData, uint8_t spriteNumber, uint8_t factor, bool flipped, int y
struct SpriteData* spriteData, uint8_t spriteNumber, bool flipped, int y
) {
int x = (BUFFER_X - (spriteData->spriteWidth * factor)) / 2;
int new_y;
if (y == -1) {
new_y = (BUFFER_Y - (spriteData->spriteHeight * factor)) / 2;
} else {
new_y = y;
}
int x = (BUFFER_X - spriteData->spriteWidth) / 2;
int new_y = (y == -1)
? (BUFFER_Y - spriteData->spriteHeight) / 2
: y;
draw_drawSprite(
spr, x, new_y,
spriteData, spriteNumber, factor, flipped
);
draw_drawSprite(spr, x, new_y, spriteData, spriteNumber, flipped);
}
-1
View File
@@ -2,6 +2,5 @@
#define ENERGY_H
void energy_startLightSleep();
void energy_setUpLightSleep();
#endif
+88 -15
View File
@@ -1,28 +1,101 @@
#include "energy.h"
#include <Arduino.h>
#include <esp_sleep.h>
#include <driver/gpio.h>
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sprite_data.h"
#include "display/display.h"
#include "driver/rtc_io.h"
#include "defs/screen_defs.h"
#include "storage/storage.h"
#include "vpet/vpet/vpet.h"
#define SLEEP_TIME_US 15000000ull
#define BUTTON_PIN_BITMASK(GPIO) (1ULL << GPIO) // Macro for individual GPIO bitmask
void energy_setUpLightSleep() {
// Plena confianza en manolo
esp_sleep_enable_ext0_wakeup((gpio_num_t) K4_PIN, LOW);
esp_sleep_enable_timer_wakeup(SLEEP_TIME_US);
}
#define SLEEP_TIME_US 60000000ull // 60 seconds periodic wakeup
void energy_startLightSleep() {
printf("[ENERGY] Entering light sleep...\n");
// Keep RTC peripherals powered on during sleep so internal pullups/pulldowns stay active
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
// EXT1 wakeup uses the RTC IO subsystem. We must explicitly configure the RTC pull resistors
// so the pins do not float and cause immediate wake-ups.
// NOTE: We must initialize the pins as RTC GPIOs using rtc_gpio_init() first!
#if BUTTON_MODE == INPUT_PULLUP
rtc_gpio_init((gpio_num_t)K1_PIN); rtc_gpio_pullup_en((gpio_num_t)K1_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K1_PIN);
rtc_gpio_init((gpio_num_t)K2_PIN); rtc_gpio_pullup_en((gpio_num_t)K2_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K2_PIN);
rtc_gpio_init((gpio_num_t)K3_PIN); rtc_gpio_pullup_en((gpio_num_t)K3_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K3_PIN);
rtc_gpio_init((gpio_num_t)K4_PIN); rtc_gpio_pullup_en((gpio_num_t)K4_PIN); rtc_gpio_pulldown_dis((gpio_num_t)K4_PIN);
#else
rtc_gpio_init((gpio_num_t)K1_PIN); rtc_gpio_pulldown_en((gpio_num_t)K1_PIN); rtc_gpio_pullup_dis((gpio_num_t)K1_PIN);
rtc_gpio_init((gpio_num_t)K2_PIN); rtc_gpio_pulldown_en((gpio_num_t)K2_PIN); rtc_gpio_pullup_dis((gpio_num_t)K2_PIN);
rtc_gpio_init((gpio_num_t)K3_PIN); rtc_gpio_pulldown_en((gpio_num_t)K3_PIN); rtc_gpio_pullup_dis((gpio_num_t)K3_PIN);
rtc_gpio_init((gpio_num_t)K4_PIN); rtc_gpio_pulldown_en((gpio_num_t)K4_PIN); rtc_gpio_pullup_dis((gpio_num_t)K4_PIN);
#endif
esp_sleep_enable_timer_wakeup(SLEEP_TIME_US);
uint64_t mask = (1ULL << K1_PIN) | (1ULL << K2_PIN) | (1ULL << K3_PIN) | (1ULL << K4_PIN);
#if BUTTON_MODE == INPUT_PULLUP
#if defined(ESP_EXT1_WAKEUP_ANY_LOW)
esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ANY_LOW);
#else
esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ALL_LOW);
#endif
#else
esp_sleep_enable_ext1_wakeup(mask, ESP_EXT1_WAKEUP_ANY_HIGH);
#endif
digitalWrite(48, LOW);
esp_light_sleep_start();
printf("[MAIN] Woken up\n");
// Who woke you up???? TELL me!!
auto cause = esp_sleep_get_wakeup_cause();
digitalWrite(48, HIGH);
// Release the pins from RTC control after waking up so digitalRead works normally
rtc_gpio_deinit((gpio_num_t)K1_PIN);
rtc_gpio_deinit((gpio_num_t)K2_PIN);
rtc_gpio_deinit((gpio_num_t)K3_PIN);
rtc_gpio_deinit((gpio_num_t)K4_PIN);
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
printf("[ENERGY] Woken up. Cause: %d\n", cause);
runVpetTasks = true;
}
vpet_runVpetTasks();
if (cause == ESP_SLEEP_WAKEUP_TIMER) {
bool hasAlert = (
charaData[currentCharacter].hunger == 0 ||
charaData[currentCharacter].strength == 0 ||
charaData[currentCharacter].careMistakeCallLight ||
screenKey == TIMER_FINISHED_SCREEN
);
if (hasAlert) {
printf("[ENERGY] Periodic wakeup triggered, maybe care mistake.\n");
digitalWrite(BL_PIN, HIGH);
screenOff = false;
inactive = false;
if (screenKey != TIMER_FINISHED_SCREEN) {
screenKey = TIMER_FINISHED_SCREEN;
}
} else {
printf("[ENERGY] Periodic wake up triggered, no alerts. Sampling steps...\n");
isSamplingSteps = true;
sampleStartTime = esp_timer_get_time();
initialSteps = stepCounter;
storage_saveState();
}
} else if (cause == ESP_SLEEP_WAKEUP_EXT1) {
printf("[ENERGY] User button press detected.\n");
digitalWrite(BL_PIN, HIGH);
screenOff = false;
inactive = false;
screenKey = MAIN_SCREEN;
} else {
// Fallback for other wake-up causes to prevent high-speed loop thrashing
delay(200);
}
}
+86 -25
View File
@@ -15,13 +15,14 @@
#include "driver/rtc_io.h"
#include "loop/loop.h"
#include "menu/training/training_screens.h"
#include "defs/sounds.h"
#include "sound/sound.h"
const char* TAG = "[MAIN]";
// TFT_eSPI stuff, important
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite composite1 = TFT_eSprite(&tft);
TFT_eSprite composite2 = TFT_eSprite(&tft);
TFT_eSprite composite = TFT_eSprite(&tft);
TFT_eSprite sprite = TFT_eSprite(&tft);
TFT_eSprite bg = TFT_eSprite(&tft);
@@ -41,7 +42,7 @@ struct CharacterData* charaData;
uint8_t currentCharacter = 0;
// Boot flag, tells if the device clock has been initialized
bool coldBoot = true;
bool timeSet = false;
// Screen keys, this tells which screen is being shown the screens state machine
int screenKey = TITLE_SCREEN;
@@ -62,50 +63,71 @@ uint32_t dayUnixTime = 0;
Egg_t* eggSelection = NULL;
uint8_t eggNumber = 0;
// Background stuff
int currentBackground = 0;
// Tasks
TaskHandle_t secondLoop = NULL;
// Settings
bool soundEnabled = true;
bool alwaysOnEnabled = false;
// Background step counting
bool isSamplingSteps = false;
uint64_t sampleStartTime = 0;
uint16_t initialSteps = 0;
void loop2();
void secondCoreTask(void*);
void setup() {
Serial.begin(115200);
delay(100); // Give MPU6050 and ESP32 time to power up
//Wire.begin(MPU_SDA_PIN, MPU_SCL_PIN); // I2C init before MPU6050
//mpu.initialize();
while (!Serial) { }
//delay(10000);
pinMode(48, OUTPUT);
digitalWrite(48, HIGH);
Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); // I2C init before MPU6050
mpu.initialize();
tft_initDisplay(tft, TFT_BLACK);
tft_initScreenBuffer(TFT_BLACK);
tft_initScreenBuffer(TFT_TRANSPARENT);
tft.setRotation(2);
sound_init();
storage_init();
charaData = (struct CharacterData*) calloc(CHARA_COUNT_IN_DEVICE, sizeof(struct CharacterData));
storage_readFile("/menu.bin", &menuElementsData);
storage_readFile("/ui.bin", &uiElementsData);
storage_initBackground("/bg.bin", bg);
pinMode(K1_PIN, INPUT_PULLDOWN);
pinMode(K2_PIN, INPUT_PULLDOWN);
pinMode(K3_PIN, INPUT_PULLDOWN);
pinMode(K4_PIN, INPUT_PULLDOWN);
storage_initBackground(currentBackground, bg);
pinMode(K1_PIN, BUTTON_MODE);
pinMode(K2_PIN, BUTTON_MODE);
pinMode(K3_PIN, BUTTON_MODE);
pinMode(K4_PIN, BUTTON_MODE);
xTaskCreatePinnedToCore(secondCoreTask, "VPET_EVAL", 4096, NULL, 0, &secondLoop, 0);
sound_playMelody(SOUND_BOOT, SOUND_NOTE_COUNT(SOUND_BOOT));
lines_initLineStorage();
vpet_initTimer();
energy_setUpLightSleep();
storage_loadState();
}
void loop() {
switch (screenKey) {
case TITLE_SCREEN:
menu_drawTitle(bg);
menu_drawTitle(bg, composite);
break;
case CLOCK_EDIT_SCREEN:
@@ -185,7 +207,7 @@ void loop() {
break;
case EGG_EMPTY_SCREEN:
menu_drawDeathScreen( bg, sprite, &menuElementsData, &uiElementsData);
menu_drawDeathScreen(bg, sprite, &menuElementsData, &uiElementsData);
break;
case EVOLUTION_SCREEN:
@@ -193,7 +215,7 @@ void loop() {
break;
case TRAINING_SCREEN_1:
training_screenTraining1(bg, sprite, &mainCharacterSprites, &uiElementsData);
training_screenTraining2(bg, sprite, &mainCharacterSprites, &uiElementsData);
break;
case MAIN_SCREEN:
@@ -203,6 +225,22 @@ void loop() {
case CHANGE_SCREEN:
menu_changeCharaScreen(bg, sprite, &mainCharacterSprites, &uiElementsData);
break;
case FROZEN_SCREEN:
menu_drawFridgeScreen(bg, sprite, &mainCharacterSprites, &menuElementsData);
break;
case SETTINGS_SCREEN:
menu_settingsScreen(bg, sprite, &uiElementsData);
break;
case BACKGROUND_CHANGE_SCREEN:
menu_changeBackgroundScreen(bg, sprite, &uiElementsData);
break;
case RESET_DATA_SCREEN:
menu_resetDataScreen(bg);
break;
}
if (screenKey == IDLE_SCREEN || screenKey == OFF_SCREEN) {
@@ -217,11 +255,34 @@ void loop2() {
getLocalTime(&timeInfo, 50);
dayUnixTime = mktime(&timeInfo) % SECONDS_IN_DAY;
if (screenOff) { energy_startLightSleep(); }
if (screenOff) {
if (isSamplingSteps) {
uint64_t currentTime = esp_timer_get_time();
if ((currentTime - sampleStartTime) > 10000000) {
isSamplingSteps = false;
uint16_t sampledSteps = stepCounter - initialSteps;
uint16_t approximatedSteps = sampledSteps * 6;
stepCounter += approximatedSteps;
printf("[STEPS] Sampled %d steps in 10s, added %d approximated steps for sleep period.\n", sampledSteps, approximatedSteps);
energy_startLightSleep();
}
} else {
energy_startLightSleep();
}
} else {
isSamplingSteps = false;
}
sound_update();
}
void secondCoreTask(void*) {
for (;;) {
loop2();
}
}
}
+24 -28
View File
@@ -4,43 +4,39 @@
#include "display/display.h"
#include "draw/draw.h"
#include "animations/animations.h"
#include "defs/sounds.h"
void menu_drawAngryScreen(
TFT_eSprite &bg, TFT_eSprite &sprite,
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 = MAIN_SCREEN; // TODO: Change for while battling
menuKey = STATUS_SCREEN;
static uint8_t frameCounter = 0;
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);
animate_performAngryAnimation(sprite, spriteData);
if (frameCounter % 2 == 0) {
tone(SPK_PIN, 1000, 100);
tone(SPK_PIN, 1000, 200);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON, 6);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON, 6);
}
frameCounter++;
lastUpdateTime = currentTime;
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
}
frameCounter++;
lastUpdateTime = currentTime;
tft_drawBuffer();
}
}
}
+4 -4
View File
@@ -3,18 +3,18 @@
#include "animations/animations.h"
#include "display/display.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "draw/draw.h"
uint64_t lastBeepTime = esp_timer_get_time();
uint8_t beepCounter = 0;
void menu_careMistakeScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* uiSpritesBig) {
void menu_careMistakeScreen(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);
sound_playMelody(SOUND_CARE_ALERT, SOUND_NOTE_COUNT(SOUND_CARE_ALERT));
lastBeepTime = currentTime;
@@ -39,4 +39,4 @@ void menu_careMistakeScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteD
}
tft_drawBuffer();
}
}
+137 -68
View File
@@ -2,149 +2,217 @@
#include "draw/draw.h"
#include "display/display.h"
#include "defs/screen_defs.h"
#include "defs/sounds.h"
#include "vpet/evolution/evolution.h"
#include "loop/loop.h"
struct SpriteData* checkerboardPattern;
void menu_createCheckerboard() {
if (checkerboardPattern != NULL) {
return;
}
const uint8_t SCALE = 6;
const uint8_t logicalW = 34;
const uint8_t logicalH = 1;
const uint16_t scaledW = logicalW * SCALE;
const uint16_t scaledH = logicalH * SCALE;
const uint32_t bufferSize = scaledW * scaledH;
checkerboardPattern = (SpriteData*) malloc(sizeof(SpriteData));
checkerboardPattern->spriteHeight = 1;
checkerboardPattern->spriteWidth = 34;
checkerboardPattern->spriteWidth = scaledW;
checkerboardPattern->spriteHeight = scaledH;
checkerboardPattern->spriteNumber = 1;
checkerboardPattern->spriteData = (uint16_t**) malloc(sizeof(uint16_t*) * checkerboardPattern->spriteNumber);
checkerboardPattern->spriteData[0] = (uint16_t*) malloc(sizeof(uint16_t) * checkerboardPattern->spriteWidth);
for (int i = 0; i < checkerboardPattern->spriteWidth; i++) {
if (i % 2 == 0) {
checkerboardPattern->spriteData[0][i] = TFT_BLACK;
} else {
checkerboardPattern->spriteData[0][i] = TFT_TRANSPARENT;
checkerboardPattern->spriteData = (uint16_t**) malloc(sizeof(uint16_t*));
checkerboardPattern->spriteData[0] = (uint16_t*) malloc(sizeof(uint16_t) * bufferSize);
uint16_t* buf = checkerboardPattern->spriteData[0];
for (uint16_t row = 0; row < scaledH; row++) {
for (uint8_t col = 0; col < logicalW; col++) {
uint16_t color = (col % 2 == 0) ? TFT_BLACK : TFT_TRANSPARENT;
uint16_t* dst = buf + row * scaledW + col * SCALE;
for (uint8_t dx = 0; dx < SCALE; dx++) {
dst[dx] = color;
}
}
}
}
void menu_freeCheckerboard() {
if (checkerboardPattern == NULL) {
return;
}
free(checkerboardPattern->spriteData[0]);
free(checkerboardPattern->spriteData);
free(checkerboardPattern);
checkerboardPattern = NULL;
}
// Don't worry, I hate this too
void menu_evolutionScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* mainCharacterSprites) {
menu_createCheckerboard();
TFT_eSprite checkerboard = TFT_eSprite(&tft);
void menu_evolutionScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* mainCharacterSprites) {
enum EvolutionPhase {
EVOLUTION_INIT,
EVOLUTION_WOBBLE,
EVOLUTION_RED_FILL,
EVOLUTION_BLACK_FILL,
EVOLUTION_APPLY_CHANGE,
EVOLUTION_GREEN_REVEAL,
EVOLUTION_FINAL_REVEAL,
EVOLUTION_DONE
};
bool checkerboardShift = false;
static EvolutionPhase phase = EVOLUTION_INIT;
static TFT_eSprite checkerboard = TFT_eSprite(&tft);
static bool checkerboardShift = false;
static int frameIndex = 0;
tft_clearBuffer(sprite, TFT_TRANSPARENT);
sound_update();
for (int i = 0; i < 5;) {
uint64_t currentTime = esp_timer_get_time();
uint64_t currentTime = esp_timer_get_time();
if (phase == EVOLUTION_INIT) {
menu_createCheckerboard();
checkerboardShift = false;
frameIndex = 0;
tft_clearBuffer(sprite, TFT_TRANSPARENT);
lastUpdateTime = 0;
phase = EVOLUTION_WOBBLE;
return;
}
if (phase == EVOLUTION_WOBBLE) {
if (frameIndex >= 5) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
frameIndex = 0;
lastUpdateTime = 0;
phase = EVOLUTION_RED_FILL;
return;
}
if (currentTime - lastUpdateTime > 500000) {
tone(SPK_PIN, 4100, 50);
tone(SPK_PIN, 3500, 50);
sound_playMelody(SOUND_EVOLUTION_WOBBLE, SOUND_NOTE_COUNT(SOUND_EVOLUTION_WOBBLE));
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72 + ((i % 2 == 0) * 6), 72, mainCharacterSprites, 6, 6);
draw_drawSprite(sprite, 72 + ((frameIndex % 2 == 0) * 6), 72, mainCharacterSprites, 6);
tft_drawBuffer();
i++;
frameIndex++;
lastUpdateTime = currentTime;
}
return;
}
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7, 6);
if (phase == EVOLUTION_RED_FILL) {
if (frameIndex >= 16) {
frameIndex = 0;
lastUpdateTime = 0;
phase = EVOLUTION_BLACK_FILL;
return;
}
tft_clearBuffer(sprite, TFT_TRANSPARENT);
for (int i = 0; i < 16;) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6);
uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_RED);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, 6, checkerboardShift);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift);
tft_drawBuffer();
checkerboardShift = !checkerboardShift;
i++;
frameIndex++;
lastUpdateTime = currentTime;
}
return;
}
for (int i = 0; i < 16;) {
uint64_t currentTime = esp_timer_get_time();
if (phase == EVOLUTION_BLACK_FILL) {
if (frameIndex >= 16) {
frameIndex = 15;
lastUpdateTime = 0;
phase = EVOLUTION_APPLY_CHANGE;
return;
}
if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6);
uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_BLACK);
tft_drawBuffer();
checkerboardShift = !checkerboardShift;
i++;
frameIndex++;
lastUpdateTime = currentTime;
}
return;
}
change_onChangeComplete();
if (phase == EVOLUTION_APPLY_CHANGE) {
change_onChangeComplete();
lastUpdateTime = 0;
phase = EVOLUTION_GREEN_REVEAL;
return;
}
if (phase == EVOLUTION_GREEN_REVEAL) {
if (frameIndex < 0) {
frameIndex = 15;
lastUpdateTime = 0;
phase = EVOLUTION_FINAL_REVEAL;
return;
}
for (int i = 15; i >= 0;) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 100000) {
uint8_t startYPos = 72 + (i * 6);
uint8_t startYPos = 72 + (frameIndex * 6);
tft_drawRectangle(18, startYPos, 204, 6, TFT_GREEN);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, 6, checkerboardShift);
draw_drawSprite(checkerboard, 18, startYPos, checkerboardPattern, 0, checkerboardShift);
tft_drawBuffer();
checkerboardShift = !checkerboardShift;
i--;
frameIndex--;
lastUpdateTime = currentTime;
}
return;
}
for (int i = 15; i >= 0;) {
uint64_t currentTime = esp_timer_get_time();
if (phase == EVOLUTION_FINAL_REVEAL) {
if (frameIndex < 0) {
phase = EVOLUTION_DONE;
return;
}
if (currentTime - lastUpdateTime > 100000) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7, 6);
draw_drawSprite(sprite, 72, 72, mainCharacterSprites, 7);
uint8_t rectHeight = (6 * i);
uint8_t rectHeight = 6 * frameIndex;
tft_drawRectangle(18, 72, 204, rectHeight, TFT_GREEN);
for (int j = 0; j < i; j++) {
for (int j = 0; j < frameIndex; j++) {
uint8_t rectYPos = 72 + (6 * j);
draw_drawSprite(checkerboard, 18, rectYPos, checkerboardPattern, 0, 6, checkerboardShift);
draw_drawSprite(checkerboard, 18, rectYPos, checkerboardPattern, 0, checkerboardShift);
checkerboardShift = !checkerboardShift;
}
tft_drawBuffer();
i--;
frameIndex--;
lastUpdateTime = currentTime;
}
return;
}
tone(SPK_PIN, 2100, 100);
tone(SPK_PIN, 3500, 100);
tone(SPK_PIN, 4100, 100);
tone(SPK_PIN, 4650, 200);
sound_playMelody(SOUND_EVOLUTION_COMPLETE, SOUND_NOTE_COUNT(SOUND_EVOLUTION_COMPLETE));
lastPressedButtonTime = esp_timer_get_time();
@@ -152,7 +220,8 @@ void menu_evolutionScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteDat
vTaskResume(secondLoop);
phase = EVOLUTION_INIT;
screenKey = MAIN_SCREEN;
lastUpdateTime = 0; // Un pequeño empujoncito
}
lastUpdateTime = 0;
}
+91
View File
@@ -0,0 +1,91 @@
#include "menu.h"
#include "defs/sprite_data.h"
#include "buttons/buttons.h"
#include "draw/draw.h"
#include "storage/storage.h"
#include "display/display.h"
#include "defs/screen_defs.h"
void menu_changeBackgroundScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSpriteData
) {
static bool initialized = false;
static int8_t selectedBackground = 0;
static int8_t selectedPreviousBackground = -1;
static uint8_t backgrounds = 0;
static uint64_t screenLastActionTime = 0;
uint64_t currentTime = esp_timer_get_time();
if (!initialized) {
fs::File bgFolder = SPIFFS.open("/bg");
fs::File background = bgFolder.openNextFile();
backgrounds = 0;
while (background) {
if (!background.isDirectory()) {
backgrounds++;
}
background = bgFolder.openNextFile();
}
selectedBackground = currentBackground;
selectedPreviousBackground = -1;
screenLastActionTime = currentTime;
initialized = true;
printf("[BACKGROUNDS] numBackgrounds=%i\n", backgrounds);
}
uint8_t buttonsPressed = buttons_getPressedButtons();
switch (buttonsPressed) {
case K1_PRESSED:
selectedBackground--;
if (selectedBackground < 0) {
selectedBackground = backgrounds - 1;
}
storage_initBackground(selectedBackground, bg);
screenLastActionTime = currentTime;
break;
case K2_PRESSED:
selectedBackground++;
if (selectedBackground >= backgrounds) {
selectedBackground = 0;
}
storage_initBackground(selectedBackground, bg);
screenLastActionTime = currentTime;
break;
case K3_PRESSED:
currentBackground = selectedBackground;
initialized = false;
screenKey = MAIN_SCREEN;
return;
case K4_PRESSED:
storage_initBackground(currentBackground, bg);
initialized = false;
screenKey = MAIN_SCREEN;
return;
default:
break;
}
if (selectedPreviousBackground != selectedBackground) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON);
tft_drawBuffer();
selectedPreviousBackground = selectedBackground;
}
if (currentTime - screenLastActionTime > INACTIVITY_THRESHOLD_TIME_US) {
printf("[BACKGROUND] Returning home cuz yes\n");
storage_initBackground(currentBackground, bg);
initialized = false;
screenKey = MAIN_SCREEN;
}
}
+74 -68
View File
@@ -8,84 +8,90 @@
#include "defs/defs.h"
void menu_changeCharaScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* mainSpriteData, struct SpriteData* uiSpriteData) {
vTaskSuspend(secondLoop);
void menu_changeCharaScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* mainSpriteData, struct SpriteData* uiSpriteData) {
static bool initialized = false;
static uint8_t selectedChara = 0;
static CharacterData* selectedCharaData = NULL;
static bool updateScreen = true;
uint8_t selectedChara = currentCharacter;
CharacterData* selectedCharaData = &charaData[selectedChara];
if (!initialized) {
selectedChara = currentCharacter;
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
initialized = true;
}
bool updateScreen = true;
for (;;) {
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
selectedChara++;
if (selectedChara >= CHARA_COUNT_IN_DEVICE) {
selectedChara = 0;
}
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
break;
case K2_PRESSED:
currentCharacter = selectedChara;
vTaskResume(secondLoop);
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
break;
case K3_PRESSED:
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(fileName, mainSpriteData);
vTaskResume(secondLoop);
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
break;
default:
break;
}
delay(15);
if (updateScreen) {
draw_drawBackground(bg, 90, 90, 3);
if (selectedCharaData->hatched) {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", selectedCharaData->idChara);
storage_readFile(fileName, mainSpriteData);
draw_drawSprite(sprite, 18, 72, mainSpriteData, 0, 6);
} else {
tft_drawCenteredText("EMPTY", 4, 120);
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
selectedChara--;
if (selectedChara < 0) {
selectedChara = CHARA_COUNT_IN_DEVICE - 1;
}
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
break;
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON, 6);
tft_drawBuffer();
case K2_PRESSED:
selectedChara++;
if (selectedChara >= CHARA_COUNT_IN_DEVICE) {
selectedChara = 0;
}
selectedCharaData = &charaData[selectedChara];
updateScreen = true;
break;
updateScreen = false;
}
case K3_PRESSED:
currentCharacter = selectedChara;
initialized = false;
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US) {
case K4_PRESSED: {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(fileName, mainSpriteData);
vTaskResume(secondLoop);
storage_readFile(fileName, mainSpriteData);
initialized = false;
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
return;
}
default:
break;
}
}
if (updateScreen) {
draw_drawBackground(bg, 90, 90, 3);
if (selectedCharaData->hatched) {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", selectedCharaData->idChara);
storage_readFile(fileName, mainSpriteData);
draw_drawSprite(sprite, 18, 72, mainSpriteData, 0);
} else {
tft_drawCenteredText("EMPTY", 4, 120);
}
draw_drawSprite(sprite, 174, 96, uiSpriteData, ARROW_ICON);
tft_drawBuffer();
updateScreen = false;
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastPressedButtonTime > INACTIVITY_THRESHOLD_TIME_US) {
char fileName[20];
sprintf(fileName, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(fileName, mainSpriteData);
initialized = false;
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN;
}
}
+18 -6
View File
@@ -4,11 +4,19 @@
#include "display/display.h"
#include "buttons/buttons.h"
#include "defs/screen_defs.h"
#include "vpet/vpet/vpet.h"
void menu_drawClock(TFT_eSprite &bg) {
void menu_drawClock(TFT_eSprite& bg) {
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K2_PRESSED | K3_PRESSED:
screenKey = CLOCK_EDIT_SCREEN;
break;
case K1_PRESSED:
case K2_PRESSED:
case K3_PRESSED:
case K4_PRESSED:
draw_drawBackground(bg, 90, 90, 3);
screenKey = MAIN_SCREEN;
break;
@@ -30,7 +38,7 @@ void menu_drawClock(TFT_eSprite &bg) {
tft_drawBuffer();
}
void menu_drawClockEdit(TFT_eSprite &bg) {
void menu_drawClockEdit(TFT_eSprite& bg) {
char textBuffer[6];
static int clockHourCount = 0;
@@ -46,14 +54,18 @@ void menu_drawClockEdit(TFT_eSprite &bg) {
case K2_PRESSED:
clockMinuteCount = (clockMinuteCount + 1) % 60;
break;
case K3_PRESSED:
case K4_PRESSED:
// Es un dia random, nada significativo, ya pondre mas adelante que tenga dia del año
rtc.setTime(0, clockMinuteCount, clockHourCount, 1, 11, 2024);
srand(time(NULL));
coldBoot = false;
timeSet = true;
screenKey = CLOCK_SCREEN;
vpet_initTimer();
break;
default:
+6 -5
View File
@@ -6,24 +6,25 @@
#include "defs/sprite_data.h"
#include "vpet/lines/lines.h"
void menu_drawDeathScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiBigSprite, struct SpriteData* uiSmallSprite) {
void menu_drawDeathScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* uiBigSprite, struct SpriteData* uiSmallSprite) {
static uint8_t frameCounter = 0;
uint64_t currentTime = esp_timer_get_time();
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
case K4_PRESSED:
lines_getAvailableLines();
screenKey = EGG_SELECT_SCREEN;
return;
break;
case K2_PRESSED:
case K3_PRESSED:
screenKey = CLOCK_SCREEN;
return;
break;
case K3_PRESSED:
case K1_PRESSED:
case K2_PRESSED:
lastUpdateTime = currentTime;
frameCounter = 0;
@@ -33,7 +34,7 @@ void menu_drawDeathScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteDat
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 72 + (6 * (frameCounter == 0)), 72, uiBigSprite, EMPTY_EGG, 6);
draw_drawSprite(sprite, 72 + (6 * (frameCounter == 0)), 72, uiBigSprite, EMPTY_EGG);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, uiSmallSprite);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
+68 -35
View File
@@ -8,14 +8,28 @@
#include "animations/animations.h"
#include "vpet/vpet/vpet.h"
#include "vpet/lines/lines.h"
#include "defs/sounds.h"
void menu_eggHatchScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiBigSprite, struct SpriteData* uiSmallSprite) {
const uint64_t HATCH_ANIMATION_FRAME_TIME_US = 100000;
const uint64_t HATCH_COMPLETE_HOLD_TIME_US = 2000000;
void menu_eggHatchScreen(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* uiBigSprite, struct SpriteData* uiSmallSprite) {
static bool eggSpriteFrame = false;
static bool hatchSoundStarted = false;
static uint8_t hatchingFrame = 0;
static uint64_t hatchHoldStartTime = 0;
static uint64_t hatchAnimationLastFrameTime = 0;
sound_update();
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
switch (pressedButtons) {
case K2_PRESSED:
screenKey = CLOCK_SCREEN;
hatchSoundStarted = false;
hatchingFrame = 0;
hatchHoldStartTime = 0;
hatchAnimationLastFrameTime = 0;
break;
default:
@@ -23,39 +37,58 @@ void menu_eggHatchScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
if (charaData[currentCharacter].hatchTimer <= currentLine[currentCharacter]->hatchTime) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, eggSpriteFrame, 6);
eggSpriteFrame = !eggSpriteFrame;
lastUpdateTime = currentTime;
tft_drawBuffer();
} else if (charaData[currentCharacter].hatchTimer > currentLine[currentCharacter]->hatchTime && !charaData[currentCharacter].hatched) {
for (int i = 0; i < 30; i++) {
tone(SPK_PIN, 4100, 35);
tone(SPK_PIN, 3500, 35);
draw_drawBackground(bg, 90, 90, 3);
animate_performHatchingAnimation(sprite, &currentEgg->eggSprite);
tft_drawBuffer();
}
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, 2, 6);
tft_drawBuffer();
delay(2000);
if (hatchHoldStartTime > 0) {
if (currentTime - hatchHoldStartTime > HATCH_COMPLETE_HOLD_TIME_US) {
hatchHoldStartTime = 0;
hatchSoundStarted = false;
hatchingFrame = 0;
hatchAnimationLastFrameTime = 0;
lines_onHatchComplete();
}
return;
}
if (charaData[currentCharacter].hatchTimer > currentLine[currentCharacter]->hatchTime && !charaData[currentCharacter].hatched) {
if (!hatchSoundStarted) {
sound_playMelody(SOUND_HATCH, SOUND_NOTE_COUNT(SOUND_HATCH));
hatchSoundStarted = true;
hatchAnimationLastFrameTime = 0;
}
if (hatchingFrame < 30 && currentTime - hatchAnimationLastFrameTime > HATCH_ANIMATION_FRAME_TIME_US) {
draw_drawBackground(bg, 90, 90, 3);
animate_performHatchingAnimation(sprite, &currentEgg->eggSprite);
tft_drawBuffer();
hatchingFrame++;
hatchAnimationLastFrameTime = currentTime;
return;
}
if (hatchingFrame < 30) {
return;
}
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, 2);
tft_drawBuffer();
hatchHoldStartTime = currentTime;
return;
}
}
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, &currentEgg->eggSprite, eggSpriteFrame);
eggSpriteFrame = !eggSpriteFrame;
lastUpdateTime = currentTime;
tft_drawBuffer();
}
}
+8 -4
View File
@@ -9,16 +9,20 @@
#include "vpet/vpet/vpet.h"
void menu_lineSwitcher(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSmallSprite) {
void menu_lineSwitcher(TFT_eSprite& bg, TFT_eSprite &sprite, struct SpriteData* uiSmallSprite) {
static uint8_t eggCounter = 0;
uint8_t buttonsPressed = buttons_getPressedButtons();
switch(buttonsPressed) {
case K1_PRESSED:
eggCounter = (eggCounter - 1) % eggNumber;
break;
case K2_PRESSED:
eggCounter = (eggCounter + 1) % eggNumber;
break;
case K2_PRESSED:
case K4_PRESSED:
menu_reloadEggs(eggCounter);
eggCounter = 0;
screenKey = EGG_HATCH_SCREEN;
@@ -36,9 +40,9 @@ void menu_lineSwitcher(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSpriteCentered(sprite, &eggSelection[eggCounter].eggSprite, 0, 6);
draw_drawSpriteCentered(sprite, &eggSelection[eggCounter].eggSprite, 0);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 194, 96, uiSmallSprite, ARROW_ICON, 6);
draw_drawSprite(sprite, 194, 96, uiSmallSprite, ARROW_ICON);
tft_drawBuffer();
}
+2 -2
View File
@@ -5,7 +5,7 @@
#include "display/display.h"
void menu_feedingScreen(
TFT_eSprite &bg, TFT_eSprite &charaSprite,
TFT_eSprite& bg, TFT_eSprite &charaSprite,
struct SpriteData* uiSpriteData, struct SpriteData* charaSpriteData, uint8_t item
) {
static int currentAnimationFrame = 0;
@@ -19,7 +19,7 @@ void menu_feedingScreen(
animate_performEatingAnimation(charaSprite, charaSpriteData);
tft_clearBuffer(charaSprite, TFT_TRANSPARENT);
draw_drawSprite(charaSprite, 24, 120, uiSpriteData, item, 6);
draw_drawSprite(charaSprite, 24, 120, uiSpriteData, item);
lastUpdateTime = currentTime;
currentAnimationFrame++;
+91 -77
View File
@@ -1,92 +1,106 @@
#include "menu.h"
#include "display/display.h"
#include "draw/draw.h"
#include "buttons/buttons.h"
#include "defs/chara_data.h"
#include "display/display.h"
#include "draw/draw.h"
#include "menu.h"
#include "defs/sounds.h"
#include "vpet/vpet/vpet.h"
void menu_foodScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData* spriteData) {
if (charaData[currentCharacter].sleepy) {
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
delay(100);
tone(SPK_PIN, BEEP_FREQ_HZ, BEEP_LEN_MS);
screenKey = MENU_SCREEN;
return;
}
void menu_foodScreen(TFT_eSprite &bg, TFT_eSprite &mainChara,
struct SpriteData *spriteData) {
if (charaData[currentCharacter].sleepy) {
sound_playMelody(SOUND_BUTTON_BEEP, SOUND_NOTE_COUNT(SOUND_BUTTON_BEEP));
screenKey = MENU_SCREEN;
static uint8_t arrowPosition = 0;
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 8:
arrowPosition = (arrowPosition + 1) % 2;
break;
return;
}
case 2:
screenKey = MENU_SCREEN;
break;
default:
break;
}
if (pressedButtons == 4) {
lastUpdateTime = 0;
switch(arrowPosition) {
case 0:
if (charaData[currentCharacter].hunger < 8) {
charaData[currentCharacter].hungerCareMistakeTimer = charaData[currentCharacter].initialStatsReductionTime;
charaData[currentCharacter].hungerCareMistakeObtained = false;
charaData[currentCharacter].weight++;
charaData[currentCharacter].hunger++;
screenKey = FEEDING_SCREEN;
submenuKey = FOOD_ICON;
} else {
screenKey = REFUSING_SCREEN;
if (!charaData[currentCharacter].overfeedHappened) {
charaData[currentCharacter].overfeed++;
charaData[currentCharacter].overfeedHappened = true;
}
}
return;
break;
static int8_t arrowPosition = 0;
const int numItems = 2;
case 1:
if (charaData[currentCharacter].strength < 8) {
charaData[currentCharacter].strengthCareMistakeTimer = charaData[currentCharacter].initialStatsReductionTime;
charaData[currentCharacter].strength++;
charaData[currentCharacter].weight += 2;
screenKey = FEEDING_SCREEN;
submenuKey = PILL_ICON;
} else {
screenKey = REFUSING_SCREEN;
}
return;
break;
default:
break;
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition--;
if (arrowPosition < 0) {
arrowPosition = numItems - 1;
}
break;
case K2_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition++;
if (arrowPosition >= numItems) {
arrowPosition = 0;
}
break;
case K3_PRESSED:
screenKey = MENU_SCREEN;
break;
default:
break;
}
if (pressedButtons == K4_PRESSED) {
lastUpdateTime = 0;
switch (arrowPosition) {
case 0:
if (charaData[currentCharacter].hunger < 8) {
charaData[currentCharacter].hungerCareMistakeTimer =
charaData[currentCharacter].initialStatsReductionTime;
charaData[currentCharacter].hungerCareMistakeObtained = false;
charaData[currentCharacter].weight++;
charaData[currentCharacter].hunger++;
screenKey = FEEDING_SCREEN;
submenuKey = FOOD_ICON;
} else {
screenKey = REFUSING_SCREEN;
if (!charaData[currentCharacter].overfeedHappened) {
charaData[currentCharacter].overfeed++;
charaData[currentCharacter].overfeedHappened = true;
}
}
return;
break;
vpet_computeCallLight();
case 1:
if (charaData[currentCharacter].strength < 8) {
charaData[currentCharacter].strengthCareMistakeTimer =
charaData[currentCharacter].initialStatsReductionTime;
charaData[currentCharacter].strength++;
charaData[currentCharacter].weight += 2;
screenKey = FEEDING_SCREEN;
submenuKey = PILL_ICON;
} else {
screenKey = REFUSING_SCREEN;
}
return;
break;
default:
break;
}
vpet_computeCallLight();
}
draw_drawBackground(bg, 90, 90, 3);
menu_foodScreen_drawEntry(mainChara, spriteData, 0, FOOD_ICON, "Meat");
menu_foodScreen_drawEntry(mainChara, spriteData, 1, PILL_ICON, "Pill");
draw_drawSprite(mainChara, 5, (arrowPosition * 34) + 5, spriteData, ARROW_ICON, 4);
draw_drawBackground(bg, 90, 90, 3);
menu_foodScreen_drawEntry(mainChara, spriteData, 0, FOOD_ICON, "Meat");
menu_foodScreen_drawEntry(mainChara, spriteData, 1, PILL_ICON, "Pill");
tft_drawBuffer();
draw_drawSprite(mainChara, 5, (arrowPosition * 34) + 5, spriteData,
ARROW_ICON);
tft_drawBuffer();
}
void menu_foodScreen_drawEntry(
TFT_eSprite &mainChara, struct SpriteData* spriteData,
uint8_t entryId, uint8_t spriteNumber, const char* textEntry
) {
tft_clearBuffer(mainChara, TFT_TRANSPARENT);
draw_drawSprite(mainChara, 45, (entryId * 34) + 5, spriteData, spriteNumber, 4);
tft_drawText(textEntry, 4, 80, (entryId * 34) + 5);
}
void menu_foodScreen_drawEntry(TFT_eSprite &mainChara,
struct SpriteData *spriteData, uint8_t entryId,
uint8_t spriteNumber, const char *textEntry) {
tft_clearBuffer(mainChara, TFT_TRANSPARENT);
draw_drawSprite(mainChara, 45, (entryId * 34) + 5, spriteData, spriteNumber);
tft_drawText(textEntry, 4, 80, (entryId * 34) + 5);
}
+35
View File
@@ -0,0 +1,35 @@
#include "menu.h"
#include "buttons/buttons.h"
#include "draw/draw.h"
#include "display/display.h"
void menu_drawFridgeScreen(TFT_eSprite &bg, TFT_eSprite& sprite, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements) {
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
menuKey = STATUS_SCREEN_MENU;
break;
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
default:
break;
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, bigUiElements, FRIDGE_DOOR);
menu_uiOverlay(sprite, bigUiElements);
lastUpdateTime = currentTime;
}
tft_drawBuffer();
}
+25 -31
View File
@@ -4,45 +4,39 @@
#include "display/display.h"
#include "draw/draw.h"
#include "animations/animations.h"
#include "defs/sounds.h"
void menu_drawHappyScreen(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements
TFT_eSprite& bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements, const int returnScreen
) {
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;
static uint8_t frameCounter = 0;
vTaskResume(secondLoop);
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US) {
if (frameCounter > 3) {
frameCounter = 0;
screenKey = returnScreen; // TODO: Change for while battling
menuKey = STATUS_SCREEN;
return;
}
return;
}
draw_drawBackground(bg, 90, 90, 3);
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);
animate_performHappyAnimation(sprite, spriteData);
if (frameCounter % 2 == 0) {
tone(SPK_PIN, 7500, 50);
tone(SPK_PIN, 5000, 50);
tone(SPK_PIN, 2500, 50);
tone(SPK_PIN, 1000, 50);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON, 6);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON, 6);
}
frameCounter++;
lastUpdateTime = currentTime;
draw_drawSprite(sprite, 18, 72, smallUiElements, FIREWORKS_ICON);
draw_drawSprite(sprite, 174, 72, smallUiElements, FIREWORKS_ICON);
}
frameCounter++;
lastUpdateTime = currentTime;
tft_drawBuffer();
}
}
}
+3 -2
View File
@@ -12,11 +12,12 @@ void menu_drawIdleScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
menuKey = 0;
menuKey = STATUS_SCREEN_MENU;
break;
case K2_PRESSED:
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
+5 -1
View File
@@ -4,10 +4,14 @@
void menu_mainScreen() {
printf("[MAINSCR] on main screen\n");
lastUpdateTime = 0;
if (coldBoot) {
if (!timeSet) {
screenKey = TITLE_SCREEN;
return;
} else if (charaData[currentCharacter].frozen) {
screenKey = FROZEN_SCREEN;
return;
} else if (!charaData[currentCharacter].hatched && !charaData[currentCharacter].hatching) {
screenKey = EGG_EMPTY_SCREEN;
return;
+16 -3
View File
@@ -3,11 +3,12 @@
#include <TFT_eSPI.h>
#include "defs/defs.h"
#include "defs/sprite_data.h"
void menu_drawCurrentMenuOption(TFT_eSprite &bg, TFT_eSprite &icon, struct SpriteData* spriteData);
void menu_drawClock(TFT_eSprite &bg);
void menu_drawClockEdit(TFT_eSprite &bg);
void menu_drawTitle(TFT_eSprite &bg);
void menu_drawTitle(TFT_eSprite &bg, TFT_eSprite &composite);
void menu_drawIdleScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements);
void menu_offScreen();
void menu_statusScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData);
@@ -38,7 +39,7 @@ uint8_t menu_poopOverlay(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData
void menu_clearPoopScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements);
void menu_drawHappyScreen(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements
struct SpriteData* spriteData, struct SpriteData* smallUiElements, const int returnScreen = MAIN_SCREEN
);
void menu_lineSwitcher(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSmallSprite);
void menu_eggHatchScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiBigSprite, struct SpriteData* uiSmallSprite);
@@ -51,8 +52,20 @@ void menu_drawAngryScreen(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements
);
void menu_drawFridgeScreen(TFT_eSprite &bg, TFT_eSprite& sprite, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements);
void training_screenTraining2(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
);
void menu_changeBackgroundScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* uiSpriteData
);
void menu_settingsScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData *spriteData);
void menu_settingsScreen_drawEntry(uint8_t entryId, const char *textEntry);
void menu_resetDataScreen(TFT_eSprite &bg);
void menu_sleepScreen_sleepAction();
void menu_sleepScreen_recalculateSleep();
void menu_freezeScreen_alternateFreeze();
#endif
#endif
+44 -8
View File
@@ -12,7 +12,7 @@
const int textXPos = 10;
const int textYPos = 180;
void menu_drawCurrentMenuOption(TFT_eSprite &bg, TFT_eSprite &icon, struct SpriteData* spriteData) {
void menu_drawCurrentMenuOption(TFT_eSprite& bg, TFT_eSprite &icon, struct SpriteData* spriteData) {
draw_drawBackground(bg, 90, 90, 3);
uint8_t pressedButtons = buttons_getPressedButtons();
@@ -22,6 +22,13 @@ void menu_drawCurrentMenuOption(TFT_eSprite &bg, TFT_eSprite &icon, struct Sprit
menuKey++;
break;
case K2_PRESSED:
menuKey--;
if (menuKey < 0) {
menuKey = FREEZE_SCREEN_MENU;
}
break;
case K3_PRESSED:
screenKey = MAIN_SCREEN;
menuKey = STATUS_SCREEN_MENU;
@@ -33,26 +40,33 @@ void menu_drawCurrentMenuOption(TFT_eSprite &bg, TFT_eSprite &icon, struct Sprit
}
// Separaíto mas guapito
if (pressedButtons == K2_PRESSED) {
if (pressedButtons == K4_PRESSED) {
const uint64_t currentTime = esp_timer_get_time();
lastUpdateTime = currentTime;
switch (menuKey) {
case STATUS_SCREEN_MENU:
screenKey = STATUS_SCREEN;
break;
case FOOD_SCREEN_MENU:
if (charaData[currentCharacter].frozen) { break; }
screenKey = FOOD_SCREEN;
break;
case SLEEP_SCREEN_MENU:
if (charaData[currentCharacter].frozen) { break; }
menu_sleepScreen_sleepAction();
break;
case TRAIN_SCREEN_MENU:
if (charaData[currentCharacter].frozen) { break; }
screenKey = TRAINING_SCREEN_1;
return;
break;
case POOP_SCREEN_MENU:
if (charaData[currentCharacter].frozen) { break; }
menuKey = STATUS_SCREEN;
screenKey = CLEAR_POOP_SCREEN;
return;
@@ -64,15 +78,26 @@ void menu_drawCurrentMenuOption(TFT_eSprite &bg, TFT_eSprite &icon, struct Sprit
return;
break;
case FREEZE_SCREEN_MENU:
menu_freezeScreen_alternateFreeze();
return;
break;
case SETTINGS_SCREEN_MENU:
menuKey = STATUS_SCREEN;
screenKey = SETTINGS_SCREEN;
return;
break;
default:
break;
}
return;
}
draw_drawSpriteCentered(icon, spriteData, menuKey % 9, 6);
draw_drawSpriteCentered(icon, spriteData, menuKey % 10);
switch(menuKey % 10) {
switch(menuKey % 11) {
case STATUS_SCREEN_MENU:
tft_drawCenteredText("Status", 4, textYPos);
break;
@@ -108,8 +133,12 @@ void menu_drawCurrentMenuOption(TFT_eSprite &bg, TFT_eSprite &icon, struct Sprit
case SETTINGS_SCREEN_MENU:
tft_drawCenteredText("Settings", 4, textYPos);
break;
case 9:
case FREEZE_SCREEN_MENU:
tft_drawCenteredText("Freeze", 4, textYPos);
break;
case 10:
menuKey = STATUS_SCREEN_MENU;
screenKey = MAIN_SCREEN;
return;
@@ -130,7 +159,7 @@ void menu_sleepScreen_sleepAction() {
charaData[currentCharacter].sleepDisturbances++;
menuKey = STATUS_SCREEN;
menuKey = STATUS_SCREEN_MENU;
screenKey = MAIN_SCREEN;
} else {
@@ -138,11 +167,18 @@ void menu_sleepScreen_sleepAction() {
vpet_computeCallLight(); // Lo hago por cortesia, no me gusta
menuKey = STATUS_SCREEN;
menuKey = STATUS_SCREEN_MENU;
screenKey = SLEEP_SCREEN;
}
}
void menu_freezeScreen_alternateFreeze() {
charaData[currentCharacter].frozen = !charaData[currentCharacter].frozen;
menuKey = STATUS_SCREEN;
screenKey = MAIN_SCREEN;
}
void menu_sleepScreen_recalculateSleep() {
uint32_t newSleepTime = (dayUnixTime + 3600) % SECONDS_IN_DAY;
uint32_t newWakeUpTime = charaData[currentCharacter].wakeupTime + 3600;
+34 -33
View File
@@ -9,43 +9,44 @@
void menu_clearPoopScreen(
TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData, struct SpriteData* bigUiElements, struct SpriteData* smallUiElements
) {
printf("[AAAAAAA] pausing loop...\n");
static bool initialized = false;
static int cleanerXPos = 174;
vTaskSuspend(secondLoop);
if (!initialized) {
cleanerXPos = 174;
lastUpdateTime = 0;
printf("[AAAAAAA] loop paused...\n");
draw_drawBackground(bg, 90, 90, 3);
uint8_t offsetX = menu_poopOverlay(bg, sprite, smallUiElements);
int cleanerXPos = 174;
animate_performAnimation(sprite, spriteData, offsetX);
menu_uiOverlay(sprite, bigUiElements);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
lastUpdateTime = 0;
printf("[AAAAAAA] drawing idle screen...\n");
draw_drawBackground(bg, 90, 90, 3);
uint8_t offsetX = menu_poopOverlay(bg, sprite, smallUiElements);
printf("[AAAAAAA] drawing animation...\n");
animate_performAnimation(sprite, spriteData, offsetX);
printf("[AAAAAAA] drawing overlay...\n");
menu_uiOverlay(sprite, bigUiElements);
printf("[AAAAAAA] idle screen down...\n");
tft_clearBuffer(sprite, TFT_TRANSPARENT);
while (cleanerXPos > 18) {
draw_drawSprite(sprite, cleanerXPos, 72, smallUiElements, CLEANER_ICON, 6);
draw_drawSprite(sprite, cleanerXPos, 120, smallUiElements, CLEANER_ICON, 6);
tft_drawBuffer();
cleanerXPos -= 6;
delay(50);
initialized = true;
}
screenKey = HAPPY_SCREEN;
charaData[currentCharacter].poopNumber = 0;
if (cleanerXPos <= 18 - 48) {
screenKey = HAPPY_SCREEN;
menuKey = -1;
charaData[currentCharacter].poopNumber = 0;
initialized = false;
return;
}
return;
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > 50000) {
draw_drawBackgroundSection(bg, cleanerXPos + 6, 72, 48, 96);
draw_drawSprite(sprite, cleanerXPos, 72, smallUiElements, CLEANER_ICON);
draw_drawSprite(sprite, cleanerXPos, 120, smallUiElements, CLEANER_ICON);
draw_drawBackgroundSection(bg, 0, 72, 18, 96);
tft_drawBuffer();
cleanerXPos -= 6;
lastUpdateTime = currentTime;
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ uint8_t menu_poopOverlay(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData
bool poopTop = false;
for (int i = 0; i < charaData[currentCharacter].poopNumber; i++) {
draw_drawSprite(sprite, poopStartX, poopStartY - (48 * poopTop), smallUiElements, POOP_ICON, 6, poopFlip);
draw_drawSprite(sprite, poopStartX, poopStartY - (48 * poopTop), smallUiElements, POOP_ICON, poopFlip);
poopStartX -= (i % 2) * 48;
poopTop = !poopTop;
}
+52 -58
View File
@@ -4,78 +4,72 @@
#include "display/display.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
void menu_poopScreen(
TFT_eSprite &bg, TFT_eSprite &sprite,
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* spriteData, struct SpriteData* smallUiElements, struct SpriteData* bigUiElements
) {
uint8_t animationFrame = 0;
bool animationPosition = 0;
static uint8_t animationFrame = 0;
static bool animationPosition = 0;
static bool beepedAlready = false;
bool beepedAlready = false;
uint64_t currentTime = esp_timer_get_time();
while (1) {
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 4) {
draw_drawBackground(bg, 90, 90, 3);
if (currentTime - lastUpdateTime > ANIMATION_THRESHOLD_TIME_US && animationFrame < 4) {
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72 + (animationPosition * 6), 72, spriteData, 6, 6);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72 + (animationPosition * 6), 72, spriteData, 6);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
animationFrame++;
animationPosition = !animationPosition;
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
lastUpdateTime = currentTime;
animationFrame++;
animationPosition = !animationPosition;
} 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);
lastUpdateTime = currentTime;
tft_drawBuffer();
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);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 174, 120, smallUiElements, POOP_ICON, 6);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72, 72, spriteData, 7, 6);
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 = 0;
animationFrame = 0;
animationPosition = 0;
break;
beepedAlready = true;
}
draw_drawBackground(bg, 90, 90, 3);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 174, 120, smallUiElements, POOP_ICON);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72, 72, spriteData, 7);
animationFrame++;
animationPosition = !animationPosition;
lastUpdateTime = currentTime;
tft_drawBuffer();
} else if (animationFrame >= 6) {
if (
(charaData[currentCharacter].hunger == 0 && !charaData[currentCharacter].hungerCareMistakeObtained) ||
(charaData[currentCharacter].strength == 0 && !charaData[currentCharacter].strengthCareMistakeObtained) ||
(charaData[currentCharacter].sleepy && !charaData[currentCharacter].asleep && !charaData[currentCharacter].sleepCareMistakeObtained)
) {
screenKey = CARE_MISTAKE_SCREEN;
} else {
screenKey = MAIN_SCREEN;
}
menuKey = -1;
animationFrame = 0;
animationPosition = 0;
beepedAlready = false;
}
}
}
+7 -5
View File
@@ -3,6 +3,7 @@
#include "draw/draw.h"
#include "display/display.h"
#include "defs/defs.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
#include "animations/animations.h"
@@ -13,8 +14,10 @@ void menu_refuseScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteDat
uint64_t currentTime = esp_timer_get_time();
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 8:
case 4:
case K1_PRESSED:
case K2_PRESSED:
case K3_PRESSED:
case K4_PRESSED:
currentAnimationFrame = 0;
screenKey = FOOD_SCREEN;
soundPlayed = false;
@@ -34,8 +37,7 @@ void menu_refuseScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteDat
}
if (!soundPlayed) {
tone(SPK_PIN, 3000, 100);
tone(SPK_PIN, 1000, 100);
sound_playMelody(SOUND_REFUSE, SOUND_NOTE_COUNT(SOUND_REFUSE));
soundPlayed = true;
}
@@ -47,4 +49,4 @@ void menu_refuseScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteDat
}
tft_drawBuffer();
}
}
+69
View File
@@ -0,0 +1,69 @@
#include <Arduino.h>
#include "buttons/buttons.h"
#include "defs/defs.h"
#include "display/display.h"
#include "draw/draw.h"
#include "menu.h"
#include "storage/storage.h"
void menu_resetDataScreen(TFT_eSprite &bg) {
static uint8_t selectedOption = 0;
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
selectedOption = (selectedOption - 1) % 2;
break;
case K2_PRESSED:
selectedOption = (selectedOption + 1) % 2;
break;
case K4_PRESSED:
if (selectedOption == 1) {
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("RESETTING", 3, 104);
tft_drawBuffer();
if (storage_deleteState()) {
ESP.restart();
}
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("FAILED", 4, 95);
tft_drawBuffer();
return;
}
selectedOption = 0;
screenKey = SETTINGS_SCREEN;
return;
case K3_PRESSED:
selectedOption = 0;
screenKey = SETTINGS_SCREEN;
return;
default:
break;
}
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("RESET DATA?", 3, 35);
const char* labels[] = { "NO", "YES" };
const int startX = 72;
const int startY = 95;
const int spacingY = 42;
for (uint8_t i = 0; i < 2; i++) {
bool selected = (i == selectedOption);
int y = startY + (i * spacingY);
tft_drawText(labels[i], 4, startX, y, selected ? TFT_BLACK : TFT_WHITE, selected ? TFT_WHITE : TFT_TRANSPARENT);
}
tft_drawBuffer();
}
+112
View File
@@ -0,0 +1,112 @@
#include "buttons/buttons.h"
#include "defs/chara_data.h"
#include "defs/defs.h"
#include "display/display.h"
#include "draw/draw.h"
#include "menu.h"
#include "vpet/vpet/vpet.h"
enum SettingsItemType {
SETTINGS_SUBMENU,
SETTINGS_ACTION
};
struct SettingsMenuItem {
const char* label;
SettingsItemType type;
uint8_t targetScreen;
void (*actionFunction)();
bool* stateValue;
};
void switchSoundState() {
if (soundEnabled) {
pinMode(SPK_PIN, INPUT);
} else {
pinMode(SPK_PIN, OUTPUT);
}
soundEnabled = !soundEnabled;
printf("[SETTINGS] soundEnabled=%i\n", soundEnabled);
}
void switchScreenState() {
alwaysOnEnabled = !alwaysOnEnabled;
printf("[SETTINGS] alwaysOnEnabled=%i\n", alwaysOnEnabled);
}
void menu_settingsScreen(TFT_eSprite &bg, TFT_eSprite &mainChara, struct SpriteData *spriteData)
{
static int8_t arrowPosition = 0;
static SettingsMenuItem menuItems[] = {
{ "BG", SETTINGS_SUBMENU, BACKGROUND_CHANGE_SCREEN, nullptr, nullptr },
{ "SOUND", SETTINGS_ACTION, 0, switchSoundState, &soundEnabled },
{ "AOD", SETTINGS_ACTION, 0, switchScreenState, &alwaysOnEnabled },
{ "RESET", SETTINGS_SUBMENU, RESET_DATA_SCREEN, nullptr, nullptr }
};
const uint8_t numItems = sizeof(menuItems) / sizeof(menuItems[0]);
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case K1_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition--;
if (arrowPosition < 0) {
arrowPosition = numItems - 1;
}
break;
case K2_PRESSED:
printf("[FOOD] arrowPosition=%i\n", arrowPosition);
arrowPosition++;
if (arrowPosition >= numItems) {
arrowPosition = 0;
}
break;
case K3_PRESSED:
screenKey = MENU_SCREEN;
return;
case K4_PRESSED:
lastUpdateTime = 0;
if (menuItems[arrowPosition].type == SETTINGS_ACTION) {
if (menuItems[arrowPosition].actionFunction != nullptr) {
menuItems[arrowPosition].actionFunction();
}
} else if (menuItems[arrowPosition].type == SETTINGS_SUBMENU) {
screenKey = menuItems[arrowPosition].targetScreen;
return;
}
break;
default:
break;
}
draw_drawBackground(bg, 90, 90, 3);
const int startX = 20;
const int startY = 10;
const int spacingY = 40;
for (uint8_t i = 0; i < numItems; i++) {
bool selected = (i == arrowPosition);
int y = startY + (i * spacingY);
tft_drawText(menuItems[i].label, 4, startX, y, selected ? TFT_BLACK : TFT_WHITE, selected ? TFT_WHITE : TFT_TRANSPARENT);
if (menuItems[i].stateValue != nullptr) {
const char* stateText = (*menuItems[i].stateValue) ? "ON" : "OFF";
tft_drawText(stateText, 4, 150, y, selected ? TFT_BLACK : TFT_WHITE, selected ? TFT_WHITE : TFT_TRANSPARENT);
}
}
tft_drawBuffer();
}
+6 -4
View File
@@ -5,6 +5,7 @@
#include "buttons/buttons.h"
#include "animations/animations.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* charaSprites, struct SpriteData* uiSprites) {
if (!charaData[currentCharacter].asleep && !charaData[currentCharacter].sleepy) {
@@ -18,10 +19,12 @@ void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
uint64_t currentTime = esp_timer_get_time();
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 8:
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
break;
case 4:
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
@@ -45,8 +48,7 @@ void menu_sleepyScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
}
if (currentTime - lastBeepTime > ANIMATION_THRESHOLD_TIME_US * 2 && beepCounter < 10) {
tone(SPK_PIN, 2500, 100);
tone(SPK_PIN, 5000, 100);
sound_playMelody(SOUND_CARE_ALERT, SOUND_NOTE_COUNT(SOUND_CARE_ALERT));
lastBeepTime = currentTime;
+5 -4
View File
@@ -23,11 +23,12 @@ void menu_sleepingScreen(
uint8_t buttonsPressed = buttons_getPressedButtons();
switch (buttonsPressed) {
case 8:
case K1_PRESSED:
case K2_PRESSED:
screenKey = MENU_SCREEN;
break;
case 4:
case K4_PRESSED:
screenKey = CLOCK_SCREEN;
break;
@@ -42,10 +43,10 @@ void menu_sleepingScreen(
animate_performSleepyAnimation(sprite, mainCharaData);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 72, 72, bigUiElements, BED_SPRITE, 6);
draw_drawSprite(sprite, 72, 72, bigUiElements, BED_SPRITE);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
draw_drawSprite(sprite, 172, 72, smallUIElements, ZZZ_ICON, 6);
draw_drawSprite(sprite, 172, 72, smallUIElements, ZZZ_ICON);
tft_clearBuffer(sprite, TFT_TRANSPARENT);
menu_uiOverlay(sprite, bigUiElements);
+5 -4
View File
@@ -6,12 +6,14 @@
#include "display/display.h"
#include "draw/draw.h"
#include <math.h>
void menu_statusScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData* spriteData) {
tft_clearBuffer(sprite, TFT_TRANSPARENT);
uint8_t pressedButtons = buttons_getPressedButtons();
switch (pressedButtons) {
case 2:
case K3_PRESSED:
screenKey = MENU_SCREEN;
break;
@@ -23,7 +25,7 @@ void menu_statusScreen(TFT_eSprite &bg, TFT_eSprite &sprite, struct SpriteData*
menu_statusScreen_drawStat(sprite, spriteData, 10, 10, "Hunger", charaData[currentCharacter].hunger);
menu_statusScreen_drawStat(sprite, spriteData, 10, 80, "Strength", charaData[currentCharacter].strength);
menu_statusScreen_drawStat(sprite, spriteData, 10, 150, "Effort", charaData[currentCharacter].effort);
menu_statusScreen_drawStat(sprite, spriteData, 10, 150, "Effort", floor(charaData[currentCharacter].effort / 4));
tft_drawBuffer();
}
@@ -39,11 +41,10 @@ void menu_statusScreen_drawStat(TFT_eSprite &sprite, struct SpriteData* spriteDa
draw_drawSprite(
sprite,
15 + (i * 32),
15 + (i * 48),
y + 30,
spriteData,
icon,
4,
false
);
}
+9 -3
View File
@@ -4,13 +4,18 @@
#include "defs/defs.h"
#include "buttons/buttons.h"
void menu_drawTitle(TFT_eSprite &bg) {
void menu_drawTitle(TFT_eSprite &bg, TFT_eSprite &composite) {
uint8_t pressedButtons = buttons_getPressedButtons();
if (pressedButtons == 8 || pressedButtons == 4) {
if (pressedButtons != 0) {
screenKey = CLOCK_EDIT_SCREEN;
return;
}
uint64_t currentTime = esp_timer_get_time();
if (currentTime - lastUpdateTime < 200000) {
return;
}
draw_drawBackground(bg, 90, 90, 3);
tft_drawCenteredText("NacaPet", 4, 40);
@@ -18,4 +23,5 @@ void menu_drawTitle(TFT_eSprite &bg) {
tft_drawCenteredText(VERSION, 2, 80);
tft_drawBuffer();
}
lastUpdateTime = currentTime;
}
+6 -6
View File
@@ -1,6 +1,7 @@
#include "vpet/training/training.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
#include "buttons/buttons.h"
#include "display/display.h"
@@ -14,17 +15,16 @@ void training_screenTraining1(
vTaskSuspend(secondLoop);
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, mainCharaData, 11, 6);
tone(SPK_PIN, 4100, 100);
tone(SPK_PIN, 3500, 100);
draw_drawSpriteCentered(sprite, mainCharaData, 11);
sound_playMelody(SOUND_TRAINING_START, SOUND_NOTE_COUNT(SOUND_TRAINING_START));
tft_drawBuffer();
delay(500);
draw_drawBackground(bg, 90, 90, 3);
draw_drawSpriteCentered(sprite, mainCharaData, 0, 6);
draw_drawSpriteCentered(sprite, mainCharaData, 0);
tft_drawCenteredText("PUSH!!", 4, 190);
tft_drawBuffer();
@@ -76,4 +76,4 @@ void training_screenTraining1(
}
training_displayTrainingResult(bg, sprite, mainCharaData, attackSprites, attackResult);
}
}
+5
View File
@@ -7,5 +7,10 @@ void training_screenTraining1(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
);
void training_screenTraining2(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
);
#endif
+108
View File
@@ -0,0 +1,108 @@
#include "menu.h"
#include "vpet/training/training.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "draw/draw.h"
#include "display/display.h"
#include "buttons/buttons.h"
void training_screenTraining2(
TFT_eSprite &bg, TFT_eSprite &sprite,
struct SpriteData* mainCharaData, struct SpriteData* attackSprites
) {
enum TrainingState {
TRAINING_INIT,
TRAINING_WAIT_INPUT,
TRAINING_SHOW_BOTH,
TRAINING_SHOW_HIT
};
static TrainingState state = TRAINING_INIT;
static uint64_t inactivityTimer = 0;
static uint64_t stageStartTime = 0;
static uint8_t randomPosition = 0;
static uint8_t projectilePosition = 0;
uint64_t currentTime = esp_timer_get_time();
if (state == TRAINING_INIT) {
draw_drawBackground(bg, 90, 90 ,3);
// Player
draw_drawSprite(sprite, 174, 72, mainCharaData, 0, false);
draw_drawBackgroundSection(bg, 222, 72, 18, 96);
// Opponent
draw_drawSprite(sprite, -30, 72, mainCharaData, 0, true);
draw_drawBackgroundSection(bg, 0, 72, 18, 96);
tft_drawBuffer();
inactivityTimer = currentTime;
state = TRAINING_WAIT_INPUT;
return;
}
if (currentTime - lastUpdateTime > 500000) {
sound_playMelody(SOUND_BUTTON_BEEP, SOUND_NOTE_COUNT(SOUND_BUTTON_BEEP));
lastUpdateTime = currentTime;
}
if (state == TRAINING_WAIT_INPUT) {
if (currentTime - inactivityTimer > 3000000) {
screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU;
state = TRAINING_INIT;
return;
}
uint8_t pressedButtons = buttons_getPressedButtons();
if (pressedButtons == K3_PRESSED || pressedButtons == K4_PRESSED) {
randomPosition = rand() % 2;
projectilePosition = pressedButtons >> 1; // pressedButtons >> 4 == 1 => K1; != 1 => K2
printf("[TRAIN] projectilePosition=%i\n", projectilePosition);
inactivityTimer = currentTime;
// Player attack
draw_drawSprite(sprite, 126, 72 + 48 * projectilePosition, attackSprites, POOP_ICON);
// Opponent attack
draw_drawSprite(sprite, 66, 72 + 48 * randomPosition, attackSprites, FOOD_ICON);
tft_drawBuffer();
stageStartTime = currentTime;
state = TRAINING_SHOW_BOTH;
} else if (pressedButtons == K3_PRESSED) {
screenKey = MAIN_SCREEN;
submenuKey = STATUS_SCREEN_MENU;
state = TRAINING_INIT;
return;
}
} else if (state == TRAINING_SHOW_BOTH && currentTime - stageStartTime > 500000) {
if (projectilePosition != randomPosition) {
draw_drawBackgroundSection(bg, 126, 72 + 48 * projectilePosition, 48, 48);
draw_drawSprite(sprite, 66, 72 + 48 * projectilePosition, attackSprites, POOP_ICON);
tft_drawBuffer();
stageStartTime = currentTime;
state = TRAINING_SHOW_HIT;
} else {
draw_drawBackgroundSection(bg, 66, 72, 108, 96);
tft_drawBuffer();
printf("[TRAIN] Train failed\n");
screenKey = ANGRY_SCREEN;
state = TRAINING_INIT;
}
} else if (state == TRAINING_SHOW_HIT && currentTime - stageStartTime > 500000) {
draw_drawBackgroundSection(bg, 66, 72, 108, 96);
tft_drawBuffer();
charaData[currentCharacter].strength++;
screenKey = HAPPY_SCREEN;
state = TRAINING_INIT;
}
}
+17 -16
View File
@@ -1,22 +1,23 @@
#include "menu.h"
#include "draw/draw.h"
#include "display/display.h"
#include "defs/chara_data.h"
#include "defs/screen_defs.h"
#include "display/display.h"
#include "draw/draw.h"
#include "menu.h"
void menu_uiOverlay(TFT_eSprite &charSprite, struct SpriteData* uiElements) {
char hourBuffer[6];
void menu_uiOverlay(TFT_eSprite &charSprite, struct SpriteData *uiElements) {
char hourBuffer[6];
snprintf(hourBuffer, 6, "%02d:%02d", timeInfo.tm_hour, timeInfo.tm_min);
snprintf(hourBuffer, 6, "%02d:%02d", timeInfo.tm_hour, timeInfo.tm_min);
composite1.fillRect(0, 0, 240, 24, TFT_BLACK);
tft_drawText(hourBuffer, 2, 4, 4, TFT_WHITE);
snprintf(hourBuffer, 6, "%05d", stepCounter);
tft_drawText(hourBuffer, 2, 176, 4, TFT_WHITE);
if (charaData[currentCharacter].careMistakeCallLight) {
tft_clearBuffer(charSprite, TFT_TRANSPARENT);
draw_drawSprite(charSprite, 192, 192, uiElements, CARE_MISTAKE_CALL_LIGHT, 2);
}
composite.fillRect(0, 0, 240, 24, TFT_BLACK);
tft_drawText(hourBuffer, 2, 4, 4, TFT_WHITE);
snprintf(hourBuffer, 6, "%05d", stepCounter);
tft_drawText(hourBuffer, 2, 176, 4, TFT_WHITE);
if (charaData[currentCharacter].careMistakeCallLight) {
tft_clearBuffer(charSprite, TFT_TRANSPARENT);
// draw_drawSprite(charSprite, 192, 192, uiElements,
// CARE_MISTAKE_CALL_LIGHT, 2);
}
}
+98
View File
@@ -0,0 +1,98 @@
#include "sound.h"
#include "defs/defs.h"
static const Note* currentMelody = nullptr;
static uint16_t melodyLength = 0;
static uint16_t currentNote = 0;
static bool playing = false;
static unsigned long nextNoteTime = 0;
void sound_init() {
pinMode(SPK_PIN, OUTPUT);
}
void sound_playTone(uint16_t frequency, uint16_t duration) {
if (!soundEnabled) { return; }
currentMelody = nullptr;
melodyLength = 0;
currentNote = 0;
if (frequency == 0) {
noTone(SPK_PIN);
} else {
tone(SPK_PIN, frequency, duration);
}
playing = true;
nextNoteTime = millis() + duration;
}
void sound_playMelody(const Note* melody, uint16_t noteCount) {
if (!soundEnabled) { return; }
if (melody == nullptr || noteCount == 0) {
return;
}
currentMelody = melody;
melodyLength = noteCount;
currentNote = 0;
playing = true;
nextNoteTime = 0;
}
void sound_stop() {
noTone(SPK_PIN);
playing = false;
currentMelody = nullptr;
melodyLength = 0;
currentNote = 0;
}
bool sound_isPlaying() {
return playing;
}
void sound_update() {
if (!soundEnabled) {
sound_stop();
return;
}
if (!playing) {
return;
}
if (currentMelody == nullptr) {
if (millis() >= nextNoteTime) {
sound_stop();
}
return;
}
if (millis() < nextNoteTime) {
return;
}
if (currentNote >= melodyLength) {
sound_stop();
return;
}
const Note& note = currentMelody[currentNote];
if (note.frequency == 0) {
noTone(SPK_PIN);
} else {
tone(SPK_PIN, note.frequency, note.duration);
}
nextNoteTime = millis() + note.duration;
currentNote++;
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <Arduino.h>
struct Note {
uint16_t frequency;
uint16_t duration;
};
void sound_init();
void sound_update();
void sound_playTone(uint16_t frequency, uint16_t duration);
void sound_playMelody(const Note* melody, uint16_t noteCount);
void sound_stop();
bool sound_isPlaying();
+124
View File
@@ -0,0 +1,124 @@
#include "storage.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "utils/utils.h"
const char* TAG_SR = "[STORAGE]";
void storage_readFile(const char* path, struct SpriteData* spriteData) {
File file = SPIFFS.open(path, "r");
if (!file) {
printf("%s Failed to open file for reading\n", TAG_SR);
return;
}
uint8_t width, height, spriteNumber;
file.read(&width, 1);
file.read(&height, 1);
file.read(&spriteNumber, 1);
if (spriteData->spriteData != NULL) {
memory_free(spriteData);
}
const uint8_t scaledW = width * SPRITE_SCALE;
const uint8_t scaledH = height * SPRITE_SCALE;
uint16_t** scaled =
(uint16_t**) ps_malloc(spriteNumber * sizeof(uint16_t*));
if (!scaled) {
printf("%s PSRAM alloc failed for pointer table\n", TAG_SR);
file.close();
return;
}
for (uint8_t i = 0; i < spriteNumber; i++) {
scaled[i] =
(uint16_t*) ps_malloc(scaledW * scaledH * sizeof(uint16_t));
if (!scaled[i]) {
printf("%s PSRAM alloc failed for sprite %d\n", TAG_SR, i);
for (uint8_t j = 0; j < i; j++) {
free(scaled[j]);
}
free(scaled);
file.close();
return;
}
}
uint16_t* spriteBuf =
(uint16_t*) malloc(width * height * sizeof(uint16_t));
if (!spriteBuf) {
printf("%s scratch alloc failed\n", TAG_SR);
for (uint8_t i = 0; i < spriteNumber; i++) {
free(scaled[i]);
}
free(scaled);
file.close();
return;
}
printf(
"%s Read header: width=%d, height=%d, numSprites=%d -> scaled to %dx%d\n",
TAG_SR,
width,
height,
spriteNumber,
scaledW,
scaledH
);
for (int sprN = 0; sprN < spriteNumber; sprN++) {
// Read original sprite into temporary buffer
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
uint8_t hi, lo;
file.read(&hi, 1);
file.read(&lo, 1);
spriteBuf[y * width + x] =
(lo << 8) | hi;
}
}
// Upscale sprite
utils_upscaleSprite(
spriteBuf,
width,
height,
scaled[sprN]
);
}
free(spriteBuf);
file.close();
spriteData->spriteWidth = scaledW;
spriteData->spriteHeight = scaledH;
spriteData->spriteNumber = spriteNumber;
spriteData->spriteData = scaled;
printf(
"%s Loaded & upscaled %s (%d sprites, each %dx%d px)\n",
TAG_SR,
path,
spriteNumber,
scaledW,
scaledH
);
}
+188 -68
View File
@@ -1,6 +1,10 @@
#include "storage.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sprite_data.h"
#include "defs/screen_defs.h"
#include "TFT_eSPI.h"
const char* TAG_S = "[STORAGE]";
@@ -13,106 +17,222 @@ void storage_init() {
}
void storage_readFile(const char* path, struct SpriteData* spriteData) {
void storage_initBackground(const int id, TFT_eSprite& bg) {
char path[15];
snprintf(path, 15, "/bg/%i.bin", id);
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, height;
file.read(&width, 1);
file.read(&height, 1);
uint8_t width, height, spriteNumber;
bytesRead += file.read(&width, 1);
bytesRead += file.read(&height, 1);
bytesRead += file.read(&spriteNumber, 1);
size_t pixelCount = width * height;
if (spriteData->spriteData != NULL) {
memory_free(spriteData);
}
spriteData->spriteWidth = width;
spriteData->spriteHeight = height;
spriteData->spriteNumber = spriteNumber;
spriteData->spriteData = memory_allocate(spriteData->spriteNumber, spriteData->spriteWidth, spriteData->spriteHeight);
printf("%s width=%d height=%d pixels=%zu\n", TAG_S, width, height, pixelCount);
printf(
"%s Read header: width=%d, height=%d, numSprites=%d\n",
TAG_S, spriteData->spriteWidth, spriteData->spriteHeight, spriteData->spriteNumber
);
bg.createSprite(width, height);
fileSize = (fileSize - 3) / sizeof(uint16_t);
uint16_t* bgBuf = (uint16_t*) bg.getPointer();
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;
}
}
for (size_t i = 0; i < pixelCount; i++) {
uint8_t hi, lo;
file.read(&lo, 1);
file.read(&hi, 1);
bgBuf[i] = (hi << 8) | lo;
}
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");
void storage_saveState() {
File file;
file = SPIFFS.open("/save.bin", "w");
if (!file) {
printf("%s Failed to open file for reading\n", TAG_S);
printf("%s Cannot save: cannot open save file.\n", TAG_S);
return;
}
size_t bytesRead = 0;
file.write(
(uint8_t*) charaData,
sizeof(struct CharacterData) * CHARA_COUNT_IN_DEVICE
);
size_t fileSize = file.size();
printf("%s Saved current character data.\n", TAG_S);
uint8_t width;
uint8_t height;
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
printf("%s Saving line data %i\n", TAG_S, i);
bytesRead += file.read(&width, 1);
bytesRead += file.read(&height, 1);
uint8_t lineUsed = (currentLine[i] != NULL);
file.write(lineUsed);
printf("%s Read header: width=%d, height=%d\n", TAG_S, width, height);
if (lineUsed) {
file.write(currentLine[i]->id);
file.write((uint8_t*) &(currentLine[i]->hatchTime), sizeof(uint16_t));
file.write((uint8_t*) currentLine[i]->name, 16);
file.write(currentLine[i]->charaNumber);
printf("%s Done saving static line %i\n", TAG_S, i);
uint8_t hasCharacters = (currentLine[i]->characters != NULL);
file.write(hasCharacters);
printf("%s hasCharacters=%i, characters=%i, charaNumber=%i\n",
TAG_S, hasCharacters, currentLine[i]->characters, currentLine[i]->charaNumber);
if (hasCharacters) {
file.write(
(uint8_t*) currentLine[i]->characters,
sizeof(LineChara_t) * currentLine[i]->charaNumber
);
}
printf("%s Done saving line data for %i\n", TAG_S, i);
}
}
fileSize = (fileSize - 2) / sizeof(uint16_t);
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
printf("%s Saving care data %i\n", TAG_S, i);
uint8_t careDataUsed = currentLineCareInstr[i] != NULL;
file.write(careDataUsed);
bg.createSprite(width, height);
if (careDataUsed) {
file.write(currentLineCareInstr[i]->lineId);
file.write(currentLineCareInstr[i]->numCareMistakesData);
printf("%s Done saving static care data %i\n", TAG_S, i);
uint8_t hasCareData = (currentLineCareInstr[i]->careMistakeData != NULL);
file.write(hasCareData);
printf("%s hasCharacters=%i, characters=%i, charaNumber=%i\n",
TAG_S, hasCareData, currentLineCareInstr[i]->careMistakeData, currentLineCareInstr[i]->numCareMistakesData);
if (hasCareData) {
file.write(
(uint8_t*) currentLineCareInstr[i]->careMistakeData,
sizeof(CareMistakes_t) * currentLineCareInstr[i]->numCareMistakesData
);
}
printf("%s Done saving care data for %i\n", TAG_S, i);
}
for(int i = 0; i < width * height; i++) {
uint8_t highByte;
uint8_t lowByte;
}
bytesRead += file.read(&highByte, 1);
bytesRead += file.read(&lowByte, 1);
file.write(currentCharacter);
uint16_t pixel = (highByte << 8) | lowByte;
file.close();
if (i < fileSize) {
bg.drawPixel(i % width, i / width, pixel);
} else {
printf("%s Buffer overflow, skipping pixel\n", TAG_S);
break;
printf("%s Save completed!\n", TAG_S);
}
void storage_loadState() {
File file;
if (!SPIFFS.exists("/save.bin")) {
printf("%s Cannot load: File does not exist.\n", TAG_S);
return;
}
file = SPIFFS.open("/save.bin", "r");
if (!file) {
printf("%s Cannot save: cannot open save file.\n", TAG_S);
return;
}
file.read((uint8_t*) charaData, sizeof(struct CharacterData) * CHARA_COUNT_IN_DEVICE);
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
uint8_t currentLineUsed = file.read();
if (currentLineUsed) {
currentLine[i] = (Line_t*) calloc(1, sizeof(Line_t));
currentLine[i]->id = file.read();
file.read((uint8_t*) &(currentLine[i]->hatchTime), sizeof(uint16_t));
file.read((uint8_t*) currentLine[i]->name, 16);
currentLine[i]->charaNumber = file.read();
uint8_t hasCharacters = file.read();
if (hasCharacters) {
if (currentLine[i]->characters != NULL) {
free(currentLine[i]->characters);
}
currentLine[i]->characters = (LineChara_t*) malloc(sizeof(LineChara_t) * currentLine[i]->charaNumber);
file.read(
(uint8_t*) currentLine[i]->characters,
sizeof(LineChara_t) * currentLine[i]->charaNumber
);
} else {
currentLine[i]->characters = NULL;
}
}
}
for (int i = 0; i < CHARA_COUNT_IN_DEVICE; i++) {
uint8_t currentLineUsed = file.read();
if (currentLineUsed) {
currentLineCareInstr[i] = (LineCare_t*) calloc(1, sizeof(LineCare_t));
currentLineCareInstr[i]->lineId = file.read();
currentLineCareInstr[i]->numCareMistakesData = file.read();
uint8_t hasCareData = file.read();
if (hasCareData) {
if (currentLineCareInstr[i]->careMistakeData != NULL) {
free(currentLineCareInstr[i]->careMistakeData);
}
currentLineCareInstr[i]->careMistakeData = (CareMistakes_t*) malloc(sizeof(CareMistakes_t) * currentLineCareInstr[i]->numCareMistakesData);
file.read(
(uint8_t*) currentLineCareInstr[i]->careMistakeData,
sizeof(CareMistakes_t) * currentLineCareInstr[i]->numCareMistakesData
);
} else {
currentLineCareInstr[i]->careMistakeData = NULL;
}
}
}
printf("%s Read %zu bytes from file %s\n", TAG_S, bytesRead, path);
currentCharacter = file.read();
file.close();
}
char spriteFileName[30];
snprintf(spriteFileName, 30, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(spriteFileName, &mainCharacterSprites);
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;
}
+6 -2
View File
@@ -9,6 +9,10 @@
void storage_init();
void storage_readFile(const char* path, struct SpriteData* spriteData);
void storage_initBackground(const char* path, TFT_eSprite& bg);
void storage_initBackground(const int id, TFT_eSprite &bg);
#endif
void storage_saveState();
void storage_loadState();
bool storage_deleteState();
#endif
+41
View File
@@ -0,0 +1,41 @@
#include "utils.h"
#include "defs/defs.h"
/**
* Upscale a sprite using nearest-neighbor scaling.
*
* @param src Pointer to source sprite pixels
* @param srcWidth Original sprite width
* @param srcHeight Original sprite height
* @param dst Destination buffer for upscaled sprite
*/
void utils_upscaleSprite(
const uint16_t* src,
uint8_t srcWidth,
uint8_t srcHeight,
uint16_t* dst
) {
const uint8_t scaledW = srcWidth * SPRITE_SCALE;
for (int srcY = 0; srcY < srcHeight; srcY++) {
for (int dy = 0; dy < SPRITE_SCALE; dy++) {
uint16_t* dstRow =
dst + ((srcY * SPRITE_SCALE + dy) * scaledW);
for (int srcX = 0; srcX < srcWidth; srcX++) {
uint16_t color = src[srcY * srcWidth + srcX];
uint16_t* dstPixel =
dstRow + (srcX * SPRITE_SCALE);
for (int dx = 0; dx < SPRITE_SCALE; dx++) {
dstPixel[dx] = color;
}
}
}
}
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef UTILS_H
#define UTILS_H
#include <Arduino.h>
void utils_upscaleSprite(
const uint16_t* src,
uint8_t srcWidth,
uint8_t srcHeight,
uint16_t* dst
);
#endif
+2
View File
@@ -86,4 +86,6 @@ void change_onChangeComplete() {
snprintf(spriteFileName, 30, "/chara/%02x.bin", charaData[currentCharacter].idChara);
storage_readFile(spriteFileName, &mainCharacterSprites);
storage_saveState();
}
+56 -24
View File
@@ -1,22 +1,24 @@
#include "lines.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "utils/utils.h"
#include "SPIFFS.h"
#include <FS.h>
#include <SPIFFS.h>
const char lineHeader[5] = "NPET";
const char lineHeader[5] = "NPET";
const uint8_t headerSize = 4;
void lines_getAvailableLines() {
if (eggSelection != NULL) {
return;
}
File root = SPIFFS.open("/lines");
File lineFile = root.openNextFile();
fs::File root = SPIFFS.open("/lines");
fs::File lineFile = root.openNextFile();
uint8_t allocCount = 0;
char header[5];
char header[5];
while (lineFile) {
printf("[LINES] Opening file %s\n", lineFile.name());
@@ -39,39 +41,69 @@ void lines_getAvailableLines() {
lineFile = root.openNextFile("r");
while (lineFile) {
uint16_t bytesRead = lineFile.readBytes(header, headerSize);
uint16_t bytesRead = 0;
bytesRead += lineFile.readBytes(header, headerSize);
bytesRead += lineFile.read(&availableLines[allocCount].id, 1);
bytesRead += lineFile.readBytes(availableLines[allocCount].name, 16);
bytesRead += lineFile.read(&availableLines[allocCount].eggSprite.spriteWidth, 1);
bytesRead += lineFile.read(&availableLines[allocCount].eggSprite.spriteHeight, 1);
bytesRead += lineFile.read(&availableLines[allocCount].eggSprite.spriteNumber, 1); // Se coloca el cursor al principio de los datos de sprite
uint8_t originalWidth;
uint8_t originalHeight;
uint8_t spriteCount;
availableLines[allocCount].eggSprite.spriteNumber = 1; // Inutil, pero es que necesito hacer la lectura
bytesRead += lineFile.read(&originalWidth, 1);
bytesRead += lineFile.read(&originalHeight, 1);
bytesRead += lineFile.read(&spriteCount, 1);
availableLines[allocCount].eggSprite.spriteData = memory_allocate(
availableLines[allocCount].eggSprite.spriteNumber,
availableLines[allocCount].eggSprite.spriteWidth,
availableLines[allocCount].eggSprite.spriteHeight
);
const uint8_t scaledWidth = originalWidth * SPRITE_SCALE;
const uint8_t scaledHeight = originalHeight * SPRITE_SCALE;
availableLines[allocCount].eggSprite.spriteWidth = scaledWidth;
availableLines[allocCount].eggSprite.spriteHeight = scaledHeight;
availableLines[allocCount].eggSprite.spriteNumber = 1;
availableLines[allocCount].eggSprite.spriteData = memory_allocate(1, scaledWidth, scaledHeight);
uint16_t* spriteBuffer =
(uint16_t*) malloc(
originalWidth *
originalHeight *
sizeof(uint16_t)
);
if (!spriteBuffer) {
printf("[LINES] Failed to allocate sprite buffer\n");
lineFile.close();
lineFile = root.openNextFile();
continue;
}
uint8_t highByte;
uint8_t lowByte;
for (int i = 0; i < availableLines[allocCount].eggSprite.spriteWidth * availableLines[allocCount].eggSprite.spriteHeight; i++) {
bytesRead += lineFile.read(&highByte, 1);
for (int i = 0; i < originalWidth * originalHeight; i++) {
bytesRead += lineFile.read(&lowByte, 1);
bytesRead += lineFile.read(&highByte, 1);
uint16_t pixel = (highByte << 8) | lowByte;
availableLines[allocCount].eggSprite.spriteData[0][i] = pixel;
spriteBuffer[i] = (highByte << 8) | lowByte;
}
utils_upscaleSprite(
spriteBuffer,
originalWidth,
originalHeight,
availableLines[allocCount].eggSprite.spriteData[0]
);
free(spriteBuffer);
strcpy(availableLines[allocCount].fileName, lineFile.name());
lineFile.close();
allocCount++;
lineFile = root.openNextFile();
}
@@ -79,4 +111,4 @@ void lines_getAvailableLines() {
eggNumber = allocCount;
eggSelection = availableLines;
}
}
+4 -3
View File
@@ -2,19 +2,20 @@
#include "defs/file_chara.h"
#include "defs/defs.h"
#include "SPIFFS.h"
#include <FS.h>
#include <SPIFFS.h>
void lines_getLineCareMistakes(const char* fileName) {
char careMistakesPath[strlen(fileName) + 8];
snprintf(careMistakesPath, strlen(fileName) + 8, "/care/%s", fileName);
File careMistakesFile = SPIFFS.open(careMistakesPath);
fs::File careMistakesFile = SPIFFS.open(careMistakesPath);
uint8_t bytesRead = 0;
LineCare_t* careMistakesData = (LineCare_t*) malloc(sizeof(LineCare_t));
careMistakesFile.seek(4, SeekCur);
careMistakesFile.seek(4, fs::SeekCur);
bytesRead += careMistakesFile.read(&careMistakesData->lineId, 1);
bytesRead += careMistakesFile.read(&careMistakesData->numCareMistakesData, 1);
+59 -18
View File
@@ -1,14 +1,16 @@
#include "lines.h"
#include "memory/memory.h"
#include "defs/defs.h"
#include "utils/utils.h"
#include <FS.h>
#include <SPIFFS.h>
void lines_getSingleLine(const char* fileName) {
char fullPath[8 + strlen(fileName)];
snprintf(fullPath, 20, "/lines/%s", fileName);
File lineFile = SPIFFS.open(fullPath);
fs::File lineFile = SPIFFS.open(fullPath);
struct Line_t* selectedLine = (struct Line_t*) malloc(sizeof(struct Line_t));
if (selectedLine == NULL) {
@@ -17,7 +19,7 @@ void lines_getSingleLine(const char* fileName) {
uint8_t buffer[4];
lineFile.seek(4, SeekCur);
lineFile.seek(4, fs::SeekCur);
uint8_t bytesRead = lineFile.read(&selectedLine->id, 1);
bytesRead += lineFile.readBytes(selectedLine->name, 16);
@@ -39,37 +41,76 @@ void lines_getSingleLine(const char* fileName) {
currentLine[currentCharacter] = selectedLine;
currentEgg = selectedEgg;
}
void lines_getSingleEggSprites(fs::File &lineFile, Egg_t* selectedEgg) {
void lines_getSingleEggSprites(File &lineFile, Egg_t* selectedEgg) {
// Importante tener el nombre de archivo del huevo en todo momento
strcpy(selectedEgg->fileName, lineFile.name());
// Ahora se lee los datos
lineFile.read(&(selectedEgg->eggSprite.spriteWidth), 1);
lineFile.read(&(selectedEgg->eggSprite.spriteHeight), 1);
// Leer dimensiones originales
uint8_t originalWidth;
uint8_t originalHeight;
lineFile.read(&originalWidth, 1);
lineFile.read(&originalHeight, 1);
lineFile.read(&(selectedEgg->eggSprite.spriteNumber), 1);
const uint8_t scaledWidth = originalWidth * SPRITE_SCALE;
const uint8_t scaledHeight = originalHeight * SPRITE_SCALE;
// Guardar dimensiones escaladas
selectedEgg->eggSprite.spriteWidth = scaledWidth;
selectedEgg->eggSprite.spriteHeight = scaledHeight;
// Reservar memoria para sprites escalados
selectedEgg->eggSprite.spriteData = memory_allocate(
selectedEgg->eggSprite.spriteNumber,
selectedEgg->eggSprite.spriteWidth,
selectedEgg->eggSprite.spriteHeight
selectedEgg->eggSprite.spriteNumber,
scaledWidth,
scaledHeight
);
uint16_t size = selectedEgg->eggSprite.spriteWidth * selectedEgg->eggSprite.spriteHeight;
const uint16_t originalSize =
originalWidth * originalHeight;
// Buffer temporal en SRAM
uint16_t* spriteBuffer =
(uint16_t*) malloc(
originalSize * sizeof(uint16_t)
);
if (!spriteBuffer) {
printf("[LINES] Failed to allocate sprite buffer\n");
return;
}
uint8_t highByte;
uint8_t lowByte;
for (int spr = 0; spr < selectedEgg->eggSprite.spriteNumber; spr++) {
for (int i= 0; i < size; i++) {
lineFile.read(&highByte, 1);
for (
int spr = 0;
spr < selectedEgg->eggSprite.spriteNumber;
spr++
) {
// Leer sprite original
for (int i = 0; i < originalSize; i++) {
lineFile.read(&lowByte, 1);
lineFile.read(&highByte, 1);
uint16_t pixel = (highByte << 8) | lowByte;
selectedEgg->eggSprite.spriteData[spr][i] = pixel;
spriteBuffer[i] =
(highByte << 8) | lowByte;
}
}
// Escalar sprite
utils_upscaleSprite(
spriteBuffer,
originalWidth,
originalHeight,
selectedEgg->eggSprite.spriteData[spr]
);
}
free(spriteBuffer);
}
// Son las 22:35, que estoy haciendo?
+4 -2
View File
@@ -1,12 +1,14 @@
#include "lines.h"
#include "defs/defs.h"
#include "defs/file_chara.h"
#include "defs/chara_data.h"
Egg_t* currentEgg = NULL;
LineCare_t** currentLineCareInstr = NULL;
Line_t** currentLine = NULL;
void lines_initLineStorage() {
currentLineCareInstr = (LineCare_t**) malloc(sizeof(LineCare_t*) * CHARA_COUNT_IN_DEVICE);
currentLine = (Line_t**) malloc(sizeof(Line_t*) * CHARA_COUNT_IN_DEVICE);
charaData = (struct CharacterData*) calloc(CHARA_COUNT_IN_DEVICE, sizeof(struct CharacterData));
currentLineCareInstr = (LineCare_t**) calloc(CHARA_COUNT_IN_DEVICE, sizeof(LineCare_t*));
currentLine = (Line_t**) calloc(CHARA_COUNT_IN_DEVICE, sizeof(Line_t*));
}
+1 -1
View File
@@ -22,7 +22,7 @@ void steps_countSteps() {
float dyn = mag - gravity;
unsigned long now = esp_timer_get_time();
if (dyn > thresh && (now - lastStepTime) > 250000) {
if (dyn > thresh && (now - lastStepTime) > 350000) {
stepCounter++;
lastStepTime = now;
}
+1
View File
@@ -2,6 +2,7 @@
#define TRAINING_H
#include <TFT_eSPI.h>
#include "defs/sprite_data.h"
void training_displayTrainingResult(
TFT_eSprite &bg, TFT_eSprite &sprite,
+12 -21
View File
@@ -2,6 +2,8 @@
#include "draw/draw.h"
#include "defs/defs.h"
#include "defs/chara_data.h"
#include "defs/sounds.h"
#include "defs/sprite_data.h"
#include "display/display.h"
#define NUM_ROUNDS 5
@@ -75,13 +77,17 @@ void training_displayTrainingResult(
break;
}
draw_drawBackground(bg, 90, 90, 3);
for (int i = 0; i < NUM_ROUNDS; i++) {
training_trainingAttackSounds();
for (int j = 78; j >= -48; j -= 3) {
draw_drawBackground(bg, 90, 90, 3);
draw_drawSprite(sprite, 126, 72, mainCharaData, 11, 6);
draw_drawAttacks(sprite, attackSprites, j, 72, pattern[i], charaData[currentCharacter].spriteAttackId, 6);
for (int j = 78; j >= -48; j -= 6) {
draw_drawSprite(sprite, 126, 72, mainCharaData, 11);
draw_drawAttacks(bg, sprite, attackSprites, j, 72, pattern[i], charaData[currentCharacter].spriteAttackId);
draw_drawBackgroundSection(bg, 0, 72, 18, 96);
tft_drawBuffer();
}
@@ -95,20 +101,5 @@ void training_displayTrainingResult(
// nOT FANCY
void training_trainingAttackSounds() {
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 4100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
tone(SPK_PIN, 3700, 25);
tone(SPK_PIN, 3100, 25);
}
sound_playMelody(SOUND_TRAINING_ATTACK, SOUND_NOTE_COUNT(SOUND_TRAINING_ATTACK));
}
+15 -1
View File
@@ -167,7 +167,12 @@ void vpet_evalHungerTimer() {
charaData[currentCharacter].hungerCareMistakeTimer <= 0 &&
charaData[currentCharacter].hunger > 0
) {
#ifndef DEBUG
charaData[currentCharacter].hunger--;
#else
charaData[currentCharacter].hunger -= 60;
#endif
if (charaData[currentCharacter].hunger > 0) {
charaData[currentCharacter].hungerCareMistakeTimer = charaData[currentCharacter].initialStatsReductionTime;
@@ -202,7 +207,12 @@ void vpet_evalStrengthTimer() {
charaData[currentCharacter].strengthCareMistakeTimer <= 0 &&
charaData[currentCharacter].strength > 0
) {
#ifndef DEBUG
charaData[currentCharacter].strength--;
#else
charaData[currentCharacter].strength -= 60;
#endif
if (charaData[currentCharacter].strength > 0) {
charaData[currentCharacter].strengthCareMistakeTimer = charaData[currentCharacter].initialStatsReductionTime;
} else {
@@ -226,7 +236,11 @@ void vpet_evalStrengthTimer() {
void vpet_evalChangeTimer(uint8_t diff_sec) {
if (charaData[currentCharacter].changeTimerLeft > 0) {
#ifndef DEBUG
charaData[currentCharacter].changeTimerLeft -= diff_sec;
#else
charaData[currentCharacter].changeTimerLeft -= 600;
#endif
}
if (charaData[currentCharacter].changeTimerLeft <= 0) {
@@ -245,7 +259,7 @@ void IRAM_ATTR onActionTimerDelta() {
}
void vpet_runVpetTasks() {
if (runVpetTasks) {
if (runVpetTasks && !charaData[currentCharacter].frozen) {
uint64_t currentEvaluationTime = esp_timer_get_time();
uint64_t deltaUs = currentEvaluationTime - vpetLastEvaluationTime;
-11
View File
@@ -1,11 +0,0 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html