Trabajando en hacer que puedas entrar a la jail

This commit is contained in:
2022-11-05 20:56:09 +01:00
parent 1bcdadb6c0
commit 45fc923be9
10 changed files with 248 additions and 110 deletions

View File

@@ -12,66 +12,66 @@ Demo::Demo(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *as
rooms.push_back("60.room");
rooms.push_back("58.room");
//rooms.push_back("01.room");
//rooms.push_back("02.room");
//rooms.push_back("03.room");
//rooms.push_back("04.room");
//rooms.push_back("05.room");
//rooms.push_back("06.room");
//rooms.push_back("07.room");
//rooms.push_back("08.room");
//rooms.push_back("09.room");
//rooms.push_back("10.room");
//rooms.push_back("11.room");
//rooms.push_back("12.room");
//rooms.push_back("13.room");
//rooms.push_back("14.room");
//rooms.push_back("15.room");
//rooms.push_back("16.room");
//rooms.push_back("17.room");
//rooms.push_back("18.room");
//rooms.push_back("19.room");
//rooms.push_back("20.room");
//rooms.push_back("21.room");
//rooms.push_back("22.room");
//rooms.push_back("23.room");
//rooms.push_back("24.room");
//rooms.push_back("25.room");
//rooms.push_back("26.room");
//rooms.push_back("27.room");
//rooms.push_back("28.room");
//rooms.push_back("29.room");
//rooms.push_back("30.room");
//rooms.push_back("31.room");
//rooms.push_back("32.room");
//rooms.push_back("33.room");
//rooms.push_back("34.room");
//rooms.push_back("35.room");
//rooms.push_back("36.room");
//rooms.push_back("37.room");
//rooms.push_back("38.room");
//rooms.push_back("39.room");
//rooms.push_back("40.room");
//rooms.push_back("41.room");
//rooms.push_back("42.room");
//rooms.push_back("43.room");
//rooms.push_back("44.room");
//rooms.push_back("45.room");
//rooms.push_back("46.room");
//rooms.push_back("47.room");
//rooms.push_back("48.room");
//rooms.push_back("49.room");
//rooms.push_back("50.room");
//rooms.push_back("51.room");
//rooms.push_back("52.room");
//rooms.push_back("53.room");
//rooms.push_back("54.room");
//rooms.push_back("55.room");
//rooms.push_back("56.room");
//rooms.push_back("57.room");
//rooms.push_back("58.room");
//rooms.push_back("59.room");
//rooms.push_back("60.room");
// rooms.push_back("01.room");
// rooms.push_back("02.room");
// rooms.push_back("03.room");
// rooms.push_back("04.room");
// rooms.push_back("05.room");
// rooms.push_back("06.room");
// rooms.push_back("07.room");
// rooms.push_back("08.room");
// rooms.push_back("09.room");
// rooms.push_back("10.room");
// rooms.push_back("11.room");
// rooms.push_back("12.room");
// rooms.push_back("13.room");
// rooms.push_back("14.room");
// rooms.push_back("15.room");
// rooms.push_back("16.room");
// rooms.push_back("17.room");
// rooms.push_back("18.room");
// rooms.push_back("19.room");
// rooms.push_back("20.room");
// rooms.push_back("21.room");
// rooms.push_back("22.room");
// rooms.push_back("23.room");
// rooms.push_back("24.room");
// rooms.push_back("25.room");
// rooms.push_back("26.room");
// rooms.push_back("27.room");
// rooms.push_back("28.room");
// rooms.push_back("29.room");
// rooms.push_back("30.room");
// rooms.push_back("31.room");
// rooms.push_back("32.room");
// rooms.push_back("33.room");
// rooms.push_back("34.room");
// rooms.push_back("35.room");
// rooms.push_back("36.room");
// rooms.push_back("37.room");
// rooms.push_back("38.room");
// rooms.push_back("39.room");
// rooms.push_back("40.room");
// rooms.push_back("41.room");
// rooms.push_back("42.room");
// rooms.push_back("43.room");
// rooms.push_back("44.room");
// rooms.push_back("45.room");
// rooms.push_back("46.room");
// rooms.push_back("47.room");
// rooms.push_back("48.room");
// rooms.push_back("49.room");
// rooms.push_back("50.room");
// rooms.push_back("51.room");
// rooms.push_back("52.room");
// rooms.push_back("53.room");
// rooms.push_back("54.room");
// rooms.push_back("55.room");
// rooms.push_back("56.room");
// rooms.push_back("57.room");
// rooms.push_back("58.room");
// rooms.push_back("59.room");
// rooms.push_back("60.room");
roomIndex = 0;
currentRoom = rooms.at(roomIndex);
@@ -100,8 +100,7 @@ Demo::Demo(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *as
board.lives = 9;
board.items = 0;
board.rooms = 1;
const color_t c = room->getBorderColor();
board.color = (c.r + c.g + c.b == 0) ? stringToColor(options->palette, "white") : c; // Si el color es negro lo cambia a blanco
setScoreBoardColor();
board.music = !debug->getEnabled();
@@ -271,8 +270,8 @@ void Demo::switchPalette()
room->reLoadPalette();
scoreboard->reLoadPalette();
const color_t c = room->getBorderColor();
board.color = (c.r + c.g + c.b == 0) ? stringToColor(options->palette, "white") : c; // Si el color es negro lo cambia a blanco
// Pone el color del marcador en función del color del borde de la habitación
setScoreBoardColor();
}
// Cambia de habitación
@@ -290,9 +289,8 @@ bool Demo::changeRoom(std::string file)
// Crea un objeto habitación nuevo a partir del fichero
room = new Room(resource->getRoom(file), renderer, screen, asset, options, itemTracker, &board.items, debug);
// Actualiza el marcador
const color_t c = room->getBorderColor(); // Pone el color del marcador
board.color = (c.r + c.g + c.b == 0) ? stringToColor(options->palette, "white") : c; // Si el color es negro lo cambia a blanco
// Pone el color del marcador en función del color del borde de la habitación
setScoreBoardColor();
return true;
}
@@ -319,3 +317,18 @@ void Demo::checkRoomChange()
}
}
}
// Pone el color del marcador en función del color del borde de la habitación
void Demo::setScoreBoardColor()
{
// Obtiene el color del borde
const color_t c = room->getBorderColor();
// Si el color es negro lo cambia a blanco
const color_t cBlack = stringToColor(options->palette, "black");
board.color = colorAreEqual(c, cBlack) ? stringToColor(options->palette, "white") : c;
// Si el color es negro brillante lo cambia a blanco
const color_t cBrightBlack = stringToColor(options->palette, "bright_black");
board.color = colorAreEqual(c, cBrightBlack) ? stringToColor(options->palette, "white") : c;
}

