Merge branch 'master' into extraspells
|
@ -38,6 +38,8 @@ install(DIRECTORY gfx DESTINATION ${DATA_DIR}
|
|||
FILES_MATCHING PATTERN "*.png")
|
||||
install(DIRECTORY gfx DESTINATION ${DATA_DIR}
|
||||
FILES_MATCHING PATTERN "*.ttf")
|
||||
install(DIRECTORY gfx DESTINATION ${DATA_DIR}
|
||||
FILES_MATCHING PATTERN "*.ani")
|
||||
install(DIRECTORY sfx DESTINATION ${DATA_DIR})
|
||||
install(DIRECTORY bgm DESTINATION ${DATA_DIR})
|
||||
install(DIRECTORY shader DESTINATION ${DATA_DIR})
|
||||
|
|
3
COPYING
|
@ -28,5 +28,8 @@ public domain or CC0 and were not taken by us. Here are some honorary mentions.
|
|||
* The mountains in the main menu background are by Luca Zanon.
|
||||
https://unsplash.com/photos/X0OoHrPvgXE
|
||||
|
||||
* the insect wings in Scuttle’s background are by GLady.
|
||||
https://pixabay.com/en/morpho-peleides-butterfly-43483/
|
||||
|
||||
* For the old ones, sadly I didn’t keep a list. You may find them by doing an
|
||||
image search. Check out the taisei-rawmedia repository for the raw files.
|
||||
|
|
19
README.md
|
@ -52,21 +52,18 @@ BGM (as well as SFX) may be in `.wav`, `.flac`, or `.ogg` format; additionally
|
|||
you may try another formats such as `.mp3`, `.aiff`, `.mod`, `.xm`, etc. if
|
||||
your build of SDL2_mixer supports these formats.
|
||||
|
||||
Complete music pack consists of 16 bgm\_\*.(ogg/wav/flac) files, where ‘\*’ mean:
|
||||
Complete music pack consists of 16 bgm\_\*.(ogg/wav/flac) files, where ‘\*’ means:
|
||||
```
|
||||
credits BGM for credits screen
|
||||
ending BGM for ending
|
||||
gameover BGM for game over screen
|
||||
menu BGM for menus (excluding in-game menu which pauses BGM)
|
||||
stageN N=1..6, standard stage theme
|
||||
stageNboss N=1..6, boss theme for a stage
|
||||
credits BGM for credits screen
|
||||
ending BGM for ending
|
||||
gameover BGM for game over screen
|
||||
menu BGM for menus (excluding in-game menu which pauses BGM)
|
||||
stageN N=1..6, standard stage theme
|
||||
stageNboss N=1..6, boss theme for a stage
|
||||
```
|
||||
|
||||
If you want to specify stage/boss theme names to be shown during gameplay, you
|
||||
may do it in `bgm/bgm.conf` file. This file contains some lines, each of which
|
||||
consists of bgm filename (without extension), space of tab, and theme name.
|
||||
No space/tab allowed either in beginning of line or BGM filenames listed in
|
||||
this file; theme names may contain them.
|
||||
may do it by editing the [`bgm/bgm.conf`](bgm/bgm.conf) file.
|
||||
|
||||
## Sound problems
|
||||
|
||||
|
|
24
bgm/bgm.conf
|
@ -1,13 +1,13 @@
|
|||
bgm_stage1 Generic Stage 1 Theme
|
||||
bgm_stage2 Generic Stage 2 Theme
|
||||
bgm_stage3 Generic Stage 3 Theme
|
||||
bgm_stage4 Generic Stage 4 Theme
|
||||
bgm_stage5 Generic Stage 5 Theme
|
||||
bgm_stage6 Generic Stage 6 Theme
|
||||
bgm_stage1 = Generic Stage 1 Theme
|
||||
bgm_stage2 = Generic Stage 2 Theme
|
||||
bgm_stage3 = Generic Stage 3 Theme
|
||||
bgm_stage4 = Generic Stage 4 Theme
|
||||
bgm_stage5 = Generic Stage 5 Theme
|
||||
bgm_stage6 = Generic Stage 6 Theme
|
||||
|
||||
bgm_stage1boss Stage 1 Boss Theme
|
||||
bgm_stage2boss Stage 2 Boss Theme
|
||||
bgm_stage3boss Stage 3 Boss Theme
|
||||
bgm_stage4boss Stage 4 Boss Theme
|
||||
bgm_stage5boss Stage 5 Boss Theme
|
||||
bgm_stage6boss Stage 6 Boss Theme
|
||||
bgm_stage1boss = Stage 1 Boss Theme
|
||||
bgm_stage2boss = Stage 2 Boss Theme
|
||||
bgm_stage3boss = Stage 3 Boss Theme
|
||||
bgm_stage4boss = Stage 4 Boss Theme
|
||||
bgm_stage5boss = Stage 5 Boss Theme
|
||||
bgm_stage6boss = Stage 6 Boss Theme
|
||||
|
|
3
gfx/bigfairy.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 2
|
||||
cols = 2
|
||||
speed = 15
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
3
gfx/cirno.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 10
|
Before Width: | Height: | Size: 9.6 KiB After Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 8 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 11 KiB |
3
gfx/elly.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 10
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
3
gfx/fairy.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 2
|
||||
cols = 2
|
||||
speed = 15
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
3
gfx/fire.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 25
|
||||
speed = 1
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
3
gfx/hina.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 10
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
3
gfx/hinabg.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 25
|
||||
speed = 1
|
Before Width: | Height: | Size: 486 KiB After Width: | Height: | Size: 486 KiB |
3
gfx/iku.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 25
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
3
gfx/kurumi.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 10
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
3
gfx/marisa.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 2
|
||||
cols = 4
|
||||
speed = 10
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
3
gfx/scuttle.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 10
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 184 KiB |
BIN
gfx/stage3/spellbg2.png
Normal file
After Width: | Height: | Size: 955 KiB |
3
gfx/wriggle.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 10
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
3
gfx/wriggleex.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 1
|
||||
cols = 1
|
||||
speed = 10
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
3
gfx/youmu.ani
Normal file
|
@ -0,0 +1,3 @@
|
|||
rows = 2
|
||||
cols = 4
|
||||
speed = 10
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
@ -21,6 +21,7 @@ endif()
|
|||
|
||||
set(SRCs
|
||||
main.c
|
||||
log.c
|
||||
util.c
|
||||
taiseigl.c
|
||||
random.c
|
||||
|
@ -110,10 +111,6 @@ else()
|
|||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(SRCs ${SRCs} taisei_err.c)
|
||||
endif()
|
||||
|
||||
if(DEFINED TAISEI_DEBUG)
|
||||
if(TAISEI_DEBUG)
|
||||
set(CMAKE_BUILD_TYPE "Debug")
|
||||
|
@ -130,7 +127,6 @@ endif()
|
|||
message(STATUS "Build configuration: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -DDEBUG")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
|
||||
|
||||
add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}" -Wall -Wno-parentheses -Wtype-limits -std=c11 -pedantic)
|
||||
|
||||
|
@ -146,6 +142,10 @@ if(FATALERRS)
|
|||
add_definitions(-Wfatal-errors)
|
||||
endif()
|
||||
|
||||
if(WIN32 OR APPLE)
|
||||
add_definitions(-DLOG_FATAL_MSGBOX)
|
||||
endif()
|
||||
|
||||
set(LIBs ${LIBs}
|
||||
${SDL2_LIBRARIES}
|
||||
${SDL2_TTF_LIBRARIES}
|
||||
|
@ -196,6 +196,13 @@ if(POSIX)
|
|||
add_definitions(-D__POSIX__)
|
||||
endif()
|
||||
|
||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE)
|
||||
if(HAVE_BACKTRACE)
|
||||
add_definitions(-DLOG_ENABLE_BACKTRACE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL "Ninja" AND
|
||||
((CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) OR
|
||||
(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.5)))
|
||||
|
|
2
src/assert.h
Normal file
|
@ -0,0 +1,2 @@
|
|||
|
||||
#error Do not include assert.h, Taisei provides its own implementation.
|
|
@ -49,12 +49,12 @@ void reset_sounds(void) {
|
|||
}
|
||||
|
||||
Sound* get_sound(const char *name) {
|
||||
Resource *res = get_resource(RES_SFX, name, 0);
|
||||
Resource *res = get_resource(RES_SFX, name, RESF_OPTIONAL);
|
||||
return res ? res->sound : NULL;
|
||||
}
|
||||
|
||||
Music* get_music(const char *name) {
|
||||
Resource *res = get_resource(RES_BGM, name, 0);
|
||||
Resource *res = get_resource(RES_BGM, name, RESF_OPTIONAL);
|
||||
return res ? res->music : NULL;
|
||||
}
|
||||
|
||||
|
@ -68,42 +68,13 @@ static void bgm_cfg_volume_callback(ConfigIndex idx, ConfigValue v) {
|
|||
|
||||
static void load_bgm_descriptions(void) {
|
||||
char *fullname = strjoin(get_prefix(), "bgm/bgm.conf", NULL);
|
||||
FILE *fp = fopen(fullname, "rt");
|
||||
bgm_descriptions = parse_keyvalue_file(fullname, 16);
|
||||
free(fullname);
|
||||
|
||||
bgm_descriptions = hashtable_new_stringkeys(16);
|
||||
|
||||
if(fp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
char line[256];
|
||||
while(fgets(line, sizeof(line), fp)) {
|
||||
char *rem;
|
||||
|
||||
while((rem = strchr(line,'\n')) != NULL) *rem = '\0';
|
||||
while((rem = strchr(line,'\r')) != NULL) *rem = '\0';
|
||||
while((rem = strchr(line,'\t')) != NULL) *rem = ' ';
|
||||
|
||||
if((rem = strchr(line,' ' )) == NULL) {
|
||||
if(strlen(line) > 0)
|
||||
warnx("load_bgm_description(): illegal string format. See README.");
|
||||
continue;
|
||||
}
|
||||
|
||||
*(rem++)='\0';
|
||||
|
||||
char *value = strjoin("BGM: ", rem, NULL);
|
||||
hashtable_set_string(bgm_descriptions, line, value);
|
||||
printf("Music %s is now known as \"%s\".\n", line, value);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline char* get_bgm_desc(char *name) {
|
||||
return (char*)hashtable_get_string(bgm_descriptions, name);
|
||||
return bgm_descriptions ? (char*)hashtable_get_string(bgm_descriptions, name) : NULL;
|
||||
}
|
||||
|
||||
void resume_bgm(void) {
|
||||
|
@ -122,9 +93,9 @@ void stop_bgm(bool force) {
|
|||
audio_backend_music_pause();
|
||||
}
|
||||
|
||||
printf("BGM stopped.\n");
|
||||
log_info("BGM stopped");
|
||||
} else {
|
||||
printf("stop_bgm(): No BGM was playing.\n");
|
||||
log_info("No BGM was playing");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,7 +123,7 @@ void start_bgm(const char *name) {
|
|||
stralloc(¤t_bgm.name, name);
|
||||
|
||||
if((current_bgm.music = get_music(name)) == NULL) {
|
||||
warnx("start_bgm(): BGM '%s' does not exist", current_bgm.name);
|
||||
log_warn("BGM '%s' does not exist", current_bgm.name);
|
||||
stop_bgm(true);
|
||||
free(current_bgm.name);
|
||||
current_bgm.name = NULL;
|
||||
|
@ -181,7 +152,7 @@ void start_bgm(const char *name) {
|
|||
current_bgm.started_at = -1;
|
||||
}
|
||||
|
||||
printf("Started %s\n", (current_bgm.title ? current_bgm.title : current_bgm.name));
|
||||
log_info("Started %s", (current_bgm.title ? current_bgm.title : current_bgm.name));
|
||||
}
|
||||
|
||||
void audio_init(void) {
|
||||
|
@ -193,6 +164,9 @@ void audio_init(void) {
|
|||
|
||||
void audio_shutdown(void) {
|
||||
audio_backend_shutdown();
|
||||
hashtable_foreach(bgm_descriptions, hashtable_iter_free_data, NULL);
|
||||
hashtable_free(bgm_descriptions);
|
||||
|
||||
if(bgm_descriptions) {
|
||||
hashtable_foreach(bgm_descriptions, hashtable_iter_free_data, NULL);
|
||||
hashtable_free(bgm_descriptions);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "audio.h"
|
||||
#include "global.h"
|
||||
#include "list.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
#define AUDIO_FREQ 44100
|
||||
#define AUDIO_FORMAT MIX_DEFAULT_FORMAT
|
||||
|
@ -30,7 +29,7 @@ void audio_backend_init(void) {
|
|||
}
|
||||
|
||||
if(SDL_InitSubSystem(SDL_INIT_AUDIO)) {
|
||||
warnx("audio_backend_init(): SDL_InitSubSystem() failed: %s.\n", SDL_GetError());
|
||||
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -40,21 +39,21 @@ void audio_backend_init(void) {
|
|||
}
|
||||
|
||||
if(Mix_OpenAudio(AUDIO_FREQ, AUDIO_FORMAT, 2, config_get_int(CONFIG_MIXER_CHUNKSIZE)) == -1) {
|
||||
warnx("audio_backend_init(): Mix_OpenAudio() failed: %s.\n", Mix_GetError());
|
||||
log_warn("Mix_OpenAudio() failed: %s", Mix_GetError());
|
||||
Mix_Quit();
|
||||
return;
|
||||
}
|
||||
|
||||
int channels = Mix_AllocateChannels(AUDIO_CHANNELS);
|
||||
if(!channels) {
|
||||
warnx("audio_backend_init(): unable to allocate any channels.\n");
|
||||
log_warn("Unable to allocate any channels");
|
||||
Mix_CloseAudio();
|
||||
Mix_Quit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(channels < AUDIO_CHANNELS) {
|
||||
warnx("audio_backend_init(): allocated only %d of %d channels.\n", channels, AUDIO_CHANNELS);
|
||||
log_warn("Allocated only %d of %d channels", channels, AUDIO_CHANNELS);
|
||||
}
|
||||
|
||||
mixer_loaded = true;
|
||||
|
@ -68,13 +67,13 @@ void audio_backend_init(void) {
|
|||
Mix_QuerySpec(&frequency, &format, &channels);
|
||||
|
||||
if(frequency != AUDIO_FREQ || format != AUDIO_FORMAT) {
|
||||
warnx( "audio_backend_init(): mixer spec doesn't match our request, "
|
||||
"requested (freq=%i, fmt=%u), got (freq=%i, fmt=%u). "
|
||||
"Sound may be distorted.",
|
||||
AUDIO_FREQ, AUDIO_FORMAT, frequency, format);
|
||||
log_warn( "Mixer spec doesn't match our request, "
|
||||
"requested (freq=%i, fmt=%u), got (freq=%i, fmt=%u). "
|
||||
"Sound may be distorted.",
|
||||
AUDIO_FREQ, AUDIO_FORMAT, frequency, format);
|
||||
}
|
||||
|
||||
printf("audio_backend_init(): audio subsystem initialized (SDL2_Mixer)\n");
|
||||
log_info("Audio subsystem initialized (SDL2_Mixer)");
|
||||
}
|
||||
|
||||
void audio_backend_shutdown(void) {
|
||||
|
@ -83,7 +82,7 @@ void audio_backend_shutdown(void) {
|
|||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
mixer_loaded = false;
|
||||
|
||||
printf("audio_backend_shutdown(): audio subsystem uninitialized (SDL2_Mixer)\n");
|
||||
log_info("Audio subsystem uninitialized (SDL2_Mixer)");
|
||||
}
|
||||
|
||||
bool audio_backend_initialized(void) {
|
||||
|
@ -153,7 +152,7 @@ bool audio_backend_music_play(void *impl) {
|
|||
bool result = (Mix_PlayMusic((Mix_Music*)impl, -1) != -1);
|
||||
|
||||
if(!result) {
|
||||
warnx("audio_backend_music_play(): Mix_PlayMusic() failed: %s", Mix_GetError());
|
||||
log_warn("Mix_PlayMusic() failed: %s", Mix_GetError());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -166,7 +165,7 @@ bool audio_backend_sound_play(void *impl) {
|
|||
bool result = (Mix_PlayChannel(-1, (Mix_Chunk*)impl, 0) != -1);
|
||||
|
||||
if(!result) {
|
||||
warnx("audio_backend_sound_play(): Mix_PlayChannel() failed: %s", Mix_GetError());
|
||||
log_warn("Mix_PlayChannel() failed: %s", Mix_GetError());
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
25
src/boss.c
|
@ -289,22 +289,20 @@ void free_attack(Attack *a) {
|
|||
}
|
||||
|
||||
void start_attack(Boss *b, Attack *a) {
|
||||
#if DEBUG
|
||||
printf("BOSS start_attack(): %s\n", a->name);
|
||||
#endif
|
||||
log_debug("%s", a->name);
|
||||
|
||||
if(global.replaymode == REPLAY_RECORD && global.stage->type == STAGE_STORY && !global.plr.continues) {
|
||||
StageInfo *i = stage_get_by_spellcard(a->info, global.diff);
|
||||
if(i) {
|
||||
StageProgress *p = stage_get_progress_from_info(i, global.diff, true);
|
||||
if(p && !p->unlocked) {
|
||||
printf("Spellcard unlocked! %s: %s\n", i->title, i->subtitle);
|
||||
log_info("Spellcard unlocked! %s: %s", i->title, i->subtitle);
|
||||
p->unlocked = true;
|
||||
}
|
||||
}
|
||||
#if DEBUG
|
||||
else if(a->type == AT_Spellcard || a->type == AT_ExtraSpell) {
|
||||
warnx("FIXME: spellcard '%s' is not available in spell practice mode!", a->name);
|
||||
log_warn("FIXME: spellcard '%s' is not available in spell practice mode!", a->name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -325,6 +323,7 @@ void start_attack(Boss *b, Attack *a) {
|
|||
Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) {
|
||||
boss->attacks = realloc(boss->attacks, sizeof(Attack)*(++boss->acount));
|
||||
Attack *a = &boss->attacks[boss->acount-1];
|
||||
memset(a, 0, sizeof(Attack));
|
||||
|
||||
boss->current = &boss->attacks[0];
|
||||
|
||||
|
@ -362,3 +361,19 @@ Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move) {
|
|||
a->info = info;
|
||||
return a;
|
||||
}
|
||||
|
||||
void boss_preload(void) {
|
||||
preload_resources(RES_SFX, RESF_OPTIONAL,
|
||||
"charge_generic",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"boss_spellcircle0",
|
||||
"boss_circle",
|
||||
"boss_indicator",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"boss_zoom",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -114,6 +114,8 @@ Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move);
|
|||
void boss_death(Boss **boss);
|
||||
void boss_kill_projectiles(void);
|
||||
|
||||
void boss_preload(void);
|
||||
|
||||
#define BOSS_DEFAULT_SPAWN_POS (VIEWPORT_W * 0.5 - I * VIEWPORT_H * 0.5)
|
||||
#define BOSS_DEFAULT_GO_POS (VIEWPORT_W * 0.5 + 200.0*I)
|
||||
#define BOSS_NOMOVE (-3142-39942.0*I)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "color.h"
|
||||
|
||||
|
|
114
src/config.c
|
@ -7,12 +7,10 @@
|
|||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "global.h"
|
||||
#include "paths/native.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
static bool config_initialized = false;
|
||||
|
||||
|
@ -182,11 +180,7 @@ static void config_set_val(ConfigIndex idx, ConfigValue v) {
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
#define PRINTVAL(t) printf("config_set_val(): %s:" #t " = %" #t "\n", e->name, e->val.t);
|
||||
#else
|
||||
#define PRINTVAL(t)
|
||||
#endif
|
||||
#define PRINTVAL(t) log_debug("%s:" #t " = %" #t, e->name, e->val.t);
|
||||
|
||||
switch(e->type) {
|
||||
case CONFIG_TYPE_INT:
|
||||
|
@ -269,69 +263,71 @@ static void config_delete_unknown_entries(void) {
|
|||
delete_all_elements((void**)&unknowndefs, config_delete_unknown_entry);
|
||||
}
|
||||
|
||||
static FILE* config_open(const char *filename, const char *mode) {
|
||||
char *buf = strjoin(get_config_path(), "/", filename, NULL);
|
||||
FILE *out = fopen(buf, mode);
|
||||
static char* config_path(const char *filename) {
|
||||
return strjoin(get_config_path(), "/", filename, NULL);
|
||||
}
|
||||
|
||||
static SDL_RWops* config_open(const char *filename, const char *mode) {
|
||||
char *buf = config_path(filename);
|
||||
SDL_RWops *out = SDL_RWFromFile(buf, mode);
|
||||
|
||||
free(buf);
|
||||
|
||||
if(!out) {
|
||||
warnx("config_open(): couldn't open '%s'", filename);
|
||||
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void config_save(const char *filename) {
|
||||
FILE *out = config_open(filename, "w");
|
||||
SDL_RWops *out = config_open(filename, "w");
|
||||
ConfigEntry *e = configdefs;
|
||||
|
||||
if(!out)
|
||||
return;
|
||||
|
||||
fputs("# Generated by taisei\n", out);
|
||||
SDL_RWprintf(out, "# Generated by taisei\n");
|
||||
|
||||
do switch(e->type) {
|
||||
case CONFIG_TYPE_INT:
|
||||
fprintf(out, "%s = %i\n", e->name, e->val.i);
|
||||
SDL_RWprintf(out, "%s = %i\n", e->name, e->val.i);
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_KEYBINDING:
|
||||
fprintf(out, "%s = %s\n", e->name, SDL_GetScancodeName(e->val.i));
|
||||
SDL_RWprintf(out, "%s = %s\n", e->name, SDL_GetScancodeName(e->val.i));
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_STRING:
|
||||
fprintf(out, "%s = %s\n", e->name, e->val.s);
|
||||
SDL_RWprintf(out, "%s = %s\n", e->name, e->val.s);
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_FLOAT:
|
||||
fprintf(out, "%s = %f\n", e->name, e->val.f);
|
||||
SDL_RWprintf(out, "%s = %f\n", e->name, e->val.f);
|
||||
break;
|
||||
} while((++e)->name);
|
||||
|
||||
if(unknowndefs) {
|
||||
fputs("# The following options were not recognized by taisei\n", out);
|
||||
SDL_RWprintf(out, "# The following options were not recognized by taisei\n");
|
||||
|
||||
for(ConfigEntryList *l = unknowndefs; l; l = l->next) {
|
||||
e = &l->entry;
|
||||
fprintf(out, "%s = %s\n", e->name, e->val.s);
|
||||
SDL_RWprintf(out, "%s = %s\n", e->name, e->val.s);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
printf("Saved config '%s'\n", filename);
|
||||
SDL_RWclose(out);
|
||||
log_info("Saved config '%s'", filename);
|
||||
}
|
||||
|
||||
#define SYNTAXERROR { warnx("config_load(): syntax error on line %i, aborted! [%s:%i]\n", line, __FILE__, __LINE__); goto end; }
|
||||
#define BUFFERERROR { warnx("config_load(): string exceed the limit of %i, aborted! [%s:%i]", CONFIG_LOAD_BUFSIZE, __FILE__, __LINE__); goto end; }
|
||||
#define INTOF(s) ((int)strtol(s, NULL, 10))
|
||||
#define FLOATOF(s) ((float)strtod(s, NULL))
|
||||
|
||||
static void config_set(const char *key, const char *val) {
|
||||
static void config_set(const char *key, const char *val, void *data) {
|
||||
ConfigEntry *e = config_find_entry(key);
|
||||
|
||||
if(!e) {
|
||||
warnx("config_set(): unknown setting '%s'", key);
|
||||
log_warn("Unknown setting '%s'", key);
|
||||
config_set_unknown(key, val);
|
||||
return;
|
||||
}
|
||||
|
@ -345,7 +341,7 @@ static void config_set(const char *key, const char *val) {
|
|||
SDL_Scancode scan = SDL_GetScancodeFromName(val);
|
||||
|
||||
if(scan == SDL_SCANCODE_UNKNOWN) {
|
||||
warnx("config_set(): unknown key '%s'", val);
|
||||
log_warn("Unknown key '%s'", val);
|
||||
} else {
|
||||
e->val.i = scan;
|
||||
}
|
||||
|
@ -367,68 +363,10 @@ static void config_set(const char *key, const char *val) {
|
|||
#undef FLOATOF
|
||||
|
||||
void config_load(const char *filename) {
|
||||
FILE *in = config_open(filename, "r");
|
||||
int c, i = 0, found, line = 0;
|
||||
char buf[CONFIG_LOAD_BUFSIZE];
|
||||
char key[CONFIG_LOAD_BUFSIZE];
|
||||
char val[CONFIG_LOAD_BUFSIZE];
|
||||
|
||||
char *path = config_path(filename);
|
||||
config_init();
|
||||
|
||||
if(!in) {
|
||||
return;
|
||||
if(!parse_keyvalue_file_cb(path, config_set, NULL)) {
|
||||
log_warn("Errors occured while parsing the configuration file");
|
||||
}
|
||||
|
||||
while((c = fgetc(in)) != EOF) {
|
||||
if(c == '#' && !i) {
|
||||
i = 0;
|
||||
while(fgetc(in) != '\n');
|
||||
} else if(c == ' ') {
|
||||
if(!i) SYNTAXERROR
|
||||
|
||||
buf[i] = 0;
|
||||
i = 0;
|
||||
strcpy(key, buf);
|
||||
|
||||
found = 0;
|
||||
while((c = fgetc(in)) != EOF) {
|
||||
if(c == '=') {
|
||||
if(++found > 1) SYNTAXERROR
|
||||
} else if(c != ' ') {
|
||||
if(!found || c == '\n') SYNTAXERROR
|
||||
|
||||
do {
|
||||
if(c == '\n') {
|
||||
if(!i) SYNTAXERROR
|
||||
|
||||
buf[i] = 0;
|
||||
i = 0;
|
||||
strcpy(val, buf);
|
||||
found = 0;
|
||||
++line;
|
||||
|
||||
config_set(key, val);
|
||||
break;
|
||||
} else {
|
||||
buf[i++] = c;
|
||||
if(i == CONFIG_LOAD_BUFSIZE)
|
||||
BUFFERERROR
|
||||
}
|
||||
} while((c = fgetc(in)) != EOF);
|
||||
|
||||
break;
|
||||
}
|
||||
} if(found) SYNTAXERROR
|
||||
} else {
|
||||
buf[i++] = c;
|
||||
if(i == CONFIG_LOAD_BUFSIZE)
|
||||
BUFFERERROR
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
fclose(in);
|
||||
free(path);
|
||||
}
|
||||
|
||||
#undef SYNTAXERROR
|
||||
#undef BUFFERERROR
|
||||
|
|
|
@ -253,7 +253,18 @@ void credits_free(void) {
|
|||
free(credits.entries);
|
||||
}
|
||||
|
||||
void credits_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_credits", RESF_OPTIONAL);
|
||||
preload_resource(RES_SHADER, "tower_wall", RESF_DEFAULT);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage6/sky",
|
||||
"stage6/towerwall",
|
||||
"yukkureimu",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void credits_loop(void) {
|
||||
credits_preload();
|
||||
credits_init();
|
||||
while(credits.end) {
|
||||
handle_events(NULL, 0, NULL);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
void credits_loop(void);
|
||||
void credits_add(char*, int);
|
||||
void credits_preload(void);
|
||||
|
||||
#define CREDITS_ENTRY_FADEIN 200.0
|
||||
#define CREDITS_ENTRY_FADEOUT 100.0
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include "difficulty.h"
|
||||
#include "resource/resource.h"
|
||||
|
||||
const char* difficulty_name(Difficulty diff) {
|
||||
switch(diff) {
|
||||
|
@ -40,3 +41,9 @@ Color difficulty_color(Difficulty diff) {
|
|||
default: return rgb(0.5, 0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
void difficulty_preload(void) {
|
||||
for(Difficulty diff = D_Easy; diff < NUM_SELECTABLE_DIFFICULTIES + D_Easy; ++diff) {
|
||||
preload_resource(RES_TEXTURE, difficulty_tex(diff), RESF_PERMANENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,5 +27,6 @@ typedef enum {
|
|||
const char* difficulty_name(Difficulty diff);
|
||||
const char* difficulty_tex(Difficulty diff);
|
||||
Color difficulty_color(Difficulty diff);
|
||||
void difficulty_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -121,8 +121,14 @@ void ending_draw(Ending *e) {
|
|||
draw_and_update_transition();
|
||||
}
|
||||
|
||||
void ending_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_ending", RESF_OPTIONAL);
|
||||
}
|
||||
|
||||
void ending_loop(void) {
|
||||
Ending e;
|
||||
|
||||
ending_preload();
|
||||
create_ending(&e);
|
||||
|
||||
global.frames = 0;
|
||||
|
|
|
@ -38,5 +38,6 @@ void add_ending_entry(Ending *e, int time, char *msg, char *tex);
|
|||
void create_ending(Ending *e);
|
||||
void ending_loop(void);
|
||||
void free_ending(Ending *e);
|
||||
void ending_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
15
src/enemy.c
|
@ -224,3 +224,18 @@ void process_enemies(Enemy **enemies) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enemies_preload(void) {
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"fairy",
|
||||
"bigfairy",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"swirl",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, RESF_OPTIONAL,
|
||||
"enemydeath",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -64,4 +64,6 @@ void BigFairy(Enemy*, int t);
|
|||
int enemy_flare(Projectile *p, int t);
|
||||
void EnemyFlareShrink(Projectile *p, int t);
|
||||
|
||||
void enemies_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "fbo.h"
|
||||
#include "global.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
void init_fbo(FBO *fbo) {
|
||||
glGenTextures(1, &fbo->tex);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
*/
|
||||
|
||||
#include "gamepad.h"
|
||||
#include "taisei_err.h"
|
||||
#include "config.h"
|
||||
#include "events.h"
|
||||
#include "global.h"
|
||||
|
@ -28,32 +27,32 @@ void gamepad_init(void) {
|
|||
return;
|
||||
|
||||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
|
||||
warnx("gamepad_init(): couldn't initialize SDL joystick subsystem: %s", SDL_GetError());
|
||||
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
int i, cnt = gamepad_devicecount();
|
||||
printf("gamepad_init(): found %i devices\n", cnt);
|
||||
log_info("Found %i devices", cnt);
|
||||
for(i = 0; i < cnt; ++i)
|
||||
printf("%i: %s\n", i, SDL_JoystickNameForIndex(i));
|
||||
log_info("Device #%i: %s", i, SDL_JoystickNameForIndex(i));
|
||||
|
||||
int dev = config_get_int(CONFIG_GAMEPAD_DEVICE);
|
||||
if(dev < 0 || dev >= cnt) {
|
||||
warnx("gamepad_init(): device %i is not available\n", dev);
|
||||
log_warn("Device #%i is not available", dev);
|
||||
gamepad_shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
gamepad.device = SDL_JoystickOpen(dev);
|
||||
if(!gamepad.device) {
|
||||
warnx("gamepad_init(): failed to open device %i [%s]", dev, gamepad_devicename(dev));
|
||||
log_warn("Failed to open device %i: %s", dev, SDL_GetError());
|
||||
gamepad_shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
gamepad.axis = malloc(SDL_JoystickNumAxes(gamepad.device));
|
||||
|
||||
printf("gamepad_init(): using device #%i: %s\n", dev, gamepad_devicename(dev));
|
||||
log_info("Using device #%i: %s", dev, gamepad_devicename(dev));
|
||||
SDL_JoystickEventState(SDL_ENABLE);
|
||||
gamepad.initialized = 1;
|
||||
}
|
||||
|
@ -63,7 +62,7 @@ void gamepad_shutdown(void) {
|
|||
return;
|
||||
|
||||
if(gamepad.initialized != 2)
|
||||
printf("gamepad_shutdown(): disabled the gamepad subsystem\n");
|
||||
log_info("Disabled the gamepad subsystem");
|
||||
|
||||
if(gamepad.device)
|
||||
SDL_JoystickClose(gamepad.device);
|
||||
|
@ -282,7 +281,7 @@ void gamepad_init_bare(void) {
|
|||
return;
|
||||
|
||||
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
|
||||
warnx("gamepad_init(): couldn't initialize SDL joystick subsystem: %s", SDL_GetError());
|
||||
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
10
src/global.c
|
@ -6,14 +6,6 @@
|
|||
*/
|
||||
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <png.h>
|
||||
#include "paths/native.h"
|
||||
#include "resource/resource.h"
|
||||
#include "taisei_err.h"
|
||||
#include "replay.h"
|
||||
|
||||
Global global;
|
||||
|
||||
|
@ -35,6 +27,6 @@ void init_global(void) {
|
|||
global.frameskip = INT_MAX;
|
||||
}
|
||||
|
||||
warnx("FPS limiter disabled by environment. Gotta go fast! (frameskip = %i)", global.frameskip);
|
||||
log_warn("FPS limiter disabled by environment. Gotta go fast! (frameskip = %i)", global.frameskip);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
#include "difficulty.h"
|
||||
#include "color.h"
|
||||
#include "audio.h"
|
||||
#include "taisei_err.h"
|
||||
#include "rwops/all.h"
|
||||
|
||||
#define FILE_PREFIX PREFIX "/share/taisei/"
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -301,13 +301,13 @@ void hashtable_print_stringkeys(Hashtable *ht) {
|
|||
int total = 0;
|
||||
int collisions = 0;
|
||||
|
||||
printf("------ %p:\n", (void*)ht);
|
||||
log_debug("------ %p:", (void*)ht);
|
||||
for(size_t i = 0; i < ht->table_size; ++i) {
|
||||
int elems = 0;
|
||||
printf("[bucket %lu] %p\n", (unsigned long)i, (void*)ht->table[i]);
|
||||
log_debug("[bucket %lu] %p", (unsigned long)i, (void*)ht->table[i]);
|
||||
|
||||
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
|
||||
printf(" -- %s (%lu): %p\n", (char*)e->key, (unsigned long)e->hash, e->data);
|
||||
log_debug(" -- %s (%lu): %p", (char*)e->key, (unsigned long)e->hash, e->data);
|
||||
++elems;
|
||||
++total;
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ void hashtable_print_stringkeys(Hashtable *ht) {
|
|||
}
|
||||
}
|
||||
|
||||
printf("%i total elements, %i unused buckets, %i collisions, max %i elems per bucket, %lu approx overhead\n",
|
||||
log_debug("%i total elements, %i unused buckets, %i collisions, max %i elems per bucket, %lu approx overhead",
|
||||
total, free_buckets, collisions, max_elems,
|
||||
(unsigned long int)hashtable_get_approx_overhead(ht));
|
||||
}
|
||||
|
@ -341,7 +341,7 @@ void hashtable_print_stringkeys(Hashtable *ht) {
|
|||
static void hashtable_printstrings(Hashtable *ht) {
|
||||
for(size_t i = 0; i < ht->table_size; ++i) {
|
||||
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
|
||||
printf("[HT %lu] %s (%lu): %s\n", (unsigned long)i, (char*)e->key, (unsigned long)e->hash, (char*)e->data);
|
||||
log_info("[HT %lu] %s (%lu): %s\n", (unsigned long)i, (char*)e->key, (unsigned long)e->hash, (char*)e->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +365,7 @@ int hashtable_test(void) {
|
|||
}
|
||||
|
||||
hashtable_printstrings(ht);
|
||||
printf("-----\n");
|
||||
log_info("-----\n");
|
||||
hashtable_set_string(ht, "12345", "asdfg");
|
||||
hashtable_unset_string(ht, "test");
|
||||
hashtable_set_string(ht, "herp", "deeeeeerp");
|
||||
|
|
14
src/item.c
|
@ -148,3 +148,17 @@ void spawn_items(complex pos, int point, int power, int bomb, int life) {
|
|||
for(i = 0; i < life; i++)
|
||||
spawn_item(pos, Life);
|
||||
}
|
||||
|
||||
void items_preload(void) {
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"items/power",
|
||||
"items/point",
|
||||
"items/life",
|
||||
"items/bomb",
|
||||
"items/bullet_point",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, RESF_OPTIONAL,
|
||||
"item_generic",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ void process_items(void);
|
|||
void spawn_item(complex pos, Type type);
|
||||
void spawn_items(complex pos, int point, int power, int bomb, int life);
|
||||
|
||||
void items_preload(void);
|
||||
|
||||
#define POWER_VALUE 3
|
||||
|
||||
#endif
|
||||
|
|
14
src/list.c
|
@ -84,7 +84,7 @@ void delete_all_elements_witharg(void **dest, void (callback)(void **, void *, v
|
|||
#endif
|
||||
|
||||
#ifdef DEBUG_REFS
|
||||
#define REFLOG(...) fprintf(stderr, __VA_ARGS__);
|
||||
#define REFLOG(...) log_debug(__VA_ARGS__);
|
||||
#else
|
||||
#define REFLOG(...)
|
||||
#endif
|
||||
|
@ -95,7 +95,7 @@ int add_ref(void *ptr) {
|
|||
for(i = 0; i < global.refs.count; i++) {
|
||||
if(global.refs.ptrs[i].ptr == ptr) {
|
||||
global.refs.ptrs[i].refs++;
|
||||
REFLOG("increased refcount for %p (ref %i): %i\n", ptr, i, global.refs.ptrs[i].refs);
|
||||
REFLOG("increased refcount for %p (ref %i): %i", ptr, i, global.refs.ptrs[i].refs);
|
||||
return i;
|
||||
} else if(firstfree < 0 && global.refs.ptrs[i].ptr == FREEREF) {
|
||||
firstfree = i;
|
||||
|
@ -105,14 +105,14 @@ int add_ref(void *ptr) {
|
|||
if(firstfree >= 0) {
|
||||
global.refs.ptrs[firstfree].ptr = ptr;
|
||||
global.refs.ptrs[firstfree].refs = 1;
|
||||
REFLOG("found free ref for %p: %i\n", ptr, firstfree);
|
||||
REFLOG("found free ref for %p: %i", ptr, firstfree);
|
||||
return firstfree;
|
||||
}
|
||||
|
||||
global.refs.ptrs = realloc(global.refs.ptrs, (++global.refs.count)*sizeof(Reference));
|
||||
global.refs.ptrs[global.refs.count - 1].ptr = ptr;
|
||||
global.refs.ptrs[global.refs.count - 1].refs = 1;
|
||||
REFLOG("new ref for %p: %i\n", ptr, global.refs.count - 1);
|
||||
REFLOG("new ref for %p: %i", ptr, global.refs.count - 1);
|
||||
|
||||
return global.refs.count - 1;
|
||||
}
|
||||
|
@ -130,12 +130,12 @@ void free_ref(int i) {
|
|||
return;
|
||||
|
||||
global.refs.ptrs[i].refs--;
|
||||
REFLOG("decreased refcount for %p (ref %i): %i\n", global.refs.ptrs[i].ptr, i, global.refs.ptrs[i].refs);
|
||||
REFLOG("decreased refcount for %p (ref %i): %i", global.refs.ptrs[i].ptr, i, global.refs.ptrs[i].refs);
|
||||
|
||||
if(global.refs.ptrs[i].refs <= 0) {
|
||||
global.refs.ptrs[i].ptr = FREEREF;
|
||||
global.refs.ptrs[i].refs = 0;
|
||||
REFLOG("ref %i is now free\n", i);
|
||||
REFLOG("ref %i is now free", i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ void free_all_refs(void) {
|
|||
}
|
||||
|
||||
if(inuse) {
|
||||
warnx("free_all_refs(): %i refs were still in use (%i unique, %i total allocated)", inuse, inuse_unique, global.refs.count);
|
||||
log_warn("%i refs were still in use (%i unique, %i total allocated)", inuse, inuse_unique, global.refs.count);
|
||||
}
|
||||
|
||||
free(global.refs.ptrs);
|
||||
|
|
226
src/log.c
Normal file
|
@ -0,0 +1,226 @@
|
|||
|
||||
#include <SDL_bits.h>
|
||||
#include <SDL_mutex.h>
|
||||
|
||||
#ifdef LOG_ENABLE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "list.h"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#define LOG_EOL "\r\n"
|
||||
#else
|
||||
#define LOG_EOL "\n"
|
||||
#endif
|
||||
|
||||
typedef struct Logger {
|
||||
struct Logger *next;
|
||||
struct Logger *prev;
|
||||
SDL_RWops *out;
|
||||
unsigned int levels;
|
||||
} Logger;
|
||||
|
||||
static Logger *loggers = NULL;
|
||||
static unsigned int enabled_log_levels;
|
||||
static unsigned int backtrace_log_levels;
|
||||
static SDL_mutex *log_mutex;
|
||||
|
||||
// order must much the LogLevel enum after LOG_NONE
|
||||
static const char *level_prefix_map[] = { "D", "I", "W", "E" };
|
||||
|
||||
static const char* level_prefix(LogLevel lvl) {
|
||||
int idx = SDL_MostSignificantBitIndex32(lvl);
|
||||
assert_nolog(idx >= 0 && idx < sizeof(level_prefix_map) / sizeof(char*));
|
||||
return level_prefix_map[idx];
|
||||
}
|
||||
|
||||
static char* format_log_string(LogLevel lvl, const char *funcname, const char *fmt, va_list args) {
|
||||
const char *pref = level_prefix(lvl);
|
||||
char *msg = vstrfmt(fmt, args);
|
||||
char *final = strfmt("%-9d %s: %s(): %s%s", SDL_GetTicks(), pref, funcname, msg, LOG_EOL);
|
||||
free(msg);
|
||||
|
||||
// TODO: maybe convert all \n in the message to LOG_EOL
|
||||
|
||||
return final;
|
||||
}
|
||||
|
||||
noreturn static void log_abort(const char *msg) {
|
||||
#ifdef LOG_FATAL_MSGBOX
|
||||
if(msg) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Taisei error", msg, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
// abort() doesn't clean up, but it lets us get a backtrace, which is more useful
|
||||
log_shutdown();
|
||||
abort();
|
||||
}
|
||||
|
||||
static void log_internal(LogLevel lvl, bool is_backtrace, const char *funcname, const char *fmt, va_list args) {
|
||||
assert(fmt[strlen(fmt)-1] != '\n');
|
||||
|
||||
char *str = NULL;
|
||||
size_t slen = 0;
|
||||
lvl &= enabled_log_levels;
|
||||
|
||||
if(lvl == LOG_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(Logger *l = loggers; l; l = l->next) {
|
||||
if(l->levels & lvl) {
|
||||
if(!str) {
|
||||
str = format_log_string(lvl, funcname, fmt, args);
|
||||
slen = strlen(str);
|
||||
}
|
||||
|
||||
// log_backtrace locks the mutex by itself, then recursively calls log_internal
|
||||
if(is_backtrace) {
|
||||
SDL_RWwrite(l->out, str, 1, slen);
|
||||
} else {
|
||||
SDL_LockMutex(log_mutex);
|
||||
SDL_RWwrite(l->out, str, 1, slen);
|
||||
SDL_UnlockMutex(log_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(str);
|
||||
|
||||
if(is_backtrace) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(lvl & backtrace_log_levels) {
|
||||
log_backtrace(lvl);
|
||||
}
|
||||
|
||||
if(lvl & LOG_FATAL) {
|
||||
log_abort(str);
|
||||
}
|
||||
}
|
||||
|
||||
static char** get_backtrace(int *num) {
|
||||
#ifdef LOG_ENABLE_BACKTRACE
|
||||
void *ptrs[*num];
|
||||
*num = backtrace(ptrs, *num);
|
||||
return backtrace_symbols(ptrs, *num);
|
||||
#else
|
||||
char **dummy = malloc(sizeof(char*));
|
||||
*num = 1;
|
||||
*dummy = "[Backtrace support is not available in this build]";
|
||||
return dummy;
|
||||
#endif
|
||||
}
|
||||
|
||||
void log_backtrace(LogLevel lvl) {
|
||||
int num = LOG_BACKTRACE_SIZE;
|
||||
char **symbols = get_backtrace(&num);
|
||||
|
||||
SDL_LockMutex(log_mutex);
|
||||
_taisei_log(lvl, true, __func__, "*** BACKTRACE ***");
|
||||
|
||||
for(int i = 0; i < num; ++i) {
|
||||
_taisei_log(lvl, true, __func__, "> %s", symbols[i]);
|
||||
}
|
||||
|
||||
_taisei_log(lvl, true, __func__, "*** END OF BACKTRACE ***");
|
||||
SDL_UnlockMutex(log_mutex);
|
||||
|
||||
free(symbols);
|
||||
}
|
||||
|
||||
void _taisei_log(LogLevel lvl, bool is_backtrace, const char *funcname, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log_internal(lvl, is_backtrace, funcname, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
noreturn void _taisei_log_fatal(LogLevel lvl, const char *funcname, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log_internal(lvl, false, funcname, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// should usually not get here, log_internal will abort earlier if lvl is LOG_FATAL
|
||||
// that is unless LOG_FATAL is disabled for some reason
|
||||
log_abort(NULL);
|
||||
}
|
||||
|
||||
static void delete_logger(void **loggers, void *logger) {
|
||||
Logger *l = logger;
|
||||
SDL_RWclose(l->out);
|
||||
delete_element(loggers, logger);
|
||||
}
|
||||
|
||||
void log_init(LogLevel lvls, LogLevel backtrace_lvls) {
|
||||
enabled_log_levels = lvls;
|
||||
backtrace_log_levels = lvls & backtrace_lvls;
|
||||
log_mutex = SDL_CreateMutex();
|
||||
}
|
||||
|
||||
void log_shutdown(void) {
|
||||
delete_all_elements((void**)&loggers, delete_logger);
|
||||
SDL_DestroyMutex(log_mutex);
|
||||
log_mutex = NULL;
|
||||
}
|
||||
|
||||
bool log_initialized(void) {
|
||||
return log_mutex;
|
||||
}
|
||||
|
||||
void log_add_output(LogLevel levels, SDL_RWops *output) {
|
||||
if(!output) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(levels & enabled_log_levels)) {
|
||||
SDL_RWclose(output);
|
||||
return;
|
||||
}
|
||||
|
||||
Logger *l = create_element((void**)&loggers, sizeof(Logger));
|
||||
l->levels = levels;
|
||||
l->out = output;
|
||||
}
|
||||
|
||||
static LogLevel chr2lvl(char c) {
|
||||
c = toupper(c);
|
||||
|
||||
for(int i = 0; i < sizeof(level_prefix_map) / sizeof(char*); ++i) {
|
||||
if(c == level_prefix_map[i][0]) {
|
||||
return (1 << i);
|
||||
} else if(c == 'A') {
|
||||
return LOG_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LogLevel log_parse_levels(LogLevel lvls, const char *lvlmod) {
|
||||
if(!lvlmod) {
|
||||
return lvls;
|
||||
}
|
||||
|
||||
bool enable = true;
|
||||
|
||||
for(const char *c = lvlmod; *c; ++c) {
|
||||
if(*c == '+') {
|
||||
enable = true;
|
||||
} else if(*c == '-') {
|
||||
enable = false;
|
||||
} else if(enable) {
|
||||
lvls |= chr2lvl(*c);
|
||||
} else {
|
||||
lvls &= ~chr2lvl(*c);
|
||||
}
|
||||
}
|
||||
|
||||
return lvls;
|
||||
}
|
86
src/log.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
|
||||
#ifndef TAISEI_LOG_H
|
||||
#define TAISEI_LOG_H
|
||||
|
||||
#include <stdnoreturn.h>
|
||||
#include <stdbool.h>
|
||||
#include <SDL.h>
|
||||
|
||||
typedef enum LogLevel {
|
||||
LOG_NONE = 0,
|
||||
LOG_DEBUG = 1,
|
||||
LOG_INFO = 2,
|
||||
LOG_WARN = 4,
|
||||
LOG_FATAL = 8,
|
||||
|
||||
LOG_SPAM = LOG_DEBUG | LOG_INFO,
|
||||
LOG_ALERT = LOG_WARN | LOG_FATAL,
|
||||
|
||||
LOG_ALL = LOG_SPAM | LOG_ALERT,
|
||||
} LogLevel;
|
||||
|
||||
#ifndef LOG_DEFAULT_LEVELS
|
||||
#define LOG_DEFAULT_LEVELS LOG_ALL
|
||||
#endif
|
||||
|
||||
#ifndef LOG_DEFAULT_LEVELS_FILE
|
||||
#define LOG_DEFAULT_LEVELS_FILE LOG_ALL
|
||||
#endif
|
||||
|
||||
#ifndef LOG_DEFAULT_LEVELS_CONSOLE
|
||||
#ifdef DEBUG
|
||||
#define LOG_DEFAULT_LEVELS_CONSOLE LOG_ALL
|
||||
#else
|
||||
#define LOG_DEFAULT_LEVELS_CONSOLE LOG_ALERT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LOG_DEFAULT_LEVELS_STDOUT
|
||||
#define LOG_DEFAULT_LEVELS_STDOUT LOG_SPAM
|
||||
#endif
|
||||
|
||||
#ifndef LOG_DEFAULT_LEVELS_STDERR
|
||||
#define LOG_DEFAULT_LEVELS_STDERR LOG_ALERT
|
||||
#endif
|
||||
|
||||
#ifndef LOG_DEFAULT_LEVELS_BACKTRACE
|
||||
#ifdef LOG_ENABLE_BACKTRACE
|
||||
#define LOG_DEFAULT_LEVELS_BACKTRACE LOG_FATAL
|
||||
#else
|
||||
#define LOG_DEFAULT_LEVELS_BACKTRACE LOG_NONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef LOG_BACKTRACE_SIZE
|
||||
#define LOG_BACKTRACE_SIZE 32
|
||||
#endif
|
||||
|
||||
void log_init(LogLevel lvls, LogLevel backtrace_lvls);
|
||||
void log_shutdown(void);
|
||||
void log_add_output(LogLevel levels, SDL_RWops *output);
|
||||
void log_backtrace(LogLevel lvl);
|
||||
LogLevel log_parse_levels(LogLevel lvls, const char *lvlmod);
|
||||
bool log_initialized(void);
|
||||
|
||||
#ifdef DEBUG
|
||||
#define log_debug(...) _taisei_log(LOG_DEBUG, false, __func__, __VA_ARGS__)
|
||||
#else
|
||||
#define log_debug(...)
|
||||
#endif
|
||||
|
||||
#define log_info(...) _taisei_log(LOG_INFO, false, __func__, __VA_ARGS__)
|
||||
#define log_warn(...) _taisei_log(LOG_WARN, false, __func__, __VA_ARGS__)
|
||||
#define log_fatal(...) _taisei_log_fatal(LOG_FATAL, __func__, __VA_ARGS__)
|
||||
#define log_custom(lvl, ...) _taisei_log(lvl, false, __func__, __VA_ARGS__)
|
||||
|
||||
//
|
||||
// don't call these directly, use the macros
|
||||
//
|
||||
|
||||
void _taisei_log(LogLevel lvl, bool is_backtrace, const char *funcname, const char *fmt, ...)
|
||||
__attribute__((format(printf, 4, 5)));
|
||||
|
||||
noreturn void _taisei_log_fatal(LogLevel lvl, const char *funcname, const char *fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
#endif
|
86
src/main.c
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include "taisei_err.h"
|
||||
#include <locale.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
|
@ -19,37 +19,44 @@
|
|||
#include "resource/bgm.h"
|
||||
#include "progress.h"
|
||||
#include "hashtable.h"
|
||||
#include "log.h"
|
||||
|
||||
void taisei_shutdown(void) {
|
||||
log_info("Shutting down");
|
||||
|
||||
config_save(CONFIG_FILE);
|
||||
progress_save();
|
||||
printf("\nshutdown:\n");
|
||||
|
||||
free_all_refs();
|
||||
free_resources();
|
||||
free_resources(true);
|
||||
audio_shutdown();
|
||||
video_shutdown();
|
||||
gamepad_shutdown();
|
||||
stage_free_array();
|
||||
config_uninit();
|
||||
|
||||
log_info("Good bye");
|
||||
SDL_Quit();
|
||||
printf("-- Good Bye.\n");
|
||||
|
||||
log_shutdown();
|
||||
}
|
||||
|
||||
void init_log(void) {
|
||||
#if defined(__WINDOWS__) && !defined(__WINDOWS_CONSOLE__)
|
||||
const char *pref = get_config_path();
|
||||
char *s;
|
||||
char *logpath = strfmt("%s/%s", pref, "log.txt");
|
||||
|
||||
s = strfmt("%s/%s", pref, "stdout.txt");
|
||||
freopen(s, "w", stdout);
|
||||
free(s);
|
||||
LogLevel lvls_console = log_parse_levels(LOG_DEFAULT_LEVELS_CONSOLE, getenv("TAISEI_LOGLVLS_CONSOLE"));
|
||||
LogLevel lvls_stdout = lvls_console & log_parse_levels(LOG_DEFAULT_LEVELS_STDOUT, getenv("TAISEI_LOGLVLS_STDOUT"));
|
||||
LogLevel lvls_stderr = lvls_console & log_parse_levels(LOG_DEFAULT_LEVELS_STDERR, getenv("TAISEI_LOGLVLS_STDERR"));
|
||||
LogLevel lvls_file = log_parse_levels(LOG_DEFAULT_LEVELS_FILE, getenv("TAISEI_LOGLVLS_FILE"));
|
||||
LogLevel lvls_backtrace = log_parse_levels(LOG_DEFAULT_LEVELS_BACKTRACE, getenv("TAISEI_LOGLVLS_BACKTRACE"));
|
||||
|
||||
s = strfmt("%s/%s", pref, "stderr.txt");
|
||||
freopen(s, "w", stderr);
|
||||
free(s);
|
||||
#endif
|
||||
log_init(LOG_DEFAULT_LEVELS, lvls_backtrace);
|
||||
log_add_output(lvls_stdout, SDL_RWFromFP(stdout, false));
|
||||
log_add_output(lvls_stderr, SDL_RWFromFP(stderr, false));
|
||||
log_add_output(lvls_file, SDL_RWFromFile(logpath, "w"));
|
||||
|
||||
free(logpath);
|
||||
}
|
||||
|
||||
int run_tests(void) {
|
||||
|
@ -83,16 +90,14 @@ int run_tests(void) {
|
|||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if(run_tests()) {
|
||||
return 0;
|
||||
}
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
#ifdef DEBUG
|
||||
if(argc >= 2 && argv[1] && !strcmp(argv[1], "dumpstages")) {
|
||||
stage_init_array();
|
||||
|
||||
for(StageInfo *stg = stages; stg->procs; ++stg) {
|
||||
printf("%i %s: %s\n", stg->id, stg->title, stg->subtitle);
|
||||
tsfprintf(stdout, "%i %s: %s\n", stg->id, stg->title, stg->subtitle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -105,7 +110,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
if(argc >= 2 && !strcmp(argv[1], "replay")) {
|
||||
if(argc < 3) {
|
||||
fprintf(stderr, "Usage: %s replay /path/to/replay.tsr [stage num]\n", argv[0]);
|
||||
tsfprintf(stderr, "Usage: %s replay /path/to/replay.tsr [stage num]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -123,40 +128,35 @@ int main(int argc, char **argv) {
|
|||
init_paths();
|
||||
init_log();
|
||||
|
||||
printf("Content path: %s\n", get_prefix());
|
||||
printf("Userdata path: %s\n", get_config_path());
|
||||
if(run_tests()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_info("Content path: %s", get_prefix());
|
||||
log_info("Userdata path: %s", get_config_path());
|
||||
|
||||
MKDIR(get_config_path());
|
||||
MKDIR(get_screenshots_path());
|
||||
MKDIR(get_replays_path());
|
||||
|
||||
if(chdir(get_prefix())) {
|
||||
errx(-1, "chdir() failed: %s", strerror(errno));
|
||||
log_fatal("chdir() failed: %s", strerror(errno));
|
||||
} else {
|
||||
char cwd[1024]; // i don't care if this is not enough for you, getcwd is garbage
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
printf("Changed working directory to %s\n", cwd);
|
||||
log_info("Changed working directory to %s", cwd);
|
||||
}
|
||||
|
||||
config_load(CONFIG_FILE);
|
||||
|
||||
printf("initialize:\n");
|
||||
|
||||
if(SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
errx(-1, "Error initializing SDL: %s", SDL_GetError());
|
||||
printf("-- SDL\n");
|
||||
log_fatal("SDL_Init() failed: %s", SDL_GetError());
|
||||
|
||||
init_global();
|
||||
|
||||
video_init();
|
||||
printf("-- Video and OpenGL\n");
|
||||
|
||||
audio_init();
|
||||
printf("-- Audio\n");
|
||||
|
||||
init_resources();
|
||||
draw_loading_screen();
|
||||
|
||||
load_resources();
|
||||
gamepad_init();
|
||||
stage_init_array();
|
||||
|
@ -164,7 +164,8 @@ int main(int argc, char **argv) {
|
|||
|
||||
set_transition(TransLoader, 0, FADE_TIME*2);
|
||||
|
||||
printf("initialization complete.\n");
|
||||
log_info("Initialization complete");
|
||||
|
||||
atexit(taisei_shutdown);
|
||||
|
||||
if(replay_path) {
|
||||
|
@ -180,28 +181,27 @@ int main(int argc, char **argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
printf("** Compiled with DEBUG flag!\n");
|
||||
log_warn("Compiled with DEBUG flag!");
|
||||
|
||||
if(argc >= 2 && argv[1]) {
|
||||
printf("** Entering stage skip mode: Stage %d\n", atoi(argv[1]));
|
||||
log_info("Entering stage skip mode: Stage %d", atoi(argv[1]));
|
||||
|
||||
StageInfo* stg = stage_get(atoi(argv[1]));
|
||||
|
||||
if(!stg) {
|
||||
errx(-1, "Invalid stage id");
|
||||
log_fatal("Invalid stage id");
|
||||
}
|
||||
|
||||
global.diff = stg->difficulty;
|
||||
|
||||
if(!global.diff) {
|
||||
if(argc == 3 && argv[2]) {
|
||||
global.diff = atoi(argv[2]);
|
||||
log_info("Setting difficulty to %s", difficulty_name(global.diff));
|
||||
} else if(!global.diff) {
|
||||
global.diff = D_Easy;
|
||||
}
|
||||
|
||||
if(argc == 3 && argv[2]) {
|
||||
printf("** Setting difficulty to %d.\n", atoi(argv[2]));
|
||||
global.diff = atoi(argv[2]);
|
||||
}
|
||||
|
||||
printf("** Entering %s.\n", stg->title);
|
||||
log_info("Entering %s", stg->title);
|
||||
|
||||
do {
|
||||
global.game_over = 0;
|
||||
|
|
|
@ -66,6 +66,8 @@ troll2:
|
|||
goto troll2;
|
||||
}
|
||||
|
||||
free_resources(false);
|
||||
|
||||
if(global.replay_stage) {
|
||||
switch(config_get_int(CONFIG_SAVE_RPY)) {
|
||||
case 0: break;
|
||||
|
@ -91,6 +93,7 @@ troll2:
|
|||
ending_loop();
|
||||
start_bgm("bgm_credits");
|
||||
credits_loop();
|
||||
free_resources(false);
|
||||
}
|
||||
|
||||
start_bgm("bgm_menu");
|
||||
|
|
|
@ -54,7 +54,7 @@ void draw_difficulty_menu(MenuData *menu) {
|
|||
menu->entries[i].drawdata += 0.2 * (30*(i == menu->cursor) - menu->entries[i].drawdata);
|
||||
|
||||
glPushMatrix();
|
||||
glTranslatef(SCREEN_W/2 - (int)menu->entries[i].drawdata+25*i-50, SCREEN_H/3 + 90*(i-0.3*menu->drawdata[0]),0);
|
||||
glTranslatef(SCREEN_W/2 + SCREEN_W*sign((i&1)-0.5)*(i!=menu->cursor)*menu_fade(menu) - (int)menu->entries[i].drawdata+25*i-50, SCREEN_H/3 + 90*(i-0.3*menu->drawdata[0]),0);
|
||||
|
||||
//glColor4f(0,0,0,1);
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
void continue_game(MenuData *m, void *arg)
|
||||
{
|
||||
printf("The game is being continued...\n");
|
||||
log_info("The game is being continued...");
|
||||
|
||||
if(global.replaymode == REPLAY_RECORD) { // actually... I'd be strange if REPLAY_PLAY ever got there
|
||||
replay_destroy(&global.replay); // 19:39:29 [@ laochailan] no. no fame for continue users >:D
|
||||
|
|
|
@ -165,7 +165,32 @@ void draw_main_menu(MenuData *menu) {
|
|||
}
|
||||
|
||||
void draw_loading_screen(void) {
|
||||
preload_resource(RES_TEXTURE, "loading", RESF_PERMANENT);
|
||||
set_ortho();
|
||||
draw_texture(SCREEN_W/2, SCREEN_H/2, "loading");
|
||||
SDL_GL_SwapWindow(video.window);
|
||||
}
|
||||
|
||||
void menu_preload(void) {
|
||||
difficulty_preload();
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"mainmenu/mainmenubg",
|
||||
"mainmenu/logo",
|
||||
"part/smoke",
|
||||
"part/petal",
|
||||
"dialog/marisa",
|
||||
"dialog/youmu",
|
||||
"charselect_arrow",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, RESF_PERMANENT | RESF_OPTIONAL,
|
||||
"generic_shot",
|
||||
"shot_special1",
|
||||
"hit",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_BGM, RESF_PERMANENT | RESF_OPTIONAL,
|
||||
"bgm_menu",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -15,5 +15,6 @@ void draw_main_menu_bg(MenuData *m);
|
|||
void draw_main_menu(MenuData *m);
|
||||
void main_menu_update_spellpractice(void);
|
||||
void draw_loading_screen(void);
|
||||
void menu_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "menu.h"
|
||||
#include "global.h"
|
||||
#include "video.h"
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "global.h"
|
||||
#include "video.h"
|
||||
#include "paths/native.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
// --- Menu entry <-> config option binding stuff --- //
|
||||
|
||||
|
|
|
@ -266,7 +266,7 @@ int fill_replayview_menu(MenuData *m) {
|
|||
int rpys = 0;
|
||||
|
||||
if(!dir) {
|
||||
printf("Could't read %s\n", get_replays_path());
|
||||
log_warn("Could't read %s", get_replays_path());
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
23
src/player.c
|
@ -434,3 +434,26 @@ void player_graze(Player *plr, complex pos, int pts) {
|
|||
create_particle2c("flare", pos, 0, Shrink, timeout_linear, 5 + 5 * afrand(2), (1+afrand(0)*5)*cexp(I*tsrand_a(1)))->type=PlrProj;
|
||||
}
|
||||
}
|
||||
|
||||
void player_preload(void) {
|
||||
const int flags = RESF_DEFAULT;
|
||||
|
||||
preload_resources(RES_TEXTURE, flags,
|
||||
"focus",
|
||||
"fairy_circle",
|
||||
"masterspark",
|
||||
"masterspark_ring",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, flags | RESF_OPTIONAL,
|
||||
"graze",
|
||||
"death",
|
||||
"generic_shot",
|
||||
"masterspark",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_ANIM, flags,
|
||||
"youmu",
|
||||
"marisa",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -110,4 +110,6 @@ void player_event(Player* plr, int type, int key);
|
|||
void player_applymovement(Player* plr);
|
||||
void player_input_workaround(Player *plr);
|
||||
|
||||
void player_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "progress.h"
|
||||
#include "paths/native.h"
|
||||
#include "taisei_err.h"
|
||||
#include "stage.h"
|
||||
|
||||
/*
|
||||
|
@ -73,18 +72,18 @@ static void progress_read(SDL_RWops *file) {
|
|||
int64_t filesize = SDL_RWsize(file);
|
||||
|
||||
if(filesize < 0) {
|
||||
warnx("progress_read(): SDL_RWsize() failed: %s", SDL_GetError());
|
||||
log_warn("SDL_RWsize() failed: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
if(filesize > PROGRESS_MAXFILESIZE) {
|
||||
warnx("progress_read(): progress file is huge (%i bytes, %i max)", filesize, PROGRESS_MAXFILESIZE);
|
||||
log_warn("Progress file is huge (%li bytes, %i max)", (long)filesize, PROGRESS_MAXFILESIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; i < sizeof(progress_magic_bytes); ++i) {
|
||||
if(SDL_ReadU8(file) != progress_magic_bytes[i]) {
|
||||
warnx("progress_read(): invalid header");
|
||||
log_warn("Invalid header");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +100,7 @@ static void progress_read(SDL_RWops *file) {
|
|||
uint8_t *buf = malloc(bufsize);
|
||||
|
||||
if(!SDL_RWread(file, buf, bufsize, 1)) {
|
||||
warnx("progress_read(): SDL_RWread() failed: %s", SDL_GetError());
|
||||
log_warn("SDL_RWread() failed: %s", SDL_GetError());
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
@ -110,7 +109,7 @@ static void progress_read(SDL_RWops *file) {
|
|||
uint32_t checksum = progress_checksum(buf, bufsize);
|
||||
|
||||
if(checksum != checksum_fromfile) {
|
||||
warnx("progress_read(): bad checksum: %x != %x", checksum, checksum_fromfile);
|
||||
log_warn("Bad checksum: %x != %x", checksum, checksum_fromfile);
|
||||
SDL_RWclose(vfile);
|
||||
free(buf);
|
||||
return;
|
||||
|
@ -152,7 +151,7 @@ static void progress_read(SDL_RWops *file) {
|
|||
break;
|
||||
|
||||
default:
|
||||
warnx("progress_read(): unknown command %i, skipping %u bytes", cmd, cmdsize);
|
||||
log_warn("Unknown command %i, skipping %u bytes", cmd, cmdsize);
|
||||
while(cur++ < cmdsize)
|
||||
SDL_ReadU8(vfile);
|
||||
break;
|
||||
|
@ -305,7 +304,7 @@ static void progress_write(SDL_RWops *file) {
|
|||
|
||||
if(SDL_RWtell(vfile) != bufsize) {
|
||||
free(buf);
|
||||
errx(-1, "progress_write(): buffer is inconsistent\n");
|
||||
log_fatal("Buffer is inconsistent");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -314,7 +313,7 @@ static void progress_write(SDL_RWops *file) {
|
|||
SDL_RWwrite(file, &cs, 4, 1);
|
||||
|
||||
if(!SDL_RWwrite(file, buf, bufsize, 1)) {
|
||||
warnx("progress_write(): SDL_RWread() failed: %s", SDL_GetError());
|
||||
log_fatal("SDL_RWwrite() failed: %s", SDL_GetError());
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
@ -348,7 +347,7 @@ void progress_load(void) {
|
|||
SDL_RWops *file = SDL_RWFromFile(p, "rb");
|
||||
|
||||
if(!file) {
|
||||
warnx("progress_load(): couldn't open the progress file: %s\n", SDL_GetError());
|
||||
log_warn("Couldn't open the progress file: %s", SDL_GetError());
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
|
@ -363,7 +362,7 @@ void progress_save(void) {
|
|||
SDL_RWops *file = SDL_RWFromFile(p, "wb");
|
||||
|
||||
if(!file) {
|
||||
warnx("progress_save(): couldn't open the progress file: %s\n", SDL_GetError());
|
||||
log_warn("Couldn't open the progress file: %s", SDL_GetError());
|
||||
free(p);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -419,3 +419,39 @@ void petal_explosion(int n, complex pos) {
|
|||
create_particle4c("petal", pos, rgba(0.6,1-afrand(0)*0.4,0.5,1-0.5*afrand(1)), Petal, asymptotic, (3+5*afrand(2))*cexp(I*M_PI*2*afrand(3)), 5, afrand(4) + afrand(5)*I, afrand(6) + 360.0*I*afrand(7));
|
||||
}
|
||||
}
|
||||
|
||||
void projectiles_preload(void) {
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"part/blast",
|
||||
"part/boss_shadow",
|
||||
"part/flare",
|
||||
"part/lasercurve",
|
||||
"part/marilaser_part0",
|
||||
"part/maristar_orbit",
|
||||
"part/petal",
|
||||
"part/smoke",
|
||||
"part/stain",
|
||||
"part/youmu_slice",
|
||||
"proj/ball",
|
||||
"proj/bigball",
|
||||
"proj/bullet",
|
||||
"proj/card",
|
||||
"proj/crystal",
|
||||
"proj/flea",
|
||||
"proj/hghost",
|
||||
"proj/marilaser",
|
||||
"proj/marisa",
|
||||
"proj/maristar",
|
||||
"proj/plainball",
|
||||
"proj/rice",
|
||||
"proj/soul",
|
||||
"proj/thickrice",
|
||||
"proj/wave",
|
||||
"proj/youhoming",
|
||||
"proj/youmu",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER, RESF_PERMANENT,
|
||||
"bullet_color",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -98,4 +98,6 @@ int timeout_linear(Projectile *p, int t);
|
|||
void Petal(Projectile *p, int t);
|
||||
void petal_explosion(int n, complex pos);
|
||||
|
||||
void projectiles_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
15
src/random.c
|
@ -11,7 +11,6 @@
|
|||
#include <time.h>
|
||||
#include "global.h"
|
||||
#include "random.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
/*
|
||||
* Multiply-with-carry algorithm
|
||||
|
@ -36,7 +35,7 @@ void tsrand_seed_p(RandomState *rnd, uint32_t seed) {
|
|||
|
||||
uint32_t tsrand_p(RandomState *rnd) {
|
||||
if(rnd->locked) {
|
||||
warnx("Attempted to use a locked RNG state!\n");
|
||||
log_warn("Attempted to use a locked RNG state");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -105,7 +104,7 @@ static uint32_t tsrand_array[TSRAND_ARRAY_LIMIT];
|
|||
static int tsrand_array_elems;
|
||||
static uint64_t tsrand_fillflags = 0;
|
||||
|
||||
static void tsrand_error(const char *file, unsigned int line, const char *fmt, ...) {
|
||||
static void tsrand_error(const char *file, const char *func, unsigned int line, const char *fmt, ...) {
|
||||
char buf[2048] = { 0 };
|
||||
va_list args;
|
||||
|
||||
|
@ -113,14 +112,14 @@ static void tsrand_error(const char *file, unsigned int line, const char *fmt, .
|
|||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
errx(-1, "tsrand error: %s [%s:%u]", buf, file, line);
|
||||
log_fatal("%s(): %s [%s:%u]", func, buf, file, line);
|
||||
}
|
||||
|
||||
#define TSRANDERR(...) tsrand_error(file, line, __VA_ARGS__)
|
||||
#define TSRANDERR(...) tsrand_error(file, __func__, line, __VA_ARGS__)
|
||||
|
||||
void __tsrand_fill_p(RandomState *rnd, int amount, const char *file, unsigned int line) {
|
||||
if(tsrand_fillflags) {
|
||||
TSRANDERR("tsrand_fill_p: some indices left unused from the previous call");
|
||||
TSRANDERR("Some indices left unused from the previous call");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -138,7 +137,7 @@ void __tsrand_fill(int amount, const char *file, unsigned int line) {
|
|||
|
||||
uint32_t __tsrand_a(int idx, const char *file, unsigned int line) {
|
||||
if(idx >= tsrand_array_elems || idx < 0) {
|
||||
TSRANDERR("tsrand_a: index out of range (%i / %i)", idx, tsrand_array_elems);
|
||||
TSRANDERR("Index out of range (%i / %i)", idx, tsrand_array_elems);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -147,7 +146,7 @@ uint32_t __tsrand_a(int idx, const char *file, unsigned int line) {
|
|||
return tsrand_array[idx];
|
||||
}
|
||||
|
||||
TSRANDERR("tsrand_a: index %i used multiple times", idx);
|
||||
TSRANDERR("Index %i used multiple times", idx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
73
src/replay.c
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "replay.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
@ -16,14 +15,13 @@
|
|||
|
||||
#include "global.h"
|
||||
#include "paths/native.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
static uint8_t replay_magic_header[] = REPLAY_MAGIC_HEADER;
|
||||
|
||||
void replay_init(Replay *rpy) {
|
||||
memset(rpy, 0, sizeof(Replay));
|
||||
stralloc(&rpy->playername, config_get_str(CONFIG_PLAYERNAME));
|
||||
printf("replay_init(): replay initialized for writting\n");
|
||||
log_debug("Replay at %p initialized for writing", (void*)rpy);
|
||||
}
|
||||
|
||||
ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, Difficulty diff, uint32_t points, Player *plr) {
|
||||
|
@ -52,7 +50,7 @@ ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, D
|
|||
s->plr_power = plr->power;
|
||||
s->plr_inputflags = plr->inputflags;
|
||||
|
||||
printf("replay_init_stage(): created a new stage for writting\n");
|
||||
log_debug("Created a new stage %p in replay %p", (void*)s, (void*)rpy);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -103,7 +101,7 @@ void replay_destroy(Replay *rpy) {
|
|||
free(rpy->playername);
|
||||
|
||||
memset(rpy, 0, sizeof(Replay));
|
||||
printf("Replay destroyed.\n");
|
||||
log_debug("Replay at %p destroyed", (void*)rpy);
|
||||
}
|
||||
|
||||
void replay_stage_event(ReplayStage *stg, uint32_t frame, uint8_t type, int16_t value) {
|
||||
|
@ -119,14 +117,14 @@ void replay_stage_event(ReplayStage *stg, uint32_t frame, uint8_t type, int16_t
|
|||
s->numevents++;
|
||||
|
||||
if(s->numevents >= s->capacity) {
|
||||
printf("Replay stage reached its capacity of %d, reallocating\n", s->capacity);
|
||||
log_debug("Replay stage reached its capacity of %d, reallocating", s->capacity);
|
||||
s->capacity *= 2;
|
||||
s->events = (ReplayEvent*)realloc(s->events, sizeof(ReplayEvent) * s->capacity);
|
||||
printf("The new capacity is %d\n", s->capacity);
|
||||
log_debug("The new capacity is %d", s->capacity);
|
||||
}
|
||||
|
||||
if(type == EV_OVER) {
|
||||
printf("The replay is OVER\n");
|
||||
log_debug("The replay is OVER");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,12 +251,12 @@ int replay_write(Replay *rpy, SDL_RWops *file, bool compression) {
|
|||
}
|
||||
|
||||
#ifdef REPLAY_LOAD_GARBAGE_TEST
|
||||
#define PRINTPROP(prop,fmt) printf("replay_read(): " #prop " = %" # fmt " [%li / %li]\n", prop, (long int)SDL_RWtell(file), (long int)filesize)
|
||||
#define PRINTPROP(prop,fmt) log_debug(#prop " = %" # fmt " [%li / %li]", prop, (long int)SDL_RWtell(file), (long int)filesize)
|
||||
#else
|
||||
#define PRINTPROP(prop,fmt) (void)(prop)
|
||||
#endif
|
||||
|
||||
#define CHECKPROP(prop,fmt) PRINTPROP(prop,fmt); if(filesize > 0 && SDL_RWtell(file) == filesize) { warnx("replay_read(): premature EOF"); return false; }
|
||||
#define CHECKPROP(prop,fmt) PRINTPROP(prop,fmt); if(filesize > 0 && SDL_RWtell(file) == filesize) { log_warn("Premature EOF"); return false; }
|
||||
|
||||
static void replay_read_string(SDL_RWops *file, char **ptr) {
|
||||
size_t len = SDL_ReadLE16(file);
|
||||
|
@ -273,7 +271,7 @@ static int replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, si
|
|||
for(uint8_t *u8_p = replay_magic_header; *u8_p; ++u8_p) {
|
||||
++(*ofs);
|
||||
if(SDL_ReadU8(file) != *u8_p) {
|
||||
warnx("replay_read(): incorrect header");
|
||||
log_warn("Incorrect header");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -282,7 +280,7 @@ static int replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, si
|
|||
(*ofs) += 2;
|
||||
|
||||
if((rpy->version & ~REPLAY_VERSION_COMPRESSION_BIT) != REPLAY_STRUCT_VERSION) {
|
||||
warnx("replay_read(): incorrect version");
|
||||
log_warn("Incorrect version");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -301,7 +299,7 @@ static int replay_read_meta(Replay *rpy, SDL_RWops *file, int64_t filesize) {
|
|||
CHECKPROP(rpy->numstages = SDL_ReadLE16(file), u);
|
||||
|
||||
if(!rpy->numstages) {
|
||||
warnx("replay_read(): no stages in replay");
|
||||
log_warn("No stages in replay");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -327,7 +325,7 @@ static int replay_read_meta(Replay *rpy, SDL_RWops *file, int64_t filesize) {
|
|||
CHECKPROP(stg->numevents = SDL_ReadLE16(file), u);
|
||||
|
||||
if(replay_calc_stageinfo_checksum(stg) + SDL_ReadLE32(file)) {
|
||||
warnx("replay_read(): stageinfo is corrupt");
|
||||
log_warn("Stageinfo is corrupt");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -340,7 +338,7 @@ static int replay_read_events(Replay *rpy, SDL_RWops *file, int64_t filesize) {
|
|||
ReplayStage *stg = rpy->stages + i;
|
||||
|
||||
if(!stg->numevents) {
|
||||
warnx("replay_read(): no events in stage");
|
||||
log_warn("No events in stage");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -366,23 +364,22 @@ int replay_read(Replay *rpy, SDL_RWops *file, ReplayReadMode mode) {
|
|||
mode &= REPLAY_READ_ALL;
|
||||
|
||||
if(!mode) {
|
||||
errx(-1, "replay_read(): called with invalid read mode");
|
||||
return false;
|
||||
log_fatal("Called with invalid read mode");
|
||||
}
|
||||
|
||||
filesize = SDL_RWsize(file);
|
||||
|
||||
if(filesize < 0) {
|
||||
warnx("replay_read(): SDL_RWsize() failed: %s", SDL_GetError());
|
||||
log_warn("SDL_RWsize() failed: %s", SDL_GetError());
|
||||
} else {
|
||||
printf("replay_read(): %li bytes\n", (long int)filesize);
|
||||
log_debug("%li bytes", (long int)filesize);
|
||||
}
|
||||
|
||||
if(mode & REPLAY_READ_META) {
|
||||
memset(rpy, 0, sizeof(Replay));
|
||||
|
||||
if(filesize > 0 && filesize <= sizeof(replay_magic_header) + 2) {
|
||||
warnx("replay_read(): replay file is too short (%i)", filesize);
|
||||
log_warn("Replay file is too short (%li)", (long int)filesize);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -396,7 +393,7 @@ int replay_read(Replay *rpy, SDL_RWops *file, ReplayReadMode mode) {
|
|||
|
||||
if(rpy->version & REPLAY_VERSION_COMPRESSION_BIT) {
|
||||
if(rpy->fileoffset < SDL_RWtell(file)) {
|
||||
warnx("replay_read(): invalid offset %li", (long int)rpy->fileoffset);
|
||||
log_warn("Invalid offset %li", (long int)rpy->fileoffset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -425,20 +422,19 @@ int replay_read(Replay *rpy, SDL_RWops *file, ReplayReadMode mode) {
|
|||
if(mode & REPLAY_READ_EVENTS) {
|
||||
if(!(mode & REPLAY_READ_META)) {
|
||||
if(!rpy->fileoffset) {
|
||||
errx(-1, "replay_read(): tried to read events before reading metadata");
|
||||
return false;
|
||||
log_fatal("Tried to read events before reading metadata");
|
||||
}
|
||||
|
||||
for(int i = 0; i < rpy->numstages; ++i) {
|
||||
if(rpy->stages[i].events) {
|
||||
warnx("replay_read(): reading events into a replay that already had events, call replay_destroy_events() if this is intended");
|
||||
log_warn("Reading events into a replay that already had events, call replay_destroy_events() if this is intended");
|
||||
replay_destroy_events(rpy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(SDL_RWseek(file, rpy->fileoffset, RW_SEEK_SET) < 0) {
|
||||
warnx("replay_read(): SDL_RWseek() failed: %s", SDL_GetError());
|
||||
log_warn("SDL_RWseek() failed: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -488,13 +484,13 @@ char* replay_getpath(const char *name, bool ext) {
|
|||
|
||||
int replay_save(Replay *rpy, const char *name) {
|
||||
char *p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
|
||||
printf("replay_save(): saving %s\n", p);
|
||||
log_info("Saving %s", p);
|
||||
|
||||
SDL_RWops *file = SDL_RWFromFile(p, "wb");
|
||||
free(p);
|
||||
|
||||
if(!file) {
|
||||
warnx("replay_save(): SDL_RWFromFile() failed: %s\n", SDL_GetError());
|
||||
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -512,7 +508,7 @@ int replay_load(Replay *rpy, const char *name, ReplayReadMode mode) {
|
|||
p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
|
||||
}
|
||||
|
||||
printf("replay_load(): loading %s (mode %i)\n", p, mode);
|
||||
log_info("replay_load(): loading %s (mode %i)", p, mode);
|
||||
|
||||
SDL_RWops *file = SDL_RWFromFile(p, "rb");
|
||||
|
||||
|
@ -521,7 +517,7 @@ int replay_load(Replay *rpy, const char *name, ReplayReadMode mode) {
|
|||
}
|
||||
|
||||
if(!file) {
|
||||
warnx("replay_save(): SDL_RWFromFile() failed: %s\n", SDL_GetError());
|
||||
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -569,14 +565,14 @@ void replay_stage_check_desync(ReplayStage *stg, int time, uint16_t check, Repla
|
|||
|
||||
if(mode == REPLAY_PLAY) {
|
||||
if(stg->desync_check && stg->desync_check != check) {
|
||||
warnx("replay_check_desync(): Replay desync detected! %u != %u\n", stg->desync_check, check);
|
||||
log_warn("Replay desync detected! %u != %u", stg->desync_check, check);
|
||||
} else {
|
||||
printf("replay_check_desync(): %u OK\n", check);
|
||||
log_debug("%u OK", check);
|
||||
}
|
||||
}
|
||||
#ifdef REPLAY_WRITE_DESYNC_CHECKS
|
||||
else {
|
||||
printf("replay_stage_check_desync(): %u\n", check);
|
||||
log_debug("%u", check);
|
||||
replay_stage_event(stg, time, EV_CHECK_DESYNC, (int16_t)check);
|
||||
}
|
||||
#endif
|
||||
|
@ -607,7 +603,7 @@ int replay_test(void) {
|
|||
SDL_WriteU8(handle, 's');
|
||||
SDL_WriteU8(handle, 't');
|
||||
|
||||
printf("replay_test(): wrote a valid replay header\n");
|
||||
log_info("Wrote a valid replay header");
|
||||
|
||||
RandomState rnd;
|
||||
tsrand_init(&rnd, time(0));
|
||||
|
@ -616,20 +612,20 @@ int replay_test(void) {
|
|||
SDL_WriteU8(handle, tsrand_p(&rnd) & 0xFF);
|
||||
}
|
||||
|
||||
printf("replay_test(): wrote %i bytes of garbage\n", sz);
|
||||
log_info("Wrote %i bytes of garbage", sz);
|
||||
|
||||
SDL_RWseek(handle, 0, RW_SEEK_SET);
|
||||
|
||||
for(int i = 0; i < headsz; ++i) {
|
||||
printf("%x ", buf[i]);
|
||||
tsfprintf(stdout, "%x ", buf[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
tsfprintf(stdout, "\n");
|
||||
|
||||
Replay rpy;
|
||||
|
||||
if(replay_read(&rpy, handle, REPLAY_READ_ALL)) {
|
||||
errx(-1, "Succeeded loading garbage data as a replay... that shouldn't happen");
|
||||
log_fatal("Succeeded loading garbage data as a replay... that shouldn't happen");
|
||||
}
|
||||
|
||||
replay_destroy(&rpy);
|
||||
|
@ -656,7 +652,7 @@ void replay_play(Replay *rpy, int firststage) {
|
|||
StageInfo *gstg = stage_get(rstg->stage);
|
||||
|
||||
if(!gstg) {
|
||||
printf("replay_play(): Invalid stage %d in replay at %i skipped.\n", rstg->stage, i);
|
||||
log_warn("Invalid stage %d in replay at %i skipped.\n", rstg->stage, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -673,6 +669,7 @@ void replay_play(Replay *rpy, int firststage) {
|
|||
global.replaymode = REPLAY_RECORD;
|
||||
replay_destroy(&global.replay);
|
||||
global.replay_stage = NULL;
|
||||
free_resources(false);
|
||||
}
|
||||
|
||||
void replay_play_path(const char *path, int firststage) {
|
||||
|
|
|
@ -5,92 +5,56 @@
|
|||
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include "animation.h"
|
||||
#include "texture.h"
|
||||
#include "global.h"
|
||||
#include "resource.h"
|
||||
#include "list.h"
|
||||
|
||||
#include "taisei_err.h"
|
||||
|
||||
char* animation_path(const char *name) {
|
||||
DIR *dir = opendir("gfx/");
|
||||
if(dir == NULL)
|
||||
return NULL;
|
||||
|
||||
struct dirent *dp;
|
||||
|
||||
while((dp = readdir(dir)) != NULL) {
|
||||
char *filepath = strjoin("gfx/", dp->d_name, NULL);
|
||||
char *tmpname = NULL;
|
||||
|
||||
if(check_animation_path(filepath)) {
|
||||
if(!strcmp(tmpname = animation_name(filepath), name)) {
|
||||
free(tmpname);
|
||||
return filepath;
|
||||
}
|
||||
}
|
||||
|
||||
free(filepath);
|
||||
free(tmpname);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return strjoin(ANI_PATH_PREFIX, name, ANI_EXTENSION, NULL);
|
||||
}
|
||||
|
||||
bool check_animation_path(const char *path) {
|
||||
char *base = strjoin(TEX_PATH_PREFIX, "ani_", NULL);
|
||||
bool result = strstartswith(path, base) && strendswith(path, TEX_EXTENSION);
|
||||
free(base);
|
||||
return result;
|
||||
return strendswith(path, ANI_EXTENSION);
|
||||
}
|
||||
|
||||
char* animation_name(const char *filename) {
|
||||
char *name = resource_util_basename(ANI_PATH_PREFIX, filename);
|
||||
char *c = name, *newname = NULL;
|
||||
|
||||
while(c = strchr(c, '_')) {
|
||||
newname = ++c;
|
||||
}
|
||||
|
||||
newname = strdup(newname);
|
||||
free(name);
|
||||
return newname;
|
||||
}
|
||||
|
||||
void* load_animation(const char *filename) {
|
||||
Animation *ani = malloc(sizeof(Animation));
|
||||
|
||||
void* load_animation(const char *filename, unsigned int flags) {
|
||||
char *basename = resource_util_basename(ANI_PATH_PREFIX, filename);
|
||||
char name[strlen(basename) + 1];
|
||||
strcpy(name, basename);
|
||||
|
||||
char *tok;
|
||||
strtok(name, "_");
|
||||
Hashtable *ht = parse_keyvalue_file(filename, 5);
|
||||
|
||||
#define ANIFAIL(what) { warnx("load_animation(): bad '" what "' in filename '%s'", basename); free(basename); return NULL; }
|
||||
|
||||
if((tok = strtok(NULL, "_")) == NULL)
|
||||
ANIFAIL("rows")
|
||||
ani->rows = atoi(tok);
|
||||
if((tok = strtok(NULL, "_")) == NULL)
|
||||
ANIFAIL("cols")
|
||||
ani->cols = atoi(tok);
|
||||
if((tok = strtok(NULL, "_")) == NULL)
|
||||
ANIFAIL("speed")
|
||||
ani->speed = atoi(tok);
|
||||
|
||||
if(ani->speed == 0) {
|
||||
warnx("load_animation(): animation speed of %s == 0. relativity?", name);
|
||||
if(!ht) {
|
||||
log_warn("parse_keyvalue_file() failed");
|
||||
free(basename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ani->tex = get_tex(basename);
|
||||
#define ANIFAIL(what) { log_warn("Bad '" what "' in animation '%s'", basename); free(ani); free(basename); return NULL; }
|
||||
|
||||
Animation *ani = malloc(sizeof(Animation));
|
||||
ani->rows = atoi((char*)hashtable_get_string(ht, "rows"));
|
||||
ani->cols = atoi((char*)hashtable_get_string(ht, "cols"));
|
||||
ani->speed = atoi((char*)hashtable_get_string(ht, "speed"));
|
||||
hashtable_foreach(ht, hashtable_iter_free_data, NULL);
|
||||
hashtable_free(ht);
|
||||
|
||||
if(ani->rows < 1) ANIFAIL("rows")
|
||||
if(ani->cols < 1) ANIFAIL("cols")
|
||||
|
||||
if(ani->speed == 0) {
|
||||
log_warn("Animation speed of %s == 0. relativity?", name);
|
||||
free(basename);
|
||||
free(ani);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ani->tex = get_resource(RES_TEXTURE, basename, flags)->texture;
|
||||
|
||||
if(!ani->tex) {
|
||||
warnx("load_animation(): couldn't get texture '%s'", basename);
|
||||
log_warn("Couldn't get texture '%s'", basename);
|
||||
free(basename);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -105,7 +69,7 @@ void* load_animation(const char *filename) {
|
|||
}
|
||||
|
||||
Animation *get_ani(const char *name) {
|
||||
return get_resource(RES_ANIM, name, RESF_REQUIRED)->animation;
|
||||
return get_resource(RES_ANIM, name, RESF_DEFAULT)->animation;
|
||||
}
|
||||
|
||||
void draw_animation(float x, float y, int row, const char *name) {
|
||||
|
|
|
@ -26,8 +26,7 @@ typedef struct Animation {
|
|||
|
||||
char* animation_path(const char *name);
|
||||
bool check_animation_path(const char *path);
|
||||
void* load_animation(const char *filename);
|
||||
char* animation_name(const char *filename);
|
||||
void* load_animation(const char *filename, unsigned int flags);
|
||||
|
||||
Animation *get_ani(const char *name);
|
||||
|
||||
|
@ -35,5 +34,6 @@ void draw_animation(float x, float y, int row, const char *name);
|
|||
void draw_animation_p(float x, float y, int row, Animation *ani);
|
||||
|
||||
#define ANI_PATH_PREFIX TEX_PATH_PREFIX
|
||||
#define ANI_EXTENSION ".ani"
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct Music {
|
|||
|
||||
char* music_path(const char *name);
|
||||
bool check_music_path(const char *path);
|
||||
void* load_music(const char *path);
|
||||
void* load_music(const char *path, unsigned int flags);
|
||||
void unload_music(void *snd);
|
||||
|
||||
#define BGM_PATH_PREFIX "bgm/"
|
||||
|
|
|
@ -22,11 +22,11 @@ bool check_music_path(const char *path) {
|
|||
return strstartswith(path, BGM_PATH_PREFIX) && audio_mixer_check_sound_path(path, true);
|
||||
}
|
||||
|
||||
void* load_music(const char *path) {
|
||||
void* load_music(const char *path, unsigned int flags) {
|
||||
Mix_Music *music = Mix_LoadMUS(path);
|
||||
|
||||
if(!music) {
|
||||
warnx("load_music(): Mix_LoadMUS() failed: %s", Mix_GetError());
|
||||
log_warn("Mix_LoadMUS() failed: %s", Mix_GetError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
char* music_path(const char *name) { return NULL; }
|
||||
bool check_music_path(const char *path) { return NULL; }
|
||||
void* load_music(const char *path) { return NULL; }
|
||||
void* load_music(const char *path, unsigned int flags) { return NULL; }
|
||||
void unload_music(void *vmus) { }
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include "font.h"
|
||||
#include "global.h"
|
||||
#include "paths/native.h"
|
||||
#include <assert.h>
|
||||
#include "taisei_err.h"
|
||||
|
||||
struct Fonts _fonts;
|
||||
|
||||
|
@ -18,9 +16,9 @@ TTF_Font *load_font(char *name, int size) {
|
|||
|
||||
TTF_Font *f = TTF_OpenFont(buf, size);
|
||||
if(!f)
|
||||
errx(-1, "failed to load font '%s'", buf);
|
||||
log_fatal("Failed to load font '%s'", buf);
|
||||
|
||||
printf("-- loaded '%s'\n", buf);
|
||||
log_info("Loaded '%s'", buf);
|
||||
|
||||
free(buf);
|
||||
return f;
|
||||
|
@ -68,7 +66,7 @@ void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *fo
|
|||
x -= tex->w/2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// if textures are odd pixeled, align them for ideal sharpness.
|
||||
if(tex->w&1)
|
||||
x += 0.5;
|
||||
|
|
|
@ -8,15 +8,10 @@
|
|||
#include "model.h"
|
||||
#include "list.h"
|
||||
#include "resource.h"
|
||||
#include "taisei_err.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void bad_reference_error(const char *filename, const char *aux, int n) {
|
||||
warnx("load_model():\n!- OBJ file '%s': Index %d: bad %s index reference\n", filename, n, aux);
|
||||
}
|
||||
|
||||
static void parse_obj(const char *filename, ObjFileData *data);
|
||||
static void free_obj(ObjFileData *data);
|
||||
|
||||
|
@ -28,7 +23,7 @@ bool check_model_path(const char *path) {
|
|||
return strendswith(path, MDL_EXTENSION);
|
||||
}
|
||||
|
||||
void* load_model(const char *path) {
|
||||
void* load_model(const char *path, unsigned int flags) {
|
||||
Model *m = malloc(sizeof(Model));
|
||||
|
||||
ObjFileData data;
|
||||
|
@ -45,7 +40,7 @@ void* load_model(const char *path) {
|
|||
|
||||
verts = calloc(data.icount, sizeof(Vertex));
|
||||
|
||||
#define BADREF(...) { bad_reference_error(__VA_ARGS__); free(verts); free_obj(&data); return NULL; }
|
||||
#define BADREF(filename,aux,n) { log_warn("OBJ file '%s': Index %d: bad %s index reference\n", filename, n, aux); free(verts); free_obj(&data); return NULL; }
|
||||
|
||||
memset(verts, 0, data.icount*sizeof(Vertex));
|
||||
for(i = 0; i < data.icount; i++) {
|
||||
|
@ -100,7 +95,12 @@ static void free_obj(ObjFileData *data) {
|
|||
}
|
||||
|
||||
static void parse_obj(const char *filename, ObjFileData *data) {
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
SDL_RWops *rw = SDL_RWFromFile(filename, "r");
|
||||
|
||||
if(!rw) {
|
||||
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
char line[256];
|
||||
Vector buf;
|
||||
|
@ -109,7 +109,7 @@ static void parse_obj(const char *filename, ObjFileData *data) {
|
|||
|
||||
memset(data, 0, sizeof(ObjFileData));
|
||||
|
||||
while(fgets(line, sizeof(line), fp)) {
|
||||
while(SDL_RWgets(rw, line, sizeof(line))) {
|
||||
linen++;
|
||||
|
||||
char *first;
|
||||
|
@ -175,7 +175,7 @@ static void parse_obj(const char *filename, ObjFileData *data) {
|
|||
}
|
||||
|
||||
if(jj == 0 || jj > 3 || segment[0] == '/')
|
||||
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: Corrupt face definition\n", filename,linen);
|
||||
log_fatal("OBJ file '%s:%d': Parsing error: Corrupt face definition", filename,linen);
|
||||
|
||||
data->indices = realloc(data->indices, sizeof(IVector)*(++data->icount));
|
||||
memcpy(data->indices[data->icount-1], ibuf, sizeof(IVector));
|
||||
|
@ -185,18 +185,18 @@ static void parse_obj(const char *filename, ObjFileData *data) {
|
|||
data->fverts = j;
|
||||
|
||||
if(data->fverts != j)
|
||||
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: face vertex count must stay the same in the whole file\n", filename, linen);
|
||||
log_fatal("OBJ file '%s:%d': Parsing error: face vertex count must stay the same in the whole file", filename, linen);
|
||||
|
||||
if(data->fverts != 3 && data->fverts != 4)
|
||||
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: face vertex count must be either 3 or 4\n", filename, linen);
|
||||
log_fatal("OBJ file '%s:%d': Parsing error: face vertex count must be either 3 or 4", filename, linen);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
|
||||
Model* get_model(const char *name) {
|
||||
return get_resource(RES_MODEL, name, RESF_REQUIRED)->model;
|
||||
return get_resource(RES_MODEL, name, RESF_DEFAULT)->model;
|
||||
}
|
||||
|
||||
void draw_model_p(Model *model) {
|
||||
|
|
|
@ -37,7 +37,7 @@ typedef struct Model {
|
|||
|
||||
char* model_path(const char *name);
|
||||
bool check_model_path(const char *path);
|
||||
void* load_model(const char *path);
|
||||
void* load_model(const char *path, unsigned int flags);
|
||||
void unload_model(void*); // Does not delete elements from the VBO, so doing this at runtime is leaking VBO space
|
||||
|
||||
Model* get_model(const char *name);
|
||||
|
|
|
@ -5,14 +5,13 @@
|
|||
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include "resource.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "paths/native.h"
|
||||
#include "config.h"
|
||||
#include "taisei_err.h"
|
||||
#include "video.h"
|
||||
#include "menu/mainmenu.h"
|
||||
|
||||
Resources resources;
|
||||
|
||||
|
@ -65,18 +64,25 @@ Resource* insert_resource(ResourceType type, const char *name, void *data, Resou
|
|||
Resource *oldres = hashtable_get_string(handler->mapping, name);
|
||||
Resource *res = malloc(sizeof(Resource));
|
||||
|
||||
if(type == RES_MODEL) {
|
||||
// FIXME: models can't be safely unloaded at runtime
|
||||
flags |= RESF_PERMANENT;
|
||||
}
|
||||
|
||||
res->type = handler->type;
|
||||
res->flags = flags;
|
||||
res->data = data;
|
||||
|
||||
if(oldres) {
|
||||
warnx("insert_resource(): replacing a previously loaded %s '%s'", resource_type_names[type], name);
|
||||
log_warn("Replacing a previously loaded %s '%s'", resource_type_names[type], name);
|
||||
unload_resource(oldres);
|
||||
}
|
||||
|
||||
hashtable_set_string(handler->mapping, name, res);
|
||||
|
||||
printf("Loaded %s '%s' from '%s'\n", resource_type_names[handler->type], name, source);
|
||||
log_info("Loaded %s '%s' from '%s' (%s)", resource_type_names[handler->type], name, source,
|
||||
(flags & RESF_PERMANENT) ? "permanent" : "transient");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -102,10 +108,10 @@ static Resource* load_resource(ResourceHandler *handler, const char *path, const
|
|||
path = allocated_path = handler->find(name);
|
||||
|
||||
if(!path) {
|
||||
if(flags & RESF_REQUIRED) {
|
||||
errx(-1, "load_resource(): required %s '%s' couldn't be located", typename, name);
|
||||
if(!(flags & RESF_OPTIONAL)) {
|
||||
log_fatal("Required %s '%s' couldn't be located", typename, name);
|
||||
} else {
|
||||
warnx("load_resource(): failed to locate %s '%s'", typename, name);
|
||||
log_warn("Failed to locate %s '%s'", typename, name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -120,22 +126,22 @@ static Resource* load_resource(ResourceHandler *handler, const char *path, const
|
|||
res = hashtable_get_string(handler->mapping, name);
|
||||
|
||||
if(res) {
|
||||
warnx("load_resource(): %s '%s' is already loaded", typename, name);
|
||||
log_warn("%s '%s' is already loaded", typename, name);
|
||||
free(allocated_name);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
raw = handler->load(path);
|
||||
raw = handler->load(path, flags);
|
||||
|
||||
if(!raw) {
|
||||
name = name ? name : "<name unknown>";
|
||||
path = path ? path : "<path unknown>";
|
||||
|
||||
if(flags & RESF_REQUIRED) {
|
||||
errx(-1, "load_resource(): required %s '%s' couldn't be loaded (%s)", typename, name, path);
|
||||
if(!(flags & RESF_OPTIONAL)) {
|
||||
log_fatal("Required %s '%s' couldn't be loaded (%s)", typename, name, path);
|
||||
} else {
|
||||
warnx("load_resource(): failed to load %s '%s' (%s)", typename, name, path);
|
||||
log_warn("Failed to load %s '%s' (%s)", typename, name, path);
|
||||
}
|
||||
|
||||
free(allocated_path);
|
||||
|
@ -156,13 +162,43 @@ Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags)
|
|||
ResourceHandler *handler = get_handler(type);
|
||||
Resource *res = hashtable_get_string(handler->mapping, name);
|
||||
|
||||
if(!res) {
|
||||
if(!res || flags & RESF_OVERRIDE) {
|
||||
if(!(flags & (RESF_PRELOAD | RESF_OVERRIDE))) {
|
||||
log_warn("%s '%s' was not preloaded", resource_type_names[type], name);
|
||||
|
||||
if(!(flags & RESF_OPTIONAL) && getenvint("TAISEI_PRELOAD_REQUIRED")) {
|
||||
log_fatal("Aborting due to TAISEI_PRELOAD_REQUIRED");
|
||||
}
|
||||
}
|
||||
|
||||
res = load_resource(handler, NULL, name, flags);
|
||||
}
|
||||
|
||||
if(res && flags & RESF_PERMANENT && !(res->flags & RESF_PERMANENT)) {
|
||||
log_debug("Promoted %s '%s' to permanent", resource_type_names[type], name);
|
||||
res->flags |= RESF_PERMANENT;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void preload_resource(ResourceType type, const char *name, ResourceFlags flags) {
|
||||
if(!getenvint("TAISEI_NOPRELOAD")) {
|
||||
get_resource(type, name, flags | RESF_PRELOAD);
|
||||
}
|
||||
}
|
||||
|
||||
void preload_resources(ResourceType type, ResourceFlags flags, const char *firstname, ...) {
|
||||
va_list args;
|
||||
va_start(args, firstname);
|
||||
|
||||
for(const char *name = firstname; name; name = va_arg(args, const char*)) {
|
||||
preload_resource(type, name, flags);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void init_resources(void) {
|
||||
// hashtable sizes were carefully pulled out of my ass to reduce collisions a bit
|
||||
|
||||
|
@ -171,7 +207,7 @@ void init_resources(void) {
|
|||
);
|
||||
|
||||
register_handler(
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, 23
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, NULL, animation_path, check_animation_path, 23
|
||||
);
|
||||
|
||||
register_handler(
|
||||
|
@ -216,83 +252,21 @@ const char* resource_util_filename(const char *path) {
|
|||
return path;
|
||||
}
|
||||
|
||||
static void recurse_dir(const char *path) {
|
||||
DIR *dir = opendir(path);
|
||||
if(dir == NULL)
|
||||
errx(-1, "Can't open directory '%s'", path);
|
||||
|
||||
struct dirent *dp;
|
||||
|
||||
while((dp = readdir(dir)) != NULL) {
|
||||
char *filepath = strjoin(path, "/", dp->d_name, NULL);
|
||||
struct stat statbuf;
|
||||
|
||||
stat(filepath, &statbuf);
|
||||
|
||||
if(S_ISDIR(statbuf.st_mode) && *dp->d_name != '.') {
|
||||
recurse_dir(filepath);
|
||||
} else for(int rtype = 0; rtype < RES_NUMTYPES; ++rtype) {
|
||||
ResourceHandler *handler = get_handler(rtype);
|
||||
|
||||
if(handler->check(filepath)) {
|
||||
load_resource(handler, filepath, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
free(filepath);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void recurse_dir_rel(const char *relpath) {
|
||||
char *path = strdup(relpath);
|
||||
strip_trailing_slashes(path);
|
||||
recurse_dir(path);
|
||||
free(path);
|
||||
}
|
||||
|
||||
static void scan_resources(void) {
|
||||
ListContainer *visited = NULL;
|
||||
|
||||
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
|
||||
ResourceHandler *handler = get_handler(type);
|
||||
ListContainer *c;
|
||||
bool skip = false;
|
||||
|
||||
for(c = visited; c; c = c->next) {
|
||||
if(!strcmp((char*)c->data, handler->subdir)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!skip) {
|
||||
recurse_dir_rel(handler->subdir);
|
||||
create_container(&visited)->data = handler->subdir;
|
||||
}
|
||||
}
|
||||
|
||||
delete_all_elements((void**)&visited, delete_element);
|
||||
}
|
||||
|
||||
void load_resources(void) {
|
||||
if(!getenvint("TAISEI_NOSCAN")) {
|
||||
scan_resources();
|
||||
}
|
||||
|
||||
init_fonts();
|
||||
|
||||
if(glext.draw_instanced) {
|
||||
load_shader_snippets("shader/laser_snippets", "laser_");
|
||||
load_shader_snippets("shader/laser_snippets", "laser_", RESF_PERMANENT);
|
||||
}
|
||||
|
||||
menu_preload();
|
||||
|
||||
init_fbo(&resources.fbg[0]);
|
||||
init_fbo(&resources.fbg[1]);
|
||||
init_fbo(&resources.fsec);
|
||||
}
|
||||
|
||||
void free_resources(void) {
|
||||
void free_resources(bool all) {
|
||||
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
|
||||
ResourceHandler *handler = get_handler(type);
|
||||
|
||||
|
@ -303,11 +277,29 @@ void free_resources(void) {
|
|||
Resource *res;
|
||||
|
||||
for(HashtableIterator *i = hashtable_iter(handler->mapping); hashtable_iter_next(i, (void**)&name, (void**)&res);) {
|
||||
if(!all && res->flags & RESF_PERMANENT)
|
||||
continue;
|
||||
|
||||
ResourceFlags flags = res->flags;
|
||||
unload_resource(res);
|
||||
printf("Unloaded %s '%s'\n", resource_type_names[type], name);
|
||||
log_info("Unloaded %s '%s' (%s)", resource_type_names[type], name,
|
||||
(flags & RESF_PERMANENT) ? "permanent" : "transient"
|
||||
);
|
||||
|
||||
if(!all) {
|
||||
hashtable_unset_deferred(handler->mapping, name);
|
||||
}
|
||||
}
|
||||
|
||||
hashtable_free(handler->mapping);
|
||||
if(all) {
|
||||
hashtable_free(handler->mapping);
|
||||
} else {
|
||||
hashtable_unset_deferred_now(handler->mapping);
|
||||
}
|
||||
}
|
||||
|
||||
if(!all) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete_vbo(&_vbo);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "font.h"
|
||||
#include "model.h"
|
||||
#include "hashtable.h"
|
||||
#include "assert.h"
|
||||
#include "paths/native.h"
|
||||
|
||||
typedef enum ResourceType {
|
||||
|
@ -32,11 +31,14 @@ typedef enum ResourceType {
|
|||
} ResourceType;
|
||||
|
||||
typedef enum ResourceFlags {
|
||||
RESF_REQUIRED = 1,
|
||||
RESF_OVERRIDE = 2,
|
||||
// RESF_PERMANENT = 4;
|
||||
RESF_OVERRIDE = 1,
|
||||
RESF_OPTIONAL = 2,
|
||||
RESF_PERMANENT = 4,
|
||||
RESF_PRELOAD = 8,
|
||||
} ResourceFlags;
|
||||
|
||||
#define RESF_DEFAULT 0
|
||||
|
||||
// All paths are relative to the current working directory, which can assumed to be the resources directory,
|
||||
// unless mentioned otherwise.
|
||||
|
||||
|
@ -56,7 +58,7 @@ typedef bool (*ResourceCheckFunc)(const char *path);
|
|||
|
||||
// Loads a resource at path and returns a pointer to it.
|
||||
// Must return NULL and not crash the program on failure.
|
||||
typedef void* (*ResourceLoadFunc)(const char *path);
|
||||
typedef void* (*ResourceLoadFunc)(const char *path, unsigned int flags);
|
||||
|
||||
// Unloads a resource, freeing all allocated to it memory.
|
||||
typedef void (*ResourceUnloadFunc)(void *res);
|
||||
|
@ -97,10 +99,12 @@ extern Resources resources;
|
|||
|
||||
void init_resources(void);
|
||||
void load_resources(void);
|
||||
void free_resources(void);
|
||||
void free_resources(bool all);
|
||||
|
||||
Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags);
|
||||
Resource* insert_resource(ResourceType type, const char *name, void *data, ResourceFlags flags, const char *source);
|
||||
void preload_resource(ResourceType type, const char *name, ResourceFlags flags);
|
||||
void preload_resources(ResourceType type, ResourceFlags flags, const char *firstname, ...) __attribute__((sentinel));
|
||||
|
||||
void resource_util_strip_ext(char *path);
|
||||
char* resource_util_basename(const char *prefix, const char *path);
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct Sound {
|
|||
|
||||
char* sound_path(const char *name);
|
||||
bool check_sound_path(const char *path);
|
||||
void* load_sound(const char *path);
|
||||
void* load_sound(const char *path, unsigned int flags);
|
||||
void unload_sound(void *snd);
|
||||
|
||||
#define SFX_PATH_PREFIX "sfx/"
|
||||
|
|
|
@ -22,11 +22,11 @@ bool check_sound_path(const char *path) {
|
|||
return strstartswith(path, SFX_PATH_PREFIX) && audio_mixer_check_sound_path(path, false);
|
||||
}
|
||||
|
||||
void* load_sound(const char *path) {
|
||||
void* load_sound(const char *path, unsigned int flags) {
|
||||
Mix_Chunk *sound = Mix_LoadWAV(path);
|
||||
|
||||
if(!sound) {
|
||||
warnx("load_sound(): Mix_LoadWAV() failed: %s", Mix_GetError());
|
||||
log_warn("Mix_LoadWAV() failed: %s", Mix_GetError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
char* sound_path(const char *name) { return NULL; }
|
||||
bool check_sound_path(const char *path) { return NULL; }
|
||||
void* load_sound(const char *path) { return NULL; }
|
||||
void* load_sound(const char *path, unsigned int flags) { return NULL; }
|
||||
void unload_sound(void *vmus) { }
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "resource.h"
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
#include "taisei_err.h"
|
||||
|
||||
static char snippet_header_EXT_draw_instanced[] =
|
||||
"#version 120\n"
|
||||
|
@ -39,7 +38,7 @@ bool check_shader_path(const char *path) {
|
|||
|
||||
static Shader* load_shader(const char *vheader, const char *fheader, const char *vtext, const char *ftext);
|
||||
|
||||
void* load_shader_file(const char *path) {
|
||||
void* load_shader_file(const char *path, unsigned int flags) {
|
||||
char *text, *vtext, *ftext, *delim;
|
||||
|
||||
text = read_all(path, NULL);
|
||||
|
@ -48,7 +47,7 @@ void* load_shader_file(const char *path) {
|
|||
delim = strstr(text, SHA_DELIM);
|
||||
|
||||
if(delim == NULL) {
|
||||
warnx("load_shader_file(): expected '%s' delimiter.", SHA_DELIM);
|
||||
log_warn("Expected '%s' delimiter.", SHA_DELIM);
|
||||
free(text);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -81,14 +80,14 @@ static char* get_snippet_header(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void load_shader_snippets(const char *filename, const char *prefix) {
|
||||
void load_shader_snippets(const char *filename, const char *prefix, unsigned int flags) {
|
||||
int size, vhsize = 0, vfsize = 0, fhsize = 0, ffsize = 0, ssize, prefixlen;
|
||||
char *text, *vhead, *vfoot, *fhead, *ffoot;
|
||||
char *sec, *name, *nend, *send;
|
||||
char *vtext = NULL, *ftext = NULL;
|
||||
char *nbuf;
|
||||
|
||||
printf("-- loading snippet file '%s'\n", filename);
|
||||
log_info("Loading snippet file '%s' with prefix '%s'", filename, prefix);
|
||||
|
||||
prefixlen = strlen(prefix);
|
||||
|
||||
|
@ -103,9 +102,9 @@ void load_shader_snippets(const char *filename, const char *prefix) {
|
|||
ffoot = copy_segment(text, "%%FSHADER-FOOT%%", &ffsize);
|
||||
|
||||
if(!vhead || !fhead)
|
||||
errx(-1, "Syntax Error: missing HEAD section(s).");
|
||||
log_fatal("Syntax Error: missing HEAD section(s)");
|
||||
if((vfoot == NULL) + (ffoot == NULL) != 1)
|
||||
errx(-1, "Syntax Error: must contain exactly 1 FOOT section");
|
||||
log_fatal("Syntax Error: must contain exactly 1 FOOT section");
|
||||
|
||||
while((sec = strstr(sec, "%%"))) {
|
||||
sec += 2;
|
||||
|
@ -113,7 +112,7 @@ void load_shader_snippets(const char *filename, const char *prefix) {
|
|||
name = sec;
|
||||
nend = strstr(name, "%%");
|
||||
if(!nend)
|
||||
errx(-1, "Syntax Error: expected '%%'");
|
||||
log_fatal("Syntax Error: expected '%%'");
|
||||
|
||||
sec = nend + 2;
|
||||
|
||||
|
@ -160,7 +159,7 @@ void load_shader_snippets(const char *filename, const char *prefix) {
|
|||
nbuf[nend-name+prefixlen] = 0;
|
||||
|
||||
Shader *sha = load_shader(get_snippet_header(), NULL, vtext, ftext);
|
||||
insert_resource(RES_SHADER, nbuf, sha, 0, filename);
|
||||
insert_resource(RES_SHADER, nbuf, sha, flags, filename);
|
||||
|
||||
free(nbuf);
|
||||
free(vtext);
|
||||
|
@ -179,12 +178,12 @@ static void print_info_log(GLuint shader, tsglGetShaderiv_ptr lenfunc, tsglGetSh
|
|||
lenfunc(shader, GL_INFO_LOG_LENGTH, &len);
|
||||
|
||||
if(len > 1) {
|
||||
printf(" == GLSL %s info log (%u) ==\n", type, shader);
|
||||
char log[len];
|
||||
memset(log, 0, len);
|
||||
logfunc(shader, len, &alen, log);
|
||||
printf("%s\n", log);
|
||||
printf("\n == End of GLSL %s info log (%u) ==\n", type, shader);
|
||||
|
||||
log_warn("\n == GLSL %s info log (%u) ==\n%s\n == End of GLSL %s info log (%u) ==",
|
||||
type, shader, log, type, shader);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,5 +264,5 @@ int uniloc(Shader *sha, const char *name) {
|
|||
}
|
||||
|
||||
Shader* get_shader(const char *name) {
|
||||
return get_resource(RES_SHADER, name, RESF_REQUIRED)->shader;
|
||||
return get_resource(RES_SHADER, name, RESF_DEFAULT)->shader;
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ typedef struct Shader {
|
|||
|
||||
char* shader_path(const char *name);
|
||||
bool check_shader_path(const char *path);
|
||||
void* load_shader_file(const char *path);
|
||||
void* load_shader_file(const char *path, unsigned int flags);
|
||||
void unload_shader(void *vsha);
|
||||
|
||||
void load_shader_snippets(const char *filename, const char *prefix);
|
||||
void load_shader_snippets(const char *filename, const char *prefix, unsigned int flags);
|
||||
Shader* get_shader(const char *name);
|
||||
|
||||
int uniloc(Shader *sha, const char *name);
|
||||
|
|
|
@ -6,13 +6,11 @@
|
|||
*/
|
||||
|
||||
#include <png.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "texture.h"
|
||||
#include "resource.h"
|
||||
#include "global.h"
|
||||
#include "paths/native.h"
|
||||
#include "taisei_err.h"
|
||||
#include "vbo.h"
|
||||
|
||||
static SDL_Surface* load_png(const char *filename);
|
||||
|
@ -25,7 +23,7 @@ bool check_texture_path(const char *path) {
|
|||
return strendswith(path, TEX_EXTENSION);
|
||||
}
|
||||
|
||||
void* load_texture(const char *path) {
|
||||
void* load_texture(const char *path, unsigned int flags) {
|
||||
SDL_Surface *surface = load_png(path);
|
||||
|
||||
if(surface == NULL) {
|
||||
|
@ -42,7 +40,7 @@ void* load_texture(const char *path) {
|
|||
}
|
||||
|
||||
Texture* get_tex(const char *name) {
|
||||
return get_resource(RES_TEXTURE, name, RESF_REQUIRED)->texture;
|
||||
return get_resource(RES_TEXTURE, name, RESF_DEFAULT)->texture;
|
||||
}
|
||||
|
||||
Texture* prefix_get_tex(const char *name, const char *prefix) {
|
||||
|
@ -52,48 +50,61 @@ Texture* prefix_get_tex(const char *name, const char *prefix) {
|
|||
return tex;
|
||||
}
|
||||
|
||||
static SDL_Surface* load_png(const char *filename) {
|
||||
#define PNGFAIL(msg) { warnx("load_png(): couldn't load '%s': %s", filename, msg); return NULL; }
|
||||
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
|
||||
if(!fp) {
|
||||
PNGFAIL("fopen() failed")
|
||||
static SDL_Surface* load_png_p(const char *filename, SDL_RWops *rwops) {
|
||||
#define PNGFAIL(msg) { log_warn("Couldn't load '%s': %s", filename, msg); return NULL; }
|
||||
if(!rwops) {
|
||||
PNGFAIL(SDL_GetError())
|
||||
}
|
||||
|
||||
png_structp png_ptr;
|
||||
if(!(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) {
|
||||
fclose(fp);
|
||||
PNGFAIL("png_create_read_struct() failed")
|
||||
}
|
||||
|
||||
png_setup_error_handlers(png_ptr);
|
||||
|
||||
png_infop info_ptr;
|
||||
if(!(info_ptr = png_create_info_struct(png_ptr))) {
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
PNGFAIL("png_create_info_struct() failed")
|
||||
}
|
||||
|
||||
png_infop end_info;
|
||||
if(!(end_info = png_create_info_struct(png_ptr))) {
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
PNGFAIL("png_create_info_struct() failed")
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
png_read_png(png_ptr, info_ptr, 0, NULL);
|
||||
png_init_rwops_read(png_ptr, rwops);
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
int colortype = png_get_color_type(png_ptr,info_ptr);
|
||||
|
||||
if(colortype == PNG_COLOR_TYPE_PALETTE)
|
||||
png_set_expand(png_ptr);
|
||||
if (colortype == PNG_COLOR_TYPE_GRAY ||
|
||||
colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
if(!(colortype & PNG_COLOR_MASK_ALPHA))
|
||||
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
|
||||
|
||||
png_read_update_info(png_ptr, info_ptr);
|
||||
|
||||
int width = png_get_image_width(png_ptr, info_ptr);
|
||||
int height = png_get_image_height(png_ptr, info_ptr);
|
||||
int depth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
|
||||
png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr);
|
||||
|
||||
png_bytep row_pointers[height];
|
||||
|
||||
Uint32 *pixels = malloc(sizeof(Uint32)*width*height);
|
||||
|
||||
for(int i = 0; i < height; i++)
|
||||
memcpy(&pixels[i*width], row_pointers[i], sizeof(Uint32)*width);
|
||||
row_pointers[i] = (png_bytep)(pixels+i*width);
|
||||
|
||||
png_read_image(png_ptr, row_pointers);
|
||||
png_read_end(png_ptr, end_info);
|
||||
|
||||
|
||||
Uint32 rmask, gmask, bmask, amask;
|
||||
|
||||
|
@ -112,17 +123,22 @@ static SDL_Surface* load_png(const char *filename) {
|
|||
SDL_Surface *res = SDL_CreateRGBSurfaceFrom(pixels, width, height, depth*4, 0, rmask, gmask, bmask, amask);
|
||||
|
||||
if(!res) {
|
||||
fclose(fp);
|
||||
PNGFAIL(SDL_GetError())
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
|
||||
|
||||
return res;
|
||||
#undef PNGFAIL
|
||||
}
|
||||
|
||||
static SDL_Surface* load_png(const char *filename) {
|
||||
SDL_RWops *rwops = SDL_RWFromFile(filename, "r");
|
||||
SDL_Surface *surf = load_png_p(filename, rwops);
|
||||
SDL_RWclose(rwops);
|
||||
return surf;
|
||||
}
|
||||
|
||||
void load_sdl_surf(SDL_Surface *surface, Texture *texture) {
|
||||
glGenTextures(1, &texture->gltex);
|
||||
glBindTexture(GL_TEXTURE_2D, texture->gltex);
|
||||
|
|
|
@ -21,7 +21,7 @@ struct Texture {
|
|||
};
|
||||
|
||||
char* texture_path(const char *name);
|
||||
void* load_texture(const char *path);
|
||||
void* load_texture(const char *path, unsigned int flags);
|
||||
bool check_texture_path(const char *path);
|
||||
|
||||
void load_sdl_surf(SDL_Surface *surface, Texture *texture);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "rwops_segment.h"
|
||||
#include "taisei_err.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct Segment {
|
||||
SDL_RWops *wrapped;
|
||||
|
@ -104,7 +103,7 @@ static size_t segment_readwrite(SDL_RWops *rw, void *ptr, size_t size, size_t ma
|
|||
size_t onum;
|
||||
|
||||
if(pos < 0) {
|
||||
warnx("segment_readwrite: SDL_RWtell failed (%i): %s", (int)pos, SDL_GetError());
|
||||
log_debug("SDL_RWtell failed (%i): %s", (int)pos, SDL_GetError());
|
||||
SDL_SetError("segment_readwrite: SDL_RWtell failed (%i) %s", (int)pos, SDL_GetError());
|
||||
|
||||
// this could be a non-seekable stream, like /dev/stdin...
|
||||
|
@ -114,7 +113,7 @@ static size_t segment_readwrite(SDL_RWops *rw, void *ptr, size_t size, size_t ma
|
|||
}
|
||||
|
||||
if(pos < s->start || pos > s->end) {
|
||||
warnx("segment_readwrite: segment range violation");
|
||||
log_warn("Segment range violation");
|
||||
SDL_SetError("segment_readwrite: segment range violation");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
#include <SDL.h>
|
||||
#include <stdint.h>
|
||||
#include <zlib.h>
|
||||
#include <assert.h>
|
||||
#include "rwops_zlib.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MIN_CHUNK_SIZE 8
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef DEBUG_ZRWOPS
|
||||
#define PRINT(...) printf(__VA_ARGS__)
|
||||
#define PRINT(...) tsfprintf(stdout, __VA_ARGS__)
|
||||
#else
|
||||
#define PRINT(...)
|
||||
#endif
|
||||
|
@ -130,11 +130,11 @@ static SDL_RWops* common_alloc(SDL_RWops *wrapped, size_t bufsize, bool autoclos
|
|||
|
||||
#ifdef DEBUG_ZRWOPS
|
||||
static void printbuf(void *buf, size_t size) {
|
||||
printf("[ ");
|
||||
tsfprintf(stdout, "[ ");
|
||||
for(unsigned int i = 0; i < size; ++i) {
|
||||
printf("%02x ", ((uint8_t*)buf)[i]);
|
||||
tsfprintf(stdout, "%02x ", ((uint8_t*)buf)[i]);
|
||||
}
|
||||
printf("]\n");
|
||||
tsfprintf(stdout, "]\n");
|
||||
}
|
||||
#else
|
||||
#define printbuf(buf,size)
|
||||
|
@ -336,7 +336,7 @@ int zrwops_test(void) {
|
|||
printbuf(buffer1, sizeof(buffer1));
|
||||
printbuf(buffer2, sizeof(buffer2));
|
||||
|
||||
printf("%lu %s\n", x, buffer2);
|
||||
log_info("%lu %s\n", x, buffer2);
|
||||
|
||||
assert(!memcmp(data, buffer2, sizeof(data)));
|
||||
return 1;
|
||||
|
|
52
src/stage.c
|
@ -5,8 +5,6 @@
|
|||
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "stage.h"
|
||||
|
||||
|
@ -19,8 +17,8 @@
|
|||
#include "player.h"
|
||||
#include "menu/ingamemenu.h"
|
||||
#include "menu/gameovermenu.h"
|
||||
#include "taisei_err.h"
|
||||
#include "audio.h"
|
||||
#include "log.h"
|
||||
|
||||
static size_t numstages = 0;
|
||||
StageInfo *stages = NULL;
|
||||
|
@ -43,7 +41,7 @@ static void add_stage(uint16_t id, StageProcs *procs, StageType type, const char
|
|||
|
||||
#ifdef DEBUG
|
||||
if(title && subtitle) {
|
||||
fprintf(stderr, "Added stage 0x%04x: %s: %s\n", id, title, subtitle);
|
||||
log_debug("Added stage 0x%04x: %s: %s", id, title, subtitle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -111,12 +109,12 @@ void stage_init_array(void) {
|
|||
#ifdef DEBUG
|
||||
for(int i = 0; stages[i].procs; ++i) {
|
||||
if(stages[i].type == STAGE_SPELL && !(stages[i].id & STAGE_SPELL_BIT)) {
|
||||
errx(-1, "Spell stage has an ID without the spell bit set: 0x%04x", stages[i].id);
|
||||
log_fatal("Spell stage has an ID without the spell bit set: 0x%04x", stages[i].id);
|
||||
}
|
||||
|
||||
for(int j = 0; stages[j].procs; ++j) {
|
||||
if(i != j && stages[i].id == stages[j].id) {
|
||||
errx(-1, "Duplicate ID 0x%04x in stages array, indices: %i, %i", stages[i].id, i, j);
|
||||
log_fatal("Duplicate ID 0x%04x in stages array, indices: %i, %i", stages[i].id, i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,9 +175,8 @@ StageProgress* stage_get_progress_from_info(StageInfo *stage, Difficulty diff, b
|
|||
size_t allocsize = sizeof(StageProgress) * (fixed_diff ? 1 : NUM_SELECTABLE_DIFFICULTIES);
|
||||
stage->progress = malloc(allocsize);
|
||||
memset(stage->progress, 0, allocsize);
|
||||
#ifdef DEBUG
|
||||
printf("stage_get_progress_from_info(): allocated %lu bytes for stage %u (%s: %s)\n", (unsigned long int)allocsize, stage->id, stage->title, stage->subtitle);
|
||||
#endif
|
||||
|
||||
log_debug("Allocated %lu bytes for stage %u (%s: %s)", (unsigned long int)allocsize, stage->id, stage->title, stage->subtitle);
|
||||
}
|
||||
|
||||
return stage->progress + (fixed_diff ? 0 : diff - D_Easy);
|
||||
|
@ -450,7 +447,7 @@ static void stage_draw(StageInfo *stage) {
|
|||
if(config_get_int(CONFIG_NO_STAGEBG) == 2 && global.fps.stagebg_fps < config_get_int(CONFIG_NO_STAGEBG_FPSLIMIT)
|
||||
&& !global.nostagebg) {
|
||||
|
||||
printf("stage_draw(): !- Stage background has been switched off due to low frame rate. You can change that in the options.\n");
|
||||
log_warn("Stage background has been switched off due to low frame rate. You can change that in the options.");
|
||||
global.nostagebg = true;
|
||||
}
|
||||
|
||||
|
@ -691,9 +688,34 @@ void stage_finish(int gameover) {
|
|||
set_transition_callback(TransFadeBlack, FADE_TIME, FADE_TIME*2, stage_finalize, (void*)(intptr_t)gameover);
|
||||
}
|
||||
|
||||
static void stage_preload(void) {
|
||||
difficulty_preload();
|
||||
projectiles_preload();
|
||||
player_preload();
|
||||
items_preload();
|
||||
boss_preload();
|
||||
|
||||
if(global.stage->type != STAGE_SPELL)
|
||||
enemies_preload();
|
||||
|
||||
global.stage->procs->preload();
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"hud",
|
||||
"star",
|
||||
"titletransition",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER, RESF_PERMANENT,
|
||||
"stagetitle",
|
||||
"ingame_menu",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage_loop(StageInfo *stage) {
|
||||
assert(stage);
|
||||
assert(stage->procs);
|
||||
assert(stage->procs->preload);
|
||||
assert(stage->procs->begin);
|
||||
assert(stage->procs->end);
|
||||
assert(stage->procs->draw);
|
||||
|
@ -709,6 +731,8 @@ void stage_loop(StageInfo *stage) {
|
|||
// I really want to separate all of the game state from the global struct sometime
|
||||
global.stage = stage;
|
||||
|
||||
stage_preload();
|
||||
|
||||
uint32_t seed = (uint32_t)time(0);
|
||||
tsrand_switch(&global.rand_game);
|
||||
tsrand_seed_p(&global.rand_game, seed);
|
||||
|
@ -725,18 +749,18 @@ void stage_loop(StageInfo *stage) {
|
|||
global.replay_stage = NULL;
|
||||
}
|
||||
|
||||
printf("Random seed: %u\n", seed);
|
||||
log_debug("Random seed: %u", seed);
|
||||
} else {
|
||||
if(!global.replay_stage) {
|
||||
errx(-1, "Attemped to replay a NULL stage");
|
||||
log_fatal("Attemped to replay a NULL stage");
|
||||
return;
|
||||
}
|
||||
|
||||
ReplayStage *stg = global.replay_stage;
|
||||
printf("REPLAY_PLAY mode: %d events, stage: \"%s\"\n", stg->numevents, stage_get(stg->stage)->title);
|
||||
log_debug("REPLAY_PLAY mode: %d events, stage: \"%s\"", stg->numevents, stage_get(stg->stage)->title);
|
||||
|
||||
tsrand_seed_p(&global.rand_game, stg->seed);
|
||||
printf("Random seed: %u\n", stg->seed);
|
||||
log_debug("Random seed: %u", stg->seed);
|
||||
|
||||
global.diff = stg->diff;
|
||||
init_player(&global.plr);
|
||||
|
|