import Radio Edit codebase

This commit is contained in:
Sebastian Krzyszkowiak 2016-06-27 21:20:02 +02:00
parent e92e4b6bec
commit 46827594b4
16 changed files with 1368 additions and 668 deletions

View file

@ -69,9 +69,9 @@
if (WIN32) if (WIN32)
# use relative install prefix to avoid hardcoded install paths in cmake_install.cmake files # 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(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(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) set(SBIN_INSTALL_DIR "sbin" ) # The install dir for system executables (default ${EXEC_INSTALL_PREFIX}/sbin)

View file

@ -5,6 +5,10 @@ SET(SRC_LIST
gamestate.c gamestate.c
) )
SET(EXECUTABLE_SRC_LIST
main.c
)
find_package(Allegro5 REQUIRED) find_package(Allegro5 REQUIRED)
find_package(Allegro5Font REQUIRED) find_package(Allegro5Font REQUIRED)
find_package(Allegro5TTF REQUIRED) find_package(Allegro5TTF REQUIRED)
@ -17,42 +21,36 @@ if(APPLE)
endif(APPLE) endif(APPLE)
if(MINGW) if(MINGW)
# resource compilation for 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 ) 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(EXECUTABLE_SRC_LIST ${EXECUTABLE_SRC_LIST} ${CMAKE_CURRENT_BINARY_DIR}/icon.o)
set(LINK_FLAGS -Wl,-subsystem,windows) set(LINK_FLAGS -Wl,-subsystem,windows)
endif(MINGW) endif(MINGW)
SET(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib/superderpy:\$ORIGIN/gamestates:\$ORIGIN/levels:\$ORIGIN:\$ORIGIN/../lib") SET(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib/radioedit:\$ORIGIN/gamestates:\$ORIGIN:\$ORIGIN/../lib:\$ORIGIN/lib:\$ORIGIN/bin")
#IF(${PACKAGE_BUILD})
# SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
# SET(CMAKE_INSTALL_RPATH "\$ORIGIN/../lib/superderpy:\$ORIGIN")
#ENDIF(${PACKAGE_BUILD})
if(APPLE) if(APPLE)
set(EXECUTABLE "SuperDerpy") set(EXECUTABLE "RadioEdit")
else(APPLE) else(APPLE)
set(EXECUTABLE "superderpy") set(EXECUTABLE "radioedit")
endif(APPLE) endif(APPLE)
add_library("libsuperderpy" SHARED ${SRC_LIST}) add_library("libsuperderpy-radioedit" SHARED ${SRC_LIST})
add_executable(${EXECUTABLE} WIN32 MACOSX_BUNDLE "main.c") 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}) 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) if(ALLEGRO5_MAIN_FOUND)
target_link_libraries(${EXECUTABLE} ${ALLEGRO5_MAIN_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${ALLEGRO5_MAIN_LIBRARIES})
endif(ALLEGRO5_MAIN_FOUND) endif(ALLEGRO5_MAIN_FOUND)
add_subdirectory(gamestates) add_subdirectory(gamestates)
add_subdirectory(levels)
install(TARGETS ${EXECUTABLE} DESTINATION ${BIN_INSTALL_DIR}) install(TARGETS ${EXECUTABLE} DESTINATION ${BIN_INSTALL_DIR})
install(TARGETS "libsuperderpy" DESTINATION ${LIB_INSTALL_DIR}) install(TARGETS "libsuperderpy-radioedit" DESTINATION ${LIB_INSTALL_DIR})

View file

@ -26,33 +26,33 @@
struct Game; struct Game;
struct Gamestate { struct Gamestate {
char* name; char* name;
void* handle; void* handle;
bool loaded, pending_load; bool loaded, pending_load;
bool started, pending_start; bool started, pending_start;
bool showLoading; bool showLoading;
bool paused; bool paused;
bool fade; // TODO: or maybe should it be in API? bool fade; // TODO: or maybe should it be in API?
unsigned char fade_counter; unsigned char fade_counter;
char** after; // TODO: and this one too? char** after; // TODO: and this one too?
struct Gamestate* next; struct Gamestate* next;
void* data; void* data;
struct { struct {
void (*Gamestate_Draw)(struct Game *game, void* data); void (*Gamestate_Draw)(struct Game *game, void* data);
void (*Gamestate_Logic)(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_Load)(struct Game *game, void (*progress)(struct Game *game));
void (*Gamestate_Start)(struct Game *game, void* data); void (*Gamestate_Start)(struct Game *game, void* data);
void (*Gamestate_Pause)(struct Game *game, void* data); void (*Gamestate_Pause)(struct Game *game, void* data);
void (*Gamestate_Resume)(struct Game *game, void* data); void (*Gamestate_Resume)(struct Game *game, void* data);
void (*Gamestate_Stop)(struct Game *game, void* data); void (*Gamestate_Stop)(struct Game *game, void* data);
void (*Gamestate_Unload)(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_ProcessEvent)(struct Game *game, void* data, ALLEGRO_EVENT *ev);
void (*Gamestate_Reload)(struct Game *game, void* data); void (*Gamestate_Reload)(struct Game *game, void* data);
int *Gamestate_ProgressCount; int *Gamestate_ProgressCount;
} api; } api;
}; };
void LoadGamestate(struct Game *game, const char* name); void LoadGamestate(struct Game *game, const char* name);

View file

@ -1,21 +1,16 @@
MACRO(GAMESTATE name) 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() ENDMACRO()
GAMESTATE("dosowisko") GAMESTATE("dosowisko")
GAMESTATE("menu") GAMESTATE("menu")
GAMESTATE("disclaimer")
GAMESTATE("intro")
GAMESTATE("map")
GAMESTATE("about")
#GAMESTATE("pause")
GAMESTATE("loading") GAMESTATE("loading")

View file

@ -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_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_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); double tg = tan(-data->tan/384.0 * ALLEGRO_PI - ALLEGRO_PI/2);
int fade = data->fadeout ? 255 : data->fade; 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_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_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->timeline = TM_Init(game, "main");
data->bitmap = al_create_bitmap(game->viewport.width, game->viewport.height); data->bitmap = al_create_bitmap(game->viewport.width, game->viewport.height);
data->checkerboard = 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_set_target_bitmap(data->checkerboard);
al_lock_bitmap(data->checkerboard, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY); al_lock_bitmap(data->checkerboard, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY);
int x, y; int x, y;
for (x = 0; x < al_get_bitmap_width(data->checkerboard); x=x+2) { 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) { 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+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, y+1, al_map_rgba(0,0,0,0));
al_put_pixel(x+1, 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_sample(data->key_sample);
al_destroy_bitmap(data->bitmap); al_destroy_bitmap(data->bitmap);
al_destroy_bitmap(data->checkerboard); al_destroy_bitmap(data->checkerboard);
al_destroy_bitmap(data->pixelator);
TM_Destroy(data->timeline); TM_Destroy(data->timeline);
free(data); free(data);
} }

