#include <MD_MAX72xx.h>
#include <MD_Parola.h>
#include "main.h"
int scrollPosition = 32; // Start COMPLETELY off-screen right
int currentChar = 0;
unsigned long lastScrollTime = 0;
unsigned long lastCharTime = 0;
int textIndex = 0;
bool textChanged = false;
int lastXOffset = 32; // Track last position for clearing
int Left =44;
unsigned long currentMillis;
// 8x8 pixel retro game characters - OPTIMIZED FOR VISIBILITY
uint8_t retro[][8] = {
// Pac-Man (open mouth) - MORE DETAILED
{0x3C, 0x7E, 0xE7, 0xC3, 0xC3, 0xE7, 0x7E, 0x3C},
// Pac-Man (closed mouth)
{0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C},
// Blinky Ghost (red)
{0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x5A, 0x7E},
// Pinky Ghost
{0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C},
// Space Invader 1
{0x18, 0x3C, 0x7E, 0xDB, 0xFF, 0x24, 0x5A, 0x42},
// Space Invader 2
{0x18, 0x3C, 0x7E, 0xDB, 0xBD, 0x24, 0x5A, 0x42},
// Mario - BETTER DETAIL
{0x18, 0x3C, 0x7E, 0xDB, 0x7E, 0x3C, 0x5A, 0x7E},
// Luigi
{0x18, 0x3C, 0x7E, 0xDB, 0x7E, 0x3C, 0x7E, 0x5A},
// Donkey Kong
{0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Barrel
{0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C},
// Tetris L-block
{0x40, 0x40, 0x40, 0x40, 0x7C, 0x7C, 0x7C, 0x7C},
// Tetris Square
{0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C},
// Galaga Ship
{0x18, 0x3C, 0x7E, 0xFF, 0x7E, 0x3C, 0x18, 0x00},
// Galaga Enemy
{0x24, 0x5A, 0xBD, 0xDB, 0xDB, 0xBD, 0x5A, 0x24},
// Frogger
{0x18, 0x3C, 0x5A, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Dig Dug
{0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Q*bert
{0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81},
// Centipede
{0x66, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00},
// Missile Command Base
{0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Asteroids Ship
{0x18, 0x3C, 0x66, 0xFF, 0xFF, 0x66, 0x3C, 0x18},
// Defender Ship
{0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Robotron 2084
{0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3C},
// Burger Time Chef
{0x3C, 0x42, 0x81, 0x99, 0x99, 0x81, 0x42, 0x3C},
// Bubble Bobble Dragon
{0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C},
// Bomberman
{0x3C, 0x42, 0x99, 0xBD, 0xBD, 0x99, 0x42, 0x3C},
// Arkanoid Paddle
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
// Pong Paddle
{0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80},
// Tetris T-block
{0x00, 0x10, 0x38, 0x7C, 0x10, 0x10, 0x10, 0x00},
// Zelda Triforce
{0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x3C, 0x18, 0x00},
// Metroid Samus
{0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Castlevania
{0x00, 0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00, 0x00},
// Contra Soldier
{0x3C, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3C},
// Double Dragon
{0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Street Fighter Hadouken
{0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00},
// Sonic
{0x3C, 0x42, 0x81, 0x99, 0x81, 0x42, 0x3C, 0x00},
// Megaman
{0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18},
// Extra Monsters (red/black only)
// Dracula (Castlevania style)
{0x3C, 0x42, 0xA5, 0x81, 0xA5, 0x99, 0x42, 0x3C},
// Frankenstein Monster
{0x7E, 0xDB, 0xFF, 0xFF, 0xE7, 0xE7, 0xDB, 0x7E},
// Demon Face
{0x3C, 0x7E, 0xDB, 0xFF, 0xFF, 0xDB, 0x7E, 0x3C},
// Skull
{0x3C, 0x7E, 0xDB, 0xFF, 0xFF, 0xDB, 0x7E, 0x3C},
// Bat
{0x18, 0x3C, 0x7E, 0xFF, 0x7E, 0x3C, 0x18, 0x00},
// Spider
{0x24, 0x5A, 0xBD, 0xFF, 0xFF, 0xBD, 0x5A, 0x24},
// Dragon Head
{0x3C, 0x7E, 0xFF, 0xE7, 0xE7, 0xFF, 0x7E, 0x3C},
// Ogre
{0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xDB, 0xFF, 0x7E},
// Zombie
{0x3C, 0x7E, 0xDB, 0xFF, 0xFF, 0xDB, 0x7E, 0x3C},
// Alien (Space Invader boss style)
{0x18, 0x3C, 0x7E, 0xDB, 0xFF, 0xDB, 0x7E, 0x3C},
// Classic UFO (flying saucer)
{0x00, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x00},
// Alien Invader (wide arms)
{0x18, 0x3C, 0x7E, 0xDB, 0xFF, 0xDB, 0x7E, 0x3C},
// Alien Crab (Space Invaders style)
{0x3C, 0x7E, 0xFF, 0x5A, 0x5A, 0xFF, 0x7E, 0x3C},
// Saucer with beam
{0x00, 0x3C, 0x7E, 0xFF, 0x7E, 0x3C, 0x18, 0x18},
// Rocket Ship
{0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18},
// Alien Face (big eyes)
{0x3C, 0x42, 0xA5, 0x81, 0xA5, 0x99, 0x42, 0x3C},
// UFO with antenna
{0x00, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x5A, 0x24},
// Space Fighter (Galaga style)
{0x18, 0x3C, 0x7E, 0xFF, 0x7E, 0x3C, 0x18, 0x00},
// Alien Octopus
{0x3C, 0x7E, 0xFF, 0x5A, 0x5A, 0xFF, 0x7E, 0x3C},
// Mothership
{0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xDB, 0xFF, 0x7E}
};
const int TOTAL_CHARS = sizeof(retro) / sizeof(retro[0]);
// COMPREHENSIVE RETRO GAME NAMES FOR SCROLLING TEXT
const char* gameTexts[] = {
"PAC-MAN * MS. PAC-MAN * GALAGA * DONKEY KONG * SPACE INVADERS * ASTEROIDS * DEFENDER */"
"CENTIPEDE * FROGGER * DIG DUG * BURGERTIME * QBERT * JOUST * ROBOTRON * TETRIS * /"
"ARKANOID * PONG * BREAKOUT * TEMPEST * STAR WARS * TRON * ZAXXON * BUBBLE BOBBLE * /"
"GHOSTS N GOBLINS * DOUBLE DRAGON * STREET FIGHTER * FINAL FIGHTER * CONTRA * CASTLEVANIA * /"
"METROID * MEGA MAN * SONIC * MARIO BROS * SUPER MARIO * ZELDA * PUNCH OUT * OUTRUN * /"
"AFTER BURNER * GYRUSS * TIME PILOT * 1942 * SPY HUNTER * POLE POSITION * OUTLAWS * /"
"GAUNTLET * RAMPAGE * ALTERED BEAST * GOLDEN AXE * SHINOBI * STRIDER * /"
"TEENAGE MUTANT NINJA TURTLES * SIMPSONS * X-MEN * CAPTAIN COMMANDO * /"
"CADILLACS AND DINOSAURS * KING OF FIGHTERS * METAL SLUG * DARKSTALKERS * /"
"MARVEL VS CAPCOM * HOUSE OF THE DEAD * TIME CRISIS * VIRTUA FIGHTER * /"
"TEKKEN * SOUL CALIBUR * DANCE DANCE REVOLUTION * BEATMANIA /"
"POKEMON * KIRBY'S ADVENTURE * EARTHBOUND * CHRONO TRIGGER * FINAL FANTASY /"
"QUAKE * DUKE NUKEM * WOLFENSTEIN 3D * "
};
void drawCharAtPosition(uint8_t charData[8], int xOffset) {
// SIMPLIFIED - Only clear the column that's being left behind
int columnToClear = xOffset + 8; // The column RIGHT of the character
if (columnToClear >= 0 && columnToClear < Left) {
for (int y = 0; y < 8; y++) {
mx2.setPoint(y, columnToClear, false);
}
}
// Draw the 8x8 character at current position
for (int x = 0; x < 8; x++) {
int displayX = x + xOffset;
if (displayX >= 0 && displayX < Left) {
for (int y = 0; y < 8; y++) {
bool pixelOn = (charData[y] >> (7 - x)) & 0x01;
mx2.setPoint(y, displayX, pixelOn);
}
}
}
}
void anime1()
{
// ===== PANEL 1: GAME NAMES SCROLLING =====
if (parola.displayAnimate()) {
parola.displayReset();
textChanged = true;
}
// Change text occasionally for variety
if (textChanged && (currentMillis % (TEXT_CHANGE_MIN * 60000) == 0)) {
textIndex = (textIndex + 1) % (sizeof(gameTexts) / sizeof(gameTexts[0]));
parola.displayText(gameTexts[textIndex], PA_CENTER, 0, 0, PA_SCROLL_LEFT, PA_SCROLL_LEFT);
textChanged = false;
// LED effect for text change
for (int i = 0; i < 3; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
}
// ===== PANEL 2: CHARACTER SCROLLING =====
// Update scroll position
if (currentMillis - lastScrollTime >= SCROLL_SPEED_MS) {
scrollPosition--;
lastScrollTime = currentMillis;
// Draw character at current position
drawCharAtPosition(retro[currentChar], scrollPosition);
// Check if character has completely scrolled off screen LEFT side
if (scrollPosition <= -OFFSCREEN_BUFFER) {
scrollPosition = 32; // Reset to off-screen right
currentChar = (currentChar + 1) % TOTAL_CHARS;
// Clear the entire display before starting new character
mx2.clear();
// LED feedback for character change
digitalWrite(LED_BUILTIN, HIGH);
delay(10);
digitalWrite(LED_BUILTIN, LOW);
Serial.print("Character changed to: ");
Serial.println(currentChar);
}
}
// Change character automatically every few seconds
if (currentMillis - lastCharTime >= CHAR_CHANGE_MS) {
currentChar = (currentChar + 1) % TOTAL_CHARS;
lastCharTime = currentMillis;
scrollPosition = 32; // Restart from off-screen right
mx2.clear(); // Clear display for fresh start
// Double blink for character change
digitalWrite(LED_BUILTIN, HIGH);
delay(30);
digitalWrite(LED_BUILTIN, LOW);
delay(30);
digitalWrite(LED_BUILTIN, HIGH);
delay(30);
digitalWrite(LED_BUILTIN, LOW);
Serial.print("Auto character change to: ");
Serial.println(currentChar);
}
}