From 46827594b4b2fe60e62c6af273230527dac4815d Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak Date: Mon, 27 Jun 2016 21:20:02 +0200 Subject: [PATCH] import Radio Edit codebase --- cmake/SetPaths.cmake | 4 +- src/CMakeLists.txt | 36 +- src/gamestate.h | 48 +- src/gamestates/CMakeLists.txt | 13 +- src/gamestates/dosowisko.c | 14 +- src/gamestates/dosowisko.h | 2 +- src/gamestates/loading.c | 11 +- src/gamestates/loading.h | 3 +- src/gamestates/menu.c | 1103 +++++++++++++++++++++++---------- src/gamestates/menu.h | 93 ++- src/main.c | 167 ++--- src/main.h | 2 + src/timeline.c | 22 +- src/timeline.h | 10 +- src/utils.c | 427 ++++++++++--- src/utils.h | 81 ++- 16 files changed, 1368 insertions(+), 668 deletions(-) diff --git a/cmake/SetPaths.cmake b/cmake/SetPaths.cmake index 098c3b3..b0c948b 100644 --- a/cmake/SetPaths.cmake +++ b/cmake/SetPaths.cmake @@ -69,9 +69,9 @@ if (WIN32) # use relative install prefix to avoid hardcoded install paths in cmake_install.cmake files - set(LIB_INSTALL_DIR "lib${LIB_SUFFIX}" ) # The subdirectory relative to the install prefix where libraries will be installed (default is ${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}) + set(LIB_INSTALL_DIR "bin" ) # The subdirectory relative to the install prefix where libraries will be installed (default is ${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}) - set(EXEC_INSTALL_PREFIX "" ) # Base directory for executables and libraries + set(EXEC_INSTALL_PREFIX "${EXEC_INSTALL_PREFIX}" ) # Base directory for executables and libraries set(SHARE_INSTALL_PREFIX "share" ) # Base directory for files which go to share/ set(BIN_INSTALL_DIR "bin" ) # The install dir for executables (default ${EXEC_INSTALL_PREFIX}/bin) set(SBIN_INSTALL_DIR "sbin" ) # The install dir for system executables (default ${EXEC_INSTALL_PREFIX}/sbin) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6a3e6cd..944f21e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,10 @@ SET(SRC_LIST gamestate.c ) +SET(EXECUTABLE_SRC_LIST + main.c +) + find_package(Allegro5 REQUIRED) find_package(Allegro5Font REQUIRED) find_package(Allegro5TTF REQUIRED) @@ -17,42 +21,36 @@ if(APPLE) endif(APPLE) if(MINGW) - # resource compilation for MinGW - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icon.o COMMAND ${CMAKE_RC_COMPILER} -I${CMAKE_SOURCE_DIR} -i${CMAKE_SOURCE_DIR}/data/icons/icon.rc -o ${CMAKE_CURRENT_BINARY_DIR}/icon.o ) - set(SRC_LIST ${SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/icon.o) - set(LINK_FLAGS -Wl,-subsystem,windows) + # resource compilation for MinGW + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icon.o COMMAND ${CMAKE_RC_COMPILER} -I${CMAKE_SOURCE_DIR} -i${CMAKE_SOURCE_DIR}/data/icons/icon.rc -o ${CMAKE_CURRENT_BINARY_DIR}/icon.o ) + set(EXECUTABLE_SRC_LIST ${EXECUTABLE_SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/icon.o) + set(LINK_FLAGS -Wl,-subsystem,windows) endif(MINGW) -SET(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib/superderpy:\$ORIGIN/gamestates:\$ORIGIN/levels:\$ORIGIN:\$ORIGIN/../lib") - -#IF(${PACKAGE_BUILD}) -# SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -# SET(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib/superderpy:\$ORIGIN") -#ENDIF(${PACKAGE_BUILD}) +SET(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib/radioedit:\$ORIGIN/gamestates:\$ORIGIN:\$ORIGIN/../lib:\$ORIGIN/lib:\$ORIGIN/bin") if(APPLE) - set(EXECUTABLE "SuperDerpy") + set(EXECUTABLE "RadioEdit") else(APPLE) - set(EXECUTABLE "superderpy") + set(EXECUTABLE "radioedit") endif(APPLE) -add_library("libsuperderpy" SHARED ${SRC_LIST}) -add_executable(${EXECUTABLE} WIN32 MACOSX_BUNDLE "main.c") +add_library("libsuperderpy-radioedit" SHARED ${SRC_LIST}) +add_executable(${EXECUTABLE} WIN32 MACOSX_BUNDLE ${EXECUTABLE_SRC_LIST}) -SET_TARGET_PROPERTIES("libsuperderpy" PROPERTIES PREFIX "") +SET_TARGET_PROPERTIES("libsuperderpy-radioedit" PROPERTIES PREFIX "") include_directories(${ALLEGRO5_INCLUDE_DIR} ${ALLEGRO5_FONT_INCLUDE_DIR} ${ALLEGRO5_TTF_INCLUDE_DIR} ${ALLEGRO5_PRIMITIVES_INCLUDE_DIR} ${ALLEGRO5_AUDIO_INCLUDE_DIR} ${ALLEGRO5_ACODEC_INCLUDE_DIR} ${ALLEGRO5_IMAGE_INCLUDE_DIR}) -target_link_libraries(${EXECUTABLE} ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m dl libsuperderpy) +target_link_libraries(${EXECUTABLE} ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m dl libsuperderpy-radioedit) -target_link_libraries("libsuperderpy" ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m) +target_link_libraries("libsuperderpy-radioedit" ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} ${ALLEGRO5_MAIN_LIBRARIES} m) if(ALLEGRO5_MAIN_FOUND) target_link_libraries(${EXECUTABLE} ${ALLEGRO5_MAIN_LIBRARIES}) endif(ALLEGRO5_MAIN_FOUND) add_subdirectory(gamestates) -add_subdirectory(levels) install(TARGETS ${EXECUTABLE} DESTINATION ${BIN_INSTALL_DIR}) -install(TARGETS "libsuperderpy" DESTINATION ${LIB_INSTALL_DIR}) +install(TARGETS "libsuperderpy-radioedit" DESTINATION ${LIB_INSTALL_DIR}) diff --git a/src/gamestate.h b/src/gamestate.h index bb7e376..1b81a77 100644 --- a/src/gamestate.h +++ b/src/gamestate.h @@ -26,33 +26,33 @@ struct Game; struct Gamestate { - char* name; - void* handle; - bool loaded, pending_load; - bool started, pending_start; - bool showLoading; - bool paused; - bool fade; // TODO: or maybe should it be in API? - unsigned char fade_counter; - char** after; // TODO: and this one too? - struct Gamestate* next; - void* data; - struct { - void (*Gamestate_Draw)(struct Game *game, void* data); - void (*Gamestate_Logic)(struct Game *game, void* data); + char* name; + void* handle; + bool loaded, pending_load; + bool started, pending_start; + bool showLoading; + bool paused; + bool fade; // TODO: or maybe should it be in API? + unsigned char fade_counter; + char** after; // TODO: and this one too? + struct Gamestate* next; + void* data; + struct { + void (*Gamestate_Draw)(struct Game *game, void* data); + void (*Gamestate_Logic)(struct Game *game, void* data); - void* (*Gamestate_Load)(struct Game *game, void (*progress)(struct Game *game)); - void (*Gamestate_Start)(struct Game *game, void* data); - void (*Gamestate_Pause)(struct Game *game, void* data); - void (*Gamestate_Resume)(struct Game *game, void* data); - void (*Gamestate_Stop)(struct Game *game, void* data); - void (*Gamestate_Unload)(struct Game *game, void* data); + void* (*Gamestate_Load)(struct Game *game, void (*progress)(struct Game *game)); + void (*Gamestate_Start)(struct Game *game, void* data); + void (*Gamestate_Pause)(struct Game *game, void* data); + void (*Gamestate_Resume)(struct Game *game, void* data); + void (*Gamestate_Stop)(struct Game *game, void* data); + void (*Gamestate_Unload)(struct Game *game, void* data); - void (*Gamestate_ProcessEvent)(struct Game *game, void* data, ALLEGRO_EVENT *ev); - void (*Gamestate_Reload)(struct Game *game, void* data); + void (*Gamestate_ProcessEvent)(struct Game *game, void* data, ALLEGRO_EVENT *ev); + void (*Gamestate_Reload)(struct Game *game, void* data); - int *Gamestate_ProgressCount; - } api; + int *Gamestate_ProgressCount; + } api; }; void LoadGamestate(struct Game *game, const char* name); diff --git a/src/gamestates/CMakeLists.txt b/src/gamestates/CMakeLists.txt index 3a56819..a499123 100644 --- a/src/gamestates/CMakeLists.txt +++ b/src/gamestates/CMakeLists.txt @@ -1,21 +1,16 @@ MACRO(GAMESTATE name) - add_library("libsuperderpy-muffinattack-${name}" SHARED "${name}.c") + add_library("libsuperderpy-radioedit-${name}" SHARED "${name}.c") - SET_TARGET_PROPERTIES("libsuperderpy-muffinattack-${name}" PROPERTIES PREFIX "") + SET_TARGET_PROPERTIES("libsuperderpy-radioedit-${name}" PROPERTIES PREFIX "") - target_link_libraries("libsuperderpy-muffinattack-${name}" ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} m libsuperderpy) + target_link_libraries("libsuperderpy-radioedit-${name}" ${ALLEGRO5_LIBRARIES} ${ALLEGRO5_FONT_LIBRARIES} ${ALLEGRO5_TTF_LIBRARIES} ${ALLEGRO5_PRIMITIVES_LIBRARIES} ${ALLEGRO5_AUDIO_LIBRARIES} ${ALLEGRO5_ACODEC_LIBRARIES} ${ALLEGRO5_IMAGE_LIBRARIES} m libsuperderpy-radioedit) - install(TARGETS "libsuperderpy-muffinattack-${name}" DESTINATION ${LIB_INSTALL_DIR}) + install(TARGETS "libsuperderpy-radioedit-${name}" DESTINATION ${LIB_INSTALL_DIR}) ENDMACRO() GAMESTATE("dosowisko") GAMESTATE("menu") -GAMESTATE("disclaimer") -GAMESTATE("intro") -GAMESTATE("map") -GAMESTATE("about") -#GAMESTATE("pause") GAMESTATE("loading") diff --git a/src/gamestates/dosowisko.c b/src/gamestates/dosowisko.c index 833f9dc..43c4555 100644 --- a/src/gamestates/dosowisko.c +++ b/src/gamestates/dosowisko.c @@ -106,18 +106,22 @@ void Gamestate_Draw(struct Game *game, struct dosowiskoResources* data) { al_clear_to_color(al_map_rgba(0,0,0,0)); al_draw_text(data->font, al_map_rgba(255,255,255,10), game->viewport.width/2, game->viewport.height*0.4167, ALLEGRO_ALIGN_CENTRE, t); - al_set_target_backbuffer(game->display); - - al_clear_to_color(al_map_rgb(35, 31, 32)); double tg = tan(-data->tan/384.0 * ALLEGRO_PI - ALLEGRO_PI/2); int fade = data->fadeout ? 255 : data->fade; + al_set_target_bitmap(data->pixelator); + al_clear_to_color(al_map_rgb(35, 31, 32)); + al_draw_tinted_scaled_bitmap(data->bitmap, al_map_rgba(fade, fade, fade, fade), 0, 0, al_get_bitmap_width(data->bitmap), al_get_bitmap_height(data->bitmap), -tg*al_get_bitmap_width(data->bitmap)*0.05, -tg*al_get_bitmap_height(data->bitmap)*0.05, al_get_bitmap_width(data->bitmap)+tg*0.1*al_get_bitmap_width(data->bitmap), al_get_bitmap_height(data->bitmap)+tg*0.1*al_get_bitmap_height(data->bitmap), 0); al_draw_bitmap(data->checkerboard, 0, 0, 0); + al_set_target_backbuffer(game->display); + + al_draw_bitmap(data->pixelator, 0, 0, 0); + } } @@ -155,13 +159,14 @@ void* Gamestate_Load(struct Game *game, void (*progress)(struct Game*)) { data->timeline = TM_Init(game, "main"); data->bitmap = al_create_bitmap(game->viewport.width, game->viewport.height); data->checkerboard = al_create_bitmap(game->viewport.width, game->viewport.height); + data->pixelator = al_create_bitmap(game->viewport.width, game->viewport.height); al_set_target_bitmap(data->checkerboard); al_lock_bitmap(data->checkerboard, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); int x, y; for (x = 0; x < al_get_bitmap_width(data->checkerboard); x=x+2) { for (y = 0; y < al_get_bitmap_height(data->checkerboard); y=y+2) { - al_put_pixel(x, y, al_map_rgb(0,0,0)); + al_put_pixel(x, y, al_map_rgba(0,0,0,64)); al_put_pixel(x+1, y, al_map_rgba(0,0,0,0)); al_put_pixel(x, y+1, al_map_rgba(0,0,0,0)); al_put_pixel(x+1, y+1, al_map_rgba(0,0,0,0)); @@ -211,6 +216,7 @@ void Gamestate_Unload(struct Game *game, struct dosowiskoResources* data) { al_destroy_sample(data->key_sample); al_destroy_bitmap(data->bitmap); al_destroy_bitmap(data->checkerboard); + al_destroy_bitmap(data->pixelator); TM_Destroy(data->timeline); free(data); } diff --git a/src/gamestates/dosowisko.h b/src/gamestates/dosowisko.h index 9dac3bf..c273404 100644 --- a/src/gamestates/dosowisko.h +++ b/src/gamestates/dosowisko.h @@ -23,7 +23,7 @@ struct dosowiskoResources { ALLEGRO_FONT *font; ALLEGRO_SAMPLE *sample, *kbd_sample, *key_sample; ALLEGRO_SAMPLE_INSTANCE *sound, *kbd, *key; - ALLEGRO_BITMAP *bitmap, *checkerboard; + ALLEGRO_BITMAP *bitmap, *checkerboard, *pixelator; int pos, fade, tick, tan; char text[255]; bool underscore, fadeout; diff --git a/src/gamestates/loading.c b/src/gamestates/loading.c index e81249c..f35e6f0 100644 --- a/src/gamestates/loading.c +++ b/src/gamestates/loading.c @@ -25,7 +25,7 @@ void Progress(struct Game *game, struct LoadingResources *data, float p) { al_set_target_bitmap(al_get_backbuffer(game->display)); al_draw_bitmap(data->loading_bitmap,0,0,0); - al_draw_filled_rectangle(0, game->viewport.height*0.985, p*game->viewport.width, game->viewport.height, al_map_rgba(255,255,255,255)); + al_draw_filled_rectangle(0, game->viewport.height-1, p*game->viewport.width, game->viewport.height, al_map_rgba(128,128,128,128)); } void Draw(struct Game *game, struct LoadingResources *data, float p) { @@ -39,15 +39,10 @@ void* Load(struct Game *game) { data->loading_bitmap = al_create_bitmap(game->viewport.width, game->viewport.height); - data->image = LoadScaledBitmap(game, "loading.png", game->viewport.height*2, game->viewport.height); - al_set_target_bitmap(data->loading_bitmap); - al_clear_to_color(al_map_rgb(193,225,218)); - al_draw_bitmap(data->image, game->viewport.width-al_get_bitmap_width(data->image), 0, 0); - DrawTextWithShadow(game->_priv.font, al_map_rgb(255,255,255), game->viewport.width*0.0234, game->viewport.height*0.84, ALLEGRO_ALIGN_LEFT, "Loading..."); - al_draw_filled_rectangle(0, game->viewport.height*0.985, game->viewport.width, game->viewport.height, al_map_rgba(128,128,128,128)); + al_clear_to_color(al_map_rgb(0,0,0)); + al_draw_filled_rectangle(0, game->viewport.height-1, game->viewport.width, game->viewport.height, al_map_rgba(32,32,32,32)); al_set_target_bitmap(al_get_backbuffer(game->display)); - al_destroy_bitmap(data->image); return data; } diff --git a/src/gamestates/loading.h b/src/gamestates/loading.h index ea0f517..0abcdd5 100644 --- a/src/gamestates/loading.h +++ b/src/gamestates/loading.h @@ -25,6 +25,5 @@ /*! \brief Resources used by Loading state. */ struct LoadingResources { - ALLEGRO_BITMAP *loading_bitmap; /*!< Rendered loading bitmap. */ - ALLEGRO_BITMAP *image; /*!< Loading background. */ + ALLEGRO_BITMAP *loading_bitmap; /*!< Rendered loading bitmap. */ }; diff --git a/src/gamestates/menu.c b/src/gamestates/menu.c index cae32cc..7267070 100644 --- a/src/gamestates/menu.c +++ b/src/gamestates/menu.c @@ -21,52 +21,79 @@ #include #include #include +#include #include "../config.h" #include "../utils.h" +#include "../timeline.h" #include "menu.h" -int Gamestate_ProgressCount = 24; +#define SOLO_MIN 20 + +int Gamestate_ProgressCount = 5; + +void About(struct Game *game, struct MenuResources* data) { + ALLEGRO_TRANSFORM trans; + al_identity_transform(&trans); + al_use_transform(&trans); + + if (!game->_priv.font_bsod) { + game->_priv.font_bsod = al_create_builtin_font(); + } + + al_set_target_backbuffer(game->display); + al_clear_to_color(al_map_rgb(0,0,170)); + + char *header = "RADIO EDIT"; + + al_draw_filled_rectangle(al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header)/2 - 4, (int)(al_get_display_height(game->display) * 0.32), 4 + al_get_display_width(game->display)/2 + al_get_text_width(game->_priv.font_bsod, header)/2, (int)(al_get_display_height(game->display) * 0.32) + al_get_font_line_height(game->_priv.font_bsod), al_map_rgb(170,170,170)); + + al_draw_text(game->_priv.font_bsod, al_map_rgb(0, 0, 170), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32), ALLEGRO_ALIGN_CENTRE, header); + + char *header2 = "A fatal exception 0xD3RP has occured at 0028:M00F11NZ in GST SD(01) +"; + + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+2*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, header2); + al_draw_textf(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+3*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "%p and system just doesn't know what went wrong.", (void*)game); + + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+5*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "About screen not implemented!"); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+6*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "See http://dosowisko.net/radioedit/"); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+7*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "Made for Ludum Dare 32"); + + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+9*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Press any key to terminate this error."); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+10*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Press any key to destroy all muffins in the world."); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+11*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Just kidding, please press any key anyway."); + + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+13*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "Press any key to continue _"); + + al_use_transform(&game->projection); +} void DrawMenuState(struct Game *game, struct MenuResources *data) { - ALLEGRO_FONT *font; + ALLEGRO_FONT *font = data->font; char* text = malloc(255*sizeof(char)); struct ALLEGRO_COLOR color; switch (data->menustate) { case MENUSTATE_MAIN: - font = data->font; if (data->selected==0) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Start game"); - font = data->font; if (data->selected==1) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "Options"); - font = data->font; if (data->selected==2) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.7, ALLEGRO_ALIGN_CENTRE, "About"); - font = data->font; if (data->selected==3) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Exit"); + DrawTextWithShadow(font, data->selected==0 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Start game"); + DrawTextWithShadow(font, data->selected==1 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "Options"); + DrawTextWithShadow(font, data->selected==2 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.7, ALLEGRO_ALIGN_CENTRE, "About"); + DrawTextWithShadow(font, data->selected==3 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Exit"); break; case MENUSTATE_OPTIONS: - font = data->font; if (data->selected==0) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Control settings"); - font = data->font; if (data->selected==1) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "Video settings"); - font = data->font; if (data->selected==2) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.7, ALLEGRO_ALIGN_CENTRE, "Audio settings"); - font = data->font; if (data->selected==3) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Back"); + DrawTextWithShadow(font, data->selected==0 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Video settings"); + DrawTextWithShadow(font, data->selected==1 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "Audio settings"); + DrawTextWithShadow(font, data->selected==3 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Back"); break; case MENUSTATE_AUDIO: - font = data->font; if (data->selected==0) font = data->font_selected; if (game->config.music) snprintf(text, 255, "Music volume: %d0%%", game->config.music); else sprintf(text, "Music disabled"); - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, text); - font = data->font; if (data->selected==1) font = data->font_selected; + DrawTextWithShadow(font, data->selected==0 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, text); if (game->config.fx) snprintf(text, 255, "Effects volume: %d0%%", game->config.fx); else sprintf(text, "Effects disabled"); - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, text); - font = data->font; if (data->selected==2) font = data->font_selected; - if (game->config.voice) snprintf(text, 255, "Voice volume: %d0%%", game->config.voice); - else sprintf(text, "Voice disabled"); - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.7, ALLEGRO_ALIGN_CENTRE, text); - font = data->font; if (data->selected==3) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Back"); + DrawTextWithShadow(font, data->selected==1 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, text); + DrawTextWithShadow(font, data->selected==3 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Back"); + break; + case MENUSTATE_ABOUT: + About(game, data); break; case MENUSTATE_VIDEO: if (data->options.fullscreen) { @@ -75,232 +102,76 @@ void DrawMenuState(struct Game *game, struct MenuResources *data) { } else { sprintf(text, "Fullscreen: no"); - color = al_map_rgba(255,255,255,255); + color = data->selected==1 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255); } - font = data->font; if (data->selected==0) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, text); - font = data->font; if (data->selected==1) font = data->font_selected; - DrawTextWithShadow(font, color, game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "Resolution: 800x500"); - font = data->font; if (data->selected==2) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.7, ALLEGRO_ALIGN_CENTRE, "FPS: 60"); - font = data->font; if (data->selected==3) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Back"); + DrawTextWithShadow(font, data->selected==0 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, text); + sprintf(text, "Resolution: %dx", data->options.resolution); + DrawTextWithShadow(font, color, game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, text); + DrawTextWithShadow(font, data->selected==3 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Back"); break; - case MENUSTATE_PAUSE: - font = data->font; if (data->selected==0) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Resume game"); - font = data->font; if (data->selected==1) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "Return to map"); - font = data->font; if (data->selected==2) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.7, ALLEGRO_ALIGN_CENTRE, "Options"); - font = data->font; if (data->selected==3) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Exit"); + case MENUSTATE_HIDDEN: + break; + case MENUSTATE_LOST: + DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "You lost!"); + sprintf(text, "Score: %d", data->score); + DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, text); + DrawTextWithShadow(font, al_map_rgb(255,255,128), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Back to menu"); + break; + case MENUSTATE_INTRO: + DrawTextWithShadow(font, al_map_rgba(0,0,0,64), 46, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Evi"); + DrawTextWithShadow(font, al_map_rgba(0,0,0,64), 51, game->viewport.height*0.5-1, ALLEGRO_ALIGN_CENTRE, "vi"); + DrawTextWithShadow(font, al_map_rgb(255,255,128), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Evil record label representatives want"); + DrawTextWithShadow(font, al_map_rgba(0,0,0,64), 47, game->viewport.height*0.55, ALLEGRO_ALIGN_CENTRE, "tu"); + DrawTextWithShadow(font, al_map_rgba(0,0,0,64), 48, game->viewport.height*0.55 - 1, ALLEGRO_ALIGN_CENTRE, "tu"); + DrawTextWithShadow(font, al_map_rgb(255,255,128), game->viewport.width*0.5, game->viewport.height*0.55, ALLEGRO_ALIGN_CENTRE, "to turn your awesome single into radio edit."); + DrawTextWithShadow(font, al_map_rgb(255,255,128), game->viewport.width*0.5, game->viewport.height*0.6, ALLEGRO_ALIGN_CENTRE, "Thankfully, with your facemelting guitar"); + DrawTextWithShadow(font, al_map_rgb(255,255,128), game->viewport.width*0.5, game->viewport.height*0.65, ALLEGRO_ALIGN_CENTRE, "skills you don't have to give up so easily!"); + DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.8, ALLEGRO_ALIGN_CENTRE, "Press ENTER to continue..."); break; default: data->selected=0; - font = data->font; if (data->selected==0) font = data->font_selected; - DrawTextWithShadow(font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Not implemented yet"); + DrawTextWithShadow(font, data->selected==0 ? al_map_rgb(255,255,128) : al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.5, ALLEGRO_ALIGN_CENTRE, "Not implemented yet"); break; } free(text); } -void Gamestate_Draw(struct Game *game, struct MenuResources* data) { +void AnimateBadguys(struct Game *game, struct MenuResources *data, int i) { + struct Badguy *tmp = data->badguys[i]; + while (tmp) { + AnimateCharacter(game, tmp->character, tmp->melting ? 1 : tmp->speed * data->badguySpeed); + tmp=tmp->next; + } +} - al_set_target_bitmap(data->pinkcloud_bitmap); - al_clear_to_color(al_map_rgba(0,0,0,0)); - float x = 1.5; - int minus; - if (data->cloud_position>0) minus=1; else minus=-1; - al_draw_bitmap(data->rain_bitmap, fmod(minus*data->cloud_position,3)*x*5+al_get_bitmap_width(data->pinkcloud_bitmap)/2.7, al_get_bitmap_height(data->pinkcloud_bitmap)*(0.88+(fmod(-1.8*(data->cloud_position+80), 6))/20.0), 0); - al_draw_bitmap(data->rain_bitmap, fmod(minus*data->cloud_position,3)*x*3+al_get_bitmap_width(data->pinkcloud_bitmap)/3.1, al_get_bitmap_height(data->pinkcloud_bitmap)*(0.78+(fmod(-2.8*(data->cloud_position+80), 4))/18.0), 0); - al_draw_scaled_bitmap(data->rain_bitmap, 0, 0, al_get_bitmap_width(data->rain_bitmap), al_get_bitmap_height(data->rain_bitmap), fmod(minus*data->cloud_position,3)*x*6+al_get_bitmap_width(data->pinkcloud_bitmap)/2.1, al_get_bitmap_height(data->pinkcloud_bitmap)*(0.87+(fmod(-4.9*(data->cloud_position+80), 8))/26.0), al_get_bitmap_width(data->pinkcloud_bitmap)*0.4, al_get_bitmap_height(data->pinkcloud_bitmap)*0.08, 0); - al_draw_bitmap(data->pinkcloud, 0, 0, 0); - al_set_target_bitmap(al_get_backbuffer(game->display)); +void MoveBadguys(struct Game *game, struct MenuResources *data, int i, float dx) { + struct Badguy *tmp = data->badguys[i]; + while (tmp) { - al_clear_to_color(al_map_rgb(183,234,193)); - al_draw_tinted_bitmap(data->mountain,al_map_rgba_f(data->tint,data->tint,data->tint,data->tint),data->mountain_position, 0,0); - al_draw_scaled_bitmap(data->cloud,0,0,al_get_bitmap_width(data->cloud), al_get_bitmap_height(data->cloud), game->viewport.width*(sin((data->cloud_position/40)-4.5)-0.3), game->viewport.height*0.35, al_get_bitmap_width(data->cloud)/2, al_get_bitmap_height(data->cloud)/2,0); - al_draw_bitmap(data->cloud2,game->viewport.width*(data->cloud2_position/100.0), game->viewport.height-(game->viewport.width*(1240.0/3910.0))*0.7,0); - al_draw_bitmap(data->image,0, game->viewport.height-(game->viewport.width*(1240.0/3910.0)),0); - - al_draw_bitmap(data->pinkcloud_bitmap,(game->viewport.width*0.12) + (cos((data->cloud_position/25+80)*1.74444))*40, 0,0); - al_draw_bitmap(data->cloud,game->viewport.width*data->cloud_position/100, game->viewport.height*0.1,0); - - al_draw_bitmap(data->pie_bitmap, game->viewport.width/2, game->viewport.height*(data->cloud_position)/10,0); - - /* GLASS EFFECT */ - al_set_target_bitmap(data->blurbg); - - al_clear_to_color(al_map_rgb(183,234,193)); - al_draw_scaled_bitmap(data->cloud,0,0,al_get_bitmap_width(data->cloud), al_get_bitmap_height(data->cloud), game->viewport.width*(sin((data->cloud_position/40)-4.5)-0.3) - (game->viewport.width/2)+(al_get_bitmap_width(data->logo)/2), game->viewport.height*0.35-(game->viewport.height*0.1), al_get_bitmap_width(data->cloud)/2, al_get_bitmap_height(data->cloud)/2,0); - al_draw_bitmap(data->pinkcloud_bitmap,(game->viewport.width*0.12) + (cos((data->cloud_position/25+80)*1.74444))*40 - (game->viewport.width/2)+(al_get_bitmap_width(data->logo)/2), -(game->viewport.height*0.1),0); - al_draw_bitmap(data->cloud,game->viewport.width*data->cloud_position/100 - (game->viewport.width/2)+(al_get_bitmap_width(data->logo)/2), game->viewport.height*0.1-(game->viewport.height*0.1),0); - al_draw_bitmap(data->pie_bitmap, game->viewport.width/2 - (game->viewport.width/2)+(al_get_bitmap_width(data->logo)/2), game->viewport.height*(data->cloud_position)/10 -(game->viewport.height*0.1),0); - - /*al_draw_bitmap_region(al_get_backbuffer(game->display), (game->viewport.width/2)-(al_get_bitmap_width(data->logo)/2), (game->viewport.height*0.1), al_get_bitmap_width(data->logo), al_get_bitmap_height(data->logo), 0, 0, 0);*/ - - al_set_target_bitmap(data->blurbg2); - al_clear_to_color(al_map_rgba(0,0,0,0)); - - float alpha = (1.0/8.0); - ALLEGRO_COLOR color = al_map_rgba_f(alpha, alpha, alpha, alpha); - int bx = 0, by = 0; - for (by = -2; by <= 2; by++) { - for (bx = -2; bx <= 2; bx++) { - if (sqrt(bx*bx+by*by) <= 2) - al_draw_tinted_bitmap(data->blurbg, color, bx*2, by*2, 0); + if (!tmp->character->spritesheet->kill) { + MoveCharacter(game, tmp->character, dx * tmp->speed * data->badguySpeed, 0, 0); } - } - al_draw_bitmap(data->glass, 0, 0, 0); - al_set_blender(ALLEGRO_ADD, ALLEGRO_ZERO, ALLEGRO_ALPHA); - al_draw_bitmap(data->logo, 0, 0, 0); - al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_INVERSE_ALPHA); - al_set_target_bitmap(al_get_backbuffer(game->display)); - al_draw_bitmap(data->blurbg2, (game->viewport.width/2)-(al_get_bitmap_width(data->logo)/2), (game->viewport.height*0.1), 0); - al_draw_bitmap(data->logoblur, (game->viewport.width/2)-(al_get_bitmap_width(data->logo)/2)-2, (game->viewport.height*0.1)-2, 0); - al_draw_tinted_bitmap(data->logo, al_map_rgba_f(0.1, 0.1, 0.1, 0.1), (game->viewport.width/2)-(al_get_bitmap_width(data->logo)/2), (game->viewport.height*0.1), 0); - /* END OF GLASS EFFECT */ - - DrawTextWithShadow(data->font_title, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.1, ALLEGRO_ALIGN_CENTRE, "Super Derpy"); - DrawTextWithShadow(data->font_subtitle, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.275, ALLEGRO_ALIGN_CENTRE, "Muffin Attack"); - - DrawMenuState(game, data); -} - -void Gamestate_Logic(struct Game *game, struct MenuResources* data) { - data->cloud_position-=0.1; - data->cloud2_position-=0.025; - if (data->cloud_position<-80) { data->cloud_position=100; PrintConsole(game, "cloud_position"); } - if (data->cloud2_position<0) { data->cloud2_position=100; PrintConsole(game, "cloud2_position"); } - data->tint = (sin((data->cloud_position-80)/15)+1)/2; - if (data->tint < 0.000004) { PrintConsole(game, "random tint %f", data->tint); data->mountain_position = (game->viewport.width*(rand()/(float)RAND_MAX)/2)+game->viewport.width/2; } -} - -void* Gamestate_Load(struct Game *game, void (*progress)(struct Game*)) { - - struct MenuResources *data = malloc(sizeof(struct MenuResources)); - - data->options.fullscreen = game->config.fullscreen; - data->options.fps = game->config.fps; - data->options.width = game->config.width; - data->options.height = game->config.height; - (*progress)(game); - data->image = LoadScaledBitmap(game, "menu/menu.png", game->viewport.width, game->viewport.width*(1240.0/3910.0)); - (*progress)(game); - data->mountain = LoadScaledBitmap(game, "menu/mountain.png", game->viewport.height*1.6*0.055, game->viewport.height/9 ); - (*progress)(game); - data->cloud = LoadScaledBitmap(game, "menu/cloud.png", game->viewport.height*1.6*0.5, game->viewport.height*0.25 ); - (*progress)(game); - data->cloud2 = LoadScaledBitmap(game, "menu/cloud2.png", game->viewport.height*1.6*0.2, game->viewport.height*0.1 ); - (*progress)(game); - data->logo = LoadScaledBitmap(game, "menu/logo.png", game->viewport.height*1.6*0.3, game->viewport.height*0.35 ); - data->blurbg = al_create_bitmap(game->viewport.height*1.6*0.3, game->viewport.height*0.35); - data->blurbg2 = al_create_bitmap(game->viewport.height*1.6*0.3, game->viewport.height*0.35); - data->logoblur = al_create_bitmap(game->viewport.height*1.6*0.3+4, game->viewport.height*0.35+4); - (*progress)(game); - al_set_target_bitmap(data->logoblur); - al_clear_to_color(al_map_rgba(0,0,0,0)); - float alpha = (1.0/40.0); - ALLEGRO_COLOR color = al_map_rgba_f(alpha, alpha, alpha, alpha); - int by, bx; - for (by = -2; by <= 2; by++) { - for (bx = -2; bx <= 2; bx++) { - if (sqrt(bx*bx+by*by) <= 2) - al_draw_tinted_bitmap(data->logo, color, bx, by, 0); + if (tmp->character->dead) { + if (tmp->prev) { + tmp->prev->next = tmp->next; + if (tmp->next) tmp->next->prev = tmp->prev; + } else { + data->badguys[i] = tmp->next; + if (tmp->next) tmp->next->prev = NULL; + } + struct Badguy *old = tmp; + tmp = tmp->next; + old->character->dead = true; + old->prev = NULL; + old->next = data->destroyQueue; + if (data->destroyQueue) data->destroyQueue->prev = old; + data->destroyQueue = old; + } else { + tmp = tmp->next; } + } - (*progress)(game); - al_set_target_bitmap(al_get_backbuffer(game->display)); - data->glass = LoadScaledBitmap(game, "menu/glass.png", game->viewport.height*1.6*0.3, game->viewport.height*0.35 ); - (*progress)(game); - //data->pinkcloud = LoadScaledBitmap(game, "menu/pinkcloud.png", game->viewport.width*0.33125, game->viewport.height*0.8122); - data->pinkcloud = LoadScaledBitmap(game, "menu/pinkcloud.png", game->viewport.height*0.8122*(1171.0/2218.0), game->viewport.height*0.8122); - (*progress)(game); - al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); - data->rain = al_load_bitmap( GetDataFilePath(game, "menu/rain.png") ); - (*progress)(game); - data->pie = al_load_bitmap( GetDataFilePath(game, "menu/pie.png") ); - (*progress)(game); - al_set_new_bitmap_flags(ALLEGRO_MAG_LINEAR | ALLEGRO_MIN_LINEAR); - - data->sample = al_load_sample( GetDataFilePath(game, "menu/menu.flac") ); - (*progress)(game); - data->rain_sample = al_load_sample( GetDataFilePath(game, "menu/rain.flac") ); - (*progress)(game); - data->click_sample = al_load_sample( GetDataFilePath(game, "menu/click.flac") ); - (*progress)(game); - data->mountain_position = game->viewport.width*0.7; - (*progress)(game); - - data->music = al_create_sample_instance(data->sample); - al_attach_sample_instance_to_mixer(data->music, game->audio.music); - al_set_sample_instance_playmode(data->music, ALLEGRO_PLAYMODE_LOOP); - (*progress)(game); - - data->rain_sound = al_create_sample_instance(data->rain_sample); - al_attach_sample_instance_to_mixer(data->rain_sound, game->audio.fx); - al_set_sample_instance_playmode(data->rain_sound, ALLEGRO_PLAYMODE_LOOP); - (*progress)(game); - - data->click = al_create_sample_instance(data->click_sample); - al_attach_sample_instance_to_mixer(data->click, game->audio.fx); - al_set_sample_instance_playmode(data->click, ALLEGRO_PLAYMODE_ONCE); - (*progress)(game); - - data->font_title = al_load_ttf_font(GetDataFilePath(game, "fonts/ShadowsIntoLight.ttf"),game->viewport.height*0.16,0 ); - (*progress)(game); - data->font_subtitle = al_load_ttf_font(GetDataFilePath(game, "fonts/ShadowsIntoLight.ttf"),game->viewport.height*0.08,0 ); - (*progress)(game); - data->font = al_load_ttf_font(GetDataFilePath(game, "fonts/ShadowsIntoLight.ttf"),game->viewport.height*0.05,0 ); - (*progress)(game); - data->font_selected = al_load_ttf_font(GetDataFilePath(game, "fonts/ShadowsIntoLight.ttf"),game->viewport.height*0.065,0 ); - (*progress)(game); - - if (!data->sample){ - fprintf(stderr, "Audio clip sample not loaded!\n" ); - exit(-1); - } - - if (!data->rain_sample){ - fprintf(stderr, "Audio clip sample#2 not loaded!\n" ); - exit(-1); - } - - if (!data->click_sample){ - fprintf(stderr, "Audio clip sample#3 not loaded!\n" ); - exit(-1); - } - - data->pinkcloud_bitmap = al_create_bitmap(game->viewport.height*0.8122*(1171.0/2218.0), game->viewport.height); - - data->pie_bitmap = al_create_bitmap(game->viewport.height*0.8, game->viewport.height); - al_set_target_bitmap(data->pie_bitmap); - al_clear_to_color(al_map_rgba(0,0,0,0)); - al_draw_scaled_bitmap(data->pie, 0, 0, al_get_bitmap_width(data->pie), al_get_bitmap_height(data->pie), al_get_bitmap_width(data->pie_bitmap)*0.5, 0, game->viewport.height*1.6*0.11875, game->viewport.height*0.0825, 0); - al_draw_scaled_bitmap(data->pie, 0, 0, al_get_bitmap_width(data->pie), al_get_bitmap_height(data->pie), al_get_bitmap_width(data->pie_bitmap)*0.1, al_get_bitmap_height(data->pie_bitmap)*0.3, game->viewport.height*1.6*0.09, game->viewport.height*0.06, ALLEGRO_FLIP_HORIZONTAL); - al_draw_scaled_bitmap(data->pie, 0, 0, al_get_bitmap_width(data->pie), al_get_bitmap_height(data->pie), al_get_bitmap_width(data->pie_bitmap)*0.3, al_get_bitmap_height(data->pie_bitmap)*0.6, game->viewport.height*1.6*0.13, game->viewport.height*0.1, 0); - al_destroy_bitmap(data->pie); - (*progress)(game); - - al_set_new_bitmap_flags(ALLEGRO_VIDEO_BITMAP); - data->rain_bitmap = al_create_bitmap(al_get_bitmap_width(data->pinkcloud_bitmap)*0.5, al_get_bitmap_height(data->pinkcloud_bitmap)*0.1); - al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); - al_set_target_bitmap(data->rain_bitmap); - al_clear_to_color(al_map_rgba(0,0,0,0)); - al_draw_scaled_bitmap(data->rain,0, 0, al_get_bitmap_width(data->rain), al_get_bitmap_height(data->rain), 0, 0, al_get_bitmap_width(data->rain_bitmap), al_get_bitmap_height(data->rain_bitmap),0); - al_destroy_bitmap(data->rain); - (*progress)(game); - - al_set_target_backbuffer(game->display); - return data; -} - -void Gamestate_Stop(struct Game *game, struct MenuResources* data) { - FadeGamestate(game, false); - al_stop_sample_instance(data->music); - al_stop_sample_instance(data->rain_sound); } void ChangeMenuState(struct Game *game, struct MenuResources* data, enum menustate_enum state) { @@ -309,54 +180,623 @@ void ChangeMenuState(struct Game *game, struct MenuResources* data, enum menusta PrintConsole(game, "menu state changed %d", state); } -void Gamestate_Unload(struct Game *game, struct MenuResources* data) { - al_destroy_bitmap(data->pinkcloud); - al_destroy_bitmap(data->image); - al_destroy_bitmap(data->cloud); - al_destroy_bitmap(data->cloud2); - al_destroy_bitmap(data->pinkcloud_bitmap); - al_destroy_bitmap(data->rain_bitmap); - al_destroy_bitmap(data->mountain); - al_destroy_bitmap(data->pie_bitmap); - al_destroy_bitmap(data->logo); - al_destroy_bitmap(data->logoblur); - al_destroy_bitmap(data->glass); - al_destroy_bitmap(data->blurbg); - al_destroy_bitmap(data->blurbg2); - al_destroy_font(data->font_title); - al_destroy_font(data->font_subtitle); - al_destroy_font(data->font); - al_destroy_font(data->font_selected); - al_destroy_sample_instance(data->music); - al_destroy_sample_instance(data->rain_sound); - al_destroy_sample_instance(data->click); - al_destroy_sample(data->sample); - al_destroy_sample(data->rain_sample); - al_destroy_sample(data->click_sample); +void CheckForEnd(struct Game *game, struct MenuResources *data) { + int i; + bool lost = false; + for (i=0; i<4; i++) { + struct Badguy *tmp = data->badguys[i]; + while (tmp) { + if (tmp->character->x <= (139-(i*10))-10) { + lost = true; + break; + } + tmp=tmp->next; + } + if (lost) break; + } + + if (lost) { + + al_stop_sample_instance(data->solo); + data->soloactive=false; + data->soloanim=0; + data->soloflash=0; + data->soloready=0; + + al_stop_sample_instance(data->music); + al_play_sample_instance(data->end); + SelectSpritesheet(game, data->ego, "cry"); + ChangeMenuState(game, data, MENUSTATE_LOST); + } } +void DrawBadguys(struct Game *game, struct MenuResources *data, int i) { + struct Badguy *tmp = data->badguys[i]; + while (tmp) { + DrawCharacter(game, tmp->character, al_map_rgb(255,255,255), 0); + tmp=tmp->next; + } +} + +void Gamestate_Draw(struct Game *game, struct MenuResources* data) { + + al_set_target_bitmap(al_get_backbuffer(game->display)); + + al_clear_to_color(al_map_rgb(3, 213, 255)); + + al_draw_bitmap(data->bg,0, 0,0); + + al_draw_bitmap(data->cloud,game->viewport.width*data->cloud_position/100, 10 ,0); + + al_draw_bitmap(data->forest,0, 0,0); + + al_draw_bitmap(data->grass,0, 0,0); + + DrawCharacter(game, data->cow, al_map_rgb(255,255,255), 0); + + al_draw_bitmap(data->speaker,104, 19,0); + + al_draw_bitmap(data->stage,0, 0,0); + + al_draw_bitmap(data->lines, 100, 136,0); + + al_draw_bitmap(data->cable,0,151,0); + + DrawCharacter(game, data->ego, al_map_rgb(255,255,255), 0); + + if (data->menustate == MENUSTATE_HIDDEN) { + + if (!data->soloactive) { + if (data->marky == 0) { + al_draw_bitmap(data->marksmall, data->markx, 128, 0); + } else if (data->marky == 1) { + al_draw_bitmap(data->marksmall, data->markx, 140, 0); + } else if (data->marky == 2) { + al_draw_bitmap(data->markbig, data->markx, 152, 0); + } else if (data->marky == 3) { + al_draw_bitmap(data->markbig, data->markx, 166, 0); + } + } + + if (data->lightanim) { + int offset = -5; + if (data->lighty == 1) offset = -3; + if (data->lighty == 2) offset = 0; + if (data->lighty == 3) offset = 4; + al_draw_tinted_bitmap(data->light, al_map_rgba(255, 255, 255,rand() % 256 / 50 * 50) , data->lightx - 171 - (data->lighty < 2 ? 1 : 0), 109+(data->lighty*10) - 143 + offset, 0); + } + + } + + DrawBadguys(game, data, 0); + DrawBadguys(game, data, 1); + DrawBadguys(game, data, 2); + DrawBadguys(game, data, 3); + + if (data->menustate != MENUSTATE_HIDDEN) { + DrawTextWithShadow(data->font_title, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.15, ALLEGRO_ALIGN_CENTRE, data->menustate == MENUSTATE_LOST ? "Radio Edited!" : "Radio Edit"); + DrawMenuState(game, data); + } else { + char score[255]; + snprintf(score, 255, "Score: %d", data->score); + DrawTextWithShadow(data->font, al_map_rgb(255,255,255), 2, game->viewport.height - 10, ALLEGRO_ALIGN_LEFT, score); + + if ((data->soloready >= SOLO_MIN) && (data->soloanim <= 30)) { + DrawTextWithShadow(data->font, al_map_rgb(255,255,255), game->viewport.width*0.5, game->viewport.height*0.15, ALLEGRO_ALIGN_CENTRE, "Press ENTER to play a solo!"); + } + } + + if (data->soloflash) { + al_draw_filled_rectangle(0, 0, 320, 180, al_map_rgb(255,255,255)); + } +} + +void AddBadguy(struct Game *game, struct MenuResources* data, int i) { + struct Badguy *n = malloc(sizeof(struct Badguy)); + n->next = NULL; + n->prev = NULL; + n->speed = (rand() % 3) * 0.25 + 1; + n->melting = false; + n->character = CreateCharacter(game, "badguy"); + n->character->spritesheets = data->badguy->spritesheets; + n->character->shared = true; + SelectSpritesheet(game, n->character, "walk"); + SetCharacterPosition(game, n->character, 320, 108+(i*13), 0); + + if (data->badguys[i]) { + struct Badguy *tmp = data->badguys[i]; + while (tmp->next) { + tmp=tmp->next; + } + tmp->next = n; + n->prev = tmp; + } else { + data->badguys[i] = n; + } +} + +void Fire(struct Game *game, struct MenuResources *data) { + + if (data->soloactive) return; + + data->lightx = data->markx; + data->lighty = data->marky; + data->lightanim=1; + data->usage=30; + + int num = rand() % 3; + if (((al_get_sample_instance_position(data->music) + 20000) / 44118) % 2 == 1) { + num += 3; + } + al_stop_sample_instance(data->chords[num]); + al_play_sample_instance(data->chords[num]); + PrintConsole(game, "playing chord nr %d", num); + + struct Badguy *tmp = data->badguys[data->marky]; + while (tmp) { + if (!tmp->melting) { + if ((data->markx >= tmp->character->x - 9) && (data->markx <= tmp->character->x + 1)) { + data->score += 100 * tmp->speed; + SelectSpritesheet(game, tmp->character, "melt"); + data->soloready++; + tmp->melting = true; + } + } + tmp=tmp->next; + } +} + +void Gamestate_Logic(struct Game *game, struct MenuResources* data) { + + if (data->keys.lastkey == data->keys.key) { + data->keys.delay = data->keys.lastdelay; // workaround for random bugus UP/DOWN events + } + + data->cloud_position-=0.1; + if (data->cloud_position<-40) { data->cloud_position=100; PrintConsole(game, "cloud_position"); } + AnimateCharacter(game, data->ego, 1); + AnimateCharacter(game, data->cow, 1); + + if (data->menustate == MENUSTATE_HIDDEN) { + + if ((data->keys.key) && (data->keys.delay < 3)) { + + if (data->keys.key==ALLEGRO_KEY_UP) { + data->marky--; + int min = 139-(data->marky*10); + int step = 10 - (data->markx - min) / ((320-min)/10); + data->markx+= step; + if (data->marky < 0) { + data->markx-=4*step; + data->marky = 3; + } + } + + if (data->keys.key==ALLEGRO_KEY_DOWN) { + data->marky++; + int min = 139-(data->marky*10); + int step = 10 - (data->markx - min) / ((320-min)/10); + data->markx-= step; + if (data->marky > 3) { + data->markx+=4*step; + data->marky = 0; + } + } + + if (data->keys.key==ALLEGRO_KEY_LEFT) { + int min = 139-(data->marky*10); + data->markx-= data->keys.shift ? 5 : 2; + if (data->markx < min) data->markx=min; + } + + if (data->keys.key==ALLEGRO_KEY_RIGHT) { + int max = 320 - al_get_bitmap_width(data->markbig); + if (data->marky < 2) max = 320 - al_get_bitmap_width(data->marksmall); + data->markx+= data->keys.shift ? 5 : 2; + if (data->markx > max) data->markx=max; + } + + if ((data->keys.key==ALLEGRO_KEY_SPACE) && (data->usage==0)) { + Fire(game, data); + } + + if (data->keys.delay == INT_MIN) data->keys.delay = 45; + else data->keys.delay += 4; + + } else if (data->keys.key) { + data->keys.delay-=3; + } + + AnimateBadguys(game, data, 0); + AnimateBadguys(game, data, 1); + AnimateBadguys(game, data, 2); + AnimateBadguys(game, data, 3); + + MoveBadguys(game, data, 0, -0.17); + MoveBadguys(game, data, 1, -0.18); + MoveBadguys(game, data, 2, -0.19); + MoveBadguys(game, data, 3, -0.2); + + data->timeTillNextBadguy--; + if (data->timeTillNextBadguy <= 0) { + data->timeTillNextBadguy = data->badguyRate; + data->badguyRate -= data->badguyRate * 0.02; + if (data->badguyRate < 20) { + data->badguyRate = 20; + } + + data->badguySpeed+= 0.001; + AddBadguy(game, data, rand() % 4); + } + + if (data->usage) { data->usage--; } + if (data->lightanim) { data->lightanim++;} + if (data->lightanim > 25) { data->lightanim = 0; } + + CheckForEnd(game, data); + } + + data->soloanim++; + if (data->soloanim >= 60) data->soloanim=0; + + if (data->soloactive) { + if (al_get_sample_instance_position(data->solo) >= 163840) { + PrintConsole(game, "BLAAAST"); + data->soloflash = 6; + data->soloactive=false; + data->badguySpeed+=0.5; + data->badguyRate += 20; + + int i; + for (i=0; i<4; i++) { + struct Badguy *tmp = data->badguys[i]; + while (tmp) { + if ((!tmp->melting) && (!tmp->character->dead)) { + data->score += 100 * tmp->speed; + SelectSpritesheet(game, tmp->character, "melt"); + tmp->melting = true; + } + tmp=tmp->next; + } + } + + } + } + + if (data->soloflash) data->soloflash--; + + data->keys.lastkey = data->keys.key; + data->keys.lastdelay = data->keys.delay; + + TM_Process(data->timeline); +} + +void* Gamestate_Load(struct Game *game, void (*progress)(struct Game*)) { + + struct MenuResources *data = malloc(sizeof(struct MenuResources)); + + data->timeline = TM_Init(game, "main"); + (*progress)(game); + + data->options.fullscreen = game->config.fullscreen; + data->options.fps = game->config.fps; + data->options.width = game->config.width; + data->options.height = game->config.height; + data->options.resolution = game->config.width / 320; + if (game->config.height / 180 < data->options.resolution) data->options.resolution = game->config.height / 180; + + data->bg = al_load_bitmap( GetDataFilePath(game, "bg.png") ); + data->forest = al_load_bitmap( GetDataFilePath(game, "forest.png") ); + data->grass = al_load_bitmap( GetDataFilePath(game, "grass.png") ); + data->speaker = al_load_bitmap( GetDataFilePath(game, "speaker.png") ); + data->stage = al_load_bitmap( GetDataFilePath(game, "stage.png") ); + data->cloud = al_load_bitmap( GetDataFilePath(game, "cloud.png") ); + data->lines = al_load_bitmap( GetDataFilePath(game, "lines.png") ); + data->cable = al_load_bitmap( GetDataFilePath(game, "cable.png") ); + data->marksmall = al_load_bitmap( GetDataFilePath(game, "mark-small.png") ); + data->markbig = al_load_bitmap( GetDataFilePath(game, "mark-big.png") ); + data->light = al_load_bitmap( GetDataFilePath(game, "light.png") ); + data->sample = al_load_sample( GetDataFilePath(game, "menu.flac") ); + data->click_sample = al_load_sample( GetDataFilePath(game, "click.flac") ); + data->quit_sample = al_load_sample( GetDataFilePath(game, "quit.flac") ); + data->end_sample = al_load_sample( GetDataFilePath(game, "end.flac") ); + data->solo_sample = al_load_sample( GetDataFilePath(game, "solo.flac") ); + (*progress)(game); + + data->music = al_create_sample_instance(data->sample); + al_attach_sample_instance_to_mixer(data->music, game->audio.music); + al_set_sample_instance_playmode(data->music, ALLEGRO_PLAYMODE_LOOP); + + data->click = al_create_sample_instance(data->click_sample); + al_attach_sample_instance_to_mixer(data->click, game->audio.fx); + al_set_sample_instance_playmode(data->click, ALLEGRO_PLAYMODE_ONCE); + + data->quit = al_create_sample_instance(data->quit_sample); + al_attach_sample_instance_to_mixer(data->quit, game->audio.fx); + al_set_sample_instance_playmode(data->quit, ALLEGRO_PLAYMODE_ONCE); + + data->solo = al_create_sample_instance(data->solo_sample); + al_attach_sample_instance_to_mixer(data->solo, game->audio.fx); + al_set_sample_instance_playmode(data->solo, ALLEGRO_PLAYMODE_ONCE); + + data->end = al_create_sample_instance(data->end_sample); + al_attach_sample_instance_to_mixer(data->end, game->audio.fx); + al_set_sample_instance_playmode(data->end, ALLEGRO_PLAYMODE_ONCE); + + int i; + for (i=0; i<6; i++) { + char name[] = "chords/0.flac"; + name[7] = '1' + i; + data->chord_samples[i] = al_load_sample( GetDataFilePath(game, name) ); + + data->chords[i] = al_create_sample_instance(data->chord_samples[i]); + al_attach_sample_instance_to_mixer(data->chords[i], game->audio.fx); + al_set_sample_instance_playmode(data->chords[i], ALLEGRO_PLAYMODE_ONCE); + } + + if (!data->click_sample){ + fprintf(stderr, "Audio clip sample not loaded!\n" ); + exit(-1); + } + (*progress)(game); + + data->font_title = al_load_ttf_font(GetDataFilePath(game, "fonts/MonkeyIsland.ttf"),game->viewport.height*0.16,0 ); + data->font = al_load_ttf_font(GetDataFilePath(game, "fonts/MonkeyIsland.ttf"),game->viewport.height*0.05,0 ); + (*progress)(game); + + data->ego = CreateCharacter(game, "ego"); + RegisterSpritesheet(game, data->ego, "stand"); + RegisterSpritesheet(game, data->ego, "fix"); + RegisterSpritesheet(game, data->ego, "fix2"); + RegisterSpritesheet(game, data->ego, "fix3"); + RegisterSpritesheet(game, data->ego, "play"); + RegisterSpritesheet(game, data->ego, "cry"); + LoadSpritesheets(game, data->ego); + + data->cow = CreateCharacter(game, "cow"); + RegisterSpritesheet(game, data->cow, "stand"); + RegisterSpritesheet(game, data->cow, "chew"); + RegisterSpritesheet(game, data->cow, "look"); + LoadSpritesheets(game, data->cow); + + data->badguy = CreateCharacter(game, "badguy"); + RegisterSpritesheet(game, data->badguy, "walk"); + RegisterSpritesheet(game, data->badguy, "melt"); + LoadSpritesheets(game, data->badguy); + (*progress)(game); + + al_set_target_backbuffer(game->display); + return data; +} + +void DestroyBadguys(struct Game *game, struct MenuResources* data, int i) { + struct Badguy *tmp = data->badguys[i]; + if (!tmp) { + tmp = data->destroyQueue; + data->destroyQueue = NULL; + } + while (tmp) { + DestroyCharacter(game, tmp->character); + struct Badguy *old = tmp; + tmp = tmp->next; + free(old); + if ((!tmp) && (data->destroyQueue)) { + tmp = data->destroyQueue; + data->destroyQueue = NULL; + } + } + data->badguys[i] = NULL; +} + +void Gamestate_Stop(struct Game *game, struct MenuResources* data) { + al_stop_sample_instance(data->music); + + int i; + for (i=0; i<4; i++) { + DestroyBadguys(game, data, i); + } +} + +void Gamestate_Unload(struct Game *game, struct MenuResources* data) { + if (game->config.fx) { + al_clear_to_color(al_map_rgb(0,0,0)); + DrawConsole(game); + al_flip_display(); + al_play_sample_instance(data->quit); + al_rest(0.3); + int i; + for (i=0;i<50; i++) { + al_rest(0.05); + ALLEGRO_KEYBOARD_STATE kb; + al_get_keyboard_state(&kb); + if (al_key_down(&kb, ALLEGRO_KEY_ESCAPE)) return; + } + } + + al_destroy_bitmap(data->bg); + al_destroy_bitmap(data->cloud); + al_destroy_bitmap(data->grass); + al_destroy_bitmap(data->forest); + al_destroy_bitmap(data->stage); + al_destroy_bitmap(data->speaker); + al_destroy_bitmap(data->lines); + al_destroy_bitmap(data->cable); + al_destroy_bitmap(data->light); + al_destroy_bitmap(data->marksmall); + al_destroy_bitmap(data->markbig); + al_destroy_font(data->font_title); + al_destroy_font(data->font); + al_destroy_sample_instance(data->music); + al_destroy_sample_instance(data->click); + al_destroy_sample_instance(data->end); + al_destroy_sample_instance(data->quit); + al_destroy_sample_instance(data->solo); + al_destroy_sample(data->sample); + al_destroy_sample(data->click_sample); + al_destroy_sample(data->quit_sample); + al_destroy_sample(data->end_sample); + al_destroy_sample(data->solo_sample); + int i; + for (i=0; i<6; i++) { + al_destroy_sample_instance(data->chords[i]); + al_destroy_sample(data->chord_samples[i]); + } + DestroyCharacter(game, data->ego); + DestroyCharacter(game, data->cow); + DestroyCharacter(game, data->badguy); + TM_Destroy(data->timeline); +} + +// TODO: refactor to single Enqueue_Anim +bool Anim_CowLook(struct Game *game, struct TM_Action *action, enum TM_ActionState state) { + struct MenuResources *data = action->arguments->value; + if (state == TM_ACTIONSTATE_START) { + ChangeSpritesheet(game, data->cow, "look"); + TM_AddQueuedBackgroundAction(data->timeline, &Anim_CowLook, TM_AddToArgs(NULL, 1, data), 54*1000, "cow_look"); + } + return true; +} + +void StartGame(struct Game *game, struct MenuResources *data) { + TM_CleanQueue(data->timeline); + TM_CleanBackgroundQueue(data->timeline); + ChangeSpritesheet(game, data->ego, "play"); + ChangeSpritesheet(game, data->cow, "chew"); + ChangeMenuState(game,data,MENUSTATE_HIDDEN); + al_play_sample_instance(data->chords[0]); +} + +bool Anim_FixGuitar(struct Game *game, struct TM_Action *action, enum TM_ActionState state) { + struct MenuResources *data = action->arguments->value; + if (state == TM_ACTIONSTATE_START) { + ChangeSpritesheet(game, data->ego, "fix"); + TM_AddQueuedBackgroundAction(data->timeline, &Anim_FixGuitar, TM_AddToArgs(NULL, 1, data), 30*1000, "fix_guitar"); + } + return true; +} + + void Gamestate_Start(struct Game *game, struct MenuResources* data) { - data->cloud_position = 100; - data->cloud2_position = 100; - ChangeMenuState(game,data,MENUSTATE_MAIN); + SetCharacterPosition(game, data->ego, 22, 107, 0); + SetCharacterPosition(game, data->cow, 35, 88, 0); + data->score = 0; + + data->markx = 119; + data->marky = 2; + + data->soloactive = false; + data->soloanim = 0; + data->soloflash = 0; + data->soloready = 0; + + data->keys.key = 0; + data->keys.delay = 0; + data->keys.shift = false; + data->keys.lastkey = -1; + + data->lightanim=0; + + data->badguySpeed = 1.2; + + data->usage = 0; + + SelectSpritesheet(game, data->ego, "stand"); + SelectSpritesheet(game, data->cow, "chew"); + ChangeMenuState(game,data,MENUSTATE_MAIN); + TM_AddQueuedBackgroundAction(data->timeline, &Anim_FixGuitar, TM_AddToArgs(NULL, 1, data), 15*1000, "fix_guitar"); + TM_AddQueuedBackgroundAction(data->timeline, &Anim_CowLook, TM_AddToArgs(NULL, 1, data), 5*1000, "cow_look"); al_play_sample_instance(data->music); - al_play_sample_instance(data->rain_sound); - FadeGamestate(game, true); + al_rest(0.01); // poor man's synchronization + + data->badguys[0] = NULL; + data->badguys[1] = NULL; + data->badguys[2] = NULL; + data->badguys[3] = NULL; + data->destroyQueue = NULL; + + data->badguyRate = 100; + data->timeTillNextBadguy = 0; } void Gamestate_ProcessEvent(struct Game *game, struct MenuResources* data, ALLEGRO_EVENT *ev) { + TM_HandleEvent(data->timeline, ev); + + if ((data->menustate == MENUSTATE_ABOUT) && (ev->type == ALLEGRO_EVENT_KEY_DOWN)) { + ChangeMenuState(game, data, MENUSTATE_MAIN); + return; + } + + if (data->menustate == MENUSTATE_HIDDEN) { + + if (ev->type == ALLEGRO_EVENT_KEY_DOWN) { + + switch (ev->keyboard.keycode) { + case ALLEGRO_KEY_UP: + case ALLEGRO_KEY_DOWN: + case ALLEGRO_KEY_LEFT: + case ALLEGRO_KEY_RIGHT: + case ALLEGRO_KEY_SPACE: + if (data->keys.key != ev->keyboard.keycode) { + data->keys.key = ev->keyboard.keycode; + data->keys.delay = INT_MIN; + } + break; + case ALLEGRO_KEY_ESCAPE: + Gamestate_Stop(game, data); + Gamestate_Start(game, data); + break; + case ALLEGRO_KEY_LSHIFT: + case ALLEGRO_KEY_RSHIFT: + data->keys.shift = true; + break; + case ALLEGRO_KEY_ENTER: + if ((!data->soloactive) && (data->soloready >= SOLO_MIN)) { + data->soloready = 0; + al_play_sample_instance(data->solo); + data->soloactive = true; + data->badguySpeed-=0.5; + } + break; + default: + data->keys.key = 0; + break; + } + } else if (ev->type == ALLEGRO_EVENT_KEY_UP) { + switch (ev->keyboard.keycode) { + case ALLEGRO_KEY_LSHIFT: + case ALLEGRO_KEY_RSHIFT: + data->keys.shift = false; + break; + default: + if (ev->keyboard.keycode == data->keys.key) { + data->keys.key = 0; + } + break; + } + } + + return; + } if (ev->type != ALLEGRO_EVENT_KEY_DOWN) return; if (ev->keyboard.keycode==ALLEGRO_KEY_UP) { data->selected--; + if ((data->selected == 2) && ((data->menustate==MENUSTATE_VIDEO) || (data->menustate==MENUSTATE_OPTIONS) || (data->menustate==MENUSTATE_AUDIO))) { + data->selected --; + } if ((data->menustate==MENUSTATE_VIDEO) && (data->selected==1) && (data->options.fullscreen)) data->selected--; al_play_sample_instance(data->click); } else if (ev->keyboard.keycode==ALLEGRO_KEY_DOWN) { data->selected++; if ((data->menustate==MENUSTATE_VIDEO) && (data->selected==1) && (data->options.fullscreen)) data->selected++; + if ((data->selected == 2) && ((data->menustate==MENUSTATE_VIDEO) || (data->menustate==MENUSTATE_OPTIONS) || (data->menustate==MENUSTATE_AUDIO))) { + data->selected ++; + } + + al_play_sample_instance(data->click); } @@ -367,19 +807,13 @@ void Gamestate_ProcessEvent(struct Game *game, struct MenuResources* data, ALLEG case MENUSTATE_MAIN: switch (data->selected) { case 0: - LoadGamestate(game, "disclaimer"); - LoadGamestate(game, "intro"); - LoadGamestate(game, "map"); - StopGamestate(game, "menu"); - StartGamestate(game, "disclaimer"); + ChangeMenuState(game,data,MENUSTATE_INTRO); break; case 1: ChangeMenuState(game,data,MENUSTATE_OPTIONS); break; case 2: - StopGamestate(game, "menu"); - LoadGamestate(game, "about"); - StartGamestate(game, "about"); + ChangeMenuState(game,data,MENUSTATE_ABOUT); break; case 3: UnloadGamestate(game, "menu"); @@ -419,12 +853,9 @@ void Gamestate_ProcessEvent(struct Game *game, struct MenuResources* data, ALLEG case MENUSTATE_OPTIONS: switch (data->selected) { case 0: - ChangeMenuState(game,data,MENUSTATE_CONTROLS); - break; - case 1: ChangeMenuState(game,data,MENUSTATE_VIDEO); break; - case 2: + case 1: ChangeMenuState(game,data,MENUSTATE_AUDIO); break; case 3: @@ -434,43 +865,6 @@ void Gamestate_ProcessEvent(struct Game *game, struct MenuResources* data, ALLEG break; } break; - case MENUSTATE_PAUSE: //TODO: REMOVE ME - switch (data->selected){ - case 0: - PrintConsole(game,"Game resumed."); - //al_destroy_bitmap(game->pause.bitmap); - //game->pause.bitmap = NULL; - - //ResumeGamestate(game); - //game->gamestate = game->loadstate; - break; - case 1: - // TODO: - SwitchGamestate(game, "pause", "map"); - /*game->gamestate=game->loadstate; - UnloadGameState(game); - game->gamestate = GAMESTATE_LOADING; - game->loadstate = GAMESTATE_MAP;*/ - break; - case 2: - ChangeMenuState(game,data,MENUSTATE_OPTIONS); - break; - case 3: - UnloadGamestate(game, "menu"); - return; - default: - break; - } - break; - case MENUSTATE_CONTROLS: - switch (data->selected) { - case 3: - ChangeMenuState(game,data,MENUSTATE_OPTIONS); - break; - default: - break; - } - break; case MENUSTATE_VIDEO: switch (data->selected) { case 0: @@ -479,21 +873,61 @@ void Gamestate_ProcessEvent(struct Game *game, struct MenuResources* data, ALLEG SetConfigOption(game, "SuperDerpy", "fullscreen", "1"); else SetConfigOption(game, "SuperDerpy", "fullscreen", "0"); + al_set_display_flag(game->display, ALLEGRO_FULLSCREEN_WINDOW, data->options.fullscreen); + SetupViewport(game); + PrintConsole(game, "Fullscreen toggled"); + break; + case 1: + data->options.resolution++; + + int max = 0, i = 0; + + for (i=0; i < al_get_num_video_adapters(); i++) { + ALLEGRO_MONITOR_INFO aminfo; + al_get_monitor_info(i , &aminfo); + int desktop_width = aminfo.x2 - aminfo.x1 + 1; + int desktop_height = aminfo.y2 - aminfo.y1 + 1; + int localmax = desktop_width / 320; + if (desktop_height / 180 < localmax) localmax = desktop_height / 180; + if (localmax > max) max = localmax; + } + + + if (data->options.resolution > max) data->options.resolution = 1; + text = malloc(255*sizeof(char)); + snprintf(text, 255, "%d", data->options.resolution * 320); + SetConfigOption(game, "SuperDerpy", "width", text); + snprintf(text, 255, "%d", data->options.resolution * 180); + SetConfigOption(game, "SuperDerpy", "height", text); + free(text); + al_resize_display(game->display, data->options.resolution * 320, data->options.resolution * 180); + + if ((al_get_display_width(game->display) < (data->options.resolution * 320)) || (al_get_display_height(game->display) < (data->options.resolution * 180))) { + SetConfigOption(game, "SuperDerpy", "width", "320"); + SetConfigOption(game, "SuperDerpy", "height", "180"); + data->options.resolution = 1; + al_resize_display(game->display, 320, 180); + } + + SetupViewport(game); + PrintConsole(game, "Resolution changed"); break; case 3: - if ((data->options.fullscreen==game->config.fullscreen) && (data->options.fps==game->config.fps) && (data->options.width==game->config.width) && (data->options.height==game->config.height)) { - ChangeMenuState(game,data,MENUSTATE_OPTIONS); - } else { - PrintConsole(game, "video settings changed, restarting..."); - game->restart = true; - UnloadGamestate(game, "menu"); - return; - } + ChangeMenuState(game,data,MENUSTATE_OPTIONS); break; default: break; } break; + case MENUSTATE_ABOUT: + break; + case MENUSTATE_INTRO: + StartGame(game, data); + break; + case MENUSTATE_LOST: + Gamestate_Stop(game,data); + Gamestate_Start(game,data); + break; default: UnloadGamestate(game, "menu"); return; @@ -504,21 +938,25 @@ void Gamestate_ProcessEvent(struct Game *game, struct MenuResources* data, ALLEG case MENUSTATE_OPTIONS: ChangeMenuState(game,data,MENUSTATE_MAIN); break; + case MENUSTATE_ABOUT: + ChangeMenuState(game,data,MENUSTATE_MAIN); + break; + case MENUSTATE_HIDDEN: + Gamestate_Stop(game,data); + Gamestate_Start(game,data); + break; case MENUSTATE_VIDEO: ChangeMenuState(game,data,MENUSTATE_OPTIONS); break; case MENUSTATE_AUDIO: ChangeMenuState(game,data,MENUSTATE_OPTIONS); break; - case MENUSTATE_CONTROLS: - ChangeMenuState(game,data,MENUSTATE_OPTIONS); + case MENUSTATE_INTRO: + ChangeMenuState(game,data,MENUSTATE_MAIN); break; - case MENUSTATE_PAUSE: - PrintConsole(game,"Game resumed."); - //al_destroy_bitmap(game->pause.bitmap); - //game->pause.bitmap = NULL; - //ResumeGameState(game); - //game->gamestate = game->loadstate; + case MENUSTATE_LOST: + Gamestate_Stop(game,data); + Gamestate_Start(game,data); break; default: UnloadGamestate(game, "menu"); @@ -531,7 +969,6 @@ void Gamestate_ProcessEvent(struct Game *game, struct MenuResources* data, ALLEG return; } - void Gamestate_Pause(struct Game *game, struct MenuResources* data) {} void Gamestate_Resume(struct Game *game, struct MenuResources* data) {} void Gamestate_Reload(struct Game *game, struct MenuResources* data) {} diff --git a/src/gamestates/menu.h b/src/gamestates/menu.h index 83e7a04..5e9663e 100644 --- a/src/gamestates/menu.h +++ b/src/gamestates/menu.h @@ -27,43 +27,69 @@ enum menustate_enum { MENUSTATE_MAIN, MENUSTATE_OPTIONS, - MENUSTATE_CONTROLS, MENUSTATE_VIDEO, - MENUSTATE_PAUSE, - MENUSTATE_AUDIO + MENUSTATE_AUDIO, + MENUSTATE_HIDDEN, + MENUSTATE_ABOUT, + MENUSTATE_LOST, + MENUSTATE_INTRO, + // FIXME: menustate abuse eeeeew }; /*! \brief Resources used by Menu state. */ struct MenuResources { - ALLEGRO_BITMAP *image; /*!< Bitmap with lower portion of menu landscape. */ + ALLEGRO_BITMAP *bg; /*!< Bitmap with lower portion of menu landscape. */ ALLEGRO_BITMAP *cloud; /*!< Bitmap with bigger cloud. */ - ALLEGRO_BITMAP *cloud2; /*!< Bitmap with small cloud. */ - ALLEGRO_BITMAP *pie; /*!< Unscaled bitmap with pie. */ - ALLEGRO_BITMAP *pie_bitmap; /*!< Scaled and "rendered" bitmap with pies. */ - ALLEGRO_BITMAP *pinkcloud_bitmap; /*!< Scaled bitmap with pinkcloud and home. */ - ALLEGRO_BITMAP *pinkcloud; /*!< Unscaled bitmap with pinkcloud and home. */ - ALLEGRO_BITMAP *rain; /*!< Unscaled bitmap with rain drop. */ - ALLEGRO_BITMAP *rain_bitmap; /*!< Scaled and "rendered" bitmap with rain drops. */ - ALLEGRO_BITMAP *mountain; /*!< Flashing mountain in background bitmap. */ - ALLEGRO_BITMAP *logo; /*!< Logo displayed in the background. */ - ALLEGRO_BITMAP *logoblur; /*!< Prerendered blurred logo. */ - ALLEGRO_BITMAP *glass; /*!< Texture used for glass effect in the logo. */ - ALLEGRO_BITMAP *blurbg; /*!< Temporary bitmap used for blur effect in glass logo. */ - ALLEGRO_BITMAP *blurbg2; /*!< Temporary bitmap used for blur effect in glass logo. */ + ALLEGRO_BITMAP *grass; + ALLEGRO_BITMAP *forest; + ALLEGRO_BITMAP *stage; + ALLEGRO_BITMAP *speaker; + ALLEGRO_BITMAP *lines; + ALLEGRO_BITMAP *cable; + ALLEGRO_BITMAP *light; + + ALLEGRO_BITMAP *marksmall; + ALLEGRO_BITMAP *markbig; + int markx, marky; + + float badguySpeed; + + ALLEGRO_SAMPLE *chord_samples[6]; + ALLEGRO_SAMPLE_INSTANCE *chords[6]; + // 0-2: low; 3-5: high + + int usage; + int lightx, lighty, lightanim; + + int soloready, soloanim, soloflash; + bool soloactive; + + struct Badguy { + struct Character *character; + struct Badguy *next, *prev; + float speed; + bool melting; + } *badguys[4], *destroyQueue; + + int timeTillNextBadguy, badguyRate; + + struct Character *ego; + struct Character *cow; + struct Character *badguy; + struct Timeline *timeline; float cloud_position; /*!< Position of bigger cloud. */ - float cloud2_position; /*!< Position of small cloud. */ - int mountain_position; /*!< Position of flashing mountain. */ - float tint; /*!< Opacity of flashing mountain. */ - ALLEGRO_SAMPLE *sample; /*!< Background music sample. */ - ALLEGRO_SAMPLE *rain_sample; /*!< Rain sound sample. */ + ALLEGRO_SAMPLE *sample; /*!< Music sample. */ ALLEGRO_SAMPLE *click_sample; /*!< Click sound sample. */ - ALLEGRO_SAMPLE_INSTANCE *music; /*!< Sample instance with background music. */ - ALLEGRO_SAMPLE_INSTANCE *rain_sound; /*!< Sample instance with rain sound. */ + ALLEGRO_SAMPLE *quit_sample; + ALLEGRO_SAMPLE *end_sample; + ALLEGRO_SAMPLE *solo_sample; + ALLEGRO_SAMPLE_INSTANCE *music; /*!< Sample instance with music sound. */ ALLEGRO_SAMPLE_INSTANCE *click; /*!< Sample instance with click sound. */ + ALLEGRO_SAMPLE_INSTANCE *quit; + ALLEGRO_SAMPLE_INSTANCE *solo; + ALLEGRO_SAMPLE_INSTANCE *end; ALLEGRO_FONT *font_title; /*!< Font of "Super Derpy" text. */ - ALLEGRO_FONT *font_subtitle; /*!< Font of "Muffin Attack" text. */ ALLEGRO_FONT *font; /*!< Font of standard menu item. */ - ALLEGRO_FONT *font_selected; /*!< Font of selected menu item. */ int selected; /*!< Number of selected menu item. */ enum menustate_enum menustate; /*!< Current menu page. */ struct { @@ -71,8 +97,17 @@ struct MenuResources { int fps; int width; int height; + int resolution; } options; /*!< Options which can be changed in menu. */ -}; -//void DrawMenuState(struct Game *game); -//void ChangeMenuState(struct Game *game, enum menustate_enum state); + struct { + int key; + bool shift; + int delay; + // workaround for random bogus UP/DOWN events + int lastkey; + int lastdelay; + } keys; + + int score; +}; diff --git a/src/main.c b/src/main.c index 8e3ba0d..d7c1f6a 100644 --- a/src/main.c +++ b/src/main.c @@ -35,23 +35,6 @@ #include "config.h" #include "main.h" - -void DrawConsole(struct Game *game) { - if (game->_priv.showconsole) { - al_draw_bitmap(game->_priv.console, 0, 0, 0); - double game_time = al_get_time(); - if(game_time - game->_priv.fps_count.old_time >= 1.0) { - game->_priv.fps_count.fps = game->_priv.fps_count.frames_done / (game_time - game->_priv.fps_count.old_time); - game->_priv.fps_count.frames_done = 0; - game->_priv.fps_count.old_time = game_time; - } - char sfps[6] = { }; - snprintf(sfps, 6, "%.0f", game->_priv.fps_count.fps); - DrawTextWithShadow(game->_priv.font, al_map_rgb(255,255,255), game->viewport.width*0.99, 0, ALLEGRO_ALIGN_RIGHT, sfps); - } - game->_priv.fps_count.frames_done++; -} - void DrawGamestates(struct Game *game) { al_set_target_backbuffer(game->display); al_clear_to_color(al_map_rgb(0,0,0)); @@ -84,64 +67,8 @@ void EventGamestates(struct Game *game, ALLEGRO_EVENT *ev) { } } -void SetupViewport(struct Game *game) { - game->viewport.width = al_get_display_width(game->display); - game->viewport.height = al_get_display_height(game->display); - if (atoi(GetConfigOptionDefault(game, "SuperDerpy", "letterbox", "0"))) { - float const aspectRatio = (float)1920 / (float)1080; // full HD - int clipWidth = game->viewport.width, clipHeight = game->viewport.width / aspectRatio; - int clipX = 0, clipY = (game->viewport.height - clipHeight) / 2; - if (clipY <= 0) { - clipHeight = game->viewport.height; - clipWidth = game->viewport.height * aspectRatio; - clipX = (game->viewport.width - clipWidth) / 2; - clipY = 0; - } - al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight); - - ALLEGRO_TRANSFORM projection; - al_build_transform(&projection, clipX, clipY, 1, 1, 0.0f); - al_use_transform(&projection); - game->viewport.width = clipWidth; - game->viewport.height = clipHeight; - } else if ((atoi(GetConfigOptionDefault(game, "SuperDerpy", "rotate", "1"))) && (game->viewport.height > game->viewport.width)) { - ALLEGRO_TRANSFORM projection; - al_identity_transform(&projection); - al_rotate_transform(&projection, 0.5*ALLEGRO_PI); - al_translate_transform(&projection, game->viewport.width, 0); - al_use_transform(&projection); - int temp = game->viewport.height; - game->viewport.height = game->viewport.width; - game->viewport.width = temp; - } -} - -int Console_Load(struct Game *game) { - game->_priv.font_console = NULL; - game->_priv.console = NULL; - game->_priv.font_console = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"),game->viewport.height*0.018,0 ); - if (game->viewport.height*0.022 >= 16) { - game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/PerfectDOSVGA437.ttf"),16,0 ); - } else { - game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"),game->viewport.height*0.022,0 ); - } - game->_priv.font = al_load_ttf_font(GetDataFilePath(game, "fonts/ShadowsIntoLight.ttf"),game->viewport.height*0.09,0 ); - game->_priv.console = al_create_bitmap(game->viewport.width, game->viewport.height*0.12); - al_set_target_bitmap(game->_priv.console); - al_clear_to_color(al_map_rgba(0,0,0,80)); - al_set_target_bitmap(al_get_backbuffer(game->display)); - return 0; -} - -void Console_Unload(struct Game *game) { - al_destroy_font(game->_priv.font); - al_destroy_font(game->_priv.font_console); - al_destroy_bitmap(game->_priv.console); -} - void derp(int sig) { - write(STDERR_FILENO, "Segmentation fault\n", 19); - write(STDERR_FILENO, "I just don't know what went wrong!\n", 35); + int __attribute__((unused)) n = write(STDERR_FILENO, "Segmentation fault\nI just don't know what went wrong!\n", 54); abort(); } @@ -151,7 +78,7 @@ int main(int argc, char **argv){ srand(time(NULL)); al_set_org_name("Super Derpy"); - al_set_app_name("Muffin Attack"); + al_set_app_name("Radio Edit"); if(!al_init()) { fprintf(stderr, "failed to initialize allegro!\n"); @@ -169,14 +96,14 @@ int main(int argc, char **argv){ game._priv.font_bsod = NULL; game._priv.console = NULL; - game.config.fullscreen = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fullscreen", "1")); - game.config.music = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "music", "7")); + game.config.fullscreen = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fullscreen", "0")); + game.config.music = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "music", "10")); game.config.voice = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "voice", "10")); game.config.fx = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fx", "10")); game.config.debug = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "debug", "0")); - game.config.width = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "width", "800")); + game.config.width = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "width", "1280")); if (game.config.width<320) game.config.width=320; - game.config.height = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "height", "450")); + game.config.height = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "height", "720")); if (game.config.height<180) game.config.height=180; if(!al_init_image_addon()) { @@ -217,6 +144,9 @@ int main(int argc, char **argv){ else al_set_new_display_flags(ALLEGRO_WINDOWED); al_set_new_display_option(ALLEGRO_VSYNC, 2-atoi(GetConfigOptionDefault(&game, "SuperDerpy", "vsync", "1")), ALLEGRO_SUGGEST); al_set_new_display_option(ALLEGRO_OPENGL, atoi(GetConfigOptionDefault(&game, "SuperDerpy", "opengl", "1")), ALLEGRO_SUGGEST); +#ifdef ALLEGRO_WINDOWS + al_set_new_window_position(20, 40); // workaround nasty Windows bug with window being created off-screen +#endif game.display = al_create_display(game.config.width, game.config.height); if(!game.display) { @@ -226,20 +156,17 @@ int main(int argc, char **argv){ SetupViewport(&game); - int ret = Console_Load(&game); - if (ret!=0) return ret; - PrintConsole(&game, "Viewport %dx%d", game.viewport.width, game.viewport.height); - ALLEGRO_BITMAP *icon = al_load_bitmap(GetDataFilePath(&game, "icons/superderpy.png")); - al_set_window_title(game.display, "Super Derpy: Muffin Attack"); + ALLEGRO_BITMAP *icon = al_load_bitmap(GetDataFilePath(&game, "icons/radioedit.png")); + al_set_window_title(game.display, "Radio Edit"); al_set_display_icon(game.display, icon); al_destroy_bitmap(icon); if (game.config.fullscreen) al_hide_mouse_cursor(game.display); al_inhibit_screensaver(true); - al_set_new_bitmap_flags(ALLEGRO_MAG_LINEAR | ALLEGRO_MIN_LINEAR); + al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR); game._priv.gamestates = NULL; @@ -250,7 +177,7 @@ int main(int argc, char **argv){ return -1; } - game.audio.v = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); + game.audio.v = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); game.audio.mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); game.audio.fx = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); game.audio.music = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); @@ -268,15 +195,15 @@ int main(int argc, char **argv){ game._priv.showconsole = game.config.debug; - al_flip_display(); al_clear_to_color(al_map_rgb(0,0,0)); - al_wait_for_vsync(); game._priv.timer = al_create_timer(ALLEGRO_BPS_TO_SECS(60)); // logic timer if(!game._priv.timer) { FatalError(&game, true, "Failed to create logic timer."); return -1; } al_register_event_source(game._priv.event_queue, al_get_timer_event_source(game._priv.timer)); + + al_flip_display(); al_start_timer(game._priv.timer); setlocale(LC_NUMERIC, "C"); @@ -306,24 +233,20 @@ int main(int argc, char **argv){ free(gamestate); char libname[1024] = {}; - snprintf(libname, 1024, "libsuperderpy-%s-loading.so", "muffinattack"); + snprintf(libname, 1024, "libsuperderpy-%s-loading" LIBRARY_EXTENTION, "radioedit"); void *handle = dlopen(libname, RTLD_NOW); if (!handle) { FatalError(&game, true, "Error while initializing loading screen %s", dlerror()); exit(1); } else { - void gs_error() { - FatalError(&game, true, "Error on resolving loading symbol: %s", dlerror()); - exit(1); - } + #define GS_LOADINGERROR FatalError(&game, true, "Error on resolving loading symbol: %s", dlerror()); exit(1); - if (!(game._priv.loading.Draw = dlsym(handle, "Draw"))) { gs_error(); } - - if (!(game._priv.loading.Load = dlsym(handle, "Load"))) { gs_error(); } - if (!(game._priv.loading.Start = dlsym(handle, "Start"))) { gs_error(); } - if (!(game._priv.loading.Stop = dlsym(handle, "Stop"))) { gs_error(); } - if (!(game._priv.loading.Unload = dlsym(handle, "Unload"))) { gs_error(); } + if (!(game._priv.loading.Draw = dlsym(handle, "Draw"))) { GS_LOADINGERROR; } + if (!(game._priv.loading.Load = dlsym(handle, "Load"))) { GS_LOADINGERROR; } + if (!(game._priv.loading.Start = dlsym(handle, "Start"))) { GS_LOADINGERROR; } + if (!(game._priv.loading.Stop = dlsym(handle, "Stop"))) { GS_LOADINGERROR; } + if (!(game._priv.loading.Unload = dlsym(handle, "Unload"))) { GS_LOADINGERROR; } } game._priv.loading.data = (*game._priv.loading.Load)(&game); @@ -370,7 +293,7 @@ int main(int argc, char **argv){ al_stop_timer(game._priv.timer); // TODO: take proper game name char libname[1024]; - snprintf(libname, 1024, "libsuperderpy-%s-%s.so", "muffinattack", tmp->name); + snprintf(libname, 1024, "libsuperderpy-%s-%s" LIBRARY_EXTENTION, "radioedit", tmp->name); tmp->handle = dlopen(libname,RTLD_NOW); if (!tmp->handle) { //PrintConsole(&game, "Error while loading gamestate \"%s\": %s", tmp->name, dlerror()); @@ -380,27 +303,22 @@ int main(int argc, char **argv){ tmp->pending_start = false; } else { - void gs_error() { - FatalError(&game, true, "Error on resolving gamestate symbol: %s", dlerror()); - tmp->pending_load = false; - tmp->pending_start = false; - tmp=tmp->next; - } +#define GS_ERROR FatalError(&game, false, "Error on resolving gamestate symbol: %s", dlerror()); tmp->pending_load = false; tmp->pending_start = false; tmp=tmp->next; continue; - if (!(tmp->api.Gamestate_Draw = dlsym(tmp->handle, "Gamestate_Draw"))) { gs_error(); continue; } - if (!(tmp->api.Gamestate_Logic = dlsym(tmp->handle, "Gamestate_Logic"))) { gs_error(); continue; } + if (!(tmp->api.Gamestate_Draw = dlsym(tmp->handle, "Gamestate_Draw"))) { GS_ERROR; } + if (!(tmp->api.Gamestate_Logic = dlsym(tmp->handle, "Gamestate_Logic"))) { GS_ERROR; } - if (!(tmp->api.Gamestate_Load = dlsym(tmp->handle, "Gamestate_Load"))) { gs_error(); continue; } - if (!(tmp->api.Gamestate_Start = dlsym(tmp->handle, "Gamestate_Start"))) { gs_error(); continue; } - if (!(tmp->api.Gamestate_Pause = dlsym(tmp->handle, "Gamestate_Pause"))) { gs_error(); continue; } - if (!(tmp->api.Gamestate_Resume = dlsym(tmp->handle, "Gamestate_Resume"))) { gs_error(); continue; } - if (!(tmp->api.Gamestate_Stop = dlsym(tmp->handle, "Gamestate_Stop"))) { gs_error(); continue; } - if (!(tmp->api.Gamestate_Unload = dlsym(tmp->handle, "Gamestate_Unload"))) { gs_error(); continue; } + if (!(tmp->api.Gamestate_Load = dlsym(tmp->handle, "Gamestate_Load"))) { GS_ERROR; } + if (!(tmp->api.Gamestate_Start = dlsym(tmp->handle, "Gamestate_Start"))) { GS_ERROR; } + if (!(tmp->api.Gamestate_Pause = dlsym(tmp->handle, "Gamestate_Pause"))) { GS_ERROR; } + if (!(tmp->api.Gamestate_Resume = dlsym(tmp->handle, "Gamestate_Resume"))) { GS_ERROR; } + if (!(tmp->api.Gamestate_Stop = dlsym(tmp->handle, "Gamestate_Stop"))) { GS_ERROR; } + if (!(tmp->api.Gamestate_Unload = dlsym(tmp->handle, "Gamestate_Unload"))) { GS_ERROR; } - if (!(tmp->api.Gamestate_ProcessEvent = dlsym(tmp->handle, "Gamestate_ProcessEvent"))) { gs_error(); continue; } - if (!(tmp->api.Gamestate_Reload = dlsym(tmp->handle, "Gamestate_Reload"))) { gs_error(); continue; } + if (!(tmp->api.Gamestate_ProcessEvent = dlsym(tmp->handle, "Gamestate_ProcessEvent"))) { GS_ERROR; } + if (!(tmp->api.Gamestate_Reload = dlsym(tmp->handle, "Gamestate_Reload"))) { GS_ERROR; } - if (!(tmp->api.Gamestate_ProgressCount = dlsym(tmp->handle, "Gamestate_ProgressCount"))) { gs_error(); continue; } + if (!(tmp->api.Gamestate_ProgressCount = dlsym(tmp->handle, "Gamestate_ProgressCount"))) { GS_ERROR; } int p = 0; void progress(struct Game *game) { @@ -420,7 +338,7 @@ int main(int argc, char **argv){ } DrawConsole(&game); al_flip_display(); - tmp->data = (*tmp->api.Gamestate_Load)(&game, &progress); + tmp->data = (*tmp->api.Gamestate_Load)(&game, &progress); // feel free to replace "progress" with empty function if you want to compile with clang loaded++; tmp->loaded = true; @@ -437,7 +355,7 @@ int main(int argc, char **argv){ while (tmp) { - if ((tmp->pending_start) && (!tmp->started) && (tmp->loaded)) { + if ((tmp->pending_start) && (!tmp->started) && (tmp->loaded)) { PrintConsole(&game, "Starting gamestate \"%s\"...", tmp->name); al_stop_timer(game._priv.timer); (*tmp->api.Gamestate_Start)(&game, tmp->data); @@ -471,11 +389,14 @@ int main(int argc, char **argv){ else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { break; } - #ifdef ALLEGRO_MACOSX + else if(ev.type == ALLEGRO_EVENT_DISPLAY_FOUND) { + SetupViewport(&game); + } +#ifdef ALLEGRO_MACOSX else if ((ev.type == ALLEGRO_EVENT_KEY_DOWN) && (ev.keyboard.keycode == 104)) { //TODO: report to upstream - #else +#else else if ((ev.type == ALLEGRO_EVENT_KEY_DOWN) && (ev.keyboard.keycode == ALLEGRO_KEY_TILDE)) { - #endif +#endif game._priv.showconsole = !game._priv.showconsole; } else if ((ev.type == ALLEGRO_EVENT_KEY_DOWN) && (game.config.debug) && (ev.keyboard.keycode == ALLEGRO_KEY_F1)) { @@ -502,7 +423,7 @@ int main(int argc, char **argv){ } else if ((ev.type == ALLEGRO_EVENT_KEY_DOWN) && (game.config.debug) && (ev.keyboard.keycode == ALLEGRO_KEY_F12)) { ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH); char filename[255] = { }; - snprintf(filename, 255, "SuperDerpy_%ld_%ld.png", time(NULL), clock()); + snprintf(filename, 255, "RadioEdit_%ld_%ld.png", time(NULL), clock()); al_set_path_filename(path, filename); al_save_bitmap(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP), al_get_backbuffer(game.display)); PrintConsole(&game, "Screenshot stored in %s", al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); diff --git a/src/main.h b/src/main.h index 78bccd1..e7ccef1 100644 --- a/src/main.h +++ b/src/main.h @@ -35,6 +35,8 @@ struct Gamestate; struct Game { ALLEGRO_DISPLAY *display; /*!< Main Allegro display. */ + ALLEGRO_TRANSFORM projection; + struct { int width; /*!< Actual available width of viewport. */ int height; /*!< Actual available height of viewport. */ diff --git a/src/timeline.c b/src/timeline.c index 188eaf2..5977d48 100644 --- a/src/timeline.c +++ b/src/timeline.c @@ -226,6 +226,7 @@ struct TM_Action* TM_AddAction(struct Timeline* timeline, bool (*func)(struct Ga } struct TM_Action* TM_AddBackgroundAction(struct Timeline* timeline, bool (*func)(struct Game*, struct TM_Action*, enum TM_ActionState), struct TM_Arguments* args, int delay, char* name) { + // FIXME: some action wasn't freed! struct TM_Action *action = malloc(sizeof(struct TM_Action)); if (timeline->background) { struct TM_Action *pom = timeline->background; @@ -297,8 +298,9 @@ void TM_CleanQueue(struct Timeline* timeline) { while (pom!=NULL) { if (pom->active) { if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY); - else { - if (pom->timer) al_destroy_timer(pom->timer); + if (pom->timer) { + al_stop_timer(pom->timer); + al_destroy_timer(pom->timer); } } else { TM_DestroyArgs(pom->arguments); @@ -311,23 +313,25 @@ void TM_CleanQueue(struct Timeline* timeline) { free(pom->name); free(pom); tmp2 = tmp; - if (!tmp) pom=timeline->background->next; + if (!tmp) pom=timeline->queue->next; else pom=tmp->next; tmp = tmp2; } } + // TODO: it shouldn't be needed, but is. Debug! + timeline->queue = NULL; } void TM_CleanBackgroundQueue(struct Timeline* timeline) { PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning background queue", timeline->name); - struct TM_Action *tmp, *tmp2, *pom = timeline->queue; + struct TM_Action *tmp, *tmp2, *pom = timeline->background; tmp = NULL; - pom=timeline->background; while (pom!=NULL) { if (pom->active) { if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY); - else { - if (pom->timer) al_destroy_timer(pom->timer); + if (pom->timer) { + al_stop_timer(pom->timer); + al_destroy_timer(pom->timer); } } else { TM_DestroyArgs(pom->arguments); @@ -345,6 +349,8 @@ void TM_CleanBackgroundQueue(struct Timeline* timeline) { tmp = tmp2; } } + // TODO: it shouldn't be needed, but is. Debug! + timeline->background = NULL; } void TM_Destroy(struct Timeline* timeline) { @@ -363,6 +369,8 @@ struct TM_Arguments* TM_AddToArgs(struct TM_Arguments* args, int num, ...) { struct TM_Arguments* tmp = args; for(i = 0; i < num; i++) { if (!tmp) { + //FIXME: on some occasions some arguments weren't freed. Check it out. + // TM_AddQueuedBackgroundAction? possibly not only. tmp = malloc(sizeof(struct TM_Arguments)); tmp->value = va_arg(ap, void*); tmp->next = NULL; diff --git a/src/timeline.h b/src/timeline.h index 26ab033..8017bfb 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -39,11 +39,11 @@ enum TM_ActionState { /*! \brief Timeline structure. */ struct Timeline { - struct TM_Action *queue; /*!< Main timeline queue. */ - struct TM_Action *background; /*!< Background queue. */ - char* name; /*!< Name of the timeline. */ - unsigned int lastid; /*!< Last ID given to timeline action. */ - struct Game* game; /*!< Reference to the game object. */ + struct TM_Action *queue; /*!< Main timeline queue. */ + struct TM_Action *background; /*!< Background queue. */ + char* name; /*!< Name of the timeline. */ + unsigned int lastid; /*!< Last ID given to timeline action. */ + struct Game* game; /*!< Reference to the game object. */ }; /*! \brief Arguments for TM_Action. */ diff --git a/src/utils.c b/src/utils.c index 1a404f5..867a219 100644 --- a/src/utils.c +++ b/src/utils.c @@ -20,11 +20,98 @@ */ #include +#include #include "stdio.h" #include "config.h" +#include "string.h" #include "math.h" #include "utils.h" +char* strdup(const char *str) { + int n = strlen(str) + 1; + char *dup = malloc(n); + if (dup) { strcpy(dup, str); } + return dup; +} + +void DrawConsole(struct Game *game) { + if (game->_priv.showconsole) { + ALLEGRO_TRANSFORM trans; + al_identity_transform(&trans); + int clipX, clipY, clipWidth, clipHeight; + al_get_clipping_rectangle(&clipX, &clipY, &clipWidth, &clipHeight); + al_use_transform(&trans); + + al_draw_bitmap(game->_priv.console, clipX, clipY, 0); + double game_time = al_get_time(); + if(game_time - game->_priv.fps_count.old_time >= 1.0) { + game->_priv.fps_count.fps = game->_priv.fps_count.frames_done / (game_time - game->_priv.fps_count.old_time); + game->_priv.fps_count.frames_done = 0; + game->_priv.fps_count.old_time = game_time; + } + char sfps[6] = { }; + snprintf(sfps, 6, "%.0f", game->_priv.fps_count.fps); + al_use_transform(&game->projection); + + DrawTextWithShadow(game->_priv.font, al_map_rgb(255,255,255), game->viewport.width*0.99, 0, ALLEGRO_ALIGN_RIGHT, sfps); + + } + game->_priv.fps_count.frames_done++; +} + +void Console_Load(struct Game *game) { + game->_priv.font_console = NULL; + game->_priv.console = NULL; + game->_priv.font_console = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"),al_get_display_height(game->display)*0.025,0 ); + if (al_get_display_height(game->display)*0.025 >= 16) { + game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/PerfectDOSVGA437.ttf"),16,0 ); + } else { + game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), al_get_display_height(game->display)*0.025,0 ); + } + game->_priv.console = al_create_bitmap((al_get_display_width(game->display) / 320) * 320, al_get_font_line_height(game->_priv.font_console)*5); + game->_priv.font = al_load_ttf_font(GetDataFilePath(game, "fonts/MonkeyIsland.ttf"), 0 ,0 ); + al_set_target_bitmap(game->_priv.console); + al_clear_to_color(al_map_rgba(0,0,0,80)); + al_set_target_bitmap(al_get_backbuffer(game->display)); +} + +void Console_Unload(struct Game *game) { + al_destroy_font(game->_priv.font); + al_destroy_font(game->_priv.font_console); + al_destroy_bitmap(game->_priv.console); +} + + +void SetupViewport(struct Game *game) { + game->viewport.width = 320; + game->viewport.height = 180; + + int resolution = al_get_display_width(game->display) / 320; + if (al_get_display_height(game->display) / 180 < resolution) resolution = al_get_display_height(game->display) / 180; + if (resolution < 1) resolution = 1; + + if (atoi(GetConfigOptionDefault(game, "SuperDerpy", "letterbox", "1"))) { + int clipWidth = 320 * resolution, clipHeight = 180 * resolution; + int clipX = (al_get_display_width(game->display) - clipWidth) / 2, clipY = (al_get_display_height(game->display) - clipHeight) / 2; + al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight); + + al_build_transform(&game->projection, clipX, clipY, resolution, resolution, 0.0f); + al_use_transform(&game->projection); + + } else if ((atoi(GetConfigOptionDefault(game, "SuperDerpy", "rotate", "1"))) && (game->viewport.height > game->viewport.width)) { + al_identity_transform(&game->projection); + al_rotate_transform(&game->projection, 0.5*ALLEGRO_PI); + al_translate_transform(&game->projection, game->viewport.width, 0); + al_scale_transform(&game->projection, resolution, resolution); + al_use_transform(&game->projection); + int temp = game->viewport.height; + game->viewport.height = game->viewport.width; + game->viewport.width = temp; + } + if (game->_priv.console) Console_Unload(game); + Console_Load(game); +} + void DrawVerticalGradientRect(float x, float y, float w, float h, ALLEGRO_COLOR top, ALLEGRO_COLOR bottom) { ALLEGRO_VERTEX v[] = { {.x = x, .y = y, .z = 0, .color = top}, @@ -48,41 +135,12 @@ void DrawTextWithShadow(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float al_draw_text(font, color, (int)x, (int)y, flags, text); } -void FadeGamestate(struct Game *game, bool in) { - //TODO: reimplement -/* ALLEGRO_BITMAP* bitmap = al_create_bitmap(game->viewportWidth, game->viewportHeight); - al_set_target_bitmap(bitmap); - al_clear_to_color(al_map_rgb(0,0,0)); - al_set_target_bitmap(al_get_backbuffer(game->display)); - float fadeloop; - if (in) { - fadeloop = 255; - } else { - fadeloop = 0; - } - while ((in && fadeloop>=0) || (!in && fadeloop<255)) { - ALLEGRO_EVENT ev; - al_wait_for_event(game->event_queue, &ev); - if ((ev.type == ALLEGRO_EVENT_TIMER) && (ev.timer.source == game->timer)) { - LogicGamestates(game); - if (in) { - fadeloop-=10; - } else { - fadeloop+=10; - } - } - if (al_is_event_queue_empty(game->event_queue)) { - DrawGamestates(game); - al_draw_tinted_bitmap(bitmap,al_map_rgba_f(1,1,1,fadeloop/255.0),0,0,0); - DrawConsole(game); - al_flip_display(); - } - } - al_destroy_bitmap(bitmap); - al_clear_to_color(al_map_rgb(0,0,0)); - if (in) { - DrawGamestates(game); - }*/ +/* linear filtering code written by SiegeLord */ +ALLEGRO_COLOR interpolate(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2, float frac) { + return al_map_rgba_f(c1.r + frac * (c2.r - c1.r), + c1.g + frac * (c2.g - c1.g), + c1.b + frac * (c2.b - c1.b), + c1.a + frac * (c2.a - c1.a)); } /*! \brief Scales bitmap using software linear filtering method to current target. */ @@ -95,15 +153,6 @@ void ScaleBitmap(ALLEGRO_BITMAP* source, int width, int height) { al_lock_bitmap(al_get_target_bitmap(), ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); al_lock_bitmap(source, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); - /* linear filtering code written by SiegeLord */ - - ALLEGRO_COLOR interpolate(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2, float frac) { - return al_map_rgba_f(c1.r + frac * (c2.r - c1.r), - c1.g + frac * (c2.g - c1.g), - c1.b + frac * (c2.b - c1.b), - c1.a + frac * (c2.a - c1.a)); - } - for (y = 0; y < height; y++) { float pixy = ((float)y / height) * ((float)al_get_bitmap_height(source) - 1); float pixy_f = floor(pixy); @@ -133,33 +182,23 @@ ALLEGRO_BITMAP* LoadScaledBitmap(struct Game *game, char* filename, int width, i al_set_target_bitmap(target); al_clear_to_color(al_map_rgba(0,0,0,0)); char* origfn = GetDataFilePath(game, filename); - void GenerateBitmap() { - if (memoryscale) al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); - source = al_load_bitmap( origfn ); - if (memoryscale) { - al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); - ScaleBitmap(source, width, height); - } - else { - al_draw_scaled_bitmap(source, 0, 0, al_get_bitmap_width(source), al_get_bitmap_height(source), 0, 0, width, height, 0); - } - /*al_save_bitmap(cachefn, target); - PrintConsole(game, "Cache bitmap %s generated.", filename);*/ - al_destroy_bitmap(source); + if (memoryscale) al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP); + + source = al_load_bitmap( origfn ); + if (memoryscale) { + al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR); + ScaleBitmap(source, width, height); + } + else { + al_draw_scaled_bitmap(source, 0, 0, al_get_bitmap_width(source), al_get_bitmap_height(source), 0, 0, width, height, 0); } - /*source = al_load_bitmap( cachefn ); - if (source) { - if ((al_get_bitmap_width(source)!=width) || (al_get_bitmap_height(source)!=height)) { - al_destroy_bitmap(source);*/ - GenerateBitmap(); + al_destroy_bitmap(source); + free(origfn); return target; - /* } - return source; - } else GenerateBitmap(); - return target;*/ + } void FatalError(struct Game *game, bool fatal, char* format, ...) { @@ -179,6 +218,10 @@ void FatalError(struct Game *game, bool fatal, char* format, ...) { PrintConsole(game, text); } + ALLEGRO_TRANSFORM trans; + al_identity_transform(&trans); + al_use_transform(&trans); + if (!game->_priv.font_bsod) { game->_priv.font_bsod = al_create_builtin_font(); } @@ -186,7 +229,7 @@ void FatalError(struct Game *game, bool fatal, char* format, ...) { al_set_target_backbuffer(game->display); al_clear_to_color(al_map_rgb(0,0,170)); al_flip_display(); - al_rest(1.1); + al_rest(0.6); bool done = false; while (!done) { @@ -194,32 +237,32 @@ void FatalError(struct Game *game, bool fatal, char* format, ...) { al_set_target_backbuffer(game->display); al_clear_to_color(al_map_rgb(0,0,170)); - char *header = "SUPER DERPY"; + char *header = "RADIO EDIT"; - al_draw_filled_rectangle(game->viewport.width/2 - al_get_text_width(game->_priv.font_bsod, header)/2 - 4, (int)(game->viewport.height * 0.32), 4 + game->viewport.width/2 + al_get_text_width(game->_priv.font_bsod, header)/2, (int)(game->viewport.height * 0.32) + al_get_font_line_height(game->_priv.font_bsod), al_map_rgb(170,170,170)); + al_draw_filled_rectangle(al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header)/2 - 4, (int)(al_get_display_height(game->display) * 0.32), 4 + al_get_display_width(game->display)/2 + al_get_text_width(game->_priv.font_bsod, header)/2, (int)(al_get_display_height(game->display) * 0.32) + al_get_font_line_height(game->_priv.font_bsod), al_map_rgb(170,170,170)); - al_draw_text(game->_priv.font_bsod, al_map_rgb(0, 0, 170), game->viewport.width/2, (int)(game->viewport.height * 0.32), ALLEGRO_ALIGN_CENTRE, header); + al_draw_text(game->_priv.font_bsod, al_map_rgb(0, 0, 170), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32), ALLEGRO_ALIGN_CENTRE, header); char *header2 = "A fatal exception 0xD3RP has occured at 0028:M00F11NZ in GST SD(01) +"; - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2, (int)(game->viewport.height * 0.32+2*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, header2); - al_draw_textf(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(game->viewport.height * 0.32+3*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "%p and system just doesn't know what went wrong.", game); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+2*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, header2); + al_draw_textf(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+3*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "%p and system just doesn't know what went wrong.", game); - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2, (int)(game->viewport.height * 0.32+5*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, text); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+5*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, text); - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(game->viewport.height * 0.32+7*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Press any key to terminate this error."); - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(game->viewport.height * 0.32+8*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Press any key to destroy all muffins in the world."); - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(game->viewport.height * 0.32+9*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Just kidding, please press any key anyway."); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+7*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Press any key to terminate this error."); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+8*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Press any key to destroy all muffins in the world."); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+9*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Just kidding, please press any key anyway."); if (fatal) { - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(game->viewport.height * 0.32+11*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "This is fatal error. My bad."); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+11*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "This is fatal error. My bad."); - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2, (int)(game->viewport.height * 0.32+13*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "Press any key to quit _"); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+13*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "Press any key to quit _"); } else { - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(game->viewport.height * 0.32+11*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "Anything I can do to help?"); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2 - al_get_text_width(game->_priv.font_bsod, header2)/2, (int)(al_get_display_height(game->display) * 0.32+11*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "Anything I can do to help?"); - al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), game->viewport.width/2, (int)(game->viewport.height * 0.32+13*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "Press any key to continue _"); + al_draw_text(game->_priv.font_bsod, al_map_rgb(255,255,255), al_get_display_width(game->display)/2, (int)(al_get_display_height(game->display) * 0.32+13*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_CENTRE, "Press any key to continue _"); } al_flip_display(); @@ -235,12 +278,31 @@ void FatalError(struct Game *game, bool fatal, char* format, ...) { } } } + al_use_transform(&game->projection); +} + +void TestPath(char* filename, char* subpath, char** result) { + if (*result) return; //already found + ALLEGRO_PATH *tail = al_create_path(filename); + ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH); + ALLEGRO_PATH *data = al_create_path(subpath); + al_join_paths(path, data); + al_join_paths(path, tail); + //printf("Testing for %s\n", al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); + if (al_filename_exists(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP))) { + *result = strdup(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); + } + al_destroy_path(tail); + al_destroy_path(data); + al_destroy_path(path); } char* GetDataFilePath(struct Game *game, char* filename) { //TODO: support for current game + //FIXME: strdups result in memory leaks! + char *result = 0; if (al_filename_exists(filename)) { @@ -254,24 +316,13 @@ char* GetDataFilePath(struct Game *game, char* filename) { return strdup(origfn); } - void TestPath(char* subpath) { - ALLEGRO_PATH *tail = al_create_path(filename); - ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH); - ALLEGRO_PATH *data = al_create_path(subpath); - al_join_paths(path, data); - al_join_paths(path, tail); - //printf("Testing for %s\n", al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); - if (al_filename_exists(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP))) { - result = strdup(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); - } - al_destroy_path(tail); - al_destroy_path(data); - al_destroy_path(path); - } - TestPath("../share/superderpy/data/"); - TestPath("../data/"); - TestPath("../Resources/data/"); - TestPath("data/"); + TestPath(filename, "data/", &result); + TestPath(filename, "../share/radioedit/data/", &result); + TestPath(filename, "../data/", &result); +#ifdef ALLEGRO_MACOSX + TestPath(filename, "../Resources/data/", &result); + TestPath(filename, "../Resources/gamestates/", &result); +#endif if (!result) { FatalError(game, true, "Could not find data file: %s!", filename); @@ -280,7 +331,6 @@ char* GetDataFilePath(struct Game *game, char* filename) { return result; } - void PrintConsole(struct Game *game, char* format, ...) { va_list vl; va_start(vl, format); @@ -288,6 +338,8 @@ void PrintConsole(struct Game *game, char* format, ...) { vsnprintf(text, 1024, format, vl); va_end(vl); if (game->config.debug) { printf("%s\n", text); fflush(stdout); } + if (!game->_priv.console) return; + if ((!game->config.debug) && (!game->_priv.showconsole)) return; ALLEGRO_BITMAP *con = al_create_bitmap(al_get_bitmap_width(game->_priv.console), al_get_bitmap_height(game->_priv.console)); al_set_target_bitmap(con); al_clear_to_color(al_map_rgba(0,0,0,80)); @@ -299,3 +351,180 @@ void PrintConsole(struct Game *game, char* format, ...) { al_set_target_bitmap(al_get_backbuffer(game->display)); al_destroy_bitmap(con); } + + +void SelectSpritesheet(struct Game *game, struct Character *character, char *name) { + struct Spritesheet *tmp = character->spritesheets; + PrintConsole(game, "Selecting spritesheet for %s: %s", character->name, name); + if (!tmp) { + PrintConsole(game, "ERROR: No spritesheets registered for %s!", character->name); + return; + } + while (tmp) { + if (!strcmp(tmp->name, name)) { + character->spritesheet = tmp; + if (character->successor) free(character->successor); + if (tmp->successor) { + character->successor = strdup(tmp->successor); + } else { + character->successor = NULL; + } + character->pos = 0; + if (character->bitmap) { + if ((al_get_bitmap_width(character->bitmap) != tmp->width / tmp->cols) || (al_get_bitmap_height(character->bitmap) != tmp->height / tmp->rows)) { + al_destroy_bitmap(character->bitmap); + character->bitmap = al_create_bitmap(tmp->width / tmp->cols, tmp->height / tmp->rows); + } + } else { + character->bitmap = al_create_bitmap(tmp->width / tmp->cols, tmp->height / tmp->rows); + } + PrintConsole(game, "SUCCESS: Spritesheet for %s activated: %s (%dx%d)", character->name, character->spritesheet->name, al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap)); + return; + } + tmp = tmp->next; + } + PrintConsole(game, "ERROR: No spritesheets registered for %s with given name: %s", character->name, name); + return; +} + +void ChangeSpritesheet(struct Game *game, struct Character *character, char* name) { + if (character->successor) free(character->successor); + character->successor = strdup(name); +} + +void LoadSpritesheets(struct Game *game, struct Character *character) { + PrintConsole(game, "Loading spritesheets for character %s...", character->name); + struct Spritesheet *tmp = character->spritesheets; + while (tmp) { + if (!tmp->bitmap) { + char filename[255] = { }; + snprintf(filename, 255, "sprites/%s/%s.png", character->name, tmp->name); + tmp->bitmap = al_load_bitmap(GetDataFilePath(game, filename)); + tmp->width = al_get_bitmap_width(tmp->bitmap); + tmp->height = al_get_bitmap_height(tmp->bitmap); + } + tmp = tmp->next; + } +} + +void UnloadSpritesheets(struct Game *game, struct Character *character) { + PrintConsole(game, "Unloading spritesheets for character %s...", character->name); + struct Spritesheet *tmp = character->spritesheets; + while (tmp) { + if (tmp->bitmap) al_destroy_bitmap(tmp->bitmap); + tmp->bitmap = NULL; + tmp = tmp->next; + } +} + +void RegisterSpritesheet(struct Game *game, struct Character *character, char* name) { + struct Spritesheet *s = character->spritesheets; + while (s) { + if (!strcmp(s->name, name)) { + //PrintConsole(game, "%s spritesheet %s already registered!", character->name, name); + return; + } + s = s->next; + } + PrintConsole(game, "Registering %s spritesheet: %s", character->name, name); + char filename[255] = { }; + snprintf(filename, 255, "sprites/%s/%s.ini", character->name, name); + ALLEGRO_CONFIG *config = al_load_config_file(GetDataFilePath(game, filename)); + s = malloc(sizeof(struct Spritesheet)); + s->name = strdup(name); + s->bitmap = NULL; + s->cols = atoi(al_get_config_value(config, "", "cols")); + s->rows = atoi(al_get_config_value(config, "", "rows")); + s->blanks = atoi(al_get_config_value(config, "", "blanks")); + s->delay = atof(al_get_config_value(config, "", "delay")); + s->kill = false; + const char *kill = al_get_config_value(config, "", "kill"); + if (kill) s->kill = atoi(kill); + s->successor=NULL; + const char* successor = al_get_config_value(config, "", "successor"); + if (successor) { + s->successor = malloc(255*sizeof(char)); + strncpy(s->successor, successor, 255); + } + s->next = character->spritesheets; + character->spritesheets = s; + al_destroy_config(config); +} + +struct Character* CreateCharacter(struct Game *game, char* name) { + PrintConsole(game, "Creating character %s...", name); + struct Character *character = malloc(sizeof(struct Character)); + character->name = strdup(name); + character->angle = 0; + character->bitmap = NULL; + character->data = NULL; + character->pos = 0; + character->pos_tmp = 0; + character->x = -1; + character->y = -1; + character->spritesheets = NULL; + character->spritesheet = NULL; + character->successor = NULL; + character->shared = false; + character->dead = false; + return character; +} + +void DestroyCharacter(struct Game *game, struct Character *character) { + PrintConsole(game, "Destroying character %s...", character->name); + if (!character->shared) { + struct Spritesheet *tmp, *s = character->spritesheets; + tmp = s; + while (s) { + tmp = s; + s = s->next; + if (tmp->bitmap) al_destroy_bitmap(tmp->bitmap); + if (tmp->successor) free(tmp->successor); + free(tmp->name); + free(tmp); + } + } + + if (character->bitmap) al_destroy_bitmap(character->bitmap); + if (character->successor) free(character->successor); + free(character->name); + free(character); +} + +void AnimateCharacter(struct Game *game, struct Character *character, float speed_modifier) { + if (character->dead) return; + if (speed_modifier) { + character->pos_tmp++; + if (character->pos_tmp >= character->spritesheet->delay / speed_modifier) { + character->pos_tmp = 0; + character->pos++; + } + if (character->pos>=character->spritesheet->cols*character->spritesheet->rows-character->spritesheet->blanks) { + character->pos=0; + if (character->spritesheet->kill) { + character->dead = true; + } else if (character->successor) { + SelectSpritesheet(game, character, character->successor); + } + } + } +} + +void MoveCharacter(struct Game *game, struct Character *character, float x, float y, float angle) { + if (character->dead) return; + character->x += x; + character->y += y; + character->angle += angle; +} + +void SetCharacterPosition(struct Game *game, struct Character *character, int x, int y, float angle) { + if (character->dead) return; + character->x = x; + character->y = y; + character->angle = angle; +} + +void DrawCharacter(struct Game *game, struct Character *character, ALLEGRO_COLOR tilt, int flags) { + if (character->dead) return; + al_draw_tinted_bitmap_region(character->spritesheet->bitmap, tilt, al_get_bitmap_width(character->bitmap)*(character->pos%character->spritesheet->cols),al_get_bitmap_height(character->bitmap)*(character->pos/character->spritesheet->cols),al_get_bitmap_width(character->bitmap), al_get_bitmap_height(character->bitmap), character->x, character->y, flags); +} diff --git a/src/utils.h b/src/utils.h index a69b8d6..5240eed 100644 --- a/src/utils.h +++ b/src/utils.h @@ -22,6 +22,32 @@ #include #include "main.h" +#ifdef ALLEGRO_WINDOWS +#define LIBRARY_EXTENTION ".dll" +#else +#define LIBRARY_EXTENTION ".so" +#endif + + +// hacks for "pixelness" +#define al_draw_bitmap(a,b,c,d) al_draw_bitmap(a,(int)(b), (int)(c), d) +#define al_draw_scaled_bitmap(a,b,c,d,e,f,g,h,i,j) al_draw_scaled_bitmap(a,b,c,d,e,(int)(f), (int)(g), (int)(h), (int)(i), j) +//#define al_draw_tinted_scaled_bitmap(a,tint,b,c,d,e,f,g,h,i,j) al_draw_tinted_scaled_bitmap(a,tint,(int)(b),(int)(c),(int)(d),(int)(e),(int)(f), (int)(g), (int)(h), (int)(i), j) +#define al_draw_rotated_bitmap(a,b,c,d,e,f,g) al_draw_rotated_bitmap(a,(int)(b),(int)(c),(int)(d),(int)(e), f, g) +#define al_draw_bitmap_region(a, b, c, d, e, f, g, h) al_draw_bitmap_region(a,(int)(b),(int)(c),(int)(d),(int)(e),(int)(f), (int)(g), h) +#define al_draw_tinted_bitmap_region(a, tint, b, c, d, e, f, g, h) al_draw_tinted_bitmap_region(a,tint,(int)(b),(int)(c),(int)(d),(int)(e),(int)(f), (int)(g), h) +#define al_draw_tinted_rotated_bitmap(a,tint,b,c,d,e,f,g) al_draw_tinted_rotated_bitmap(a,tint,(int)(b),(int)(c),(int)(d),(int)(e), f, g) +//#define al_draw_filled_rectangle +//#define al_draw_prim() +#define al_load_ttf_font(a,b,c) al_load_ttf_font(a, (int)(b / 8)*8 == 0 ? 8 : (int)(b / 8)*8, c) +#define al_draw_text(a,b,c,d,e,f) al_draw_text(a, b, (int)(c), (int)(d), e, f) + +char* strdup(const char *str); + +void SetupViewport(struct Game *game); +void Console_Unload(struct Game *game); +void DrawConsole(struct Game *game); + /*! \brief Draws rectangle filled with vertical gradient. */ void DrawVerticalGradientRect(float x, float y, float w, float h, ALLEGRO_COLOR top, ALLEGRO_COLOR bottom); /*! \brief Draws rectangle filled with horizontal gradient. */ @@ -36,12 +62,11 @@ void DrawTextWithShadow(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float /*! \brief Loads bitmap into memory and scales it with software linear filtering. */ ALLEGRO_BITMAP* LoadScaledBitmap(struct Game *game, char* filename, int width, int height); -/*! \brief Displays fade in or fade out animation on current gamestate. */ -void FadeGamestate(struct Game *game, bool in); - /*! \brief Finds path for data file. */ char* GetDataFilePath(struct Game *game, char* filename); +char* GetLibFilePath(struct Game *game, char* filename); + /*! \brief Print some message on game console. * * Draws message on console bitmap, so it'll be displayed when calling DrawConsole. @@ -51,3 +76,53 @@ char* GetDataFilePath(struct Game *game, char* filename); void PrintConsole(struct Game *game, char* format, ...); void FatalError(struct Game *game, bool exit, char* format, ...); + +/*! \brief Structure representing one spritesheet for character animation. */ +struct Spritesheet { + char* name; /*!< Name of the spritesheet (used in file paths). */ + ALLEGRO_BITMAP* bitmap; /*!< Spritesheet bitmap. */ + int rows; /*!< Number of rows in the spritesheet. */ + int cols; /*!< Number of columns in the spritesheet. */ + int blanks; /*!< Number of blank frames at the end of the spritesheet. */ + int width; + int height; + int delay; + bool kill; + float scale; /*!< Scale modifier of the frame. */ + char* successor; /*!< Name of animation successor. If it's not blank, then animation will be played only once. */ + struct Spritesheet* next; /*!< Next spritesheet in the queue. */ +}; + +/*! \brief Structure representing one visible character. */ +struct Character { + char* name; /*!< Name of the character (used in file paths). */ + struct Spritesheet *spritesheet; /*!< Current spritesheet used by character. */ + struct Spritesheet *spritesheets; /*!< List of all spritesheets registered to character. */ + char* successor; + ALLEGRO_BITMAP* bitmap; + int pos; /*!< Current spritesheet position. */ + int pos_tmp; /*!< A counter used to slow down spritesheet animation. */ + float x; /*!< Horizontal position of character. */ + float y; /*!< Vertical position of character. */ + float angle; /*!< Characters display angle (radians). */ + void* data; /*!< Additional, custom character data (HP etc.). */ + bool shared; + bool dead; +}; + + +void SelectSpritesheet(struct Game *game, struct Character *character, char* name); +void ChangeSpritesheet(struct Game *game, struct Character *character, char* name); +void RegisterSpritesheet(struct Game *game, struct Character *character, char* name); + +void DrawCharacter(struct Game *game, struct Character *character, ALLEGRO_COLOR tilt, int flags); + +struct Character* CreateCharacter(struct Game *game, char* name); +void DestroyCharacter(struct Game *game, struct Character *character); + +void LoadSpritesheets(struct Game *game, struct Character *character); +void UnloadSpritesheets(struct Game *game, struct Character *character); + +void AnimateCharacter(struct Game *game, struct Character *character, float speed_modifier); +void MoveCharacter(struct Game *game, struct Character *character, float x, float y, float angle); +void SetCharacterPosition(struct Game *game, struct Character *character, int x, int y, float angle);