View File

@@ -70,6 +70,9 @@ private:
// Comprueba si se ha de cambiar de habitación
void checkRoomChange();
// Pone el color del marcador en función del color del borde de la habitación
void setScoreBoardColor();
public:
// Constructor
Demo(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *asset, options_t *options, Debug *debug);

View File

@@ -9,7 +9,7 @@ Director::Director(int argc, char *argv[])
section.name = SECTION_PROG_LOGO;
section.subsection = SUBSECTION_LOGO_TO_INTRO;
section.name = SECTION_PROG_ENDING2;
section.name = SECTION_PROG_GAME;
// Crea e inicializa las opciones del programa
iniOptions();

View File

@@ -17,18 +17,27 @@ Ending2::Ending2(SDL_Renderer *renderer, Screen *screen, Resource *resource, Ass
music = JA_LoadMusic(asset->get("ending2.ogg").c_str());
// Inicializa variables
counter = -1;
counterEnabled = false;
preCounter = 0;
postCounter = 0;
postCounterEnabled = false;
section.name = SECTION_PROG_ENDING2;
section.subsection = 0;
ticks = 0;
ticksSpeed = 15;
distSpriteText = 8;
distSpriteSprite = 0;
despSpeed = -1.6f;
despSpeed = -0.2f;
firstCol = GAMECANVAS_FIRST_QUARTER_X + (GAMECANVAS_WIDTH / 16);
secondCol = GAMECANVAS_THIRD_QUARTER_X - (GAMECANVAS_WIDTH / 16);
// Inicializa el vector de colores
const std::vector<std::string> colorList = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
for (auto cl : colorList)
{
colors.push_back(stringToColor(options->palette, cl));
}
// Cambia el color del borde
screen->setBorderColor(stringToColor(options->palette, "black"));
@@ -76,6 +85,8 @@ void Ending2::update()
// Actualiza los contadores
updateCounters();
if (counterEnabled)
{
// Actualiza los sprites
updateSprites();
@@ -85,6 +96,13 @@ void Ending2::update()
// Actualiza los sprites de texto del final
updateTexts();
}
// Actualiza el fade final
updateFinalFade();
// Actualiza el volumen de la musica
updateMusicVolume();
}
}
// Dibuja el final en pantalla
@@ -105,7 +123,7 @@ void Ending2::render()
// Dibuja los sprites con el texto del final
renderTexts();
const std::string txt = std::to_string(preCounter) + " - " + std::to_string(counter) + " - W:" + std::to_string(maxSpriteWidth) + " - H:" + std::to_string(maxSpriteHeight);
const std::string txt = std::to_string(postCounter);
// text->write(0, 192 - 8, txt);
// Dibuja la cuadricula
@@ -124,6 +142,7 @@ void Ending2::render()
}*/
{
// Dibuja una trama arriba y abajo
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);
for (int i = 0; i < 256; i += 2)
{
@@ -219,7 +238,7 @@ void Ending2::checkEventHandler()
// Bucle principal
section_t Ending2::run()
{
// JA_PlayMusic(music);
JA_PlayMusic(music);
while (section.name == SECTION_PROG_ENDING2)
{
@@ -227,7 +246,8 @@ section_t Ending2::run()
render();
}
// JA_StopMusic();
JA_StopMusic();
JA_SetVolume(128);
return section;
}
@@ -236,13 +256,24 @@ section_t Ending2::run()
void Ending2::updateCounters()
{
// Incrementa el contador
if (preCounter < 100)
if (preCounter < 200)
{
preCounter++;
}
else
{
counter++;
counterEnabled = true;
}
if (postCounterEnabled)
{
postCounter++;
}
if (postCounter > 600)
{
section.name = SECTION_PROG_LOGO;
section.subsection = SUBSECTION_LOGO_TO_INTRO;
}
}
@@ -342,13 +373,17 @@ void Ending2::updateTextSprites()
// Actualiza los sprites de texto del final
void Ending2::updateTexts()
{
for (auto sprite : texts)
if (texts.back()->getPosY() > GAMECANVAS_CENTER_Y)
{
if (sprite->getPosY() > GAMECANVAS_CENTER_Y)
for (auto sprite : texts)
{
sprite->update();
}
}
else
{
postCounterEnabled = true;
}
}
// Dibuja los sprites
@@ -363,7 +398,6 @@ void Ending2::renderSprites()
{
sprite->getTexture()->setColor(color.r, color.g, color.b);
sprite->render();
sprite->getTexture()->setColor(255, 255, 255);
}
}
@@ -371,7 +405,6 @@ void Ending2::renderSprites()
const color_t c = stringToColor(options->palette, "white");
sprites.back()->getTexture()->setColor(c.r, c.g, c.b);
sprites.back()->render();
sprites.back()->getTexture()->setColor(255, 255, 255);
}
// Dibuja los sprites con el texto
@@ -386,7 +419,6 @@ void Ending2::renderSpriteTexts()
{
sprite->getTexture()->setColor(color.r, color.g, color.b);
sprite->render();
sprite->getTexture()->setColor(255, 255, 255);
}
}
}
@@ -394,16 +426,13 @@ void Ending2::renderSpriteTexts()
// Dibuja los sprites con el texto del final
void Ending2::renderTexts()
{
const color_t color = stringToColor(options->palette, "white");
for (auto sprite : texts)
{
const bool a = sprite->getRect().y + sprite->getRect().h > 0;
const bool b = sprite->getRect().y < GAMECANVAS_HEIGHT;
if (a && b)
{
sprite->getTexture()->setColor(color.r, color.g, color.b);
sprite->render();
sprite->getTexture()->setColor(255, 255, 255);
}
}
}
@@ -414,7 +443,7 @@ void Ending2::placeSprites()
for (int i = 0; i < (int)sprites.size(); ++i)
{
const int x = i % 2 == 0 ? firstCol : secondCol;
const int y = (i / 1) * (maxSpriteHeight + distSpriteText + text->getCharacterSize() + distSpriteSprite) + GAMECANVAS_HEIGHT;
const int y = (i / 1) * (maxSpriteHeight + distSpriteText + text->getCharacterSize() + distSpriteSprite) + GAMECANVAS_HEIGHT + 40;
const int w = sprites.at(i)->getAnimationClip(0, 0).w;
const int h = sprites.at(i)->getAnimationClip(0, 0).h;
const int dx = -(w / 2);
@@ -474,8 +503,36 @@ void Ending2::createTexts()
// Borra la memoria ocupada por los sprites con las texturas de los textos del final
deleteTexts();
const int start = spriteTexts.back()->getPosY() + text->getCharacterSize() * 6;
// Crea los primeros textos
std::vector<std::string> list;
list.push_back("STARRING");
// Crea los sprites de texto a partir de la lista
for (int i = 0; i < (int)list.size(); ++i)
{
// Calcula constantes
const int w = text->lenght(list.at(i), 1);
const int h = text->getCharacterSize();
const int x = GAMECANVAS_CENTER_X;
const int dx = -(w / 2);
const int y = GAMECANVAS_HEIGHT + (text->getCharacterSize() * (i * 2));
// Crea la textura
Texture *texture = new Texture(renderer);
texture->createBlank(renderer, w, h, SDL_TEXTUREACCESS_TARGET);
texture->setAsRenderTarget(renderer);
texture->setBlendMode(SDL_BLENDMODE_BLEND);
text->write(0, 0, list.at(i));
// Crea el sprite
MovingSprite *sprite = new MovingSprite(x + dx, y, w, h, 0.0f, despSpeed, 0.0f, 0.0f, texture, renderer);
texts.push_back(sprite);
}
// Crea los últimos textos
// El primer texto va a continuación del ultimo spriteText
const int start = spriteTexts.back()->getPosY() + text->getCharacterSize() * 6;
list.clear();
list.push_back("THANK YOU");
list.push_back("FOR PLAYING!");
@@ -532,3 +589,27 @@ void Ending2::deleteTexts()
}
texts.clear();
}
// Actualiza el fade final
void Ending2::updateFinalFade()
{
// La variable step va de 0 a 40 en el tramo de postCounter que va de 500 a 540. Al dividirlo por 40, va de 0.0f a 1.0f
const float step = std::min(std::max(postCounter, 500) - 500, 40) / 40.0f;
const int index = (colors.size() - 1) * step;
for (auto t : texts)
{
t->getTexture()->setColor(colors.at(index).r, colors.at(index).g, colors.at(index).b);
}
}
// Actualiza el volumen de la musica
void Ending2::updateMusicVolume()
{
if (postCounter > 0)
{
const float step = (600.0f - postCounter) / 600.0f;
const int volume = 128 * step;
JA_SetVolume(volume);
}
}

