diff --git a/games/light_my_ritual/light_my_ritual.c b/games/light_my_ritual/light_my_ritual.c new file mode 100644 index 000000000..0f1dc47ee --- /dev/null +++ b/games/light_my_ritual/light_my_ritual.c @@ -0,0 +1,271 @@ +/******************************************************************************************* +* +* GLOBAL GAME JAM 2016 - LIGHT MY RITUAL! +* +* Preparing a ritual session is not that easy. +* You must light all the candles before the astral alignment finishes... +* but dark creatures move in the shadows to put out all your lights! +* Be fast! Be smart! Light my ritual! +* +* This game has been created using raylib (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2015 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +********************************************************************************************/ + +#include "raylib.h" +#include "screens/screens.h" // NOTE: Defines global variable: currentScreen + +#include + +#if defined(PLATFORM_WEB) + #include +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- +const int screenWidth = 1280; +const int screenHeight = 720; + +// Required variables to manage screen transitions (fade-in, fade-out) +float transAlpha = 0; +bool onTransition = false; +bool transFadeOut = false; +int transFromScreen = -1; +int transToScreen = -1; + +//---------------------------------------------------------------------------------- +// Local Functions Declaration +//---------------------------------------------------------------------------------- +void TransitionToScreen(int screen); +void ChangeToScreen(int screen); // No transition effect +void UpdateTransition(void); +void DrawTransition(void); + +void UpdateDrawFrame(void); // Update and Draw one frame + +//---------------------------------------------------------------------------------- +// Main entry point +//---------------------------------------------------------------------------------- +int main(void) +{ + // Initialization + //--------------------------------------------------------- + InitWindow(screenWidth, screenHeight, "GGJ16 - LIGHT MY RITUAL!"); + + // Global data loading (assets that must be available in all screens, i.e. fonts) + InitAudioDevice(); + + Image image = LoadImage("resources/lights_map.png"); // Load image in CPU memory (RAM) + + lightsMap = GetImageData(image); // Get image pixels data as an array of Color + lightsMapWidth = image.width; + lightsMapHeight = image.height; + + UnloadImage(image); // Unload image from CPU memory (RAM) + + //PlayMusicStream("resources/audio/come_play_with_me.ogg"); + + font = LoadSpriteFont("resources/font_arcadian.png"); + //doors = LoadTexture("resources/textures/doors.png"); + //sndDoor = LoadSound("resources/audio/door.ogg"); + + // Setup and Init first screen + currentScreen = LOGO_RL; + //InitTitleScreen(); + //InitGameplayScreen(); + rlInitLogoScreen(); + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(UpdateDrawFrame, 0, 1); +#else + SetTargetFPS(60); // Set our game to run at 60 frames-per-second + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + UpdateDrawFrame(); + } +#endif + + // De-Initialization + //-------------------------------------------------------------------------------------- + switch (currentScreen) + { + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + default: break; + } + + // Unload all global loaded data (i.e. fonts) here! + UnloadSpriteFont(font); + //UnloadSound(sndDoor); + + free(lightsMap); + + CloseAudioDevice(); + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} + +void TransitionToScreen(int screen) +{ + onTransition = true; + transFromScreen = currentScreen; + transToScreen = screen; +} + +void ChangeToScreen(int screen) +{ + switch (currentScreen) + { + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + default: break; + } + + switch (screen) + { + case LOGO_RL: rlInitLogoScreen(); break; + case TITLE: InitTitleScreen(); break; + case GAMEPLAY: InitGameplayScreen(); break; + default: break; + } + + currentScreen = screen; +} + +void UpdateTransition(void) +{ + if (!transFadeOut) + { + transAlpha += 0.05f; + + if (transAlpha >= 1.0) + { + transAlpha = 1.0; + + switch (transFromScreen) + { + case LOGO_RL: rlUnloadLogoScreen(); break; + case TITLE: UnloadTitleScreen(); break; + case GAMEPLAY: UnloadGameplayScreen(); break; + default: break; + } + + switch (transToScreen) + { + case LOGO_RL: + { + rlInitLogoScreen(); + currentScreen = LOGO_RL; + } break; + case TITLE: + { + InitTitleScreen(); + currentScreen = TITLE; + } break; + case GAMEPLAY: + { + InitGameplayScreen(); + currentScreen = GAMEPLAY; + } break; + default: break; + } + + transFadeOut = true; + } + } + else // Transition fade out logic + { + transAlpha -= 0.05f; + + if (transAlpha <= 0) + { + transAlpha = 0; + transFadeOut = false; + onTransition = false; + transFromScreen = -1; + transToScreen = -1; + } + } +} + +void DrawTransition(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, transAlpha)); +} + +// Update and draw game frame +void UpdateDrawFrame(void) +{ + // Update + //---------------------------------------------------------------------------------- + if (!onTransition) + { + switch(currentScreen) + { + case LOGO_RL: + { + rlUpdateLogoScreen(); + + if (rlFinishLogoScreen()) TransitionToScreen(TITLE); + + } break; + case TITLE: + { + UpdateTitleScreen(); + + if (FinishTitleScreen() == 1) TransitionToScreen(GAMEPLAY); + + } break; + case GAMEPLAY: + { + UpdateGameplayScreen(); + + if (FinishGameplayScreen() == 1) ChangeToScreen(LOGO_RL); + else if (FinishGameplayScreen() == 2) TransitionToScreen(TITLE); + + } break; + default: break; + } + } + else + { + // Update transition (fade-in, fade-out) + UpdateTransition(); + } + + UpdateMusicStream(); + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + switch(currentScreen) + { + case LOGO_RL: rlDrawLogoScreen(); break; + case TITLE: DrawTitleScreen(); break; + case GAMEPLAY: DrawGameplayScreen(); break; + default: break; + } + + if (onTransition) DrawTransition(); + + //DrawFPS(10, 10); + + EndDrawing(); + //---------------------------------------------------------------------------------- +} + diff --git a/games/light_my_ritual/makefile b/games/light_my_ritual/makefile new file mode 100644 index 000000000..b7e1bb580 --- /dev/null +++ b/games/light_my_ritual/makefile @@ -0,0 +1,203 @@ +#************************************************************************************************** +# +# raylib - Advance Game +# +# makefile to compile advance game +# +# Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +# +# 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. +# +#************************************************************************************************** + +# define raylib platform if not defined (by default, compile for RPI) +# Other possible platform: PLATFORM_DESKTOP +PLATFORM ?= PLATFORM_DESKTOP + +# determine PLATFORM_OS in case PLATFORM_DESKTOP selected +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + # No uname.exe on MinGW!, but OS=Windows_NT on Windows! ifeq ($(UNAME),Msys) -> Windows + ifeq ($(OS),Windows_NT) + PLATFORM_OS=WINDOWS + LIBPATH=win32 + else + UNAMEOS:=$(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS=LINUX + LIBPATH=linux + else + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS=OSX + LIBPATH=osx + endif + endif + endif +endif + +# define compiler: gcc for C program, define as g++ for C++ +ifeq ($(PLATFORM),PLATFORM_WEB) + # define emscripten compiler + CC = emcc +else +ifeq ($(PLATFORM_OS),OSX) + # define llvm compiler for mac + CC = clang +else + # define default gcc compiler + CC = gcc +endif +endif + +# define compiler flags: +# -O2 defines optimization level +# -Wall turns on most, but not all, compiler warnings +# -std=c99 use standard C from 1999 revision +ifeq ($(PLATFORM),PLATFORM_RPI) + CFLAGS = -O2 -Wall -std=gnu99 -fgnu89-inline +else + CFLAGS = -O2 -Wall -std=c99 +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + CFLAGS = -O1 -Wall -std=c99 -s USE_GLFW=3 --preload-file resources -s ALLOW_MEMORY_GROWTH=1 + #-s ASSERTIONS=1 --preload-file resources + #-s ALLOW_MEMORY_GROWTH=1 # to allow memory resizing + #-s TOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) +endif + +# define any directories containing required header files +ifeq ($(PLATFORM),PLATFORM_RPI) + INCLUDES = -I. -I../../src -I/opt/vc/include -I/opt/vc/include/interface/vcos/pthreads +else + INCLUDES = -I. -IC:/raylib/raylib/src -IC:/raylib/raylib/src +# external libraries headers +# GLFW3 + INCLUDES += -I../../external/glfw3/include +# GLEW + INCLUDES += -I../../external/glew/include +# OpenAL Soft + INCLUDES += -I../../external/openal_soft/include +endif + +# define library paths containing required libs +ifeq ($(PLATFORM),PLATFORM_RPI) + LFLAGS = -L. -L../../src -L/opt/vc/lib +else + LFLAGS = -L. -LC:/raylib/raylib/src -L../../../src + # external libraries to link with + # GLFW3 + LFLAGS += -L../../external/glfw3/lib/$(LIBPATH) + ifneq ($(PLATFORM_OS),OSX) + # OpenAL Soft + LFLAGS += -L../../external/openal_soft/lib/$(LIBPATH) + # GLEW + LFLAGS += -L../../external/glew/lib/$(LIBPATH) + endif +endif + +# define any libraries to link into executable +# if you want to link libraries (libname.so or libname.a), use the -lname +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),LINUX) + # libraries for Debian GNU/Linux desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -lGLEW -lGL -lopenal + endif + ifeq ($(PLATFORM_OS),OSX) + # libraries for OS X 10.9 desktop compiling + # requires the following packages: + # libglfw3-dev libopenal-dev libglew-dev libegl1-mesa-dev + LIBS = -lraylib -lglfw -framework OpenGL -framework OpenAl -framework Cocoa + else + # libraries for Windows desktop compiling + # NOTE: GLFW3 and OpenAL Soft libraries should be installed + LIBS = -lraylib -lglfw3 -lglew32 -lopengl32 -lopenal32 -lgdi32 + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + # libraries for Raspberry Pi compiling + # NOTE: OpenAL Soft library should be installed (libopenal1 package) + LIBS = -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lopenal +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + LIBS = C:/raylib/raylib/src/libraylib.bc +endif + +# define additional parameters and flags for windows +ifeq ($(PLATFORM_OS),WINDOWS) + # resources file contains windows exe icon + # -Wl,--subsystem,windows hides the console window + WINFLAGS = C:/raylib/raylib/src/resources -Wl,--subsystem,windows +endif + +ifeq ($(PLATFORM),PLATFORM_WEB) + EXT = .html +endif + +# define all screen object files required +SCREENS = \ + screens/screen_logo_raylib.o \ + screens/screen_title.o \ + screens/screen_gameplay.o \ + +# typing 'make' will invoke the first target entry in the file, +# in this case, the 'default' target entry is advance_game +default: light_my_ritual + +# compile template - advance_game +light_my_ritual: light_my_ritual.c $(SCREENS) + $(CC) -o $@$(EXT) $< $(SCREENS) $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) $(WINFLAGS) + +# compile screen LOGO raylib +screens/screen_logo_raylib.o: screens/screen_logo_raylib.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen TITLE +screens/screen_title.o: screens/screen_title.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# compile screen ENDING +screens/screen_gameplay.o: screens/screen_gameplay.c + $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDES) -D$(PLATFORM) + +# clean everything +clean: +ifeq ($(PLATFORM),PLATFORM_DESKTOP) + ifeq ($(PLATFORM_OS),OSX) + find . -type f -perm +ugo+x -delete + rm -f *.o + else + ifeq ($(PLATFORM_OS),LINUX) + find . -type f -executable -delete + rm -f *.o + else + del *.o *.exe + endif + endif +endif +ifeq ($(PLATFORM),PLATFORM_RPI) + find . -type f -executable -delete + rm -f *.o +endif +ifeq ($(PLATFORM),PLATFORM_WEB) + del *.o *.html *.js +endif + @echo Cleaning done + +# instead of defining every module one by one, we can define a pattern +# this pattern below will automatically compile every module defined on $(OBJS) +#%.exe : %.c +# $(CC) -o $@ $< $(CFLAGS) $(INCLUDES) $(LFLAGS) $(LIBS) -D$(PLATFORM) diff --git a/games/light_my_ritual/resources/audio/ambient.ogg b/games/light_my_ritual/resources/audio/ambient.ogg new file mode 100644 index 000000000..5828c5161 Binary files /dev/null and b/games/light_my_ritual/resources/audio/ambient.ogg differ diff --git a/games/light_my_ritual/resources/audio/light_off.wav b/games/light_my_ritual/resources/audio/light_off.wav new file mode 100644 index 000000000..d2203e721 Binary files /dev/null and b/games/light_my_ritual/resources/audio/light_off.wav differ diff --git a/games/light_my_ritual/resources/audio/light_on.wav b/games/light_my_ritual/resources/audio/light_on.wav new file mode 100644 index 000000000..38b7ca58d Binary files /dev/null and b/games/light_my_ritual/resources/audio/light_on.wav differ diff --git a/games/light_my_ritual/resources/audio/ritual.ogg b/games/light_my_ritual/resources/audio/ritual.ogg new file mode 100644 index 000000000..4674ff7b6 Binary files /dev/null and b/games/light_my_ritual/resources/audio/ritual.ogg differ diff --git a/games/light_my_ritual/resources/audio/start.wav b/games/light_my_ritual/resources/audio/start.wav new file mode 100644 index 000000000..66ce7ac16 Binary files /dev/null and b/games/light_my_ritual/resources/audio/start.wav differ diff --git a/games/light_my_ritual/resources/font_arcadian.png b/games/light_my_ritual/resources/font_arcadian.png new file mode 100644 index 000000000..5c3df51ac Binary files /dev/null and b/games/light_my_ritual/resources/font_arcadian.png differ diff --git a/games/light_my_ritual/resources/lights_map.png b/games/light_my_ritual/resources/lights_map.png new file mode 100644 index 000000000..362094cd8 Binary files /dev/null and b/games/light_my_ritual/resources/lights_map.png differ diff --git a/games/light_my_ritual/resources/textures/back_title.png b/games/light_my_ritual/resources/textures/back_title.png new file mode 100644 index 000000000..549212478 Binary files /dev/null and b/games/light_my_ritual/resources/textures/back_title.png differ diff --git a/games/light_my_ritual/resources/textures/background.png b/games/light_my_ritual/resources/textures/background.png new file mode 100644 index 000000000..367bdd30c Binary files /dev/null and b/games/light_my_ritual/resources/textures/background.png differ diff --git a/games/light_my_ritual/resources/textures/book.png b/games/light_my_ritual/resources/textures/book.png new file mode 100644 index 000000000..c0bfbdb37 Binary files /dev/null and b/games/light_my_ritual/resources/textures/book.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_i_off.png b/games/light_my_ritual/resources/textures/circle_level_i_off.png new file mode 100644 index 000000000..7961af7d4 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_i_off.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_i_on.png b/games/light_my_ritual/resources/textures/circle_level_i_on.png new file mode 100644 index 000000000..1f2177349 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_i_on.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_ii_off.png b/games/light_my_ritual/resources/textures/circle_level_ii_off.png new file mode 100644 index 000000000..642adc3be Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_ii_off.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_ii_on.png b/games/light_my_ritual/resources/textures/circle_level_ii_on.png new file mode 100644 index 000000000..93b71b3a5 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_ii_on.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_iii_off.png b/games/light_my_ritual/resources/textures/circle_level_iii_off.png new file mode 100644 index 000000000..daf50be95 Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_iii_off.png differ diff --git a/games/light_my_ritual/resources/textures/circle_level_iii_on.png b/games/light_my_ritual/resources/textures/circle_level_iii_on.png new file mode 100644 index 000000000..e2256e95c Binary files /dev/null and b/games/light_my_ritual/resources/textures/circle_level_iii_on.png differ diff --git a/games/light_my_ritual/resources/textures/enemy.png b/games/light_my_ritual/resources/textures/enemy.png new file mode 100644 index 000000000..dc0a911d2 Binary files /dev/null and b/games/light_my_ritual/resources/textures/enemy.png differ diff --git a/games/light_my_ritual/resources/textures/foreground_level_i.png b/games/light_my_ritual/resources/textures/foreground_level_i.png new file mode 100644 index 000000000..32b96740d Binary files /dev/null and b/games/light_my_ritual/resources/textures/foreground_level_i.png differ diff --git a/games/light_my_ritual/resources/textures/foreground_level_ii.png b/games/light_my_ritual/resources/textures/foreground_level_ii.png new file mode 100644 index 000000000..44f26003a Binary files /dev/null and b/games/light_my_ritual/resources/textures/foreground_level_ii.png differ diff --git a/games/light_my_ritual/resources/textures/foreground_level_iii.png b/games/light_my_ritual/resources/textures/foreground_level_iii.png new file mode 100644 index 000000000..0fc039d72 Binary files /dev/null and b/games/light_my_ritual/resources/textures/foreground_level_iii.png differ diff --git a/games/light_my_ritual/resources/textures/light.png b/games/light_my_ritual/resources/textures/light.png new file mode 100644 index 000000000..5d08326f8 Binary files /dev/null and b/games/light_my_ritual/resources/textures/light.png differ diff --git a/games/light_my_ritual/resources/textures/light_glow.png b/games/light_my_ritual/resources/textures/light_glow.png new file mode 100644 index 000000000..d31356c6d Binary files /dev/null and b/games/light_my_ritual/resources/textures/light_glow.png differ diff --git a/games/light_my_ritual/resources/textures/light_ray.png b/games/light_my_ritual/resources/textures/light_ray.png new file mode 100644 index 000000000..f9f877fa4 Binary files /dev/null and b/games/light_my_ritual/resources/textures/light_ray.png differ diff --git a/games/light_my_ritual/resources/textures/msg_ritual.png b/games/light_my_ritual/resources/textures/msg_ritual.png new file mode 100644 index 000000000..73f14d484 Binary files /dev/null and b/games/light_my_ritual/resources/textures/msg_ritual.png differ diff --git a/games/light_my_ritual/resources/textures/player.png b/games/light_my_ritual/resources/textures/player.png new file mode 100644 index 000000000..d6849478c Binary files /dev/null and b/games/light_my_ritual/resources/textures/player.png differ diff --git a/games/light_my_ritual/resources/textures/time_over.png b/games/light_my_ritual/resources/textures/time_over.png new file mode 100644 index 000000000..9f7935bea Binary files /dev/null and b/games/light_my_ritual/resources/textures/time_over.png differ diff --git a/games/light_my_ritual/resources/textures/title.png b/games/light_my_ritual/resources/textures/title.png new file mode 100644 index 000000000..55eb593dd Binary files /dev/null and b/games/light_my_ritual/resources/textures/title.png differ diff --git a/games/light_my_ritual/screens/screen_gameplay.c b/games/light_my_ritual/screens/screen_gameplay.c new file mode 100644 index 000000000..b91d25459 --- /dev/null +++ b/games/light_my_ritual/screens/screen_gameplay.c @@ -0,0 +1,842 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Gameplay Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* 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 + +#define MAX_LIGHTS_I 8 +#define MAX_LIGHTS_II 12 +#define MAX_LIGHTS_III 20 + +#define MAX_ENEMIES 8 + +#define MAX_PLAYER_ENERGY 40.0f +#define ENERGY_REFILL_RATIO 0.2f + +#define GAMEPAD_SENSITIVITY 4.0f // More sensitivity, more speed :P + +#define LIGHT_ANIM_FRAMES 7 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct Player { + Vector2 position; + Vector2 speed; + int radius; + Color color; + float lightEnergy; +} Player; + +typedef struct Enemy { + Vector2 position; + Vector2 targetPos; // light target position + int targetNum; // light target number + float speed; // scalar value + int radius; + int active; + int awakeFramesDelay; + int framesCounter; + Color color; +} Enemy; + +typedef struct Light { + Vector2 position; + int radius; + int requiredEnergy; + bool active; + Color color; + + int framesCounter; + int currentFrame; + Rectangle frameRec; +} Light; + +typedef enum { LEVEL_I, LEVEL_II, LEVEL_III, LEVEL_FINISHED } LightedLevel; + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Gameplay screen global variables +static int framesCounter; +static int finishScreen; + +//static Texture2D background; + +static bool pause; + +static Player player; + +static Light lightsI[MAX_LIGHTS_I]; +static Light lightsII[MAX_LIGHTS_II]; +static Light lightsIII[MAX_LIGHTS_III]; + +static Enemy enemies[MAX_ENEMIES]; + +static int ritualLevel; +static int previousLightedLevel; +static int currentLightedLevel; + +static Vector2 lighterPosition; + +static int maxLightEnergy; +static int currentLightEnergy; + +static float ritualTime; +static bool startRitual; +static float alphaRitual; + +static bool timeOver; +static int nextStarsAlignment; + +static Texture2D background; +static Texture2D foregroundI; +static Texture2D foregroundII; +static Texture2D foregroundIII; +static Texture2D texPlayer; +static Texture2D texEnemy; +static Texture2D texLight; +static Texture2D lightGlow; +static Texture2D lightRay; +static Texture2D book; +static Texture2D texRitual; +static Texture2D texTimeOver; +static Texture2D circleIoff, circleIIoff, circleIIIoff; +static Texture2D circleIon, circleIIon, circleIIIon; + +static Rectangle lightOff, lightOn; + +static Sound fxLightOn, fxLightOff; + +// Debug variables +static bool enemiesStopped; + +//------------------------------------------------------------------------------------ +// Module Functions Declaration (local) +//------------------------------------------------------------------------------------ +static bool ColorEqual(Color col1, Color col2); // Check if two colors are equal +static Vector2 Vector2Subtract(Vector2 v1, Vector2 v2); +static void Vector2Normalize(Vector2 *v); +static void EnemyReset(Enemy *enemy); + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Gameplay Screen Initialization logic +void InitGameplayScreen(void) +{ + framesCounter = 0; + finishScreen = 0; + pause = false; + + // Textures loading + background = LoadTexture("resources/textures/background.png"); + foregroundI = LoadTexture("resources/textures/foreground_level_i.png"); + foregroundII = LoadTexture("resources/textures/foreground_level_ii.png"); + foregroundIII = LoadTexture("resources/textures/foreground_level_iii.png"); + texPlayer = LoadTexture("resources/textures/player.png"); + texEnemy = LoadTexture("resources/textures/enemy.png"); + texLight = LoadTexture("resources/textures/light.png"); + lightGlow = LoadTexture("resources/textures/light_glow.png"); + lightRay = LoadTexture("resources/textures/light_ray.png"); + book = LoadTexture("resources/textures/book.png"); + texRitual = LoadTexture("resources/textures/msg_ritual.png"); + texTimeOver = LoadTexture("resources/textures/time_over.png"); + + circleIoff = LoadTexture("resources/textures/circle_level_i_off.png"); + circleIIoff = LoadTexture("resources/textures/circle_level_ii_off.png"); + circleIIIoff = LoadTexture("resources/textures/circle_level_iii_off.png"); + circleIon = LoadTexture("resources/textures/circle_level_i_on.png"); + circleIIon = LoadTexture("resources/textures/circle_level_ii_on.png"); + circleIIIon = LoadTexture("resources/textures/circle_level_iii_on.png"); + + lightOff = (Rectangle){ 0, 0, 64, 64 }; + lightOn = (Rectangle){ 64, 0, 64, 64 }; + + fxLightOn = LoadSound("resources/audio/light_on.wav"); + fxLightOff = LoadSound("resources/audio/light_off.wav"); + + // Initialize player + player.position = (Vector2){ GetScreenWidth()/2, GetScreenHeight()/2 - 40 }; + player.radius = 20; + player.speed = (Vector2){5, 5}; + player.color = WHITE; + + // Initialize lights positions based on lights map image data + int kI = 0, kII = 0, kIII = 0; + for (int y = 0; y < lightsMapHeight; y++) + { + for (int x = 0; x < lightsMapWidth; x++) + { + if (ColorEqual(lightsMap[y*lightsMapWidth + x], (Color){ 255, 0, 0, 255 })) + { + // Store light position I + lightsI[kI].position.x = (float)x*10; + lightsI[kI].position.y = (float)y*10; + kI++; + + //printf("Light %02i position: %i, %i\n", kI, (int)lightsI[kI - 1].position.x, (int)lightsI[kI - 1].position.y); + } + else if (ColorEqual(lightsMap[y*lightsMapWidth + x], (Color){ 0, 255, 0, 255 })) + { + // Store light position II + lightsII[kII].position.x = (float)x*10; + lightsII[kII].position.y = (float)y*10; + kII++; + } + else if (ColorEqual(lightsMap[y*lightsMapWidth + x], (Color){ 0, 0, 255, 255 })) + { + // Store light position III + lightsIII[kIII].position.x = (float)x*10; + lightsIII[kIII].position.y = (float)y*10; + kIII++; + } + } + } + + // Initialize lights I + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + lightsI[i].radius = 12; + lightsI[i].requiredEnergy = GetRandomValue(3, 9); + lightsI[i].active = false; + lightsI[i].color = GOLD; + + lightsI[i].framesCounter = 0; + lightsI[i].currentFrame = 0; + lightsI[i].frameRec = (Rectangle){ 0, 0, 64, 64 }; + } + + // Initialize lights II + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + lightsII[i].radius = 8; + lightsII[i].requiredEnergy = GetRandomValue(3, 8); + lightsII[i].active = false; + lightsII[i].color = GOLD; + + lightsII[i].framesCounter = 0; + lightsII[i].currentFrame = 0; + lightsII[i].frameRec = (Rectangle){ 0, 0, 64, 64 }; + } + + // Initialize lights III + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + lightsIII[i].radius = 8; + lightsIII[i].requiredEnergy = GetRandomValue(4, 10); + lightsIII[i].active = false; + lightsIII[i].color = GOLD; + + lightsIII[i].framesCounter = 0; + lightsIII[i].currentFrame = 0; + lightsIII[i].frameRec = (Rectangle){ 0, 0, 64, 64 }; + } + + // Initialize ritual level + ritualLevel = 0; + currentLightedLevel = LEVEL_I; + lighterPosition = (Vector2){ GetScreenWidth()/2, GetScreenHeight()/2 }; + + // Initialize enemies + for (int i = 0; i < MAX_ENEMIES; i++) EnemyReset(&enemies[i]); + + // Initialize max light energy (depends on lights randomness) + maxLightEnergy = 0; + + for (int i = 0; i < MAX_LIGHTS_I; i++) maxLightEnergy += lightsI[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_II; i++) maxLightEnergy += lightsII[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_III; i++) maxLightEnergy += lightsIII[i].requiredEnergy; + + //printf("Max light energy: %i\n", maxLightEnergy); + + // Initialize ritual variables + ritualTime = 0.0f; + startRitual = false;; + alphaRitual = 0.0f; + + timeOver = false; + nextStarsAlignment = GetRandomValue(500, 1000); + + enemiesStopped = false; + + PlayMusicStream("resources/audio/ritual.ogg"); +} + +// Gameplay Screen Update logic +void UpdateGameplayScreen(void) +{ + if (IsKeyPressed('P')) pause = !pause; + + if (!pause && (currentLightedLevel != LEVEL_FINISHED) && !timeOver) + { + framesCounter++; // Time starts counting to awake enemies + + // Player movement logic + if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x; + else if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x; + + if (IsKeyDown(KEY_UP)) player.position.y -= player.speed.y; + else if (IsKeyDown(KEY_DOWN)) player.position.y += player.speed.y; + + // Debug key to stop enemies + if (IsKeyPressed(KEY_S)) enemiesStopped = !enemiesStopped; + + /* + if (IsGamepadAvailable(GAMEPAD_PLAYER1)) + { + Vector2 movement = GetGamepadMovement(GAMEPAD_PLAYER1); + + player.position.x += movement.x*GAMEPAD_SENSITIVITY; + player.position.y += movement.y*GAMEPAD_SENSITIVITY; + } + */ + + // Player light energy filling logic + if (CheckCollisionCircles(player.position, player.radius, lighterPosition, 50)) + { + player.lightEnergy += ENERGY_REFILL_RATIO; + player.color = (Color){ 255, 255, 100, 255 }; + } + else player.color = WHITE; + + if (player.lightEnergy > MAX_PLAYER_ENERGY) player.lightEnergy = MAX_PLAYER_ENERGY; + + // Player vs lights collision detection (depends on lighted level) + if (currentLightedLevel == LEVEL_I) + { + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + // Check player vs lightI collision + if (CheckCollisionCircles(player.position, player.radius, lightsI[i].position, lightsI[i].radius)) + { + if (!lightsI[i].active && (player.lightEnergy >= lightsI[i].requiredEnergy)) + { + lightsI[i].active = true; + lightsI[i].currentFrame = 1; + player.lightEnergy -= lightsI[i].requiredEnergy; + + PlaySound(fxLightOn); + } + } + } + } + else if (currentLightedLevel == LEVEL_II) + { + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + if (CheckCollisionCircles(player.position, player.radius, lightsII[i].position, lightsII[i].radius)) + { + if (!lightsII[i].active && (player.lightEnergy >= lightsII[i].requiredEnergy)) + { + lightsII[i].active = true; + player.lightEnergy -= lightsII[i].requiredEnergy; + + PlaySound(fxLightOn); + } + } + } + } + else if (currentLightedLevel == LEVEL_III) + { + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + if (CheckCollisionCircles(player.position, player.radius, lightsIII[i].position, lightsIII[i].radius)) + { + if (!lightsIII[i].active && (player.lightEnergy >= lightsIII[i].requiredEnergy)) + { + lightsIII[i].active = true; + player.lightEnergy -= lightsIII[i].requiredEnergy; + + PlaySound(fxLightOn); + } + } + } + } + + // Lights animation (it doesn't depend on currentLightedLevel) + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + // Light animation + if (lightsI[i].active) + { + lightsI[i].framesCounter++; + + if (lightsI[i].framesCounter > 10) + { + lightsI[i].currentFrame++; + + if (lightsI[i].currentFrame > LIGHT_ANIM_FRAMES - 1) lightsI[i].currentFrame = 1; + + lightsI[i].framesCounter = 0; + } + } + + lightsI[i].frameRec.x = lightsI[i].currentFrame*texLight.width/LIGHT_ANIM_FRAMES; + } + + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + // Light animation + if (lightsII[i].active) + { + lightsII[i].framesCounter++; + + if (lightsII[i].framesCounter > 10) + { + lightsII[i].currentFrame++; + + if (lightsII[i].currentFrame > LIGHT_ANIM_FRAMES - 1) lightsII[i].currentFrame = 1; + + lightsII[i].framesCounter = 0; + } + } + + lightsII[i].frameRec.x = lightsII[i].currentFrame*texLight.width/LIGHT_ANIM_FRAMES; + } + + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + // Light animation + if (lightsIII[i].active) + { + lightsIII[i].framesCounter++; + + if (lightsIII[i].framesCounter > 10) + { + lightsIII[i].currentFrame++; + + if (lightsIII[i].currentFrame > LIGHT_ANIM_FRAMES - 1) lightsIII[i].currentFrame = 1; + + lightsIII[i].framesCounter = 0; + } + } + + lightsIII[i].frameRec.x = lightsIII[i].currentFrame*texLight.width/LIGHT_ANIM_FRAMES; + } + + // Enemies logic + if (!enemiesStopped) + { + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (!enemies[i].active) enemies[i].framesCounter++; + + if (enemies[i].framesCounter > enemies[i].awakeFramesDelay) enemies[i].active = true; + + if (enemies[i].active) + { + // Move to the target + Vector2 dir = Vector2Subtract(enemies[i].targetPos, enemies[i].position); + Vector2Normalize(&dir); + + enemies[i].position.x += dir.x*enemies[i].speed; + enemies[i].position.y += dir.y*enemies[i].speed; + + if (currentLightedLevel == LEVEL_I) + { + if (CheckCollisionCircles(enemies[i].position, enemies[i].radius, enemies[i].targetPos, lightsI[enemies[i].targetNum].radius)) + { + lightsI[enemies[i].targetNum].active = false; + lightsI[enemies[i].targetNum].framesCounter = 0; + lightsI[enemies[i].targetNum].currentFrame = 0; + lightsI[enemies[i].targetNum].frameRec = (Rectangle){ 0, 0, 64, 64 }; + + EnemyReset(&enemies[i]); + + PlaySound(fxLightOff); + } + } + else if (currentLightedLevel == LEVEL_II) + { + if (CheckCollisionCircles(enemies[i].position, enemies[i].radius, enemies[i].targetPos, lightsII[enemies[i].targetNum].radius)) + { + lightsII[enemies[i].targetNum].active = false; + lightsII[enemies[i].targetNum].framesCounter = 0; + lightsII[enemies[i].targetNum].currentFrame = 0; + lightsII[enemies[i].targetNum].frameRec = (Rectangle){ 0, 0, 64, 64 }; + + EnemyReset(&enemies[i]); + + PlaySound(fxLightOff); + } + } + else if (currentLightedLevel == LEVEL_III) + { + if (CheckCollisionCircles(enemies[i].position, enemies[i].radius, enemies[i].targetPos, lightsIII[enemies[i].targetNum].radius)) + { + lightsIII[enemies[i].targetNum].active = false; + lightsIII[enemies[i].targetNum].framesCounter = 0; + lightsIII[enemies[i].targetNum].currentFrame = 0; + lightsIII[enemies[i].targetNum].frameRec = (Rectangle){ 0, 0, 64, 64 }; + + EnemyReset(&enemies[i]); + + PlaySound(fxLightOff); + } + } + } + } + } + + // Check current light energy (for right bar) + currentLightEnergy = 0; + + for (int i = 0; i < MAX_LIGHTS_I; i++) if (lightsI[i].active) currentLightEnergy += lightsI[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_II; i++) if (lightsII[i].active) currentLightEnergy += lightsII[i].requiredEnergy; + for (int i = 0; i < MAX_LIGHTS_III; i++) if (lightsIII[i].active) currentLightEnergy += lightsIII[i].requiredEnergy; + + // Check current lighted level + // Check ending conditions: all lights off, ritual level reached + previousLightedLevel = currentLightedLevel; + + currentLightedLevel = LEVEL_I; + + bool lightedLevel = true; + for (int i = 0; i < MAX_LIGHTS_I; i++) if (!lightsI[i].active) lightedLevel = false; + if (lightedLevel) currentLightedLevel = LEVEL_II; + + for (int i = 0; i < MAX_LIGHTS_II; i++) if (!lightsII[i].active) lightedLevel = false; + if (lightedLevel) currentLightedLevel = LEVEL_III; + + for (int i = 0; i < MAX_LIGHTS_III; i++) if (!lightsIII[i].active) lightedLevel = false; + if (lightedLevel) + { + currentLightedLevel = LEVEL_FINISHED; + + for (int i = 0; i < MAX_ENEMIES; i++) enemies[i].active = false; + } + + if (currentLightedLevel != previousLightedLevel) for (int i = 0; i < MAX_ENEMIES; i++) EnemyReset(&enemies[i]); + + ritualTime = (float)framesCounter/60; + + // Check game over condition (time run out) + if ((99.0f - ritualTime) <= 0.0f) + { + ritualTime = 99.0f; + timeOver = true; + } + } + + if (startRitual) + { + alphaRitual += 0.02f; + + SetMusicVolume(1.0f - alphaRitual); + + if (alphaRitual > 1.0f) finishScreen = 1; + } +} + +// Gameplay Screen Draw logic +void DrawGameplayScreen(void) +{ + DrawTexture(background, 0, 0, WHITE); + + // DrawText("STARS ARE ALIGNED! NO TIME TO LOOSE! LIGHT MY RITUAL!", + + // Draw foreground and circles + if ((currentLightedLevel == LEVEL_FINISHED) || (currentLightedLevel == LEVEL_III)) DrawTexture(foregroundIII, 0, 0, WHITE); + else if (currentLightedLevel == LEVEL_II) DrawTexture(foregroundII, 0, 0, WHITE); + else if (currentLightedLevel == LEVEL_I) DrawTexture(foregroundI, 0, 0, WHITE); + + // Draw lighted circles (depends on current lighted level) + switch (currentLightedLevel) + { + case LEVEL_FINISHED: + { + DrawTexture(circleIIIon, GetScreenWidth()/2 - circleIIIon.width/2, GetScreenHeight()/2 - circleIIIon.height/2, WHITE); + DrawTexture(circleIIon, GetScreenWidth()/2 - circleIIon.width/2, GetScreenHeight()/2 - circleIIon.height/2, WHITE); + DrawTexture(circleIon, GetScreenWidth()/2 - circleIon.width/2, GetScreenHeight()/2 - circleIon.height/2, WHITE); + } break; + case LEVEL_III: + { + DrawTexture(circleIIIoff, GetScreenWidth()/2 - circleIIIoff.width/2, GetScreenHeight()/2 - circleIIIoff.height/2, WHITE); + DrawTexture(circleIIon, GetScreenWidth()/2 - circleIIon.width/2, GetScreenHeight()/2 - circleIIon.height/2, WHITE); + DrawTexture(circleIon, GetScreenWidth()/2 - circleIon.width/2, GetScreenHeight()/2 - circleIon.height/2, WHITE); + } break; + case LEVEL_II: + { + DrawTexture(circleIIoff, GetScreenWidth()/2 - circleIIoff.width/2, GetScreenHeight()/2 - circleIIoff.height/2, WHITE); + DrawTexture(circleIon, GetScreenWidth()/2 - circleIon.width/2, GetScreenHeight()/2 - circleIon.height/2, WHITE); + } break; + case LEVEL_I: + { + DrawTexture(circleIoff, GetScreenWidth()/2 - circleIoff.width/2, GetScreenHeight()/2 - circleIoff.height/2, WHITE); + } break; + default: break; + } + + // Draw lights (depends on current lighted level) + switch (currentLightedLevel) + { + case LEVEL_FINISHED: + case LEVEL_III: + { + for (int i = 0; i < MAX_LIGHTS_III; i++) + { + //if (lightsIII[i].active) DrawCircleV(lightsIII[i].position, lightsIII[i].radius, GOLD); + //else DrawCircleLines(lightsIII[i].position.x, lightsIII[i].position.y, lightsIII[i].radius, GRAY); + + if (lightsIII[i].active) + { + DrawTextureRec(texLight, lightsIII[i].frameRec, (Vector2){ lightsIII[i].position.x - 32, lightsIII[i].position.y - 32 }, WHITE); + DrawTexture(lightGlow, lightsIII[i].position.x - lightGlow.width/2, lightsIII[i].position.y - lightGlow.height/2, Fade(WHITE, 0.3f)); + DrawText(FormatText("%02i", lightsIII[i].requiredEnergy), lightsIII[i].position.x - 10, lightsIII[i].position.y + 14, 20, GRAY); + } + else + { + DrawTextureRec(texLight, lightsIII[i].frameRec, (Vector2){ lightsIII[i].position.x - 32, lightsIII[i].position.y - 32 }, WHITE); + DrawText(FormatText("%02i", lightsIII[i].requiredEnergy), lightsIII[i].position.x - 10, lightsIII[i].position.y + 14, 20, YELLOW); + } + } + } + case LEVEL_II: + { + for (int i = 0; i < MAX_LIGHTS_II; i++) + { + //if (lightsII[i].active) DrawCircleV(lightsII[i].position, lightsII[i].radius, GOLD); + //else DrawCircleLines(lightsI[i].position.x, lightsI[i].position.y, lightsI[i].radius, GRAY); + + if (lightsII[i].active) + { + DrawTextureRec(texLight, lightsII[i].frameRec, (Vector2){ lightsII[i].position.x - 32, lightsII[i].position.y - 32 }, WHITE); + DrawTexture(lightGlow, lightsII[i].position.x - lightGlow.width/2, lightsII[i].position.y - lightGlow.height/2, Fade(WHITE, 0.3f)); + DrawText(FormatText("%02i", lightsII[i].requiredEnergy), lightsII[i].position.x - 10, lightsII[i].position.y + 14, 20, GRAY); + } + else + { + DrawTextureRec(texLight, lightsII[i].frameRec, (Vector2){ lightsII[i].position.x - 32, lightsII[i].position.y - 32 }, WHITE); + DrawText(FormatText("%02i", lightsII[i].requiredEnergy), lightsII[i].position.x - 10, lightsII[i].position.y + 14, 20, YELLOW); + } + } + } + case LEVEL_I: + { + for (int i = 0; i < MAX_LIGHTS_I; i++) + { + //if (lightsI[i].active) DrawCircleV(lightsI[i].position, lightsI[i].radius, GOLD); + //else DrawCircleLines(lightsI[i].position.x, lightsI[i].position.y, lightsI[i].radius, GRAY); + + if (lightsI[i].active) + { + DrawTextureRec(texLight, lightsI[i].frameRec, (Vector2){ lightsI[i].position.x - 32, lightsI[i].position.y - 32 }, WHITE); + DrawTexture(lightGlow, lightsI[i].position.x - lightGlow.width/2, lightsI[i].position.y - lightGlow.height/2, Fade(WHITE, 0.3f)); + DrawText(FormatText("%02i", lightsI[i].requiredEnergy), lightsI[i].position.x - 10, lightsI[i].position.y + 14, 20, GRAY); + } + else + { + DrawTextureRec(texLight, lightsI[i].frameRec, (Vector2){ lightsI[i].position.x - 32, lightsI[i].position.y - 32 }, WHITE); + DrawText(FormatText("%02i", lightsI[i].requiredEnergy), lightsI[i].position.x - 10, lightsI[i].position.y + 14, 20, YELLOW); + } + } + } + default: break; + } + + // Draw main lighter + DrawTexture(book, GetScreenWidth()/2 - book.width/2, GetScreenHeight()/2, WHITE); + DrawTexture(lightRay, GetScreenWidth()/2 - lightRay.width/2, 0, Fade(WHITE, 0.5f)); + + // Draw player + //DrawCircleV(player.position, player.radius, player.color); + DrawTexture(texPlayer, player.position.x - 32, player.position.y - 32, player.color); + + if (currentLightedLevel != LEVEL_FINISHED) + { + // Draw enemies (depends on current lighted level) + for (int i = 0; i < MAX_ENEMIES; i++) + { + if (enemies[i].active) + { + //DrawCircleV(enemies[i].position, enemies[i].radius, enemies[i].color); + DrawTextureRec(texEnemy, (Rectangle){ 0, 0, 64, 64 }, (Vector2){ enemies[i].position.x - 32, enemies[i].position.y - 32 }, WHITE); + } + } + + // Draw time left for ritual + DrawTextEx(font, FormatText("%02.2f", (99.0f - ritualTime)), (Vector2){ 560, 20 }, font.size, 0, WHITE); + + // Draw light energy bar + DrawRectangle(20, 30, 400, 20, GRAY); + DrawRectangle(20, 30, (400*player.lightEnergy)/MAX_PLAYER_ENERGY, 20, GOLD); + DrawRectangleLines(20, 30, 400, 20, LIGHTGRAY); + DrawText(FormatText("%03.0f", player.lightEnergy), 430, 30, 20, WHITE); + + // Draw level lighted bar (for completion) + DrawRectangle(GetScreenWidth() - 40, 30, 20, 660, GRAY); + DrawRectangle(GetScreenWidth() - 40, 30 + 660 - 660*currentLightEnergy/maxLightEnergy, 20, 660*currentLightEnergy/maxLightEnergy, YELLOW); + DrawRectangleLines(GetScreenWidth() - 40, 30, 20, 660, LIGHTGRAY); + + // Show message: "You run out of light!!!" if player.lightEnergy <= 0 + if (player.lightEnergy < 2) + { + if ((framesCounter/20)%2) DrawTextEx(font, "YOU'RE RUNNING OUT OF LIGHT!", (Vector2){ 20, 60 }, font.size/2, 0, WHITE); + } + } + else if (!timeOver) // LEVEL_FINISHED + { + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, 0.4f)); + + // Wait some time before jumping to ending: raylib + DrawTexture(texRitual, GetScreenWidth()/2 - texRitual.width/2, 100, WHITE); + DrawTextEx(font, FormatText("BEST LIGHTING TIME: %02.2f", ritualTime), (Vector2){ 320, 340 }, 50, 0, WHITE); + DrawTextEx(font, "PRESS ENTER to START the RITUAL", (Vector2){ 160, 480 }, 60, 0, WHITE); + + if (IsKeyPressed(KEY_ENTER)) startRitual = true; + } + + if (timeOver) + { + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(BLACK, 0.4f)); + + DrawTexture(texTimeOver, GetScreenWidth()/2 - texTimeOver.width/2, 140, WHITE); + DrawTextEx(font, FormatText("NEXT STARS ALIGNMENT IN %i YEARS", nextStarsAlignment), (Vector2){ 200, 360 }, 50, 0, WHITE); + DrawTextEx(font, "PRESS ENTER to GO HOME...", (Vector2){ 260, 480 }, 60, 0, WHITE); + + if (IsKeyPressed(KEY_ENTER)) finishScreen = 2; + } + + if (startRitual) DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), Fade(RAYWHITE, alphaRitual)); + + if (pause) DrawTextEx(font, "RITUAL PAUSED", (Vector2){ GetScreenWidth()/2 - MeasureText("RITUAL PAUSED", 40)/2, 110 }, 50, 0, WHITE); +} + +// Gameplay Screen Unload logic +void UnloadGameplayScreen(void) +{ + // Unload GAMEPLAY screen variables here! + UnloadTexture(background); + UnloadTexture(foregroundI); + UnloadTexture(foregroundII); + UnloadTexture(foregroundIII); + UnloadTexture(texPlayer); + UnloadTexture(texEnemy); + UnloadTexture(texLight); + UnloadTexture(lightGlow); + UnloadTexture(lightRay); + UnloadTexture(book); + UnloadTexture(texRitual); + UnloadTexture(texTimeOver); + + // Unload circles + UnloadTexture(circleIoff); + UnloadTexture(circleIIoff); + UnloadTexture(circleIIIoff); + UnloadTexture(circleIon); + UnloadTexture(circleIIon); + UnloadTexture(circleIIIon); + + // Unload sounds + UnloadSound(fxLightOn); + UnloadSound(fxLightOff); +} + +// Gameplay Screen should finish? +int FinishGameplayScreen(void) +{ + return finishScreen; +} + +//------------------------------------------------------------------------------------ +// Module Functions Definitions (local) +//------------------------------------------------------------------------------------ + +// Check two colors if equal +static bool ColorEqual(Color col1, Color col2) +{ + return ((col1.r == col2.r) && (col1.g == col2.g) && (col1.b == col2.b) && (col1.a == col2.a)); +} + +// Substract two vectors +static Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) +{ + Vector2 result; + + result.x = v1.x - v2.x; + result.y = v1.y - v2.y; + + return result; +} + +// Normalize provided vector +static void Vector2Normalize(Vector2 *v) +{ + float length, ilength; + + length = sqrt(v->x*v->x + v->y*v->y); + + if (length == 0) length = 1.0f; + + ilength = 1.0f/length; + + v->x *= ilength; + v->y *= ilength; +} + +// Reset enemy parameters +// NOTE: Depends on currentLightedLevel +static void EnemyReset(Enemy *enemy) +{ + enemy->active = false; + enemy->framesCounter = 0; + enemy->color = RED; + enemy->radius = 10; + + int side = GetRandomValue(0, 1); + + if (side) enemy->position = (Vector2){ GetRandomValue(50, 150), GetRandomValue(50, GetScreenHeight() - 50) }; + else enemy->position = (Vector2){ GetRandomValue(GetScreenWidth() - 150, GetScreenWidth() - 50), GetRandomValue(50, GetScreenHeight() - 50) }; + + // TODO: Choose only active lights + // TODO: if currentLightedLevel has no active lights, choose light from a lower level! + + if (currentLightedLevel == LEVEL_I) + { + enemy->targetNum = GetRandomValue(0, MAX_LIGHTS_I - 1); // LEVEL_I + enemy->targetPos = lightsI[enemy->targetNum].position; + enemy->speed = (float)GetRandomValue(15, 20)/10.0f; + enemy->awakeFramesDelay = GetRandomValue(90, 400); + } + else if (currentLightedLevel == LEVEL_II) + { + enemy->targetNum = GetRandomValue(0, MAX_LIGHTS_II - 1); // LEVEL_II + enemy->targetPos = lightsII[enemy->targetNum].position; + enemy->speed = (float)GetRandomValue(10, 20)/10.0f; + enemy->awakeFramesDelay = GetRandomValue(240, 800); + } + else if (currentLightedLevel == LEVEL_III) + { + enemy->targetNum = GetRandomValue(0, MAX_LIGHTS_III - 1); // LEVEL_III + enemy->targetPos = lightsIII[enemy->targetNum].position; + enemy->speed = (float)GetRandomValue(8, 18)/10.0f; + enemy->awakeFramesDelay = GetRandomValue(180, 1200); + } +} \ No newline at end of file diff --git a/games/light_my_ritual/screens/screen_logo_raylib.c b/games/light_my_ritual/screens/screen_logo_raylib.c new file mode 100644 index 000000000..40157b105 --- /dev/null +++ b/games/light_my_ritual/screens/screen_logo_raylib.c @@ -0,0 +1,214 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Logo Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* 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" + +#define LOGO_RECS_SIDE 16 + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Logo screen global variables +static int framesCounter; +static int finishScreen; + +static int logoPositionX; +static int logoPositionY; + +static int lettersCount; + +static int topSideRecWidth; +static int leftSideRecHeight; + +static int bottomSideRecWidth; +static int rightSideRecHeight; + +static char raylib[8]; // raylib text array, max 8 letters +static int state; // Tracking animation states (State Machine) +static float alpha = 1.0f; // Useful for fading + +//---------------------------------------------------------------------------------- +// Logo Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Logo Screen Initialization logic +void rlInitLogoScreen(void) +{ + // Initialize LOGO screen variables here! + finishScreen = 0; + framesCounter = 0; + lettersCount = 0; + + logoPositionX = GetScreenWidth()/2 - 128; + logoPositionY = GetScreenHeight()/2 - 128; + + topSideRecWidth = LOGO_RECS_SIDE; + leftSideRecHeight = LOGO_RECS_SIDE; + bottomSideRecWidth = LOGO_RECS_SIDE; + rightSideRecHeight = LOGO_RECS_SIDE; + + for (int i = 0; i < 8; i++) raylib[i] = '\0'; + + state = 0; + alpha = 1.0f; + + PlayMusicStream("resources/audio/ambient.ogg"); + SetMusicVolume(1.0f); +} + +// Logo Screen Update logic +void rlUpdateLogoScreen(void) +{ + // Update LOGO screen variables here! + if (state == 0) // State 0: Small box blinking + { + framesCounter++; + + if (framesCounter == 80) + { + state = 1; + framesCounter = 0; // Reset counter... will be used later... + } + } + else if (state == 1) // State 1: Top and left bars growing + { + topSideRecWidth += 8; + leftSideRecHeight += 8; + + if (topSideRecWidth == 256) state = 2; + } + else if (state == 2) // State 2: Bottom and right bars growing + { + bottomSideRecWidth += 8; + rightSideRecHeight += 8; + + if (bottomSideRecWidth == 256) state = 3; + } + else if (state == 3) // State 3: Letters appearing (one by one) + { + framesCounter++; + + if (framesCounter/10) // Every 12 frames, one more letter! + { + lettersCount++; + framesCounter = 0; + } + + switch (lettersCount) + { + case 1: raylib[0] = 'r'; break; + case 2: raylib[1] = 'a'; break; + case 3: raylib[2] = 'y'; break; + case 4: raylib[3] = 'l'; break; + case 5: raylib[4] = 'i'; break; + case 6: raylib[5] = 'b'; break; + default: break; + } + + // When all letters have appeared... + if (lettersCount >= 10) + { + state = 4; + framesCounter = 0; + } + } + else if (state == 4) + { + framesCounter++; + + if (framesCounter > 100) + { + alpha -= 0.02f; + + if (alpha <= 0.0f) + { + alpha = 0.0f; + finishScreen = 1; + } + } + } +} + +// Logo Screen Draw logic +void rlDrawLogoScreen(void) +{ + if (state == 0) + { + if ((framesCounter/10)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK); + } + else if (state == 1) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); + DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); + } + else if (state == 2) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); + DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); + + DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK); + } + else if (state == 3) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); + + DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); + + DrawRectangle(GetScreenWidth()/2 - 112, GetScreenHeight()/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); + + DrawText(raylib, GetScreenWidth()/2 - 44, GetScreenHeight()/2 + 48, 50, Fade(BLACK, alpha)); + } + else if (state == 4) + { + DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); + + DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); + DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); + + DrawRectangle(GetScreenWidth()/2 - 112, GetScreenHeight()/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); + + DrawText(raylib, GetScreenWidth()/2 - 44, GetScreenHeight()/2 + 48, 50, Fade(BLACK, alpha)); + + if (framesCounter > 20) DrawText("powered by", logoPositionX, logoPositionY - 27, 20, Fade(DARKGRAY, alpha)); + } +} + +// Logo Screen Unload logic +void rlUnloadLogoScreen(void) +{ + // TODO: Unload LOGO screen variables here! +} + +// Logo Screen should finish? +int rlFinishLogoScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/light_my_ritual/screens/screen_title.c b/games/light_my_ritual/screens/screen_title.c new file mode 100644 index 000000000..c1ecaf122 --- /dev/null +++ b/games/light_my_ritual/screens/screen_title.c @@ -0,0 +1,105 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Title Screen Functions Definitions (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* 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" + +//---------------------------------------------------------------------------------- +// Global Variables Definition (local to this module) +//---------------------------------------------------------------------------------- + +// Title screen global variables +static int framesCounter; +static int finishScreen; + +static Texture2D background; +static Texture2D title; +static float titleAlpha = 0.0f; + +static Sound fxStart; + +//---------------------------------------------------------------------------------- +// Title Screen Functions Definition +//---------------------------------------------------------------------------------- + +// Title Screen Initialization logic +void InitTitleScreen(void) +{ + // Initialize TITLE screen variables here! + framesCounter = 0; + finishScreen = 0; + + background = LoadTexture("resources/textures/back_title.png"); + title = LoadTexture("resources/textures/title.png"); + + fxStart = LoadSound("resources/audio/start.wav"); +} + +// Title Screen Update logic +void UpdateTitleScreen(void) +{ + // Update TITLE screen variables here! + framesCounter++; + + titleAlpha += 0.005f; + + if (titleAlpha >= 1.0f) titleAlpha = 1.0f; + + // Press enter to change to ATTIC screen + if ((IsKeyPressed(KEY_ENTER)) || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + PlaySound(fxStart); + finishScreen = 1; + } +} + +// Title Screen Draw logic +void DrawTitleScreen(void) +{ + DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), (Color){ 26, 26, 26, 255 }); + + DrawTexture(background, GetScreenWidth()/2 - background.width/2, 0, WHITE); + DrawTexture(title, GetScreenWidth()/2 - title.width/2, 30, Fade(WHITE, titleAlpha)); + + DrawText("(c) Developed by Ramon Santamaria (@raysan5)", 20, GetScreenHeight() - 40, 20, LIGHTGRAY); + + if ((framesCounter > 180) && ((framesCounter/40)%2)) DrawTextEx(font, "PRESS ENTER to START LIGHTING", (Vector2){ 230, 450 }, font.size, -2, WHITE); +} + +// Title Screen Unload logic +void UnloadTitleScreen(void) +{ + // Unload TITLE screen variables here! + UnloadTexture(background); + UnloadTexture(title); + + UnloadSound(fxStart); +} + +// Title Screen should finish? +int FinishTitleScreen(void) +{ + return finishScreen; +} \ No newline at end of file diff --git a/games/light_my_ritual/screens/screens.h b/games/light_my_ritual/screens/screens.h new file mode 100644 index 000000000..8fee52744 --- /dev/null +++ b/games/light_my_ritual/screens/screens.h @@ -0,0 +1,78 @@ +/********************************************************************************************** +* +* raylib - Advance Game template +* +* Screens Functions Declarations (Init, Update, Draw, Unload) +* +* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* 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. +* +**********************************************************************************************/ + +#ifndef SCREENS_H +#define SCREENS_H + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum GameScreen { LOGO_RL = 0, TITLE, GAMEPLAY } GameScreen; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +GameScreen currentScreen; +SpriteFont font; + +Color *lightsMap; +int lightsMapWidth, lightsMapHeight; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// raylib Logo Screen Functions Declaration +//---------------------------------------------------------------------------------- +void rlInitLogoScreen(void); +void rlUpdateLogoScreen(void); +void rlDrawLogoScreen(void); +void rlUnloadLogoScreen(void); +int rlFinishLogoScreen(void); + +//---------------------------------------------------------------------------------- +// Title Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitTitleScreen(void); +void UpdateTitleScreen(void); +void DrawTitleScreen(void); +void UnloadTitleScreen(void); +int FinishTitleScreen(void); + +//---------------------------------------------------------------------------------- +// Gameplay Screen Functions Declaration +//---------------------------------------------------------------------------------- +void InitGameplayScreen(void); +void UpdateGameplayScreen(void); +void DrawGameplayScreen(void); +void UnloadGameplayScreen(void); +int FinishGameplayScreen(void); + +#ifdef __cplusplus +} +#endif + +#endif // SCREENS_H \ No newline at end of file