/********************************************************************************************** * * raylib - Advance Game template * * Ending Screen Functions Definitions (Init, Update, Draw, Unload) * * Copyright (c) 2014-2018 Ramon Santamaria (@raysan5) * * This software is provided "as-is", without any express or implied warranty. In no event * will the authors be held liable for any damages arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, including commercial * applications, and to alter it and redistribute it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not claim that you * wrote the original software. If you use this software in a product, an acknowledgment * in the product documentation would be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be misrepresented * as being the original software. * * 3. This notice may not be removed or altered from any source distribution. * **********************************************************************************************/ #include "raylib.h" #include "screens.h" #include #include #define MAX_TITLE_CHAR 256 #define MAX_SUBTITLE_CHAR 256 //---------------------------------------------------------------------------------- // Global Variables Definition (local to this module) //---------------------------------------------------------------------------------- static char *codingWords[MAX_CODING_WORDS] = { "pollo\0", "conejo\0", "huevo\0", "nido\0", "aire\0", "armario\0", "agujero\0", "platano\0", "pastel\0", "mercado\0", "raton\0", "melon\0", }; // Ending screen global variables static int framesCounter; static int finishScreen; static Texture2D texBackground; static Texture2D texNewspaper; static Texture2D texVignette; static Sound fxNews; static float rotation = 0.1f; static float scale = 0.05f; static int state = 0; static Mission *missions = NULL; static char headline[MAX_TITLE_CHAR] = "\0"; SpriteFont fontNews; // String (const char *) replacement function static char *StringReplace(char *orig, char *rep, char *with); //---------------------------------------------------------------------------------- // Ending Screen Functions Definition //---------------------------------------------------------------------------------- // Ending Screen Initialization logic void InitEndingScreen(void) { framesCounter = 0; finishScreen = 0; rotation = 0.1f; scale = 0.05f; state = 0; texBackground = LoadTexture("resources/textures/ending_background.png"); texVignette = LoadTexture("resources/textures/message_vignette.png"); fxNews = LoadSound("resources/audio/fx_batman.ogg"); missions = LoadMissions("resources/missions.txt"); int wordsCount = missions[currentMission].wordsCount; strcpy(headline, missions[currentMission].msg); // Base headline int len = strlen(headline); // Remove @ from headline // TODO: Also remove additional spaces for (int i = 0; i < len; i++) { if (headline[i] == '@') headline[i] = ' '; } for (int i = 0; i < wordsCount; i++) { if (messageWords[i].id != missions[currentMission].sols[i]) { // WARNING: It fails if the last sentence word has a '.' after space char *title = StringReplace(headline, messageWords[i].text, codingWords[messageWords[i].id]); strcpy(headline, title); // Base headline updated if (title != NULL) free(title); } } TraceLog(LOG_WARNING, "Titular: %s", headline); // Generate newspaper with title and subtitle Image imNewspaper = LoadImage("resources/textures/ending_newspaper.png"); fontNews = LoadSpriteFontEx("resources/fonts/Lora-Bold.ttf", 32, 250, 0); ImageDrawTextEx(&imNewspaper, (Vector2){ 50, 220 }, fontNews, headline, fontNews.baseSize, 0, DARKGRAY); texNewspaper = LoadTextureFromImage(imNewspaper); //UnloadSpriteFont(fontNews); UnloadImage(imNewspaper); } // Ending Screen Update logic void UpdateEndingScreen(void) { framesCounter++; if (framesCounter == 10) PlaySound(fxNews); if (state == 0) { rotation += 18.0f; scale += 0.0096f; if (scale >= 1.0f) { scale = 1.0f; state = 1; } } if ((state == 1) && (IsKeyPressed(KEY_ENTER) || IsButtonPressed())) { currentMission++; if (currentMission >= totalMissions) finishScreen = 2; else finishScreen = 1; } } // Ending Screen Draw logic void DrawEndingScreen(void) { DrawTexture(texBackground, 0, 0, WHITE); DrawTexturePro(texNewspaper, (Rectangle){ 0, 0, texNewspaper.width, texNewspaper.height }, (Rectangle){ GetScreenWidth()/2, GetScreenHeight()/2, texNewspaper.width*scale, texNewspaper.height*scale }, (Vector2){ (float)texNewspaper.width*scale/2, (float)texNewspaper.height*scale/2 }, rotation, WHITE); DrawTextureEx(texVignette, (Vector2){ 0, 0 }, 0.0f, 2.0f, WHITE); // Draw debug information DrawTextEx(fontNews, headline, (Vector2){ 10, 10 }, fontNews.baseSize, 0, RAYWHITE); for (int i = 0; i < missions[currentMission].wordsCount; i++) { DrawText(codingWords[messageWords[i].id], 10, 60 + 30*i, 20, (messageWords[i].id == missions[currentMission].sols[i]) ? GREEN : RED); } if (state == 1) DrawButton("continuar"); } // Ending Screen Unload logic void UnloadEndingScreen(void) { UnloadTexture(texBackground); UnloadTexture(texNewspaper); UnloadTexture(texVignette); UnloadSound(fxNews); free(missions); } // Ending Screen should finish? int FinishEndingScreen(void) { return finishScreen; } // String (const char *) replacement function // NOTE: Internally allocated memory must be freed by the user (if return != NULL) // https://stackoverflow.com/questions/779875/what-is-the-function-to-replace-string-in-c static char *StringReplace(char *orig, char *rep, char *with) { char *result; // the return string char *ins; // the next insert point char *tmp; // varies int len_rep; // length of rep (the string to remove) int len_with; // length of with (the string to replace rep with) int len_front; // distance between rep and end of last rep int count; // number of replacements // Sanity checks and initialization if (!orig || !rep) return NULL; len_rep = strlen(rep); if (len_rep == 0) return NULL; // Empty rep causes infinite loop during count if (!with) with = ""; // Replace with nothing if not provided len_with = strlen(with); // Count the number of replacements needed ins = orig; for (count = 0; tmp = strstr(ins, rep); ++count) { ins = tmp + len_rep; } tmp = result = malloc(strlen(orig) + (len_with - len_rep)*count + 1); if (!result) return NULL; // Memory could not be allocated // First time through the loop, all the variable are set correctly from here on, // tmp points to the end of the result string // ins points to the next occurrence of rep in orig // orig points to the remainder of orig after "end of rep" while (count--) { ins = strstr(orig, rep); len_front = ins - orig; tmp = strncpy(tmp, orig, len_front) + len_front; tmp = strcpy(tmp, with) + len_with; orig += len_front + len_rep; // move to next "end of rep" } strcpy(tmp, orig); return result; }