View file

@ -23,7 +23,7 @@ struct dosowiskoResources {
ALLEGRO_FONT *font; ALLEGRO_FONT *font;
ALLEGRO_SAMPLE *sample, *kbd_sample, *key_sample; ALLEGRO_SAMPLE *sample, *kbd_sample, *key_sample;
ALLEGRO_SAMPLE_INSTANCE *sound, *kbd, *key; ALLEGRO_SAMPLE_INSTANCE *sound, *kbd, *key;
ALLEGRO_BITMAP *bitmap, *checkerboard; ALLEGRO_BITMAP *bitmap, *checkerboard, *pixelator;
int pos, fade, tick, tan; int pos, fade, tick, tan;
char text[255]; char text[255];
bool underscore, fadeout; bool underscore, fadeout;

View file

@ -25,7 +25,7 @@
void Progress(struct Game *game, struct LoadingResources *data, float p) { void Progress(struct Game *game, struct LoadingResources *data, float p) {
al_set_target_bitmap(al_get_backbuffer(game->display)); al_set_target_bitmap(al_get_backbuffer(game->display));
al_draw_bitmap(data->loading_bitmap,0,0,0); 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) { 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->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_set_target_bitmap(data->loading_bitmap);
al_clear_to_color(al_map_rgb(193,225,218)); al_clear_to_color(al_map_rgb(0,0,0));
al_draw_bitmap(data->image, game->viewport.width-al_get_bitmap_width(data->image), 0, 0); al_draw_filled_rectangle(0, game->viewport.height-1, game->viewport.width, game->viewport.height, al_map_rgba(32,32,32,32));
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_set_target_bitmap(al_get_backbuffer(game->display)); al_set_target_bitmap(al_get_backbuffer(game->display));
al_destroy_bitmap(data->image);
return data; return data;
} }

View file

@ -25,6 +25,5 @@
/*! \brief Resources used by Loading state. */ /*! \brief Resources used by Loading state. */
struct LoadingResources { struct LoadingResources {
ALLEGRO_BITMAP *loading_bitmap; /*!< Rendered loading bitmap. */ ALLEGRO_BITMAP *loading_bitmap; /*!< Rendered loading bitmap. */
ALLEGRO_BITMAP *image; /*!< Loading background. */
}; };

File diff suppressed because it is too large Load diff

View file

@ -27,43 +27,69 @@
enum menustate_enum { enum menustate_enum {
MENUSTATE_MAIN, MENUSTATE_MAIN,
MENUSTATE_OPTIONS, MENUSTATE_OPTIONS,
MENUSTATE_CONTROLS,
MENUSTATE_VIDEO, 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. */ /*! \brief Resources used by Menu state. */
struct MenuResources { 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 *cloud; /*!< Bitmap with bigger cloud. */
ALLEGRO_BITMAP *cloud2; /*!< Bitmap with small cloud. */ ALLEGRO_BITMAP *grass;
ALLEGRO_BITMAP *pie; /*!< Unscaled bitmap with pie. */ ALLEGRO_BITMAP *forest;
ALLEGRO_BITMAP *pie_bitmap; /*!< Scaled and "rendered" bitmap with pies. */ ALLEGRO_BITMAP *stage;
ALLEGRO_BITMAP *pinkcloud_bitmap; /*!< Scaled bitmap with pinkcloud and home. */ ALLEGRO_BITMAP *speaker;
ALLEGRO_BITMAP *pinkcloud; /*!< Unscaled bitmap with pinkcloud and home. */ ALLEGRO_BITMAP *lines;
ALLEGRO_BITMAP *rain; /*!< Unscaled bitmap with rain drop. */ ALLEGRO_BITMAP *cable;
ALLEGRO_BITMAP *rain_bitmap; /*!< Scaled and "rendered" bitmap with rain drops. */ ALLEGRO_BITMAP *light;
ALLEGRO_BITMAP *mountain; /*!< Flashing mountain in background bitmap. */
ALLEGRO_BITMAP *logo; /*!< Logo displayed in the background. */ ALLEGRO_BITMAP *marksmall;
ALLEGRO_BITMAP *logoblur; /*!< Prerendered blurred logo. */ ALLEGRO_BITMAP *markbig;
ALLEGRO_BITMAP *glass; /*!< Texture used for glass effect in the logo. */ int markx, marky;
ALLEGRO_BITMAP *blurbg; /*!< Temporary bitmap used for blur effect in glass logo. */
ALLEGRO_BITMAP *blurbg2; /*!< Temporary bitmap used for blur effect in glass logo. */ 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 cloud_position; /*!< Position of bigger cloud. */
float cloud2_position; /*!< Position of small cloud. */ ALLEGRO_SAMPLE *sample; /*!< Music sample. */
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 *click_sample; /*!< Click sound sample. */ ALLEGRO_SAMPLE *click_sample; /*!< Click sound sample. */
ALLEGRO_SAMPLE_INSTANCE *music; /*!< Sample instance with background music. */ ALLEGRO_SAMPLE *quit_sample;
ALLEGRO_SAMPLE_INSTANCE *rain_sound; /*!< Sample instance with rain sound. */ 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 *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_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; /*!< Font of standard menu item. */
ALLEGRO_FONT *font_selected; /*!< Font of selected menu item. */
int selected; /*!< Number of selected menu item. */ int selected; /*!< Number of selected menu item. */
enum menustate_enum menustate; /*!< Current menu page. */ enum menustate_enum menustate; /*!< Current menu page. */
struct { struct {
@ -71,8 +97,17 @@ struct MenuResources {
int fps; int fps;
int width; int width;
int height; int height;
int resolution;
} options; /*!< Options which can be changed in menu. */ } options; /*!< Options which can be changed in menu. */
};
//void DrawMenuState(struct Game *game); struct {
//void ChangeMenuState(struct Game *game, enum menustate_enum state); int key;
bool shift;
int delay;
// workaround for random bogus UP/DOWN events
int lastkey;
int lastdelay;
} keys;
int score;
};

View file

@ -35,23 +35,6 @@
#include "config.h" #include "config.h"
#include "main.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) { void DrawGamestates(struct Game *game) {
al_set_target_backbuffer(game->display); al_set_target_backbuffer(game->display);
al_clear_to_color(al_map_rgb(0,0,0)); 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) { void derp(int sig) {
write(STDERR_FILENO, "Segmentation fault\n", 19); int __attribute__((unused)) n = write(STDERR_FILENO, "Segmentation fault\nI just don't know what went wrong!\n", 54);
write(STDERR_FILENO, "I just don't know what went wrong!\n", 35);
abort(); abort();
} }
@ -151,7 +78,7 @@ int main(int argc, char **argv){
srand(time(NULL)); srand(time(NULL));
al_set_org_name("Super Derpy"); al_set_org_name("Super Derpy");
al_set_app_name("Muffin Attack"); al_set_app_name("Radio Edit");
if(!al_init()) { if(!al_init()) {
fprintf(stderr, "failed to initialize allegro!\n"); fprintf(stderr, "failed to initialize allegro!\n");
@ -169,14 +96,14 @@ int main(int argc, char **argv){
game._priv.font_bsod = NULL; game._priv.font_bsod = NULL;
game._priv.console = NULL; game._priv.console = NULL;
game.config.fullscreen = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fullscreen", "1")); game.config.fullscreen = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fullscreen", "0"));
game.config.music = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "music", "7")); game.config.music = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "music", "10"));
game.config.voice = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "voice", "10")); game.config.voice = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "voice", "10"));
game.config.fx = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fx", "10")); game.config.fx = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "fx", "10"));
game.config.debug = atoi(GetConfigOptionDefault(&game, "SuperDerpy", "debug", "0")); 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; 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 (game.config.height<180) game.config.height=180;
if(!al_init_image_addon()) { if(!al_init_image_addon()) {
@ -217,6 +144,9 @@ int main(int argc, char **argv){
else al_set_new_display_flags(ALLEGRO_WINDOWED); 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_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); 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); game.display = al_create_display(game.config.width, game.config.height);
if(!game.display) { if(!game.display) {
@ -226,20 +156,17 @@ int main(int argc, char **argv){
SetupViewport(&game); SetupViewport(&game);
int ret = Console_Load(&game);
if (ret!=0) return ret;
PrintConsole(&game, "Viewport %dx%d", game.viewport.width, game.viewport.height); PrintConsole(&game, "Viewport %dx%d", game.viewport.width, game.viewport.height);
ALLEGRO_BITMAP *icon = al_load_bitmap(GetDataFilePath(&game, "icons/superderpy.png")); ALLEGRO_BITMAP *icon = al_load_bitmap(GetDataFilePath(&game, "icons/radioedit.png"));
al_set_window_title(game.display, "Super Derpy: Muffin Attack"); al_set_window_title(game.display, "Radio Edit");
al_set_display_icon(game.display, icon); al_set_display_icon(game.display, icon);
al_destroy_bitmap(icon); al_destroy_bitmap(icon);
if (game.config.fullscreen) al_hide_mouse_cursor(game.display); if (game.config.fullscreen) al_hide_mouse_cursor(game.display);
al_inhibit_screensaver(true); 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; game._priv.gamestates = NULL;
@ -250,7 +177,7 @@ int main(int argc, char **argv){
return -1; 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.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.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); 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; game._priv.showconsole = game.config.debug;
al_flip_display();
al_clear_to_color(al_map_rgb(0,0,0)); 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 game._priv.timer = al_create_timer(ALLEGRO_BPS_TO_SECS(60)); // logic timer
if(!game._priv.timer) { if(!game._priv.timer) {
FatalError(&game, true, "Failed to create logic timer."); FatalError(&game, true, "Failed to create logic timer.");
return -1; return -1;
} }
al_register_event_source(game._priv.event_queue, al_get_timer_event_source(game._priv.timer)); 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); al_start_timer(game._priv.timer);
setlocale(LC_NUMERIC, "C"); setlocale(LC_NUMERIC, "C");
@ -306,24 +233,20 @@ int main(int argc, char **argv){
free(gamestate); free(gamestate);
char libname[1024] = {}; 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); void *handle = dlopen(libname, RTLD_NOW);
if (!handle) { if (!handle) {
FatalError(&game, true, "Error while initializing loading screen %s", dlerror()); FatalError(&game, true, "Error while initializing loading screen %s", dlerror());
exit(1); exit(1);
} else { } else {
void gs_error() { #define GS_LOADINGERROR FatalError(&game, true, "Error on resolving loading symbol: %s", dlerror()); exit(1);
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.Draw = dlsym(handle, "Draw"))) { GS_LOADINGERROR; }
if (!(game._priv.loading.Load = dlsym(handle, "Load"))) { GS_LOADINGERROR; }
if (!(game._priv.loading.Load = dlsym(handle, "Load"))) { gs_error(); } if (!(game._priv.loading.Start = dlsym(handle, "Start"))) { GS_LOADINGERROR; }
if (!(game._priv.loading.Start = dlsym(handle, "Start"))) { gs_error(); } if (!(game._priv.loading.Stop = dlsym(handle, "Stop"))) { GS_LOADINGERROR; }
if (!(game._priv.loading.Stop = dlsym(handle, "Stop"))) { gs_error(); } if (!(game._priv.loading.Unload = dlsym(handle, "Unload"))) { GS_LOADINGERROR; }
if (!(game._priv.loading.Unload = dlsym(handle, "Unload"))) { gs_error(); }
} }
game._priv.loading.data = (*game._priv.loading.Load)(&game); 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); al_stop_timer(game._priv.timer);
// TODO: take proper game name // TODO: take proper game name
char libname[1024]; 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); tmp->handle = dlopen(libname,RTLD_NOW);
if (!tmp->handle) { if (!tmp->handle) {
//PrintConsole(&game, "Error while loading gamestate \"%s\": %s", tmp->name, dlerror()); //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; tmp->pending_start = false;
} else { } else {
void gs_error() { #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;
FatalError(&game, true, "Error on resolving gamestate symbol: %s", dlerror());
tmp->pending_load = false;
tmp->pending_start = false;
tmp=tmp->next;
}
if (!(tmp->api.Gamestate_Draw = dlsym(tmp->handle, "Gamestate_Draw"))) { 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(); continue; } 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_Load = dlsym(tmp->handle, "Gamestate_Load"))) { GS_ERROR; }
if (!(tmp->api.Gamestate_Start = dlsym(tmp->handle, "Gamestate_Start"))) { gs_error(); continue; } if (!(tmp->api.Gamestate_Start = dlsym(tmp->handle, "Gamestate_Start"))) { GS_ERROR; }
if (!(tmp->api.Gamestate_Pause = dlsym(tmp->handle, "Gamestate_Pause"))) { gs_error(); continue; } if (!(tmp->api.Gamestate_Pause = dlsym(tmp->handle, "Gamestate_Pause"))) { GS_ERROR; }
if (!(tmp->api.Gamestate_Resume = dlsym(tmp->handle, "Gamestate_Resume"))) { gs_error(); continue; } if (!(tmp->api.Gamestate_Resume = dlsym(tmp->handle, "Gamestate_Resume"))) { GS_ERROR; }
if (!(tmp->api.Gamestate_Stop = dlsym(tmp->handle, "Gamestate_Stop"))) { gs_error(); continue; } if (!(tmp->api.Gamestate_Stop = dlsym(tmp->handle, "Gamestate_Stop"))) { GS_ERROR; }
if (!(tmp->api.Gamestate_Unload = dlsym(tmp->handle, "Gamestate_Unload"))) { gs_error(); continue; } 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_ProcessEvent = dlsym(tmp->handle, "Gamestate_ProcessEvent"))) { GS_ERROR; }
if (!(tmp->api.Gamestate_Reload = dlsym(tmp->handle, "Gamestate_Reload"))) { gs_error(); continue; } 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; int p = 0;
void progress(struct Game *game) { void progress(struct Game *game) {
@ -420,7 +338,7 @@ int main(int argc, char **argv){
} }
DrawConsole(&game); DrawConsole(&game);
al_flip_display(); 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++; loaded++;
tmp->loaded = true; tmp->loaded = true;
@ -471,11 +389,14 @@ int main(int argc, char **argv){
else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
break; 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 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)) { else if ((ev.type == ALLEGRO_EVENT_KEY_DOWN) && (ev.keyboard.keycode == ALLEGRO_KEY_TILDE)) {
#endif #endif
game._priv.showconsole = !game._priv.showconsole; game._priv.showconsole = !game._priv.showconsole;
} }
else if ((ev.type == ALLEGRO_EVENT_KEY_DOWN) && (game.config.debug) && (ev.keyboard.keycode == ALLEGRO_KEY_F1)) { 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)) { } 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); ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH);
char filename[255] = { }; 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_set_path_filename(path, filename);
al_save_bitmap(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP), al_get_backbuffer(game.display)); 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)); PrintConsole(&game, "Screenshot stored in %s", al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP));

