From: Holger Schemel Date: Sat, 23 Mar 2002 14:20:09 +0000 (+0100) Subject: rnd-20020323-2-src X-Git-Tag: 2.1.0^2~83 X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=commitdiff_plain;h=41e8d55b767c898f20c29a1b0b8d2ef8840be2f5 rnd-20020323-2-src --- diff --git a/src/Makefile b/src/Makefile index f4f503fc..5b8f1366 100644 --- a/src/Makefile +++ b/src/Makefile @@ -125,7 +125,6 @@ SRCS = main.c \ editor.c \ files.c \ tape.c \ - joystick.c \ cartoons.c \ network.c \ netserv.c @@ -139,7 +138,6 @@ OBJS = main.o \ editor.o \ files.o \ tape.o \ - joystick.o \ cartoons.o \ network.o \ netserv.o diff --git a/src/events.c b/src/events.c index fd8c3513..652ff31d 100644 --- a/src/events.c +++ b/src/events.c @@ -21,7 +21,6 @@ #include "editor.h" #include "files.h" #include "tape.h" -#include "joystick.h" #include "network.h" /* values for key_status */ @@ -304,8 +303,8 @@ void HandleFocusEvent(FocusChangeEvent *event) int i; KeyboardAutoRepeatOn(); - old_joystick_status = joystick_status; - joystick_status = JOYSTICK_OFF; + old_joystick_status = joystick.status; + joystick.status = JOYSTICK_NOT_AVAILABLE; /* simulate key release events for still pressed keys */ key_joystick_mapping = 0; @@ -336,7 +335,7 @@ void HandleFocusEvent(FocusChangeEvent *event) KeyboardAutoRepeatOff(); } if (old_joystick_status != -1) - joystick_status = old_joystick_status; + joystick.status = old_joystick_status; } } diff --git a/src/files.c b/src/files.c index d214bf99..00e47161 100644 --- a/src/files.c +++ b/src/files.c @@ -12,7 +12,6 @@ ***********************************************************/ #include -#include #include #include "libgame/libgame.h" @@ -20,7 +19,7 @@ #include "files.h" #include "tools.h" #include "tape.h" -#include "joystick.h" + #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */ @@ -37,328 +36,7 @@ #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x" #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x" #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2" -#define SETUP_COOKIE "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2" -#define LEVELSETUP_COOKIE "ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_1.2" -#define LEVELINFO_COOKIE "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2" - -/* file names and filename extensions */ -#if !defined(PLATFORM_MSDOS) -#define LEVELSETUP_DIRECTORY "levelsetup" -#define SETUP_FILENAME "setup.conf" -#define LEVELSETUP_FILENAME "levelsetup.conf" -#define LEVELINFO_FILENAME "levelinfo.conf" -#define LEVELFILE_EXTENSION "level" -#define TAPEFILE_EXTENSION "tape" -#define SCOREFILE_EXTENSION "score" -#else -#define LEVELSETUP_DIRECTORY "lvlsetup" -#define SETUP_FILENAME "setup.cnf" -#define LEVELSETUP_FILENAME "lvlsetup.cnf" -#define LEVELINFO_FILENAME "lvlinfo.cnf" -#define LEVELFILE_EXTENSION "lvl" -#define TAPEFILE_EXTENSION "tap" -#define SCOREFILE_EXTENSION "sco" -#endif - -/* sort priorities of level series (also used as level series classes) */ -#define LEVELCLASS_TUTORIAL_START 10 -#define LEVELCLASS_TUTORIAL_END 99 -#define LEVELCLASS_CLASSICS_START 100 -#define LEVELCLASS_CLASSICS_END 199 -#define LEVELCLASS_CONTRIBUTION_START 200 -#define LEVELCLASS_CONTRIBUTION_END 299 -#define LEVELCLASS_USER_START 300 -#define LEVELCLASS_USER_END 399 -#define LEVELCLASS_BD_START 400 -#define LEVELCLASS_BD_END 499 -#define LEVELCLASS_EM_START 500 -#define LEVELCLASS_EM_END 599 -#define LEVELCLASS_SP_START 600 -#define LEVELCLASS_SP_END 699 -#define LEVELCLASS_DX_START 700 -#define LEVELCLASS_DX_END 799 - -#define LEVELCLASS_TUTORIAL LEVELCLASS_TUTORIAL_START -#define LEVELCLASS_CLASSICS LEVELCLASS_CLASSICS_START -#define LEVELCLASS_CONTRIBUTION LEVELCLASS_CONTRIBUTION_START -#define LEVELCLASS_USER LEVELCLASS_USER_START -#define LEVELCLASS_BD LEVELCLASS_BD_START -#define LEVELCLASS_EM LEVELCLASS_EM_START -#define LEVELCLASS_SP LEVELCLASS_SP_START -#define LEVELCLASS_DX LEVELCLASS_DX_START - -#define LEVELCLASS_UNDEFINED 999 - -#define NUM_LEVELCLASS_DESC 8 -char *levelclass_desc[NUM_LEVELCLASS_DESC] = -{ - "Tutorial Levels", - "Classic Originals", - "Contributions", - "Private Levels", - "Boulderdash", - "Emerald Mine", - "Supaplex", - "DX Boulderdash" -}; - -#define IS_LEVELCLASS_TUTORIAL(p) \ - ((p)->sort_priority >= LEVELCLASS_TUTORIAL_START && \ - (p)->sort_priority <= LEVELCLASS_TUTORIAL_END) -#define IS_LEVELCLASS_CLASSICS(p) \ - ((p)->sort_priority >= LEVELCLASS_CLASSICS_START && \ - (p)->sort_priority <= LEVELCLASS_CLASSICS_END) -#define IS_LEVELCLASS_CONTRIBUTION(p) \ - ((p)->sort_priority >= LEVELCLASS_CONTRIBUTION_START && \ - (p)->sort_priority <= LEVELCLASS_CONTRIBUTION_END) -#define IS_LEVELCLASS_USER(p) \ - ((p)->sort_priority >= LEVELCLASS_USER_START && \ - (p)->sort_priority <= LEVELCLASS_USER_END) -#define IS_LEVELCLASS_BD(p) \ - ((p)->sort_priority >= LEVELCLASS_BD_START && \ - (p)->sort_priority <= LEVELCLASS_BD_END) -#define IS_LEVELCLASS_EM(p) \ - ((p)->sort_priority >= LEVELCLASS_EM_START && \ - (p)->sort_priority <= LEVELCLASS_EM_END) -#define IS_LEVELCLASS_SP(p) \ - ((p)->sort_priority >= LEVELCLASS_SP_START && \ - (p)->sort_priority <= LEVELCLASS_SP_END) -#define IS_LEVELCLASS_DX(p) \ - ((p)->sort_priority >= LEVELCLASS_DX_START && \ - (p)->sort_priority <= LEVELCLASS_DX_END) - -#define LEVELCLASS(n) (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \ - IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \ - IS_LEVELCLASS_CONTRIBUTION(n) ? LEVELCLASS_CONTRIBUTION : \ - IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \ - IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \ - IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \ - IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \ - IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \ - LEVELCLASS_UNDEFINED) - -#define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \ - IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \ - IS_LEVELCLASS_BD(n) ? FC_GREEN : \ - IS_LEVELCLASS_EM(n) ? FC_YELLOW : \ - IS_LEVELCLASS_SP(n) ? FC_GREEN : \ - IS_LEVELCLASS_DX(n) ? FC_YELLOW : \ - IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \ - IS_LEVELCLASS_USER(n) ? FC_RED : \ - FC_BLUE) - -#define LEVELSORTING(n) (IS_LEVELCLASS_TUTORIAL(n) ? 0 : \ - IS_LEVELCLASS_CLASSICS(n) ? 1 : \ - IS_LEVELCLASS_BD(n) ? 2 : \ - IS_LEVELCLASS_EM(n) ? 3 : \ - IS_LEVELCLASS_SP(n) ? 4 : \ - IS_LEVELCLASS_DX(n) ? 5 : \ - IS_LEVELCLASS_CONTRIBUTION(n) ? 6 : \ - IS_LEVELCLASS_USER(n) ? 7 : \ - 9) - -char *getLevelClassDescription(struct LevelDirInfo *ldi) -{ - int position = ldi->sort_priority / 100; - - if (position >= 0 && position < NUM_LEVELCLASS_DESC) - return levelclass_desc[position]; - else - return "Unknown Level Class"; -} - -static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */ -static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */ - -static char *getUserLevelDir(char *level_subdir) -{ - static char *userlevel_dir = NULL; - char *data_dir = getUserDataDir(); - char *userlevel_subdir = LEVELS_DIRECTORY; - - if (userlevel_dir) - free(userlevel_dir); - - if (strlen(level_subdir) > 0) - userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir); - else - userlevel_dir = getPath2(data_dir, userlevel_subdir); - - return userlevel_dir; -} - -static char *getTapeDir(char *level_subdir) -{ - static char *tape_dir = NULL; - char *data_dir = getUserDataDir(); - char *tape_subdir = TAPES_DIRECTORY; - - if (tape_dir) - free(tape_dir); - - if (strlen(level_subdir) > 0) - tape_dir = getPath3(data_dir, tape_subdir, level_subdir); - else - tape_dir = getPath2(data_dir, tape_subdir); - - return tape_dir; -} - -static char *getScoreDir(char *level_subdir) -{ - static char *score_dir = NULL; - char *data_dir = options.rw_base_directory; - char *score_subdir = SCORES_DIRECTORY; - if (score_dir) - free(score_dir); - - if (strlen(level_subdir) > 0) - score_dir = getPath3(data_dir, score_subdir, level_subdir); - else - score_dir = getPath2(data_dir, score_subdir); - - return score_dir; -} - -static char *getLevelSetupDir(char *level_subdir) -{ - static char *levelsetup_dir = NULL; - char *data_dir = getUserDataDir(); - char *levelsetup_subdir = LEVELSETUP_DIRECTORY; - - if (levelsetup_dir) - free(levelsetup_dir); - - if (strlen(level_subdir) > 0) - levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir); - else - levelsetup_dir = getPath2(data_dir, levelsetup_subdir); - - return levelsetup_dir; -} - -static char *getLevelFilename(int nr) -{ - static char *filename = NULL; - char basename[MAX_FILENAME_LEN]; - - if (filename != NULL) - free(filename); - - sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION); - filename = getPath3((leveldir_current->user_defined ? - getUserLevelDir("") : - options.level_directory), - leveldir_current->fullpath, - basename); - - return filename; -} - -static char *getTapeFilename(int nr) -{ - static char *filename = NULL; - char basename[MAX_FILENAME_LEN]; - - if (filename != NULL) - free(filename); - - sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); - filename = getPath2(getTapeDir(leveldir_current->filename), basename); - - return filename; -} - -static char *getScoreFilename(int nr) -{ - static char *filename = NULL; - char basename[MAX_FILENAME_LEN]; - - if (filename != NULL) - free(filename); - - sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION); - filename = getPath2(getScoreDir(leveldir_current->filename), basename); - - return filename; -} - -static void InitTapeDirectory(char *level_subdir) -{ - createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); - createDirectory(getTapeDir(""), "main tape", PERMS_PRIVATE); - createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE); -} - -static void InitScoreDirectory(char *level_subdir) -{ - createDirectory(getScoreDir(""), "main score", PERMS_PUBLIC); - createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC); -} - -static void InitUserLevelDirectory(char *level_subdir) -{ - if (access(getUserLevelDir(level_subdir), F_OK) != 0) - { - createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); - createDirectory(getUserLevelDir(""), "main user level", PERMS_PRIVATE); - createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE); - - SaveUserLevelInfo(); - } -} - -static void InitLevelSetupDirectory(char *level_subdir) -{ - createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); - createDirectory(getLevelSetupDir(""), "main level setup", PERMS_PRIVATE); - createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE); -} - -static void ReadChunk_VERS(FILE *file, int *file_version, int *game_version) -{ - int file_version_major, file_version_minor, file_version_patch; - int game_version_major, game_version_minor, game_version_patch; - - file_version_major = fgetc(file); - file_version_minor = fgetc(file); - file_version_patch = fgetc(file); - fgetc(file); /* not used */ - - game_version_major = fgetc(file); - game_version_minor = fgetc(file); - game_version_patch = fgetc(file); - fgetc(file); /* not used */ - - *file_version = VERSION_IDENT(file_version_major, - file_version_minor, - file_version_patch); - - *game_version = VERSION_IDENT(game_version_major, - game_version_minor, - game_version_patch); -} - -static void WriteChunk_VERS(FILE *file, int file_version, int game_version) -{ - int file_version_major = VERSION_MAJOR(file_version); - int file_version_minor = VERSION_MINOR(file_version); - int file_version_patch = VERSION_PATCH(file_version); - int game_version_major = VERSION_MAJOR(game_version); - int game_version_minor = VERSION_MINOR(game_version); - int game_version_patch = VERSION_PATCH(game_version); - - fputc(file_version_major, file); - fputc(file_version_minor, file); - fputc(file_version_patch, file); - fputc(0, file); /* not used */ - - fputc(game_version_major, file); - fputc(game_version_minor, file); - fputc(game_version_patch, file); - fputc(0, file); /* not used */ -} static void setLevelInfoToDefaults() { @@ -1462,892 +1140,3 @@ void SaveScore(int level_nr) SetFilePermissions(filename, PERMS_PUBLIC); } - -/* ------------------------------------------------------------------------- */ -/* setup file stuff */ -/* ------------------------------------------------------------------------- */ - -#define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series" -#define TOKEN_STR_LAST_PLAYED_LEVEL "last_played_level" -#define TOKEN_STR_HANDICAP_LEVEL "handicap_level" -#define TOKEN_STR_PLAYER_PREFIX "player_" - -/* global setup */ -#define SETUP_TOKEN_PLAYER_NAME 0 -#define SETUP_TOKEN_SOUND 1 -#define SETUP_TOKEN_SOUND_LOOPS 2 -#define SETUP_TOKEN_SOUND_MUSIC 3 -#define SETUP_TOKEN_SOUND_SIMPLE 4 -#define SETUP_TOKEN_SCROLL_DELAY 5 -#define SETUP_TOKEN_SOFT_SCROLLING 6 -#define SETUP_TOKEN_FADING 7 -#define SETUP_TOKEN_AUTORECORD 8 -#define SETUP_TOKEN_QUICK_DOORS 9 -#define SETUP_TOKEN_TEAM_MODE 10 -#define SETUP_TOKEN_HANDICAP 11 -#define SETUP_TOKEN_TIME_LIMIT 12 -#define SETUP_TOKEN_FULLSCREEN 13 - -/* player setup */ -#define SETUP_TOKEN_USE_JOYSTICK 14 -#define SETUP_TOKEN_JOY_DEVICE_NAME 15 -#define SETUP_TOKEN_JOY_XLEFT 16 -#define SETUP_TOKEN_JOY_XMIDDLE 17 -#define SETUP_TOKEN_JOY_XRIGHT 18 -#define SETUP_TOKEN_JOY_YUPPER 19 -#define SETUP_TOKEN_JOY_YMIDDLE 20 -#define SETUP_TOKEN_JOY_YLOWER 21 -#define SETUP_TOKEN_JOY_SNAP 22 -#define SETUP_TOKEN_JOY_BOMB 23 -#define SETUP_TOKEN_KEY_LEFT 24 -#define SETUP_TOKEN_KEY_RIGHT 25 -#define SETUP_TOKEN_KEY_UP 26 -#define SETUP_TOKEN_KEY_DOWN 27 -#define SETUP_TOKEN_KEY_SNAP 28 -#define SETUP_TOKEN_KEY_BOMB 29 - -/* level directory info */ -#define LEVELINFO_TOKEN_NAME 30 -#define LEVELINFO_TOKEN_NAME_SHORT 31 -#define LEVELINFO_TOKEN_NAME_SORTING 32 -#define LEVELINFO_TOKEN_AUTHOR 33 -#define LEVELINFO_TOKEN_IMPORTED_FROM 34 -#define LEVELINFO_TOKEN_LEVELS 35 -#define LEVELINFO_TOKEN_FIRST_LEVEL 36 -#define LEVELINFO_TOKEN_SORT_PRIORITY 37 -#define LEVELINFO_TOKEN_LEVEL_GROUP 38 -#define LEVELINFO_TOKEN_READONLY 39 - -#define FIRST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_PLAYER_NAME -#define LAST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_FULLSCREEN - -#define FIRST_PLAYER_SETUP_TOKEN SETUP_TOKEN_USE_JOYSTICK -#define LAST_PLAYER_SETUP_TOKEN SETUP_TOKEN_KEY_BOMB - -#define FIRST_LEVELINFO_TOKEN LEVELINFO_TOKEN_NAME -#define LAST_LEVELINFO_TOKEN LEVELINFO_TOKEN_READONLY - -static struct SetupInfo si; -static struct SetupInputInfo sii; -static struct LevelDirInfo ldi; -static struct TokenInfo token_info[] = -{ - /* global setup */ - { TYPE_STRING, &si.player_name, "player_name" }, - { TYPE_SWITCH, &si.sound, "sound" }, - { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" }, - { TYPE_SWITCH, &si.sound_music, "background_music" }, - { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" }, - { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" }, - { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" }, - { TYPE_SWITCH, &si.fading, "screen_fading" }, - { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" }, - { TYPE_SWITCH, &si.quick_doors, "quick_doors" }, - { TYPE_SWITCH, &si.team_mode, "team_mode" }, - { TYPE_SWITCH, &si.handicap, "handicap" }, - { TYPE_SWITCH, &si.time_limit, "time_limit" }, - { TYPE_SWITCH, &si.fullscreen, "fullscreen" }, - - /* player setup */ - { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" }, - { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" }, - { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" }, - { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" }, - { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" }, - { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" }, - { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" }, - { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" }, - { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" }, - { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" }, - { TYPE_KEY, &sii.key.left, ".key.move_left" }, - { TYPE_KEY, &sii.key.right, ".key.move_right" }, - { TYPE_KEY, &sii.key.up, ".key.move_up" }, - { TYPE_KEY, &sii.key.down, ".key.move_down" }, - { TYPE_KEY, &sii.key.snap, ".key.snap_field" }, - { TYPE_KEY, &sii.key.bomb, ".key.place_bomb" }, - - /* level directory info */ - { TYPE_STRING, &ldi.name, "name" }, - { TYPE_STRING, &ldi.name_short, "name_short" }, - { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, - { TYPE_STRING, &ldi.author, "author" }, - { TYPE_STRING, &ldi.imported_from, "imported_from" }, - { TYPE_INTEGER, &ldi.levels, "levels" }, - { TYPE_INTEGER, &ldi.first_level, "first_level" }, - { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, - { TYPE_BOOLEAN, &ldi.level_group, "level_group" }, - { TYPE_BOOLEAN, &ldi.readonly, "readonly" } -}; - -static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi) -{ - ldi->filename = NULL; - ldi->fullpath = NULL; - ldi->basepath = NULL; - ldi->name = getStringCopy(ANONYMOUS_NAME); - ldi->name_short = NULL; - ldi->name_sorting = NULL; - ldi->author = getStringCopy(ANONYMOUS_NAME); - ldi->imported_from = NULL; - ldi->levels = 0; - ldi->first_level = 0; - ldi->last_level = 0; - ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ - ldi->level_group = FALSE; - ldi->parent_link = FALSE; - ldi->user_defined = FALSE; - ldi->readonly = TRUE; - ldi->color = 0; - ldi->class_desc = NULL; - ldi->handicap_level = 0; - ldi->cl_first = -1; - ldi->cl_cursor = -1; - - ldi->node_parent = NULL; - ldi->node_group = NULL; - ldi->next = NULL; -} - -static void setLevelDirInfoToDefaultsFromParent(struct LevelDirInfo *ldi, - struct LevelDirInfo *parent) -{ - if (parent == NULL) - { - setLevelDirInfoToDefaults(ldi); - return; - } - - /* first copy all values from the parent structure ... */ - *ldi = *parent; - - /* ... then set all fields to default that cannot be inherited from parent. - This is especially important for all those fields that can be set from - the 'levelinfo.conf' config file, because the function 'setSetupInfo()' - calls 'free()' for all already set token values which requires that no - other structure's pointer may point to them! - */ - - ldi->filename = NULL; - ldi->fullpath = NULL; - ldi->basepath = NULL; - ldi->name = getStringCopy(ANONYMOUS_NAME); - ldi->name_short = NULL; - ldi->name_sorting = NULL; - ldi->author = getStringCopy(parent->author); - ldi->imported_from = getStringCopy(parent->imported_from); - - ldi->level_group = FALSE; - ldi->parent_link = FALSE; - - ldi->node_parent = parent; - ldi->node_group = NULL; - ldi->next = NULL; -} - -static void setSetupInfoToDefaults(struct SetupInfo *si) -{ - int i; - - si->player_name = getStringCopy(getLoginName()); - - si->sound = TRUE; - si->sound_loops = TRUE; - si->sound_music = TRUE; - si->sound_simple = TRUE; - si->toons = TRUE; - si->double_buffering = TRUE; - si->direct_draw = !si->double_buffering; - si->scroll_delay = TRUE; - si->soft_scrolling = TRUE; - si->fading = FALSE; - si->autorecord = TRUE; - si->quick_doors = FALSE; - si->team_mode = FALSE; - si->handicap = TRUE; - si->time_limit = TRUE; - si->fullscreen = FALSE; - - for (i=0; iinput[i].use_joystick = FALSE; - si->input[i].joy.device_name = getStringCopy(joystick_device_name[i]); - si->input[i].joy.xleft = JOYSTICK_XLEFT; - si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE; - si->input[i].joy.xright = JOYSTICK_XRIGHT; - si->input[i].joy.yupper = JOYSTICK_YUPPER; - si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE; - si->input[i].joy.ylower = JOYSTICK_YLOWER; - si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0); - si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0); - si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED); - si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED); - si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED); - si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED); - si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED); - si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED); - } -} - -static void setSetupInfo(int token_nr, char *token_value) -{ - int token_type = token_info[token_nr].type; - void *setup_value = token_info[token_nr].value; - - if (token_value == NULL) - return; - - /* set setup field to corresponding token value */ - switch (token_type) - { - case TYPE_BOOLEAN: - case TYPE_SWITCH: - *(boolean *)setup_value = get_string_boolean_value(token_value); - break; - - case TYPE_KEY: - *(Key *)setup_value = getKeyFromX11KeyName(token_value); - break; - - case TYPE_INTEGER: - *(int *)setup_value = get_string_integer_value(token_value); - break; - - case TYPE_STRING: - if (*(char **)setup_value != NULL) - free(*(char **)setup_value); - *(char **)setup_value = getStringCopy(token_value); - break; - - default: - break; - } -} - -static void decodeSetupFileList(struct SetupFileList *setup_file_list) -{ - int i, pnr; - - if (!setup_file_list) - return; - - /* handle global setup values */ - si = setup; - for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++) - setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text)); - setup = si; - - /* handle player specific setup values */ - for (pnr=0; pnrparent_link || entry2->parent_link) - compare_result = (entry1->parent_link ? -1 : +1); - else if (entry1->sort_priority == entry2->sort_priority) - { - char *name1 = getStringToLower(entry1->name_sorting); - char *name2 = getStringToLower(entry2->name_sorting); - - compare_result = strcmp(name1, name2); - - free(name1); - free(name2); - } - else if (LEVELSORTING(entry1) == LEVELSORTING(entry2)) - compare_result = entry1->sort_priority - entry2->sort_priority; - else - compare_result = LEVELSORTING(entry1) - LEVELSORTING(entry2); - - return compare_result; -} - -static void createParentLevelDirNode(struct LevelDirInfo *node_parent) -{ - struct LevelDirInfo *leveldir_new = newLevelDirInfo(); - - setLevelDirInfoToDefaults(leveldir_new); - - leveldir_new->node_parent = node_parent; - leveldir_new->parent_link = TRUE; - - leveldir_new->name = ".. (parent directory)"; - leveldir_new->name_short = getStringCopy(leveldir_new->name); - leveldir_new->name_sorting = getStringCopy(leveldir_new->name); - - leveldir_new->filename = ".."; - leveldir_new->fullpath = getStringCopy(node_parent->fullpath); - - leveldir_new->sort_priority = node_parent->sort_priority; - leveldir_new->class_desc = getLevelClassDescription(leveldir_new); - - pushLevelDirInfo(&node_parent->node_group, leveldir_new); -} - -static void LoadLevelInfoFromLevelDir(struct LevelDirInfo **node_first, - struct LevelDirInfo *node_parent, - char *level_directory) -{ - DIR *dir; - struct dirent *dir_entry; - boolean valid_entry_found = FALSE; - - if ((dir = opendir(level_directory)) == NULL) - { - Error(ERR_WARN, "cannot read level directory '%s'", level_directory); - return; - } - - while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ - { - struct SetupFileList *setup_file_list = NULL; - struct stat file_status; - char *directory_name = dir_entry->d_name; - char *directory_path = getPath2(level_directory, directory_name); - char *filename = NULL; - - /* skip entries for current and parent directory */ - if (strcmp(directory_name, ".") == 0 || - strcmp(directory_name, "..") == 0) - { - free(directory_path); - continue; - } - - /* find out if directory entry is itself a directory */ - if (stat(directory_path, &file_status) != 0 || /* cannot stat file */ - (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ - { - free(directory_path); - continue; - } - - filename = getPath2(directory_path, LEVELINFO_FILENAME); - setup_file_list = loadSetupFileList(filename); - - if (setup_file_list) - { - struct LevelDirInfo *leveldir_new = newLevelDirInfo(); - int i; - - checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE); - setLevelDirInfoToDefaultsFromParent(leveldir_new, node_parent); - - /* set all structure fields according to the token/value pairs */ - ldi = *leveldir_new; - for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) - setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text)); - *leveldir_new = ldi; - - DrawInitText(leveldir_new->name, 150, FC_YELLOW); - - if (leveldir_new->name_short == NULL) - leveldir_new->name_short = getStringCopy(leveldir_new->name); - - if (leveldir_new->name_sorting == NULL) - leveldir_new->name_sorting = getStringCopy(leveldir_new->name); - - leveldir_new->filename = getStringCopy(directory_name); - - if (node_parent == NULL) /* top level group */ - { - leveldir_new->basepath = level_directory; - leveldir_new->fullpath = leveldir_new->filename; - } - else /* sub level group */ - { - leveldir_new->basepath = node_parent->basepath; - leveldir_new->fullpath = getPath2(node_parent->fullpath, - directory_name); - } - - if (leveldir_new->levels < 1) - leveldir_new->levels = 1; - - leveldir_new->last_level = - leveldir_new->first_level + leveldir_new->levels - 1; - - leveldir_new->user_defined = - (leveldir_new->basepath == options.level_directory ? FALSE : TRUE); - - leveldir_new->color = LEVELCOLOR(leveldir_new); - leveldir_new->class_desc = getLevelClassDescription(leveldir_new); - - leveldir_new->handicap_level = /* set handicap to default value */ - (leveldir_new->user_defined ? - leveldir_new->last_level : - leveldir_new->first_level); - - pushLevelDirInfo(node_first, leveldir_new); - - freeSetupFileList(setup_file_list); - valid_entry_found = TRUE; - - if (leveldir_new->level_group) - { - /* create node to link back to current level directory */ - createParentLevelDirNode(leveldir_new); - - /* step into sub-directory and look for more level series */ - LoadLevelInfoFromLevelDir(&leveldir_new->node_group, - leveldir_new, directory_path); - } - } - else - Error(ERR_WARN, "ignoring level directory '%s'", directory_path); - - free(directory_path); - free(filename); - } - - closedir(dir); - - if (!valid_entry_found) - Error(ERR_WARN, "cannot find any valid level series in directory '%s'", - level_directory); -} - -void LoadLevelInfo() -{ - InitUserLevelDirectory(getLoginName()); - - DrawInitText("Loading level series:", 120, FC_GREEN); - - LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); - LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir("")); - - leveldir_current = getFirstValidLevelSeries(leveldir_first); - - if (leveldir_first == NULL) - Error(ERR_EXIT, "cannot find any valid level series in any directory"); - - sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries); - -#if 0 - dumpLevelDirInfo(leveldir_first, 0); -#endif -} - -static void SaveUserLevelInfo() -{ - char *filename; - FILE *file; - int i; - - filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); - - if (!(file = fopen(filename, MODE_WRITE))) - { - Error(ERR_WARN, "cannot write level info file '%s'", filename); - free(filename); - return; - } - - /* always start with reliable default values */ - setLevelDirInfoToDefaults(&ldi); - - ldi.name = getLoginName(); - ldi.author = getRealName(); - ldi.levels = 100; - ldi.first_level = 1; - ldi.sort_priority = LEVELCLASS_USER_START; - ldi.readonly = FALSE; - - fprintf(file, "%s\n\n", - getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE)); - - for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) - if (i != LEVELINFO_TOKEN_NAME_SHORT && - i != LEVELINFO_TOKEN_NAME_SORTING && - i != LEVELINFO_TOKEN_IMPORTED_FROM) - fprintf(file, "%s\n", getSetupLine("", i)); - - fclose(file); - free(filename); - - SetFilePermissions(filename, PERMS_PRIVATE); -} - -void LoadSetup() -{ - char *filename; - struct SetupFileList *setup_file_list = NULL; - - /* always start with reliable default values */ - setSetupInfoToDefaults(&setup); - - filename = getPath2(getSetupDir(), SETUP_FILENAME); - - setup_file_list = loadSetupFileList(filename); - - if (setup_file_list) - { - checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE); - decodeSetupFileList(setup_file_list); - - setup.direct_draw = !setup.double_buffering; - - freeSetupFileList(setup_file_list); - - /* needed to work around problems with fixed length strings */ - if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN) - setup.player_name[MAX_PLAYER_NAME_LEN] = '\0'; - else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN) - { - char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1); - - strcpy(new_name, setup.player_name); - free(setup.player_name); - setup.player_name = new_name; - } - } - else - Error(ERR_WARN, "using default setup values"); - - free(filename); -} - -static char *getSetupLine(char *prefix, int token_nr) -{ - int i; - static char entry[MAX_LINE_LEN]; - int token_type = token_info[token_nr].type; - void *setup_value = token_info[token_nr].value; - char *token_text = token_info[token_nr].text; - - /* start with the prefix, token and some spaces to format output line */ - sprintf(entry, "%s%s:", prefix, token_text); - for (i=strlen(entry); ifilename; - FILE *file; - - /* ----------------------------------------------------------------------- */ - /* ~/.rocksndiamonds/levelsetup.conf */ - /* ----------------------------------------------------------------------- */ - - InitUserDataDirectory(); - - filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); - - if (!(file = fopen(filename, MODE_WRITE))) - { - Error(ERR_WARN, "cannot write setup file '%s'", filename); - free(filename); - return; - } - - fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, - LEVELSETUP_COOKIE)); - fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES, - level_subdir)); - - fclose(file); - free(filename); - - SetFilePermissions(filename, PERMS_PRIVATE); -} - -static void checkSeriesInfo() -{ - static char *level_directory = NULL; - DIR *dir; - struct dirent *dir_entry; - - /* check for more levels besides the 'levels' field of 'levelinfo.conf' */ - - level_directory = getPath2((leveldir_current->user_defined ? - getUserLevelDir("") : - options.level_directory), - leveldir_current->fullpath); - - if ((dir = opendir(level_directory)) == NULL) - { - Error(ERR_WARN, "cannot read level directory '%s'", level_directory); - return; - } - - while ((dir_entry = readdir(dir)) != NULL) /* last directory entry */ - { - if (strlen(dir_entry->d_name) > 4 && - dir_entry->d_name[3] == '.' && - strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0) - { - char levelnum_str[4]; - int levelnum_value; - - strncpy(levelnum_str, dir_entry->d_name, 3); - levelnum_str[3] = '\0'; - - levelnum_value = atoi(levelnum_str); - - if (levelnum_value < leveldir_current->first_level) - { - Error(ERR_WARN, "additional level %d found", levelnum_value); - leveldir_current->first_level = levelnum_value; - } - else if (levelnum_value > leveldir_current->last_level) - { - Error(ERR_WARN, "additional level %d found", levelnum_value); - leveldir_current->last_level = levelnum_value; - } - } - } - - closedir(dir); -} - -void LoadLevelSetup_SeriesInfo() -{ - char *filename; - struct SetupFileList *level_setup_list = NULL; - char *level_subdir = leveldir_current->filename; - - /* always start with reliable default values */ - level_nr = leveldir_current->first_level; - - checkSeriesInfo(leveldir_current); - - /* ----------------------------------------------------------------------- */ - /* ~/.rocksndiamonds/levelsetup//levelsetup.conf */ - /* ----------------------------------------------------------------------- */ - - level_subdir = leveldir_current->filename; - - filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); - - if ((level_setup_list = loadSetupFileList(filename))) - { - char *token_value; - - token_value = getTokenValue(level_setup_list, TOKEN_STR_LAST_PLAYED_LEVEL); - - if (token_value) - { - level_nr = atoi(token_value); - - if (level_nr < leveldir_current->first_level) - level_nr = leveldir_current->first_level; - if (level_nr > leveldir_current->last_level) - level_nr = leveldir_current->last_level; - } - - token_value = getTokenValue(level_setup_list, TOKEN_STR_HANDICAP_LEVEL); - - if (token_value) - { - int level_nr = atoi(token_value); - - if (level_nr < leveldir_current->first_level) - level_nr = leveldir_current->first_level; - if (level_nr > leveldir_current->last_level + 1) - level_nr = leveldir_current->last_level; - - if (leveldir_current->user_defined) - level_nr = leveldir_current->last_level; - - leveldir_current->handicap_level = level_nr; - } - - checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE); - - freeSetupFileList(level_setup_list); - } - else - Error(ERR_WARN, "using default setup values"); - - free(filename); -} - -void SaveLevelSetup_SeriesInfo() -{ - char *filename; - char *level_subdir = leveldir_current->filename; - char *level_nr_str = int2str(level_nr, 0); - char *handicap_level_str = int2str(leveldir_current->handicap_level, 0); - FILE *file; - - /* ----------------------------------------------------------------------- */ - /* ~/.rocksndiamonds/levelsetup//levelsetup.conf */ - /* ----------------------------------------------------------------------- */ - - InitLevelSetupDirectory(level_subdir); - - filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); - - if (!(file = fopen(filename, MODE_WRITE))) - { - Error(ERR_WARN, "cannot write setup file '%s'", filename); - free(filename); - return; - } - - fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, - LEVELSETUP_COOKIE)); - fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL, - level_nr_str)); - fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL, - handicap_level_str)); - - fclose(file); - free(filename); - - SetFilePermissions(filename, PERMS_PRIVATE); -} diff --git a/src/files.h b/src/files.h index bd593b5a..994ac1da 100644 --- a/src/files.h +++ b/src/files.h @@ -26,12 +26,4 @@ void DumpTape(struct TapeInfo *); void LoadScore(int); void SaveScore(int); -void LoadLevelInfo(void); -void LoadSetup(void); -void SaveSetup(void); -void LoadLevelSetup_LastSeries(void); -void SaveLevelSetup_LastSeries(void); -void LoadLevelSetup_SeriesInfo(void); -void SaveLevelSetup_SeriesInfo(void); - #endif /* FILES_H */ diff --git a/src/game.c b/src/game.c index 2acc4c94..fcfeb740 100644 --- a/src/game.c +++ b/src/game.c @@ -19,7 +19,6 @@ #include "init.h" #include "files.h" #include "tape.h" -#include "joystick.h" #include "network.h" /* this switch controls how rocks move horizontally */ diff --git a/src/init.c b/src/init.c index 8cdbae4d..df4099e1 100644 --- a/src/init.c +++ b/src/init.c @@ -21,7 +21,6 @@ #include "tape.h" #include "tools.h" #include "files.h" -#include "joystick.h" #include "network.h" #include "netserv.h" @@ -84,10 +83,7 @@ void InitPlayerInfo() local_player = &stored_player[0]; for (i=0; iconnected = TRUE; @@ -155,10 +151,13 @@ void InitJoysticks() int i; - if (global_joystick_status == JOYSTICK_OFF) - return; + /* always start with reliable default values */ + joystick.status = JOYSTICK_NOT_AVAILABLE; + for (i=0; i -#endif - -#include "libgame/libgame.h" - -#include "joystick.h" - -#define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0 -#define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1 - -void translate_joyname(int *joysymbol, char **name, int mode) -{ - static struct - { - int joysymbol; - char *name; - } translate_joy[] = - { - { JOY_LEFT, "joystick_left" }, - { JOY_RIGHT, "joystick_right" }, - { JOY_UP, "joystick_up" }, - { JOY_DOWN, "joystick_down" }, - { JOY_BUTTON_1, "joystick_button_1" }, - { JOY_BUTTON_2, "joystick_button_2" }, - }; - - int i; - - if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME) - { - *name = "[undefined]"; - - for (i=0; i<6; i++) - { - if (*joysymbol == translate_joy[i].joysymbol) - { - *name = translate_joy[i].name; - break; - } - } - } - else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL) - { - *joysymbol = 0; - - for (i=0; i<6; i++) - { - if (strcmp(*name, translate_joy[i].name) == 0) - { - *joysymbol = translate_joy[i].joysymbol; - break; - } - } - } -} - -char *getJoyNameFromJoySymbol(int joysymbol) -{ - char *name; - - translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME); - return name; -} - -int getJoySymbolFromJoyName(char *name) -{ - int joysymbol; - - translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL); - return joysymbol; -} - -int getJoystickNrFromDeviceName(char *device_name) -{ - char c; - int joystick_nr = 0; - - if (device_name == NULL || device_name[0] == '\0') - return 0; - - c = device_name[strlen(device_name) - 1]; - - if (c >= '0' && c <= '9') - joystick_nr = (int)(c - '0'); - - if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS) - joystick_nr = 0; - - return joystick_nr; -} - -#if !defined(PLATFORM_MSDOS) -static int JoystickPosition(int middle, int margin, int actual) -{ - long range, pos; - int percentage; - - if (margin < middle && actual > middle) - return 0; - if (margin > middle && actual < middle) - return 0; - - range = ABS(margin - middle); - pos = ABS(actual - middle); - percentage = (int)(pos * 100 / range); - - if (percentage > 100) - percentage = 100; - - return percentage; -} -#endif - -#if defined(TARGET_SDL) - -static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL }; -static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; -static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; - -SDL_Joystick *Get_SDL_Joystick(int nr) -{ - return sdl_joystick[nr]; -} - -boolean Open_SDL_Joystick(int nr) -{ - if (nr < 0 || nr > MAX_PLAYERS) - return FALSE; - - return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE); -} - -void Close_SDL_Joystick(int nr) -{ - if (nr < 0 || nr > MAX_PLAYERS) - return; - - SDL_JoystickClose(sdl_joystick[nr]); -} - -boolean Check_SDL_JoystickOpened(int nr) -{ - if (nr < 0 || nr > MAX_PLAYERS) - return FALSE; - - return (SDL_JoystickOpened(nr) ? TRUE : FALSE); -} - -void HandleJoystickEvent(Event *event) -{ - switch(event->type) - { - case SDL_JOYAXISMOTION: - if (event->jaxis.axis < 2) - { - sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value; - -#if 0 - printf("js_%d %s-axis: %d\n", - event->jaxis.which, - (event->jaxis.axis == 0 ? "x" : "y"), - event->jaxis.value); -#endif - } - break; - - case SDL_JOYBUTTONDOWN: - if (event->jbutton.button < 2) - { - sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE; - -#if 0 - printf("js_%d button %d: pressed\n", - event->jbutton.which, - event->jbutton.button); -#endif - } - break; - - case SDL_JOYBUTTONUP: - if (event->jbutton.button < 2) - { - sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE; - -#if 0 - printf("js_%d button %d: released\n", - event->jbutton.which, - event->jbutton.button); -#endif - } - break; - - default: - break; - } -} - -int Get_SDL_Joystick_Axis(int nr, int axis) -{ - if (nr < 0 || nr > MAX_PLAYERS) - return 0; - - if (axis < 0 || axis > 1) - return 0; - - return sdl_js_axis[nr][axis]; -} - -void CheckJoystickData() -{ -} - -int Joystick(int player_nr) -{ - int joystick_nr = stored_player[player_nr].joystick_fd; - int js_x,js_y, js_b1,js_b2; - int left, right, up, down; - int result = 0; - - if (joystick_status == JOYSTICK_OFF) - return 0; - - if (game_status == SETUPINPUT) - return 0; - - if (!setup.input[player_nr].use_joystick || - !Check_SDL_JoystickOpened(joystick_nr)) - return 0; - - js_x = sdl_js_axis[joystick_nr][0]; - js_y = sdl_js_axis[joystick_nr][1]; - - js_b1 = sdl_js_button[joystick_nr][0]; - js_b2 = sdl_js_button[joystick_nr][1]; - - - -#if 0 - printf("JOYSTICK %d: js_x == %d, js_y == %d, js_b1 == %d, js_b2 == %d\n", - joystick_nr, js_x, js_y, js_b1, js_b2); -#endif - - - - left = JoystickPosition(setup.input[player_nr].joy.xmiddle, - setup.input[player_nr].joy.xleft, js_x); - right = JoystickPosition(setup.input[player_nr].joy.xmiddle, - setup.input[player_nr].joy.xright, js_x); - up = JoystickPosition(setup.input[player_nr].joy.ymiddle, - setup.input[player_nr].joy.yupper, js_y); - down = JoystickPosition(setup.input[player_nr].joy.ymiddle, - setup.input[player_nr].joy.ylower, js_y); - - if (left > JOYSTICK_PERCENT) - result |= JOY_LEFT; - else if (right > JOYSTICK_PERCENT) - result |= JOY_RIGHT; - if (up > JOYSTICK_PERCENT) - result |= JOY_UP; - else if (down > JOYSTICK_PERCENT) - result |= JOY_DOWN; - - if (js_b1) - result |= JOY_BUTTON_1; - if (js_b2) - result |= JOY_BUTTON_2; - - - -#if 0 - printf("result == 0x%08x\n", result); -#endif - - - - return result; -} - -#else /* !TARGET_SDL */ - -void CheckJoystickData() -{ - int i; - int distance = 100; - - for(i=0; i= setup.input[i].joy.xmiddle) - setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance; - if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle) - setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance; - - if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle) - setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance; - if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle) - setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance; - } -} - -#if defined(PLATFORM_UNIX) -int Joystick(int player_nr) -{ -#ifdef __FreeBSD__ - struct joystick joy_ctrl; -#else - struct joystick_control - { - int buttons; - int x; - int y; - } joy_ctrl; -#endif - - int joystick_fd = stored_player[player_nr].joystick_fd; - int js_x,js_y, js_b1,js_b2; - int left, right, up, down; - int result = 0; - - if (joystick_status == JOYSTICK_OFF) - return 0; - - if (game_status == SETUPINPUT) - return 0; - - if (joystick_fd < 0 || !setup.input[player_nr].use_joystick) - return 0; - - if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) - { - Error(ERR_WARN, "cannot read joystick device '%s'", - setup.input[player_nr].joy.device_name); - joystick_status = JOYSTICK_OFF; - return 0; - } - - js_x = joy_ctrl.x; - js_y = joy_ctrl.y; - -#ifdef __FreeBSD__ - js_b1 = joy_ctrl.b1; - js_b2 = joy_ctrl.b2; -#else - js_b1 = joy_ctrl.buttons & 1; - js_b2 = joy_ctrl.buttons & 2; -#endif - - left = JoystickPosition(setup.input[player_nr].joy.xmiddle, - setup.input[player_nr].joy.xleft, js_x); - right = JoystickPosition(setup.input[player_nr].joy.xmiddle, - setup.input[player_nr].joy.xright, js_x); - up = JoystickPosition(setup.input[player_nr].joy.ymiddle, - setup.input[player_nr].joy.yupper, js_y); - down = JoystickPosition(setup.input[player_nr].joy.ymiddle, - setup.input[player_nr].joy.ylower, js_y); - - if (left > JOYSTICK_PERCENT) - result |= JOY_LEFT; - else if (right > JOYSTICK_PERCENT) - result |= JOY_RIGHT; - if (up > JOYSTICK_PERCENT) - result |= JOY_UP; - else if (down > JOYSTICK_PERCENT) - result |= JOY_DOWN; - - if (js_b1) - result |= JOY_BUTTON_1; - if (js_b2) - result |= JOY_BUTTON_2; - - return result; -} - -#else /* PLATFORM_MSDOS */ - -/* allegro global variables for joystick control */ -extern int num_joysticks; -extern JOYSTICK_INFO joy[]; - -int Joystick(int player_nr) -{ - int joystick_nr = stored_player[player_nr].joystick_fd; - int result = 0; - - if (joystick_status == JOYSTICK_OFF) - return 0; - - if (game_status == SETUPINPUT) - return 0; - - if (joystick_nr < 0) - return 0; - - /* the allegro global variable 'num_joysticks' contains the number - of joysticks found at initialization under MS-DOS / Windows */ - -#if 0 - if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick) - return 0; -#else - -#if 1 - if (joystick_nr >= num_joysticks || - (game_status == PLAYING && !setup.input[player_nr].use_joystick)) - return 0; -#else - if (joystick_nr >= num_joysticks) - return 0; -#endif - -#endif - - poll_joystick(); - - if (joy[joystick_nr].stick[0].axis[0].d1) - result |= JOY_LEFT; - else if (joy[joystick_nr].stick[0].axis[0].d2) - result |= JOY_RIGHT; - if (joy[joystick_nr].stick[0].axis[1].d1) - result |= JOY_UP; - else if (joy[joystick_nr].stick[0].axis[1].d2) - result |= JOY_DOWN; - - if (joy[joystick_nr].button[0].b) - result |= JOY_BUTTON_1; - if (joy[joystick_nr].button[1].b) - result |= JOY_BUTTON_2; - - return result; -} -#endif /* PLATFORM_MSDOS */ - -#endif /* !TARGET_SDL */ - -int JoystickButton(int player_nr) -{ - static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 }; - int joy_button = (Joystick(player_nr) & JOY_BUTTON); - int result; - - if (joy_button) - { - if (last_joy_button[player_nr]) - result = JOY_BUTTON_PRESSED; - else - result = JOY_BUTTON_NEW_PRESSED; - } - else - { - if (last_joy_button[player_nr]) - result = JOY_BUTTON_NEW_RELEASED; - else - result = JOY_BUTTON_NOT_PRESSED; - } - - last_joy_button[player_nr] = joy_button; - return result; -} - -int AnyJoystick() -{ - int i; - int result = 0; - - for (i=0; i -#define DEV_JOYSTICK_0 "/dev/joy0" -#define DEV_JOYSTICK_1 "/dev/joy1" -#define DEV_JOYSTICK_2 "/dev/joy2" -#define DEV_JOYSTICK_3 "/dev/joy3" -#else -#define DEV_JOYSTICK_0 "/dev/js0" -#define DEV_JOYSTICK_1 "/dev/js1" -#define DEV_JOYSTICK_2 "/dev/js2" -#define DEV_JOYSTICK_3 "/dev/js3" -#endif - -/* get these values from the program 'js' from the joystick package, */ -/* set JOYSTICK_PERCENT to a threshold appropriate for your joystick */ - -#ifdef TARGET_SDL -#define JOYSTICK_XLEFT -32767 -#define JOYSTICK_XMIDDLE 0 -#define JOYSTICK_XRIGHT 32767 -#define JOYSTICK_YUPPER -32767 -#define JOYSTICK_YMIDDLE 0 -#define JOYSTICK_YLOWER 32767 -#else -#define JOYSTICK_XLEFT 30 -#define JOYSTICK_XMIDDLE 530 -#define JOYSTICK_XRIGHT 1250 -#define JOYSTICK_YUPPER 40 -#define JOYSTICK_YMIDDLE 680 -#define JOYSTICK_YLOWER 1440 -#endif - -#define JOYSTICK_PERCENT 25 - -#define JOY_LEFT MV_LEFT -#define JOY_RIGHT MV_RIGHT -#define JOY_UP MV_UP -#define JOY_DOWN MV_DOWN -#define JOY_BUTTON_1 (1<<4) -#define JOY_BUTTON_2 (1<<5) -#define JOY_BUTTON (JOY_BUTTON_1 | JOY_BUTTON_2) - -#define JOY_BUTTON_NOT_PRESSED 0 -#define JOY_BUTTON_PRESSED 1 -#define JOY_BUTTON_NEW_PRESSED 2 -#define JOY_BUTTON_NEW_RELEASED 3 - -#ifdef NO_JOYSTICK -#define JOYSTICK_STATUS JOYSTICK_OFF -#else -#define JOYSTICK_STATUS JOYSTICK_AVAILABLE -#endif - - -#if defined(TARGET_SDL) -SDL_Joystick *Get_SDL_Joystick(int); -boolean Open_SDL_Joystick(int); -void Close_SDL_Joystick(int); -boolean Check_SDL_JoystickOpened(int); -void HandleJoystickEvent(Event *); -int Get_SDL_Joystick_Axis(int, int); -#endif - -void CheckJoystickData(void); -int Joystick(int); -int JoystickButton(int); -int AnyJoystick(void); -int AnyJoystickButton(void); - -#endif /* JOYSTICK_H */ diff --git a/src/libgame/Makefile b/src/libgame/Makefile index b756b27d..07159642 100644 --- a/src/libgame/Makefile +++ b/src/libgame/Makefile @@ -7,9 +7,11 @@ SRCS = system.c \ gadgets.c \ text.c \ sound.c \ + joystick.c \ pcx.c \ image.c \ random.c \ + setup.c \ misc.c \ msdos.c \ x11.c \ @@ -19,9 +21,11 @@ OBJS = system.o \ gadgets.o \ text.o \ sound.o \ + joystick.o \ pcx.o \ image.o \ random.o \ + setup.o \ misc.o \ msdos.o \ x11.o \ diff --git a/src/libgame/joystick.c b/src/libgame/joystick.c new file mode 100644 index 00000000..4bca8893 --- /dev/null +++ b/src/libgame/joystick.c @@ -0,0 +1,577 @@ +/*********************************************************** +* Artsoft Retro-Game Library * +*----------------------------------------------------------* +* (c) 1995-2002 Artsoft Entertainment * +* Holger Schemel * +* Detmolder Strasse 189 * +* 33604 Bielefeld * +* Germany * +* e-mail: info@artsoft.org * +*----------------------------------------------------------* +* joystick.c * +***********************************************************/ + +#if defined(PLATFORM_FREEBSD) +#include +#endif + +#include "joystick.h" +#include "misc.h" + + +#define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0 +#define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1 + +#if 0 +static int joystick_device = 0; +char *joystick_device_name[MAX_PLAYERS] = +{ + DEV_JOYSTICK_0, + DEV_JOYSTICK_1, + DEV_JOYSTICK_2, + DEV_JOYSTICK_3 +}; +#endif + + +void translate_joyname(int *joysymbol, char **name, int mode) +{ + static struct + { + int joysymbol; + char *name; + } translate_joy[] = + { + { JOY_LEFT, "joystick_left" }, + { JOY_RIGHT, "joystick_right" }, + { JOY_UP, "joystick_up" }, + { JOY_DOWN, "joystick_down" }, + { JOY_BUTTON_1, "joystick_button_1" }, + { JOY_BUTTON_2, "joystick_button_2" }, + }; + + int i; + + if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME) + { + *name = "[undefined]"; + + for (i=0; i<6; i++) + { + if (*joysymbol == translate_joy[i].joysymbol) + { + *name = translate_joy[i].name; + break; + } + } + } + else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL) + { + *joysymbol = 0; + + for (i=0; i<6; i++) + { + if (strcmp(*name, translate_joy[i].name) == 0) + { + *joysymbol = translate_joy[i].joysymbol; + break; + } + } + } +} + +char *getJoyNameFromJoySymbol(int joysymbol) +{ + char *name; + + translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME); + return name; +} + +int getJoySymbolFromJoyName(char *name) +{ + int joysymbol; + + translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL); + return joysymbol; +} + +int getJoystickNrFromDeviceName(char *device_name) +{ + char c; + int joystick_nr = 0; + + if (device_name == NULL || device_name[0] == '\0') + return 0; + + c = device_name[strlen(device_name) - 1]; + + if (c >= '0' && c <= '9') + joystick_nr = (int)(c - '0'); + + if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS) + joystick_nr = 0; + + return joystick_nr; +} + +char *getDeviceNameFromJoystickNr(int joystick_nr) +{ + static char *joystick_device_name[MAX_PLAYERS] = + { + DEV_JOYSTICK_0, + DEV_JOYSTICK_1, + DEV_JOYSTICK_2, + DEV_JOYSTICK_3 + }; + + return (joystick_nr >= 0 && joystick_nr <= 3 ? + joystick_device_name[joystick_nr] : ""); +} + +#if !defined(PLATFORM_MSDOS) +static int JoystickPosition(int middle, int margin, int actual) +{ + long range, pos; + int percentage; + + if (margin < middle && actual > middle) + return 0; + if (margin > middle && actual < middle) + return 0; + + range = ABS(margin - middle); + pos = ABS(actual - middle); + percentage = (int)(pos * 100 / range); + + if (percentage > 100) + percentage = 100; + + return percentage; +} +#endif + +#if defined(TARGET_SDL) + +static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL }; +static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; +static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} }; + +SDL_Joystick *Get_SDL_Joystick(int nr) +{ + return sdl_joystick[nr]; +} + +boolean Open_SDL_Joystick(int nr) +{ + if (nr < 0 || nr > MAX_PLAYERS) + return FALSE; + + return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE); +} + +void Close_SDL_Joystick(int nr) +{ + if (nr < 0 || nr > MAX_PLAYERS) + return; + + SDL_JoystickClose(sdl_joystick[nr]); +} + +boolean Check_SDL_JoystickOpened(int nr) +{ + if (nr < 0 || nr > MAX_PLAYERS) + return FALSE; + + return (SDL_JoystickOpened(nr) ? TRUE : FALSE); +} + +void HandleJoystickEvent(Event *event) +{ + switch(event->type) + { + case SDL_JOYAXISMOTION: + if (event->jaxis.axis < 2) + { + sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value; + +#if 0 + printf("js_%d %s-axis: %d\n", + event->jaxis.which, + (event->jaxis.axis == 0 ? "x" : "y"), + event->jaxis.value); +#endif + } + break; + + case SDL_JOYBUTTONDOWN: + if (event->jbutton.button < 2) + { + sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE; + +#if 0 + printf("js_%d button %d: pressed\n", + event->jbutton.which, + event->jbutton.button); +#endif + } + break; + + case SDL_JOYBUTTONUP: + if (event->jbutton.button < 2) + { + sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE; + +#if 0 + printf("js_%d button %d: released\n", + event->jbutton.which, + event->jbutton.button); +#endif + } + break; + + default: + break; + } +} + +int Get_SDL_Joystick_Axis(int nr, int axis) +{ + if (nr < 0 || nr > MAX_PLAYERS) + return 0; + + if (axis < 0 || axis > 1) + return 0; + + return sdl_js_axis[nr][axis]; +} + +void CheckJoystickData() +{ +} + +int Joystick(int player_nr) +{ +#if 0 + int joystick_nr = stored_player[player_nr].joystick_fd; +#else + int joystick_nr = joystick.fd[player_nr]; +#endif + int js_x,js_y, js_b1,js_b2; + int left, right, up, down; + int result = 0; + + if (joystick.status != JOYSTICK_ACTIVATED) + return 0; + + if (!setup.input[player_nr].use_joystick || + !Check_SDL_JoystickOpened(joystick_nr)) + return 0; + + js_x = sdl_js_axis[joystick_nr][0]; + js_y = sdl_js_axis[joystick_nr][1]; + + js_b1 = sdl_js_button[joystick_nr][0]; + js_b2 = sdl_js_button[joystick_nr][1]; + + + +#if 0 + printf("JOYSTICK %d: js_x == %d, js_y == %d, js_b1 == %d, js_b2 == %d\n", + joystick_nr, js_x, js_y, js_b1, js_b2); +#endif + + + + left = JoystickPosition(setup.input[player_nr].joy.xmiddle, + setup.input[player_nr].joy.xleft, js_x); + right = JoystickPosition(setup.input[player_nr].joy.xmiddle, + setup.input[player_nr].joy.xright, js_x); + up = JoystickPosition(setup.input[player_nr].joy.ymiddle, + setup.input[player_nr].joy.yupper, js_y); + down = JoystickPosition(setup.input[player_nr].joy.ymiddle, + setup.input[player_nr].joy.ylower, js_y); + + if (left > JOYSTICK_PERCENT) + result |= JOY_LEFT; + else if (right > JOYSTICK_PERCENT) + result |= JOY_RIGHT; + if (up > JOYSTICK_PERCENT) + result |= JOY_UP; + else if (down > JOYSTICK_PERCENT) + result |= JOY_DOWN; + + if (js_b1) + result |= JOY_BUTTON_1; + if (js_b2) + result |= JOY_BUTTON_2; + + + +#if 0 + printf("result == 0x%08x\n", result); +#endif + + + + return result; +} + +#else /* !TARGET_SDL */ + +void CheckJoystickData() +{ + int i; + int distance = 100; + + for(i=0; i= setup.input[i].joy.xmiddle) + setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance; + if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle) + setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance; + + if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle) + setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance; + if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle) + setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance; + } +} + +#if defined(PLATFORM_UNIX) +int Joystick(int player_nr) +{ +#if defined(PLATFORM_FREEBSD) + struct joystick joy_ctrl; +#else + struct joystick_control + { + int buttons; + int x; + int y; + } joy_ctrl; +#endif + +#if 0 + int joystick_fd = stored_player[player_nr].joystick_fd; +#else + int joystick_fd = joystick.fd[player_nr]; +#endif + int js_x,js_y, js_b1,js_b2; + int left, right, up, down; + int result = 0; + + if (joystick.status != JOYSTICK_ACTIVATED) + return 0; + + if (joystick_fd < 0 || !setup.input[player_nr].use_joystick) + return 0; + + if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) + { + Error(ERR_WARN, "cannot read joystick device '%s'", + setup.input[player_nr].joy.device_name); + joystick.status = JOYSTICK_NOT_AVAILABLE; + return 0; + } + + js_x = joy_ctrl.x; + js_y = joy_ctrl.y; + +#if defined(PLATFORM_FREEBSD) + js_b1 = joy_ctrl.b1; + js_b2 = joy_ctrl.b2; +#else + js_b1 = joy_ctrl.buttons & 1; + js_b2 = joy_ctrl.buttons & 2; +#endif + + left = JoystickPosition(setup.input[player_nr].joy.xmiddle, + setup.input[player_nr].joy.xleft, js_x); + right = JoystickPosition(setup.input[player_nr].joy.xmiddle, + setup.input[player_nr].joy.xright, js_x); + up = JoystickPosition(setup.input[player_nr].joy.ymiddle, + setup.input[player_nr].joy.yupper, js_y); + down = JoystickPosition(setup.input[player_nr].joy.ymiddle, + setup.input[player_nr].joy.ylower, js_y); + + if (left > JOYSTICK_PERCENT) + result |= JOY_LEFT; + else if (right > JOYSTICK_PERCENT) + result |= JOY_RIGHT; + if (up > JOYSTICK_PERCENT) + result |= JOY_UP; + else if (down > JOYSTICK_PERCENT) + result |= JOY_DOWN; + + if (js_b1) + result |= JOY_BUTTON_1; + if (js_b2) + result |= JOY_BUTTON_2; + + return result; +} + +#else /* PLATFORM_MSDOS */ + +/* allegro global variables for joystick control */ +extern int num_joysticks; +extern JOYSTICK_INFO joy[]; + +int Joystick(int player_nr) +{ +#if 0 + int joystick_nr = stored_player[player_nr].joystick_fd; +#else + int joystick_nr = joystick.fd[player_nr]; +#endif + int result = 0; + + if (joystick.status != JOYSTICK_ACTIVATED) + return 0; + + if (joystick_nr < 0) + return 0; + + /* the allegro global variable 'num_joysticks' contains the number + of joysticks found at initialization under MS-DOS / Windows */ + +#if 0 + if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick) + return 0; +#else + +#if 1 + /* + if (joystick_nr >= num_joysticks || + (game_status == PLAYING && !setup.input[player_nr].use_joystick)) + return 0; + */ + + if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick) + return 0; + +#else + if (joystick_nr >= num_joysticks) + return 0; +#endif + +#endif + + poll_joystick(); + + if (joy[joystick_nr].stick[0].axis[0].d1) + result |= JOY_LEFT; + else if (joy[joystick_nr].stick[0].axis[0].d2) + result |= JOY_RIGHT; + if (joy[joystick_nr].stick[0].axis[1].d1) + result |= JOY_UP; + else if (joy[joystick_nr].stick[0].axis[1].d2) + result |= JOY_DOWN; + + if (joy[joystick_nr].button[0].b) + result |= JOY_BUTTON_1; + if (joy[joystick_nr].button[1].b) + result |= JOY_BUTTON_2; + + return result; +} +#endif /* PLATFORM_MSDOS */ + +#endif /* !TARGET_SDL */ + +int JoystickButton(int player_nr) +{ + static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 }; + int joy_button = (Joystick(player_nr) & JOY_BUTTON); + int result; + + if (joy_button) + { + if (last_joy_button[player_nr]) + result = JOY_BUTTON_PRESSED; + else + result = JOY_BUTTON_NEW_PRESSED; + } + else + { + if (last_joy_button[player_nr]) + result = JOY_BUTTON_NEW_RELEASED; + else + result = JOY_BUTTON_NOT_PRESSED; + } + + last_joy_button[player_nr] = joy_button; + return result; +} + +int AnyJoystick() +{ + int i; + int result = 0; + + for (i=0; i #include #include +/* #include +*/ #include #include #include @@ -28,6 +30,7 @@ #endif #include "misc.h" +#include "setup.h" #include "random.h" @@ -678,6 +681,26 @@ void *checked_realloc(void *ptr, unsigned long size) return ptr; } +inline void swap_numbers(int *i1, int *i2) +{ + int help = *i1; + + *i1 = *i2; + *i2 = help; +} + +inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2) +{ + int help_x = *x1; + int help_y = *y1; + + *x1 = *x2; + *x2 = help_x; + + *y1 = *y2; + *y2 = help_y; +} + short getFile16BitInteger(FILE *file, int byte_order) { if (byte_order == BYTE_ORDER_BIG_ENDIAN) @@ -1089,650 +1112,6 @@ char getCharFromKey(Key key) return letter; } -/* ------------------------------------------------------------------------- */ -/* some functions to handle lists of level directories */ -/* ------------------------------------------------------------------------- */ - -struct LevelDirInfo *newLevelDirInfo() -{ - return checked_calloc(sizeof(struct LevelDirInfo)); -} - -void pushLevelDirInfo(struct LevelDirInfo **node_first, - struct LevelDirInfo *node_new) -{ - node_new->next = *node_first; - *node_first = node_new; -} - -int numLevelDirInfo(struct LevelDirInfo *node) -{ - int num = 0; - - while (node) - { - num++; - node = node->next; - } - - return num; -} - -boolean validLevelSeries(struct LevelDirInfo *node) -{ - return (node != NULL && !node->node_group && !node->parent_link); -} - -struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *node) -{ - if (node == NULL) - { - if (leveldir_first) /* start with first level directory entry */ - return getFirstValidLevelSeries(leveldir_first); - else - return NULL; - } - else if (node->node_group) /* enter level group (step down into tree) */ - return getFirstValidLevelSeries(node->node_group); - else if (node->parent_link) /* skip start entry of level group */ - { - if (node->next) /* get first real level series entry */ - return getFirstValidLevelSeries(node->next); - else /* leave empty level group and go on */ - return getFirstValidLevelSeries(node->node_parent->next); - } - else /* this seems to be a regular level series */ - return node; -} - -struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *node) -{ - if (node == NULL) - return NULL; - - if (node->node_parent == NULL) /* top level group */ - return leveldir_first; - else /* sub level group */ - return node->node_parent->node_group; -} - -int numLevelDirInfoInGroup(struct LevelDirInfo *node) -{ - return numLevelDirInfo(getLevelDirInfoFirstGroupEntry(node)); -} - -int posLevelDirInfo(struct LevelDirInfo *node) -{ - struct LevelDirInfo *node_cmp = getLevelDirInfoFirstGroupEntry(node); - int pos = 0; - - while (node_cmp) - { - if (node_cmp == node) - return pos; - - pos++; - node_cmp = node_cmp->next; - } - - return 0; -} - -struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *node, int pos) -{ - struct LevelDirInfo *node_default = node; - int pos_cmp = 0; - - while (node) - { - if (pos_cmp == pos) - return node; - - pos_cmp++; - node = node->next; - } - - return node_default; -} - -struct LevelDirInfo *getLevelDirInfoFromFilenameExt(struct LevelDirInfo *node, - char *filename) -{ - if (filename == NULL) - return NULL; - - while (node) - { - if (node->node_group) - { - struct LevelDirInfo *node_group; - - node_group = getLevelDirInfoFromFilenameExt(node->node_group, filename); - - if (node_group) - return node_group; - } - else if (!node->parent_link) - { - if (strcmp(filename, node->filename) == 0) - return node; - } - - node = node->next; - } - - return NULL; -} - -struct LevelDirInfo *getLevelDirInfoFromFilename(char *filename) -{ - return getLevelDirInfoFromFilenameExt(leveldir_first, filename); -} - -void dumpLevelDirInfo(struct LevelDirInfo *node, int depth) -{ - int i; - - while (node) - { - for (i=0; ifilename); - - if (node->node_group != NULL) - dumpLevelDirInfo(node->node_group, depth + 1); - - node = node->next; - } -} - -void sortLevelDirInfo(struct LevelDirInfo **node_first, - int (*compare_function)(const void *, const void *)) -{ - int num_nodes = numLevelDirInfo(*node_first); - struct LevelDirInfo **sort_array; - struct LevelDirInfo *node = *node_first; - int i = 0; - - if (num_nodes == 0) - return; - - /* allocate array for sorting structure pointers */ - sort_array = checked_calloc(num_nodes * sizeof(struct LevelDirInfo *)); - - /* writing structure pointers to sorting array */ - while (i < num_nodes && node) /* double boundary check... */ - { - sort_array[i] = node; - - i++; - node = node->next; - } - - /* sorting the structure pointers in the sorting array */ - qsort(sort_array, num_nodes, sizeof(struct LevelDirInfo *), - compare_function); - - /* update the linkage of list elements with the sorted node array */ - for (i=0; inext = sort_array[i + 1]; - sort_array[num_nodes - 1]->next = NULL; - - /* update the linkage of the main list anchor pointer */ - *node_first = sort_array[0]; - - free(sort_array); - - /* now recursively sort the level group structures */ - node = *node_first; - while (node) - { - if (node->node_group != NULL) - sortLevelDirInfo(&node->node_group, compare_function); - - node = node->next; - } -} - -inline void swap_numbers(int *i1, int *i2) -{ - int help = *i1; - - *i1 = *i2; - *i2 = help; -} - -inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2) -{ - int help_x = *x1; - int help_y = *y1; - - *x1 = *x2; - *x2 = help_x; - - *y1 = *y2; - *y2 = help_y; -} - - -/* ========================================================================= */ -/* some stuff from "files.c" */ -/* ========================================================================= */ - -#if defined(PLATFORM_WIN32) -#ifndef S_IRGRP -#define S_IRGRP S_IRUSR -#endif -#ifndef S_IROTH -#define S_IROTH S_IRUSR -#endif -#ifndef S_IWGRP -#define S_IWGRP S_IWUSR -#endif -#ifndef S_IWOTH -#define S_IWOTH S_IWUSR -#endif -#ifndef S_IXGRP -#define S_IXGRP S_IXUSR -#endif -#ifndef S_IXOTH -#define S_IXOTH S_IXUSR -#endif -#ifndef S_IRWXG -#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) -#endif -#ifndef S_ISGID -#define S_ISGID 0 -#endif -#endif /* PLATFORM_WIN32 */ - -/* file permissions for newly written files */ -#define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH) -#define MODE_W_ALL (S_IWUSR | S_IWGRP | S_IWOTH) -#define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) - -#define MODE_W_PRIVATE (S_IWUSR) -#define MODE_W_PUBLIC (S_IWUSR | S_IWGRP) -#define MODE_W_PUBLIC_DIR (S_IWUSR | S_IWGRP | S_ISGID) - -#define DIR_PERMS_PRIVATE (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE) -#define DIR_PERMS_PUBLIC (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR) - -#define FILE_PERMS_PRIVATE (MODE_R_ALL | MODE_W_PRIVATE) -#define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC) - -char *getUserDataDir(void) -{ - static char *userdata_dir = NULL; - - if (!userdata_dir) - { - char *home_dir = getHomeDir(); - char *data_dir = program.userdata_directory; - - userdata_dir = getPath2(home_dir, data_dir); - } - - return userdata_dir; -} - -char *getSetupDir() -{ - return getUserDataDir(); -} - -static mode_t posix_umask(mode_t mask) -{ -#if defined(PLATFORM_UNIX) - return umask(mask); -#else - return 0; -#endif -} - -static int posix_mkdir(const char *pathname, mode_t mode) -{ -#if defined(PLATFORM_WIN32) - return mkdir(pathname); -#else - return mkdir(pathname, mode); -#endif -} - -void createDirectory(char *dir, char *text, int permission_class) -{ - /* leave "other" permissions in umask untouched, but ensure group parts - of USERDATA_DIR_MODE are not masked */ - mode_t dir_mode = (permission_class == PERMS_PRIVATE ? - DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC); - mode_t normal_umask = posix_umask(0); - mode_t group_umask = ~(dir_mode & S_IRWXG); - posix_umask(normal_umask & group_umask); - - if (access(dir, F_OK) != 0) - if (posix_mkdir(dir, dir_mode) != 0) - Error(ERR_WARN, "cannot create %s directory '%s'", text, dir); - - posix_umask(normal_umask); /* reset normal umask */ -} - -void InitUserDataDirectory() -{ - createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); -} - -void SetFilePermissions(char *filename, int permission_class) -{ - chmod(filename, (permission_class == PERMS_PRIVATE ? - FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC)); -} - -int getFileVersionFromCookieString(const char *cookie) -{ - const char *ptr_cookie1, *ptr_cookie2; - const char *pattern1 = "_FILE_VERSION_"; - const char *pattern2 = "?.?"; - const int len_cookie = strlen(cookie); - const int len_pattern1 = strlen(pattern1); - const int len_pattern2 = strlen(pattern2); - const int len_pattern = len_pattern1 + len_pattern2; - int version_major, version_minor; - - if (len_cookie <= len_pattern) - return -1; - - ptr_cookie1 = &cookie[len_cookie - len_pattern]; - ptr_cookie2 = &cookie[len_cookie - len_pattern2]; - - if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0) - return -1; - - if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' || - ptr_cookie2[1] != '.' || - ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9') - return -1; - - version_major = ptr_cookie2[0] - '0'; - version_minor = ptr_cookie2[2] - '0'; - - return VERSION_IDENT(version_major, version_minor, 0); -} - -boolean checkCookieString(const char *cookie, const char *template) -{ - const char *pattern = "_FILE_VERSION_?.?"; - const int len_cookie = strlen(cookie); - const int len_template = strlen(template); - const int len_pattern = strlen(pattern); - - if (len_cookie != len_template) - return FALSE; - - if (strncmp(cookie, template, len_cookie - len_pattern) != 0) - return FALSE; - - return TRUE; -} - -/* ------------------------------------------------------------------------- */ -/* setup file stuff */ -/* ------------------------------------------------------------------------- */ - -static char *string_tolower(char *s) -{ - static char s_lower[100]; - int i; - - if (strlen(s) >= 100) - return s; - - strcpy(s_lower, s); - - for (i=0; itoken) - free(setup_file_list->token); - if (setup_file_list->value) - free(setup_file_list->value); - if (setup_file_list->next) - freeSetupFileList(setup_file_list->next); - free(setup_file_list); -} - -static struct SetupFileList *newSetupFileList(char *token, char *value) -{ - struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList)); - - new->token = checked_malloc(strlen(token) + 1); - strcpy(new->token, token); - - new->value = checked_malloc(strlen(value) + 1); - strcpy(new->value, value); - - new->next = NULL; - - return new; -} - -char *getTokenValue(struct SetupFileList *setup_file_list, char *token) -{ - if (!setup_file_list) - return NULL; - - if (strcmp(setup_file_list->token, token) == 0) - return setup_file_list->value; - else - return getTokenValue(setup_file_list->next, token); -} - -static void setTokenValue(struct SetupFileList *setup_file_list, - char *token, char *value) -{ - if (!setup_file_list) - return; - - if (strcmp(setup_file_list->token, token) == 0) - { - free(setup_file_list->value); - setup_file_list->value = checked_malloc(strlen(value) + 1); - strcpy(setup_file_list->value, value); - } - else if (setup_file_list->next == NULL) - setup_file_list->next = newSetupFileList(token, value); - else - setTokenValue(setup_file_list->next, token, value); -} - -#ifdef DEBUG -static void printSetupFileList(struct SetupFileList *setup_file_list) -{ - if (!setup_file_list) - return; - - printf("token: '%s'\n", setup_file_list->token); - printf("value: '%s'\n", setup_file_list->value); - - printSetupFileList(setup_file_list->next); -} -#endif - -struct SetupFileList *loadSetupFileList(char *filename) -{ - int line_len; - char line[MAX_LINE_LEN]; - char *token, *value, *line_ptr; - struct SetupFileList *setup_file_list = newSetupFileList("", ""); - struct SetupFileList *first_valid_list_entry; - - FILE *file; - - if (!(file = fopen(filename, MODE_READ))) - { - Error(ERR_WARN, "cannot open configuration file '%s'", filename); - return NULL; - } - - while(!feof(file)) - { - /* read next line of input file */ - if (!fgets(line, MAX_LINE_LEN, file)) - break; - - /* cut trailing comment or whitespace from input line */ - for (line_ptr = line; *line_ptr; line_ptr++) - { - if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r') - { - *line_ptr = '\0'; - break; - } - } - - /* cut trailing whitespaces from input line */ - for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--) - if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0') - *line_ptr = '\0'; - - /* ignore empty lines */ - if (*line == '\0') - continue; - - line_len = strlen(line); - - /* cut leading whitespaces from token */ - for (token = line; *token; token++) - if (*token != ' ' && *token != '\t') - break; - - /* find end of token */ - for (line_ptr = token; *line_ptr; line_ptr++) - { - if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') - { - *line_ptr = '\0'; - break; - } - } - - if (line_ptr < line + line_len) - value = line_ptr + 1; - else - value = "\0"; - - /* cut leading whitespaces from value */ - for (; *value; value++) - if (*value != ' ' && *value != '\t') - break; - - if (*token && *value) - setTokenValue(setup_file_list, token, value); - } - - fclose(file); - - first_valid_list_entry = setup_file_list->next; - - /* free empty list header */ - setup_file_list->next = NULL; - freeSetupFileList(setup_file_list); - - if (first_valid_list_entry == NULL) - Error(ERR_WARN, "configuration file '%s' is empty", filename); - - return first_valid_list_entry; -} - -void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, - char *identifier) -{ - if (!setup_file_list) - return; - - if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0) - { - if (strcmp(setup_file_list->value, identifier) != 0) - { - Error(ERR_WARN, "configuration file has wrong version"); - return; - } - else - return; - } - - if (setup_file_list->next) - checkSetupFileListIdentifier(setup_file_list->next, identifier); - else - { - Error(ERR_WARN, "configuration file has no version information"); - return; - } -} - /* ========================================================================= */ /* functions only needed for non-Unix (non-command-line) systems */ diff --git a/src/libgame/misc.h b/src/libgame/misc.h index 6213ae1b..d90727d9 100644 --- a/src/libgame/misc.h +++ b/src/libgame/misc.h @@ -59,31 +59,6 @@ #define MAX_FILENAME_LEN 256 #define MAX_LINE_LEN 1000 -/* values for setup file stuff */ -#define TYPE_BOOLEAN 1 -#define TYPE_SWITCH 2 -#define TYPE_KEY 3 -#define TYPE_INTEGER 4 -#define TYPE_STRING 5 - -#define TOKEN_STR_FILE_IDENTIFIER "file_identifier" - -#define TOKEN_VALUE_POSITION 30 - -struct SetupFileList -{ - char *token; - char *value; - struct SetupFileList *next; -}; - -struct TokenInfo -{ - int type; - void *value; - char *text; -}; - void InitCounter(void); unsigned long Counter(void); void Delay(unsigned long); @@ -106,6 +81,9 @@ void Error(int, char *, ...); void *checked_malloc(unsigned long); void *checked_calloc(unsigned long); void *checked_realloc(void *, unsigned long); +inline void swap_numbers(int *, int *); +inline void swap_number_pairs(int *, int *, int *, int *); + short getFile16BitInteger(FILE *, int); void putFile16BitInteger(FILE *, short, int); int getFile32BitInteger(FILE *, int); @@ -119,42 +97,6 @@ char *getKeyNameFromKey(Key); char *getX11KeyNameFromKey(Key); Key getKeyFromX11KeyName(char *); char getCharFromKey(Key); -char *getJoyNameFromJoySymbol(int); -int getJoySymbolFromJoyName(char *); -int getJoystickNrFromDeviceName(char *); - -struct LevelDirInfo *newLevelDirInfo(); -void pushLevelDirInfo(struct LevelDirInfo **, struct LevelDirInfo *); -int numLevelDirInfo(struct LevelDirInfo *); -boolean validLevelSeries(struct LevelDirInfo *); -struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *); -struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *); -int numLevelDirInfoInGroup(struct LevelDirInfo *); -int posLevelDirInfo(struct LevelDirInfo *); -struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *, int); -struct LevelDirInfo *getLevelDirInfoFromFilename(char *); -void dumpLevelDirInfo(struct LevelDirInfo *, int); -void sortLevelDirInfo(struct LevelDirInfo **, - int (*compare_function)(const void *, const void *)); - -inline void swap_numbers(int *, int *); -inline void swap_number_pairs(int *, int *, int *, int *); - -char *getUserDataDir(void); -char *getSetupDir(void); -void createDirectory(char *, char *, int); -void InitUserDataDirectory(void); -void SetFilePermissions(char *, int); -int getFileVersionFromCookieString(const char *); -boolean checkCookieString(const char *, const char *); - -int get_string_integer_value(char *); -boolean get_string_boolean_value(char *); -char *getFormattedSetupEntry(char *, char *); -void freeSetupFileList(struct SetupFileList *); -char *getTokenValue(struct SetupFileList *, char *); -struct SetupFileList *loadSetupFileList(char *); -void checkSetupFileListIdentifier(struct SetupFileList *, char *); #if !defined(PLATFORM_UNIX) void initErrorFile(); diff --git a/src/libgame/setup.c b/src/libgame/setup.c new file mode 100644 index 00000000..d0f2bc06 --- /dev/null +++ b/src/libgame/setup.c @@ -0,0 +1,1848 @@ +/*********************************************************** +* Artsoft Retro-Game Library * +*----------------------------------------------------------* +* (c) 1994-2002 Artsoft Entertainment * +* Holger Schemel * +* Detmolder Strasse 189 * +* 33604 Bielefeld * +* Germany * +* e-mail: info@artsoft.org * +*----------------------------------------------------------* +* setup.c * +***********************************************************/ + +#include +#include +#include +#include + +#include "setup.h" +#include "joystick.h" +#include "text.h" +#include "misc.h" + + +/* file identifier strings */ +#define SETUP_COOKIE "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2" +#define LEVELSETUP_COOKIE "ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_1.2" +#define LEVELINFO_COOKIE "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2" + +/* file names and filename extensions */ +#if !defined(PLATFORM_MSDOS) +#define LEVELSETUP_DIRECTORY "levelsetup" +#define SETUP_FILENAME "setup.conf" +#define LEVELSETUP_FILENAME "levelsetup.conf" +#define LEVELINFO_FILENAME "levelinfo.conf" +#define LEVELFILE_EXTENSION "level" +#define TAPEFILE_EXTENSION "tape" +#define SCOREFILE_EXTENSION "score" +#else +#define LEVELSETUP_DIRECTORY "lvlsetup" +#define SETUP_FILENAME "setup.cnf" +#define LEVELSETUP_FILENAME "lvlsetup.cnf" +#define LEVELINFO_FILENAME "lvlinfo.cnf" +#define LEVELFILE_EXTENSION "lvl" +#define TAPEFILE_EXTENSION "tap" +#define SCOREFILE_EXTENSION "sco" +#endif + +#define NUM_LEVELCLASS_DESC 8 +static char *levelclass_desc[NUM_LEVELCLASS_DESC] = +{ + "Tutorial Levels", + "Classic Originals", + "Contributions", + "Private Levels", + "Boulderdash", + "Emerald Mine", + "Supaplex", + "DX Boulderdash" +}; + +#define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \ + IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \ + IS_LEVELCLASS_BD(n) ? FC_GREEN : \ + IS_LEVELCLASS_EM(n) ? FC_YELLOW : \ + IS_LEVELCLASS_SP(n) ? FC_GREEN : \ + IS_LEVELCLASS_DX(n) ? FC_YELLOW : \ + IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \ + IS_LEVELCLASS_USER(n) ? FC_RED : \ + FC_BLUE) + +#define LEVELSORTING(n) (IS_LEVELCLASS_TUTORIAL(n) ? 0 : \ + IS_LEVELCLASS_CLASSICS(n) ? 1 : \ + IS_LEVELCLASS_BD(n) ? 2 : \ + IS_LEVELCLASS_EM(n) ? 3 : \ + IS_LEVELCLASS_SP(n) ? 4 : \ + IS_LEVELCLASS_DX(n) ? 5 : \ + IS_LEVELCLASS_CONTRIBUTION(n) ? 6 : \ + IS_LEVELCLASS_USER(n) ? 7 : \ + 9) + +/* values for setup file stuff */ +#define TYPE_BOOLEAN 1 +#define TYPE_SWITCH 2 +#define TYPE_KEY 3 +#define TYPE_INTEGER 4 +#define TYPE_STRING 5 + +#define TOKEN_STR_FILE_IDENTIFIER "file_identifier" + +#define TOKEN_VALUE_POSITION 30 + +struct SetupFileList +{ + char *token; + char *value; + struct SetupFileList *next; +}; + +struct TokenInfo +{ + int type; + void *value; + char *text; +}; + + +/* ------------------------------------------------------------------------- */ +/* file functions */ +/* ------------------------------------------------------------------------- */ + +/* +int get_string_integer_value(char *); +boolean get_string_boolean_value(char *); +char *getFormattedSetupEntry(char *, char *); +void freeSetupFileList(struct SetupFileList *); +char *getTokenValue(struct SetupFileList *, char *); +struct SetupFileList *loadSetupFileList(char *); +void checkSetupFileListIdentifier(struct SetupFileList *, char *); +*/ + +char *getLevelClassDescription(struct LevelDirInfo *ldi) +{ + int position = ldi->sort_priority / 100; + + if (position >= 0 && position < NUM_LEVELCLASS_DESC) + return levelclass_desc[position]; + else + return "Unknown Level Class"; +} + +/* for 'InitUserLevelDir()' */ +static void SaveUserLevelInfo(); + +/* for 'SaveUserLevelInfo()' */ +static char *getSetupLine(struct TokenInfo *, char *, int); + +static char *getUserLevelDir(char *level_subdir) +{ + static char *userlevel_dir = NULL; + char *data_dir = getUserDataDir(); + char *userlevel_subdir = LEVELS_DIRECTORY; + + if (userlevel_dir) + free(userlevel_dir); + + if (strlen(level_subdir) > 0) + userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir); + else + userlevel_dir = getPath2(data_dir, userlevel_subdir); + + return userlevel_dir; +} + +static char *getTapeDir(char *level_subdir) +{ + static char *tape_dir = NULL; + char *data_dir = getUserDataDir(); + char *tape_subdir = TAPES_DIRECTORY; + + if (tape_dir) + free(tape_dir); + + if (strlen(level_subdir) > 0) + tape_dir = getPath3(data_dir, tape_subdir, level_subdir); + else + tape_dir = getPath2(data_dir, tape_subdir); + + return tape_dir; +} + +static char *getScoreDir(char *level_subdir) +{ + static char *score_dir = NULL; + char *data_dir = options.rw_base_directory; + char *score_subdir = SCORES_DIRECTORY; + + if (score_dir) + free(score_dir); + + if (strlen(level_subdir) > 0) + score_dir = getPath3(data_dir, score_subdir, level_subdir); + else + score_dir = getPath2(data_dir, score_subdir); + + return score_dir; +} + +static char *getLevelSetupDir(char *level_subdir) +{ + static char *levelsetup_dir = NULL; + char *data_dir = getUserDataDir(); + char *levelsetup_subdir = LEVELSETUP_DIRECTORY; + + if (levelsetup_dir) + free(levelsetup_dir); + + if (strlen(level_subdir) > 0) + levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir); + else + levelsetup_dir = getPath2(data_dir, levelsetup_subdir); + + return levelsetup_dir; +} + +char *getLevelFilename(int nr) +{ + static char *filename = NULL; + char basename[MAX_FILENAME_LEN]; + + if (filename != NULL) + free(filename); + + sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION); + filename = getPath3((leveldir_current->user_defined ? + getUserLevelDir("") : + options.level_directory), + leveldir_current->fullpath, + basename); + + return filename; +} + +char *getTapeFilename(int nr) +{ + static char *filename = NULL; + char basename[MAX_FILENAME_LEN]; + + if (filename != NULL) + free(filename); + + sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); + filename = getPath2(getTapeDir(leveldir_current->filename), basename); + + return filename; +} + +char *getScoreFilename(int nr) +{ + static char *filename = NULL; + char basename[MAX_FILENAME_LEN]; + + if (filename != NULL) + free(filename); + + sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION); + filename = getPath2(getScoreDir(leveldir_current->filename), basename); + + return filename; +} + +void InitTapeDirectory(char *level_subdir) +{ + createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); + createDirectory(getTapeDir(""), "main tape", PERMS_PRIVATE); + createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE); +} + +void InitScoreDirectory(char *level_subdir) +{ + createDirectory(getScoreDir(""), "main score", PERMS_PUBLIC); + createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC); +} + +void InitUserLevelDirectory(char *level_subdir) +{ + if (access(getUserLevelDir(level_subdir), F_OK) != 0) + { + createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); + createDirectory(getUserLevelDir(""), "main user level", PERMS_PRIVATE); + createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE); + + SaveUserLevelInfo(); + } +} + +void InitLevelSetupDirectory(char *level_subdir) +{ + createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); + createDirectory(getLevelSetupDir(""), "main level setup", PERMS_PRIVATE); + createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE); +} + +void ReadChunk_VERS(FILE *file, int *file_version, int *game_version) +{ + int file_version_major, file_version_minor, file_version_patch; + int game_version_major, game_version_minor, game_version_patch; + + file_version_major = fgetc(file); + file_version_minor = fgetc(file); + file_version_patch = fgetc(file); + fgetc(file); /* not used */ + + game_version_major = fgetc(file); + game_version_minor = fgetc(file); + game_version_patch = fgetc(file); + fgetc(file); /* not used */ + + *file_version = VERSION_IDENT(file_version_major, + file_version_minor, + file_version_patch); + + *game_version = VERSION_IDENT(game_version_major, + game_version_minor, + game_version_patch); +} + +void WriteChunk_VERS(FILE *file, int file_version, int game_version) +{ + int file_version_major = VERSION_MAJOR(file_version); + int file_version_minor = VERSION_MINOR(file_version); + int file_version_patch = VERSION_PATCH(file_version); + int game_version_major = VERSION_MAJOR(game_version); + int game_version_minor = VERSION_MINOR(game_version); + int game_version_patch = VERSION_PATCH(game_version); + + fputc(file_version_major, file); + fputc(file_version_minor, file); + fputc(file_version_patch, file); + fputc(0, file); /* not used */ + + fputc(game_version_major, file); + fputc(game_version_minor, file); + fputc(game_version_patch, file); + fputc(0, file); /* not used */ +} + + +/* ------------------------------------------------------------------------- */ +/* some functions to handle lists of level directories */ +/* ------------------------------------------------------------------------- */ + +struct LevelDirInfo *newLevelDirInfo() +{ + return checked_calloc(sizeof(struct LevelDirInfo)); +} + +void pushLevelDirInfo(struct LevelDirInfo **node_first, + struct LevelDirInfo *node_new) +{ + node_new->next = *node_first; + *node_first = node_new; +} + +int numLevelDirInfo(struct LevelDirInfo *node) +{ + int num = 0; + + while (node) + { + num++; + node = node->next; + } + + return num; +} + +boolean validLevelSeries(struct LevelDirInfo *node) +{ + return (node != NULL && !node->node_group && !node->parent_link); +} + +struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *node) +{ + if (node == NULL) + { + if (leveldir_first) /* start with first level directory entry */ + return getFirstValidLevelSeries(leveldir_first); + else + return NULL; + } + else if (node->node_group) /* enter level group (step down into tree) */ + return getFirstValidLevelSeries(node->node_group); + else if (node->parent_link) /* skip start entry of level group */ + { + if (node->next) /* get first real level series entry */ + return getFirstValidLevelSeries(node->next); + else /* leave empty level group and go on */ + return getFirstValidLevelSeries(node->node_parent->next); + } + else /* this seems to be a regular level series */ + return node; +} + +struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *node) +{ + if (node == NULL) + return NULL; + + if (node->node_parent == NULL) /* top level group */ + return leveldir_first; + else /* sub level group */ + return node->node_parent->node_group; +} + +int numLevelDirInfoInGroup(struct LevelDirInfo *node) +{ + return numLevelDirInfo(getLevelDirInfoFirstGroupEntry(node)); +} + +int posLevelDirInfo(struct LevelDirInfo *node) +{ + struct LevelDirInfo *node_cmp = getLevelDirInfoFirstGroupEntry(node); + int pos = 0; + + while (node_cmp) + { + if (node_cmp == node) + return pos; + + pos++; + node_cmp = node_cmp->next; + } + + return 0; +} + +struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *node, int pos) +{ + struct LevelDirInfo *node_default = node; + int pos_cmp = 0; + + while (node) + { + if (pos_cmp == pos) + return node; + + pos_cmp++; + node = node->next; + } + + return node_default; +} + +struct LevelDirInfo *getLevelDirInfoFromFilenameExt(struct LevelDirInfo *node, + char *filename) +{ + if (filename == NULL) + return NULL; + + while (node) + { + if (node->node_group) + { + struct LevelDirInfo *node_group; + + node_group = getLevelDirInfoFromFilenameExt(node->node_group, filename); + + if (node_group) + return node_group; + } + else if (!node->parent_link) + { + if (strcmp(filename, node->filename) == 0) + return node; + } + + node = node->next; + } + + return NULL; +} + +struct LevelDirInfo *getLevelDirInfoFromFilename(char *filename) +{ + return getLevelDirInfoFromFilenameExt(leveldir_first, filename); +} + +void dumpLevelDirInfo(struct LevelDirInfo *node, int depth) +{ + int i; + + while (node) + { + for (i=0; ifilename); + + if (node->node_group != NULL) + dumpLevelDirInfo(node->node_group, depth + 1); + + node = node->next; + } +} + +void sortLevelDirInfo(struct LevelDirInfo **node_first, + int (*compare_function)(const void *, const void *)) +{ + int num_nodes = numLevelDirInfo(*node_first); + struct LevelDirInfo **sort_array; + struct LevelDirInfo *node = *node_first; + int i = 0; + + if (num_nodes == 0) + return; + + /* allocate array for sorting structure pointers */ + sort_array = checked_calloc(num_nodes * sizeof(struct LevelDirInfo *)); + + /* writing structure pointers to sorting array */ + while (i < num_nodes && node) /* double boundary check... */ + { + sort_array[i] = node; + + i++; + node = node->next; + } + + /* sorting the structure pointers in the sorting array */ + qsort(sort_array, num_nodes, sizeof(struct LevelDirInfo *), + compare_function); + + /* update the linkage of list elements with the sorted node array */ + for (i=0; inext = sort_array[i + 1]; + sort_array[num_nodes - 1]->next = NULL; + + /* update the linkage of the main list anchor pointer */ + *node_first = sort_array[0]; + + free(sort_array); + + /* now recursively sort the level group structures */ + node = *node_first; + while (node) + { + if (node->node_group != NULL) + sortLevelDirInfo(&node->node_group, compare_function); + + node = node->next; + } +} + + +/* ========================================================================= */ +/* some stuff from "files.c" */ +/* ========================================================================= */ + +#if defined(PLATFORM_WIN32) +#ifndef S_IRGRP +#define S_IRGRP S_IRUSR +#endif +#ifndef S_IROTH +#define S_IROTH S_IRUSR +#endif +#ifndef S_IWGRP +#define S_IWGRP S_IWUSR +#endif +#ifndef S_IWOTH +#define S_IWOTH S_IWUSR +#endif +#ifndef S_IXGRP +#define S_IXGRP S_IXUSR +#endif +#ifndef S_IXOTH +#define S_IXOTH S_IXUSR +#endif +#ifndef S_IRWXG +#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP) +#endif +#ifndef S_ISGID +#define S_ISGID 0 +#endif +#endif /* PLATFORM_WIN32 */ + +/* file permissions for newly written files */ +#define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH) +#define MODE_W_ALL (S_IWUSR | S_IWGRP | S_IWOTH) +#define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) + +#define MODE_W_PRIVATE (S_IWUSR) +#define MODE_W_PUBLIC (S_IWUSR | S_IWGRP) +#define MODE_W_PUBLIC_DIR (S_IWUSR | S_IWGRP | S_ISGID) + +#define DIR_PERMS_PRIVATE (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE) +#define DIR_PERMS_PUBLIC (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR) + +#define FILE_PERMS_PRIVATE (MODE_R_ALL | MODE_W_PRIVATE) +#define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC) + +char *getUserDataDir(void) +{ + static char *userdata_dir = NULL; + + if (!userdata_dir) + { + char *home_dir = getHomeDir(); + char *data_dir = program.userdata_directory; + + userdata_dir = getPath2(home_dir, data_dir); + } + + return userdata_dir; +} + +char *getSetupDir() +{ + return getUserDataDir(); +} + +static mode_t posix_umask(mode_t mask) +{ +#if defined(PLATFORM_UNIX) + return umask(mask); +#else + return 0; +#endif +} + +static int posix_mkdir(const char *pathname, mode_t mode) +{ +#if defined(PLATFORM_WIN32) + return mkdir(pathname); +#else + return mkdir(pathname, mode); +#endif +} + +void createDirectory(char *dir, char *text, int permission_class) +{ + /* leave "other" permissions in umask untouched, but ensure group parts + of USERDATA_DIR_MODE are not masked */ + mode_t dir_mode = (permission_class == PERMS_PRIVATE ? + DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC); + mode_t normal_umask = posix_umask(0); + mode_t group_umask = ~(dir_mode & S_IRWXG); + posix_umask(normal_umask & group_umask); + + if (access(dir, F_OK) != 0) + if (posix_mkdir(dir, dir_mode) != 0) + Error(ERR_WARN, "cannot create %s directory '%s'", text, dir); + + posix_umask(normal_umask); /* reset normal umask */ +} + +void InitUserDataDirectory() +{ + createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); +} + +void SetFilePermissions(char *filename, int permission_class) +{ + chmod(filename, (permission_class == PERMS_PRIVATE ? + FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC)); +} + +int getFileVersionFromCookieString(const char *cookie) +{ + const char *ptr_cookie1, *ptr_cookie2; + const char *pattern1 = "_FILE_VERSION_"; + const char *pattern2 = "?.?"; + const int len_cookie = strlen(cookie); + const int len_pattern1 = strlen(pattern1); + const int len_pattern2 = strlen(pattern2); + const int len_pattern = len_pattern1 + len_pattern2; + int version_major, version_minor; + + if (len_cookie <= len_pattern) + return -1; + + ptr_cookie1 = &cookie[len_cookie - len_pattern]; + ptr_cookie2 = &cookie[len_cookie - len_pattern2]; + + if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0) + return -1; + + if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' || + ptr_cookie2[1] != '.' || + ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9') + return -1; + + version_major = ptr_cookie2[0] - '0'; + version_minor = ptr_cookie2[2] - '0'; + + return VERSION_IDENT(version_major, version_minor, 0); +} + +boolean checkCookieString(const char *cookie, const char *template) +{ + const char *pattern = "_FILE_VERSION_?.?"; + const int len_cookie = strlen(cookie); + const int len_template = strlen(template); + const int len_pattern = strlen(pattern); + + if (len_cookie != len_template) + return FALSE; + + if (strncmp(cookie, template, len_cookie - len_pattern) != 0) + return FALSE; + + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* setup file list handling functions */ +/* ------------------------------------------------------------------------- */ + +int get_string_integer_value(char *s) +{ + static char *number_text[][3] = + { + { "0", "zero", "null", }, + { "1", "one", "first" }, + { "2", "two", "second" }, + { "3", "three", "third" }, + { "4", "four", "fourth" }, + { "5", "five", "fifth" }, + { "6", "six", "sixth" }, + { "7", "seven", "seventh" }, + { "8", "eight", "eighth" }, + { "9", "nine", "ninth" }, + { "10", "ten", "tenth" }, + { "11", "eleven", "eleventh" }, + { "12", "twelve", "twelfth" }, + }; + + int i, j; + char *s_lower = getStringToLower(s); + int result = -1; + + for (i=0; i<13; i++) + for (j=0; j<3; j++) + if (strcmp(s_lower, number_text[i][j]) == 0) + result = i; + + if (result == -1) + result = atoi(s); + + free(s_lower); + + return result; +} + +boolean get_string_boolean_value(char *s) +{ + char *s_lower = getStringToLower(s); + boolean result = FALSE; + + if (strcmp(s_lower, "true") == 0 || + strcmp(s_lower, "yes") == 0 || + strcmp(s_lower, "on") == 0 || + get_string_integer_value(s) == 1) + result = TRUE; + + free(s_lower); + + return result; +} + +char *getFormattedSetupEntry(char *token, char *value) +{ + int i; + static char entry[MAX_LINE_LEN]; + + sprintf(entry, "%s:", token); + for (i=strlen(entry); itoken) + free(setup_file_list->token); + if (setup_file_list->value) + free(setup_file_list->value); + if (setup_file_list->next) + freeSetupFileList(setup_file_list->next); + free(setup_file_list); +} + +static struct SetupFileList *newSetupFileList(char *token, char *value) +{ + struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList)); + + new->token = checked_malloc(strlen(token) + 1); + strcpy(new->token, token); + + new->value = checked_malloc(strlen(value) + 1); + strcpy(new->value, value); + + new->next = NULL; + + return new; +} + +char *getTokenValue(struct SetupFileList *setup_file_list, char *token) +{ + if (!setup_file_list) + return NULL; + + if (strcmp(setup_file_list->token, token) == 0) + return setup_file_list->value; + else + return getTokenValue(setup_file_list->next, token); +} + +static void setTokenValue(struct SetupFileList *setup_file_list, + char *token, char *value) +{ + if (!setup_file_list) + return; + + if (strcmp(setup_file_list->token, token) == 0) + { + free(setup_file_list->value); + setup_file_list->value = checked_malloc(strlen(value) + 1); + strcpy(setup_file_list->value, value); + } + else if (setup_file_list->next == NULL) + setup_file_list->next = newSetupFileList(token, value); + else + setTokenValue(setup_file_list->next, token, value); +} + +#ifdef DEBUG +static void printSetupFileList(struct SetupFileList *setup_file_list) +{ + if (!setup_file_list) + return; + + printf("token: '%s'\n", setup_file_list->token); + printf("value: '%s'\n", setup_file_list->value); + + printSetupFileList(setup_file_list->next); +} +#endif + +struct SetupFileList *loadSetupFileList(char *filename) +{ + int line_len; + char line[MAX_LINE_LEN]; + char *token, *value, *line_ptr; + struct SetupFileList *setup_file_list = newSetupFileList("", ""); + struct SetupFileList *first_valid_list_entry; + + FILE *file; + + if (!(file = fopen(filename, MODE_READ))) + { + Error(ERR_WARN, "cannot open configuration file '%s'", filename); + return NULL; + } + + while(!feof(file)) + { + /* read next line of input file */ + if (!fgets(line, MAX_LINE_LEN, file)) + break; + + /* cut trailing comment or whitespace from input line */ + for (line_ptr = line; *line_ptr; line_ptr++) + { + if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r') + { + *line_ptr = '\0'; + break; + } + } + + /* cut trailing whitespaces from input line */ + for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--) + if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0') + *line_ptr = '\0'; + + /* ignore empty lines */ + if (*line == '\0') + continue; + + line_len = strlen(line); + + /* cut leading whitespaces from token */ + for (token = line; *token; token++) + if (*token != ' ' && *token != '\t') + break; + + /* find end of token */ + for (line_ptr = token; *line_ptr; line_ptr++) + { + if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') + { + *line_ptr = '\0'; + break; + } + } + + if (line_ptr < line + line_len) + value = line_ptr + 1; + else + value = "\0"; + + /* cut leading whitespaces from value */ + for (; *value; value++) + if (*value != ' ' && *value != '\t') + break; + + if (*token && *value) + setTokenValue(setup_file_list, token, value); + } + + fclose(file); + + first_valid_list_entry = setup_file_list->next; + + /* free empty list header */ + setup_file_list->next = NULL; + freeSetupFileList(setup_file_list); + + if (first_valid_list_entry == NULL) + Error(ERR_WARN, "configuration file '%s' is empty", filename); + + return first_valid_list_entry; +} + +void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, + char *identifier) +{ + if (!setup_file_list) + return; + + if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0) + { + if (strcmp(setup_file_list->value, identifier) != 0) + { + Error(ERR_WARN, "configuration file has wrong version"); + return; + } + else + return; + } + + if (setup_file_list->next) + checkSetupFileListIdentifier(setup_file_list->next, identifier); + else + { + Error(ERR_WARN, "configuration file has no version information"); + return; + } +} + + +/* ========================================================================= */ +/* setup file stuff */ +/* ========================================================================= */ + +#define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series" +#define TOKEN_STR_LAST_PLAYED_LEVEL "last_played_level" +#define TOKEN_STR_HANDICAP_LEVEL "handicap_level" +#define TOKEN_STR_PLAYER_PREFIX "player_" + +/* global setup */ +#define SETUP_TOKEN_PLAYER_NAME 0 +#define SETUP_TOKEN_SOUND 1 +#define SETUP_TOKEN_SOUND_LOOPS 2 +#define SETUP_TOKEN_SOUND_MUSIC 3 +#define SETUP_TOKEN_SOUND_SIMPLE 4 +#define SETUP_TOKEN_SCROLL_DELAY 5 +#define SETUP_TOKEN_SOFT_SCROLLING 6 +#define SETUP_TOKEN_FADING 7 +#define SETUP_TOKEN_AUTORECORD 8 +#define SETUP_TOKEN_QUICK_DOORS 9 +#define SETUP_TOKEN_TEAM_MODE 10 +#define SETUP_TOKEN_HANDICAP 11 +#define SETUP_TOKEN_TIME_LIMIT 12 +#define SETUP_TOKEN_FULLSCREEN 13 + +/* player setup */ +#define SETUP_TOKEN_USE_JOYSTICK 0 +#define SETUP_TOKEN_JOY_DEVICE_NAME 1 +#define SETUP_TOKEN_JOY_XLEFT 2 +#define SETUP_TOKEN_JOY_XMIDDLE 3 +#define SETUP_TOKEN_JOY_XRIGHT 4 +#define SETUP_TOKEN_JOY_YUPPER 5 +#define SETUP_TOKEN_JOY_YMIDDLE 6 +#define SETUP_TOKEN_JOY_YLOWER 7 +#define SETUP_TOKEN_JOY_SNAP 8 +#define SETUP_TOKEN_JOY_BOMB 9 +#define SETUP_TOKEN_KEY_LEFT 10 +#define SETUP_TOKEN_KEY_RIGHT 11 +#define SETUP_TOKEN_KEY_UP 12 +#define SETUP_TOKEN_KEY_DOWN 13 +#define SETUP_TOKEN_KEY_SNAP 14 +#define SETUP_TOKEN_KEY_BOMB 15 + +/* level directory info */ +#define LEVELINFO_TOKEN_NAME 0 +#define LEVELINFO_TOKEN_NAME_SHORT 1 +#define LEVELINFO_TOKEN_NAME_SORTING 2 +#define LEVELINFO_TOKEN_AUTHOR 3 +#define LEVELINFO_TOKEN_IMPORTED_FROM 4 +#define LEVELINFO_TOKEN_LEVELS 5 +#define LEVELINFO_TOKEN_FIRST_LEVEL 6 +#define LEVELINFO_TOKEN_SORT_PRIORITY 7 +#define LEVELINFO_TOKEN_LEVEL_GROUP 8 +#define LEVELINFO_TOKEN_READONLY 9 + +#define FIRST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_PLAYER_NAME +#define LAST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_FULLSCREEN + +#define FIRST_PLAYER_SETUP_TOKEN SETUP_TOKEN_USE_JOYSTICK +#define LAST_PLAYER_SETUP_TOKEN SETUP_TOKEN_KEY_BOMB + +#define FIRST_LEVELINFO_TOKEN LEVELINFO_TOKEN_NAME +#define LAST_LEVELINFO_TOKEN LEVELINFO_TOKEN_READONLY + +static struct SetupInfo si; +static struct SetupInputInfo sii; +static struct LevelDirInfo ldi; +static struct TokenInfo global_setup_tokens[] = +{ + /* global setup */ + { TYPE_STRING, &si.player_name, "player_name" }, + { TYPE_SWITCH, &si.sound, "sound" }, + { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" }, + { TYPE_SWITCH, &si.sound_music, "background_music" }, + { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" }, + { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" }, + { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" }, + { TYPE_SWITCH, &si.fading, "screen_fading" }, + { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" }, + { TYPE_SWITCH, &si.quick_doors, "quick_doors" }, + { TYPE_SWITCH, &si.team_mode, "team_mode" }, + { TYPE_SWITCH, &si.handicap, "handicap" }, + { TYPE_SWITCH, &si.time_limit, "time_limit" }, + { TYPE_SWITCH, &si.fullscreen, "fullscreen" } +}; + +static struct TokenInfo player_setup_tokens[] = +{ + /* player setup */ + { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" }, + { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" }, + { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" }, + { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" }, + { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" }, + { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" }, + { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" }, + { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" }, + { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" }, + { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" }, + { TYPE_KEY, &sii.key.left, ".key.move_left" }, + { TYPE_KEY, &sii.key.right, ".key.move_right" }, + { TYPE_KEY, &sii.key.up, ".key.move_up" }, + { TYPE_KEY, &sii.key.down, ".key.move_down" }, + { TYPE_KEY, &sii.key.snap, ".key.snap_field" }, + { TYPE_KEY, &sii.key.bomb, ".key.place_bomb" } +}; + +static struct TokenInfo levelinfo_tokens[] = +{ + /* level directory info */ + { TYPE_STRING, &ldi.name, "name" }, + { TYPE_STRING, &ldi.name_short, "name_short" }, + { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, + { TYPE_STRING, &ldi.author, "author" }, + { TYPE_STRING, &ldi.imported_from, "imported_from" }, + { TYPE_INTEGER, &ldi.levels, "levels" }, + { TYPE_INTEGER, &ldi.first_level, "first_level" }, + { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, + { TYPE_BOOLEAN, &ldi.level_group, "level_group" }, + { TYPE_BOOLEAN, &ldi.readonly, "readonly" } +}; + +static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi) +{ + ldi->filename = NULL; + ldi->fullpath = NULL; + ldi->basepath = NULL; + ldi->name = getStringCopy(ANONYMOUS_NAME); + ldi->name_short = NULL; + ldi->name_sorting = NULL; + ldi->author = getStringCopy(ANONYMOUS_NAME); + ldi->imported_from = NULL; + ldi->levels = 0; + ldi->first_level = 0; + ldi->last_level = 0; + ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ + ldi->level_group = FALSE; + ldi->parent_link = FALSE; + ldi->user_defined = FALSE; + ldi->readonly = TRUE; + ldi->color = 0; + ldi->class_desc = NULL; + ldi->handicap_level = 0; + ldi->cl_first = -1; + ldi->cl_cursor = -1; + + ldi->node_parent = NULL; + ldi->node_group = NULL; + ldi->next = NULL; +} + +static void setLevelDirInfoToDefaultsFromParent(struct LevelDirInfo *ldi, + struct LevelDirInfo *parent) +{ + if (parent == NULL) + { + setLevelDirInfoToDefaults(ldi); + return; + } + + /* first copy all values from the parent structure ... */ + *ldi = *parent; + + /* ... then set all fields to default that cannot be inherited from parent. + This is especially important for all those fields that can be set from + the 'levelinfo.conf' config file, because the function 'setSetupInfo()' + calls 'free()' for all already set token values which requires that no + other structure's pointer may point to them! + */ + + ldi->filename = NULL; + ldi->fullpath = NULL; + ldi->basepath = NULL; + ldi->name = getStringCopy(ANONYMOUS_NAME); + ldi->name_short = NULL; + ldi->name_sorting = NULL; + ldi->author = getStringCopy(parent->author); + ldi->imported_from = getStringCopy(parent->imported_from); + + ldi->level_group = FALSE; + ldi->parent_link = FALSE; + + ldi->node_parent = parent; + ldi->node_group = NULL; + ldi->next = NULL; +} + +static void setSetupInfoToDefaults(struct SetupInfo *si) +{ + int i; + + si->player_name = getStringCopy(getLoginName()); + + si->sound = TRUE; + si->sound_loops = TRUE; + si->sound_music = TRUE; + si->sound_simple = TRUE; + si->toons = TRUE; + si->double_buffering = TRUE; + si->direct_draw = !si->double_buffering; + si->scroll_delay = TRUE; + si->soft_scrolling = TRUE; + si->fading = FALSE; + si->autorecord = TRUE; + si->quick_doors = FALSE; + si->team_mode = FALSE; + si->handicap = TRUE; + si->time_limit = TRUE; + si->fullscreen = FALSE; + + for (i=0; iinput[i].use_joystick = FALSE; + si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i)); + si->input[i].joy.xleft = JOYSTICK_XLEFT; + si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE; + si->input[i].joy.xright = JOYSTICK_XRIGHT; + si->input[i].joy.yupper = JOYSTICK_YUPPER; + si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE; + si->input[i].joy.ylower = JOYSTICK_YLOWER; + si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0); + si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0); + si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED); + si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED); + si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED); + si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED); + si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED); + si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KSYM_UNDEFINED); + } +} + +static void setSetupInfo(struct TokenInfo *token_info, + int token_nr, char *token_value) +{ + int token_type = token_info[token_nr].type; + void *setup_value = token_info[token_nr].value; + + if (token_value == NULL) + return; + + /* set setup field to corresponding token value */ + switch (token_type) + { + case TYPE_BOOLEAN: + case TYPE_SWITCH: + *(boolean *)setup_value = get_string_boolean_value(token_value); + break; + + case TYPE_KEY: + *(Key *)setup_value = getKeyFromX11KeyName(token_value); + break; + + case TYPE_INTEGER: + *(int *)setup_value = get_string_integer_value(token_value); + break; + + case TYPE_STRING: + if (*(char **)setup_value != NULL) + free(*(char **)setup_value); + *(char **)setup_value = getStringCopy(token_value); + break; + + default: + break; + } +} + +static void decodeSetupFileList(struct SetupFileList *setup_file_list) +{ + int i, pnr; + + if (!setup_file_list) + return; + + /* handle global setup values */ + si = setup; + for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++) + setSetupInfo(global_setup_tokens, i, + getTokenValue(setup_file_list, global_setup_tokens[i].text)); + setup = si; + + /* handle player specific setup values */ + for (pnr=0; pnrparent_link || entry2->parent_link) + compare_result = (entry1->parent_link ? -1 : +1); + else if (entry1->sort_priority == entry2->sort_priority) + { + char *name1 = getStringToLower(entry1->name_sorting); + char *name2 = getStringToLower(entry2->name_sorting); + + compare_result = strcmp(name1, name2); + + free(name1); + free(name2); + } + else if (LEVELSORTING(entry1) == LEVELSORTING(entry2)) + compare_result = entry1->sort_priority - entry2->sort_priority; + else + compare_result = LEVELSORTING(entry1) - LEVELSORTING(entry2); + + return compare_result; +} + +static void createParentLevelDirNode(struct LevelDirInfo *node_parent) +{ + struct LevelDirInfo *leveldir_new = newLevelDirInfo(); + + setLevelDirInfoToDefaults(leveldir_new); + + leveldir_new->node_parent = node_parent; + leveldir_new->parent_link = TRUE; + + leveldir_new->name = ".. (parent directory)"; + leveldir_new->name_short = getStringCopy(leveldir_new->name); + leveldir_new->name_sorting = getStringCopy(leveldir_new->name); + + leveldir_new->filename = ".."; + leveldir_new->fullpath = getStringCopy(node_parent->fullpath); + + leveldir_new->sort_priority = node_parent->sort_priority; + leveldir_new->class_desc = getLevelClassDescription(leveldir_new); + + pushLevelDirInfo(&node_parent->node_group, leveldir_new); +} + +static void LoadLevelInfoFromLevelDir(struct LevelDirInfo **node_first, + struct LevelDirInfo *node_parent, + char *level_directory) +{ + DIR *dir; + struct dirent *dir_entry; + boolean valid_entry_found = FALSE; + + if ((dir = opendir(level_directory)) == NULL) + { + Error(ERR_WARN, "cannot read level directory '%s'", level_directory); + return; + } + + while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ + { + struct SetupFileList *setup_file_list = NULL; + struct stat file_status; + char *directory_name = dir_entry->d_name; + char *directory_path = getPath2(level_directory, directory_name); + char *filename = NULL; + + /* skip entries for current and parent directory */ + if (strcmp(directory_name, ".") == 0 || + strcmp(directory_name, "..") == 0) + { + free(directory_path); + continue; + } + + /* find out if directory entry is itself a directory */ + if (stat(directory_path, &file_status) != 0 || /* cannot stat file */ + (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ + { + free(directory_path); + continue; + } + + filename = getPath2(directory_path, LEVELINFO_FILENAME); + setup_file_list = loadSetupFileList(filename); + + if (setup_file_list) + { + struct LevelDirInfo *leveldir_new = newLevelDirInfo(); + int i; + + checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE); + setLevelDirInfoToDefaultsFromParent(leveldir_new, node_parent); + + /* set all structure fields according to the token/value pairs */ + ldi = *leveldir_new; + for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) + setSetupInfo(levelinfo_tokens, i, + getTokenValue(setup_file_list, levelinfo_tokens[i].text)); + *leveldir_new = ldi; + + DrawInitText(leveldir_new->name, 150, FC_YELLOW); + + if (leveldir_new->name_short == NULL) + leveldir_new->name_short = getStringCopy(leveldir_new->name); + + if (leveldir_new->name_sorting == NULL) + leveldir_new->name_sorting = getStringCopy(leveldir_new->name); + + leveldir_new->filename = getStringCopy(directory_name); + + if (node_parent == NULL) /* top level group */ + { + leveldir_new->basepath = level_directory; + leveldir_new->fullpath = leveldir_new->filename; + } + else /* sub level group */ + { + leveldir_new->basepath = node_parent->basepath; + leveldir_new->fullpath = getPath2(node_parent->fullpath, + directory_name); + } + + if (leveldir_new->levels < 1) + leveldir_new->levels = 1; + + leveldir_new->last_level = + leveldir_new->first_level + leveldir_new->levels - 1; + + leveldir_new->user_defined = + (leveldir_new->basepath == options.level_directory ? FALSE : TRUE); + + leveldir_new->color = LEVELCOLOR(leveldir_new); + leveldir_new->class_desc = getLevelClassDescription(leveldir_new); + + leveldir_new->handicap_level = /* set handicap to default value */ + (leveldir_new->user_defined ? + leveldir_new->last_level : + leveldir_new->first_level); + + pushLevelDirInfo(node_first, leveldir_new); + + freeSetupFileList(setup_file_list); + valid_entry_found = TRUE; + + if (leveldir_new->level_group) + { + /* create node to link back to current level directory */ + createParentLevelDirNode(leveldir_new); + + /* step into sub-directory and look for more level series */ + LoadLevelInfoFromLevelDir(&leveldir_new->node_group, + leveldir_new, directory_path); + } + } + else + Error(ERR_WARN, "ignoring level directory '%s'", directory_path); + + free(directory_path); + free(filename); + } + + closedir(dir); + + if (!valid_entry_found) + Error(ERR_WARN, "cannot find any valid level series in directory '%s'", + level_directory); +} + +void LoadLevelInfo() +{ + InitUserLevelDirectory(getLoginName()); + + DrawInitText("Loading level series:", 120, FC_GREEN); + + LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); + LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir("")); + + leveldir_current = getFirstValidLevelSeries(leveldir_first); + + if (leveldir_first == NULL) + Error(ERR_EXIT, "cannot find any valid level series in any directory"); + + sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries); + +#if 0 + dumpLevelDirInfo(leveldir_first, 0); +#endif +} + +static void SaveUserLevelInfo() +{ + char *filename; + FILE *file; + int i; + + filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); + + if (!(file = fopen(filename, MODE_WRITE))) + { + Error(ERR_WARN, "cannot write level info file '%s'", filename); + free(filename); + return; + } + + /* always start with reliable default values */ + setLevelDirInfoToDefaults(&ldi); + + ldi.name = getLoginName(); + ldi.author = getRealName(); + ldi.levels = 100; + ldi.first_level = 1; + ldi.sort_priority = LEVELCLASS_USER_START; + ldi.readonly = FALSE; + + fprintf(file, "%s\n\n", + getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE)); + + for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) + if (i != LEVELINFO_TOKEN_NAME_SHORT && + i != LEVELINFO_TOKEN_NAME_SORTING && + i != LEVELINFO_TOKEN_IMPORTED_FROM) + fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i)); + + fclose(file); + free(filename); + + SetFilePermissions(filename, PERMS_PRIVATE); +} + +void LoadSetup() +{ + char *filename; + struct SetupFileList *setup_file_list = NULL; + + /* always start with reliable default values */ + setSetupInfoToDefaults(&setup); + + filename = getPath2(getSetupDir(), SETUP_FILENAME); + + setup_file_list = loadSetupFileList(filename); + + if (setup_file_list) + { + checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE); + decodeSetupFileList(setup_file_list); + + setup.direct_draw = !setup.double_buffering; + + freeSetupFileList(setup_file_list); + + /* needed to work around problems with fixed length strings */ + if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN) + setup.player_name[MAX_PLAYER_NAME_LEN] = '\0'; + else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN) + { + char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1); + + strcpy(new_name, setup.player_name); + free(setup.player_name); + setup.player_name = new_name; + } + } + else + Error(ERR_WARN, "using default setup values"); + + free(filename); +} + +static char *getSetupLine(struct TokenInfo *token_info, + char *prefix, int token_nr) +{ + int i; + static char entry[MAX_LINE_LEN]; + int token_type = token_info[token_nr].type; + void *setup_value = token_info[token_nr].value; + char *token_text = token_info[token_nr].text; + + /* start with the prefix, token and some spaces to format output line */ + sprintf(entry, "%s%s:", prefix, token_text); + for (i=strlen(entry); ifilename; + FILE *file; + + /* ----------------------------------------------------------------------- */ + /* ~/.rocksndiamonds/levelsetup.conf */ + /* ----------------------------------------------------------------------- */ + + InitUserDataDirectory(); + + filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); + + if (!(file = fopen(filename, MODE_WRITE))) + { + Error(ERR_WARN, "cannot write setup file '%s'", filename); + free(filename); + return; + } + + fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, + LEVELSETUP_COOKIE)); + fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES, + level_subdir)); + + fclose(file); + free(filename); + + SetFilePermissions(filename, PERMS_PRIVATE); +} + +static void checkSeriesInfo() +{ + static char *level_directory = NULL; + DIR *dir; + struct dirent *dir_entry; + + /* check for more levels besides the 'levels' field of 'levelinfo.conf' */ + + level_directory = getPath2((leveldir_current->user_defined ? + getUserLevelDir("") : + options.level_directory), + leveldir_current->fullpath); + + if ((dir = opendir(level_directory)) == NULL) + { + Error(ERR_WARN, "cannot read level directory '%s'", level_directory); + return; + } + + while ((dir_entry = readdir(dir)) != NULL) /* last directory entry */ + { + if (strlen(dir_entry->d_name) > 4 && + dir_entry->d_name[3] == '.' && + strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0) + { + char levelnum_str[4]; + int levelnum_value; + + strncpy(levelnum_str, dir_entry->d_name, 3); + levelnum_str[3] = '\0'; + + levelnum_value = atoi(levelnum_str); + + if (levelnum_value < leveldir_current->first_level) + { + Error(ERR_WARN, "additional level %d found", levelnum_value); + leveldir_current->first_level = levelnum_value; + } + else if (levelnum_value > leveldir_current->last_level) + { + Error(ERR_WARN, "additional level %d found", levelnum_value); + leveldir_current->last_level = levelnum_value; + } + } + } + + closedir(dir); +} + +void LoadLevelSetup_SeriesInfo() +{ + char *filename; + struct SetupFileList *level_setup_list = NULL; + char *level_subdir = leveldir_current->filename; + + /* always start with reliable default values */ + level_nr = leveldir_current->first_level; + + checkSeriesInfo(leveldir_current); + + /* ----------------------------------------------------------------------- */ + /* ~/.rocksndiamonds/levelsetup//levelsetup.conf */ + /* ----------------------------------------------------------------------- */ + + level_subdir = leveldir_current->filename; + + filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); + + if ((level_setup_list = loadSetupFileList(filename))) + { + char *token_value; + + token_value = getTokenValue(level_setup_list, TOKEN_STR_LAST_PLAYED_LEVEL); + + if (token_value) + { + level_nr = atoi(token_value); + + if (level_nr < leveldir_current->first_level) + level_nr = leveldir_current->first_level; + if (level_nr > leveldir_current->last_level) + level_nr = leveldir_current->last_level; + } + + token_value = getTokenValue(level_setup_list, TOKEN_STR_HANDICAP_LEVEL); + + if (token_value) + { + int level_nr = atoi(token_value); + + if (level_nr < leveldir_current->first_level) + level_nr = leveldir_current->first_level; + if (level_nr > leveldir_current->last_level + 1) + level_nr = leveldir_current->last_level; + + if (leveldir_current->user_defined) + level_nr = leveldir_current->last_level; + + leveldir_current->handicap_level = level_nr; + } + + checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE); + + freeSetupFileList(level_setup_list); + } + else + Error(ERR_WARN, "using default setup values"); + + free(filename); +} + +void SaveLevelSetup_SeriesInfo() +{ + char *filename; + char *level_subdir = leveldir_current->filename; + char *level_nr_str = int2str(level_nr, 0); + char *handicap_level_str = int2str(leveldir_current->handicap_level, 0); + FILE *file; + + /* ----------------------------------------------------------------------- */ + /* ~/.rocksndiamonds/levelsetup//levelsetup.conf */ + /* ----------------------------------------------------------------------- */ + + InitLevelSetupDirectory(level_subdir); + + filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); + + if (!(file = fopen(filename, MODE_WRITE))) + { + Error(ERR_WARN, "cannot write setup file '%s'", filename); + free(filename); + return; + } + + fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, + LEVELSETUP_COOKIE)); + fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL, + level_nr_str)); + fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL, + handicap_level_str)); + + fclose(file); + free(filename); + + SetFilePermissions(filename, PERMS_PRIVATE); +} diff --git a/src/libgame/setup.h b/src/libgame/setup.h new file mode 100644 index 00000000..edec4d0a --- /dev/null +++ b/src/libgame/setup.h @@ -0,0 +1,126 @@ +/*********************************************************** +* Artsoft Retro-Game Library * +*----------------------------------------------------------* +* (c) 1994-2002 Artsoft Entertainment * +* Holger Schemel * +* Detmolder Strasse 189 * +* 33604 Bielefeld * +* Germany * +* e-mail: info@artsoft.org * +*----------------------------------------------------------* +* setup.h * +***********************************************************/ + +#ifndef SETUP_H +#define SETUP_H + +#include "system.h" + + +/* sort priorities of level series (also used as level series classes) */ +#define LEVELCLASS_TUTORIAL_START 10 +#define LEVELCLASS_TUTORIAL_END 99 +#define LEVELCLASS_CLASSICS_START 100 +#define LEVELCLASS_CLASSICS_END 199 +#define LEVELCLASS_CONTRIBUTION_START 200 +#define LEVELCLASS_CONTRIBUTION_END 299 +#define LEVELCLASS_USER_START 300 +#define LEVELCLASS_USER_END 399 +#define LEVELCLASS_BD_START 400 +#define LEVELCLASS_BD_END 499 +#define LEVELCLASS_EM_START 500 +#define LEVELCLASS_EM_END 599 +#define LEVELCLASS_SP_START 600 +#define LEVELCLASS_SP_END 699 +#define LEVELCLASS_DX_START 700 +#define LEVELCLASS_DX_END 799 + +#define LEVELCLASS_TUTORIAL LEVELCLASS_TUTORIAL_START +#define LEVELCLASS_CLASSICS LEVELCLASS_CLASSICS_START +#define LEVELCLASS_CONTRIBUTION LEVELCLASS_CONTRIBUTION_START +#define LEVELCLASS_USER LEVELCLASS_USER_START +#define LEVELCLASS_BD LEVELCLASS_BD_START +#define LEVELCLASS_EM LEVELCLASS_EM_START +#define LEVELCLASS_SP LEVELCLASS_SP_START +#define LEVELCLASS_DX LEVELCLASS_DX_START + +#define LEVELCLASS_UNDEFINED 999 + +#define IS_LEVELCLASS_TUTORIAL(p) \ + ((p)->sort_priority >= LEVELCLASS_TUTORIAL_START && \ + (p)->sort_priority <= LEVELCLASS_TUTORIAL_END) +#define IS_LEVELCLASS_CLASSICS(p) \ + ((p)->sort_priority >= LEVELCLASS_CLASSICS_START && \ + (p)->sort_priority <= LEVELCLASS_CLASSICS_END) +#define IS_LEVELCLASS_CONTRIBUTION(p) \ + ((p)->sort_priority >= LEVELCLASS_CONTRIBUTION_START && \ + (p)->sort_priority <= LEVELCLASS_CONTRIBUTION_END) +#define IS_LEVELCLASS_USER(p) \ + ((p)->sort_priority >= LEVELCLASS_USER_START && \ + (p)->sort_priority <= LEVELCLASS_USER_END) +#define IS_LEVELCLASS_BD(p) \ + ((p)->sort_priority >= LEVELCLASS_BD_START && \ + (p)->sort_priority <= LEVELCLASS_BD_END) +#define IS_LEVELCLASS_EM(p) \ + ((p)->sort_priority >= LEVELCLASS_EM_START && \ + (p)->sort_priority <= LEVELCLASS_EM_END) +#define IS_LEVELCLASS_SP(p) \ + ((p)->sort_priority >= LEVELCLASS_SP_START && \ + (p)->sort_priority <= LEVELCLASS_SP_END) +#define IS_LEVELCLASS_DX(p) \ + ((p)->sort_priority >= LEVELCLASS_DX_START && \ + (p)->sort_priority <= LEVELCLASS_DX_END) + +#define LEVELCLASS(n) (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \ + IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \ + IS_LEVELCLASS_CONTRIBUTION(n) ? LEVELCLASS_CONTRIBUTION : \ + IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \ + IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \ + IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \ + IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \ + IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \ + LEVELCLASS_UNDEFINED) + + +char *getLevelFilename(int); +char *getTapeFilename(int); +char *getScoreFilename(int); +void InitTapeDirectory(char *); +void InitScoreDirectory(char *); +void InitUserLevelDirectory(char *); +void InitLevelSetupDirectory(char *); + +void ReadChunk_VERS(FILE *, int *, int *); +void WriteChunk_VERS(FILE *, int, int); + +struct LevelDirInfo *newLevelDirInfo(); +void pushLevelDirInfo(struct LevelDirInfo **, struct LevelDirInfo *); +int numLevelDirInfo(struct LevelDirInfo *); +boolean validLevelSeries(struct LevelDirInfo *); +struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *); +struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *); +int numLevelDirInfoInGroup(struct LevelDirInfo *); +int posLevelDirInfo(struct LevelDirInfo *); +struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *, int); +struct LevelDirInfo *getLevelDirInfoFromFilename(char *); +void dumpLevelDirInfo(struct LevelDirInfo *, int); +void sortLevelDirInfo(struct LevelDirInfo **, + int (*compare_function)(const void *, const void *)); + +char *getUserDataDir(void); +char *getSetupDir(void); +void createDirectory(char *, char *, int); +void InitUserDataDirectory(void); +void SetFilePermissions(char *, int); +int getFileVersionFromCookieString(const char *); +boolean checkCookieString(const char *, const char *); + +void LoadLevelInfo(void); +void LoadSetup(void); +void SaveSetup(void); +void LoadLevelSetup_LastSeries(void); +void SaveLevelSetup_LastSeries(void); +void LoadLevelSetup_SeriesInfo(void); +void SaveLevelSetup_SeriesInfo(void); + +#endif /* MISC_H */ diff --git a/src/libgame/system.c b/src/libgame/system.c index 3d00d8e8..5604ad21 100644 --- a/src/libgame/system.c +++ b/src/libgame/system.c @@ -22,6 +22,7 @@ #include "system.h" #include "sound.h" +#include "setup.h" #include "misc.h" @@ -34,26 +35,29 @@ struct OptionInfo options; struct VideoSystemInfo video; struct AudioSystemInfo audio; struct GfxInfo gfx; +struct JoystickInfo joystick; +struct SetupInfo setup; struct LevelDirInfo *leveldir_first = NULL; struct LevelDirInfo *leveldir_current = NULL; +int level_nr; -Display *display = NULL; -Visual *visual = NULL; -int screen = 0; -Colormap cmap = None; +Display *display = NULL; +Visual *visual = NULL; +int screen = 0; +Colormap cmap = None; -DrawWindow *window = NULL; -DrawBuffer *backbuffer = NULL; -DrawBuffer *drawto = NULL; +DrawWindow *window = NULL; +DrawBuffer *backbuffer = NULL; +DrawBuffer *drawto = NULL; -int button_status = MB_NOT_PRESSED; -boolean motion_status = FALSE; +int button_status = MB_NOT_PRESSED; +boolean motion_status = FALSE; -int redraw_mask = REDRAW_NONE; -int redraw_tiles = 0; +int redraw_mask = REDRAW_NONE; +int redraw_tiles = 0; -int FrameCounter = 0; +int FrameCounter = 0; /* ========================================================================= */ diff --git a/src/libgame/system.h b/src/libgame/system.h index bf0f58b1..0cf978df 100644 --- a/src/libgame/system.h +++ b/src/libgame/system.h @@ -40,7 +40,24 @@ #define FULLSCREEN_NOT_AVAILABLE FALSE #define FULLSCREEN_AVAILABLE TRUE -/* values for button_status */ +/* default input keys */ +#define DEFAULT_KEY_LEFT KSYM_Left +#define DEFAULT_KEY_RIGHT KSYM_Right +#define DEFAULT_KEY_UP KSYM_Up +#define DEFAULT_KEY_DOWN KSYM_Down +#define DEFAULT_KEY_SNAP KSYM_Shift_L +#define DEFAULT_KEY_BOMB KSYM_Shift_R +#define DEFAULT_KEY_OKAY KSYM_Return +#define DEFAULT_KEY_CANCEL KSYM_Escape + +/* values for move directions */ +#define MV_NO_MOVING 0 +#define MV_LEFT (1 << 0) +#define MV_RIGHT (1 << 1) +#define MV_UP (1 << 2) +#define MV_DOWN (1 << 3) + +/* values for button status */ #define MB_NOT_PRESSED FALSE #define MB_NOT_RELEASED TRUE #define MB_RELEASED FALSE @@ -77,6 +94,11 @@ #define REDRAW_FPS (1 << 11) #define REDRAWTILES_THRESHOLD (SCR_FIELDX * SCR_FIELDY / 2) +/* maximum number of parallel players supported by libgame functions */ +#define MAX_PLAYERS 4 + +/* maximum allowed length of player name */ +#define MAX_PLAYER_NAME_LEN 10 /* default name for empty highscore entry */ #define EMPTY_PLAYER_NAME "no name" @@ -206,6 +228,63 @@ struct GfxInfo int vxsize, vysize; }; +struct JoystickInfo +{ + int status; + int fd[MAX_PLAYERS]; /* file descriptor of player's joystick */ +}; + +struct SetupJoystickInfo +{ + char *device_name; /* device name of player's joystick */ + + int xleft, xmiddle, xright; + int yupper, ymiddle, ylower; + int snap; + int bomb; +}; + +struct SetupKeyboardInfo +{ + Key left; + Key right; + Key up; + Key down; + Key snap; + Key bomb; +}; + +struct SetupInputInfo +{ + boolean use_joystick; + struct SetupJoystickInfo joy; + struct SetupKeyboardInfo key; +}; + +struct SetupInfo +{ + char *player_name; + + boolean sound; + boolean sound_loops; + boolean sound_music; + boolean sound_simple; + boolean toons; + boolean double_buffering; + boolean direct_draw; /* !double_buffering (redundant!) */ + boolean scroll_delay; + boolean soft_scrolling; + boolean fading; + boolean autorecord; + boolean quick_doors; + boolean team_mode; + boolean handicap; + boolean time_limit; + boolean fullscreen; + + struct SetupInputInfo input[MAX_PLAYERS]; +}; + struct LevelDirInfo { char *filename; /* level series single directory name */ @@ -245,26 +324,29 @@ extern struct OptionInfo options; extern struct VideoSystemInfo video; extern struct AudioSystemInfo audio; extern struct GfxInfo gfx; +extern struct JoystickInfo joystick; +extern struct SetupInfo setup; extern struct LevelDirInfo *leveldir_first; extern struct LevelDirInfo *leveldir_current; +extern int level_nr; -extern Display *display; -extern Visual *visual; -extern int screen; -extern Colormap cmap; +extern Display *display; +extern Visual *visual; +extern int screen; +extern Colormap cmap; -extern DrawWindow *window; -extern DrawBuffer *backbuffer; -extern DrawBuffer *drawto; +extern DrawWindow *window; +extern DrawBuffer *backbuffer; +extern DrawBuffer *drawto; -extern int button_status; -extern boolean motion_status; +extern int button_status; +extern boolean motion_status; -extern int redraw_mask; -extern int redraw_tiles; +extern int redraw_mask; +extern int redraw_tiles; -extern int FrameCounter; +extern int FrameCounter; /* function definitions */ diff --git a/src/libgame/types.h b/src/libgame/types.h index 56a6d007..34bc8e4a 100644 --- a/src/libgame/types.h +++ b/src/libgame/types.h @@ -14,6 +14,10 @@ #ifndef TYPES_H #define TYPES_H +#include +#include +#include + typedef unsigned char boolean; typedef unsigned char byte; diff --git a/src/main.c b/src/main.c index de38f3f0..528741b9 100644 --- a/src/main.c +++ b/src/main.c @@ -17,7 +17,6 @@ #include "init.h" #include "game.h" #include "events.h" -#include "joystick.h" GC tile_clip_gc; Bitmap *pix[NUM_BITMAPS]; @@ -25,22 +24,12 @@ Pixmap tile_clipmask[NUM_TILES]; DrawBuffer *fieldbuffer; DrawBuffer *drawto_field; -int joystick_device = 0; -char *joystick_device_name[MAX_PLAYERS] = -{ - DEV_JOYSTICK_0, - DEV_JOYSTICK_1, - DEV_JOYSTICK_2, - DEV_JOYSTICK_3 -}; - int game_status = MAINMENU; boolean level_editor_test_game = FALSE; boolean network_playing = FALSE; int key_joystick_mapping = 0; int global_joystick_status = JOYSTICK_STATUS; -int joystick_status = JOYSTICK_STATUS; boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; int redraw_x1 = 0, redraw_y1 = 0; @@ -62,7 +51,6 @@ short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; unsigned long Elementeigenschaften1[MAX_ELEMENTS]; unsigned long Elementeigenschaften2[MAX_ELEMENTS]; -int level_nr; int lev_fieldx,lev_fieldy, scroll_x,scroll_y; int FX = SX, FY = SY, ScrollStepSize; diff --git a/src/main.h b/src/main.h index 86377ccf..0768ed90 100644 --- a/src/main.h +++ b/src/main.h @@ -49,8 +49,6 @@ #define MAX_LEV_FIELDX 128 #define MAX_LEV_FIELDY 128 -#define MAX_PLAYERS 4 - #define SCREENX(a) ((a) - scroll_x) #define SCREENY(a) ((a) - scroll_y) #define LEVELX(a) ((a) + scroll_x) @@ -185,7 +183,6 @@ #define NUM_BITMAPS 12 /* boundaries of arrays etc. */ -#define MAX_PLAYER_NAME_LEN 10 #define MAX_LEVEL_NAME_LEN 32 #define MAX_LEVEL_AUTHOR_LEN 32 #define MAX_TAPELEN (1000 * 50) /* max. time * framerate */ @@ -213,56 +210,6 @@ struct HiScore int Score; }; -struct SetupJoystickInfo -{ - char *device_name; - int xleft, xmiddle, xright; - int yupper, ymiddle, ylower; - int snap; - int bomb; -}; - -struct SetupKeyboardInfo -{ - Key left; - Key right; - Key up; - Key down; - Key snap; - Key bomb; -}; - -struct SetupInputInfo -{ - boolean use_joystick; - struct SetupJoystickInfo joy; - struct SetupKeyboardInfo key; -}; - -struct SetupInfo -{ - char *player_name; - - boolean sound; - boolean sound_loops; - boolean sound_music; - boolean sound_simple; - boolean toons; - boolean double_buffering; - boolean direct_draw; /* !double_buffering (redundant!) */ - boolean scroll_delay; - boolean soft_scrolling; - boolean fading; - boolean autorecord; - boolean quick_doors; - boolean team_mode; - boolean handicap; - boolean time_limit; - boolean fullscreen; - - struct SetupInputInfo input[MAX_PLAYERS]; -}; - struct PlayerInfo { boolean present; /* player present in level playfield */ @@ -278,8 +225,6 @@ struct PlayerInfo byte programmed_action; /* action forced by game itself (like moving through doors); overrides other actions */ - int joystick_fd; /* file descriptor of player's joystick */ - int jx,jy, last_jx,last_jy; int MovDir, MovPos, GfxPos; int Frame; @@ -404,7 +349,7 @@ extern boolean level_editor_test_game; extern boolean network_playing; extern int key_joystick_mapping; -extern int global_joystick_status, joystick_status; +extern int global_joystick_status; extern boolean redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE]; extern int redraw_x1, redraw_y1; @@ -426,7 +371,6 @@ extern short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern unsigned long Elementeigenschaften1[MAX_ELEMENTS]; extern unsigned long Elementeigenschaften2[MAX_ELEMENTS]; -extern int level_nr; extern int lev_fieldx,lev_fieldy, scroll_x,scroll_y; extern int FX,FY, ScrollStepSize; @@ -450,8 +394,6 @@ extern struct LevelInfo level; extern struct PlayerInfo stored_player[], *local_player; extern struct HiScore highscore[]; extern struct TapeInfo tape; -extern struct JoystickInfo joystick[]; -extern struct SetupInfo setup; extern struct GameInfo game; extern struct GlobalInfo global; @@ -1498,23 +1440,6 @@ extern int num_element_info; #define NUM_SOUNDS 55 -/* default input keys */ -#define DEFAULT_KEY_LEFT KSYM_Left -#define DEFAULT_KEY_RIGHT KSYM_Right -#define DEFAULT_KEY_UP KSYM_Up -#define DEFAULT_KEY_DOWN KSYM_Down -#define DEFAULT_KEY_SNAP KSYM_Shift_L -#define DEFAULT_KEY_BOMB KSYM_Shift_R -#define DEFAULT_KEY_OKAY KSYM_Return -#define DEFAULT_KEY_CANCEL KSYM_Escape - -/* directions for moving */ -#define MV_NO_MOVING 0 -#define MV_LEFT (1 << 0) -#define MV_RIGHT (1 << 1) -#define MV_UP (1 << 2) -#define MV_DOWN (1 << 3) - /* values for game_status */ #define EXITGAME 0 #define MAINMENU 1 diff --git a/src/screens.c b/src/screens.c index 8a6a486d..5c317af0 100644 --- a/src/screens.c +++ b/src/screens.c @@ -20,7 +20,6 @@ #include "editor.h" #include "files.h" #include "tape.h" -#include "joystick.h" #include "cartoons.h" #include "network.h" #include "init.h" @@ -94,6 +93,7 @@ void DrawMainMenu() UnmapAllGadgets(); FadeSounds(); KeyboardAutoRepeatOn(); + ActivateJoystickIfAvailable(); /* needed if last screen was the playing screen, invoked from level editor */ if (level_editor_test_game) @@ -1635,6 +1635,7 @@ void DrawSetupInputScreen() DrawText(SX+32, SY+3*32, "Device:", FS_BIG, FC_GREEN); DrawText(SX+32, SY+15*32, "Exit", FS_BIG, FC_GREEN); + DeactivateJoystickForCalibration(); DrawTextFCentered(SYSIZE - 20, FC_BLUE, "Joysticks deactivated on this screen"); @@ -1660,7 +1661,8 @@ static void setJoystickDeviceToNr(char *device_name, int device_nr) device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10); } else - strncpy(device_name, joystick_device_name[device_nr], strlen(device_name)); + strncpy(device_name, getDeviceNameFromJoystickNr(device_nr), + strlen(device_name)); } static void drawPlayerSetupInputInfo(int player_nr) @@ -2052,14 +2054,14 @@ void CalibrateJoystick(int player_nr) int calibration_step = 1; #endif - int joystick_fd = stored_player[player_nr].joystick_fd; + int joystick_fd = joystick.fd[player_nr]; int x, y, last_x, last_y, xpos = 8, ypos = 3; boolean check[3][3]; int check_remaining; int joy_value; int result = -1; - if (joystick_status == JOYSTICK_OFF || + if (joystick.status == JOYSTICK_NOT_AVAILABLE || joystick_fd < 0 || !setup.input[player_nr].use_joystick) goto error_out; @@ -2153,7 +2155,7 @@ void CalibrateJoystick(int player_nr) #else if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl)) { - joystick_status = JOYSTICK_OFF; + joystick.status = JOYSTICK_NOT_AVAILABLE; goto error_out; } #endif @@ -2192,7 +2194,7 @@ void CalibrateJoystick(int player_nr) } else if (calibrate_joystick(joystick_fd) != 0) { - joystick_status = JOYSTICK_OFF; + joystick.status = JOYSTICK_NOT_AVAILABLE; goto error_out; } diff --git a/src/tools.c b/src/tools.c index ca2bbd5d..8a5f48e0 100644 --- a/src/tools.c +++ b/src/tools.c @@ -11,18 +11,19 @@ * tools.c * ***********************************************************/ +#if 0 #include #if defined(PLATFORM_FREEBSD) #include #endif +#endif #include "libgame/libgame.h" #include "tools.h" #include "game.h" #include "events.h" -#include "joystick.h" #include "cartoons.h" #include "network.h" #include "tape.h"