View File

@@ -32,13 +32,16 @@ private:
std::vector<MovingSprite *> texts; // Vector con los sprites de texto
// Variables
int counter; // Contador
bool counterEnabled; // Indica si está el contador habilitado
int preCounter; // Contador previo
int postCounter; // Contador posterior
bool postCounterEnabled; // Indica si está habilitado el contador
section_t section; // Estado del bucle principal para saber si continua o se sale
Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticksSpeed; // Velocidad a la que se repiten los bucles del programa
JA_Music music; // Musica que suena durante el final
std::vector<std::string> spriteList; // Lista con todos los sprites a dibujar
std::vector<color_t> colors; // Vector con los colores para el fade
int maxSpriteWidth; // El valor de ancho del sprite mas ancho
int maxSpriteHeight; // El valor de alto del sprite mas alto
int distSpriteText; // Distancia entre el sprite y el texto que lo acompaña
@@ -101,6 +104,12 @@ private:
// Borra la memoria ocupada por los sprites con las texturas de los textos del final
void deleteTexts();
// Actualiza el fade final
void updateFinalFade();
// Actualiza el volumen de la musica
void updateMusicVolume();
public:
// Constructor
Ending2(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *asset, options_t *options);

View File

@@ -45,16 +45,14 @@ Game::Game(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *as
board.lives = 9;
board.items = 0;
board.rooms = 1;
const color_t c = room->getBorderColor();
board.color = (c.r + c.g + c.b == 0) ? stringToColor(options->palette, "white") : c; // Si el color es negro lo cambia a blanco
setScoreBoardColor();
board.music = true;
board.jailEnabled = false;
roomTracker->addRoom(currentRoom);
paused = false;
blackScreen = false;
blackScreenCounter = 0;
// this->player->setInvincible(debug->getEnabled());
// board.music = !debug->getEnabled();
section.name = SECTION_PROG_GAME;
section.subsection = 0;
}
@@ -503,10 +501,16 @@ void Game::setScoreBoardColor()
// Comprueba si ha finalizado el juego
bool Game::checkEndGame()
{
const bool a = room->getName() == "THE JAIL";
const bool b = board.items >= 2;
const bool b = board.items >= 5;
const bool c = player->getRect().x < 152;
if (b)
{
board.jailEnabled = true;
}
if (a && b && c)
{
section.name = SECTION_PROG_ENDING;

View File

@@ -281,6 +281,7 @@ void Intro::render()
section_t Intro::run()
{
// Inicia el sonido de carga
JA_SetVolume(64);
JA_PlayMusic(loadingSound1);
while (section.name == SECTION_PROG_INTRO)
@@ -289,6 +290,7 @@ section_t Intro::run()
render();
}
JA_SetVolume(128);
return section;
}

View File

@@ -13,7 +13,7 @@ ScoreBoard::ScoreBoard(SDL_Renderer *renderer, Resource *resource, Asset *asset,
this->options = options;
// Reserva memoria para los objetos
//playerTexture = resource->getTexture("player.png");
// playerTexture = resource->getTexture("player.png");
itemTexture = resource->getTexture("items.png");
sprite = new AnimatedSprite(renderer, resource->getAnimation("player.ani"));
sprite->setCurrentAnimation("walk_menu");
@@ -25,6 +25,7 @@ ScoreBoard::ScoreBoard(SDL_Renderer *renderer, Resource *resource, Asset *asset,
paused = false;
timePaused = 0;
totalTimePaused = 0;
itemsColor = stringToColor(options->palette, "white");
// Inicializa el vector de colores
const std::vector<std::string> vColors = {"blue", "magenta", "green", "cyan", "yellow", "white", "bright_blue", "bright_magenta", "bright_green", "bright_cyan", "bright_yellow", "bright_white"};
@@ -79,7 +80,7 @@ void ScoreBoard::render()
const std::string timeTxt = std::to_string((clock.minutes % 60) / 10) + std::to_string(clock.minutes % 10) + clock.separator + std::to_string((clock.seconds % 60) / 10) + std::to_string(clock.seconds % 10);
const std::string itemsTxt = std::to_string(board->items / 100) + std::to_string((board->items % 100) / 10) + std::to_string(board->items % 10);
this->text->writeColored(BLOCK, line1, "Items collected ", board->color);
this->text->writeColored(17 * BLOCK, line1, itemsTxt, stringToColor(options->palette, "white"));
this->text->writeColored(17 * BLOCK, line1, itemsTxt, itemsColor);
this->text->writeColored(20 * BLOCK, line1, " Time ", board->color);
this->text->writeColored(26 * BLOCK, line1, timeTxt, stringToColor(options->palette, "white"));
@@ -94,6 +95,9 @@ void ScoreBoard::update()
counter++;
sprite->update();
// Actualiza el color de la cantidad de items recogidos
updateItemsColor();
if (!paused)
{ // Si está en pausa no se actualiza el reloj
clock = getTime();
@@ -118,7 +122,7 @@ ScoreBoard::clock_t ScoreBoard::getTime()
void ScoreBoard::reLoadTexture()
{
sprite->getTexture()->reLoad();
//playerTexture->reLoad();
// playerTexture->reLoad();
itemTexture->reLoad();
text->reLoadTexture();
}
@@ -148,3 +152,21 @@ void ScoreBoard::resume()
paused = false;
totalTimePaused += SDL_GetTicks() - timePaused;
}
// Actualiza el color de la cantidad de items recogidos
void ScoreBoard::updateItemsColor()
{
if (!board->jailEnabled)
{
return;
}
if (counter % 20 <10)
{
itemsColor = stringToColor(options->palette, "white");
}
else
{
itemsColor = stringToColor(options->palette, "magenta");
}
}

View File

@@ -19,7 +19,8 @@ struct board_t
int rooms; // Lleva la cuenta de las habitaciones visitadas
bool music; // Indica si ha de sonar la musica durante el juego
color_t color; // Color para escribir el texto del marcador
Uint32 iniClock;
Uint32 iniClock; // Tiempo inicial para calcular el tiempo transcurrido
bool jailEnabled; // Indica si se puede entrar a la Jail
};
class ScoreBoard
@@ -34,7 +35,6 @@ private:
};
// Objetos y punteros
//Texture *playerTexture; // Textura con los graficos para las vidas
AnimatedSprite *sprite; // Sprite para mostrar las vidas en el marcador
SDL_Renderer *renderer; // El renderizador de la ventana
Resource *resource; // Objeto con los recursos
@@ -52,10 +52,14 @@ private:
Uint32 timePaused; // Milisegundos que ha estado el marcador en pausa
Uint32 totalTimePaused; // Tiempo acumulado en pausa
clock_t clock; // Contiene las horas, minutos y segundos transcurridos desde el inicio de la partida
color_t itemsColor; // Color de la cantidad de items recogidos
// Obtiene el tiempo transcurrido de partida
clock_t getTime();
// Actualiza el color de la cantidad de items recogidos
void updateItemsColor();
public:
// Constructor
ScoreBoard(SDL_Renderer *renderer, Resource *resource, Asset *asset, options_t *options, board_t *board);

View File

@@ -29,8 +29,8 @@ Title::Title(SDL_Renderer *renderer, Screen *screen, Resource *resource, Asset *
section.subsection = 0;
ticks = 0;
ticksSpeed = 15;
//longText = "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!! HAVE YOU HEARD IT? JAILGAMES ARE BACK!! YEEESSS BACK!! MORE THAN 10 TITLES ON JAILDOC'S KITCHEN!! THATS A LOOOOOOT OF JAILGAMES, BUT WHICH ONE WILL STRIKE FIRST? THERE IS ALSO A NEW DEVICE TO COME P.A.C.O. THAT WILL BLOW YOUR MIND WITH JAILGAMES ON THE GO. BUT WAIT! WHAT'S THAT BEAUTY I'M SEEING RIGHT OVER THERE?? OOOH THAT TINY MINIASCII IS PURE LOVE!! I WANT TO LICK EVERY BYTE OF IT!! OH SHIT! AND DON'T FORGET TO BRING BACK THOSE OLD AND FAT MS-DOS JAILGAMES TO GITHUB TO KEEP THEM ALIVE!! WHAT WILL BE THE NEXT JAILDOC RELEASE? WHAT WILL BE THE NEXT PROJECT TO COME ALIVE?? OH BABY WE DON'T KNOW BUT HERE YOU CAN FIND THE ANSWER, YOU JUST HAVE TO COMPLETE JAILDOCTOR'S DILEMMA ... COULD YOU?";
longText = "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!!";
longText = "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!! HAVE YOU HEARD IT? JAILGAMES ARE BACK!! YEEESSS BACK!! MORE THAN 10 TITLES ON JAILDOC'S KITCHEN!! THATS A LOOOOOOT OF JAILGAMES, BUT WHICH ONE WILL STRIKE FIRST? THERE IS ALSO A NEW DEVICE TO COME THAT WILL BLOW YOUR MIND WITH JAILGAMES ON THE GO: P. A. C. O BUT WAIT! WHAT'S THAT BEAUTY I'M SEEING RIGHT OVER THERE?? OOOH THAT TINY MINIASCII IS PURE LOVE!! I WANT TO LICK EVERY BYTE OF IT!! OH SHIT! AND DON'T FORGET TO BRING BACK THOSE OLD AND FAT MS-DOS JAILGAMES TO GITHUB TO KEEP THEM ALIVE!! WHAT WILL BE THE NEXT JAILDOC RELEASE? WHAT WILL BE THE NEXT PROJECT TO COME ALIVE?? OH BABY WE DON'T KNOW BUT HERE YOU CAN FIND THE ANSWER, YOU JUST HAVE TO COMPLETE JAILDOCTOR'S DILEMMA ... COULD YOU?";
//longText = "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!!";
for (int i = 0; i < (int)longText.length(); ++i)
{
letter_t l;