View file

@ -35,6 +35,8 @@ struct Gamestate;
struct Game { struct Game {
ALLEGRO_DISPLAY *display; /*!< Main Allegro display. */ ALLEGRO_DISPLAY *display; /*!< Main Allegro display. */
ALLEGRO_TRANSFORM projection;
struct { struct {
int width; /*!< Actual available width of viewport. */ int width; /*!< Actual available width of viewport. */
int height; /*!< Actual available height of viewport. */ int height; /*!< Actual available height of viewport. */

View file

@ -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) { 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)); struct TM_Action *action = malloc(sizeof(struct TM_Action));
if (timeline->background) { if (timeline->background) {
struct TM_Action *pom = timeline->background; struct TM_Action *pom = timeline->background;
@ -297,8 +298,9 @@ void TM_CleanQueue(struct Timeline* timeline) {
while (pom!=NULL) { while (pom!=NULL) {
if (pom->active) { if (pom->active) {
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY); if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
else { if (pom->timer) {
if (pom->timer) al_destroy_timer(pom->timer); al_stop_timer(pom->timer);
al_destroy_timer(pom->timer);
} }
} else { } else {
TM_DestroyArgs(pom->arguments); TM_DestroyArgs(pom->arguments);
@ -311,23 +313,25 @@ void TM_CleanQueue(struct Timeline* timeline) {
free(pom->name); free(pom->name);
free(pom); free(pom);
tmp2 = tmp; tmp2 = tmp;
if (!tmp) pom=timeline->background->next; if (!tmp) pom=timeline->queue->next;
else pom=tmp->next; else pom=tmp->next;
tmp = tmp2; tmp = tmp2;
} }
} }
// TODO: it shouldn't be needed, but is. Debug!
timeline->queue = NULL;
} }
void TM_CleanBackgroundQueue(struct Timeline* timeline) { void TM_CleanBackgroundQueue(struct Timeline* timeline) {
PrintConsole(timeline->game, "Timeline Manager[%s]: cleaning background queue", timeline->name); 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; tmp = NULL;
pom=timeline->background;
while (pom!=NULL) { while (pom!=NULL) {
if (pom->active) { if (pom->active) {
if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY); if (*pom->function) (*pom->function)(timeline->game, pom, TM_ACTIONSTATE_DESTROY);
else { if (pom->timer) {
if (pom->timer) al_destroy_timer(pom->timer); al_stop_timer(pom->timer);
al_destroy_timer(pom->timer);
} }
} else { } else {
TM_DestroyArgs(pom->arguments); TM_DestroyArgs(pom->arguments);
@ -345,6 +349,8 @@ void TM_CleanBackgroundQueue(struct Timeline* timeline) {
tmp = tmp2; tmp = tmp2;
} }
} }
// TODO: it shouldn't be needed, but is. Debug!
timeline->background = NULL;
} }
void TM_Destroy(struct Timeline* timeline) { 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; struct TM_Arguments* tmp = args;
for(i = 0; i < num; i++) { for(i = 0; i < num; i++) {
if (!tmp) { 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 = malloc(sizeof(struct TM_Arguments));
tmp->value = va_arg(ap, void*); tmp->value = va_arg(ap, void*);
tmp->next = NULL; tmp->next = NULL;

View file

@ -39,11 +39,11 @@ enum TM_ActionState {
/*! \brief Timeline structure. */ /*! \brief Timeline structure. */
struct Timeline { struct Timeline {
struct TM_Action *queue; /*!< Main timeline queue. */ struct TM_Action *queue; /*!< Main timeline queue. */
struct TM_Action *background; /*!< Background queue. */ struct TM_Action *background; /*!< Background queue. */
char* name; /*!< Name of the timeline. */ char* name; /*!< Name of the timeline. */
unsigned int lastid; /*!< Last ID given to timeline action. */ unsigned int lastid; /*!< Last ID given to timeline action. */
struct Game* game; /*!< Reference to the game object. */ struct Game* game; /*!< Reference to the game object. */
}; };
/*! \brief Arguments for TM_Action. */ /*! \brief Arguments for TM_Action. */

View file

@ -20,11 +20,98 @@
*/ */
#include <allegro5/allegro_primitives.h> #include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_ttf.h>
#include "stdio.h" #include "stdio.h"
#include "config.h" #include "config.h"
#include "string.h"
#include "math.h" #include "math.h"
#include "utils.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) { void DrawVerticalGradientRect(float x, float y, float w, float h, ALLEGRO_COLOR top, ALLEGRO_COLOR bottom) {
ALLEGRO_VERTEX v[] = { ALLEGRO_VERTEX v[] = {
{.x = x, .y = y, .z = 0, .color = top}, {.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); al_draw_text(font, color, (int)x, (int)y, flags, text);
} }
void FadeGamestate(struct Game *game, bool in) { /* linear filtering code written by SiegeLord */
//TODO: reimplement ALLEGRO_COLOR interpolate(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2, float frac) {
/* ALLEGRO_BITMAP* bitmap = al_create_bitmap(game->viewportWidth, game->viewportHeight); return al_map_rgba_f(c1.r + frac * (c2.r - c1.r),
al_set_target_bitmap(bitmap); c1.g + frac * (c2.g - c1.g),
al_clear_to_color(al_map_rgb(0,0,0)); c1.b + frac * (c2.b - c1.b),
al_set_target_bitmap(al_get_backbuffer(game->display)); c1.a + frac * (c2.a - c1.a));
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);
}*/
} }
/*! \brief Scales bitmap using software linear filtering method to current target. */ /*! \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(al_get_target_bitmap(), ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_WRITEONLY);
al_lock_bitmap(source, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY); 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++) { for (y = 0; y < height; y++) {
float pixy = ((float)y / height) * ((float)al_get_bitmap_height(source) - 1); float pixy = ((float)y / height) * ((float)al_get_bitmap_height(source) - 1);
float pixy_f = floor(pixy); 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_set_target_bitmap(target);
al_clear_to_color(al_map_rgba(0,0,0,0)); al_clear_to_color(al_map_rgba(0,0,0,0));
char* origfn = GetDataFilePath(game, filename); 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_MEMORY_BITMAP);
if (memoryscale) {
al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); source = al_load_bitmap( origfn );
ScaleBitmap(source, width, height); if (memoryscale) {
} al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR);
else { ScaleBitmap(source, width, height);
al_draw_scaled_bitmap(source, 0, 0, al_get_bitmap_width(source), al_get_bitmap_height(source), 0, 0, width, height, 0); }
} else {
/*al_save_bitmap(cachefn, target); al_draw_scaled_bitmap(source, 0, 0, al_get_bitmap_width(source), al_get_bitmap_height(source), 0, 0, width, height, 0);
PrintConsole(game, "Cache bitmap %s generated.", filename);*/
al_destroy_bitmap(source);
} }
/*source = al_load_bitmap( cachefn ); al_destroy_bitmap(source);
if (source) {
if ((al_get_bitmap_width(source)!=width) || (al_get_bitmap_height(source)!=height)) {
al_destroy_bitmap(source);*/
GenerateBitmap();
free(origfn); free(origfn);
return target; return target;
/* }
return source;
} else GenerateBitmap();
return target;*/
} }
void FatalError(struct Game *game, bool fatal, char* format, ...) { 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); PrintConsole(game, text);
} }
ALLEGRO_TRANSFORM trans;
al_identity_transform(&trans);
al_use_transform(&trans);
if (!game->_priv.font_bsod) { if (!game->_priv.font_bsod) {
game->_priv.font_bsod = al_create_builtin_font(); 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_set_target_backbuffer(game->display);
al_clear_to_color(al_map_rgb(0,0,170)); al_clear_to_color(al_map_rgb(0,0,170));
al_flip_display(); al_flip_display();
al_rest(1.1); al_rest(0.6);
bool done = false; bool done = false;
while (!done) { while (!done) {
@ -194,32 +237,32 @@ void FatalError(struct Game *game, bool fatal, char* format, ...) {
al_set_target_backbuffer(game->display); al_set_target_backbuffer(game->display);
al_clear_to_color(al_map_rgb(0,0,170)); 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) +"; 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_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), 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_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), 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), 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), 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), 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+9*al_get_font_line_height(game->_priv.font_bsod)*1.25), ALLEGRO_ALIGN_LEFT, "* Just kidding, please press any key anyway.");
if (fatal) { 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 { } 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(); 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) { char* GetDataFilePath(struct Game *game, char* filename) {
//TODO: support for current game //TODO: support for current game
//FIXME: strdups result in memory leaks!
char *result = 0; char *result = 0;
if (al_filename_exists(filename)) { if (al_filename_exists(filename)) {
@ -254,24 +316,13 @@ char* GetDataFilePath(struct Game *game, char* filename) {
return strdup(origfn); return strdup(origfn);
} }
void TestPath(char* subpath) { TestPath(filename, "data/", &result);
ALLEGRO_PATH *tail = al_create_path(filename); TestPath(filename, "../share/radioedit/data/", &result);
ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH); TestPath(filename, "../data/", &result);
ALLEGRO_PATH *data = al_create_path(subpath); #ifdef ALLEGRO_MACOSX
al_join_paths(path, data); TestPath(filename, "../Resources/data/", &result);
al_join_paths(path, tail); TestPath(filename, "../Resources/gamestates/", &result);
//printf("Testing for %s\n", al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); #endif
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/");
if (!result) { if (!result) {
FatalError(game, true, "Could not find data file: %s!", filename); FatalError(game, true, "Could not find data file: %s!", filename);
@ -280,7 +331,6 @@ char* GetDataFilePath(struct Game *game, char* filename) {
return result; return result;
} }
void PrintConsole(struct Game *game, char* format, ...) { void PrintConsole(struct Game *game, char* format, ...) {
va_list vl; va_list vl;
va_start(vl, format); va_start(vl, format);
@ -288,6 +338,8 @@ void PrintConsole(struct Game *game, char* format, ...) {
vsnprintf(text, 1024, format, vl); vsnprintf(text, 1024, format, vl);
va_end(vl); va_end(vl);
if (game->config.debug) { printf("%s\n", text); fflush(stdout); } 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)); 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_set_target_bitmap(con);
al_clear_to_color(al_map_rgba(0,0,0,80)); 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_set_target_bitmap(al_get_backbuffer(game->display));
al_destroy_bitmap(con); 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);
}

View file

@ -22,6 +22,32 @@
#include <allegro5/allegro_font.h> #include <allegro5/allegro_font.h>
#include "main.h" #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. */ /*! \brief Draws rectangle filled with vertical gradient. */
void DrawVerticalGradientRect(float x, float y, float w, float h, ALLEGRO_COLOR top, ALLEGRO_COLOR bottom); void DrawVerticalGradientRect(float x, float y, float w, float h, ALLEGRO_COLOR top, ALLEGRO_COLOR bottom);
/*! \brief Draws rectangle filled with horizontal gradient. */ /*! \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. */ /*! \brief Loads bitmap into memory and scales it with software linear filtering. */
ALLEGRO_BITMAP* LoadScaledBitmap(struct Game *game, char* filename, int width, int height); 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. */ /*! \brief Finds path for data file. */
char* GetDataFilePath(struct Game *game, char* filename); char* GetDataFilePath(struct Game *game, char* filename);
char* GetLibFilePath(struct Game *game, char* filename);
/*! \brief Print some message on game console. /*! \brief Print some message on game console.
* *
* Draws message on console bitmap, so it'll be displayed when calling DrawConsole. * 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 PrintConsole(struct Game *game, char* format, ...);
void FatalError(struct Game *game, bool exit, 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);