From 6a5685ceb73a6e3375ff32c0d6ff383eac9a2a9d Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Tue, 5 Oct 1999 02:10:36 +0200 Subject: [PATCH] rnd-19991005-1-src --- src/files.c | 141 +++++++++++++++--------- src/files.h | 2 - src/main.c | 2 +- src/main.h | 14 ++- src/misc.c | 111 ++++++++++++++++++- src/misc.h | 8 +- src/network.c | 2 +- src/screens.c | 294 +++++++++++++++++++++++++++++++++++++------------- 8 files changed, 436 insertions(+), 138 deletions(-) diff --git a/src/files.c b/src/files.c index b3d280c6..e0d444b1 100644 --- a/src/files.c +++ b/src/files.c @@ -287,7 +287,7 @@ static char *getLevelFilename(int nr) filename = getPath3((leveldir_current->user_defined ? getUserLevelDir("") : options.level_directory), - leveldir_current->filename, + leveldir_current->fullpath, basename); return filename; @@ -1067,7 +1067,8 @@ void SaveScore(int level_nr) #define LEVELINFO_TOKEN_LEVELS 34 #define LEVELINFO_TOKEN_FIRST_LEVEL 35 #define LEVELINFO_TOKEN_SORT_PRIORITY 36 -#define LEVELINFO_TOKEN_READONLY 37 +#define LEVELINFO_TOKEN_LEVEL_GROUP 37 +#define LEVELINFO_TOKEN_READONLY 38 #define FIRST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_PLAYER_NAME #define LAST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_TIME_LIMIT @@ -1142,6 +1143,7 @@ static struct { 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" } }; @@ -1403,6 +1405,8 @@ static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, 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; @@ -1412,11 +1416,19 @@ static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi) ldi->first_level = 0; ldi->last_level = 0; ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ - ldi->readonly = TRUE; + 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 setSetupInfoToDefaults(struct SetupInfo *si) @@ -1529,31 +1541,15 @@ static void decodeSetupFileList(struct SetupFileList *setup_file_list) } } -struct LevelDirInfo *getLevelDirInfoFromLevelDirName(char *level_dir_name) -{ - struct LevelDirInfo *leveldir_node = leveldir_first; - - if (level_dir_name == NULL) - return NULL; - - while (leveldir_node) - { - if (strcmp(level_dir_name, leveldir_node->name) == 0) - return leveldir_node; /* return success value */ - - leveldir_node = leveldir_node->next; - } - - return NULL; -} - static int compareLevelDirInfoEntries(const void *object1, const void *object2) { const struct LevelDirInfo *entry1 = *((struct LevelDirInfo **)object1); const struct LevelDirInfo *entry2 = *((struct LevelDirInfo **)object2); int compare_result; - if (entry1->sort_priority == entry2->sort_priority) + if (entry1->parent_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); @@ -1571,7 +1567,31 @@ static int compareLevelDirInfoEntries(const void *object1, const void *object2) return compare_result; } -static void LoadLevelInfoFromLevelDir(char *level_directory) +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; @@ -1585,26 +1605,29 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ { + struct SetupFileList *setup_file_list = NULL; struct stat file_status; - char *directory = NULL; + char *directory_name = dir_entry->d_name; + char *directory_path = getPath2(level_directory, directory_name); char *filename = NULL; - struct SetupFileList *setup_file_list = NULL; /* skip entries for current and parent directory */ - if (strcmp(dir_entry->d_name, ".") == 0 || - strcmp(dir_entry->d_name, "..") == 0) + if (strcmp(directory_name, ".") == 0 || + strcmp(directory_name, "..") == 0) + { + free(directory_path); continue; + } /* find out if directory entry is itself a directory */ - directory = getPath2(level_directory, dir_entry->d_name); - if (stat(directory, &file_status) != 0 || /* cannot stat file */ + if (stat(directory_path, &file_status) != 0 || /* cannot stat file */ (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */ { - free(directory); + free(directory_path); continue; } - filename = getPath2(directory, LEVELINFO_FILENAME); + filename = getPath2(directory_path, LEVELINFO_FILENAME); setup_file_list = loadSetupFileList(filename); if (setup_file_list) @@ -1615,6 +1638,9 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE); setLevelDirInfoToDefaults(leveldir_new); + leveldir_new->node_parent = 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)); @@ -1628,7 +1654,19 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) if (leveldir_new->name_sorting == NULL) leveldir_new->name_sorting = getStringCopy(leveldir_new->name); - leveldir_new->filename = getStringCopy(dir_entry->d_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; @@ -1637,7 +1675,8 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) leveldir_new->first_level + leveldir_new->levels - 1; leveldir_new->user_defined = - (level_directory == options.level_directory ? FALSE : TRUE); + (leveldir_new->basepath == options.level_directory ? FALSE : TRUE); + leveldir_new->color = LEVELCOLOR(leveldir_new); leveldir_new->class_desc = getLevelClassDescription(leveldir_new); @@ -1646,15 +1685,25 @@ static void LoadLevelInfoFromLevelDir(char *level_directory) leveldir_new->last_level : leveldir_new->first_level); - pushLevelDirInfo(leveldir_new); /* add new LevelDirInfo to list */ + 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); + Error(ERR_WARN, "ignoring level directory '%s'", directory_path); - free(directory); + free(directory_path); free(filename); } @@ -1671,22 +1720,18 @@ void LoadLevelInfo() DrawInitText("Loading level series:", 120, FC_GREEN); - LoadLevelInfoFromLevelDir(options.level_directory); - LoadLevelInfoFromLevelDir(getUserLevelDir("")); + LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); + LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir("")); - num_leveldirs = numLevelDirInfo(leveldir_first); - leveldir_current = leveldir_first; + leveldir_current = getFirstValidLevelSeries(leveldir_first); - if (num_leveldirs == 0) + if (leveldir_first == NULL) Error(ERR_EXIT, "cannot find any valid level series in any directory"); + sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries); + #if 0 - if (num_leveldirs > 1) - qsort(leveldir, num_leveldirs, sizeof(struct LevelDirInfo), - compareLevelDirInfoEntries); -#else - if (num_leveldirs > 1) - sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries); + dumpLevelDirInfo(leveldir_first, 0); #endif } @@ -1902,7 +1947,7 @@ void LoadLevelSetup_LastSeries() char *last_level_series = getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES); - leveldir_current = getLevelDirInfoFromLevelDirName(last_level_series); + leveldir_current = getLevelDirInfoFromFilename(last_level_series); if (leveldir_current == NULL) leveldir_current = leveldir_first; diff --git a/src/files.h b/src/files.h index cc094458..35fa3f10 100644 --- a/src/files.h +++ b/src/files.h @@ -25,8 +25,6 @@ void SaveTape(int); void LoadScore(int); void SaveScore(int); -struct LevelDirInfo *getLevelDirInfoFromLevelDirName(char *); - void LoadLevelInfo(void); void LoadSetup(void); void SaveSetup(void); diff --git a/src/main.c b/src/main.c index 3182b47d..78ce1be2 100644 --- a/src/main.c +++ b/src/main.c @@ -84,7 +84,7 @@ short AmoebaCnt[MAX_NUM_AMOEBA], AmoebaCnt2[MAX_NUM_AMOEBA]; unsigned long Elementeigenschaften1[MAX_ELEMENTS]; unsigned long Elementeigenschaften2[MAX_ELEMENTS]; -int level_nr, num_leveldirs; +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 0ec85dcb..9a58655c 100644 --- a/src/main.h +++ b/src/main.h @@ -384,7 +384,9 @@ struct LevelInfo struct LevelDirInfo { - char *filename; /* level series sub-directory inside level directory */ + char *filename; /* level series single directory name */ + char *fullpath; /* complete path relative to level directory */ + char *basepath; /* absolute base path of level directory */ char *name; /* level series name, as displayed on main screen */ char *name_short; /* optional short name for level selection screen */ char *name_sorting; /* optional sorting name for correct level sorting */ @@ -394,13 +396,19 @@ struct LevelDirInfo int first_level; /* first level number (to allow start with 0 or 1) */ int last_level; /* last level number (automatically calculated) */ int sort_priority; /* sort levels by 'sort_priority' and then by name */ + boolean level_group; /* directory contains more level series directories */ + boolean parent_link; /* entry links back to parent directory */ boolean user_defined; /* user defined levels are stored in home directory */ boolean readonly; /* readonly levels can not be changed with editor */ int color; /* color to use on selection screen for this level */ char *class_desc; /* description of level series class */ int handicap_level; /* number of the lowest unsolved level */ + int cl_first; /* internal control field for "choose level" screen */ + int cl_cursor; /* internal control field for "choose level" screen */ - struct LevelDirInfo *next; + struct LevelDirInfo *node_parent; /* parent level directory info */ + struct LevelDirInfo *node_group; /* level group sub-directory info */ + struct LevelDirInfo *next; /* next level series structure node */ }; struct TapeInfo @@ -496,7 +504,7 @@ extern short AmoebaCnt[MAX_NUM_AMOEBA], AmoebaCnt2[MAX_NUM_AMOEBA]; extern unsigned long Elementeigenschaften1[MAX_ELEMENTS]; extern unsigned long Elementeigenschaften2[MAX_ELEMENTS]; -extern int level_nr, num_leveldirs; +extern int level_nr; extern int lev_fieldx,lev_fieldy, scroll_x,scroll_y; extern int FX,FY, ScrollStepSize; diff --git a/src/misc.c b/src/misc.c index e60067ca..40bfad4b 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1076,10 +1076,11 @@ struct LevelDirInfo *newLevelDirInfo() return checked_calloc(sizeof(struct LevelDirInfo)); } -void pushLevelDirInfo(struct LevelDirInfo *node) +void pushLevelDirInfo(struct LevelDirInfo **node_first, + struct LevelDirInfo *node_new) { - node->next = leveldir_first; - leveldir_first = node; + node_new->next = *node_first; + *node_first = node_new; } int numLevelDirInfo(struct LevelDirInfo *node) @@ -1095,9 +1096,47 @@ int numLevelDirInfo(struct LevelDirInfo *node) 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) /* start with first level directory entry */ + return getFirstValidLevelSeries(leveldir_first); + 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 = leveldir_first; + struct LevelDirInfo *node_cmp = getLevelDirInfoFirstGroupEntry(node); int pos = 0; while (node_cmp) @@ -1129,6 +1168,58 @@ struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *node, int pos) 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 *)) { @@ -1137,7 +1228,7 @@ void sortLevelDirInfo(struct LevelDirInfo **node_first, struct LevelDirInfo *node = *node_first; int i = 0; - if (num_nodes < 2) /* a list with only one element is always sorted... */ + if (num_nodes == 0) return; /* allocate array for sorting structure pointers */ @@ -1165,6 +1256,16 @@ void sortLevelDirInfo(struct LevelDirInfo **node_first, *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; + } } diff --git a/src/misc.h b/src/misc.h index 591ca06b..d2749225 100644 --- a/src/misc.h +++ b/src/misc.h @@ -79,10 +79,16 @@ int getJoySymbolFromJoyName(char *); int getJoystickNrFromDeviceName(char *); struct LevelDirInfo *newLevelDirInfo(); -void pushLevelDirInfo(struct LevelDirInfo *); +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 *)); diff --git a/src/network.c b/src/network.c index b3b8eca2..1c593270 100644 --- a/src/network.c +++ b/src/network.c @@ -424,7 +424,7 @@ static void Handle_OP_START_PLAYING() (buffer[6] << 24) | (buffer[7] << 16) | (buffer[8] << 8) | (buffer[9]); new_leveldir_name = (char *)&buffer[10]; - new_leveldir = getLevelDirInfoFromLevelDirName(new_leveldir_name); + new_leveldir = getLevelDirInfoFromFilename(new_leveldir_name); if (new_leveldir == NULL) { Error(ERR_WARN, "no such level directory: '%s'", new_leveldir_name); diff --git a/src/screens.c b/src/screens.c index 4839ab39..abe7925a 100644 --- a/src/screens.c +++ b/src/screens.c @@ -69,6 +69,7 @@ void DrawHeadline() void DrawMainMenu() { + static struct LevelDirInfo *leveldir_last_valid = NULL; int i; char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:"); @@ -90,7 +91,14 @@ void DrawMainMenu() /* map gadgets for main menu screen */ MapTapeButtons(); - /* level_nr may have set to value over handicap with level editor */ + /* leveldir_current may be invalid (level group, parent link) */ + if (!validLevelSeries(leveldir_current)) + leveldir_current = getFirstValidLevelSeries(leveldir_last_valid); + + /* store valid level series information */ + leveldir_last_valid = leveldir_current; + + /* level_nr may have been set to value over handicap with level editor */ if (setup.handicap && level_nr > leveldir_current->handicap_level) level_nr = leveldir_current->handicap_level; @@ -157,6 +165,35 @@ void DrawMainMenu() } +static void gotoTopLevelDir() +{ + /* move upwards to top level directory */ + while (leveldir_current->node_parent) + { + /* write a "path" into level tree for easy navigation to last level */ + if (leveldir_current->node_parent->node_group->cl_first == -1) + { + int num_leveldirs = numLevelDirInfoInGroup(leveldir_current); + int leveldir_pos = posLevelDirInfo(leveldir_current); + int num_page_entries; + int cl_first, cl_cursor; + + if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN) + num_page_entries = num_leveldirs; + else + num_page_entries = MAX_LEVEL_SERIES_ON_SCREEN - 1; + + cl_first = MAX(0, leveldir_pos - num_page_entries + 1); + cl_cursor = leveldir_pos - cl_first + 3; + + leveldir_current->node_parent->node_group->cl_first = cl_first; + leveldir_current->node_parent->node_group->cl_cursor = cl_cursor; + } + + leveldir_current = leveldir_current->node_parent; + } +} + void HandleMainMenu(int mx, int my, int dx, int dy, int button) { static int choice = 3; @@ -260,11 +297,14 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) } else if (y == 4) { - if (num_leveldirs) + if (leveldir_first) { game_status = CHOOSELEVEL; SaveLevelSetup_LastSeries(); SaveLevelSetup_SeriesInfo(); + + gotoTopLevelDir(); + DrawChooseLevel(); } } @@ -824,6 +864,33 @@ void HandleTypeName(int newxpos, KeySym key) BackToFront(); } +static void drawCursorExt(int ypos, int color, int graphic) +{ + static int cursor_array[SCR_FIELDY]; + + if (graphic) + cursor_array[ypos] = graphic; + + graphic = cursor_array[ypos]; + + if (color == FC_RED) + graphic = (graphic == GFX_ARROW_BLUE_LEFT ? GFX_ARROW_RED_LEFT : + graphic == GFX_ARROW_BLUE_RIGHT ? GFX_ARROW_RED_RIGHT : + GFX_KUGEL_ROT); + + DrawGraphic(0, ypos, graphic); +} + +static void initCursor(int ypos, int graphic) +{ + drawCursorExt(ypos, FC_BLUE, graphic); +} + +static void drawCursor(int ypos, int color) +{ + drawCursorExt(ypos, color, 0); +} + void DrawChooseLevel() { UnmapAllGadgets(); @@ -842,7 +909,7 @@ static void AdjustChooseLevelScrollbar(int id, int first_entry) struct GadgetInfo *gi = screen_gadget[id]; int items_max, items_visible, item_position; - items_max = num_leveldirs; + items_max = numLevelDirInfoInGroup(leveldir_current); items_visible = MAX_LEVEL_SERIES_ON_SCREEN - 1; item_position = first_entry; @@ -858,6 +925,7 @@ static void drawChooseLevelList(int first_entry, int num_page_entries) int i; char buffer[SCR_FIELDX * 2]; int max_buffer_len = (SCR_FIELDX - 2) * 2; + int num_leveldirs = numLevelDirInfoInGroup(leveldir_current); XFillRectangle(display, backbuffer, gc, SX, SY, SXSIZE - 32, SYSIZE); redraw_mask |= REDRAW_FIELD; @@ -866,16 +934,24 @@ static void drawChooseLevelList(int first_entry, int num_page_entries) for(i=0; iname , max_buffer_len); + node_first = getLevelDirInfoFirstGroupEntry(leveldir_current); + node = getLevelDirInfoFromPos(node_first, leveldir_pos); + + strncpy(buffer, node->name , max_buffer_len); buffer[max_buffer_len] = '\0'; - DrawText(SX + 32, SY + (i + 2) * 32, buffer, FS_MEDIUM, - leveldir_node->color); - DrawGraphic(0, i + 2, GFX_KUGEL_BLAU); + DrawText(SX + 32, SY + ypos * 32, buffer, FS_MEDIUM, node->color); + + if (node->parent_link) + initCursor(ypos, GFX_ARROW_BLUE_LEFT); + else if (node->level_group) + initCursor(ypos, GFX_ARROW_BLUE_RIGHT); + else + initCursor(ypos, GFX_KUGEL_BLAU); } if (first_entry > 0) @@ -887,16 +963,21 @@ static void drawChooseLevelList(int first_entry, int num_page_entries) static void drawChooseLevelInfo(int leveldir_pos) { - struct LevelDirInfo *leveldir_node; + struct LevelDirInfo *node, *node_first; int x, last_redraw_mask = redraw_mask; - leveldir_node = getLevelDirInfoFromPos(leveldir_first, leveldir_pos); + node_first = getLevelDirInfoFirstGroupEntry(leveldir_current); + node = getLevelDirInfoFromPos(node_first, leveldir_pos); XFillRectangle(display, drawto, gc, SX + 32, SY + 32, SXSIZE - 64, 32); - DrawTextFCentered(40, FC_RED, "%3d levels (%s)", - leveldir_node->levels, - leveldir_node->class_desc); + if (node->parent_link) + DrawTextFCentered(40, FC_RED, "leave group \"%s\"", node->class_desc); + else if (node->level_group) + DrawTextFCentered(40, FC_RED, "enter group \"%s\"", node->class_desc); + else + DrawTextFCentered(40, FC_RED, "%3d levels (%s)", + node->levels, node->class_desc); /* let BackToFront() redraw only what is needed */ redraw_mask = last_redraw_mask | REDRAW_TILES; @@ -906,12 +987,11 @@ static void drawChooseLevelInfo(int leveldir_pos) void HandleChooseLevel(int mx, int my, int dx, int dy, int button) { - static int choice = 3; - static int first_entry = -1; static unsigned long choose_delay = 0; static int redraw = TRUE; int x = (mx + 32 - SX) / 32, y = (my + 32 - SY) / 32; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); + int num_leveldirs = numLevelDirInfoInGroup(leveldir_current); int num_page_entries; if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN) @@ -923,24 +1003,27 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button) { int leveldir_pos = posLevelDirInfo(leveldir_current); - if (first_entry == -1) + if (leveldir_current->cl_first == -1) { - first_entry = MAX(0, leveldir_pos - num_page_entries + 1); - choice = leveldir_pos - first_entry + 3; - AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, first_entry); + leveldir_current->cl_first = MAX(0, leveldir_pos - num_page_entries + 1); + leveldir_current->cl_cursor = + leveldir_pos - leveldir_current->cl_first + 3; } - if (dx == 1) /* 'first_entry' is set by scrollbar position */ - first_entry = dy; + if (dx == 999) /* first entry is set by scrollbar position */ + leveldir_current->cl_first = dy; + else + AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, + leveldir_current->cl_first); - drawChooseLevelList(first_entry, num_page_entries); + drawChooseLevelList(leveldir_current->cl_first, num_page_entries); drawChooseLevelInfo(leveldir_pos); redraw = TRUE; } if (redraw) { - DrawGraphic(0, choice - 1, GFX_KUGEL_ROT); + drawCursor(leveldir_current->cl_cursor - 1, FC_RED); redraw = FALSE; } @@ -952,7 +1035,7 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button) if (dy) { x = 1; - y = choice + dy; + y = leveldir_current->cl_cursor + dy; } else x = y = 0; /* no action */ @@ -968,33 +1051,37 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button) if (x == 1 && y == 2) { - if (first_entry > 0 && + if (leveldir_current->cl_first > 0 && (dy || DelayReached(&choose_delay, GADGET_FRAME_DELAY))) { - first_entry -= step; - if (first_entry < 0) - first_entry = 0; - - drawChooseLevelList(first_entry, num_page_entries); - drawChooseLevelInfo(first_entry + choice - 3); - AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, first_entry); - DrawGraphic(0, choice - 1, GFX_KUGEL_ROT); + leveldir_current->cl_first -= step; + if (leveldir_current->cl_first < 0) + leveldir_current->cl_first = 0; + + drawChooseLevelList(leveldir_current->cl_first, num_page_entries); + drawChooseLevelInfo(leveldir_current->cl_first + + leveldir_current->cl_cursor - 3); + drawCursor(leveldir_current->cl_cursor - 1, FC_RED); + AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, + leveldir_current->cl_first); return; } } else if (x == 1 && y > num_page_entries + 2) { - if (first_entry + num_page_entries < num_leveldirs && + if (leveldir_current->cl_first + num_page_entries < num_leveldirs && (dy || DelayReached(&choose_delay, GADGET_FRAME_DELAY))) { - first_entry += step; - if (first_entry + num_page_entries > num_leveldirs) - first_entry = MAX(0, num_leveldirs - num_page_entries); - - drawChooseLevelList(first_entry, num_page_entries); - drawChooseLevelInfo(first_entry + choice - 3); - AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, first_entry); - DrawGraphic(0, choice - 1, GFX_KUGEL_ROT); + leveldir_current->cl_first += step; + if (leveldir_current->cl_first + num_page_entries > num_leveldirs) + leveldir_current->cl_first = MAX(0, num_leveldirs - num_page_entries); + + drawChooseLevelList(leveldir_current->cl_first, num_page_entries); + drawChooseLevelInfo(leveldir_current->cl_first + + leveldir_current->cl_cursor - 3); + drawCursor(leveldir_current->cl_cursor - 1, FC_RED); + AdjustChooseLevelScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL, + leveldir_current->cl_first); return; } } @@ -1002,43 +1089,77 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button) if (!mx && !my && !dx && !dy) { x = 1; - y = choice; + y = leveldir_current->cl_cursor; + } + + if (dx == 1) + { + struct LevelDirInfo *node_first, *node_cursor; + int leveldir_pos = + leveldir_current->cl_first + leveldir_current->cl_cursor - 3; + + node_first = getLevelDirInfoFirstGroupEntry(leveldir_current); + node_cursor = getLevelDirInfoFromPos(node_first, leveldir_pos); + + if (node_cursor->node_group) + { + node_cursor->cl_first = leveldir_current->cl_first; + node_cursor->cl_cursor = leveldir_current->cl_cursor; + leveldir_current = node_cursor->node_group; + DrawChooseLevel(); + } + } + else if (dx == -1 && leveldir_current->node_parent) + { + leveldir_current = leveldir_current->node_parent; + DrawChooseLevel(); } if (x == 1 && y >= 3 && y <= num_page_entries + 2) { if (button) { - if (y != choice) + if (y != leveldir_current->cl_cursor) { - DrawGraphic(0, y - 1, GFX_KUGEL_ROT); - DrawGraphic(0, choice - 1, GFX_KUGEL_BLAU); - drawChooseLevelInfo(first_entry + y - 3); - choice = y; + drawCursor(y - 1, FC_RED); + drawCursor(leveldir_current->cl_cursor - 1, FC_BLUE); + drawChooseLevelInfo(leveldir_current->cl_first + y - 3); + leveldir_current->cl_cursor = y; } } else { - int leveldir_pos = first_entry + y - 3; - - leveldir_current = getLevelDirInfoFromPos(leveldir_first, leveldir_pos); + struct LevelDirInfo *node_first, *node_cursor; + int leveldir_pos = leveldir_current->cl_first + y - 3; - LoadLevelSetup_SeriesInfo(); - - SaveLevelSetup_LastSeries(); - SaveLevelSetup_SeriesInfo(); - TapeErase(); + node_first = getLevelDirInfoFirstGroupEntry(leveldir_current); + node_cursor = getLevelDirInfoFromPos(node_first, leveldir_pos); + if (node_cursor->node_group) + { + node_cursor->cl_first = leveldir_current->cl_first; + node_cursor->cl_cursor = leveldir_current->cl_cursor; + leveldir_current = node_cursor->node_group; + DrawChooseLevel(); + } + else if (node_cursor->parent_link) + { + leveldir_current = node_cursor->node_parent; + DrawChooseLevel(); + } + else + { + leveldir_current = node_cursor; - printf("first_level == %d, last_level == %d, levels == %d\n", - leveldir_current->first_level, - leveldir_current->last_level, - leveldir_current->levels); + LoadLevelSetup_SeriesInfo(); + SaveLevelSetup_LastSeries(); + SaveLevelSetup_SeriesInfo(); + TapeErase(); - game_status = MAINMENU; - DrawMainMenu(); - redraw = TRUE; + game_status = MAINMENU; + DrawMainMenu(); + } } } @@ -1190,8 +1311,12 @@ void DrawSetupScreen() if (!(i >= SETUP_SCREEN_POS_EMPTY1 && i <= SETUP_SCREEN_POS_EMPTY2)) { - DrawGraphic(0,i,GFX_KUGEL_BLAU); DrawText(SX+32,SY+i*32, setup_info[base].text, FS_BIG,FC_GREEN); + + if (strcmp(setup_info[base].text, "Input Devices") == 0) + initCursor(i, GFX_ARROW_BLUE_RIGHT); + else + initCursor(i, GFX_KUGEL_BLAU); } if (setup_info[base].value) @@ -1223,7 +1348,7 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) if (redraw) { - DrawGraphic(0,choice-1,GFX_KUGEL_ROT); + drawCursor(choice - 1, FC_RED); redraw = FALSE; } @@ -1255,6 +1380,13 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) y = choice; } + if (dx == 1 && choice == 14) + { + game_status = SETUPINPUT; + DrawSetupInputScreen(); + redraw = TRUE; + } + if (x==1 && y >= pos_start && y <= pos_end && !(y >= pos_empty1 && y <= pos_empty2)) { @@ -1262,8 +1394,8 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button) { if (y!=choice) { - DrawGraphic(0,y-1,GFX_KUGEL_ROT); - DrawGraphic(0,choice-1,GFX_KUGEL_BLAU); + drawCursor(y - 1, FC_RED); + drawCursor(choice - 1, FC_BLUE); } choice = y; } @@ -1440,10 +1572,11 @@ void DrawSetupInputScreen() ClearWindow(); DrawText(SX+16, SY+16, "SETUP INPUT", FS_BIG, FC_YELLOW); - DrawGraphic(0, 2, GFX_KUGEL_BLAU); - DrawGraphic(0, 3, GFX_KUGEL_BLAU); - DrawGraphic(0, 4, GFX_KUGEL_BLAU); - DrawGraphic(0, 15, GFX_KUGEL_BLAU); + initCursor(2, GFX_KUGEL_BLAU); + initCursor(3, GFX_KUGEL_BLAU); + initCursor(4, GFX_ARROW_BLUE_RIGHT); + initCursor(15, GFX_KUGEL_BLAU); + DrawGraphic(10, 2, GFX_ARROW_BLUE_LEFT); DrawGraphic(12, 2, GFX_ARROW_BLUE_RIGHT); @@ -1569,7 +1702,7 @@ void HandleSetupInputScreen(int mx, int my, int dx, int dy, int button) if (redraw) { - DrawGraphic(0,choice-1,GFX_KUGEL_ROT); + drawCursor(choice - 1, FC_RED); redraw = FALSE; } @@ -1630,8 +1763,8 @@ void HandleSetupInputScreen(int mx, int my, int dx, int dy, int button) { if (y != choice) { - DrawGraphic(0, y-1, GFX_KUGEL_ROT); - DrawGraphic(0, choice-1, GFX_KUGEL_BLAU); + drawCursor(y - 1, FC_RED); + drawCursor(choice - 1, FC_BLUE); } choice = y; } @@ -2226,8 +2359,9 @@ static void CreateScreenScrollbars() struct GadgetInfo *gi; int items_max, items_visible, item_position; unsigned long event_mask; - int num_page_entries; + int num_page_entries = MAX_LEVEL_SERIES_ON_SCREEN - 1; +#if 0 if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN) num_page_entries = num_leveldirs; else @@ -2236,6 +2370,11 @@ static void CreateScreenScrollbars() items_max = MAX(num_leveldirs, num_page_entries); items_visible = num_page_entries; item_position = 0; +#else + items_max = num_page_entries; + items_visible = num_page_entries; + item_position = 0; +#endif event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS; @@ -2278,6 +2417,7 @@ void CreateScreenGadgets() void MapChooseLevelGadgets() { + int num_leveldirs = numLevelDirInfoInGroup(leveldir_current); int i; if (num_leveldirs <= MAX_LEVEL_SERIES_ON_SCREEN) @@ -2313,7 +2453,7 @@ static void HandleScreenGadgets(struct GadgetInfo *gi) break; case SCREEN_CTRL_ID_SCROLL_VERTICAL: - HandleChooseLevel(0,0, 1,gi->event.item_position, MB_MENU_INITIALIZE); + HandleChooseLevel(0,0, 999,gi->event.item_position, MB_MENU_INITIALIZE); break; default: -- 2.34.1