From: Holger Schemel Date: Sat, 30 Aug 2014 08:45:04 +0000 (+0200) Subject: Merge branch 'master' into releases X-Git-Tag: 3.0.8^0 X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=commitdiff_plain;h=1ae6433828b1881d7810082472c72dfb3372a061;hp=5c2c97affd0c8fcc7afa5f363550473da5e02498 Merge branch 'master' into releases --- diff --git a/CHANGES b/CHANGES index a279c296..f8bad859 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,39 @@ +Release Version 3.0.8 [14 DEC 2003] +----------------------------------- + - added "musicinfo.conf" for menu and level music configuration + - added "editorsetup.conf" for editor element list configuration + - added "copy" and "exchange" functions for custom elements to editor + - added configurable "bored" and "sleeping" animations for the player + - added "awakening" sound for player waking up after sleeping + - added configurable element animations for info screen + - added configurable music credits for info screen + - added configurable level set information for info screen + - added warnings for undefined token values in artwork config files + - menu text now directly clickable + - better sniksnak turning movement (two steps instead of only one) + - fixed turning movement of butterflies and fireflies (no frame reset) + - fixed bug with wrong default impact sound for colored emeralds + - fixed bug with double nut cracking sound + - fixed a very nasty bug in dragon turning code in TurnRoundExt() + - finally fixed tape recording when player is created from CE change + - added new contributed levels from the following players: + + Audrius Saikunas (4 levels) + + Efraim Yawitz (20 levels) + + Krystian Abramowicz (100 levels) + + Paul E Collins (formerly known as Equinox Tetrachloride; 64 levels) + + Sebastian Simon (12 levels) + - amazing new level set: + + "BD2K3" from Alan Bond + + 43 levels full of BD nostalgia, action and fantastic effects + + overwhelming use of custom elements + + complete artwork set with graphics, sounds and music + + available as a separate download from www.artsoft.org + - another great level set was updated: + + "jue2" from Jürgen Bonhagen + + 15 new mind-boggling levels full of new challenges for your brain + + complete artwork set with graphics and sounds + + available for downloading from "http://www.jb-line.de/rnd.html" + Release Version 3.0.7 [10 NOV 2003] ----------------------------------- - fixed incorrectly displayed animation for attacking dragon diff --git a/src/Makefile b/src/Makefile index 61285b02..05eccd99 100644 --- a/src/Makefile +++ b/src/Makefile @@ -135,6 +135,8 @@ LDFLAGS = $(SYS_LDFLAGS) $(EXTRA_LDFLAGS) -lm SRCS = main.c \ conf_gfx.c \ conf_snd.c \ + conf_mus.c \ + conf_hlp.c \ init.c \ config.c \ events.c \ @@ -151,6 +153,8 @@ SRCS = main.c \ OBJS = main.o \ conf_gfx.o \ conf_snd.o \ + conf_mus.o \ + conf_hlp.o \ init.o \ config.o \ events.o \ @@ -166,6 +170,7 @@ OBJS = main.o \ CNFS = conf_gfx.h \ conf_snd.h \ + conf_mus.h \ conf_chr.c \ conf_chr.h \ conf_cus.c \ @@ -173,7 +178,9 @@ CNFS = conf_gfx.h \ conf_e2g.c \ conf_esg.c \ conf_e2s.c \ - conf_fnt.c + conf_fnt.c \ + conf_g2s.c \ + conf_g2m.c CNFS_CMD = ../Scripts/create_element_defs.pl @@ -215,6 +222,9 @@ conf_gfx.h: conf_gfx.c conf_snd.h: conf_snd.c @$(MAKE) auto-conf +conf_mus.h: conf_mus.c + @$(MAKE) auto-conf + $(TIMESTAMP_FILE): $(SRCS) $(LIBGAME) @date '+"[%Y-%m-%d %H:%M]"' \ | sed -e 's/^/#define COMPILE_DATE_STRING /' \ diff --git a/src/cartoons.c b/src/cartoons.c index e6892ebb..fd53e502 100644 --- a/src/cartoons.c +++ b/src/cartoons.c @@ -26,13 +26,13 @@ static void PrepareBackbuffer() /* Fill empty backbuffer for animation functions */ if (setup.direct_draw && game_status == GAME_MODE_PLAYING) { - int xx,yy; + int xx, yy; SetDrawtoField(DRAW_BACKBUFFER); - for(xx=0; xx= NUM_FILE_ELEMENTS) Error(ERR_WARN, "editor element %d is runtime element", element); @@ -2991,9 +3106,10 @@ static void ReinitializeElementList() } num_editor_elements = 0; + use_el_empty = FALSE; /* determine size of element list */ - for (i=0; editor_elements_info[i].setup_value != NULL; i++) + for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { if (*editor_elements_info[i].setup_value) { @@ -3006,26 +3122,26 @@ static void ReinitializeElementList() if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS) { - /* workaround: offer at least as many elements as element buttons exist */ - int list_nr = 1; /* see above: editor_elements_info for Emerald Mine */ + /* offer at least as many elements as element buttons exist */ + use_el_empty = TRUE; + num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements; - *editor_elements_info[list_nr].setup_value = TRUE; - num_editor_elements += *editor_elements_info[list_nr].element_list_size; + num_editor_elements += num_editor_el_empty; } editor_elements = checked_malloc(num_editor_elements * sizeof(int)); /* fill element list */ - for (i=0; editor_elements_info[i].setup_value != NULL; i++) + for (i = 0; editor_elements_info[i].setup_value != NULL; i++) { if (*editor_elements_info[i].setup_value) { if (setup.editor.el_headlines) - for (j=0; j < *editor_elements_info[i].headline_list_size; j++) - editor_elements[pos++] = editor_elements_info[i].headline_list[j]; + for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) + editor_elements[pos++] = (*editor_elements_info[i].headline_list)[j]; - for (j=0; j < *editor_elements_info[i].element_list_size; j++) - editor_elements[pos++] = editor_elements_info[i].element_list[j]; + for (j = 0; j < *editor_elements_info[i].element_list_size; j++) + editor_elements[pos++] = (*editor_elements_info[i].element_list)[j]; } } @@ -3036,6 +3152,35 @@ static void ReinitializeElementList() element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS; } +void PrintEditorElementList() +{ + boolean *stop = &setup.editor.el_user_defined; + int i, j; + + for (i = 0; editor_elements_info[i].setup_value != stop; i++) + { + for (j = 0; j < *editor_elements_info[i].headline_list_size; j++) + { + int element = (*editor_elements_info[i].headline_list)[j]; + + printf("# %s\n", element_info[element].token_name); + } + + if (j > 0) + printf("#\n"); + + for (j = 0; j < *editor_elements_info[i].element_list_size; j++) + { + int element = (*editor_elements_info[i].element_list)[j]; + + printf("# %s\n", element_info[element].token_name); + } + + if (j > 0) + printf("#\n"); + } +} + static void ReinitializeElementListButtons() { static boolean last_setup_value_headlines = FALSE; @@ -3047,7 +3192,7 @@ static void ReinitializeElementListButtons() if (last_setup_value_headlines != setup.editor.el_headlines) initialization_needed = TRUE; - for (i=0; editor_elements_info[i].setup_value != NULL; i++) + for (i = 0; editor_elements_info[i].setup_value != NULL; i++) if (editor_elements_info[i].last_setup_value != *editor_elements_info[i].setup_value) initialization_needed = TRUE; @@ -3061,7 +3206,7 @@ static void ReinitializeElementListButtons() /* store current setup values for next invocation of this function */ last_setup_value_headlines = setup.editor.el_headlines; - for (i=0; editor_elements_info[i].setup_value != NULL; i++) + for (i = 0; editor_elements_info[i].setup_value != NULL; i++) editor_elements_info[i].last_setup_value = *editor_elements_info[i].setup_value; @@ -3081,8 +3226,8 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height, getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y); - for (y=0; y < num_mini_tiley; y++) - for (x=0; x < num_mini_tilex; x++) + for (y = 0; y < num_mini_tiley; y++) + for (x = 0; x < num_mini_tilex; x++) BlitBitmap(src_bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY, dest_x - MINI_TILEX / 2 + x * MINI_TILEX, dest_y - MINI_TILEY / 2 + y * MINI_TILEY); @@ -3104,8 +3249,8 @@ static void DrawDrawingArea(int id) DrawMiniGraphicExt(drawto, gi->x, gi->y, el2edimg(custom_element.gfx_element)); else if (id == ED_DRAWING_ID_CUSTOM_CONTENT) - for (y=0; y<3; y++) - for (x=0; x<3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY, el2edimg(custom_element.content[x][y])); @@ -3113,8 +3258,8 @@ static void DrawDrawingArea(int id) DrawMiniGraphicExt(drawto, gi->x, gi->y, el2edimg(custom_element_change.target_element)); else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT) - for (y=0; y < 3; y++) - for (x=0; x < 3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY, el2edimg(custom_element_change.content[x][y])); @@ -3126,8 +3271,8 @@ static void DrawDrawingArea(int id) { int nr = id - ED_DRAWING_ID_ELEMENT_CONTENT_0; - for (y=0; y < 3; y++) - for (x=0; x < 3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY, el2edimg(level.yamyam_content[nr][x][y])); @@ -3150,13 +3295,13 @@ static void ScrollMiniLevel(int from_x, int from_y, int scroll) if (dx) { x = (dx == 1 ? 0 : ed_fieldx - 1); - for(y=0; y selectbox_info[i].size) selectbox_info[i].size = strlen(selectbox_info[i].options[j].text); @@ -3754,7 +3922,7 @@ static void CreateTextbuttonGadgets() int max_infotext_len = getMaxInfoTextLength(); int i; - for (i=0; iwidth, gi->height, gi->x, gi->y); + + redraw_mask |= REDRAW_DOOR_3; + } + } + } +} + +static void MapLevelEditorToolboxDrawingGadgets() +{ + MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE); +} + +static void UnmapLevelEditorToolboxDrawingGadgets() +{ + MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE); +} + static void UnmapDrawingArea(int id) { UnmapGadget(level_editor_gadget[id]); } -void UnmapLevelEditorWindowGadgets() +static void UnmapLevelEditorWindowGadgets() { int i; - for (i=0; ix < SX + SXSIZE) UnmapGadget(level_editor_gadget[i]); } @@ -4402,7 +4638,7 @@ void UnmapLevelEditorGadgets() { int i; - for (i=0; idescription[i] = ei_from->description[i]; + + /* ---------- copy element properties ---------- */ + Properties[element_to][EP_BITFIELD_BASE] = + Properties[element_from][EP_BITFIELD_BASE]; + + /* ---------- copy custom property values ---------- */ + + ei_to->use_gfx_element = ei_from->use_gfx_element; + ei_to->gfx_element = ei_from->gfx_element; + + ei_to->collect_score = ei_from->collect_score; + ei_to->collect_count = ei_from->collect_count; + + ei_to->push_delay_fixed = ei_from->push_delay_fixed; + ei_to->push_delay_random = ei_from->push_delay_random; + ei_to->move_delay_fixed = ei_from->move_delay_fixed; + ei_to->move_delay_random = ei_from->move_delay_random; + + ei_to->move_pattern = ei_from->move_pattern; + ei_to->move_direction_initial = ei_from->move_direction_initial; + ei_to->move_stepsize = ei_from->move_stepsize; + + ei_to->slippery_type = ei_from->slippery_type; + + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) + ei_to->content[x][y] = ei_from->content[x][y]; + + ei_to->num_change_pages = ei_from->num_change_pages; + setElementChangePages(ei_to, ei_to->num_change_pages); + + for (i=0; i < ei_to->num_change_pages; i++) + { + struct ElementChangeInfo *change_to = &ei_to->change_page[i]; + struct ElementChangeInfo *change_from = &ei_from->change_page[i]; + + /* always start with reliable default values */ + setElementChangeInfoToDefaults(change_to); + + change_to->events = change_from->events; + + change_to->target_element = change_from->target_element; + + change_to->delay_fixed = change_from->delay_fixed; + change_to->delay_random = change_from->delay_random; + change_to->delay_frames = change_from->delay_frames; + + change_to->trigger_element = change_from->trigger_element; + + change_to->explode = change_from->explode; + change_to->use_content = change_from->use_content; + change_to->only_complete = change_from->only_complete; + change_to->use_random_change = change_from->use_random_change; + + change_to->random = change_from->random; + change_to->power = change_from->power; + + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) + change_to->content[x][y] = change_from->content[x][y]; + + change_to->can_change = change_from->can_change; + + change_to->sides = change_from->sides; + } + + /* mark this custom element as modified */ + ei_to->modified_settings = TRUE; +} + +static void replace_custom_element_in_settings(int element_from, + int element_to) +{ + int i, j, x, y; + + for (i = 0; i < NUM_FILE_ELEMENTS; i++) + { + struct ElementInfo *ei = &element_info[i]; + + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) + if (ei->content[x][y] == element_from) + ei->content[x][y] = element_to; + + for (j=0; j < ei->num_change_pages; j++) + { + struct ElementChangeInfo *change = &ei->change_page[j]; + + if (change->target_element == element_from) + change->target_element = element_to; + + if (change->trigger_element == element_from) + change->trigger_element = element_to; + + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) + if (change->content[x][y] == element_from) + change->content[x][y] = element_to; + } + } +} + +static void replace_custom_element_in_playfield(int element_from, + int element_to) +{ + int x, y; + + for (x = 0; x < lev_fieldx; x++) + for (y = 0; y < lev_fieldy; y++) + if (Feld[x][y] == element_from) + Feld[x][y] = element_to; +} + +static void CopyCustomElement(int element_old, int element_new, int copy_mode) +{ + if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM) + { + copy_custom_element_settings(element_new, element_old); + } + else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO) + { + copy_custom_element_settings(element_old, element_new); + } + else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE) + { + copy_custom_element_settings(element_old, EL_DUMMY); + copy_custom_element_settings(element_new, element_old); + copy_custom_element_settings(EL_DUMMY, element_new); + + replace_custom_element_in_settings(element_old, EL_DUMMY); + replace_custom_element_in_settings(element_new, element_old); + replace_custom_element_in_settings(EL_DUMMY, element_new); + + replace_custom_element_in_playfield(element_old, EL_DUMMY); + replace_custom_element_in_playfield(element_new, element_old); + replace_custom_element_in_playfield(EL_DUMMY, element_new); + } + + UpdateCustomElementGraphicGadgets(); + DrawPropertiesWindow(); +} + static void CopyCustomElementPropertiesToEditor(int element) { int i; int current_change_page = element_info[element].current_change_page; /* dynamically (re)build selectbox for selecting change page */ - for (i=0; i < element_info[element].num_change_pages; i++) + for (i = 0; i < element_info[element].num_change_pages; i++) { sprintf(options_change_page_strings[i], "%d", i + 1); @@ -4505,13 +4892,13 @@ static void CopyCustomElementPropertiesToEditor(int element) custom_element_change = *element_info[element].change; /* needed to initially set selectbox value variables to reliable defaults */ - for (i=0; i < ED_NUM_SELECTBOX; i++) + for (i = 0; i < ED_NUM_SELECTBOX; i++) setSelectboxValue(i, *selectbox_info[i].value); - for (i=0; i < NUM_ELEMENT_PROPERTIES; i++) + for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) custom_element_properties[i] = HAS_PROPERTY(element, i); - for (i=0; i < NUM_CHANGE_EVENTS; i++) + for (i = 0; i < NUM_CHANGE_EVENTS; i++) custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i); /* ---------- element settings: configure (custom elements) ------------- */ @@ -4596,7 +4983,8 @@ static void CopyCustomElementPropertiesToEditor(int element) HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED : - HAS_CHANGE_EVENT(element, CE_COLLISION) ? CE_COLLISION : + HAS_CHANGE_EVENT(element, CE_COLLISION_ACTIVE) ? CE_COLLISION_ACTIVE : + HAS_CHANGE_EVENT(element, CE_COLLISION_PASSIVE) ? CE_COLLISION_PASSIVE : HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT : HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED : custom_element_change.direct_action); @@ -4612,6 +5000,8 @@ static void CopyCustomElementPropertiesToEditor(int element) HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED : HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DROPPED) ? CE_OTHER_GETS_DROPPED : HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING : + HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_ACTIVE) ? CE_OTHER_IS_COLL_ACTIVE : + HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_PASSIVE) ? CE_OTHER_IS_COLL_PASSIVE : HAS_CHANGE_EVENT(element, CE_OTHER_IS_SWITCHING) ? CE_OTHER_IS_SWITCHING : HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING : HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING : @@ -4628,7 +5018,7 @@ static void CopyCustomElementPropertiesToGame(int element) if (level.use_custom_template) { - if (Request("Copy and modify level tem- plate ?", REQ_ASK)) + if (Request("Copy and modify level template ?", REQ_ASK)) { level.use_custom_template = FALSE; ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE], @@ -4714,7 +5104,8 @@ static void CopyCustomElementPropertiesToGame(int element) custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE; custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE; custom_element_change_events[CE_SWITCHED] = FALSE; - custom_element_change_events[CE_COLLISION] = FALSE; + custom_element_change_events[CE_COLLISION_ACTIVE] = FALSE; + custom_element_change_events[CE_COLLISION_PASSIVE] = FALSE; custom_element_change_events[CE_IMPACT] = FALSE; custom_element_change_events[CE_SMASHED] = FALSE; custom_element_change_events[custom_element_change.direct_action] = @@ -4730,16 +5121,18 @@ static void CopyCustomElementPropertiesToGame(int element) custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE; custom_element_change_events[CE_OTHER_GETS_DROPPED] = FALSE; custom_element_change_events[CE_OTHER_IS_TOUCHING] = FALSE; + custom_element_change_events[CE_OTHER_IS_COLL_ACTIVE] = FALSE; + custom_element_change_events[CE_OTHER_IS_COLL_PASSIVE] = FALSE; custom_element_change_events[CE_OTHER_IS_SWITCHING] = FALSE; custom_element_change_events[CE_OTHER_IS_CHANGING] = FALSE; custom_element_change_events[CE_OTHER_IS_EXPLODING] = FALSE; custom_element_change_events[custom_element_change.other_action] = custom_element_change_events[CE_BY_OTHER_ACTION]; - for (i=0; i < NUM_ELEMENT_PROPERTIES; i++) + for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) SET_PROPERTY(element, i, custom_element_properties[i]); - for (i=0; i < NUM_CHANGE_EVENTS; i++) + for (i = 0; i < NUM_CHANGE_EVENTS; i++) SET_CHANGE_EVENT(element, i, custom_element_change_events[i]); /* copy change events also to special level editor variable */ @@ -4942,7 +5335,7 @@ static void ModifyEditorElementList() { int i; - for (i=0; i= max_lines_per_screen) + if (start_line >= max_lines_per_screen) return FALSE; - DrawText(sx, sy + screen_line * font_height, text, font_nr); + DrawText(sx, sy + start_line * font_height, text, font_nr); return TRUE; } -static int PrintElementDescriptionFromFile(char *filename, int screen_line) +#if 1 + +static int PrintElementDescriptionFromFile(char *filename, int start_line) { int font_nr = FONT_TEXT_2; int font_width = getFontWidth(font_nr); + int font_height = getFontHeight(font_nr); int pad_x = ED_SETTINGS_XPOS(0); + int pad_y = ED_SETTINGS_YPOS(0) + ED_BORDER_SIZE; + int sx = SX + pad_x; + int sy = SY + pad_y + start_line * font_height; int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width; + int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1; + + return DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line, + max_lines_per_screen); +} + +#else + +static int PrintElementDescriptionFromFile(char *filename, int start_line) +{ + int font_nr = FONT_TEXT_2; + int font_width = getFontWidth(font_nr); + int font_height = getFontHeight(font_nr); + int pad_x = ED_SETTINGS_XPOS(0); + int pad_y = ED_SETTINGS_YPOS(0) + ED_BORDER_SIZE; + int sx = SX + pad_x; + int sy = SY + pad_y; + int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width; + int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1; + int current_line = start_line; char line[MAX_LINE_LEN]; char buffer[max_chars_per_line + 1]; int buffer_len; - int lines_printed = 0; FILE *file; + if (current_line >= max_lines_per_screen) + return 0; + if (filename == NULL) return 0; @@ -5193,9 +5617,9 @@ static int PrintElementDescriptionFromFile(char *filename, int screen_line) buffer[0] = '\0'; buffer_len = 0; - while(!feof(file)) + while (!feof(file) && current_line < max_lines_per_screen) { - char *line_ptr, *word_ptr; + char *line_ptr; boolean last_line_was_empty = TRUE; /* read next line of input file */ @@ -5219,92 +5643,40 @@ static int PrintElementDescriptionFromFile(char *filename, int screen_line) if (strlen(line) == 0) /* special case: force empty line */ strcpy(line, "\n"); - word_ptr = line; + line_ptr = line; - while (*word_ptr) + while (*line_ptr && current_line < max_lines_per_screen) { - boolean print_buffer = FALSE; - int word_len; - - /* skip leading whitespaces */ - while (*word_ptr == ' ' || *word_ptr == '\t') - word_ptr++; - - line_ptr = word_ptr; - word_len = 0; - - /* look for end of next word */ - while (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0') - { - line_ptr++; - word_len++; - } - - if (word_len == 0) - { - continue; - } - else if (*word_ptr == '\n') /* special case: force empty line */ + boolean buffer_filled = RenderLineToBuffer(&line_ptr, + buffer, &buffer_len, + last_line_was_empty, + max_chars_per_line); + if (buffer_filled) { - if (buffer_len == 0) - word_ptr++; - - /* prevent printing of multiple empty lines */ - if (buffer_len > 0 || !last_line_was_empty) - print_buffer = TRUE; - } - else if (word_len < max_chars_per_line - buffer_len) - { - /* word fits into text buffer -- add word */ - - if (buffer_len > 0) - buffer[buffer_len++] = ' '; - - strncpy(&buffer[buffer_len], word_ptr, word_len); - buffer_len += word_len; - buffer[buffer_len] = '\0'; - word_ptr += word_len; - } - else if (buffer_len > 0) - { - /* not enough space left for word in text buffer -- print buffer */ - - print_buffer = TRUE; - } - else - { - /* word does not fit at all into empty text buffer -- cut word */ - - strncpy(buffer, word_ptr, max_chars_per_line); - buffer[max_chars_per_line] = '\0'; - word_ptr += max_chars_per_line; - print_buffer = TRUE; - } - - if (print_buffer) - { - if (!PrintInfoText(buffer, font_nr, screen_line + lines_printed)) - return lines_printed; + DrawText(sx, sy + current_line * font_height, buffer, font_nr); + current_line++; last_line_was_empty = (buffer_len == 0); - lines_printed++; buffer[0] = '\0'; buffer_len = 0; - print_buffer = FALSE; } } } fclose(file); - if (buffer_len > 0) - if (PrintInfoText(buffer, font_nr, screen_line + lines_printed)) - lines_printed++; + if (buffer_len > 0 && current_line < max_lines_per_screen) + { + DrawText(sx, sy + current_line * font_height, buffer, font_nr); + current_line++; + } - return lines_printed; + return (current_line - start_line); } +#endif + static void DrawPropertiesTabulatorGadgets() { struct GadgetInfo *gd_gi = level_editor_gadget[GADGET_ID_PROPERTIES_INFO]; @@ -5320,7 +5692,7 @@ static void DrawPropertiesTabulatorGadgets() if (IS_CUSTOM_ELEMENT(properties_element)) id_last = ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED; - for (i=id_first; i <= id_last; i++) + for (i = id_first; i <= id_last; i++) { int gadget_id = textbutton_info[i].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; @@ -5424,13 +5796,13 @@ static void DrawPropertiesInfo() /* ----- print number of elements / percentage of this element in level */ num_elements_in_level = 0; - for (y=0; y to_x) swap_numbers(&from_x, &to_x); - for (x=from_x; x<=to_x; x++) + for (x = from_x; x <= to_x; x++) DrawLineElement(x, y, element, change_level); } else if (from_x == to_x) /* vertical line */ @@ -5828,7 +6205,7 @@ static void DrawLine(int from_x, int from_y, int to_x, int to_y, if (from_y > to_y) swap_numbers(&from_y, &to_y); - for (y=from_y; y<=to_y; y++) + for (y = from_y; y <= to_y; y++) DrawLineElement(x, y, element, change_level); } else /* diagonal line */ @@ -5844,7 +6221,7 @@ static void DrawLine(int from_x, int from_y, int to_x, int to_y, if (from_x > to_x) swap_number_pairs(&from_x, &from_y, &to_x, &to_y); - for (x=0; x<=len_x; x++) + for (x = 0; x <= len_x; x++) { y = (int)(a * x + 0.5) * (to_y < from_y ? -1 : +1); DrawLineElement(from_x + x, from_y + y, element, change_level); @@ -5857,7 +6234,7 @@ static void DrawLine(int from_x, int from_y, int to_x, int to_y, if (from_y > to_y) swap_number_pairs(&from_x, &from_y, &to_x, &to_y); - for (y=0; y<=len_y; y++) + for (y = 0; y <= len_y; y++) { x = (int)(a * y + 0.5) * (to_x < from_x ? -1 : +1); DrawLineElement(from_x + x, from_y + y, element, change_level); @@ -5883,7 +6260,7 @@ static void DrawFilledBox(int from_x, int from_y, int to_x, int to_y, if (from_y > to_y) swap_number_pairs(&from_x, &from_y, &to_x, &to_y); - for (y=from_y; y<=to_y; y++) + for (y = from_y; y <= to_y; y++) DrawLine(from_x, y, to_x, y, element, change_level); } @@ -5901,7 +6278,7 @@ static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2, /* not optimal (some points get drawn twice) but simple, and fast enough for the few points we are drawing */ - for (x=0; x<=radius; x++) + for (x = 0; x <= radius; x++) { int sx, sy, lx, ly; @@ -5916,7 +6293,7 @@ static void DrawArcExt(int from_x, int from_y, int to_x2, int to_y2, DrawLineElement(sx, sy, element, change_level); } - for (y=0; y<=radius; y++) + for (y = 0; y <= radius; y++) { int sx, sy, lx, ly; @@ -6029,9 +6406,9 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y, from_lx = from_x + level_xpos; from_ly = from_y + level_ypos; - for (y=0; y= num_free_positions) { - for (x=0; xcustom_id; int button = gi->event.button; int step = BUTTON_STEPSIZE(button); @@ -6930,8 +7313,11 @@ static void HandleControlButtons(struct GadgetInfo *gi) if (edit_mode == ED_MODE_DRAWING && drawing_function == GADGET_ID_TEXT) DrawLevelText(0, 0, 0, TEXT_END); - if (id < ED_NUM_CTRL1_BUTTONS && id != GADGET_ID_PROPERTIES && - id != GADGET_ID_PICK_ELEMENT && edit_mode != ED_MODE_DRAWING && + if (id < ED_NUM_CTRL1_BUTTONS && + id != GADGET_ID_SINGLE_ITEMS && + id != GADGET_ID_PROPERTIES && + id != GADGET_ID_PICK_ELEMENT && + edit_mode != ED_MODE_DRAWING && drawing_function != GADGET_ID_PICK_ELEMENT && !(GetKeyModState() & KMOD_Control)) { @@ -7093,14 +7479,28 @@ static void HandleControlButtons(struct GadgetInfo *gi) properties_element = new_element; DrawPropertiesWindow(); edit_mode = ED_MODE_PROPERTIES; + + last_level_drawing_function = drawing_function; + ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], + MB_LEFTBUTTON); } else { DrawDrawingWindow(); edit_mode = ED_MODE_DRAWING; + + ClickOnGadget(level_editor_gadget[last_level_drawing_function], + MB_LEFTBUTTON); } break; + case GADGET_ID_CUSTOM_COPY_FROM: + case GADGET_ID_CUSTOM_COPY_TO: + case GADGET_ID_CUSTOM_EXCHANGE: + last_custom_copy_mode = id; + last_drawing_function = drawing_function; + break; + case GADGET_ID_UNDO: if (undo_buffer_steps == 0) { @@ -7118,8 +7518,8 @@ static void HandleControlButtons(struct GadgetInfo *gi) (undo_buffer_position - 1 + NUM_UNDO_STEPS) % NUM_UNDO_STEPS; undo_buffer_steps--; - for(x=0; x= GADGET_ID_ELEMENT_CONTENT_0 && id <= GADGET_ID_ELEMENT_CONTENT_7) diff --git a/src/editor.h b/src/editor.h index 3213c452..3844a2c8 100644 --- a/src/editor.h +++ b/src/editor.h @@ -32,5 +32,6 @@ void HandleLevelEditorKeyInput(Key); void HandleLevelEditorIdle(); void HandleEditorGadgetInfoText(void *ptr); void RequestExitLevelEditor(boolean); +void PrintEditorElementList(); #endif diff --git a/src/events.c b/src/events.c index e021ec83..19c47763 100644 --- a/src/events.c +++ b/src/events.c @@ -79,7 +79,7 @@ static boolean NextValidEvent(Event *event) void EventLoop(void) { - while(1) + while (1) { if (PendingEvent()) /* got event */ { @@ -219,7 +219,7 @@ void ClearPlayerAction() /* simulate key release events for still pressed keys */ key_joystick_mapping = 0; - for (i=0; i string_len) + return FALSE; + + return (strcmp(&string[string_len - suffix_len], suffix) == 0); +} + +#define MAX_CHEAT_INPUT_LEN 32 + +static void HandleKeysCheating(Key key) +{ + static char cheat_input[2 * MAX_CHEAT_INPUT_LEN + 1] = ""; + char letter = getCharFromKey(key); + int cheat_input_len = strlen(cheat_input); + int i; + + if (letter == 0) + return; + + if (cheat_input_len >= 2 * MAX_CHEAT_INPUT_LEN) + { + for (i = 0; i < MAX_CHEAT_INPUT_LEN + 1; i++) + cheat_input[i] = cheat_input[MAX_CHEAT_INPUT_LEN + i]; + + cheat_input_len = MAX_CHEAT_INPUT_LEN; + } + + cheat_input[cheat_input_len++] = letter; + cheat_input[cheat_input_len] = '\0'; + +#if 0 + printf("::: '%s' [%d]\n", cheat_input, cheat_input_len); +#endif + +#if 1 + if (is_string_suffix(cheat_input, ":insert solution tape")) + InsertSolutionTape(); +#else + if (is_string_suffix(cheat_input, ":ist")) + InsertSolutionTape(); +#endif + +#ifdef DEBUG + else if (is_string_suffix(cheat_input, ":dump tape")) + DumpTape(&tape); + else if (is_string_suffix(cheat_input, ".q")) + for (i = 0; i < MAX_INVENTORY_SIZE; i++) + if (local_player->inventory_size < MAX_INVENTORY_SIZE) + local_player->inventory_element[local_player->inventory_size++] = + EL_DYNAMITE; +#endif +} + void HandleKey(Key key, int key_status) { int joy = 0; @@ -473,7 +533,7 @@ void HandleKey(Key key, int key_status) static boolean bomb_placed[MAX_PLAYERS] = { FALSE,FALSE,FALSE,FALSE }; int pnr; - for (pnr=0; pnrinventory_size < MAX_INVENTORY_SIZE) - local_player->inventory_element[local_player->inventory_size++] = - EL_DYNAMITE; - } - - break; - - #if 0 case KSYM_z: { int i; - for(i=0; i #include +#include +#include #include "libgame/libgame.h" @@ -89,8 +91,8 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) change->random = 100; change->power = CP_NON_DESTRUCTIVE; - for(x=0; x<3; x++) - for(y=0; y<3; y++) + for (x = 0; x < 3; x++) + for (y = 0; y < 3; y++) change->content[x][y] = EL_EMPTY_SPACE; change->direct_action = 0; @@ -115,8 +117,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->fieldx = STD_LEV_FIELDX; level->fieldy = STD_LEV_FIELDY; - for(x=0; xfield[x][y] = EL_SAND; level->time = 100; @@ -133,45 +135,45 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->use_custom_template = FALSE; - for(i=0; iname[i] = '\0'; - for(i=0; iauthor[i] = '\0'; strcpy(level->name, NAMELESS_LEVEL_NAME); strcpy(level->author, ANONYMOUS_NAME); - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { level->envelope_text[i][0] = '\0'; level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE; level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE; } - for(i=0; iscore[i] = 10; level->num_yamyam_contents = STD_ELEMENT_CONTENTS; - for(i=0; iyamyam_content[i][x][y] = (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY); level->field[0][0] = EL_PLAYER_1; level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED; - for (i=0; i < MAX_NUM_ELEMENTS; i++) + for (i = 0; i < MAX_NUM_ELEMENTS; i++) { setElementChangePages(&element_info[i], 1); setElementChangeInfoToDefaults(element_info[i].change); } - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; - for(j=0; j < MAX_ELEMENT_NAME_LEN + 1; j++) + for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++) element_info[element].description[j] = '\0'; if (element_info[element].custom_description != NULL) strncpy(element_info[element].description, @@ -197,8 +199,8 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) element_info[element].slippery_type = SLIPPERY_ANY_RANDOM; - for(x=0; x<3; x++) - for(y=0; y<3; y++) + for (x = 0; x < 3; x++) + for (y = 0; y < 3; y++) element_info[element].content[x][y] = EL_EMPTY_SPACE; element_info[element].access_type = 0; @@ -215,7 +217,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) element_info[element].current_change_page = 0; /* start with no properties at all */ - for (j=0; j < NUM_EP_BITFIELDS; j++) + for (j = 0; j < NUM_EP_BITFIELDS; j++) Properties[element][j] = EP_BITMASK_DEFAULT; element_info[element].modified_settings = FALSE; @@ -354,17 +356,17 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level) level->time = getFile16BitBE(file); level->gems_needed = getFile16BitBE(file); - for(i=0; iname[i] = getFile8Bit(file); level->name[MAX_LEVEL_NAME_LEN] = 0; - for(i=0; iscore[i] = getFile8Bit(file); level->num_yamyam_contents = STD_ELEMENT_CONTENTS; - for(i=0; iyamyam_content[i][x][y] = checkLevelElement(getFile8Bit(file)); level->amoeba_speed = getFile8Bit(file); @@ -387,7 +389,7 @@ static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level) { int i; - for(i=0; iauthor[i] = getFile8Bit(file); level->author[MAX_LEVEL_NAME_LEN] = 0; @@ -413,8 +415,8 @@ static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level) return chunk_size_expected; } - for(y=0; yfieldy; y++) - for(x=0; xfieldx; x++) + for (y = 0; y < level->fieldy; y++) + for (x = 0; x < level->fieldx; x++) level->field[x][y] = checkLevelElement(level->encoding_16bit_field ? getFile16BitBE(file) : getFile8Bit(file)); @@ -452,9 +454,9 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level) level->num_yamyam_contents > MAX_ELEMENT_CONTENTS) level->num_yamyam_contents = STD_ELEMENT_CONTENTS; - for(i=0; iyamyam_content[i][x][y] = checkLevelElement(level->encoding_16bit_field ? getFile16BitBE(file) : getFile8Bit(file)); @@ -475,9 +477,9 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level) ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED); - for(i=0; inum_yamyam_contents = num_contents; - for(i=0; iyamyam_content[i][x][y] = content_array[i][x][y]; } else if (element == EL_BD_AMOEBA) @@ -534,7 +536,7 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level) return chunk_size_expected; } - for(i=0; i < envelope_len; i++) + for (i = 0; i < envelope_len; i++) level->envelope_text[envelope_nr][i] = getFile8Bit(file); return chunk_size; @@ -552,7 +554,7 @@ static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level) return chunk_size_expected; } - for (i=0; i < num_changed_custom_elements; i++) + for (i = 0; i < num_changed_custom_elements; i++) { int element = getFile16BitBE(file); int properties = getFile32BitBE(file); @@ -578,7 +580,7 @@ static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level) return chunk_size_expected; } - for (i=0; i < num_changed_custom_elements; i++) + for (i = 0; i < num_changed_custom_elements; i++) { int element = getFile16BitBE(file); int custom_target_element = getFile16BitBE(file); @@ -604,7 +606,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level) return chunk_size_expected; } - for (i=0; i < num_changed_custom_elements; i++) + for (i = 0; i < num_changed_custom_elements; i++) { int element = getFile16BitBE(file); @@ -612,10 +614,10 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level) { Error(ERR_WARN, "invalid custom element number %d", element); - element = EL_DEFAULT; /* dummy element used for artwork config */ + element = EL_DUMMY; } - for(j=0; jrandom = getFile8Bit(file); element_info[element].change->power = getFile8Bit(file); - for(y=0; y<3; y++) - for(x=0; x<3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) element_info[element].change->content[x][y] = checkLevelElement(getFile16BitBE(file)); @@ -695,12 +697,12 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) { Error(ERR_WARN, "invalid custom element number %d", element); - element = EL_DEFAULT; /* dummy element used for artwork config */ + element = EL_DUMMY; } ei = &element_info[element]; - for(i=0; i < MAX_ELEMENT_NAME_LEN; i++) + for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) ei->description[i] = getFile8Bit(file); ei->description[MAX_ELEMENT_NAME_LEN] = 0; @@ -738,8 +740,8 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) ei->slippery_type = getFile8Bit(file); - for(y=0; y<3; y++) - for(x=0; x<3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) ei->content[x][y] = checkLevelElement(getFile16BitBE(file)); /* some free bytes for future custom property values and padding */ @@ -749,7 +751,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) setElementChangePages(ei, ei->num_change_pages); - for (i=0; i < ei->num_change_pages; i++) + for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; @@ -774,8 +776,8 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) change->random = getFile8Bit(file); change->power = getFile8Bit(file); - for(y=0; y<3; y++) - for(x=0; x<3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) change->content[x][y] = checkLevelElement(getFile16BitBE(file)); change->can_change = getFile8Bit(file); @@ -1025,12 +1027,12 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) (these following values were accidentally changed in version 3.0.1) */ if (level->game_version <= VERSION_IDENT(3,0,0,0)) { - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; /* order of checking and copying events to be mapped is important */ - for (j=CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER; j--) + for (j = CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER_OBSOLETE; j--) { if (HAS_CHANGE_EVENT(element, j - 2)) { @@ -1040,7 +1042,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) } /* order of checking and copying events to be mapped is important */ - for (j=CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION; j--) + for (j = CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION_ACTIVE; j--) { if (HAS_CHANGE_EVENT(element, j - 1)) { @@ -1052,15 +1054,15 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) } /* some custom element change events get mapped since version 3.0.3 */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; - if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER) || - HAS_CHANGE_EVENT(element, CE_BY_COLLISION)) + if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE) || + HAS_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE)) { - SET_CHANGE_EVENT(element, CE_BY_PLAYER, FALSE); - SET_CHANGE_EVENT(element, CE_BY_COLLISION, FALSE); + SET_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE, FALSE); + SET_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE, FALSE); SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, TRUE); } @@ -1069,7 +1071,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) /* initialize "can_change" field for old levels with only one change page */ if (level->game_version <= VERSION_IDENT(3,0,2,0)) { - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -1092,7 +1094,7 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) } /* set uninitialized push delay values of custom elements in older levels */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -1112,9 +1114,9 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) int x, y; /* map elements that have changed in newer versions */ - for(y=0; yfieldy; y++) + for (y = 0; y < level->fieldy; y++) { - for(x=0; xfieldx; x++) + for (x = 0; x < level->fieldx; x++) { int element = level->field[x][y]; @@ -1142,8 +1144,8 @@ static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename) } /* copy elements to runtime playfield array */ - for(x=0; xfield[x][y]; /* initialize level size variables for faster access */ @@ -1200,15 +1202,15 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level) putFile16BitBE(file, level->time); putFile16BitBE(file, level->gems_needed); - for(i=0; iname[i]); - for(i=0; iscore[i]); - for(i=0; iencoding_16bit_yamyam ? EL_EMPTY : level->yamyam_content[i][x][y])); putFile8Bit(file, level->amoeba_speed); @@ -1230,7 +1232,7 @@ static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level) { int i; - for(i=0; iauthor[i]); } @@ -1238,8 +1240,8 @@ static void SaveLevel_BODY(FILE *file, struct LevelInfo *level) { int x, y; - for(y=0; yfieldy; y++) - for(x=0; xfieldx; x++) + for (y = 0; y < level->fieldy; y++) + for (x = 0; x < level->fieldx; x++) if (level->encoding_16bit_field) putFile16BitBE(file, level->field[x][y]); else @@ -1256,9 +1258,9 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level) putFile8Bit(file, 0); putFile8Bit(file, 0); - for(i=0; iencoding_16bit_field) putFile16BitBE(file, level->yamyam_content[i][x][y]); else @@ -1278,9 +1280,9 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element) content_xsize = 3; content_ysize = 3; - for(i=0; iyamyam_content[i][x][y]; } else if (element == EL_BD_AMOEBA) @@ -1289,9 +1291,9 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element) content_xsize = 1; content_ysize = 1; - for(i=0; iamoeba_content; } @@ -1311,9 +1313,9 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element) WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED); - for(i=0; ienvelope_text[envelope_nr][i]); } @@ -1342,7 +1344,7 @@ static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level, putFile16BitBE(file, num_changed_custom_elements); - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -1371,7 +1373,7 @@ static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level, putFile16BitBE(file, num_changed_custom_elements); - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -1400,7 +1402,7 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, putFile16BitBE(file, num_changed_custom_elements); - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -1410,7 +1412,7 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, { putFile16BitBE(file, element); - for(j=0; jevents); @@ -1455,8 +1457,8 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, putFile8Bit(file, element_info[element].change->random); putFile8Bit(file, element_info[element].change->power); - for(y=0; y<3; y++) - for(x=0; x<3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) putFile16BitBE(file, element_info[element].change->content[x][y]); putFile8Bit(file, element_info[element].slippery_type); @@ -1481,7 +1483,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) putFile16BitBE(file, element); - for(i=0; i < MAX_ELEMENT_NAME_LEN; i++) + for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++) putFile8Bit(file, ei->description[i]); putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]); @@ -1511,8 +1513,8 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) putFile8Bit(file, ei->slippery_type); - for(y=0; y<3; y++) - for(x=0; x<3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) putFile16BitBE(file, ei->content[x][y]); /* some free bytes for future custom property values and padding */ @@ -1520,7 +1522,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) /* write change property values */ - for (i=0; i < ei->num_change_pages; i++) + for (i = 0; i < ei->num_change_pages; i++) { struct ElementChangeInfo *change = &ei->change_page[i]; @@ -1542,8 +1544,8 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) putFile8Bit(file, change->random); putFile8Bit(file, change->power); - for(y=0; y<3; y++) - for(x=0; x<3; x++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) putFile16BitBE(file, change->content[x][y]); putFile8Bit(file, change->can_change); @@ -1572,16 +1574,16 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) /* check level field for 16-bit elements */ level->encoding_16bit_field = FALSE; - for(y=0; yfieldy; y++) - for(x=0; xfieldx; x++) + for (y = 0; y < level->fieldy; y++) + for (x = 0; x < level->fieldx; x++) if (level->field[x][y] > 255) level->encoding_16bit_field = TRUE; /* check yamyam content for 16-bit elements */ level->encoding_16bit_yamyam = FALSE; - for(i=0; inum_yamyam_contents; i++) - for(y=0; y<3; y++) - for(x=0; x<3; x++) + for (i = 0; i < level->num_yamyam_contents; i++) + for (y = 0; y < 3; y++) + for (x = 0; x < 3; x++) if (level->yamyam_content[i][x][y] > 255) level->encoding_16bit_yamyam = TRUE; @@ -1623,7 +1625,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) } /* check for envelope content */ - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { if (strlen(level->envelope_text[i]) > 0) { @@ -1637,7 +1639,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename) /* check for non-default custom elements (unless using template level) */ if (!level->use_custom_template) { - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -1713,7 +1715,7 @@ static void setTapeInfoToDefaults() /* default values (also for pre-1.2 tapes) with only the first player */ tape.player_participates[0] = TRUE; - for(i=1; inum_participating_players = 0; - for(i=0; iplayer_participates[i] = FALSE; @@ -1785,7 +1787,7 @@ static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape) tape->level_identifier = checked_realloc(tape->level_identifier, level_identifier_size); - for(i=0; i < level_identifier_size; i++) + for (i = 0; i < level_identifier_size; i++) tape->level_identifier[i] = getFile8Bit(file); tape->level_nr = getFile16BitBE(file); @@ -1807,12 +1809,12 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape) return chunk_size_expected; } - for(i=0; ilength; i++) + for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPELEN) break; - for(j=0; jpos[i].action[j] = MV_NO_MOVING; @@ -1831,7 +1833,7 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape) byte action = tape->pos[i].action[0]; int k, num_moves = 0; - for (k=0; k<4; k++) + for (k = 0; k<4; k++) { if (action & joy_dir[k]) { @@ -1860,7 +1862,7 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape) tape->pos[i + 1].delay = 1; /* delay part */ - for(j=0; jpos[i].action[j] = MV_NO_MOVING; tape->pos[i].delay--; @@ -2009,6 +2011,13 @@ void LoadTape(int level_nr) LoadTapeFromFilename(filename); } +void LoadSolutionTape(int level_nr) +{ + char *filename = getSolutionTapeFilename(level_nr); + + LoadTapeFromFilename(filename); +} + static void SaveTape_VERS(FILE *file, struct TapeInfo *tape) { putFileVersion(file, tape->file_version); @@ -2021,7 +2030,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape) byte store_participating_players = 0; /* set bits for participating players for compact storage */ - for(i=0; iplayer_participates[i]) store_participating_players |= (1 << i); @@ -2044,7 +2053,7 @@ static void SaveTape_INFO(FILE *file, struct TapeInfo *tape) putFile16BitBE(file, level_identifier_size); - for(i=0; i < level_identifier_size; i++) + for (i = 0; i < level_identifier_size; i++) putFile8Bit(file, tape->level_identifier[i]); putFile16BitBE(file, tape->level_nr); @@ -2054,9 +2063,9 @@ static void SaveTape_BODY(FILE *file, struct TapeInfo *tape) { int i, j; - for(i=0; ilength; i++) + for (i = 0; i < tape->length; i++) { - for(j=0; jplayer_participates[j]) putFile8Bit(file, tape->pos[i].action[j]); @@ -2094,7 +2103,7 @@ void SaveTape(int level_nr) tape.game_version = GAME_VERSION_ACTUAL; /* count number of participating players */ - for(i=0; ilevel_identifier); printf_line("-", 79); - for(i=0; ilength; i++) + for (i = 0; i < tape->length; i++) { if (i >= MAX_TAPELEN) break; printf("%03d: ", i); - for(j=0; jplayer_participates[j]) { @@ -2187,7 +2196,7 @@ void LoadScore(int level_nr) FILE *file; /* always start with reliable default values */ - for(i=0; ieditor.el_custom_more = FALSE; si->editor.el_headlines = TRUE; + si->editor.el_user_defined = FALSE; si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME; si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME; si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE; - for (i=0; iinput[i].use_joystick = FALSE; si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i)); @@ -2525,34 +2537,34 @@ static void decodeSetupFileHash(SetupFileHash *setup_file_hash) /* global setup */ si = setup; - for (i=0; inext) + (*num_elements)++; + + /* add space for up to 3 more elements for padding that may be needed */ + *num_elements += 3; + + *elements = checked_malloc(*num_elements * sizeof(int)); + + *num_elements = 0; + for (list = setup_file_list; list != NULL; list = list->next) + { + char *value = getHashEntry(element_hash, list->token); + + if (value) + { + (*elements)[(*num_elements)++] = atoi(value); + } + else + { + if (num_unknown_tokens == 0) + { + Error(ERR_RETURN_LINE, "-"); + Error(ERR_RETURN, "warning: unknown token(s) found in config file:"); + Error(ERR_RETURN, "- config file: '%s'", filename); + + num_unknown_tokens++; + } + + Error(ERR_RETURN, "- token: '%s'", list->token); + } + } + + if (num_unknown_tokens > 0) + Error(ERR_RETURN_LINE, "-"); + + while (*num_elements % 4) /* pad with empty elements, if needed */ + (*elements)[(*num_elements)++] = EL_EMPTY; + + freeSetupFileList(setup_file_list); + freeSetupFileHash(element_hash); + +#if 0 + /* TEST-ONLY */ + for (i = 0; i < *num_elements; i++) + printf("editor: element '%s' [%d]\n", + element_info[(*elements)[i]].token_name, (*elements)[i]); +#endif +} + +static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music, + boolean is_sound) +{ + SetupFileHash *setup_file_hash = NULL; + struct MusicFileInfo tmp_music_file_info, *new_music_file_info; + char *filename_music, *filename_prefix, *filename_info; + struct + { + char *token; + char **value_ptr; + } + token_to_value_ptr[] = + { + { "title_header", &tmp_music_file_info.title_header }, + { "artist_header", &tmp_music_file_info.artist_header }, + { "album_header", &tmp_music_file_info.album_header }, + { "year_header", &tmp_music_file_info.year_header }, + + { "title", &tmp_music_file_info.title }, + { "artist", &tmp_music_file_info.artist }, + { "album", &tmp_music_file_info.album }, + { "year", &tmp_music_file_info.year }, + + { NULL, NULL }, + }; + int i; + + filename_music = (is_sound ? getCustomSoundFilename(basename) : + getCustomMusicFilename(basename)); + + if (filename_music == NULL) + return NULL; + + /* ---------- try to replace file extension ---------- */ + + filename_prefix = getStringCopy(filename_music); + if (strrchr(filename_prefix, '.') != NULL) + *strrchr(filename_prefix, '.') = '\0'; + filename_info = getStringCat2(filename_prefix, ".txt"); + +#if 0 + printf("trying to load file '%s'...\n", filename_info); +#endif + + if (fileExists(filename_info)) + setup_file_hash = loadSetupFileHash(filename_info); + + free(filename_prefix); + free(filename_info); + + if (setup_file_hash == NULL) + { + /* ---------- try to add file extension ---------- */ + + filename_prefix = getStringCopy(filename_music); + filename_info = getStringCat2(filename_prefix, ".txt"); + +#if 0 + printf("trying to load file '%s'...\n", filename_info); +#endif + + if (fileExists(filename_info)) + setup_file_hash = loadSetupFileHash(filename_info); + + free(filename_prefix); + free(filename_info); + } + + if (setup_file_hash == NULL) + return NULL; + + /* ---------- music file info found ---------- */ + + memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo)); + + for (i = 0; token_to_value_ptr[i].token != NULL; i++) + { + char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token); + + *token_to_value_ptr[i].value_ptr = + getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME); + } + + tmp_music_file_info.basename = getStringCopy(basename); + tmp_music_file_info.music = music; + tmp_music_file_info.is_sound = is_sound; + + new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo)); + *new_music_file_info = tmp_music_file_info; + + return new_music_file_info; +} + +static struct MusicFileInfo *get_music_file_info(char *basename, int music) +{ + return get_music_file_info_ext(basename, music, FALSE); +} + +static struct MusicFileInfo *get_sound_file_info(char *basename, int sound) +{ + return get_music_file_info_ext(basename, sound, TRUE); +} + +static boolean music_info_listed_ext(struct MusicFileInfo *list, + char *basename, boolean is_sound) +{ + for (; list != NULL; list = list->next) + if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0) + return TRUE; + + return FALSE; +} + +static boolean music_info_listed(struct MusicFileInfo *list, char *basename) +{ + return music_info_listed_ext(list, basename, FALSE); +} + +static boolean sound_info_listed(struct MusicFileInfo *list, char *basename) +{ + return music_info_listed_ext(list, basename, TRUE); +} + +void LoadMusicInfo() +{ + char *music_directory = getCustomMusicDirectory(); + int num_music = getMusicListSize(); + int num_music_noconf = 0; + int num_sounds = getSoundListSize(); + DIR *dir; + struct dirent *dir_entry; + struct FileInfo *music, *sound; + struct MusicFileInfo *next, **new; + int i; + + while (music_file_info != NULL) + { + next = music_file_info->next; + + checked_free(music_file_info->basename); + + checked_free(music_file_info->title_header); + checked_free(music_file_info->artist_header); + checked_free(music_file_info->album_header); + checked_free(music_file_info->year_header); + + checked_free(music_file_info->title); + checked_free(music_file_info->artist); + checked_free(music_file_info->album); + checked_free(music_file_info->year); + + free(music_file_info); + + music_file_info = next; + } + + new = &music_file_info; + +#if 0 + printf("::: num_music == %d\n", num_music); +#endif + + for (i = 0; i < num_music; i++) + { + music = getMusicListEntry(i); + +#if 0 + printf("::: %d [%08x]\n", i, music->filename); +#endif + + if (music->filename == NULL) + continue; + + if (strcmp(music->filename, UNDEFINED_FILENAME) == 0) + continue; + + /* a configured file may be not recognized as music */ + if (!FileIsMusic(music->filename)) + continue; + +#if 0 + printf("::: -> '%s' (configured)\n", music->filename); +#endif + + if (!music_info_listed(music_file_info, music->filename)) + { + *new = get_music_file_info(music->filename, i); + if (*new != NULL) + new = &(*new)->next; + } + } + + if ((dir = opendir(music_directory)) == NULL) + { + Error(ERR_WARN, "cannot read music directory '%s'", music_directory); + return; + } + + while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ + { + char *basename = dir_entry->d_name; + boolean music_already_used = FALSE; + int i; + + for (i = 0; i < num_music; i++) + { + music = getMusicListEntry(i); + + if (music->filename == NULL) + continue; + + if (strcmp(basename, music->filename) == 0) + { + music_already_used = TRUE; + break; + } + } + + if (music_already_used) + continue; + + if (!FileIsMusic(basename)) + continue; + +#if 0 + printf("::: -> '%s' (found in directory)\n", basename); +#endif + + if (!music_info_listed(music_file_info, basename)) + { + *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf)); + if (*new != NULL) + new = &(*new)->next; + } + + num_music_noconf++; + } + + closedir(dir); + + for (i = 0; i < num_sounds; i++) + { + sound = getSoundListEntry(i); + + if (sound->filename == NULL) + continue; + + if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0) + continue; + + /* a configured file may be not recognized as sound */ + if (!FileIsSound(sound->filename)) + continue; + +#if 0 + printf("::: -> '%s' (configured)\n", sound->filename); +#endif + + if (!sound_info_listed(music_file_info, sound->filename)) + { + *new = get_sound_file_info(sound->filename, i); + if (*new != NULL) + new = &(*new)->next; + } + } + +#if 0 + /* TEST-ONLY */ + for (next = music_file_info; next != NULL; next = next->next) + printf("::: title == '%s'\n", next->title); +#endif +} + +void add_helpanim_entry(int element, int action, int direction, int delay, + int *num_list_entries) +{ + struct HelpAnimInfo *new_list_entry; + (*num_list_entries)++; + + helpanim_info = + checked_realloc(helpanim_info, + *num_list_entries * sizeof(struct HelpAnimInfo)); + new_list_entry = &helpanim_info[*num_list_entries - 1]; + + new_list_entry->element = element; + new_list_entry->action = action; + new_list_entry->direction = direction; + new_list_entry->delay = delay; +} + +void print_unknown_token(char *filename, char *token, int token_nr) +{ + if (token_nr == 0) + { + Error(ERR_RETURN_LINE, "-"); + Error(ERR_RETURN, "warning: unknown token(s) found in config file:"); + Error(ERR_RETURN, "- config file: '%s'", filename); + } + + Error(ERR_RETURN, "- token: '%s'", token); +} + +void print_unknown_token_end(int token_nr) +{ + if (token_nr > 0) + Error(ERR_RETURN_LINE, "-"); +} + +void LoadHelpAnimInfo() +{ + char *filename = getHelpAnimFilename(); + SetupFileList *setup_file_list = NULL, *list; + SetupFileHash *element_hash, *action_hash, *direction_hash; + int num_list_entries = 0; + int num_unknown_tokens = 0; + int i; + + if (fileExists(filename)) + setup_file_list = loadSetupFileList(filename); + + if (setup_file_list == NULL) + { + /* use reliable default values from static configuration */ + SetupFileList *insert_ptr; + + insert_ptr = setup_file_list = + newSetupFileList(helpanim_config[0].token, + helpanim_config[0].value); + + for (i = 1; helpanim_config[i].token; i++) + insert_ptr = addListEntry(insert_ptr, + helpanim_config[i].token, + helpanim_config[i].value); + } + + element_hash = newSetupFileHash(); + action_hash = newSetupFileHash(); + direction_hash = newSetupFileHash(); + + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + setHashEntry(element_hash, element_info[i].token_name, i_to_a(i)); + + for (i = 0; i < NUM_ACTIONS; i++) + setHashEntry(action_hash, element_action_info[i].suffix, + i_to_a(element_action_info[i].value)); + + /* do not store direction index (bit) here, but direction value! */ + for (i = 0; i < NUM_DIRECTIONS; i++) + setHashEntry(direction_hash, element_direction_info[i].suffix, + i_to_a(1 << element_direction_info[i].value)); + + for (list = setup_file_list; list != NULL; list = list->next) + { + char *element_token, *action_token, *direction_token; + char *element_value, *action_value, *direction_value; + int delay = atoi(list->value); + + if (strcmp(list->token, "end") == 0) + { + add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries); + + continue; + } + + /* first try to break element into element/action/direction parts; + if this does not work, also accept combined "element[.act][.dir]" + elements (like "dynamite.active"), which are unique elements */ + + if (strchr(list->token, '.') == NULL) /* token contains no '.' */ + { + element_value = getHashEntry(element_hash, list->token); + if (element_value != NULL) /* element found */ + add_helpanim_entry(atoi(element_value), -1, -1, delay, + &num_list_entries); + else + { + /* no further suffixes found -- this is not an element */ + print_unknown_token(filename, list->token, num_unknown_tokens++); + } + + continue; + } + + /* token has format "." */ + + action_token = strchr(list->token, '.'); /* suffix may be action ... */ + direction_token = action_token; /* ... or direction */ + + element_token = getStringCopy(list->token); + *strchr(element_token, '.') = '\0'; + + element_value = getHashEntry(element_hash, element_token); + + if (element_value == NULL) /* this is no element */ + { + element_value = getHashEntry(element_hash, list->token); + if (element_value != NULL) /* combined element found */ + add_helpanim_entry(atoi(element_value), -1, -1, delay, + &num_list_entries); + else + print_unknown_token(filename, list->token, num_unknown_tokens++); + + free(element_token); + + continue; + } + + action_value = getHashEntry(action_hash, action_token); + + if (action_value != NULL) /* action found */ + { + add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay, + &num_list_entries); + + free(element_token); + + continue; + } + + direction_value = getHashEntry(direction_hash, direction_token); + + if (direction_value != NULL) /* direction found */ + { + add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay, + &num_list_entries); + + free(element_token); + + continue; + } + + if (strchr(action_token + 1, '.') == NULL) + { + /* no further suffixes found -- this is not an action nor direction */ + + element_value = getHashEntry(element_hash, list->token); + if (element_value != NULL) /* combined element found */ + add_helpanim_entry(atoi(element_value), -1, -1, delay, + &num_list_entries); + else + print_unknown_token(filename, list->token, num_unknown_tokens++); + + free(element_token); + + continue; + } + + /* token has format ".." */ + + direction_token = strchr(action_token + 1, '.'); + + action_token = getStringCopy(action_token); + *strchr(action_token + 1, '.') = '\0'; + + action_value = getHashEntry(action_hash, action_token); + + if (action_value == NULL) /* this is no action */ + { + element_value = getHashEntry(element_hash, list->token); + if (element_value != NULL) /* combined element found */ + add_helpanim_entry(atoi(element_value), -1, -1, delay, + &num_list_entries); + else + print_unknown_token(filename, list->token, num_unknown_tokens++); + + free(element_token); + free(action_token); + + continue; + } + + direction_value = getHashEntry(direction_hash, direction_token); + + if (direction_value != NULL) /* direction found */ + { + add_helpanim_entry(atoi(element_value), atoi(action_value), + atoi(direction_value), delay, &num_list_entries); + + free(element_token); + free(action_token); + + continue; + } + + /* this is no direction */ + + element_value = getHashEntry(element_hash, list->token); + if (element_value != NULL) /* combined element found */ + add_helpanim_entry(atoi(element_value), -1, -1, delay, + &num_list_entries); + else + print_unknown_token(filename, list->token, num_unknown_tokens++); + + free(element_token); + free(action_token); + } + + print_unknown_token_end(num_unknown_tokens); + + add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries); + add_helpanim_entry(HELPANIM_LIST_END, -1, -1, -1, &num_list_entries); + + freeSetupFileList(setup_file_list); + freeSetupFileHash(element_hash); + freeSetupFileHash(action_hash); + freeSetupFileHash(direction_hash); + +#if 0 + /* TEST ONLY */ + for (i = 0; i < num_list_entries; i++) + printf("::: %d, %d, %d => %d\n", + helpanim_info[i].element, + helpanim_info[i].action, + helpanim_info[i].direction, + helpanim_info[i].delay); +#endif +} + +void LoadHelpTextInfo() +{ + char *filename = getHelpTextFilename(); + int i; + + if (helptext_info != NULL) + { + freeSetupFileHash(helptext_info); + helptext_info = NULL; + } + + if (fileExists(filename)) + helptext_info = loadSetupFileHash(filename); + + if (helptext_info == NULL) + { + /* use reliable default values from static configuration */ + helptext_info = newSetupFileHash(); + + for (i = 0; helptext_config[i].token; i++) + setHashEntry(helptext_info, + helptext_config[i].token, + helptext_config[i].value); + } + +#if 0 + /* TEST ONLY */ + BEGIN_HASH_ITERATION(helptext_info, itr) + { + printf("::: '%s' => '%s'\n", + HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr)); + } + END_HASH_ITERATION(hash, itr) +#endif +} diff --git a/src/files.h b/src/files.h index 1ae371db..aa9c03e3 100644 --- a/src/files.h +++ b/src/files.h @@ -29,6 +29,7 @@ void DumpLevel(struct LevelInfo *); void LoadTapeFromFilename(char *); void LoadTape(int); +void LoadSolutionTape(int); void SaveTape(int); void DumpTape(struct TapeInfo *); @@ -40,5 +41,9 @@ void SaveSetup(); void LoadCustomElementDescriptions(); void LoadSpecialMenuDesignSettings(); +void LoadUserDefinedEditorElementList(int **, int *); +void LoadMusicInfo(); +void LoadHelpAnimInfo(); +void LoadHelpTextInfo(); #endif /* FILES_H */ diff --git a/src/game.c b/src/game.c index 71013bf5..05e65026 100644 --- a/src/game.c +++ b/src/game.c @@ -144,6 +144,10 @@ Feld[x][y] == EL_EXIT_OPEN || \ Feld[x][y] == EL_ACID)) +#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \ + (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ + IS_FOOD_DARK_YAMYAM(Feld[x][y]))) + #define MOLE_CAN_ENTER_FIELD(x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || (condition))) @@ -182,12 +186,14 @@ static boolean CheckTriggeredElementChange(int, int, int, int); static boolean CheckElementSideChange(int, int, int, int, int, int); static boolean CheckElementChange(int, int, int, int); -static void PlaySoundLevel(int, int, int); -static void PlaySoundLevelNearest(int, int, int); -static void PlaySoundLevelAction(int, int, int); -static void PlaySoundLevelElementAction(int, int, int, int); -static void PlaySoundLevelActionIfLoop(int, int, int); -static void StopSoundLevelActionIfLoop(int, int, int); +static void PlayLevelSound(int, int, int); +static void PlayLevelSoundNearest(int, int, int); +static void PlayLevelSoundAction(int, int, int); +static void PlayLevelSoundElementAction(int, int, int, int); +static void PlayLevelSoundElementActionIfLoop(int, int, int, int); +static void PlayLevelSoundActionIfLoop(int, int, int); +static void StopLevelSoundActionIfLoop(int, int, int); +static void PlayLevelMusic(); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); @@ -754,8 +760,8 @@ void DrawGameDoorValues() { int i, j; - for (i=0; ichange_events = CE_BITMASK_DEFAULT; - for (j=0; j < NUM_CHANGE_EVENTS; j++) + for (j = 0; j < NUM_CHANGE_EVENTS; j++) { ei->event_page_nr[j] = 0; ei->event_page[j] = &ei->change_page[0]; @@ -842,7 +848,7 @@ static void InitGameEngine() } /* add changing elements from pre-defined list */ - for (i=0; change_delay_list[i].element != EL_UNDEFINED; i++) + for (i = 0; change_delay_list[i].element != EL_UNDEFINED; i++) { struct ChangingElementInfo *ch_delay = &change_delay_list[i]; struct ElementInfo *ei = &element_info[ch_delay->element]; @@ -859,16 +865,16 @@ static void InitGameEngine() #if 1 /* add change events from custom element configuration */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; - for (j=0; j < ei->num_change_pages; j++) + for (j = 0; j < ei->num_change_pages; j++) { if (!ei->change_page[j].can_change) continue; - for (k=0; k < NUM_CHANGE_EVENTS; k++) + for (k = 0; k < NUM_CHANGE_EVENTS; k++) { /* only add event page for the first page found with this event */ if (ei->change_page[j].events & CH_EVENT_BIT(k) && @@ -885,7 +891,7 @@ static void InitGameEngine() #else /* add change events from custom element configuration */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -898,16 +904,16 @@ static void InitGameEngine() /* ---------- initialize trigger events ---------------------------------- */ /* initialize trigger events information */ - for (i=0; inum_change_pages; j++) + for (j = 0; j < ei->num_change_pages; j++) { if (!ei->change_page[j].can_change) continue; @@ -922,7 +928,7 @@ static void InitGameEngine() } #else /* add trigger events from element change event properties */ - for (i=0; itrigger_element] |= element_info[i].change->events; @@ -931,7 +937,7 @@ static void InitGameEngine() /* ---------- initialize push delay -------------------------------------- */ /* initialize push delay values to default */ - for (i=0; ilights_still_needed = 0; player->friends_still_needed = 0; - for (j=0; j<4; j++) + for (j = 0; j < 4; j++) player->key[j] = FALSE; player->dynabomb_count = 0; @@ -1048,6 +1054,8 @@ void InitGame() player->actual_frame_counter = 0; + player->step_counter = 0; + player->last_move_dir = MV_NO_MOVING; player->is_waiting = FALSE; @@ -1058,6 +1066,53 @@ void InitGame() player->is_pushing = FALSE; player->is_switching = FALSE; + player->is_bored = FALSE; + player->is_sleeping = FALSE; + + player->frame_counter_bored = -1; + player->frame_counter_sleeping = -1; + + player->anim_delay_counter = 0; + player->post_delay_counter = 0; + + player->action_waiting = ACTION_DEFAULT; + player->last_action_waiting = ACTION_DEFAULT; + player->special_action_bored = ACTION_DEFAULT; + player->special_action_sleeping = ACTION_DEFAULT; + + player->num_special_action_bored = 0; + player->num_special_action_sleeping = 0; + + /* determine number of special actions for bored and sleeping animation */ + for (j = ACTION_BORING_1; j <= ACTION_BORING_LAST; j++) + { + boolean found = FALSE; + + for (k = 0; k < NUM_DIRECTIONS; k++) + if (el_act_dir2img(player->element_nr, j, k) != + el_act_dir2img(player->element_nr, ACTION_DEFAULT, k)) + found = TRUE; + + if (found) + player->num_special_action_bored++; + else + break; + } + for (j = ACTION_SLEEPING_1; j <= ACTION_SLEEPING_LAST; j++) + { + boolean found = FALSE; + + for (k = 0; k < NUM_DIRECTIONS; k++) + if (el_act_dir2img(player->element_nr, j, k) != + el_act_dir2img(player->element_nr, ACTION_DEFAULT, k)) + found = TRUE; + + if (found) + player->num_special_action_sleeping++; + else + break; + } + player->switch_x = -1; player->switch_y = -1; @@ -1119,18 +1174,18 @@ void InitGame() game.envelope_active = FALSE; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { game.belt_dir[i] = MV_NO_MOVING; game.belt_dir_nr[i] = 3; /* not moving, next moving left */ } - for (i=0; iconnected && !player->present) { - for (j=0; jjx, jy = some_player->jy; @@ -1216,7 +1274,7 @@ void InitGame() { /* when playing a tape, eliminate all players who do not participate */ - for (i=0; iscore < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; - for (k=0; kscore > highscore[k].Score) { @@ -1788,14 +1851,14 @@ int NewHiScore() int m = MAX_SCORE_ENTRIES - 1; #ifdef ONE_PER_NAME - for (l=k; lk; l--) + for (l = m; l > k; l--) { strcpy(highscore[l].Name, highscore[l - 1].Name); highscore[l].Score = highscore[l - 1].Score; @@ -2050,14 +2113,14 @@ void CheckDynamite(int x, int y) if (MovDelay[x][y] != 0) { DrawDynamite(x, y); - PlaySoundLevelActionIfLoop(x, y, ACTION_ACTIVE); + PlayLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); return; } } #if 1 - StopSoundLevelActionIfLoop(x, y, ACTION_ACTIVE); + StopLevelSoundActionIfLoop(x, y, ACTION_ACTIVE); #else if (Feld[x][y] == EL_DYNAMITE_ACTIVE || Feld[x][y] == EL_SP_DISK_RED_ACTIVE) @@ -2170,7 +2233,7 @@ void Explode(int ex, int ey, int phase, int mode) #endif if (mode == EX_NORMAL || mode == EX_CENTER) - PlaySoundLevelAction(ex, ey, ACTION_EXPLODING); + PlayLevelSoundAction(ex, ey, ACTION_EXPLODING); /* remove things displayed in background while burning dynamite */ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) @@ -2184,7 +2247,7 @@ void Explode(int ex, int ey, int phase, int mode) Feld[ex][ey] = center_element; } - for (y = ey - 1; y <= ey + 1; y++) for(x = ex - 1; x <= ex + 1; x++) + for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++) { int xx = x - ex + 1; int yy = y - ey + 1; @@ -2504,9 +2567,9 @@ void DynaExplode(int ex, int ey) Explode(ex, ey, EX_PHASE_START, EX_CENTER); - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { - for (j=1; j<=dynabomb_size; j++) + for (j = 1; j <= dynabomb_size; j++) { int x = ex + j * xy[i % 4][0]; int y = ey + j * xy[i % 4][1]; @@ -2555,12 +2618,12 @@ void Bang(int x, int y) #if 0 #if 1 - PlaySoundLevelAction(x, y, ACTION_EXPLODING); + PlayLevelSoundAction(x, y, ACTION_EXPLODING); #else if (game.emulation == EMU_SUPAPLEX) - PlaySoundLevel(x, y, SND_SP_ELEMENT_EXPLODING); + PlayLevelSound(x, y, SND_SP_ELEMENT_EXPLODING); else - PlaySoundLevel(x, y, SND_ELEMENT_EXPLODING); + PlayLevelSound(x, y, SND_ELEMENT_EXPLODING); #endif #endif @@ -2618,7 +2681,7 @@ void SplashAcid(int x, int y) if (element != EL_ACID_SPLASH_LEFT && element != EL_ACID_SPLASH_RIGHT) { - PlaySoundLevel(x, y, SND_ACID_SPLASHING); + PlayLevelSound(x, y, SND_ACID_SPLASHING); if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) && (!IN_LEV_FIELD(x-1, y-1) || @@ -2652,11 +2715,11 @@ static void InitBeltMovement() int x, y, i, j; /* set frame order for belt animation graphic according to belt direction */ - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int belt_nr = i; - for (j=0; j<3; j++) + for (j = 0; j < 3; j++) { int element = belt_base_active_element[belt_nr] + j; int graphic = el2img(element); @@ -2668,13 +2731,13 @@ static void InitBeltMovement() } } - for(y=0; y rnd_value / 8) MovDir[x][y] = old_move_dir; else if (can_turn_left && can_turn_right) @@ -3402,8 +3472,25 @@ inline static void TurnRoundExt(int x, int y) xx = x + move_xy[MovDir[x][y]].x; yy = y + move_xy[MovDir[x][y]].y; +#if 0 + if (FrameCounter < 1 && x == 0 && y == 29) + printf(":3: %d/%d: %d (%d/%d: %d) [%d]\n", x, y, MovDir[x][y], + xx, yy, Feld[xx][yy], + FrameCounter); +#endif + +#if 1 + if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy)) + MovDir[x][y] = old_move_dir; +#else if (!IS_FREE(xx, yy)) MovDir[x][y] = old_move_dir; +#endif + +#if 0 + if (FrameCounter < 1 && x == 0 && y == 29) + printf(":4: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter); +#endif MovDelay[x][y] = 0; } @@ -3463,7 +3550,7 @@ inline static void TurnRoundExt(int x, int y) { int i; - for (i=0; ijx, jy = player->jy; @@ -3497,7 +3584,7 @@ inline static void TurnRoundExt(int x, int y) { 0, +1 } }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int ex = x + xy[i % 4][0]; int ey = y + xy[i % 4][1]; @@ -3593,16 +3680,16 @@ inline static void TurnRoundExt(int x, int y) } } } - else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS || - element_info[element].move_pattern == MV_TURNING_LEFT || - element_info[element].move_pattern == MV_TURNING_RIGHT) + else if (move_pattern == MV_ALL_DIRECTIONS || + move_pattern == MV_TURNING_LEFT || + move_pattern == MV_TURNING_RIGHT) { boolean can_turn_left = ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y); boolean can_turn_right = ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y); - if (element_info[element].move_pattern == MV_TURNING_LEFT) + if (move_pattern == MV_TURNING_LEFT) MovDir[x][y] = left_dir; - else if (element_info[element].move_pattern == MV_TURNING_RIGHT) + else if (move_pattern == MV_TURNING_RIGHT) MovDir[x][y] = right_dir; else if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); @@ -3615,24 +3702,24 @@ inline static void TurnRoundExt(int x, int y) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_HORIZONTAL || - element_info[element].move_pattern == MV_VERTICAL) + else if (move_pattern == MV_HORIZONTAL || + move_pattern == MV_VERTICAL) { - if (element_info[element].move_pattern & old_move_dir) + if (move_pattern & old_move_dir) MovDir[x][y] = back_dir; - else if (element_info[element].move_pattern == MV_HORIZONTAL) + else if (move_pattern == MV_HORIZONTAL) MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT); - else if (element_info[element].move_pattern == MV_VERTICAL) + else if (move_pattern == MV_VERTICAL) MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN); MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern & MV_ANY_DIRECTION) + else if (move_pattern & MV_ANY_DIRECTION) { - MovDir[x][y] = element_info[element].move_pattern; + MovDir[x][y] = move_pattern; MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_ALONG_LEFT_SIDE) + else if (move_pattern == MV_ALONG_LEFT_SIDE) { if (ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y)) MovDir[x][y] = left_dir; @@ -3642,7 +3729,7 @@ inline static void TurnRoundExt(int x, int y) if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_ALONG_RIGHT_SIDE) + else if (move_pattern == MV_ALONG_RIGHT_SIDE) { if (ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y)) MovDir[x][y] = right_dir; @@ -3652,13 +3739,12 @@ inline static void TurnRoundExt(int x, int y) if (MovDir[x][y] != old_move_dir) MovDelay[x][y] = GET_NEW_MOVE_DELAY(element); } - else if (element_info[element].move_pattern == MV_TOWARDS_PLAYER || - element_info[element].move_pattern == MV_AWAY_FROM_PLAYER) + else if (move_pattern == MV_TOWARDS_PLAYER || + move_pattern == MV_AWAY_FROM_PLAYER) { int attr_x = -1, attr_y = -1; int newx, newy; - boolean move_away = - (element_info[element].move_pattern == MV_AWAY_FROM_PLAYER); + boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER); if (AllPlayersGone) { @@ -3669,7 +3755,7 @@ inline static void TurnRoundExt(int x, int y) { int i; - for (i=0; ijx, jy = player->jy; @@ -3720,13 +3806,84 @@ inline static void TurnRoundExt(int x, int y) MovDir[x][y] = old_move_dir; } } - else if (element_info[element].move_pattern == MV_WHEN_PUSHED) + else if (move_pattern == MV_WHEN_PUSHED) { if (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y)) MovDir[x][y] = MV_NO_MOVING; MovDelay[x][y] = 0; } + else if (move_pattern & MV_MAZE_RUNNER_STYLE || + element == EL_MAZE_RUNNER) + { + static int test_xy[7][2] = + { + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 }, + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + }; + static int test_dir[7] = + { + MV_UP, + MV_LEFT, + MV_RIGHT, + MV_DOWN, + MV_UP, + MV_LEFT, + MV_RIGHT, + }; + boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER); + int move_preference = -1000000; /* start with very low preference */ + int new_move_dir = MV_NO_MOVING; + int start_test = RND(4); + int i; + + for (i = 0; i < 4; i++) + { + int move_dir = test_dir[start_test + i]; + int move_dir_preference; + + xx = x + test_xy[start_test + i][0]; + yy = y + test_xy[start_test + i][1]; + + if (hunter_mode && IN_LEV_FIELD(xx, yy) && + (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING)) + { + new_move_dir = move_dir; + + break; + } + + if (!MAZE_RUNNER_CAN_ENTER_FIELD(xx, yy)) + continue; + + move_dir_preference = -1 * RunnerVisit[xx][yy]; + if (hunter_mode && PlayerVisit[xx][yy] > 0) + move_dir_preference = PlayerVisit[xx][yy]; + + if (move_dir_preference > move_preference) + { + /* prefer field that has not been visited for the longest time */ + move_preference = move_dir_preference; + new_move_dir = move_dir; + } + else if (move_dir_preference == move_preference && + move_dir == old_move_dir) + { + /* prefer last direction when all directions are preferred equally */ + move_preference = move_dir_preference; + new_move_dir = move_dir; + } + } + + MovDir[x][y] = new_move_dir; + if (old_move_dir != new_move_dir) + MovDelay[x][y] = 9; + } } static void TurnRound(int x, int y) @@ -3759,7 +3916,7 @@ static boolean JustBeingPushed(int x, int y) { int i; - for (i=0; ican_change && + change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_ACTIVE) && + change->sides & touched_side && + change->trigger_element == touched_element) + { + CheckElementSideChange(newx, newy, hitting_element, + CH_SIDE_ANY, CE_OTHER_IS_COLL_ACTIVE, i); + break; + } + } + } + + if (IS_CUSTOM_ELEMENT(touched_element) && + HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_IS_COLL_PASSIVE)) + { + for (i = 0; i < element_info[touched_element].num_change_pages; i++) + { + struct ElementChangeInfo *change = + &element_info[touched_element].change_page[i]; + + if (change->can_change && + change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_PASSIVE) && + change->sides & hitting_side && + change->trigger_element == hitting_element) + { + CheckElementSideChange(nextx, nexty, touched_element, + CH_SIDE_ANY, CE_OTHER_IS_COLL_PASSIVE, i); + break; + } + } + } + } + } +#endif + } TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); @@ -4698,7 +4968,7 @@ int AmoebeNachbarNr(int ax, int ay) { 0, +1 } }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int x = ax + xy[i][0]; int y = ay + xy[i][1]; @@ -4728,7 +4998,7 @@ void AmoebenVereinigen(int ax, int ay) if (new_group_nr == 0) return; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { x = ax + xy[i][0]; y = ay + xy[i][1]; @@ -4751,9 +5021,9 @@ void AmoebenVereinigen(int ax, int ay) AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr]; AmoebaCnt2[old_group_nr] = 0; - for (yy=0; yyrandom) return FALSE; - for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++) + for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3 ; xx++) { int ex = x + xx - 1; int ey = y + yy - 1; @@ -5723,14 +5993,14 @@ static boolean ChangeElementNow(int x, int y, int element, int page) } if (something_has_changed) - PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); + PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); } } else { ChangeElementNowExt(x, y, change->target_element); - PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING); + PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); } return TRUE; @@ -5813,7 +6083,7 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly, if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event))) return FALSE; - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -5823,7 +6093,7 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly, if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event)) continue; - for (j=0; j < element_info[element].num_change_pages; j++) + for (j = 0; j < element_info[element].num_change_pages; j++) { struct ElementChangeInfo *change = &element_info[element].change_page[j]; @@ -5850,7 +6120,7 @@ static boolean CheckTriggeredElementSideChange(int lx, int ly, if (!change_element) continue; - for (y=0; yjx, jy = player->jy; + int element = player->element_nr; + int last_action = player->last_action_waiting; + int action = player->action_waiting; + + if (player->is_waiting) + { + if (action != last_action) + PlayLevelSoundElementAction(jx, jy, element, action); + else + PlayLevelSoundElementActionIfLoop(jx, jy, element, action); + } + else + { + if (action != last_action) + StopSound(element_info[element].sound[last_action]); + + if (last_action == ACTION_SLEEPING) + PlayLevelSoundElementAction(jx, jy, element, ACTION_AWAKENING); + } +} + +static void PlayAllPlayersSound() +{ + int i; + + for (i = 0; i < MAX_PLAYERS; i++) + if (stored_player[i].active) + PlayPlayerSound(&stored_player[i]); +} + +static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting) +{ + boolean last_waiting = player->is_waiting; + int move_dir = player->MovDir; + + player->last_action_waiting = player->action_waiting; + + if (is_waiting) + { + if (!last_waiting) /* not waiting -> waiting */ + { + player->is_waiting = TRUE; + + player->frame_counter_bored = + FrameCounter + + game.player_boring_delay_fixed + + SimpleRND(game.player_boring_delay_random); + player->frame_counter_sleeping = + FrameCounter + + game.player_sleeping_delay_fixed + + SimpleRND(game.player_sleeping_delay_random); + + InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir); + } + + if (game.player_sleeping_delay_fixed + + game.player_sleeping_delay_random > 0 && + player->anim_delay_counter == 0 && + player->post_delay_counter == 0 && + FrameCounter >= player->frame_counter_sleeping) + player->is_sleeping = TRUE; + else if (game.player_boring_delay_fixed + + game.player_boring_delay_random > 0 && + FrameCounter >= player->frame_counter_bored) + player->is_bored = TRUE; + + player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING : + player->is_bored ? ACTION_BORING : + ACTION_WAITING); + + if (player->is_sleeping) + { + if (player->num_special_action_sleeping > 0) + { + if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) + { + int last_special_action = player->special_action_sleeping; + int num_special_action = player->num_special_action_sleeping; + int special_action = + (last_special_action == ACTION_DEFAULT ? ACTION_SLEEPING_1 : + last_special_action == ACTION_SLEEPING ? ACTION_SLEEPING : + last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ? + last_special_action + 1 : ACTION_SLEEPING); + int special_graphic = + el_act_dir2img(player->element_nr, special_action, move_dir); + + player->anim_delay_counter = + graphic_info[special_graphic].anim_delay_fixed + + SimpleRND(graphic_info[special_graphic].anim_delay_random); + player->post_delay_counter = + graphic_info[special_graphic].post_delay_fixed + + SimpleRND(graphic_info[special_graphic].post_delay_random); + + player->special_action_sleeping = special_action; + } + + if (player->anim_delay_counter > 0) + { + player->action_waiting = player->special_action_sleeping; + player->anim_delay_counter--; + } + else if (player->post_delay_counter > 0) + { + player->post_delay_counter--; + } + } + } + else if (player->is_bored) + { + if (player->num_special_action_bored > 0) + { + if (player->anim_delay_counter == 0 && player->post_delay_counter == 0) + { + int special_action = + ACTION_BORING_1 + SimpleRND(player->num_special_action_bored); + int special_graphic = + el_act_dir2img(player->element_nr, special_action, move_dir); + + player->anim_delay_counter = + graphic_info[special_graphic].anim_delay_fixed + + SimpleRND(graphic_info[special_graphic].anim_delay_random); + player->post_delay_counter = + graphic_info[special_graphic].post_delay_fixed + + SimpleRND(graphic_info[special_graphic].post_delay_random); + + player->special_action_bored = special_action; + } + + if (player->anim_delay_counter > 0) + { + player->action_waiting = player->special_action_bored; + player->anim_delay_counter--; + } + else if (player->post_delay_counter > 0) + { + player->post_delay_counter--; + } + } + } + } + else if (last_waiting) /* waiting -> not waiting */ + { + player->is_waiting = FALSE; + player->is_bored = FALSE; + player->is_sleeping = FALSE; + + player->frame_counter_bored = -1; + player->frame_counter_sleeping = -1; + + player->anim_delay_counter = 0; + player->post_delay_counter = 0; + + player->action_waiting = ACTION_DEFAULT; + + player->special_action_bored = ACTION_DEFAULT; + player->special_action_sleeping = ACTION_DEFAULT; + } +} + #if 1 static byte PlayerActions(struct PlayerInfo *player, byte player_action) { @@ -5960,6 +6392,8 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) } } + SetPlayerWaiting(player, FALSE); + #if 1 return player_action; #else @@ -5979,7 +6413,7 @@ static byte PlayerActions(struct PlayerInfo *player, byte player_action) CheckGravityMovement(player); if (player->MovPos == 0) - InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir); + SetPlayerWaiting(player, TRUE); if (player->MovPos == 0) /* needed for tape.playing */ player->is_moving = FALSE; @@ -6129,9 +6563,13 @@ void GameActions() if (tape.pausing) return; +#if 0 + printf("::: getting new tape action [%d]\n", FrameCounter); +#endif + recorded_player_action = (tape.playing ? TapePlayAction() : NULL); - for (i=0; ieffective_action = summarized_player_action; - for (i=0; i < MAX_PLAYERS; i++) + for (i = 0; i < MAX_PLAYERS; i++) { int actual_player_action = stored_player[i].effective_action; @@ -6159,6 +6597,9 @@ void GameActions() tape_action[i] = PlayerActions(&stored_player[i], actual_player_action); + if (tape.recording && tape_action[i] && !tape.player_participates[i]) + tape.player_participates[i] = TRUE; /* player just appeared from CE */ + ScrollPlayer(&stored_player[i], SCROLL_GO_ON); } @@ -6175,14 +6616,14 @@ void GameActions() FrameCounter++; TimeFrames++; - for (i=0; ijx; @@ -6203,7 +6644,7 @@ void GameActions() } #endif - for (y=0; y 0) @@ -6511,7 +6952,7 @@ void GameActions() game.magic_wall_time_left--; if (!game.magic_wall_time_left) { - for (y=0; yshield_deadly_time_left) - PlaySoundLevel(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE); + PlayLevelSound(player->jx, player->jy, SND_SHIELD_DEADLY_ACTIVE); else if (player->shield_normal_time_left) - PlaySoundLevel(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE); + PlayLevelSound(player->jx, player->jy, SND_SHIELD_NORMAL_ACTIVE); } } @@ -6568,7 +7009,7 @@ void GameActions() TimeFrames = 0; TimePlayed++; - for (i=0; iMovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value); + player->step_counter++; + + PlayerVisit[jx][jy] = FrameCounter; + ScrollPlayer(player, SCROLL_INIT); #if 0 @@ -7226,7 +7672,7 @@ void TestIfPlayerTouchesCustomElement(int x, int y) int center_element = Feld[x][y]; /* should always be non-moving! */ int i; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; @@ -7284,7 +7730,7 @@ void TestIfElementTouchesCustomElement(int x, int y) }; static int change_sides[4][2] = { - /* center side border side */ + /* center side border side */ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */ @@ -7302,7 +7748,7 @@ void TestIfElementTouchesCustomElement(int x, int y) int center_element = Feld[x][y]; /* should always be non-moving! */ int i, j; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; @@ -7327,7 +7773,7 @@ void TestIfElementTouchesCustomElement(int x, int y) HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) && !change_center_element) { - for (j=0; j < element_info[center_element].num_change_pages; j++) + for (j = 0; j < element_info[center_element].num_change_pages; j++) { struct ElementChangeInfo *change = &element_info[center_element].change_page[j]; @@ -7349,7 +7795,7 @@ void TestIfElementTouchesCustomElement(int x, int y) if (IS_CUSTOM_ELEMENT(border_element) && HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING)) { - for (j=0; j < element_info[border_element].num_change_pages; j++) + for (j = 0; j < element_info[border_element].num_change_pages; j++) { struct ElementChangeInfo *change = &element_info[border_element].change_page[j]; @@ -7390,7 +7836,7 @@ void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir) MV_DOWN }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int test_x, test_y, test_move_dir, test_element; @@ -7465,7 +7911,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) if (bad_element == EL_EXPLOSION) /* skip just exploding bad things */ return; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int test_x, test_y, test_move_dir, test_element; @@ -7569,7 +8015,7 @@ void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y) { 0, +1 } }; - for (i=0; i<4; i++) + for (i = 0; i < 4; i++) { int x, y, element; @@ -7624,11 +8070,11 @@ void BuryHero(struct PlayerInfo *player) return; #if 1 - PlaySoundLevelElementAction(jx, jy, player->element_nr, ACTION_DYING); + PlayLevelSoundElementAction(jx, jy, player->element_nr, ACTION_DYING); #else - PlaySoundLevel(jx, jy, SND_CLASS_PLAYER_DYING); + PlayLevelSound(jx, jy, SND_CLASS_PLAYER_DYING); #endif - PlaySoundLevel(jx, jy, SND_GAME_LOSING); + PlayLevelSound(jx, jy, SND_GAME_LOSING); player->GameOver = TRUE; RemoveHero(player); @@ -7645,7 +8091,7 @@ void RemoveHero(struct PlayerInfo *player) if (!ExplodeField[jx][jy]) StorePlayer[jx][jy] = 0; - for (i=0; iprogrammed_action = move_direction; DOUBLE_PLAYER_SPEED(player); - PlaySoundLevel(x, y, SND_CLASS_SP_PORT_PASSING); + PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING); break; case EL_TUBE_ANY: @@ -7865,7 +8311,7 @@ int DigField(struct PlayerInfo *player, if (!(tube_enter_directions[i][1] & move_direction)) return MF_NO_ACTION; /* tube has no opening in this direction */ - PlaySoundLevel(x, y, SND_CLASS_TUBE_WALKING); + PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING); } break; @@ -7898,9 +8344,9 @@ int DigField(struct PlayerInfo *player, /* play sound from background or player, whatever is available */ if (element_info[element].sound[sound_action] != SND_UNDEFINED) - PlaySoundLevelElementAction(x, y, element, sound_action); + PlayLevelSoundElementAction(x, y, element, sound_action); else - PlaySoundLevelElementAction(x, y, player->element_nr, sound_action); + PlayLevelSoundElementAction(x, y, player->element_nr, sound_action); break; } @@ -7929,7 +8375,7 @@ int DigField(struct PlayerInfo *player, player->programmed_action = move_direction; DOUBLE_PLAYER_SPEED(player); - PlaySoundLevelAction(x, y, ACTION_PASSING); + PlayLevelSoundAction(x, y, ACTION_PASSING); break; } @@ -7948,7 +8394,7 @@ int DigField(struct PlayerInfo *player, player->is_digging = TRUE; } - PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING); + PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING); CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED); @@ -8027,7 +8473,7 @@ int DigField(struct PlayerInfo *player, { int i; - for (i=0; i < element_info[element].collect_count; i++) + for (i = 0; i < element_info[element].collect_count; i++) if (player->inventory_size < MAX_INVENTORY_SIZE) player->inventory_element[player->inventory_size++] = element; @@ -8046,7 +8492,7 @@ int DigField(struct PlayerInfo *player, } RaiseScoreElement(element); - PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING); + PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING); CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED); @@ -8170,23 +8616,23 @@ int DigField(struct PlayerInfo *player, Feld[x][y] = EL_SOKOBAN_OBJECT; if (Back[x][y] == Back[nextx][nexty]) - PlaySoundLevelAction(x, y, ACTION_PUSHING); + PlayLevelSoundAction(x, y, ACTION_PUSHING); else if (Back[x][y] != 0) - PlaySoundLevelElementAction(x, y, EL_SOKOBAN_FIELD_FULL, + PlayLevelSoundElementAction(x, y, EL_SOKOBAN_FIELD_FULL, ACTION_EMPTYING); else - PlaySoundLevelElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, + PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY, ACTION_FILLING); if (local_player->sokobanfields_still_needed == 0 && game.emulation == EMU_SOKOBAN) { player->LevelSolved = player->GameOver = TRUE; - PlaySoundLevel(x, y, SND_GAME_SOKOBAN_SOLVING); + PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING); } } else - PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); + PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING); InitMovingField(x, y, move_direction); GfxAction[x][y] = ACTION_PUSHING; @@ -8220,7 +8666,7 @@ int DigField(struct PlayerInfo *player, player->switch_x = x; player->switch_y = y; - PlaySoundLevelElementAction(x, y, element, ACTION_ACTIVATING); + PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING); if (element == EL_ROBOT_WHEEL) { @@ -8234,7 +8680,7 @@ int DigField(struct PlayerInfo *player, { int xx, yy; - for (yy=0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++) + for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++) { if (Feld[xx][yy] == EL_SP_DISK_YELLOW) Bang(xx, yy); @@ -8257,7 +8703,7 @@ int DigField(struct PlayerInfo *player, ToggleLightSwitch(x, y); #if 0 - PlaySoundLevel(x, y, element == EL_LIGHT_SWITCH ? + PlayLevelSound(x, y, element == EL_LIGHT_SWITCH ? SND_LIGHT_SWITCH_ACTIVATING : SND_LIGHT_SWITCH_DEACTIVATING); #endif @@ -8438,7 +8884,7 @@ boolean DropElement(struct PlayerInfo *player) if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0); - PlaySoundLevelAction(jx, jy, ACTION_DROPPING); + PlayLevelSoundAction(jx, jy, ACTION_DROPPING); CheckTriggeredElementChange(jx, jy, new_element, CE_OTHER_GETS_DROPPED); CheckElementChange(jx, jy, new_element, CE_DROPPED_BY_PLAYER); @@ -8455,7 +8901,7 @@ boolean DropElement(struct PlayerInfo *player) if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0); - PlaySoundLevelAction(jx, jy, ACTION_DROPPING); + PlayLevelSoundAction(jx, jy, ACTION_DROPPING); } return TRUE; @@ -8468,21 +8914,18 @@ boolean DropElement(struct PlayerInfo *player) static int *loop_sound_frame = NULL; static int *loop_sound_volume = NULL; -void InitPlaySoundLevel() +void InitPlayLevelSound() { int num_sounds = getSoundListSize(); - if (loop_sound_frame != NULL) - free(loop_sound_frame); - - if (loop_sound_volume != NULL) - free(loop_sound_volume); + checked_free(loop_sound_frame); + checked_free(loop_sound_volume); - loop_sound_frame = checked_calloc(num_sounds * sizeof(int)); + loop_sound_frame = checked_calloc(num_sounds * sizeof(int)); loop_sound_volume = checked_calloc(num_sounds * sizeof(int)); } -static void PlaySoundLevel(int x, int y, int nr) +static void PlayLevelSound(int x, int y, int nr) { int sx = SCREENX(x), sy = SCREENY(y); int volume, stereo_position; @@ -8527,42 +8970,59 @@ static void PlaySoundLevel(int x, int y, int nr) PlaySoundExt(nr, volume, stereo_position, type); } -static void PlaySoundLevelNearest(int x, int y, int sound_action) +static void PlayLevelSoundNearest(int x, int y, int sound_action) { - PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) : + PlayLevelSound(x < LEVELX(BX1) ? LEVELX(BX1) : x > LEVELX(BX2) ? LEVELX(BX2) : x, y < LEVELY(BY1) ? LEVELY(BY1) : y > LEVELY(BY2) ? LEVELY(BY2) : y, sound_action); } -static void PlaySoundLevelAction(int x, int y, int action) +static void PlayLevelSoundAction(int x, int y, int action) { - PlaySoundLevelElementAction(x, y, Feld[x][y], action); + PlayLevelSoundElementAction(x, y, Feld[x][y], action); } -static void PlaySoundLevelElementAction(int x, int y, int element, int action) +static void PlayLevelSoundElementAction(int x, int y, int element, int action) { int sound_effect = element_info[element].sound[action]; if (sound_effect != SND_UNDEFINED) - PlaySoundLevel(x, y, sound_effect); + PlayLevelSound(x, y, sound_effect); } -static void PlaySoundLevelActionIfLoop(int x, int y, int action) +static void PlayLevelSoundElementActionIfLoop(int x, int y, int element, + int action) +{ + int sound_effect = element_info[element].sound[action]; + + if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) + PlayLevelSound(x, y, sound_effect); +} + +static void PlayLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[Feld[x][y]].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) - PlaySoundLevel(x, y, sound_effect); + PlayLevelSound(x, y, sound_effect); } -static void StopSoundLevelActionIfLoop(int x, int y, int action) +static void StopLevelSoundActionIfLoop(int x, int y, int action) { int sound_effect = element_info[Feld[x][y]].sound[action]; if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect)) - StopSoundExt(sound_effect, SND_CTRL_STOP_SOUND); + StopSound(sound_effect); +} + +static void PlayLevelMusic() +{ + if (levelset.music[level_nr] != MUS_UNDEFINED) + PlayMusic(levelset.music[level_nr]); /* from config file */ + else + PlayMusic(MAP_NOCONF_MUSIC(level_nr)); /* from music dir */ } void RaiseScore(int value) @@ -8726,7 +9186,7 @@ void CreateGameButtons() { int i; - for (i=0; iclip_mask) { @@ -147,11 +149,11 @@ static void InitTileClipmasks() clip_gc_valuemask, &clip_gc_values); /* create only those clipping Pixmaps we really need */ - for (i=0; tile_needs_clipping[i].start>=0; i++) + for (i = 0; tile_needs_clipping[i].start >= 0; i++) { int j; - for (j=0; jstored_clip_gc) { @@ -244,15 +246,15 @@ void InitElementSmallImages() int i; /* initialize normal images from static configuration */ - for (i=0; element_to_graphic[i].element > -1; i++) + for (i = 0; element_to_graphic[i].element > -1; i++) CreateImageWithSmallImages(element_to_graphic[i].graphic); /* initialize special images from static configuration */ - for (i=0; element_to_special_graphic[i].element > -1; i++) + for (i = 0; element_to_special_graphic[i].element > -1; i++) CreateImageWithSmallImages(element_to_special_graphic[i].graphic); /* initialize images from dynamic configuration */ - for (i=0; i < num_property_mappings; i++) + for (i = 0; i < num_property_mappings; i++) if (property_mapping[i].artwork_index < MAX_NUM_ELEMENTS) CreateImageWithSmallImages(property_mapping[i].artwork_index); } @@ -293,15 +295,15 @@ void InitFontGraphicInfo() /* always start with reliable default values (normal font graphics) */ #if 1 - for (i=0; i < NUM_FONTS; i++) + for (i = 0; i < NUM_FONTS; i++) font_info[i].graphic = IMG_FONT_INITIAL_1; #else - for (i=0; i < NUM_FONTS; i++) + for (i = 0; i < NUM_FONTS; i++) font_info[i].graphic = FONT_INITIAL_1; #endif /* initialize normal font/graphic mapping from static configuration */ - for (i=0; font_to_graphic[i].font_nr > -1; i++) + for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; @@ -314,9 +316,9 @@ void InitFontGraphicInfo() } /* always start with reliable default values (special font graphics) */ - for (i=0; i < NUM_FONTS; i++) + for (i = 0; i < NUM_FONTS; i++) { - for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++) + for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { font_info[i].special_graphic[j] = font_info[i].graphic; font_info[i].special_bitmap_id[j] = i; @@ -324,7 +326,7 @@ void InitFontGraphicInfo() } /* initialize special font/graphic mapping from static configuration */ - for (i=0; font_to_graphic[i].font_nr > -1; i++) + for (i = 0; font_to_graphic[i].font_nr > -1; i++) { int font_nr = font_to_graphic[i].font_nr; int special = font_to_graphic[i].special; @@ -339,7 +341,7 @@ void InitFontGraphicInfo() } /* initialize special element/graphic mapping from dynamic configuration */ - for (i=0; i < num_property_mappings; i++) + for (i = 0; i < num_property_mappings; i++) { int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS; int special = property_mapping[i].ext3_index; @@ -366,7 +368,7 @@ void InitFontGraphicInfo() /* ---------- initialize font bitmap definitions ---------- */ - for (i=0; i < NUM_FONTS; i++) + for (i = 0; i < NUM_FONTS; i++) { if (i < NUM_INITIAL_FONTS) { @@ -374,7 +376,7 @@ void InitFontGraphicInfo() continue; } - for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++) + for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) { int font_bitmap_id = font_info[i].special_bitmap_id[j]; int graphic = font_info[i].special_graphic[j]; @@ -412,14 +414,14 @@ void InitElementGraphicInfo() int i, act, dir; /* set values to -1 to identify later as "uninitialized" values */ - for (i=0; i -1; i++) + for (i = 0; element_to_graphic[i].element > -1; i++) { int element = element_to_graphic[i].element; int action = element_to_graphic[i].action; @@ -473,7 +475,7 @@ void InitElementGraphicInfo() } /* initialize normal element/graphic mapping from dynamic configuration */ - for (i=0; i < num_property_mappings; i++) + for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; @@ -500,7 +502,7 @@ void InitElementGraphicInfo() if (crumbled) { if (direction < 0) - for (dir=0; dir -1) @@ -511,7 +513,7 @@ void InitElementGraphicInfo() else { if (direction < 0) - for (dir=0; dir -1) @@ -522,7 +524,7 @@ void InitElementGraphicInfo() } /* now copy all graphics that are defined to be cloned from other graphics */ - for (i=0; i 0 && graphic_info[graphic].bitmap == NULL) element_info[i].crumbled[act] = -1; - for (dir=0; dir 0 && graphic_info[graphic].bitmap == NULL) @@ -585,7 +587,7 @@ void InitElementGraphicInfo() #endif /* now set all '-1' values to element specific default values */ - for (i=0; i -1; i++) + for (i = 0; element_to_special_graphic[i].element > -1; i++) { int element = element_to_special_graphic[i].element; int special = element_to_special_graphic[i].special; @@ -759,7 +761,7 @@ void InitElementSpecialGraphicInfo() } /* initialize special element/graphic mapping from dynamic configuration */ - for (i=0; i < num_property_mappings; i++) + for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int special = property_mapping[i].ext3_index; @@ -774,8 +776,8 @@ void InitElementSpecialGraphicInfo() #if 1 /* now set all undefined/invalid graphics to default */ - for (i=0; i < MAX_NUM_ELEMENTS; i++) - for (j=0; j < NUM_SPECIAL_GFX_ARGS; j++) + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++) if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL) element_info[i].special_graphic[j] = element_info[i].graphic[ACTION_DEFAULT]; @@ -786,7 +788,7 @@ static int get_element_from_token(char *token) { int i; - for (i=0; i < MAX_NUM_ELEMENTS; i++) + for (i = 0; i < MAX_NUM_ELEMENTS; i++) if (strcmp(element_info[i].token_name, token) == 0) return i; @@ -802,7 +804,7 @@ static void set_graphic_parameters(int graphic, char **parameter_raw) int i; /* get integer values from string parameters */ - for (i=0; i < NUM_GFX_ARGS; i++) + for (i = 0; i < NUM_GFX_ARGS; i++) { parameter[i] = get_parameter_value(image_config_suffix[i].token, parameter_raw[i], @@ -824,6 +826,10 @@ static void set_graphic_parameters(int graphic, char **parameter_raw) graphic_info[graphic].crumbled_like = -1; /* do not use clone element */ graphic_info[graphic].diggable_like = -1; /* do not use clone element */ graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */ + graphic_info[graphic].anim_delay_fixed = 0; + graphic_info[graphic].anim_delay_random = 0; + graphic_info[graphic].post_delay_fixed = 0; + graphic_info[graphic].post_delay_random = 0; /* optional x and y tile position of animation frame sequence */ if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE) @@ -919,6 +925,20 @@ static void set_graphic_parameters(int graphic, char **parameter_raw) if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE) graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE]; + /* this is only used for player "boring" and "sleeping" actions */ + if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE) + graphic_info[graphic].anim_delay_fixed = + parameter[GFX_ARG_ANIM_DELAY_FIXED]; + if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) + graphic_info[graphic].anim_delay_random = + parameter[GFX_ARG_ANIM_DELAY_RANDOM]; + if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE) + graphic_info[graphic].post_delay_fixed = + parameter[GFX_ARG_POST_DELAY_FIXED]; + if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE) + graphic_info[graphic].post_delay_random = + parameter[GFX_ARG_POST_DELAY_RANDOM]; + /* this is only used for toon animations */ graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET]; graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY]; @@ -947,8 +967,7 @@ static void InitGraphicInfo() GC copy_clipmask_gc = None; #endif - if (graphic_info != NULL) - free(graphic_info); + checked_free(graphic_info); graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo)); @@ -959,7 +978,7 @@ static void InitGraphicInfo() #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND) if (clipmasks_initialized) { - for (i=0; i -1; i++) + for (i = 0; element_to_sound[i].element > -1; i++) { int element = element_to_sound[i].element; int action = element_to_sound[i].action; @@ -1115,14 +1134,14 @@ static void InitElementSoundInfo() if (!is_class) element_info[element].sound[action] = sound; else - for (j=0; j < MAX_NUM_ELEMENTS; j++) + for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (strcmp(element_info[j].class_name, element_info[element].class_name) == 0) element_info[j].sound[action] = sound; } /* initialize element class/sound mapping from dynamic configuration */ - for (i=0; i < num_property_mappings; i++) + for (i = 0; i < num_property_mappings; i++) { int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS; int action = property_mapping[i].ext1_index; @@ -1134,14 +1153,14 @@ static void InitElementSoundInfo() if (action < 0) action = ACTION_DEFAULT; - for (j=0; j < MAX_NUM_ELEMENTS; j++) + for (j = 0; j < MAX_NUM_ELEMENTS; j++) if (strcmp(element_info[j].class_name, element_info[element_class].class_name) == 0) element_info[j].sound[action] = sound; } /* initialize element/sound mapping from dynamic configuration */ - for (i=0; i < num_property_mappings; i++) + for (i = 0; i < num_property_mappings; i++) { int element = property_mapping[i].base_index; int action = property_mapping[i].ext1_index; @@ -1157,9 +1176,9 @@ static void InitElementSoundInfo() } /* now set all '-1' values to element specific default values */ - for (i=0; i -1; i++) + { + int gamemode = gamemode_to_sound[i].gamemode; + int sound = gamemode_to_sound[i].sound; + + if (gamemode < 0) + gamemode = GAME_MODE_DEFAULT; + + menu.sound[gamemode] = sound; + } + + /* now set all '-1' values to levelset specific default values */ + for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) + if (menu.sound[i] == -1) + menu.sound[i] = menu.sound[GAME_MODE_DEFAULT]; + +#if 0 + /* TEST ONLY */ + for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) + if (menu.sound[i] != -1) + printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]); +#endif +} + static void set_sound_parameters(int sound, char **parameter_raw) { int parameter[NUM_SND_ARGS]; int i; /* get integer values from string parameters */ - for (i=0; i < NUM_SND_ARGS; i++) + for (i = 0; i < NUM_SND_ARGS; i++) parameter[i] = get_parameter_value(sound_config_suffix[i].token, parameter_raw[i], sound_config_suffix[i].type); @@ -1209,24 +1264,23 @@ static void InitSoundInfo() int num_sounds = getSoundListSize(); int i, j; - if (sound_info != NULL) - free(sound_info); + checked_free(sound_info); sound_effect_properties = checked_calloc(num_sounds * sizeof(int)); sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo)); /* initialize sound effect for all elements to "no sound" */ - for (i=0; itoken); sound_effect_properties[i] = ACTION_OTHER; - sound_info[i].loop = FALSE; + sound_info[i].loop = FALSE; /* default: play sound only once */ #if 0 printf("::: sound %d: '%s'\n", i, sound->token); @@ -1234,7 +1288,7 @@ static void InitSoundInfo() /* determine all loop sounds and identify certain sound classes */ - for (j=0; element_action_info[j].suffix; j++) + for (j = 0; element_action_info[j].suffix; j++) { int len_action_text = strlen(element_action_info[j].suffix); @@ -1256,7 +1310,7 @@ static void InitSoundInfo() /* associate elements and some selected sound actions */ - for (j=0; j -1; i++) + { + int gamemode = gamemode_to_music[i].gamemode; + int music = gamemode_to_music[i].music; + +#if 0 + printf("::: gamemode == %d, music == %d\n", gamemode, music); +#endif + + if (gamemode < 0) + gamemode = GAME_MODE_DEFAULT; + + menu.music[gamemode] = music; + } + + /* initialize gamemode/music mapping from dynamic configuration */ + for (i = 0; i < num_property_mappings; i++) + { + int prefix = property_mapping[i].base_index; + int gamemode = property_mapping[i].ext1_index; + int level = property_mapping[i].ext2_index; + int music = property_mapping[i].artwork_index; + +#if 0 + printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n", + prefix, gamemode, level, music); +#endif + + if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES) + continue; + + if (gamemode < 0) + gamemode = GAME_MODE_DEFAULT; + + /* level specific music only allowed for in-game music */ + if (level != -1 && gamemode == GAME_MODE_DEFAULT) + gamemode = GAME_MODE_PLAYING; + + if (level == -1) + { + level = 0; + default_levelset_music = music; + } + + if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT) + levelset.music[level] = music; + if (gamemode != GAME_MODE_PLAYING) + menu.music[gamemode] = music; + } + + /* now set all '-1' values to menu specific default values */ + /* (undefined values of "levelset.music[]" might stay at "-1" to + allow dynamic selection of music files from music directory!) */ + for (i = 0; i < MAX_LEVELS; i++) + if (levelset.music[i] == -1) + levelset.music[i] = default_levelset_music; + for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) + if (menu.music[i] == -1) + menu.music[i] = menu.music[GAME_MODE_DEFAULT]; + +#if 0 + /* TEST ONLY */ + for (i = 0; i < MAX_LEVELS; i++) + if (levelset.music[i] != -1) + printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]); + for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++) + if (menu.music[i] != -1) + printf("::: menu.music[%d] == %d\n", i, menu.music[i]); +#endif +} + +static void set_music_parameters(int music, char **parameter_raw) +{ + int parameter[NUM_MUS_ARGS]; + int i; + + /* get integer values from string parameters */ + for (i = 0; i < NUM_MUS_ARGS; i++) + parameter[i] = + get_parameter_value(music_config_suffix[i].token, parameter_raw[i], + music_config_suffix[i].type); + + /* explicit loop mode setting in configuration overrides default value */ + if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE) + music_info[music].loop = parameter[MUS_ARG_MODE_LOOP]; +} + +static void InitMusicInfo() +{ + int num_music = getMusicListSize(); + int i, j; + + checked_free(music_info); + + music_info = checked_calloc(num_music * sizeof(struct MusicInfo)); + + for (i = 0; i < num_music; i++) + { + struct FileInfo *music = getMusicListEntry(i); + int len_music_text = strlen(music->token); + + music_info[i].loop = TRUE; /* default: play music in loop mode */ + + /* determine all loop music */ + + for (j = 0; music_prefix_info[j].prefix; j++) + { + int len_prefix_text = strlen(music_prefix_info[j].prefix); + + if (len_prefix_text < len_music_text && + strncmp(music->token, + music_prefix_info[j].prefix, len_prefix_text) == 0) + { + music_info[i].loop = music_prefix_info[j].is_loop_music; + + break; + } + } + + set_music_parameters(i, music->parameter); + } +} + static void ReinitializeGraphics() { InitGraphicInfo(); /* graphic properties mapping */ @@ -1355,13 +1546,15 @@ static void ReinitializeSounds() { InitSoundInfo(); /* sound properties mapping */ InitElementSoundInfo(); /* element game sound mapping */ + InitGameModeSoundInfo(); /* game mode sound mapping */ - InitPlaySoundLevel(); /* internal game sound settings */ + InitPlayLevelSound(); /* internal game sound settings */ } static void ReinitializeMusic() { - /* currently nothing to do */ + InitMusicInfo(); /* music properties mapping */ + InitGameModeMusicInfo(); /* game mode music mapping */ } void InitElementPropertiesStatic() @@ -1638,6 +1831,7 @@ void InitElementPropertiesStatic() EL_SP_ELECTRON, EL_BALLOON, EL_SPRING, + EL_MAZE_RUNNER, -1 }; @@ -2713,21 +2907,21 @@ void InitElementPropertiesStatic() int i, j, k; /* always start with reliable default values (element has no properties) */ - for (i=0; i < MAX_NUM_ELEMENTS; i++) - for (j=0; j < NUM_ELEMENT_PROPERTIES; j++) + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++) SET_PROPERTY(i, j, FALSE); /* set all base element properties from above array definitions */ - for (i=0; element_properties[i].elements != NULL; i++) - for (j=0; (element_properties[i].elements)[j] != -1; j++) + for (i = 0; element_properties[i].elements != NULL; i++) + for (j = 0; (element_properties[i].elements)[j] != -1; j++) SET_PROPERTY((element_properties[i].elements)[j], element_properties[i].property, TRUE); /* copy properties to some elements that are only stored in level file */ - for (i=0; i < NUM_ELEMENT_PROPERTIES; i++) - for (j=0; copy_properties[j][0] != -1; j++) + for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++) + for (j = 0; copy_properties[j][0] != -1; j++) if (HAS_PROPERTY(copy_properties[j][0], i)) - for (k=1; k<=4; k++) + for (k = 1; k <= 4; k++) SET_PROPERTY(copy_properties[j][k], i, TRUE); } @@ -2800,10 +2994,10 @@ void InitElementPropertiesEngine(int engine_version) #endif /* set all special, combined or engine dependent element properties */ - for (i=0; i < MAX_NUM_ELEMENTS; i++) + for (i = 0; i < MAX_NUM_ELEMENTS; i++) { #if 0 - for (j=EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++) + for (j = EP_ACCESSIBLE_OVER; j < NUM_ELEMENT_PROPERTIES; j++) SET_PROPERTY(i, j, FALSE); #endif @@ -2845,7 +3039,7 @@ void InitElementPropertiesEngine(int engine_version) /* ---------- WALL ----------------------------------------------------- */ SET_PROPERTY(i, EP_WALL, TRUE); /* default: element is wall */ - for (j=0; no_wall_properties[j] != -1; j++) + for (j = 0; no_wall_properties[j] != -1; j++) if (HAS_PROPERTY(i, no_wall_properties[j]) || i >= EL_FIRST_RUNTIME_UNREAL) SET_PROPERTY(i, EP_WALL, FALSE); @@ -2910,7 +3104,7 @@ void InitElementPropertiesEngine(int engine_version) /* ---------- CAN_CHANGE ----------------------------------------------- */ SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */ - for (j=0; j < element_info[i].num_change_pages; j++) + for (j = 0; j < element_info[i].num_change_pages; j++) if (element_info[i].change_page[j].can_change) SET_PROPERTY(i, EP_CAN_CHANGE, TRUE); @@ -2921,11 +3115,11 @@ void InitElementPropertiesEngine(int engine_version) #if 0 /* determine inactive elements (used for engine main loop optimization) */ - for (i=0; i < MAX_NUM_ELEMENTS; i++) + for (i = 0; i < MAX_NUM_ELEMENTS; i++) { boolean active = FALSE; - for (j=0; i < NUM_ELEMENT_PROPERTIES; j++) + for (j = 0; i < NUM_ELEMENT_PROPERTIES; j++) { if (HAS_PROPERTY(i, j)) active = TRUE; @@ -2952,7 +3146,7 @@ void InitElementPropertiesEngine(int engine_version) }; /* special EM style gems behaviour */ - for (i=0; ep_em_slippery_wall[i] != -1; i++) + for (i = 0; ep_em_slippery_wall[i] != -1; i++) SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL, level.em_slippery_gems); @@ -2976,7 +3170,7 @@ void InitElementPropertiesEngine(int engine_version) } /* set uninitialized push delay values of custom elements in older levels */ - for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; @@ -2999,51 +3193,92 @@ static void InitGlobal() void Execute_Command(char *command) { + int i; + if (strcmp(command, "print graphicsinfo.conf") == 0) { - int i; - printf("# You can configure additional/alternative image files here.\n"); - printf("# (The images below are default and therefore commented out.)\n"); + printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics")); printf("\n"); printf("%s\n", getFormattedSetupEntry("sort_priority", "100")); printf("\n"); - for (i=0; image_config[i].token != NULL; i++) - printf("# %s\n", - getFormattedSetupEntry(image_config[i].token, - image_config[i].value)); + for (i = 0; image_config[i].token != NULL; i++) + printf("# %s\n", getFormattedSetupEntry(image_config[i].token, + image_config[i].value)); exit(0); } else if (strcmp(command, "print soundsinfo.conf") == 0) { - int i; - printf("# You can configure additional/alternative sound files here.\n"); - printf("# (The sounds below are default and therefore commented out.)\n"); + printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds")); printf("\n"); printf("%s\n", getFormattedSetupEntry("sort_priority", "100")); printf("\n"); - for (i=0; sound_config[i].token != NULL; i++) - printf("# %s\n", - getFormattedSetupEntry(sound_config[i].token, - sound_config[i].value)); + for (i = 0; sound_config[i].token != NULL; i++) + printf("# %s\n", getFormattedSetupEntry(sound_config[i].token, + sound_config[i].value)); exit(0); } else if (strcmp(command, "print musicinfo.conf") == 0) { - printf("# (Currently only \"name\" and \"sort_priority\" recognized.)\n"); + printf("# You can configure additional/alternative music files here.\n"); + printf("# (The entries below are default and therefore commented out.)\n"); printf("\n"); printf("%s\n", getFormattedSetupEntry("name", "Classic Music")); printf("\n"); printf("%s\n", getFormattedSetupEntry("sort_priority", "100")); + printf("\n"); + + for (i = 0; music_config[i].token != NULL; i++) + printf("# %s\n", getFormattedSetupEntry(music_config[i].token, + music_config[i].value)); + + exit(0); + } + else if (strcmp(command, "print editorsetup.conf") == 0) + { + printf("# You can configure your personal editor element list here.\n"); + printf("# (The entries below are default and therefore commented out.)\n"); + printf("\n"); + + PrintEditorElementList(); + + exit(0); + } + else if (strcmp(command, "print helpanim.conf") == 0) + { + printf("# You can configure different element help animations here.\n"); + printf("# (The entries below are default and therefore commented out.)\n"); + printf("\n"); + + for (i = 0; helpanim_config[i].token != NULL; i++) + { + printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token, + helpanim_config[i].value)); + + if (strcmp(helpanim_config[i].token, "end") == 0) + printf("#\n"); + } + + exit(0); + } + else if (strcmp(command, "print helptext.conf") == 0) + { + printf("# You can configure different element help text here.\n"); + printf("# (The entries below are default and therefore commented out.)\n"); + printf("\n"); + + for (i = 0; helptext_config[i].token != NULL; i++) + printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token, + helptext_config[i].value)); exit(0); } @@ -3108,7 +3343,7 @@ static void InitPlayerInfo() /* choose default local player */ local_player = &stored_player[0]; - for (i=0; iconnected = TRUE; @@ -3128,6 +3363,18 @@ static char *get_string_in_brackets(char *string) return string_in_brackets; } +static char *get_level_id_suffix(int id_nr) +{ + char *id_suffix = checked_malloc(1 + 3 + 1); + + if (id_nr < 0 || id_nr > 999) + id_nr = 0; + + sprintf(id_suffix, ".%03d", id_nr); + + return id_suffix; +} + #if 0 static char *get_element_class_token(int element) { @@ -3154,9 +3401,11 @@ static void InitArtworkConfig() { static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1]; static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1]; + static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1]; static char *action_id_suffix[NUM_ACTIONS + 1]; static char *direction_id_suffix[NUM_DIRECTIONS + 1]; static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1]; + static char *level_id_suffix[MAX_LEVELS + 1]; static char *dummy[1] = { NULL }; static char *ignore_generic_tokens[] = { @@ -3164,25 +3413,29 @@ static void InitArtworkConfig() "sort_priority", NULL }; - static char **ignore_image_tokens, **ignore_sound_tokens; + static char **ignore_image_tokens; + static char **ignore_sound_tokens; + static char **ignore_music_tokens; int num_ignore_generic_tokens; - int num_ignore_image_tokens, num_ignore_sound_tokens; + int num_ignore_image_tokens; + int num_ignore_sound_tokens; + int num_ignore_music_tokens; int i; /* dynamically determine list of generic tokens to be ignored */ num_ignore_generic_tokens = 0; - for (i=0; ignore_generic_tokens[i] != NULL; i++) + for (i = 0; ignore_generic_tokens[i] != NULL; i++) num_ignore_generic_tokens++; /* dynamically determine list of image tokens to be ignored */ num_ignore_image_tokens = num_ignore_generic_tokens; - for (i=0; image_config_vars[i].token != NULL; i++) + for (i = 0; image_config_vars[i].token != NULL; i++) num_ignore_image_tokens++; ignore_image_tokens = checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *)); - for (i=0; i < num_ignore_generic_tokens; i++) + for (i = 0; i < num_ignore_generic_tokens; i++) ignore_image_tokens[i] = ignore_generic_tokens[i]; - for (i=0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++) + for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++) ignore_image_tokens[num_ignore_generic_tokens + i] = image_config_vars[i].token; ignore_image_tokens[num_ignore_image_tokens] = NULL; @@ -3191,41 +3444,60 @@ static void InitArtworkConfig() num_ignore_sound_tokens = num_ignore_generic_tokens; ignore_sound_tokens = checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *)); - for (i=0; i < num_ignore_generic_tokens; i++) + for (i = 0; i < num_ignore_generic_tokens; i++) ignore_sound_tokens[i] = ignore_generic_tokens[i]; ignore_sound_tokens[num_ignore_sound_tokens] = NULL; - for (i=0; ibitmap, drawto, gd->x, gd->y + gi->border.ysize, gi->width, design_body, @@ -636,7 +636,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) xpos, ypos); /* middle part of gadget */ - for (i=0; ibitmap, drawto, gd->x + gi->border.xsize, gd->y, design_body, gi->height, @@ -1302,7 +1302,7 @@ void ClickOnGadget(struct GadgetInfo *gi, int button) HandleGadgets(gi->x, gi->y, 0); } -void HandleGadgets(int mx, int my, int button) +boolean HandleGadgets(int mx, int my, int button) { static struct GadgetInfo *last_info_gi = NULL; static unsigned long pressed_delay = 0; @@ -1327,7 +1327,7 @@ void HandleGadgets(int mx, int my, int button) /* check if there are any gadgets defined */ if (gadget_list_first_entry == NULL) - return; + return FALSE; /* simulated release of mouse button over last gadget */ if (mx == -1 && my == -1 && button == 0) @@ -1591,7 +1591,7 @@ void HandleGadgets(int mx, int my, int button) /* don't handle this scrollbar anymore while mouse button pressed */ last_gi = NULL; - return; + return TRUE; } } @@ -1723,6 +1723,9 @@ void HandleGadgets(int mx, int my, int button) /* handle gadgets unmapped/mapped between pressing and releasing */ if (release_event && !gadget_released && new_gi) new_gi->state = GD_BUTTON_UNPRESSED; + + return (gadget_pressed || gadget_pressed_repeated || + gadget_released || gadget_moving); } static void insertCharIntoTextArea(struct GadgetInfo *gi, char c) @@ -1740,7 +1743,7 @@ static void insertCharIntoTextArea(struct GadgetInfo *gi, char c) setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); } -void HandleGadgetsKeyInput(Key key) +boolean HandleGadgetsKeyInput(Key key) { struct GadgetInfo *gi = last_gi; @@ -1748,7 +1751,7 @@ void HandleGadgetsKeyInput(Key key) !(gi->type & GD_TYPE_TEXT_INPUT || gi->type & GD_TYPE_TEXT_AREA || gi->type & GD_TYPE_SELECTBOX)) - return; + return FALSE; if (key == KSYM_Return) /* valid for both text input and selectbox */ { @@ -1900,4 +1903,6 @@ void HandleGadgetsKeyInput(Key key) DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } + + return TRUE; } diff --git a/src/libgame/gadgets.h b/src/libgame/gadgets.h index 160bd611..4e1dd0f7 100644 --- a/src/libgame/gadgets.h +++ b/src/libgame/gadgets.h @@ -249,7 +249,7 @@ void RemapAllGadgets(); boolean anyTextGadgetActive(); void ClickOnGadget(struct GadgetInfo *, int); -void HandleGadgets(int, int, int); -void HandleGadgetsKeyInput(Key); +boolean HandleGadgets(int, int, int); +boolean HandleGadgetsKeyInput(Key); #endif /* GADGETS_H */ diff --git a/src/libgame/hash.c b/src/libgame/hash.c index 805190bf..bce20519 100644 --- a/src/libgame/hash.c +++ b/src/libgame/hash.c @@ -58,7 +58,7 @@ create_hashtable(unsigned int minsize, float maxloadfactor, h->table = (struct entry **)malloc(sizeof(struct entry*) * size); if (NULL == h->table) { free(h); return NULL; } /*oom*/ - for (i=0;itable[i] = NULL; } + for (i=0; i < size; i++) { h->table[i] = NULL; } h->tablelength = size; h->entrycount = 0; h->hashfn = hashf; diff --git a/src/libgame/image.c b/src/libgame/image.c index f06a126e..e267fd80 100644 --- a/src/libgame/image.c +++ b/src/libgame/image.c @@ -47,7 +47,7 @@ Image *newImage(unsigned int width, unsigned int height, unsigned int depth) image->bytes_per_row = width * bytes_per_pixel; image->rgb.used = 0; - for (i=0; irgb.color_used[i] = FALSE; image->type = (depth < 8 ? IMAGETYPE_BITMAP : @@ -115,14 +115,14 @@ static Pixmap Image_to_Mask(Image *image, Display *display, Window window) * the corresponding image pixmap */ - for (y=0; yheight; y++) + for (y = 0; y < image->height; y++) { bitmask = 0x01; /* start with leftmost bit in the byte */ dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */ - for (x=0; xwidth; x++) + for (x = 0; x < image->width; x++) { - for (i=0; ibytes_per_pixel; i++) + for (i = 0; i < image->bytes_per_pixel; i++) if (*src_ptr++) /* source pixel solid? (pixel index != 0) */ *dst_ptr2 |= bitmask; /* then write a bit into the image mask */ @@ -152,7 +152,7 @@ static int bitsPerPixelAtDepth(Display *display, int screen, int depth) pixmap_format = XListPixmapFormats(display, &num_pixmap_formats); /* find format that matches the given depth */ - for (i=0; ired_mask) redcolors <<= 1; @@ -251,7 +251,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, redbottom = greenbottom = bluebottom = 0; redtop = greentop = bluetop = 0; - for (a=0; amap_entries; a++) + for (a = 0; a < visual->map_entries; a++) { if (redbottom < 256) redtop = redbottom + redstep; @@ -307,7 +307,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, ximageinfo->cmap = global_cmap; - for (a=0; a=0; i--) + for (i = num_cmap_entries - 1; i >= 0; i--) { xcolor2.pixel = *(global_cmap_index + i); xcolor2 = xcolor_private[xcolor2.pixel]; @@ -464,9 +464,9 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, { case IMAGETYPE_RGB: { - for (y=0; yheight; y++) /* general case */ + for (y = 0; y < image->height; y++) /* general case */ { - for (x=0; xwidth; x++) + for (x = 0; x < image->width; x++) { pixval = *src_ptr++; pixval = @@ -483,9 +483,9 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, case IMAGETYPE_TRUECOLOR: { - for (y=0; yheight; y++) /* general case */ + for (y = 0; y < image->height; y++) /* general case */ { - for (x=0; xwidth; x++) + for (x = 0; x < image->width; x++) { pixval = memory_to_value(src_ptr, image->bytes_per_pixel); pixval = @@ -515,15 +515,15 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, { if (display_bytes_per_pixel == 1) /* special case */ { - for (y=0; yheight; y++) - for (x=0; xwidth; x++) + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) *dst_ptr++ = ximageinfo->index[c + *src_ptr++]; } else /* general case */ { - for (y=0; yheight; y++) + for (y = 0; y < image->height; y++) { - for (x=0; xwidth; x++) + for (x = 0; x < image->width; x++) { value_to_memory(ximageinfo->index[c + *src_ptr++], dst_ptr, display_bytes_per_pixel); @@ -611,9 +611,9 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap, row_skip = col_skip * src_width; /* scale image down by scaling factor 'zoom_factor' */ - for (y=0; y < src_height; y += zoom_factor, src_ptr += row_skip) - for (x=0; x < src_width; x += zoom_factor, src_ptr += col_skip) - for (i=0; i < bytes_per_pixel; i++) + for (y = 0; y < src_height; y += zoom_factor, src_ptr += row_skip) + for (x = 0; x < src_width; x += zoom_factor, src_ptr += col_skip) + for (i = 0; i < bytes_per_pixel; i++) *dst_ptr++ = *src_ptr++; /* copy scaled image to destination pixmap */ @@ -822,7 +822,7 @@ int getImageIDFromToken(char *token) int num_list_entries = image_info->num_file_list_entries; int i; - for (i=0; i < num_list_entries; i++) + for (i = 0; i < num_list_entries; i++) if (strcmp(file_list[i].token, token) == 0) return i; @@ -866,7 +866,7 @@ void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, image_info->dynamic_file_list = NULL; image_info->num_suffix_list_entries = 0; - for (i=0; config_suffix_list[i].token != NULL; i++) + for (i = 0; config_suffix_list[i].token != NULL; i++) image_info->num_suffix_list_entries++; image_info->suffix_list = config_suffix_list; @@ -874,23 +874,23 @@ void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, /* ---------- initialize base prefix and suffixes lists ---------- */ image_info->num_base_prefixes = 0; - for (i=0; base_prefixes[i] != NULL; i++) + for (i = 0; base_prefixes[i] != NULL; i++) image_info->num_base_prefixes++; image_info->num_ext1_suffixes = 0; - for (i=0; ext1_suffixes[i] != NULL; i++) + for (i = 0; ext1_suffixes[i] != NULL; i++) image_info->num_ext1_suffixes++; image_info->num_ext2_suffixes = 0; - for (i=0; ext2_suffixes[i] != NULL; i++) + for (i = 0; ext2_suffixes[i] != NULL; i++) image_info->num_ext2_suffixes++; image_info->num_ext3_suffixes = 0; - for (i=0; ext3_suffixes[i] != NULL; i++) + for (i = 0; ext3_suffixes[i] != NULL; i++) image_info->num_ext3_suffixes++; image_info->num_ignore_tokens = 0; - for (i=0; ignore_tokens[i] != NULL; i++) + for (i = 0; ignore_tokens[i] != NULL; i++) image_info->num_ignore_tokens++; image_info->base_prefixes = base_prefixes; diff --git a/src/libgame/joystick.c b/src/libgame/joystick.c index 32efad6f..d9cad128 100644 --- a/src/libgame/joystick.c +++ b/src/libgame/joystick.c @@ -28,7 +28,7 @@ void UnixInitJoysticks() { int i; - for (i=0; i= setup.input[i].joy.xmiddle) setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance; @@ -317,7 +317,7 @@ int AnyJoystick() int i; int result = 0; - for (i=0; i 2147483647) /* yes, this is a kludge */ + i = 2147483647; + + a = checked_malloc(10 + 1); + + sprintf(a, "%d", i); + + return a; +} + /* ------------------------------------------------------------------------- */ /* counter functions */ @@ -243,7 +263,7 @@ void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay) { unsigned long actual_counter; - while(1) + while (1) { actual_counter = Counter(); @@ -262,48 +282,6 @@ void WaitUntilDelayReached(unsigned long *counter_var, unsigned long delay) /* random generator functions */ /* ------------------------------------------------------------------------- */ -#if 0 -unsigned int SimpleRND(unsigned int max) -{ - return (random_linux_libc(RND_FREE) % max); -} - -unsigned int InitSimpleRND(long seed) -{ - if (seed == NEW_RANDOMIZE) - { - struct timeval current_time; - - gettimeofday(¤t_time, NULL); - seed = (long)current_time.tv_usec; - } - - srandom_linux_libc(RND_FREE, (unsigned int) seed); - - return (unsigned int) seed; -} - -unsigned int RND(unsigned int max) -{ - return (random_linux_libc(RND_GAME) % max); -} - -unsigned int InitRND(long seed) -{ - if (seed == NEW_RANDOMIZE) - { - struct timeval current_time; - - gettimeofday(¤t_time, NULL); - seed = (long)current_time.tv_usec; - } - - srandom_linux_libc(RND_GAME, (unsigned int) seed); - - return (unsigned int) seed; -} -#endif - unsigned int init_random_number(int nr, long seed) { if (seed == NEW_RANDOMIZE) @@ -323,7 +301,7 @@ unsigned int init_random_number(int nr, long seed) return (unsigned int) seed; } -unsigned int get_random_number(int nr, unsigned int max) +unsigned int get_random_number(int nr, int max) { return (max > 0 ? random_linux_libc(nr) % max : 0); } @@ -522,8 +500,7 @@ char *getStringToLower(char *s) void setString(char **old_value, char *new_value) { - if (*old_value != NULL) - free(*old_value); + checked_free(*old_value); *old_value = getStringCopy(new_value); } @@ -533,36 +510,7 @@ void setString(char **old_value, char *new_value) /* command line option handling functions */ /* ------------------------------------------------------------------------- */ -static void printUsage() -{ - printf("\n" - "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n" - "\n" - "Options:\n" - " -d, --display HOSTNAME[:SCREEN] specify X server display\n" - " -b, --basepath DIRECTORY alternative base DIRECTORY\n" - " -l, --level DIRECTORY alternative level DIRECTORY\n" - " -g, --graphics DIRECTORY alternative graphics DIRECTORY\n" - " -s, --sounds DIRECTORY alternative sounds DIRECTORY\n" - " -m, --music DIRECTORY alternative music DIRECTORY\n" - " -n, --network network multiplayer game\n" - " --serveronly only start network server\n" - " -v, --verbose verbose mode\n" - " --debug display debugging information\n" - " -e, --execute COMMAND execute batch COMMAND:\n" - "\n" - "Valid commands for '--execute' option:\n" - " \"print graphicsinfo.conf\" print default graphics config\n" - " \"print soundsinfo.conf\" print default sounds config\n" - " \"print musicinfo.conf\" print default music config\n" - " \"dump level FILE\" dump level data from FILE\n" - " \"dump tape FILE\" dump tape data from FILE\n" - " \"autoplay LEVELDIR\" play level tapes for LEVELDIR\n" - "\n", - program.command_basename); -} - -void GetOptions(char *argv[]) +void GetOptions(char *argv[], void (*print_usage_function)(void)) { char **options_left = &argv[1]; @@ -624,7 +572,7 @@ void GetOptions(char *argv[]) Error(ERR_EXIT_HELP, "unrecognized option '%s'", option); else if (strncmp(option, "-help", option_len) == 0) { - printUsage(); + print_usage_function(); exit(0); } @@ -834,7 +782,7 @@ void Error(int mode, char *format, ...) /* ------------------------------------------------------------------------- */ -/* memory allocation functions */ +/* checked memory allocation and freeing functions */ /* ------------------------------------------------------------------------- */ void *checked_malloc(unsigned long size) @@ -871,6 +819,12 @@ void *checked_realloc(void *ptr, unsigned long size) return ptr; } +void checked_free(void *ptr) +{ + if (ptr != NULL) /* this check should be done by free() anyway */ + free(ptr); +} + /* ------------------------------------------------------------------------- */ /* various helper functions */ @@ -1395,8 +1349,8 @@ int get_integer_from_string(char *s) char *s_lower = getStringToLower(s); int result = -1; - for (i=0; number_text[i][0] != NULL; i++) - for (j=0; j < 3; j++) + for (i = 0; number_text[i][0] != NULL; i++) + for (j = 0; j < 3; j++) if (strcmp(s_lower, number_text[i][j]) == 0) result = i; @@ -1530,8 +1484,7 @@ boolean fileHasPrefix(char *basename, char *prefix) static char *basename_lower = NULL; int basename_length, prefix_length; - if (basename_lower != NULL) - free(basename_lower); + checked_free(basename_lower); if (basename == NULL || prefix == NULL) return FALSE; @@ -1553,8 +1506,7 @@ boolean fileHasSuffix(char *basename, char *suffix) static char *basename_lower = NULL; int basename_length, suffix_length; - if (basename_lower != NULL) - free(basename_lower); + checked_free(basename_lower); if (basename == NULL || suffix == NULL) return FALSE; @@ -1571,18 +1523,30 @@ boolean fileHasSuffix(char *basename, char *suffix) return FALSE; } -boolean FileIsGraphic(char *basename) +boolean FileIsGraphic(char *filename) { + char *basename = strrchr(filename, '/'); + + basename = (basename != NULL ? basename + 1 : filename); + return fileHasSuffix(basename, "pcx"); } -boolean FileIsSound(char *basename) +boolean FileIsSound(char *filename) { + char *basename = strrchr(filename, '/'); + + basename = (basename != NULL ? basename + 1 : filename); + return fileHasSuffix(basename, "wav"); } -boolean FileIsMusic(char *basename) +boolean FileIsMusic(char *filename) { + char *basename = strrchr(filename, '/'); + + basename = (basename != NULL ? basename + 1 : filename); + if (FileIsSound(basename)) return TRUE; @@ -1723,11 +1687,11 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list, file_list = checked_calloc(num_file_list_entries * sizeof(struct FileInfo)); - for (i=0; suffix_list[i].token != NULL; i++) + for (i = 0; suffix_list[i].token != NULL; i++) num_suffix_list_entries++; /* always start with reliable default values */ - for (i=0; ifilename, filename); /* when file definition found, set all parameters to default values */ - for (i=0; suffix_list[i].token != NULL; i++) + for (i = 0; suffix_list[i].token != NULL; i++) setString(&file_list_entry->parameter[i], suffix_list[i].value); file_list_entry->redefined = TRUE; @@ -1879,7 +1843,7 @@ static void read_token_parameters(SetupFileHash *setup_file_hash, #endif /* check for config tokens that can be build by base token and suffixes */ - for (i=0; suffix_list[i].token != NULL; i++) + for (i = 0; suffix_list[i].token != NULL; i++) { char *token = getStringCat2(file_list_entry->token, suffix_list[i].token); char *value = getHashEntry(setup_file_hash, token); @@ -1960,7 +1924,8 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info, int num_ext2_suffixes = artwork_info->num_ext2_suffixes; int num_ext3_suffixes = artwork_info->num_ext3_suffixes; int num_ignore_tokens = artwork_info->num_ignore_tokens; - SetupFileHash *setup_file_hash, *extra_file_hash; + SetupFileHash *setup_file_hash, *valid_file_hash; + SetupFileHash *extra_file_hash, *empty_file_hash; char *known_token_value = KNOWN_TOKEN_VALUE; int i, j, k, l; @@ -1974,26 +1939,42 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info, if ((setup_file_hash = loadSetupFileHash(filename)) == NULL) return; + /* separate valid (defined) from empty (undefined) config token values */ + valid_file_hash = newSetupFileHash(); + empty_file_hash = newSetupFileHash(); + BEGIN_HASH_ITERATION(setup_file_hash, itr) + { + char *value = HASH_ITERATION_VALUE(itr); + + setHashEntry(*value ? valid_file_hash : empty_file_hash, + HASH_ITERATION_TOKEN(itr), value); + } + END_HASH_ITERATION(setup_file_hash, itr) + + /* at this point, we do not need the setup file hash anymore -- free it */ + freeSetupFileHash(setup_file_hash); + /* read parameters for all known config file tokens */ - for (i=0; isizeof_artwork_list_entry); } - if (extra_file_hash != NULL && options.verbose && IS_PARENT_PROCESS()) + if (options.verbose && IS_PARENT_PROCESS()) { SetupFileList *setup_file_list, *list; boolean dynamic_tokens_found = FALSE; boolean unknown_tokens_found = FALSE; + boolean undefined_values_found = (hashtable_count(empty_file_hash) != 0); if ((setup_file_list = loadSetupFileList(filename)) == NULL) Error(ERR_EXIT, "loadSetupFileHash works, but loadSetupFileList fails"); @@ -2262,13 +2244,31 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info, Error(ERR_RETURN_LINE, "-"); } + if (undefined_values_found) + { + Error(ERR_RETURN_LINE, "-"); + Error(ERR_RETURN, "warning: undefined values found in config file:"); + Error(ERR_RETURN, "- config file: '%s'", filename); + + for (list = setup_file_list; list != NULL; list = list->next) + { + char *value = getHashEntry(empty_file_hash, list->token); + + if (value != NULL) + Error(ERR_RETURN, "- undefined value for token: '%s'", list->token); + } + + Error(ERR_RETURN_LINE, "-"); + } + freeSetupFileList(setup_file_list); } freeSetupFileHash(extra_file_hash); + freeSetupFileHash(empty_file_hash); #if 0 - for (i=0; itype), 150, FC_YELLOW); /* always start with reliable default values */ - for (i=0; idynamic_file_list != NULL) { - for (i=0; inum_dynamic_file_list_entries; i++) + for (i = 0; i < artwork_info->num_dynamic_file_list_entries; i++) { free(artwork_info->dynamic_file_list[i].token); free(artwork_info->dynamic_file_list[i].filename); @@ -2520,7 +2520,7 @@ void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info) num_file_list_entries); #endif - for(i=0; idynamic_artwork_list[i], dynamic_file_list[i].filename, i); @@ -2566,7 +2566,7 @@ static void FreeCustomArtworkList(struct ArtworkListInfo *artwork_info, if (*list == NULL) return; - for(i=0; i<*num_list_entries; i++) + for (i = 0; i < *num_list_entries; i++) deleteArtworkListEntry(artwork_info, &(*list)[i]); free(*list); diff --git a/src/libgame/misc.h b/src/libgame/misc.h index 71c0d7fe..af65d4ca 100644 --- a/src/libgame/misc.h +++ b/src/libgame/misc.h @@ -70,6 +70,7 @@ void fprintf_line(FILE *, char *, int); void printf_line(char *, int); char *int2str(int, int); +char *i_to_a(unsigned int); void InitCounter(void); unsigned long Counter(void); @@ -86,7 +87,7 @@ unsigned int InitRND(long); #endif unsigned int init_random_number(int, long); -unsigned int get_random_number(int, unsigned int); +unsigned int get_random_number(int, int); char *getLoginName(void); char *getRealName(void); @@ -99,7 +100,7 @@ char *getStringCopy(char *); char *getStringToLower(char *); void setString(char **, char *); -void GetOptions(char **); +void GetOptions(char **, void (*print_usage_function)(void)); void SetError(char *, ...); char *GetError(void); @@ -108,6 +109,7 @@ void Error(int, char *, ...); void *checked_malloc(unsigned long); void *checked_calloc(unsigned long); void *checked_realloc(void *, unsigned long); +void checked_free(void *); inline void swap_numbers(int *, int *); inline void swap_number_pairs(int *, int *, int *, int *); diff --git a/src/libgame/msdos.c b/src/libgame/msdos.c index ec19ef63..a82da6cd 100644 --- a/src/libgame/msdos.c +++ b/src/libgame/msdos.c @@ -60,10 +60,10 @@ static void allegro_init_drivers() { int i; - for (i=0; i>= 10; /* try to use existing colors from the global colormap */ - for (i=0; irgb.color_used[i]) continue; @@ -527,8 +526,8 @@ static BITMAP *Image_to_AllegroBitmap(Image *image) } /* copy bitmap data */ - for (y=0; yheight; y++) - for (x=0; xwidth; x++) + for (y = 0; y < image->height; y++) + for (x = 0; x < image->width; x++) putpixel(bitmap, x, y, pixel_mapping[*src_ptr++]); return bitmap; @@ -598,11 +597,9 @@ void XFreePixmap(Display *display, Pixmap pixmap) void XFreeGC(Display *display, GC gc) { - XGCValues *gcv; + XGCValues *gcv = (XGCValues *)gc; - gcv = (XGCValues *)gc; - if (gcv) - free(gcv); + checked_free(gcv); } void XUnmapWindow(Display *display, Window window) @@ -616,11 +613,8 @@ void XCloseDisplay(Display *display) if (is_screen_bitmap(bitmap)) destroy_bitmap(bitmap); - if (display->screens) - free(display->screens); - - if (display) - free(display); + checked_free(display->screens); + checked_free(display); /* return to text mode (or DOS box on Windows screen) */ set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); @@ -671,7 +665,7 @@ static void HandleKeyboardRaw(int mode) { int i; - for (i=0; irgb.red[i] = *buffer_ptr++ << 8; image->rgb.green[i] = *buffer_ptr++ << 8; @@ -256,7 +256,7 @@ static boolean PCX_ReadColormap(FILE *file,struct PCX_Header *pcx,Image *image) while (value != PCX_256COLORS_MAGIC); /* read 256 colors from PCX colormap */ - for(i = 0; i < PCX_MAXCOLORS; i++) + for (i = 0; i < PCX_MAXCOLORS; i++) { image->rgb.red[i] = (byte)fgetc(file) << 8; image->rgb.green[i] = (byte)fgetc(file) << 8; @@ -265,7 +265,7 @@ static boolean PCX_ReadColormap(FILE *file,struct PCX_Header *pcx,Image *image) } else { - for(i = 0; i < num_colors; i++) + for (i = 0; i < num_colors; i++) { image->rgb.red[i] = pcx->palette[i][0] << 8; image->rgb.green[i] = pcx->palette[i][1] << 8; @@ -375,7 +375,7 @@ Image *Read_PCX_to_Image(char *filename) if (pcx_depth == 8) { /* determine number of used colormap entries for 8-bit PCX images */ - for (i=0; irgb.color_used[i]) image->rgb.used++; } diff --git a/src/libgame/sdl.c b/src/libgame/sdl.c index 74123228..e9d10df5 100644 --- a/src/libgame/sdl.c +++ b/src/libgame/sdl.c @@ -71,7 +71,7 @@ inline void SDLInitVideoBuffer(DrawBuffer **backbuffer, DrawWindow **window, fullscreen_yoffset = 0; #ifdef FULLSCREEN_BUG - for (i=0; screen_xy[i][0] != -1; i++) + for (i = 0; screen_xy[i][0] != -1; i++) { if (video.width <= screen_xy[i][0] && video.height <= screen_xy[i][1]) { @@ -340,11 +340,11 @@ inline void SDLDrawLines(SDL_Surface *surface, struct XY *points, int i, x, y; int line_width = 4; - for (i=0; iformat->palette->ncolors; i++) + for (i = 0; i < zoom_src->format->palette->ncolors; i++) zoom_dst->format->palette->colors[i] = zoom_src->format->palette->colors[i]; zoom_dst->format->palette->ncolors = zoom_src->format->palette->ncolors; @@ -1454,7 +1454,7 @@ void SDLInitJoysticks() } } - for (i=0; iuser_defined ? getUserLevelDir(NULL) : options.level_directory), node->fullpath); @@ -180,6 +159,35 @@ static char *getCurrentLevelDir() return getLevelDirFromTreeInfo(leveldir_current); } +static char *getTapeDir(char *level_subdir) +{ + static char *tape_dir = NULL; + char *data_dir = getUserDataDir(); + char *tape_subdir = TAPES_DIRECTORY; + + checked_free(tape_dir); + + if (level_subdir != NULL) + tape_dir = getPath3(data_dir, tape_subdir, level_subdir); + else + tape_dir = getPath2(data_dir, tape_subdir); + + return tape_dir; +} + +static char *getSolutionTapeDir() +{ + static char *tape_dir = NULL; + char *data_dir = getCurrentLevelDir(); + char *tape_subdir = TAPES_DIRECTORY; + + checked_free(tape_dir); + + tape_dir = getPath2(data_dir, tape_subdir); + + return tape_dir; +} + static char *getDefaultGraphicsDir(char *graphics_subdir) { static char *graphics_dir = NULL; @@ -187,8 +195,7 @@ static char *getDefaultGraphicsDir(char *graphics_subdir) if (graphics_subdir == NULL) return options.graphics_directory; - if (graphics_dir) - free(graphics_dir); + checked_free(graphics_dir); graphics_dir = getPath2(options.graphics_directory, graphics_subdir); @@ -202,8 +209,7 @@ static char *getDefaultSoundsDir(char *sounds_subdir) if (sounds_subdir == NULL) return options.sounds_directory; - if (sounds_dir) - free(sounds_dir); + checked_free(sounds_dir); sounds_dir = getPath2(options.sounds_directory, sounds_subdir); @@ -217,8 +223,7 @@ static char *getDefaultMusicDir(char *music_subdir) if (music_subdir == NULL) return options.music_directory; - if (music_dir) - free(music_dir); + checked_free(music_dir); music_dir = getPath2(options.music_directory, music_subdir); @@ -276,8 +281,7 @@ static char *getSetupArtworkDir(TreeInfo *ti) { static char *artwork_dir = NULL; - if (artwork_dir != NULL) - free(artwork_dir); + checked_free(artwork_dir); artwork_dir = getPath2(ti->basepath, ti->fullpath); @@ -295,8 +299,7 @@ char *setLevelArtworkDir(TreeInfo *ti) artwork_path_ptr = &(LEVELDIR_ARTWORK_PATH(leveldir_current, ti->type)); artwork_set_ptr = &(LEVELDIR_ARTWORK_SET( leveldir_current, ti->type)); - if (*artwork_path_ptr != NULL) - free(*artwork_path_ptr); + checked_free(*artwork_path_ptr); if ((level_artwork = getTreeInfoFromIdentifier(ti, *artwork_set_ptr))) *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork)); @@ -311,8 +314,7 @@ char *setLevelArtworkDir(TreeInfo *ti) char *dir = getPath2(getCurrentLevelDir(), ARTWORK_DIRECTORY(ti->type)); - if (*artwork_set_ptr != NULL) - free(*artwork_set_ptr); + checked_free(*artwork_set_ptr); if (fileExists(dir)) { @@ -352,8 +354,7 @@ char *getLevelFilename(int nr) static char *filename = NULL; char basename[MAX_FILENAME_LEN]; - if (filename != NULL) - free(filename); + checked_free(filename); if (nr < 0) sprintf(basename, "template.%s", LEVELFILE_EXTENSION); @@ -370,8 +371,7 @@ char *getTapeFilename(int nr) static char *filename = NULL; char basename[MAX_FILENAME_LEN]; - if (filename != NULL) - free(filename); + checked_free(filename); sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getTapeDir(leveldir_current->filename), basename); @@ -379,13 +379,25 @@ char *getTapeFilename(int nr) return filename; } +char *getSolutionTapeFilename(int nr) +{ + static char *filename = NULL; + char basename[MAX_FILENAME_LEN]; + + checked_free(filename); + + sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); + filename = getPath2(getSolutionTapeDir(), basename); + + return filename; +} + char *getScoreFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; - if (filename != NULL) - free(filename); + checked_free(filename); sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION); filename = getPath2(getScoreDir(leveldir_current->filename), basename); @@ -397,14 +409,75 @@ char *getSetupFilename() { static char *filename = NULL; - if (filename != NULL) - free(filename); + checked_free(filename); filename = getPath2(getSetupDir(), SETUP_FILENAME); return filename; } +char *getEditorSetupFilename() +{ + static char *filename = NULL; + + checked_free(filename); + + filename = getPath2(getSetupDir(), EDITORSETUP_FILENAME); + + return filename; +} + +char *getHelpAnimFilename() +{ + static char *filename = NULL; + + checked_free(filename); + + filename = getPath2(getCurrentLevelDir(), HELPANIM_FILENAME); + + return filename; +} + +char *getHelpTextFilename() +{ + static char *filename = NULL; + + checked_free(filename); + + filename = getPath2(getCurrentLevelDir(), HELPTEXT_FILENAME); + + return filename; +} + +char *getLevelSetInfoFilename() +{ + static char *filename = NULL; + char *basenames[] = + { + "README", + "README.txt", + "README.TXT", + "Readme", + "Readme.txt", + "readme", + "readme.txt", + + NULL + }; + int i; + + for (i = 0; basenames[i] != NULL; i++) + { + checked_free(filename); + + filename = getPath2(getCurrentLevelDir(), basenames[i]); + if (fileExists(filename)) + return filename; + } + + return NULL; +} + static char *getCorrectedArtworkBasename(char *basename) { char *basename_corrected = basename; @@ -424,8 +497,7 @@ static char *getCorrectedArtworkBasename(char *basename) { static char *msdos_filename = NULL; - if (msdos_filename != NULL) - free(msdos_filename); + checked_free(msdos_filename); msdos_filename = getStringCopy(basename_corrected); strncpy(&msdos_filename[8], &basename[strlen(basename) - (1+3)], 1+3 +1); @@ -443,8 +515,7 @@ char *getCustomImageFilename(char *basename) static char *filename = NULL; boolean skip_setup_artwork = FALSE; - if (filename != NULL) - free(filename); + checked_free(filename); basename = getCorrectedArtworkBasename(basename); @@ -502,8 +573,7 @@ char *getCustomSoundFilename(char *basename) static char *filename = NULL; boolean skip_setup_artwork = FALSE; - if (filename != NULL) - free(filename); + checked_free(filename); basename = getCorrectedArtworkBasename(basename); @@ -556,12 +626,72 @@ char *getCustomSoundFilename(char *basename) return NULL; /* cannot find specified artwork file anywhere */ } +char *getCustomMusicFilename(char *basename) +{ + static char *filename = NULL; + boolean skip_setup_artwork = FALSE; + + checked_free(filename); + + basename = getCorrectedArtworkBasename(basename); + + if (!setup.override_level_music) + { + /* 1st try: look for special artwork in current level series directory */ + filename = getPath3(getCurrentLevelDir(), MUSIC_DIRECTORY, basename); + if (fileExists(filename)) + return filename; + + free(filename); + + /* check if there is special artwork configured in level series config */ + if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL) + { + /* 2nd try: look for special artwork configured in level series config */ + filename = getPath2(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR), basename); + if (fileExists(filename)) + return filename; + + free(filename); + + /* take missing artwork configured in level set config from default */ + skip_setup_artwork = TRUE; + } + } + + if (!skip_setup_artwork) + { + /* 3rd try: look for special artwork in configured artwork directory */ + filename = getPath2(getSetupArtworkDir(artwork.mus_current), basename); + if (fileExists(filename)) + return filename; + + free(filename); + } + + /* 4th try: look for default artwork in new default artwork directory */ + filename = getPath2(getDefaultMusicDir(MUS_CLASSIC_SUBDIR), basename); + if (fileExists(filename)) + return filename; + + free(filename); + + /* 5th try: look for default artwork in old default artwork directory */ + filename = getPath2(options.music_directory, basename); + if (fileExists(filename)) + return filename; + + return NULL; /* cannot find specified artwork file anywhere */ +} + char *getCustomArtworkFilename(char *basename, int type) { if (type == ARTWORK_TYPE_GRAPHICS) return getCustomImageFilename(basename); else if (type == ARTWORK_TYPE_SOUNDS) return getCustomSoundFilename(basename); + else if (type == ARTWORK_TYPE_MUSIC) + return getCustomMusicFilename(basename); else return UNDEFINED_FILENAME; } @@ -575,8 +705,7 @@ char *getCustomArtworkLevelConfigFilename(int type) { static char *filename = NULL; - if (filename != NULL) - free(filename); + checked_free(filename); filename = getPath2(getLevelArtworkDir(type), ARTWORKINFO_FILENAME(type)); @@ -588,8 +717,7 @@ char *getCustomMusicDirectory(void) static char *directory = NULL; boolean skip_setup_artwork = FALSE; - if (directory != NULL) - free(directory); + checked_free(directory); if (!setup.override_level_music) { @@ -813,7 +941,7 @@ void dumpTreeInfo(TreeInfo *node, int depth) while (node) { - for (i=0; i<(depth + 1) * 3; i++) + for (i = 0; i < (depth + 1) * 3; i++) printf(" "); #if 1 @@ -859,7 +987,7 @@ void sortTreeInfo(TreeInfo **node_first, 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; @@ -1081,9 +1209,13 @@ char *getFormattedSetupEntry(char *token, char *value) int i; static char entry[MAX_LINE_LEN]; + /* if value is an empty string, just return token without value */ + if (*value == '\0') + return token; + /* start with the token and some spaces to format output line */ sprintf(entry, "%s:", token); - for (i=strlen(entry); itoken) - free(list->token); - if (list->value) - free(list->value); + checked_free(list->token); + checked_free(list->value); + if (list->next) freeSetupFileList(list->next); + free(list); } @@ -1136,8 +1268,7 @@ SetupFileList *setListEntry(SetupFileList *list, char *token, char *value) if (strcmp(list->token, token) == 0) { - if (list->value) - free(list->value); + checked_free(list->value); list->value = getStringCopy(value); @@ -1149,6 +1280,17 @@ SetupFileList *setListEntry(SetupFileList *list, char *token, char *value) return setListEntry(list->next, token, value); } +SetupFileList *addListEntry(SetupFileList *list, char *token, char *value) +{ + if (list == NULL) + return NULL; + + if (list->next == NULL) + return (list->next = newSetupFileList(token, value)); + else + return addListEntry(list->next, token, value); +} + #ifdef DEBUG static void printSetupFileList(SetupFileList *list) { @@ -1214,6 +1356,9 @@ SetupFileHash *newSetupFileHash() SetupFileHash *new_hash = create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal); + if (new_hash == NULL) + Error(ERR_EXIT, "create_hashtable() failed -- out of memory"); + return new_hash; } @@ -1248,6 +1393,14 @@ void setHashEntry(SetupFileHash *hash, char *token, char *value) Error(ERR_EXIT, "cannot insert into hash -- aborting"); } +char *removeHashEntry(SetupFileHash *hash, char *token) +{ + if (hash == NULL) + return NULL; + + return remove_hash_entry(hash, token); +} + #if 0 #ifdef DEBUG static void printSetupFileHash(SetupFileHash *hash) @@ -1264,10 +1417,10 @@ static void printSetupFileHash(SetupFileHash *hash) static void *loadSetupFileData(char *filename, boolean use_hash) { - int line_len; - char line[MAX_LINE_LEN]; + char line[MAX_LINE_LEN], previous_line[MAX_LINE_LEN]; char *token, *value, *line_ptr; void *setup_file_data, *insert_ptr = NULL; + boolean read_continued_line = FALSE; FILE *file; if (use_hash) @@ -1281,16 +1434,48 @@ static void *loadSetupFileData(char *filename, boolean use_hash) return NULL; } - while(!feof(file)) + 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 */ + /* cut trailing newline or carriage return */ + for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--) + if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0') + *line_ptr = '\0'; + + if (read_continued_line) + { + /* cut leading whitespaces from input line */ + for (line_ptr = line; *line_ptr; line_ptr++) + if (*line_ptr != ' ' && *line_ptr != '\t') + break; + + /* append new line to existing line, if there is enough space */ + if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN) + strcat(previous_line, line_ptr); + + strcpy(line, previous_line); /* copy storage buffer to line */ + + read_continued_line = FALSE; + } + + /* if the last character is '\', continue at next line */ + if (strlen(line) > 0 && line[strlen(line) - 1] == '\\') + { + line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */ + strcpy(previous_line, line); /* copy line to storage buffer */ + + read_continued_line = TRUE; + + continue; + } + + /* cut trailing comment from input line */ for (line_ptr = line; *line_ptr; line_ptr++) { - if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r') + if (*line_ptr == '#') { *line_ptr = '\0'; break; @@ -1298,47 +1483,50 @@ static void *loadSetupFileData(char *filename, boolean use_hash) } /* 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') + 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 */ + /* start with empty value as reliable default */ + value = ""; + + /* find end of token to determine start of value */ for (line_ptr = token; *line_ptr; line_ptr++) { if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') { - *line_ptr = '\0'; + *line_ptr = '\0'; /* terminate token string */ + value = line_ptr + 1; /* set beginning of value */ + 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) +#if 0 + if (*value == '\0') + value = "true"; /* treat tokens without value as "true" */ +#endif + + if (*token) { if (use_hash) setHashEntry((SetupFileHash *)setup_file_data, token, value); else - insert_ptr = setListEntry((SetupFileList *)insert_ptr, token, value); + insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value); } } @@ -1589,40 +1777,26 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent) static void freeTreeInfo(TreeInfo *ldi) { - if (ldi->filename) - free(ldi->filename); - if (ldi->fullpath) - free(ldi->fullpath); - if (ldi->basepath) - free(ldi->basepath); - if (ldi->identifier) - free(ldi->identifier); - - if (ldi->name) - free(ldi->name); - if (ldi->name_sorting) - free(ldi->name_sorting); - if (ldi->author) - free(ldi->author); - - if (ldi->class_desc) - free(ldi->class_desc); + checked_free(ldi->filename); + checked_free(ldi->fullpath); + checked_free(ldi->basepath); + checked_free(ldi->identifier); + + checked_free(ldi->name); + checked_free(ldi->name_sorting); + checked_free(ldi->author); + + checked_free(ldi->class_desc); if (ldi->type == TREE_TYPE_LEVEL_DIR) { - if (ldi->graphics_set) - free(ldi->graphics_set); - if (ldi->sounds_set) - free(ldi->sounds_set); - if (ldi->music_set) - free(ldi->music_set); - - if (ldi->graphics_path) - free(ldi->graphics_path); - if (ldi->sounds_path) - free(ldi->sounds_path); - if (ldi->music_path) - free(ldi->music_path); + checked_free(ldi->graphics_set); + checked_free(ldi->sounds_set); + checked_free(ldi->music_set); + + checked_free(ldi->graphics_path); + checked_free(ldi->sounds_path); + checked_free(ldi->music_path); } } @@ -1656,8 +1830,7 @@ void setSetupInfo(struct TokenInfo *token_info, break; case TYPE_STRING: - if (*(char **)setup_value != NULL) - free(*(char **)setup_value); + checked_free(*(char **)setup_value); *(char **)setup_value = getStringCopy(token_value); break; @@ -1783,7 +1956,7 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, /* set all structure fields according to the token/value pairs */ ldi = *leveldir_new; - for (i=0; ifullpath = getStringCopy(UNDEFINED_FILENAME); artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME); - if (artwork_new->name != NULL) - free(artwork_new->name); + checked_free(artwork_new->name); artwork_new->identifier = getStringCopy(UNDEFINED_FILENAME); artwork_new->name = getStringCopy(UNDEFINED_FILENAME); @@ -2458,7 +2630,7 @@ static void SaveUserLevelInfo() getCookie("LEVELINFO"))); ldi = *level_info; - for (i=0; i/levelsetup.conf */ /* ----------------------------------------------------------------------- */ - filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); + char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); + SetupFileHash *level_setup_hash = NULL; + + /* always start with reliable default values */ + leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); if ((level_setup_hash = loadSetupFileHash(filename))) { @@ -2591,17 +2761,15 @@ void LoadLevelSetup_LastSeries() void SaveLevelSetup_LastSeries() { - char *filename; - char *level_subdir = leveldir_current->filename; - FILE *file; - /* ----------------------------------------------------------------------- */ /* ~/./levelsetup.conf */ /* ----------------------------------------------------------------------- */ - InitUserDataDirectory(); + char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); + char *level_subdir = leveldir_current->filename; + FILE *file; - filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); + InitUserDataDirectory(); if (!(file = fopen(filename, MODE_WRITE))) { diff --git a/src/libgame/setup.h b/src/libgame/setup.h index 2498fe7d..1f46cc20 100644 --- a/src/libgame/setup.h +++ b/src/libgame/setup.h @@ -33,13 +33,14 @@ TYPE_YES_NO) /* additional values for setup screen */ -#define TYPE_ENTER_MENU (1 << 8) -#define TYPE_LEAVE_MENU (1 << 9) -#define TYPE_EMPTY (1 << 10) -#define TYPE_KEYTEXT (1 << 11) +#define TYPE_ENTER_SCREEN (1 << 8) +#define TYPE_ENTER_MENU (1 << 9) +#define TYPE_LEAVE_MENU (1 << 10) +#define TYPE_EMPTY (1 << 11) +#define TYPE_KEYTEXT (1 << 12) -#define TYPE_GHOSTED (1 << 12) -#define TYPE_QUERY (1 << 13) +#define TYPE_GHOSTED (1 << 13) +#define TYPE_QUERY (1 << 14) #define TYPE_VALUE (TYPE_BOOLEAN_STYLE | \ TYPE_KEY | \ @@ -52,7 +53,8 @@ TYPE_KEY | \ TYPE_STRING) -#define TYPE_ENTER_OR_LEAVE_MENU (TYPE_ENTER_MENU | \ +#define TYPE_ENTER_OR_LEAVE_MENU (TYPE_ENTER_SCREEN | \ + TYPE_ENTER_MENU | \ TYPE_LEAVE_MENU) /* cookie token for file identifier and version number */ @@ -67,7 +69,7 @@ struct TokenInfo /* some definitions for list and hash handling */ typedef struct SetupFileList SetupFileList; -typedef struct hashtable SetupFileHash; +typedef struct hashtable SetupFileHash; #define BEGIN_HASH_ITERATION(hash, itr) \ if (hash != NULL && hashtable_count(hash) > 0) \ @@ -194,11 +196,17 @@ typedef struct hashtable SetupFileHash; char *setLevelArtworkDir(TreeInfo *); char *getLevelFilename(int); char *getTapeFilename(int); +char *getSolutionTapeFilename(int); char *getScoreFilename(int); char *getSetupFilename(void); +char *getEditorSetupFilename(void); +char *getHelpAnimFilename(void); +char *getHelpTextFilename(void); +char *getLevelSetInfoFilename(void); char *getImageFilename(char *); char *getCustomImageFilename(char *); char *getCustomSoundFilename(char *); +char *getCustomMusicFilename(char *); char *getCustomArtworkFilename(char *, int); char *getCustomArtworkConfigFilename(int); char *getCustomArtworkLevelConfigFilename(int); @@ -240,12 +248,14 @@ SetupFileList *newSetupFileList(char *, char *); void freeSetupFileList(SetupFileList *); char *getListEntry(SetupFileList *, char *); SetupFileList *setListEntry(SetupFileList *, char *, char *); +SetupFileList *addListEntry(SetupFileList *, char *, char *); SetupFileList *loadSetupFileList(char *); SetupFileHash *newSetupFileHash(); void freeSetupFileHash(SetupFileHash *); char *getHashEntry(SetupFileHash *, char *); void setHashEntry(SetupFileHash *, char *, char *); +char *removeHashEntry(SetupFileHash *, char *); SetupFileHash *loadSetupFileHash(char *); void checkSetupFileHashIdentifier(SetupFileHash *, char *); void setSetupInfo(struct TokenInfo *, int, char *); diff --git a/src/libgame/sound.c b/src/libgame/sound.c index 72681647..a70ea3ac 100644 --- a/src/libgame/sound.c +++ b/src/libgame/sound.c @@ -149,14 +149,19 @@ struct SoundControl typedef struct SoundControl SoundControl; static struct ArtworkListInfo *sound_info = NULL; +static struct ArtworkListInfo *music_info = NULL; + #if 0 static SoundInfo **Sound = NULL; #endif -static MusicInfo **Music = NULL; + +static MusicInfo **Music_NoConf = NULL; + #if 0 static int num_sounds = 0; #endif -static int num_music = 0; + +static int num_music_noconf = 0; static int stereo_volume[SOUND_MAX_LEFT2RIGHT + 1]; @@ -179,8 +184,11 @@ static int ulaw_to_linear(unsigned char); static void ReloadCustomSounds(); static void ReloadCustomMusic(); static void FreeSound(void *); +static void FreeMusic(void *); +static void FreeAllMusic_NoConf(); static SoundInfo *getSoundInfoEntryFromSoundID(int); +static MusicInfo *getMusicInfoEntryFromMusicID(int); /* ------------------------------------------------------------------------- */ @@ -229,7 +237,7 @@ static boolean TestAudioDevices(void) int i; /* look for available audio devices, starting with preferred ones */ - for (i=0; i= 0) break; @@ -561,8 +569,7 @@ static void ReadReloadInfoFromPipe(SoundControl *snd_ctrl) &setup.override_level_sounds : &setup.override_level_music); - if (set_identifier) - free(set_identifier); + checked_free(set_identifier); set_identifier = checked_malloc(snd_ctrl->data_len); @@ -571,16 +578,12 @@ static void ReadReloadInfoFromPipe(SoundControl *snd_ctrl) if (ti == NULL) ti = *ti_ptr = checked_calloc(sizeof(TreeInfo)); - if (leveldir_current->fullpath != NULL) - free(leveldir_current->fullpath); - if (leveldir_current->sounds_path != NULL) - free(leveldir_current->sounds_path); - if (leveldir_current->music_path != NULL) - free(leveldir_current->music_path); - if (ti->basepath != NULL) - free(ti->basepath); - if (ti->fullpath != NULL) - free(ti->fullpath); + + checked_free(leveldir_current->fullpath); + checked_free(leveldir_current->sounds_path); + checked_free(leveldir_current->music_path); + checked_free(ti->basepath); + checked_free(ti->fullpath); if (read(audio.mixer_pipe[0], set_identifier, snd_ctrl->data_len) != snd_ctrl->data_len || @@ -637,7 +640,7 @@ void Mixer_InitChannels() { int i; - for(i=0; i= num_music) /* invalid music */ + return; + + if (snd_ctrl.nr < 0) /* undefined music */ + { + if (num_music_noconf == 0) /* no fallback music available */ + return; + + snd_ctrl.nr = UNMAP_NOCONF_MUSIC(snd_ctrl.nr) % num_music_noconf; + snd_info = Music_NoConf[snd_ctrl.nr]; + } + else + snd_info = getMusicInfoEntryFromMusicID(snd_ctrl.nr); + } + else + { + if (snd_ctrl.nr < 0 || snd_ctrl.nr >= num_sounds) + return; + + snd_info = getSoundInfoEntryFromSoundID(snd_ctrl.nr); + } + + /* + if (snd_ctrl.nr >= (IS_MUSIC(snd_ctrl) ? num_music : num_sounds)) + return; + */ +#else if (IS_MUSIC(snd_ctrl)) { - if (num_music == 0) + if (num_music_noconf == 0) return; - snd_ctrl.nr = snd_ctrl.nr % num_music; + snd_ctrl.nr = snd_ctrl.nr % num_music_noconf; } else if (snd_ctrl.nr >= num_sounds) return; +#endif #if 0 - snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] : Sound[snd_ctrl.nr]); +#if 1 + snd_info = (IS_MUSIC(snd_ctrl) ? getMusicInfoEntryFromMusicID(snd_ctrl.nr) : + getSoundInfoEntryFromSoundID(snd_ctrl.nr)); #else - snd_info = (IS_MUSIC(snd_ctrl) ? Music[snd_ctrl.nr] : + snd_info = (IS_MUSIC(snd_ctrl) ? Music_NoConf[snd_ctrl.nr] : getSoundInfoEntryFromSoundID(snd_ctrl.nr)); +#endif #endif if (snd_info == NULL) @@ -862,6 +910,10 @@ static void Mixer_InsertSound(SoundControl snd_ctrl) /* play music samples on a dedicated music channel */ if (IS_MUSIC(snd_ctrl)) { +#if 0 + printf("::: slot %d, ptr 0x%08x\n", snd_ctrl.nr, snd_ctrl.data_ptr); +#endif + Mixer_StopMusicChannel(); mixer[audio.music_channel] = snd_ctrl; @@ -871,7 +923,7 @@ static void Mixer_InsertSound(SoundControl snd_ctrl) } /* check if (and how often) this sound sample is already playing */ - for (k=0, i=audio.first_sound_channel; i 0 && IS_LOOP(snd_ctrl)) { - for(i=audio.first_sound_channel; idata_ptr + num_channels * sample_pos; - for (i=0; inum_channels == 1 ? 0 : i); - for (j=0; jdata_ptr + num_channels * sample_pos; - for (i=0; inum_channels == 1 ? 0 : i); - for (j=0; j= mixer[i].data_len) Mixer_StopChannel(i); - for(i=0; i> 8) ^ 0x80; /* finally play the sound fragment */ @@ -1392,7 +1444,7 @@ void Mixer_Main() FD_ZERO(&mixer_fdset); FD_SET(audio.mixer_pipe[0], &mixer_fdset); - while(1) /* wait for sound playing commands from client */ + while (1) /* wait for sound playing commands from client */ { struct timeval delay = { 0, 0 }; @@ -1765,11 +1817,11 @@ static void *Load_WAV(char *filename) int i; if (snd_ctrl->format == AUDIO_FORMAT_U8) - for (i=0; idata_ptr = Mix_LoadMUS(filename)) == NULL) + { + Error(ERR_WARN, "cannot read music file '%s'", filename); + free(mod_info); + return NULL; + } + + mod_info->type = MUS_TYPE_MOD; + mod_info->source_filename = getStringCopy(filename); + + return mod_info; +#else + return NULL; +#endif +} + +static void *Load_WAV_or_MOD(char *filename) +{ + if (FileIsSound(filename)) + return Load_WAV(filename); + else if (FileIsMusic(filename)) + return Load_MOD(filename); + else + return NULL; +} + +void LoadCustomMusic_NoConf(void) +{ + static boolean draw_init_text = TRUE; /* only draw at startup */ + static char *last_music_directory = NULL; + char *music_directory = getCustomMusicDirectory(); + DIR *dir; + struct dirent *dir_entry; + int num_music = getMusicListSize(); + + if (!audio.sound_available) + return; + + if (last_music_directory != NULL && + strcmp(last_music_directory, music_directory) == 0) + return; /* old and new music directory are the same */ + + if (last_music_directory != NULL) + free(last_music_directory); + last_music_directory = getStringCopy(music_directory); + + FreeAllMusic_NoConf(); + + if ((dir = opendir(music_directory)) == NULL) + { + Error(ERR_WARN, "cannot read music directory '%s'", music_directory); + audio.music_available = FALSE; + return; + } + + if (draw_init_text) + DrawInitText("Loading music:", 120, FC_GREEN); + + while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ + { + char *basename = dir_entry->d_name; + char *filename = NULL; + MusicInfo *mus_info = NULL; + boolean music_already_used = FALSE; + int i; + + for (i = 0; i < num_music; i++) + { + struct FileInfo *music = getMusicListEntry(i); + + if (strcmp(basename, music->filename) == 0) + { + music_already_used = TRUE; + break; + } + } + + if (music_already_used) + continue; + +#if 0 + if (FileIsSound(basename) || FileIsMusic(basename)) + printf("DEBUG: loading music '%s' ...\n", basename); +#endif + + if (draw_init_text) + DrawInitText(basename, 150, FC_YELLOW); + + filename = getPath2(music_directory, basename); + +#if 1 + if (FileIsMusic(basename)) + mus_info = Load_WAV_or_MOD(filename); +#else + if (FileIsSound(basename)) + mus_info = Load_WAV(filename); + else if (FileIsMusic(basename)) + mus_info = Load_MOD(filename); +#endif + + free(filename); + + if (mus_info) + { + num_music_noconf++; + Music_NoConf = checked_realloc(Music_NoConf, + num_music_noconf * sizeof(MusicInfo *)); + Music_NoConf[num_music_noconf - 1] = mus_info; + } + } + + closedir(dir); + + draw_init_text = FALSE; + + if (num_music_noconf == 0) + Error(ERR_WARN, "cannot find any valid music files in directory '%s'", + music_directory); +} + int getSoundListSize() { return (sound_info->num_file_list_entries + sound_info->num_dynamic_file_list_entries); } +int getMusicListSize() +{ + return (music_info->num_file_list_entries + + music_info->num_dynamic_file_list_entries); +} + struct FileInfo *getSoundListEntry(int pos) { int num_list_entries = sound_info->num_file_list_entries; @@ -1798,6 +1986,15 @@ struct FileInfo *getSoundListEntry(int pos) &sound_info->dynamic_file_list[list_pos]); } +struct FileInfo *getMusicListEntry(int pos) +{ + int num_list_entries = music_info->num_file_list_entries; + int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); + + return (pos < num_list_entries ? &music_info->file_list[list_pos] : + &music_info->dynamic_file_list[list_pos]); +} + static SoundInfo *getSoundInfoEntryFromSoundID(int pos) { int num_list_entries = sound_info->num_file_list_entries; @@ -1809,16 +2006,37 @@ static SoundInfo *getSoundInfoEntryFromSoundID(int pos) return snd_info[list_pos]; } +static MusicInfo *getMusicInfoEntryFromMusicID(int pos) +{ + int num_list_entries = music_info->num_file_list_entries; + int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); + MusicInfo **mus_info = + (MusicInfo **)(pos < num_list_entries ? music_info->artwork_list : + music_info->dynamic_artwork_list); + + return mus_info[list_pos]; +} + int getSoundListPropertyMappingSize() { return sound_info->num_property_mapping_entries; } +int getMusicListPropertyMappingSize() +{ + return music_info->num_property_mapping_entries; +} + struct PropertyMapping *getSoundListPropertyMapping() { return sound_info->property_mapping; } +struct PropertyMapping *getMusicListPropertyMapping() +{ + return music_info->property_mapping; +} + void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries, struct ConfigInfo *config_suffix_list, char **base_prefixes, char **ext1_suffixes, @@ -1841,7 +2059,7 @@ void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries, sound_info->dynamic_file_list = NULL; sound_info->num_suffix_list_entries = 0; - for (i=0; config_suffix_list[i].token != NULL; i++) + for (i = 0; config_suffix_list[i].token != NULL; i++) sound_info->num_suffix_list_entries++; sound_info->suffix_list = config_suffix_list; @@ -1849,23 +2067,23 @@ void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries, /* ---------- initialize base prefix and suffixes lists ---------- */ sound_info->num_base_prefixes = 0; - for (i=0; base_prefixes[i] != NULL; i++) + for (i = 0; base_prefixes[i] != NULL; i++) sound_info->num_base_prefixes++; sound_info->num_ext1_suffixes = 0; - for (i=0; ext1_suffixes[i] != NULL; i++) + for (i = 0; ext1_suffixes[i] != NULL; i++) sound_info->num_ext1_suffixes++; sound_info->num_ext2_suffixes = 0; - for (i=0; ext2_suffixes[i] != NULL; i++) + for (i = 0; ext2_suffixes[i] != NULL; i++) sound_info->num_ext2_suffixes++; sound_info->num_ext3_suffixes = 0; - for (i=0; ext3_suffixes[i] != NULL; i++) + for (i = 0; ext3_suffixes[i] != NULL; i++) sound_info->num_ext3_suffixes++; sound_info->num_ignore_tokens = 0; - for (i=0; ignore_tokens[i] != NULL; i++) + for (i = 0; ignore_tokens[i] != NULL; i++) sound_info->num_ignore_tokens++; sound_info->base_prefixes = base_prefixes; @@ -1899,98 +2117,79 @@ void InitSoundList(struct ConfigInfo *config_list, int num_file_list_entries, #endif } -static MusicInfo *Load_MOD(char *filename) +void InitMusicList(struct ConfigInfo *config_list, int num_file_list_entries, + struct ConfigInfo *config_suffix_list, + char **base_prefixes, char **ext1_suffixes, + char **ext2_suffixes, char **ext3_suffixes, + char **ignore_tokens) { -#if defined(TARGET_SDL) - MusicInfo *mod_info; + int i; - if (!audio.sound_available) - return NULL; + music_info = checked_calloc(sizeof(struct ArtworkListInfo)); + music_info->type = ARTWORK_TYPE_MUSIC; - mod_info = checked_calloc(sizeof(MusicInfo)); + /* ---------- initialize file list and suffix lists ---------- */ - if ((mod_info->data_ptr = Mix_LoadMUS(filename)) == NULL) - { - Error(ERR_WARN, "cannot read music file '%s'", filename); - free(mod_info); - return NULL; - } + music_info->num_file_list_entries = num_file_list_entries; + music_info->num_dynamic_file_list_entries = 0; - mod_info->type = MUS_TYPE_MOD; - mod_info->source_filename = getStringCopy(filename); + music_info->file_list = + getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, + num_file_list_entries); + music_info->dynamic_file_list = NULL; - return mod_info; -#else - return NULL; -#endif -} + music_info->num_suffix_list_entries = 0; + for (i = 0; config_suffix_list[i].token != NULL; i++) + music_info->num_suffix_list_entries++; -void LoadCustomMusic(void) -{ - static boolean draw_init_text = TRUE; /* only draw at startup */ - static char *last_music_directory = NULL; - char *music_directory = getCustomMusicDirectory(); - DIR *dir; - struct dirent *dir_entry; + music_info->suffix_list = config_suffix_list; - if (!audio.sound_available) - return; + /* ---------- initialize base prefix and suffixes lists ---------- */ - if (last_music_directory != NULL && - strcmp(last_music_directory, music_directory) == 0) - return; /* old and new music directory are the same */ + music_info->num_base_prefixes = 0; + for (i = 0; base_prefixes[i] != NULL; i++) + music_info->num_base_prefixes++; - if (last_music_directory != NULL) - free(last_music_directory); - last_music_directory = getStringCopy(music_directory); + music_info->num_ext1_suffixes = 0; + for (i = 0; ext1_suffixes[i] != NULL; i++) + music_info->num_ext1_suffixes++; - FreeAllMusic(); + music_info->num_ext2_suffixes = 0; + for (i = 0; ext2_suffixes[i] != NULL; i++) + music_info->num_ext2_suffixes++; - if ((dir = opendir(music_directory)) == NULL) - { - Error(ERR_WARN, "cannot read music directory '%s'", music_directory); - audio.music_available = FALSE; - return; - } + music_info->num_ext3_suffixes = 0; + for (i = 0; ext3_suffixes[i] != NULL; i++) + music_info->num_ext3_suffixes++; - if (draw_init_text) - DrawInitText("Loading music:", 120, FC_GREEN); + music_info->num_ignore_tokens = 0; + for (i = 0; ignore_tokens[i] != NULL; i++) + music_info->num_ignore_tokens++; - while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */ - { - char *basename = dir_entry->d_name; - char *filename = getPath2(music_directory, basename); - MusicInfo *mus_info = NULL; + music_info->base_prefixes = base_prefixes; + music_info->ext1_suffixes = ext1_suffixes; + music_info->ext2_suffixes = ext2_suffixes; + music_info->ext3_suffixes = ext3_suffixes; + music_info->ignore_tokens = ignore_tokens; -#if 0 - printf("DEBUG: loading music '%s' ...\n", basename); -#endif + music_info->num_property_mapping_entries = 0; - if (draw_init_text) - DrawInitText(basename, 150, FC_YELLOW); + music_info->property_mapping = NULL; - if (FileIsSound(basename)) - mus_info = Load_WAV(filename); - else if (FileIsMusic(basename)) - mus_info = Load_MOD(filename); + /* ---------- initialize artwork reference and content lists ---------- */ - free(filename); + music_info->sizeof_artwork_list_entry = sizeof(MusicInfo *); - if (mus_info) - { - num_music++; - Music = checked_realloc(Music, num_music * sizeof(MusicInfo *)); - Music[num_music - 1] = mus_info; - } - } + music_info->artwork_list = + checked_calloc(num_file_list_entries * sizeof(MusicInfo *)); + music_info->dynamic_artwork_list = NULL; - closedir(dir); + music_info->content_list = NULL; - draw_init_text = FALSE; + /* ---------- initialize artwork loading/freeing functions ---------- */ - if (num_music == 0) - Error(ERR_WARN, "cannot find any valid music files in directory '%s'", - music_directory); + music_info->load_artwork = Load_WAV_or_MOD; + music_info->free_artwork = FreeMusic; } void PlayMusic(int nr) @@ -2066,10 +2265,15 @@ void FadeSound(int nr) void FadeSounds() { - FadeMusic(); StopSoundExt(-1, SND_CTRL_FADE_ALL); } +void FadeSoundsAndMusic() +{ + FadeSounds(); + FadeMusic(); +} + void StopMusic(void) { if (!audio.music_available) @@ -2125,7 +2329,13 @@ static void ReloadCustomMusic() printf("DEBUG: reloading music '%s' ...\n", artwork.mus_current_identifier); #endif - LoadCustomMusic(); + LoadArtworkConfig(music_info); + ReloadCustomArtworkList(music_info); + +#if 1 + /* load all music files from directory not defined in "musicinfo.conf" */ + LoadCustomMusic_NoConf(); +#endif } void InitReloadCustomSounds(char *set_identifier) @@ -2147,6 +2357,7 @@ void InitReloadCustomMusic(char *set_identifier) return; #if defined(AUDIO_UNIX_NATIVE) + LoadArtworkConfig(music_info); /* also load config on sound client */ WriteReloadInfoToPipe(set_identifier, SND_CTRL_RELOAD_MUSIC); #else ReloadCustomMusic(); @@ -2171,14 +2382,15 @@ void FreeSound(void *ptr) #endif } - if (sound->source_filename) - free(sound->source_filename); + checked_free(sound->source_filename); free(sound); } -void FreeMusic(MusicInfo *music) +void FreeMusic(void *ptr) { + MusicInfo *music = (MusicInfo *)ptr; + if (music == NULL) return; @@ -2199,25 +2411,31 @@ void FreeMusic(MusicInfo *music) free(music); } -void FreeAllSounds() -{ - FreeCustomArtworkLists(sound_info); -} - -void FreeAllMusic() +static void FreeAllMusic_NoConf() { int i; - if (Music == NULL) + if (Music_NoConf == NULL) return; - for(i=0; isource_filename) - free(bitmap->source_filename); + checked_free(bitmap->source_filename); bitmap->source_filename = NULL; } @@ -559,9 +558,9 @@ inline void DrawLine(Bitmap *bitmap, int from_x, int from_y, { int x, y; - for (x=0; xwidth, &cursor->height); i = -1; - for (y=0; y < cursor->width; y++) + for (y = 0; y < cursor->width; y++) { - for (x=0; x < cursor->height; x++) + for (x = 0; x < cursor->height; x++) { int bit_nr = x % 8; int bit_mask = 0x01 << (bit_order_msb ? 7 - bit_nr : bit_nr ); @@ -1165,7 +1164,7 @@ inline void InitJoysticks() /* always start with reliable default values */ joystick.status = JOYSTICK_NOT_AVAILABLE; - for (i=0; i= gfx.sx && x < gfx.sx + gfx.sxsize && \ + y >= gfx.sy && y < gfx.sy + gfx.sysize) +#define IN_GFX_DOOR(x, y) (x >= gfx.dx && x < gfx.dx + gfx.dxsize && \ + y >= gfx.dy && y < gfx.dy + gfx.dysize) +#define IN_GFX_VIDEO(x, y) (x >= gfx.vx && x < gfx.vx + gfx.vxsize && \ + y >= gfx.vy && y < gfx.vy + gfx.vysize) /* values for mouse cursor */ #define CURSOR_DEFAULT 0 @@ -175,6 +181,9 @@ /* default name for unknown player names */ #define ANONYMOUS_NAME "anonymous" +/* default for other unknown names */ +#define UNKNOWN_NAME "unknown" + /* default name for new levels */ #define NAMELESS_LEVEL_NAME "nameless level" @@ -227,6 +236,9 @@ #define LEVELSETUP_DIRECTORY "levelsetup" #define SETUP_FILENAME "setup.conf" #define LEVELSETUP_FILENAME "levelsetup.conf" +#define EDITORSETUP_FILENAME "editorsetup.conf" +#define HELPANIM_FILENAME "helpanim.conf" +#define HELPTEXT_FILENAME "helptext.conf" #define LEVELINFO_FILENAME "levelinfo.conf" #define GRAPHICSINFO_FILENAME "graphicsinfo.conf" #define SOUNDSINFO_FILENAME "soundsinfo.conf" @@ -238,6 +250,9 @@ #define LEVELSETUP_DIRECTORY "lvlsetup" #define SETUP_FILENAME "setup.cnf" #define LEVELSETUP_FILENAME "lvlsetup.cnf" +#define EDITORSETUP_FILENAME "edsetup.cnf" +#define HELPANIM_FILENAME "helpanim.conf" +#define HELPTEXT_FILENAME "helptext.conf" #define LEVELINFO_FILENAME "lvlinfo.cnf" #define GRAPHICSINFO_FILENAME "gfxinfo.cnf" #define SOUNDSINFO_FILENAME "sndinfo.cnf" @@ -539,6 +554,7 @@ struct SetupEditorInfo boolean el_chars; boolean el_custom; boolean el_custom_more; + boolean el_user_defined; boolean el_headlines; }; diff --git a/src/libgame/text.c b/src/libgame/text.c index f41635ae..6fd43735 100644 --- a/src/libgame/text.c +++ b/src/libgame/text.c @@ -50,7 +50,7 @@ static void InitFontClipmasks() clip_gc_valuemask, &clip_gc_values); /* create only those clipping Pixmaps we really need */ - for (i=0; i < gfx.num_fonts; i++) + for (i = 0; i < gfx.num_fonts; i++) { if (gfx.font_bitmap_info[i].bitmap == NULL) continue; @@ -58,7 +58,7 @@ static void InitFontClipmasks() gfx.font_bitmap_info[i].clip_mask = checked_calloc(gfx.font_bitmap_info[i].num_chars * sizeof(Pixmap)); - for (j=0; j < gfx.font_bitmap_info[i].num_chars; j++) + for (j = 0; j < gfx.font_bitmap_info[i].num_chars; j++) { Bitmap *src_bitmap = gfx.font_bitmap_info[i].bitmap; Pixmap src_pixmap = src_bitmap->clip_mask; @@ -87,11 +87,11 @@ static void FreeFontClipmasks() if (gfx.num_fonts == 0 || gfx.font_bitmap_info[0].bitmap == NULL) return; - for (i=0; i < gfx.num_fonts; i++) + for (i = 0; i < gfx.num_fonts; i++) { if (gfx.font_bitmap_info[i].clip_mask) { - for (j=0; j < gfx.font_bitmap_info[i].num_chars; j++) + for (j = 0; j < gfx.font_bitmap_info[i].num_chars; j++) XFreePixmap(display, gfx.font_bitmap_info[i].clip_mask[j]); free(gfx.font_bitmap_info[i].clip_mask); } @@ -191,7 +191,7 @@ void DrawInitText(char *text, int ypos, int font_nr) } } -void DrawTextFCentered(int y, int font_nr, char *format, ...) +void DrawTextF(int x, int y, int font_nr, char *format, ...) { char buffer[MAX_OUTPUT_LINESIZE + 1]; va_list ap; @@ -201,13 +201,12 @@ void DrawTextFCentered(int y, int font_nr, char *format, ...) va_end(ap); if (strlen(buffer) > MAX_OUTPUT_LINESIZE) - Error(ERR_EXIT, "string too long in DrawTextFCentered() -- aborting"); + Error(ERR_EXIT, "string too long in DrawTextF() -- aborting"); - DrawText(gfx.sx + (gfx.sxsize - getTextWidth(buffer, font_nr)) / 2, - gfx.sy + y, buffer, font_nr); + DrawText(gfx.sx + x, gfx.sy + y, buffer, font_nr); } -void DrawTextF(int x, int y, int font_nr, char *format, ...) +void DrawTextFCentered(int y, int font_nr, char *format, ...) { char buffer[MAX_OUTPUT_LINESIZE + 1]; va_list ap; @@ -217,9 +216,21 @@ void DrawTextF(int x, int y, int font_nr, char *format, ...) va_end(ap); if (strlen(buffer) > MAX_OUTPUT_LINESIZE) - Error(ERR_EXIT, "string too long in DrawTextF() -- aborting"); + Error(ERR_EXIT, "string too long in DrawTextFCentered() -- aborting"); - DrawText(gfx.sx + x, gfx.sy + y, buffer, font_nr); + DrawText(gfx.sx + (gfx.sxsize - getTextWidth(buffer, font_nr)) / 2, + gfx.sy + y, buffer, font_nr); +} + +void DrawTextS(int x, int y, int font_nr, char *text) +{ + DrawText(gfx.sx + x, gfx.sy + y, text, font_nr); +} + +void DrawTextSCentered(int y, int font_nr, char *text) +{ + DrawText(gfx.sx + (gfx.sxsize - getTextWidth(text, font_nr)) / 2, + gfx.sy + y, text, font_nr); } void DrawText(int x, int y, char *text, int font_nr) @@ -340,7 +351,7 @@ void DrawTextToTextArea(int x, int y, char *text, int font_nr, int line_length, char buffer[MAX_OUTPUT_LINESIZE + 1]; int i; - for (i=0; i < line_length && *text; i++) + for (i = 0; i < line_length && *text; i++) if ((buffer[i] = *text++) == '\n') break; buffer[MIN(i, area_xsize)] = '\0'; @@ -353,3 +364,183 @@ void DrawTextToTextArea(int x, int y, char *text, int font_nr, int line_length, redraw_mask |= REDRAW_FIELD; } + +boolean RenderLineToBuffer(char **src_buffer_ptr, char *dst_buffer, + int *dst_buffer_len, boolean last_line_was_empty, + int line_length) +{ + char *text_ptr = *src_buffer_ptr; + char *buffer = dst_buffer; + int buffer_len = *dst_buffer_len; + boolean buffer_filled = FALSE; + + while (*text_ptr) + { + char *word_ptr; + int word_len; + + /* skip leading whitespaces */ + while (*text_ptr == ' ' || *text_ptr == '\t') + text_ptr++; + + word_ptr = text_ptr; + word_len = 0; + + /* look for end of next word */ + while (*word_ptr != ' ' && *word_ptr != '\t' && *word_ptr != '\0') + { + word_ptr++; + word_len++; + } + + if (word_len == 0) + { + continue; + } + else if (*text_ptr == '\n') /* special case: force empty line */ + { + if (buffer_len == 0) + text_ptr++; + + /* prevent printing of multiple empty lines */ + if (buffer_len > 0 || !last_line_was_empty) + buffer_filled = TRUE; + } + else if (word_len < line_length - buffer_len) + { + /* word fits into text buffer -- add word */ + + if (buffer_len > 0) + buffer[buffer_len++] = ' '; + + strncpy(&buffer[buffer_len], text_ptr, word_len); + buffer_len += word_len; + buffer[buffer_len] = '\0'; + text_ptr += word_len; + } + else if (buffer_len > 0) + { + /* not enough space left for word in text buffer -- print buffer */ + + buffer_filled = TRUE; + } + else + { + /* word does not fit at all into empty text buffer -- cut word */ + + strncpy(buffer, text_ptr, line_length); + buffer[line_length] = '\0'; + text_ptr += line_length; + buffer_filled = TRUE; + } + + if (buffer_filled) + break; + } + + *src_buffer_ptr = text_ptr; + *dst_buffer_len = buffer_len; + + return buffer_filled; +} + +void DrawTextWrapped(int x, int y, char *text, int font_nr, int line_length, + int max_lines) +{ + char *text_ptr = text; + char buffer[line_length + 1]; + int buffer_len; + int current_line = 0; + int font_height = getFontHeight(font_nr); + + while (*text_ptr && current_line < max_lines) + { + buffer[0] = '\0'; + buffer_len = 0; + + RenderLineToBuffer(&text_ptr, buffer, &buffer_len, TRUE, line_length); + + DrawText(x, y + current_line * font_height, buffer, font_nr); + current_line++; + } +} + +int DrawTextFromFile(int x, int y, char *filename, int font_nr, + int line_length, int max_lines) +{ + int font_height = getFontHeight(font_nr); + char line[MAX_LINE_LEN]; + char buffer[line_length + 1]; + int buffer_len; + int current_line = 0; + FILE *file; + + if (current_line >= max_lines) + return 0; + + if (filename == NULL) + return 0; + + if (!(file = fopen(filename, MODE_READ))) + return 0; + + buffer[0] = '\0'; + buffer_len = 0; + + while (!feof(file) && current_line < max_lines) + { + char *line_ptr; + boolean last_line_was_empty = TRUE; + + /* read next line of input file */ + if (!fgets(line, MAX_LINE_LEN, file)) + break; + + /* skip comments (lines directly beginning with '#') */ + if (line[0] == '#') + continue; + + /* cut trailing newline from input line */ + for (line_ptr = line; *line_ptr; line_ptr++) + { + if (*line_ptr == '\n' || *line_ptr == '\r') + { + *line_ptr = '\0'; + break; + } + } + + if (strlen(line) == 0) /* special case: force empty line */ + strcpy(line, "\n"); + + line_ptr = line; + + while (*line_ptr && current_line < max_lines) + { + boolean buffer_filled = RenderLineToBuffer(&line_ptr, + buffer, &buffer_len, + last_line_was_empty, + line_length); + if (buffer_filled) + { + DrawText(x, y + current_line * font_height, buffer, font_nr); + current_line++; + + last_line_was_empty = (buffer_len == 0); + + buffer[0] = '\0'; + buffer_len = 0; + } + } + } + + fclose(file); + + if (buffer_len > 0 && current_line < max_lines) + { + DrawText(x, y + current_line * font_height, buffer, font_nr); + current_line++; + } + + return current_line; +} diff --git a/src/libgame/text.h b/src/libgame/text.h index dc29e283..0c5c7586 100644 --- a/src/libgame/text.h +++ b/src/libgame/text.h @@ -64,8 +64,13 @@ void getFontCharSource(int, char, Bitmap **, int *, int *); void DrawInitText(char *, int, int); void DrawTextF(int, int, int, char *, ...); void DrawTextFCentered(int, int, char *, ...); +void DrawTextS(int, int, int, char *); +void DrawTextSCentered(int, int, char *); void DrawText(int, int, char *, int); void DrawTextExt(DrawBuffer *, int, int, char *, int, int); void DrawTextToTextArea(int, int, char *, int, int, int, int, int); +boolean RenderLineToBuffer(char **, char *, int *, boolean, int); +void DrawTextWrapped(int, int, char *, int, int, int); +int DrawTextFromFile(int, int, char *, int, int, int); #endif /* TEXT_H */ diff --git a/src/libgame/x11.c b/src/libgame/x11.c index d7acc801..ce520f64 100644 --- a/src/libgame/x11.c +++ b/src/libgame/x11.c @@ -214,7 +214,7 @@ static DrawWindow *X11InitWindow() XCreateGC(display, new_window->drawable, gc_valuemask, &gc_values); /* create GCs for line drawing (black and white) */ - for(i=0; i<2; i++) + for (i = 0; i < 2; i++) { gc_values.graphics_exposures = False; gc_values.foreground = (i ? pen_fg : pen_bg); diff --git a/src/main.c b/src/main.c index a06efd1f..7e73ba2b 100644 --- a/src/main.c +++ b/src/main.c @@ -60,6 +60,8 @@ short AmoebaCnt[MAX_NUM_AMOEBA]; short AmoebaCnt2[MAX_NUM_AMOEBA]; short ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +int RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +int PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; unsigned long Properties[MAX_NUM_ELEMENTS][NUM_EP_BITFIELDS]; @@ -91,6 +93,7 @@ int TimeFrames, TimePlayed, TimeLeft; boolean network_player_action_received = FALSE; +struct LevelSetInfo levelset; struct LevelInfo level, level_template; struct PlayerInfo stored_player[MAX_PLAYERS], *local_player = NULL; struct HiScore highscore[MAX_SCORE_ENTRIES]; @@ -102,6 +105,10 @@ struct MenuInfo menu; struct DoorInfo door_1, door_2; struct GraphicInfo *graphic_info = NULL; struct SoundInfo *sound_info = NULL; +struct MusicInfo *music_info = NULL; +struct MusicFileInfo *music_file_info = NULL; +struct HelpAnimInfo *helpanim_info = NULL; +SetupFileHash *helptext_info = NULL; /* ------------------------------------------------------------------------- */ @@ -429,9 +436,9 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] = "invisible steel wall" }, { - "unused_63", - "unused", - "(not used)" + "maze_runner", + "maze_runner", + "maze runner" }, { "dynabomb_increase_number", @@ -3473,12 +3480,12 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] = "-" }, { - "nut_breaking", + "nut.breaking", "-", "-" }, { - "diamond_breaking", + "diamond.breaking", "-", "-" }, @@ -3493,12 +3500,12 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] = "-" }, { - "amoeba_growing", + "amoeba.growing", "-", "-" }, { - "amoeba_shrinking", + "amoeba.shrinking", "-", "-" }, @@ -3637,6 +3644,11 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] = "-", "-" }, + { + "amoeba", + "amoeba", + "-" + }, { "[default]", "default", @@ -3657,6 +3669,11 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] = "sb_default", "-" }, + { + "dummy", + "dummy", + "-" + }, /* keyword to stop parser: "ELEMENT_INFO_END" <-- do not change! */ @@ -3699,6 +3716,22 @@ struct ElementActionInfo element_action_info[NUM_ACTIONS + 1 + 1] = { ".emptying", ACTION_EMPTYING, FALSE }, { ".changing", ACTION_CHANGING, FALSE }, { ".exploding", ACTION_EXPLODING, FALSE }, + { ".boring", ACTION_BORING, FALSE }, + { ".boring[1]", ACTION_BORING_1, FALSE }, + { ".boring[2]", ACTION_BORING_2, FALSE }, + { ".boring[3]", ACTION_BORING_3, FALSE }, + { ".boring[4]", ACTION_BORING_4, FALSE }, + { ".boring[5]", ACTION_BORING_5, FALSE }, + { ".boring[6]", ACTION_BORING_6, FALSE }, + { ".boring[7]", ACTION_BORING_7, FALSE }, + { ".boring[8]", ACTION_BORING_8, FALSE }, + { ".boring[9]", ACTION_BORING_9, FALSE }, + { ".boring[10]", ACTION_BORING_10, FALSE }, + { ".sleeping", ACTION_SLEEPING, FALSE }, + { ".sleeping[1]", ACTION_SLEEPING_1, FALSE }, + { ".sleeping[2]", ACTION_SLEEPING_2, FALSE }, + { ".sleeping[3]", ACTION_SLEEPING_3, FALSE }, + { ".awakening", ACTION_AWAKENING, FALSE }, { ".dying", ACTION_DYING, FALSE }, { ".turning", ACTION_TURNING, FALSE }, { ".turning_from_left", ACTION_TURNING_FROM_LEFT, FALSE }, @@ -3723,8 +3756,9 @@ struct ElementDirectionInfo element_direction_info[NUM_DIRECTIONS + 1] = { NULL, 0 } }; -struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1] = +struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1 + 1] = { + { ".[DEFAULT]", GAME_MODE_DEFAULT, }, { ".MAIN", GAME_MODE_MAIN, }, { ".LEVELS", GAME_MODE_LEVELS }, { ".SCORES", GAME_MODE_SCORES, }, @@ -3736,6 +3770,9 @@ struct SpecialSuffixInfo special_suffix_info[NUM_SPECIAL_GFX_ARGS + 1] = { ".PREVIEW", GAME_MODE_PSEUDO_PREVIEW, }, { ".CRUMBLED", GAME_MODE_PSEUDO_CRUMBLED, }, + /* empty suffix always matches -- check as last entry in InitMusicInfo() */ + { "", GAME_MODE_DEFAULT, }, + { NULL, 0, } }; @@ -3772,6 +3809,11 @@ struct TokenIntPtrInfo image_config_vars[] = { "door_2.step_delay", &door_2.step_delay }, { "door_2.anim_mode", &door_2.anim_mode }, + { "[player].boring_delay_fixed", &game.player_boring_delay_fixed }, + { "[player].boring_delay_random", &game.player_boring_delay_random }, + { "[player].sleeping_delay_fixed", &game.player_sleeping_delay_fixed }, + { "[player].sleeping_delay_random", &game.player_sleeping_delay_random }, + { NULL, NULL, } }; @@ -3820,10 +3862,54 @@ struct FontInfo font_info[NUM_FONTS + 1] = }; +/* ------------------------------------------------------------------------- */ +/* music token prefix definitions */ +/* ------------------------------------------------------------------------- */ + +struct MusicPrefixInfo music_prefix_info[NUM_MUSIC_PREFIXES + 1] = +{ + { "background", TRUE }, + + { NULL, 0 } +}; + + /* ========================================================================= */ /* main() */ /* ========================================================================= */ +static void print_usage() +{ + printf("\n" + "Usage: %s [OPTION]... [HOSTNAME [PORT]]\n" + "\n" + "Options:\n" + " -d, --display HOSTNAME[:SCREEN] specify X server display\n" + " -b, --basepath DIRECTORY alternative base DIRECTORY\n" + " -l, --level DIRECTORY alternative level DIRECTORY\n" + " -g, --graphics DIRECTORY alternative graphics DIRECTORY\n" + " -s, --sounds DIRECTORY alternative sounds DIRECTORY\n" + " -m, --music DIRECTORY alternative music DIRECTORY\n" + " -n, --network network multiplayer game\n" + " --serveronly only start network server\n" + " -v, --verbose verbose mode\n" + " --debug display debugging information\n" + " -e, --execute COMMAND execute batch COMMAND:\n" + "\n" + "Valid commands for '--execute' option:\n" + " \"print graphicsinfo.conf\" print default graphics config\n" + " \"print soundsinfo.conf\" print default sounds config\n" + " \"print musicinfo.conf\" print default music config\n" + " \"print editorsetup.conf\" print default editor config\n" + " \"print helpanim.conf\" print default helpanim config\n" + " \"print helptext.conf\" print default helptext config\n" + " \"dump level FILE\" dump level data from FILE\n" + " \"dump tape FILE\" dump tape data from FILE\n" + " \"autoplay LEVELDIR\" play level tapes for LEVELDIR\n" + "\n", + program.command_basename); +} + int main(int argc, char *argv[]) { InitProgramInfo(argv[0], USERDATA_DIRECTORY, @@ -3835,7 +3921,7 @@ int main(int argc, char *argv[]) InitExitFunction(CloseAllAndExit); InitPlatformDependentStuff(); - GetOptions(argv); + GetOptions(argv, print_usage); OpenAll(); EventLoop(); diff --git a/src/main.h b/src/main.h index 273052ec..9484a5c6 100644 --- a/src/main.h +++ b/src/main.h @@ -26,6 +26,7 @@ #include "conf_gfx.h" /* include auto-generated data structure definitions */ #include "conf_snd.h" /* include auto-generated data structure definitions */ +#include "conf_mus.h" /* include auto-generated data structure definitions */ #define IMG_UNDEFINED (-1) #define IMG_EMPTY IMG_EMPTY_SPACE @@ -35,6 +36,7 @@ #define IMG_CUSTOM_START IMG_CUSTOM_1 #define SND_UNDEFINED (-1) +#define MUS_UNDEFINED (-1) #define WIN_XSIZE 672 #define WIN_YSIZE 560 @@ -159,7 +161,7 @@ #define CE_PRESSED_BY_PLAYER 2 #define CE_PUSHED_BY_PLAYER 3 #define CE_DROPPED_BY_PLAYER 4 -#define CE_COLLISION 5 +#define CE_COLLISION_ACTIVE 5 #define CE_IMPACT 6 #define CE_SMASHED 7 #define CE_OTHER_IS_TOUCHING 8 @@ -170,8 +172,8 @@ #define CE_OTHER_GETS_PUSHED 13 #define CE_OTHER_GETS_COLLECTED 14 #define CE_OTHER_GETS_DROPPED 15 -#define CE_BY_PLAYER 16 /* obsolete; now CE_BY_DIRECT_ACTION */ -#define CE_BY_COLLISION 17 /* obsolete; now CE_BY_DIRECT_ACTION */ +#define CE_BY_PLAYER_OBSOLETE 16 /* obsolete; now CE_BY_DIRECT_ACTION */ +#define CE_BY_COLLISION_OBSOLETE 17 /* obsolete; now CE_BY_DIRECT_ACTION */ #define CE_BY_OTHER_ACTION 18 /* activates other element events */ #define CE_BY_DIRECT_ACTION 19 /* activates direct element events */ #define CE_OTHER_GETS_DIGGED 20 @@ -181,8 +183,11 @@ #define CE_OTHER_GETS_LEFT 24 #define CE_SWITCHED 25 #define CE_OTHER_IS_SWITCHING 26 +#define CE_COLLISION_PASSIVE 27 +#define CE_OTHER_IS_COLL_ACTIVE 28 +#define CE_OTHER_IS_COLL_PASSIVE 29 -#define NUM_CHANGE_EVENTS 27 +#define NUM_CHANGE_EVENTS 30 #define CE_BITMASK_DEFAULT 0 @@ -222,6 +227,8 @@ #define MV_BIT_TURNING_LEFT 8 #define MV_BIT_TURNING_RIGHT 9 #define MV_BIT_WHEN_PUSHED 10 +#define MV_BIT_MAZE_RUNNER 11 +#define MV_BIT_MAZE_HUNTER 12 /* values for special move patterns for custom elements */ #define MV_HORIZONTAL (MV_LEFT | MV_RIGHT) @@ -235,6 +242,9 @@ #define MV_TURNING_LEFT (1 << MV_BIT_TURNING_LEFT) #define MV_TURNING_RIGHT (1 << MV_BIT_TURNING_RIGHT) #define MV_WHEN_PUSHED (1 << MV_BIT_WHEN_PUSHED) +#define MV_MAZE_RUNNER (1 << MV_BIT_MAZE_RUNNER) +#define MV_MAZE_HUNTER (1 << MV_BIT_MAZE_HUNTER) +#define MV_MAZE_RUNNER_STYLE (MV_MAZE_RUNNER | MV_MAZE_HUNTER) /* values for slippery property for custom elements */ #define SLIPPERY_ANY_RANDOM 0 @@ -512,7 +522,7 @@ #define EL_BD_MAGIC_WALL 61 #define EL_INVISIBLE_STEELWALL 62 -#define EL_UNUSED_63 63 +#define EL_MAZE_RUNNER 63 #define EL_DYNABOMB_INCREASE_NUMBER 64 #define EL_DYNABOMB_INCREASE_SIZE 65 @@ -880,12 +890,14 @@ #define EL_DYNABOMB_PLAYER_4 (EL_FIRST_DUMMY + 17) #define EL_SHIELD_NORMAL_ACTIVE (EL_FIRST_DUMMY + 18) #define EL_SHIELD_DEADLY_ACTIVE (EL_FIRST_DUMMY + 19) -#define EL_DEFAULT (EL_FIRST_DUMMY + 20) -#define EL_BD_DEFAULT (EL_FIRST_DUMMY + 21) -#define EL_SP_DEFAULT (EL_FIRST_DUMMY + 22) -#define EL_SB_DEFAULT (EL_FIRST_DUMMY + 23) +#define EL_AMOEBA (EL_FIRST_DUMMY + 20) +#define EL_DEFAULT (EL_FIRST_DUMMY + 21) +#define EL_BD_DEFAULT (EL_FIRST_DUMMY + 22) +#define EL_SP_DEFAULT (EL_FIRST_DUMMY + 23) +#define EL_SB_DEFAULT (EL_FIRST_DUMMY + 24) +#define EL_DUMMY (EL_FIRST_DUMMY + 25) -#define MAX_NUM_ELEMENTS (EL_FIRST_DUMMY + 24) +#define MAX_NUM_ELEMENTS (EL_FIRST_DUMMY + 26) /* values for graphics/sounds action types */ @@ -914,29 +926,50 @@ #define ACTION_EMPTYING 22 #define ACTION_CHANGING 23 #define ACTION_EXPLODING 24 -#define ACTION_DYING 25 -#define ACTION_TURNING 26 -#define ACTION_TURNING_FROM_LEFT 27 -#define ACTION_TURNING_FROM_RIGHT 28 -#define ACTION_TURNING_FROM_UP 29 -#define ACTION_TURNING_FROM_DOWN 30 -#define ACTION_OTHER 31 +#define ACTION_BORING 25 +#define ACTION_BORING_1 26 +#define ACTION_BORING_2 27 +#define ACTION_BORING_3 28 +#define ACTION_BORING_4 29 +#define ACTION_BORING_5 30 +#define ACTION_BORING_6 31 +#define ACTION_BORING_7 32 +#define ACTION_BORING_8 33 +#define ACTION_BORING_9 34 +#define ACTION_BORING_10 35 +#define ACTION_SLEEPING 36 +#define ACTION_SLEEPING_1 37 +#define ACTION_SLEEPING_2 38 +#define ACTION_SLEEPING_3 39 +#define ACTION_AWAKENING 40 +#define ACTION_DYING 41 +#define ACTION_TURNING 42 +#define ACTION_TURNING_FROM_LEFT 43 +#define ACTION_TURNING_FROM_RIGHT 44 +#define ACTION_TURNING_FROM_UP 45 +#define ACTION_TURNING_FROM_DOWN 46 +#define ACTION_OTHER 47 + +#define NUM_ACTIONS 48 + +#define ACTION_BORING_LAST ACTION_BORING_10 +#define ACTION_SLEEPING_LAST ACTION_SLEEPING_3 -#define NUM_ACTIONS 32 /* values for special image configuration suffixes (must match game mode) */ -#define GFX_SPECIAL_ARG_MAIN 0 -#define GFX_SPECIAL_ARG_LEVELS 1 -#define GFX_SPECIAL_ARG_SCORES 2 -#define GFX_SPECIAL_ARG_EDITOR 3 -#define GFX_SPECIAL_ARG_INFO 4 -#define GFX_SPECIAL_ARG_SETUP 5 -#define GFX_SPECIAL_ARG_PLAYING 6 -#define GFX_SPECIAL_ARG_DOOR 7 -#define GFX_SPECIAL_ARG_PREVIEW 8 -#define GFX_SPECIAL_ARG_CRUMBLED 9 +#define GFX_SPECIAL_ARG_DEFAULT 0 +#define GFX_SPECIAL_ARG_MAIN 1 +#define GFX_SPECIAL_ARG_LEVELS 2 +#define GFX_SPECIAL_ARG_SCORES 3 +#define GFX_SPECIAL_ARG_EDITOR 4 +#define GFX_SPECIAL_ARG_INFO 5 +#define GFX_SPECIAL_ARG_SETUP 6 +#define GFX_SPECIAL_ARG_PLAYING 7 +#define GFX_SPECIAL_ARG_DOOR 8 +#define GFX_SPECIAL_ARG_PREVIEW 9 +#define GFX_SPECIAL_ARG_CRUMBLED 10 -#define NUM_SPECIAL_GFX_ARGS 10 +#define NUM_SPECIAL_GFX_ARGS 11 /* values for image configuration suffixes */ @@ -966,9 +999,13 @@ #define GFX_ARG_DRAW_XOFFSET 23 #define GFX_ARG_DRAW_YOFFSET 24 #define GFX_ARG_DRAW_MASKED 25 -#define GFX_ARG_NAME 26 +#define GFX_ARG_ANIM_DELAY_FIXED 26 +#define GFX_ARG_ANIM_DELAY_RANDOM 27 +#define GFX_ARG_POST_DELAY_FIXED 28 +#define GFX_ARG_POST_DELAY_RANDOM 29 +#define GFX_ARG_NAME 30 -#define NUM_GFX_ARGS 27 +#define NUM_GFX_ARGS 31 /* values for sound configuration suffixes */ @@ -977,8 +1014,13 @@ #define NUM_SND_ARGS 1 -/* values for font configuration */ +/* values for music configuration suffixes */ +#define MUS_ARG_MODE_LOOP 0 + +#define NUM_MUS_ARGS 1 + +/* values for font configuration */ #define FONT_INITIAL_1 0 #define FONT_INITIAL_2 1 #define FONT_INITIAL_3 2 @@ -1016,40 +1058,43 @@ #define NUM_INITIAL_FONTS 4 /* values for game_status (must match special image configuration suffixes) */ -#define GAME_MODE_MAIN 0 -#define GAME_MODE_LEVELS 1 -#define GAME_MODE_SCORES 2 -#define GAME_MODE_EDITOR 3 -#define GAME_MODE_INFO 4 -#define GAME_MODE_SETUP 5 -#define GAME_MODE_PLAYING 6 -#define GAME_MODE_PSEUDO_DOOR 7 -#define GAME_MODE_PSEUDO_PREVIEW 8 -#define GAME_MODE_PSEUDO_CRUMBLED 9 +#define GAME_MODE_DEFAULT 0 +#define GAME_MODE_MAIN 1 +#define GAME_MODE_LEVELS 2 +#define GAME_MODE_SCORES 3 +#define GAME_MODE_EDITOR 4 +#define GAME_MODE_INFO 5 +#define GAME_MODE_SETUP 6 +#define GAME_MODE_PLAYING 7 +#define GAME_MODE_PSEUDO_DOOR 8 +#define GAME_MODE_PSEUDO_PREVIEW 9 +#define GAME_MODE_PSEUDO_CRUMBLED 10 /* there are no special config file suffixes for these modes */ -#define GAME_MODE_PSEUDO_TYPENAME 10 -#define GAME_MODE_QUIT 11 +#define GAME_MODE_PSEUDO_TYPENAME 11 +#define GAME_MODE_QUIT 12 + +/* special definitions currently only used for custom artwork configuration */ +#define MUSIC_PREFIX_BACKGROUND 0 +#define NUM_MUSIC_PREFIXES 1 +#define MAX_LEVELS 1000 + +/* definitions for demo animation lists */ +#define HELPANIM_LIST_NEXT -1 +#define HELPANIM_LIST_END -999 + + +/* program information and versioning definitions */ #define PROGRAM_VERSION_MAJOR 3 #define PROGRAM_VERSION_MINOR 0 -#define PROGRAM_VERSION_PATCH 7 -#define PROGRAM_VERSION_BUILD 1 - -#if 0 -#define PROGRAM_VERSION_STRING "3.0.7" -#endif +#define PROGRAM_VERSION_PATCH 8 +#define PROGRAM_VERSION_BUILD 3 #define PROGRAM_TITLE_STRING "Rocks'n'Diamonds" #define PROGRAM_AUTHOR_STRING "Holger Schemel" #define PROGRAM_COPYRIGHT_STRING "Copyright ©1995-2003 by Holger Schemel" -#if 0 -#define PROGRAM_DOS_PORT_STRING "DOS port done by Guido Schulz" -#define PROGRAM_IDENT_STRING PROGRAM_VERSION_STRING " " TARGET_STRING -#define WINDOW_TITLE_STRING PROGRAM_TITLE_STRING " " PROGRAM_IDENT_STRING -#endif - #define ICON_TITLE_STRING PROGRAM_TITLE_STRING #define COOKIE_PREFIX "ROCKSNDIAMONDS" #define FILENAME_PREFIX "Rocks" @@ -1110,6 +1155,9 @@ struct MenuInfo int list_size_default; int list_size[NUM_SPECIAL_GFX_ARGS]; + + int sound[NUM_SPECIAL_GFX_ARGS]; + int music[NUM_SPECIAL_GFX_ARGS]; }; struct DoorInfo @@ -1140,7 +1188,7 @@ struct PlayerInfo byte programmed_action; /* action forced by game itself (like moving through doors); overrides other actions */ - int jx,jy, last_jx,last_jy; + int jx, jy, last_jx, last_jy; int MovDir, MovPos, GfxDir, GfxPos; int Frame, StepFrame; @@ -1160,6 +1208,22 @@ struct PlayerInfo boolean is_pushing; boolean is_switching; + boolean is_bored; + boolean is_sleeping; + + int frame_counter_bored; + int frame_counter_sleeping; + + int anim_delay_counter; + int post_delay_counter; + + int action_waiting, last_action_waiting; + int special_action_bored; + int special_action_sleeping; + + int num_special_action_bored; + int num_special_action_sleeping; + int switch_x, switch_y; int show_envelope; @@ -1172,6 +1236,8 @@ struct PlayerInfo unsigned long actual_frame_counter; + int step_counter; + int score; int gems_still_needed; int sokobanfields_still_needed; @@ -1186,6 +1252,11 @@ struct PlayerInfo int inventory_size; }; +struct LevelSetInfo +{ + int music[MAX_LEVELS]; +}; + struct LevelInfo { int file_version; /* file format version the level is stored with */ @@ -1281,6 +1352,12 @@ struct GameInfo boolean gravity; boolean explosions_delayed; boolean envelope_active; + + /* values for player idle animation (no effect on engine) */ + int player_boring_delay_fixed; + int player_boring_delay_random; + int player_sleeping_delay_fixed; + int player_sleeping_delay_random; }; struct GlobalInfo @@ -1433,6 +1510,11 @@ struct GraphicInfo int diggable_like; /* element for cloning digging graphics */ int border_size; /* border size for "crumbled" graphics */ + int anim_delay_fixed; /* optional delay values for bored and */ + int anim_delay_random; /* sleeping player animations (animation */ + int post_delay_fixed; /* intervall and following pause before */ + int post_delay_random; /* next intervall (bored animation only) */ + int step_offset; /* optional step offset of toon animations */ int step_delay; /* optional step delay of toon animations */ @@ -1451,6 +1533,38 @@ struct SoundInfo boolean loop; }; +struct MusicInfo +{ + boolean loop; +}; + +struct MusicPrefixInfo +{ + char *prefix; + boolean is_loop_music; +}; + +struct MusicFileInfo +{ + char *basename; + + char *title_header; + char *artist_header; + char *album_header; + char *year_header; + + char *title; + char *artist; + char *album; + char *year; + + int music; + + boolean is_sound; + + struct MusicFileInfo *next; +}; + struct ElementActionInfo { char *suffix; @@ -1470,6 +1584,15 @@ struct SpecialSuffixInfo int value; }; +struct HelpAnimInfo +{ + int element; + int action; + int direction; + + int delay; +}; + #if 0 extern GC tile_clip_gc; @@ -1510,6 +1633,8 @@ extern short AmoebaCnt[MAX_NUM_AMOEBA]; extern short AmoebaCnt2[MAX_NUM_AMOEBA]; extern short ExplodePhase[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern short ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern int RunnerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; +extern int PlayerVisit[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; extern unsigned long Properties[MAX_NUM_ELEMENTS][NUM_EP_BITFIELDS]; @@ -1544,6 +1669,7 @@ extern boolean network_player_action_received; extern int graphics_action_mapping[]; +extern struct LevelSetInfo levelset; extern struct LevelInfo level, level_template; extern struct PlayerInfo stored_player[], *local_player; extern struct HiScore highscore[]; @@ -1558,9 +1684,20 @@ extern struct ElementDirectionInfo element_direction_info[]; extern struct SpecialSuffixInfo special_suffix_info[]; extern struct TokenIntPtrInfo image_config_vars[]; extern struct FontInfo font_info[]; +extern struct MusicPrefixInfo music_prefix_info[]; extern struct GraphicInfo *graphic_info; extern struct SoundInfo *sound_info; -extern struct ConfigInfo image_config[], sound_config[]; -extern struct ConfigInfo image_config_suffix[], sound_config_suffix[]; +extern struct MusicInfo *music_info; +extern struct MusicFileInfo *music_file_info; +extern struct HelpAnimInfo *helpanim_info; +extern SetupFileHash *helptext_info; +extern struct ConfigInfo image_config[]; +extern struct ConfigInfo sound_config[]; +extern struct ConfigInfo music_config[]; +extern struct ConfigInfo image_config_suffix[]; +extern struct ConfigInfo sound_config_suffix[]; +extern struct ConfigInfo music_config_suffix[]; +extern struct ConfigInfo helpanim_config[]; +extern struct ConfigInfo helptext_config[]; #endif /* MAIN_H */ diff --git a/src/netserv.c b/src/netserv.c index 11fd9bc8..71834c3b 100644 --- a/src/netserv.c +++ b/src/netserv.c @@ -89,8 +89,9 @@ static void broadcast(struct NetworkServerPlayerInfo *except, realbuffer[0] = realbuffer[1] = realbuffer[2] = 0; realbuffer[3] = (unsigned char)len; - for (player=first_player; player; player=player->next) - if (player != except && (player->active || !activeonly) && player->introduced) + for (player = first_player; player; player = player->next) + if (player != except && player->introduced && + (player->active || !activeonly)) addtobuffer(player, realbuffer, 4 + len); } @@ -113,7 +114,7 @@ static void RemovePlayer(struct NetworkServerPlayerInfo *player) first_player = player->next; else { - for (v=first_player; v; v=v->next) + for (v = first_player; v; v = v->next) { if (v->next && v->next == player) { @@ -149,6 +150,7 @@ static void AddPlayer(int fd) { struct NetworkServerPlayerInfo *player, *v; unsigned char nxn; + boolean again = TRUE; player = checked_malloc(sizeof (struct NetworkServerPlayerInfo)); @@ -166,9 +168,28 @@ static void AddPlayer(int fd) nxn = 1; +#if 1 + while (again) + { + again = FALSE; + v = player->next; + + while (v) + { + if (v->number == nxn) + { + nxn++; + + again = TRUE; + break; + } + v = v->next; + } + } +#else again: v = player->next; - while(v) + while (v) { if (v->number == nxn) { @@ -177,6 +198,7 @@ static void AddPlayer(int fd) } v = v->next; } +#endif player->number = nxn; if (options.verbose) @@ -233,7 +255,7 @@ static void Handle_OP_NUMBER_WANTED(struct NetworkServerPlayerInfo *player) Error(ERR_NETWORK_SERVER, "client %d (%s) wants to switch to # %d", player->number, player->player_name, nr_wanted); - for (v=first_player; v; v=v->next) + for (v = first_player; v; v = v->next) { if (v->number == nr_wanted) { @@ -281,7 +303,7 @@ static void Handle_OP_PLAYER_NAME(struct NetworkServerPlayerInfo *player, len=16; memcpy(player->player_name, &buffer[2], len-2); player->player_name[len-2] = 0; - for (i=0; iplayer_name[i] < ' ' || ((unsigned char)(player->player_name[i]) > 0x7e && @@ -307,7 +329,7 @@ static void Handle_OP_PLAYER_NAME(struct NetworkServerPlayerInfo *player, if (!player->introduced) { - for (v=first_player; v; v=v->next) + for (v = first_player; v; v = v->next) { if (v != player && v->introduced) { @@ -336,7 +358,7 @@ static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player) (buffer[4] << 8) + buffer[5], &buffer[6]); - for (w=first_player; w; w=w->next) + for (w = first_player; w; w = w->next) if (w->introduced) w->active = 1; @@ -344,7 +366,7 @@ static void Handle_OP_START_PLAYING(struct NetworkServerPlayerInfo *player) ServerFrameCounter = 0; /* reset player actions */ - for (v=first_player; v; v=v->next) + for (v = first_player; v; v = v->next) { v->action = 0; v->action_received = FALSE; @@ -384,7 +406,7 @@ static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player) int i; /* store player action */ - for (v=first_player; v; v=v->next) + for (v = first_player; v; v = v->next) { if (v->number == player->number) { @@ -394,7 +416,7 @@ static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player) } /* check if server received action from each player */ - for (v=first_player; v; v=v->next) + for (v = first_player; v; v = v->next) { if (!v->action_received) return; @@ -404,11 +426,11 @@ static void Handle_OP_MOVE_PLAYER(struct NetworkServerPlayerInfo *player) } /* initialize all player actions to zero */ - for (i=0; inext) + for (v = first_player; v; v = v->next) { buffer[6 + v->number-1] = v->action; v->action = 0; @@ -478,7 +500,7 @@ void NetworkServer(int port, int serveronly) { /* become a daemon, breaking all ties with the controlling terminal */ options.verbose = FALSE; - for (i=0; i<255; i++) + for (i = 0; i < 255; i++) { if (i != lfd) close(i); @@ -504,11 +526,11 @@ void NetworkServer(int port, int serveronly) PROTOCOL_VERSION_1, PROTOCOL_VERSION_2, PROTOCOL_VERSION_3); } - while(1) + while (1) { interrupt = 0; - for (player=first_player; player; player=player->next) + for (player = first_player; player; player = player->next) flushuser(player); FD_ZERO(&fds); diff --git a/src/network.c b/src/network.c index 5511d176..73a13b1f 100644 --- a/src/network.c +++ b/src/network.c @@ -100,7 +100,7 @@ char *getNetworkPlayerName(int player_nr) else if (player_nr == first_player.nr) return("you"); else - for (player=&first_player; player; player=player->next) + for (player = &first_player; player; player = player->next) if (player->nr == player_nr && player->name && strlen(player->name)) return(player->name); @@ -173,7 +173,7 @@ boolean ConnectToServer(char *hostname, int port) StartNetworkServer(port); /* wait for server to start up and try connecting several times */ - for (i=0; i<6; i++) + for (i = 0; i < 6; i++) { Delay(500); /* wait 500 ms == 0.5 seconds */ close(sfd); @@ -378,7 +378,7 @@ static void Handle_OP_PLAYER_CONNECTED() printf("OP_PLAYER_CONNECTED: %d\n", new_client_nr); Error(ERR_NETWORK_CLIENT, "new client %d connected", new_client_nr); - for (player=&first_player; player; player=player->next) + for (player = &first_player; player; player = player->next) { if (player->nr == new_client_nr) Error(ERR_EXIT, "multiplayer server sent duplicate player id"); @@ -405,7 +405,7 @@ static void Handle_OP_PLAYER_DISCONNECTED() Error(ERR_NETWORK_CLIENT, "client %d (%s) disconnected", player_nr, getNetworkPlayerName(buffer[0])); - for (player=&first_player; player; player=player->next) + for (player = &first_player; player; player = player->next) if (player->next == player_disconnected) player->next = player_disconnected->next; free(player_disconnected); @@ -506,7 +506,7 @@ static void Handle_OP_MOVE_PLAYER(unsigned int len) } /* copy valid player actions */ - for (i=0; i= GAME_MODE_MAIN && \ game_status <= GAME_MODE_SETUP ? \ @@ -139,29 +165,44 @@ static void drawChooseTreeCursor(int ypos, int color) game_status = last_game_status; /* restore current game status */ } -static void PlaySound_Menu_Start(int sound) +static void PlayMenuSound() { + int sound = menu.sound[game_status]; + + if (sound == SND_UNDEFINED) + return; + if (sound_info[sound].loop) PlaySoundLoop(sound); else PlaySound(sound); } -static void PlaySound_Menu_Continue(int sound) +static void PlayMenuSoundIfLoop() { + int sound = menu.sound[game_status]; + + if (sound == SND_UNDEFINED) + return; + if (sound_info[sound].loop) PlaySoundLoop(sound); } -void DrawHeadline() +static void PlayMenuMusic() { - int text1_width = getTextWidth(PROGRAM_TITLE_STRING, FONT_TITLE_1); - int text2_width = getTextWidth(PROGRAM_COPYRIGHT_STRING, FONT_TITLE_2); - int x1 = SX + (SXSIZE - text1_width) / 2; - int x2 = SX + (SXSIZE - text2_width) / 2; + int music = menu.music[game_status]; + + if (music == MUS_UNDEFINED) + return; - DrawText(x1, SY + 8, PROGRAM_TITLE_STRING, FONT_TITLE_1); - DrawText(x2, SY + 46, PROGRAM_COPYRIGHT_STRING, FONT_TITLE_2); + PlayMusic(music); +} + +void DrawHeadline() +{ + DrawTextSCentered(8, FONT_TITLE_1, PROGRAM_TITLE_STRING); + DrawTextSCentered(46, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING); } static void ToggleFullscreenIfNeeded() @@ -192,12 +233,11 @@ void DrawMainMenu() { static LevelDirTree *leveldir_last_valid = NULL; char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:"); - int name_width = getTextWidth("Name:", FONT_MENU_1); - int level_width = getTextWidth("Level:", FONT_MENU_1); + int name_width, level_width; int i; UnmapAllGadgets(); - FadeSounds(); + FadeSoundsAndMusic(); KeyboardAutoRepeatOn(); ActivateJoystick(); @@ -260,6 +300,10 @@ void DrawMainMenu() DrawText(mSX + 32, mSY + 8*32, "Setup", FONT_MENU_1); DrawText(mSX + 32, mSY + 9*32, "Quit", FONT_MENU_1); + /* calculated after (possible) reload of custom artwork */ + name_width = getTextWidth(name_text, FONT_MENU_1); + level_width = getTextWidth("Level:", FONT_MENU_1); + DrawText(mSX + 32 + name_width, mSY + 2*32, setup.player_name, FONT_INPUT_1); DrawText(mSX + level_width + 5 * 32, mSY + 3*32, int2str(level_nr,3), FONT_VALUE_1); @@ -271,34 +315,35 @@ void DrawMainMenu() if (leveldir_current->readonly) { - DrawTextF(mSX + level_width + 9 * 32 - 2, + DrawTextS(mSX + level_width + 9 * 32 - 2, mSY + 3 * 32 + 1 - 7, FONT_TEXT_3, "READ"); - DrawTextF(mSX + level_width + 9 * 32 - 2, + DrawTextS(mSX + level_width + 9 * 32 - 2, mSY + 3 * 32 + 1 + 7, FONT_TEXT_3, "ONLY"); } - for(i=0; i<8; i++) - initCursor(i, (i == 1 || i == 6 ? IMG_MENU_BUTTON_RIGHT :IMG_MENU_BUTTON)); + for (i = 0; i < 8; i++) + initCursor(i, (i == 1 || i == 4 || i == 6 ? IMG_MENU_BUTTON_RIGHT : + IMG_MENU_BUTTON)); drawCursorXY(level_width/32 + 4, 1, IMG_MENU_BUTTON_LEFT); drawCursorXY(level_width/32 + 8, 1, IMG_MENU_BUTTON_RIGHT); - DrawText(SX + 56, SY + 326, "A Game by Artsoft Entertainment", FONT_TITLE_2); + DrawTextSCentered(326, FONT_TITLE_2, "A Game by Artsoft Entertainment"); FadeToFront(); InitAnimation(); - HandleMainMenu(0,0, 0,0, MB_MENU_INITIALIZE); + + HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE); TapeStop(); if (TAPE_IS_EMPTY(tape)) LoadTape(level_nr); DrawCompleteVideoDisplay(); - OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2); + PlayMenuSound(); + PlayMenuMusic(); -#if 0 - ClearEventQueue(); -#endif + OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2); } static void gotoTopLevelDir() @@ -361,7 +406,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) { static unsigned long level_delay = 0; int step = (button == 1 ? 1 : button == 2 ? 5 : 10); - int new_level_nr, old_level_nr = level_nr; + int old_level_nr = level_nr; + int new_level_nr; new_level_nr = level_nr + (x == 10 ? -step : +step); if (new_level_nr < leveldir_current->first_level) @@ -372,27 +418,29 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) if (setup.handicap && new_level_nr > leveldir_current->handicap_level) new_level_nr = leveldir_current->handicap_level; - if (old_level_nr == new_level_nr || - !DelayReached(&level_delay, GADGET_FRAME_DELAY)) - goto out; - - level_nr = new_level_nr; + if (new_level_nr != old_level_nr && + DelayReached(&level_delay, GADGET_FRAME_DELAY)) + { + level_nr = new_level_nr; - DrawText(mSX + 11 * 32, mSY + 3 * 32, int2str(level_nr, 3), FONT_VALUE_1); + DrawText(mSX + 11 * 32, mSY + 3 * 32, int2str(level_nr, 3), + FONT_VALUE_1); - LoadLevel(level_nr); - DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE); + LoadLevel(level_nr); + DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE); - TapeErase(); - LoadTape(level_nr); - DrawCompleteVideoDisplay(); + TapeErase(); + LoadTape(level_nr); + DrawCompleteVideoDisplay(); - /* needed because DrawMicroLevel() takes some time */ - BackToFront(); - SyncDisplay(); - DelayReached(&level_delay, 0); /* reset delay counter */ + /* needed because DrawMicroLevel() takes some time */ + BackToFront(); + SyncDisplay(); + DelayReached(&level_delay, 0); /* reset delay counter */ + } } - else if (x == 0 && y >= 0 && y <= 7) + else if (IN_VIS_FIELD(x, y) && + y >= 0 && y <= 7 && (y != 1 || x < 10)) { if (button) { @@ -439,7 +487,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) else if (y == 4) { game_status = GAME_MODE_INFO; - DrawHelpScreen(); + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); } else if (y == 5) { @@ -473,541 +522,608 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button) } } - out: - if (game_status == GAME_MODE_MAIN) { DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, FALSE); DoAnimation(); } - - BackToFront(); } -#define MAX_HELPSCREEN_ELS 10 -#define HA_NEXT -999 -#define HA_END -1000 +/* ========================================================================= */ +/* info screen functions */ +/* ========================================================================= */ -static long helpscreen_state; -static int helpscreen_step[MAX_HELPSCREEN_ELS]; -static int helpscreen_frame[MAX_HELPSCREEN_ELS]; +static struct TokenInfo *info_info; +static int num_info_info; -static int helpscreen_action[] = +static void execInfoElements() { - IMG_PLAYER_1_MOVING_DOWN, 16, - IMG_PLAYER_1_MOVING_UP, 16, - IMG_PLAYER_1_MOVING_LEFT, 16, - IMG_PLAYER_1_MOVING_RIGHT, 16, - IMG_PLAYER_1_PUSHING_LEFT, 16, - IMG_PLAYER_1_PUSHING_RIGHT, 16, HA_NEXT, + info_mode = INFO_MODE_ELEMENTS; + DrawInfoScreen(); +} - IMG_SAND, -1, HA_NEXT, +static void execInfoMusic() +{ + info_mode = INFO_MODE_MUSIC; + DrawInfoScreen(); +} - IMG_EMPTY_SPACE, -1, HA_NEXT, +static void execInfoCredits() +{ + info_mode = INFO_MODE_CREDITS; + DrawInfoScreen(); +} - IMG_QUICKSAND_EMPTY, -1, HA_NEXT, +static void execInfoProgram() +{ + info_mode = INFO_MODE_PROGRAM; + DrawInfoScreen(); +} - IMG_STEELWALL, -1, HA_NEXT, +static void execInfoLevelSet() +{ + info_mode = INFO_MODE_LEVELSET; + DrawInfoScreen(); +} - IMG_WALL, -1, HA_NEXT, +static void execExitInfo() +{ + game_status = GAME_MODE_MAIN; + DrawMainMenu(); +} - IMG_EXPANDABLE_WALL_GROWING_LEFT, 20, - IMG_WALL, 50, - IMG_EMPTY_SPACE, 20, - IMG_EXPANDABLE_WALL_GROWING_RIGHT, 20, - IMG_WALL, 50, - IMG_EMPTY_SPACE, 20, - IMG_EXPANDABLE_WALL_GROWING_UP, 20, - IMG_WALL, 50, - IMG_EMPTY_SPACE, 20, - IMG_EXPANDABLE_WALL_GROWING_DOWN, 20, - IMG_WALL, 50, - IMG_EMPTY_SPACE, 20, HA_NEXT, +static struct TokenInfo info_info_main[] = +{ + { TYPE_ENTER_SCREEN, execInfoElements, "Elements Info" }, + { TYPE_ENTER_SCREEN, execInfoMusic, "Music Info" }, + { TYPE_ENTER_SCREEN, execInfoCredits, "Credits" }, + { TYPE_ENTER_SCREEN, execInfoProgram, "Program Info" }, + { TYPE_ENTER_SCREEN, execInfoLevelSet, "Level Set Info" }, + { TYPE_EMPTY, NULL, "" }, + { TYPE_LEAVE_MENU, execExitInfo, "Exit" }, - IMG_INVISIBLE_WALL, -1, HA_NEXT, + { 0, NULL, NULL } +}; - IMG_WALL_SLIPPERY, -1, HA_NEXT, +static void DrawInfoScreen_Main() +{ + int i; - IMG_FONT_GAME_INFO, -1, HA_NEXT, + UnmapAllGadgets(); + CloseDoor(DOOR_CLOSE_2); - IMG_EMERALD, -1, HA_NEXT, + ClearWindow(); - IMG_DIAMOND, -1, HA_NEXT, + DrawText(mSX + 16, mSY + 16, "Info Screen", FONT_TITLE_1); - IMG_BD_DIAMOND, -1, HA_NEXT, + info_info = info_info_main; + num_info_info = 0; - IMG_EMERALD_YELLOW, 50, - IMG_EMERALD_RED, 50, - IMG_EMERALD_PURPLE, 50, HA_NEXT, + for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++) + { + int ypos = MENU_SCREEN_START_YPOS + i; + int font_nr = FONT_MENU_1; - IMG_BD_ROCK, -1, HA_NEXT, + DrawText(mSX + 32, mSY + ypos * 32, info_info[i].text, font_nr); - IMG_BOMB, 100, - IMG_EXPLOSION, 16, - IMG_EMPTY_SPACE, 10, HA_NEXT, + if (info_info[i].type & TYPE_ENTER_MENU) + initCursor(i, IMG_MENU_BUTTON_RIGHT); + else if (info_info[i].type & TYPE_LEAVE_MENU) + initCursor(i, IMG_MENU_BUTTON_LEFT); + else if (info_info[i].type & ~TYPE_SKIP_ENTRY) + initCursor(i, IMG_MENU_BUTTON); - IMG_NUT, 100, - IMG_NUT_BREAKING, 6, - IMG_EMERALD, 20, HA_NEXT, + num_info_info++; + } - IMG_WALL_EMERALD, 100, - IMG_EXPLOSION, 16, - IMG_EMERALD, 20, HA_NEXT, + FadeToFront(); + InitAnimation(); - IMG_WALL_DIAMOND, 100, - IMG_EXPLOSION, 16, - IMG_DIAMOND, 20, HA_NEXT, + PlayMenuSound(); + PlayMenuMusic(); - IMG_WALL_BD_DIAMOND, 100, - IMG_EXPLOSION, 16, - IMG_BD_DIAMOND, 20, HA_NEXT, + HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE); +} - IMG_WALL_EMERALD_YELLOW, 100, - IMG_EXPLOSION, 16, - IMG_EMERALD_YELLOW, 20, - IMG_WALL_EMERALD_RED, 100, - IMG_EXPLOSION, 16, - IMG_EMERALD_RED, 20, - IMG_WALL_EMERALD_PURPLE, 100, - IMG_EXPLOSION, 16, - IMG_EMERALD_PURPLE, 20, HA_NEXT, +void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button) +{ + static int choice_store[MAX_INFO_MODES]; + int choice = choice_store[info_mode]; /* always starts with 0 */ + int x = 0; + int y = choice; - IMG_ACID, -1, HA_NEXT, + if (button == MB_MENU_INITIALIZE) + { + /* advance to first valid menu entry */ + while (choice < num_info_info && + info_info[choice].type & TYPE_SKIP_ENTRY) + choice++; + choice_store[info_mode] = choice; - IMG_KEY_1, 50, - IMG_KEY_2, 50, - IMG_KEY_3, 50, - IMG_KEY_4, 50, HA_NEXT, + drawCursor(choice, FC_RED); + return; + } + else if (button == MB_MENU_LEAVE) + { + for (y = 0; y < num_info_info; y++) + { + if (info_info[y].type & TYPE_LEAVE_MENU) + { + void (*menu_callback_function)(void) = info_info[y].value; - IMG_GATE_1, 50, - IMG_GATE_2, 50, - IMG_GATE_3, 50, - IMG_GATE_4, 50, HA_NEXT, + menu_callback_function(); + break; /* absolutely needed because function changes 'info_info'! */ + } + } - IMG_GATE_1_GRAY, 50, - IMG_GATE_2_GRAY, 50, - IMG_GATE_3_GRAY, 50, - IMG_GATE_4_GRAY, 50, HA_NEXT, + return; + } - IMG_DYNAMITE, -1, HA_NEXT, + if (mx || my) /* mouse input */ + { + x = (mx - mSX) / 32; + y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS; + } + else if (dx || dy) /* keyboard input */ + { + if (dx) + { + int menu_navigation_type = (dx < 0 ? TYPE_LEAVE_MENU : TYPE_ENTER_MENU); - IMG_DYNAMITE_ACTIVE, 96, - IMG_EXPLOSION, 16, - IMG_EMPTY_SPACE, 20, HA_NEXT, + if (info_info[choice].type & menu_navigation_type || + info_info[choice].type & TYPE_ENTER_SCREEN || + info_info[choice].type & TYPE_BOOLEAN_STYLE) + button = MB_MENU_CHOICE; + } + else if (dy) + y = choice + dy; - IMG_DYNABOMB_ACTIVE, 100, - IMG_EXPLOSION, 16, - IMG_EMPTY_SPACE, 20, HA_NEXT, + /* jump to next non-empty menu entry (up or down) */ + while (y > 0 && y < num_info_info - 1 && + info_info[y].type & TYPE_SKIP_ENTRY) + y += dy; + } - IMG_DYNABOMB_INCREASE_NUMBER, -1, HA_NEXT, + if (IN_VIS_FIELD(x, y) && + y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY) + { + if (button) + { + if (y != choice) + { + drawCursor(y, FC_RED); + drawCursor(choice, FC_BLUE); + choice = choice_store[info_mode] = y; + } + } + else if (!(info_info[y].type & TYPE_GHOSTED)) + { + if (info_info[y].type & TYPE_ENTER_OR_LEAVE_MENU) + { + void (*menu_callback_function)(void) = info_info[choice].value; - IMG_DYNABOMB_INCREASE_SIZE, -1, HA_NEXT, + menu_callback_function(); + } + } + } +} - IMG_DYNABOMB_INCREASE_POWER, -1, HA_NEXT, +void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init) +{ + static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN]; + static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN]; + int xstart = mSX + 16; + int ystart = mSY + 64 + 2 * 32; + int ystep = TILEY + 4; + int element, action, direction; + int graphic; + int delay; + int sync_frame; + int i, j; - IMG_SPACESHIP_RIGHT, 16, - IMG_SPACESHIP_UP, 16, - IMG_SPACESHIP_LEFT, 16, - IMG_SPACESHIP_DOWN, 16, HA_NEXT, + if (init) + { + for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++) + infoscreen_step[i] = infoscreen_frame[i] = 0; - IMG_BUG_RIGHT, 16, - IMG_BUG_UP, 16, - IMG_BUG_LEFT, 16, - IMG_BUG_DOWN, 16, HA_NEXT, + SetMainBackgroundImage(IMG_BACKGROUND_INFO); + ClearWindow(); + DrawHeadline(); - IMG_BD_BUTTERFLY, -1, HA_NEXT, + DrawTextSCentered(100, FONT_TEXT_1, "The Game Elements:"); - IMG_BD_FIREFLY, -1, HA_NEXT, + DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4, + "Press any key or button for next page"); - IMG_PACMAN_RIGHT, 16, - IMG_PACMAN_UP, 16, - IMG_PACMAN_LEFT, 16, - IMG_PACMAN_DOWN, 16, HA_NEXT, + FrameCounter = 0; + } - IMG_YAMYAM, -1, HA_NEXT, + i = j = 0; + while (helpanim_info[j].element != HELPANIM_LIST_END) + { + if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN || + i >= max_anims) + break; + else if (i < start) + { + while (helpanim_info[j].element != HELPANIM_LIST_NEXT) + j++; - IMG_DARK_YAMYAM, -1, HA_NEXT, + j++; + i++; - IMG_ROBOT, -1, HA_NEXT, + continue; + } - IMG_MOLE_MOVING_RIGHT, 16, - IMG_MOLE_MOVING_UP, 16, - IMG_MOLE_MOVING_LEFT, 16, - IMG_MOLE_MOVING_DOWN, 16, HA_NEXT, + j += infoscreen_step[i - start]; - IMG_PENGUIN_MOVING_RIGHT, 16, - IMG_PENGUIN_MOVING_UP, 16, - IMG_PENGUIN_MOVING_LEFT, 16, - IMG_PENGUIN_MOVING_DOWN, 16, HA_NEXT, + element = helpanim_info[j].element; + action = helpanim_info[j].action; + direction = helpanim_info[j].direction; - IMG_PIG_MOVING_RIGHT, 16, - IMG_PIG_MOVING_UP, 16, - IMG_PIG_MOVING_LEFT, 16, - IMG_PIG_MOVING_DOWN, 16, HA_NEXT, + if (action != -1 && direction != -1) + graphic = el_act_dir2img(element, action, direction); + else if (action != -1) + graphic = el_act2img(element, action); + else if (direction != -1) + graphic = el_act2img(element, direction); + else + graphic = el2img(element); - IMG_DRAGON_MOVING_RIGHT, 16, - IMG_DRAGON_MOVING_UP, 16, - IMG_DRAGON_MOVING_LEFT, 16, - IMG_DRAGON_MOVING_DOWN, 16, HA_NEXT, + delay = helpanim_info[j++].delay; - IMG_SATELLITE, -1, HA_NEXT, + if (delay == -1) + delay = 1000000; - IMG_ROBOT_WHEEL, 50, - IMG_ROBOT_WHEEL_ACTIVE, 100, HA_NEXT, + if (infoscreen_frame[i - start] == 0) + { + sync_frame = 0; + infoscreen_frame[i - start] = delay - 1; + } + else + { + sync_frame = delay - infoscreen_frame[i - start]; + infoscreen_frame[i - start]--; + } - IMG_LAMP, 50, - IMG_LAMP_ACTIVE, 50, HA_NEXT, + if (helpanim_info[j].element == HELPANIM_LIST_NEXT) + { + if (!infoscreen_frame[i - start]) + infoscreen_step[i - start] = 0; + } + else + { + if (!infoscreen_frame[i - start]) + infoscreen_step[i - start]++; + while (helpanim_info[j].element != HELPANIM_LIST_NEXT) + j++; + } - IMG_TIME_ORB_FULL, 50, - IMG_TIME_ORB_EMPTY, 50, HA_NEXT, + j++; - IMG_AMOEBA_DROP, 50, - IMG_AMOEBA_GROWING, 6, - IMG_AMOEBA_WET, 20, HA_NEXT, + ClearRectangleOnBackground(drawto, xstart, ystart + (i - start) * ystep, + TILEX, TILEY); + DrawGraphicAnimationExt(drawto, xstart, ystart + (i - start) * ystep, + graphic, sync_frame, USE_MASKING); - IMG_AMOEBA_DEAD, -1, HA_NEXT, + if (init) + DrawInfoScreen_HelpText(element, action, direction, i - start); - IMG_AMOEBA_WET, -1, HA_NEXT, + i++; + } - IMG_AMOEBA_WET, 100, - IMG_AMOEBA_GROWING, 6, HA_NEXT, + redraw_mask |= REDRAW_FIELD; - IMG_AMOEBA_FULL, 50, - IMG_AMOEBA_DEAD, 50, - IMG_EXPLOSION, 16, - IMG_DIAMOND, 20, HA_NEXT, + FrameCounter++; +} - IMG_GAME_OF_LIFE, -1, HA_NEXT, +static char *getHelpText(int element, int action, int direction) +{ + char token[MAX_LINE_LEN]; - IMG_BIOMAZE, -1, HA_NEXT, + strcpy(token, element_info[element].token_name); - IMG_MAGIC_WALL_ACTIVE, -1, HA_NEXT, + if (action != -1) + strcat(token, element_action_info[action].suffix); - IMG_BD_MAGIC_WALL_ACTIVE, -1, HA_NEXT, + if (direction != -1) + strcat(token, element_direction_info[MV_DIR_BIT(direction)].suffix); - IMG_EXIT_CLOSED, 200, - IMG_EXIT_OPENING, 16, - IMG_EXIT_OPEN, 100, HA_NEXT, + return getHashEntry(helptext_info, token); +} - IMG_EXIT_OPEN, -1, HA_NEXT, +void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos) +{ +#if 0 + int font_nr = FONT_TEXT_2; +#else + int font_nr = FONT_LEVEL_NUMBER; +#endif + int font_width = getFontWidth(font_nr); + int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX; + int sy = mSY + 65 + 2 * 32 + 1; + int ystep = TILEY + 4; + int pad_x = sx - SX; + int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width; + int max_lines_per_text = 2; + char *text = NULL; - IMG_SOKOBAN_OBJECT, -1, HA_NEXT, + if (action != -1 && direction != -1) /* element.action.direction */ + text = getHelpText(element, action, direction); - IMG_SOKOBAN_FIELD_EMPTY, -1, HA_NEXT, + if (text == NULL && action != -1) /* element.action */ + text = getHelpText(element, action, -1); - IMG_SOKOBAN_FIELD_FULL, -1, HA_NEXT, + if (text == NULL && direction != -1) /* element.direction */ + text = getHelpText(element, -1, direction); - IMG_SPEED_PILL, -1, HA_NEXT, + if (text == NULL) /* base element */ + text = getHelpText(element, -1, -1); - HA_END -}; -static char *helpscreen_eltext[][2] = -{ - {"THE HERO:", "(Is _this_ guy good old Rockford?)"}, - {"Normal sand:", "You can dig through it"}, - {"Empty field:", "You can walk through it"}, - {"Quicksand: You cannot pass it,", "but rocks can fall through it"}, - {"Massive Wall:", "Nothing can go through it"}, - {"Normal Wall: You can't go through", "it, but you can bomb it away"}, - {"Growing Wall: Grows in several di-", "rections if there is an empty field"}, - {"Invisible Wall: Behaves like normal","wall, but is invisible"}, - {"Old Wall: Like normal wall, but", "some things can fall down from it"}, - {"Letter Wall: Looks like a letter,", "behaves like a normal wall"}, - {"Emerald: You must collect enough of","them to finish a level"}, - {"Diamond: Counts as 3 emeralds, but", "can be destroyed by rocks"}, - {"Diamond (BD style): Counts like one","emerald and behaves a bit different"}, - {"Colorful Gems:", "Seem to behave like Emeralds"}, - {"Rock: Smashes several things;", "Can be moved by the player"}, - {"Bomb: You can move it, but be", "careful when dropping it"}, - {"Nut: Throw a rock on it to open it;","Each nut contains an emerald"}, - {"Wall with an emerald inside:", "Bomb the wall away to get it"}, - {"Wall with a diamond inside:", "Bomb the wall away to get it"}, - {"Wall with BD style diamond inside:", "Bomb the wall away to get it"}, - {"Wall with colorful gem inside:", "Bomb the wall away to get it"}, - {"Acid: Things that fall in are gone", "forever (including our hero)"}, - {"Key: Opens the door that has the", "same color (red/yellow/green/blue)"}, - {"Door: Can be opened by the key", "with the same color"}, - {"Door: You have to find out the", "right color of the key for it"}, - {"Dynamite: Collect it and use it to", "destroy walls or kill enemies"}, - {"Dynamite: This one explodes after", "a few seconds"}, - {"Dyna Bomb: Explodes in 4 directions","with variable explosion size"}, - {"Dyna Bomb: Increases the number of", "dyna bombs available at a time"}, - {"Dyna Bomb: Increases the size of", "explosion of dyna bombs"}, - {"Dyna Bomb: Increases the power of", "explosion of dyna bombs"}, - {"Spaceship: Moves at the left side", "of walls; don't touch it!"}, - {"Bug: Moves at the right side", "of walls; don't touch it!"}, - {"Butterfly: Moves at the right side", "of walls; don't touch it!"}, - {"Firefly: Moves at the left side", "of walls; don't touch it!"}, - {"Pacman: Eats the amoeba and you,", "if you're not careful"}, - {"Cruncher: Eats diamonds and you,", "if you're not careful"}, - {"Cruncher (BD style):", "Eats almost everything"}, - {"Robot: Tries to kill the player", ""}, - {"The mole: Eats the amoeba and turns","empty space into normal sand"}, - {"The penguin: Guide him to the exit,","but keep him away from monsters!"}, - {"The Pig: Harmless, but eats all", "gems it can get"}, - {"The Dragon: Breathes fire,", "especially to some monsters"}, - {"Sonde: Follows you everywhere;", "harmless, but may block your way"}, - {"Magic Wheel: Touch it to get rid of","the robots for some seconds"}, - {"Light Bulb: All of them must be", "switched on to finish a level"}, - {"Extra Time Orb: Adds some seconds", "to the time available for the level"}, - {"Amoeba Drop: Grows to an amoeba on", "the ground - don't touch it"}, - {"Dead Amoeba: Does not grow, but", "can still kill bugs and spaceships"}, - {"Normal Amoeba: Grows through empty", "fields, sand and quicksand"}, - {"Dropping Amoeba: This one makes", "drops that grow to a new amoeba"}, - {"Living Amoeba (BD style): Contains", "other element, when surrounded"}, - {"Game Of Life: Behaves like the well","known 'Game Of Life' (2333 style)"}, - {"Biomaze: A bit like the 'Game Of", "Life', but builds crazy mazes"}, - {"Magic Wall: Changes rocks, emeralds","and diamonds when they pass it"}, - {"Magic Wall (BD style):", "Changes rocks and BD style diamonds"}, - {"Exit door: Opens if you have enough","emeralds to finish the level"}, - {"Open exit door: Enter here to leave","the level and exit the actual game"}, - {"Sokoban element: Object which must", "be pushed to an empty field"}, - {"Sokoban element: Empty field where", "a Sokoban object can be placed on"}, - {"Sokoban element: Field with object", "which can be pushed away"}, - {"Speed pill: Lets the player run", "twice as fast as normally"}, -}; -static int num_helpscreen_els = sizeof(helpscreen_eltext) / (2*sizeof(char *)); + if (text == NULL) /* not found */ + text = "No description available"; -static char *helpscreen_music[][3] = + if (strlen(text) <= max_chars_per_line) /* only one line of text */ + sy += getFontHeight(font_nr) / 2; + + DrawTextWrapped(sx, sy + ypos * ystep, text, font_nr, + max_chars_per_line, max_lines_per_text); +} + +void DrawInfoScreen_Elements() { - { "Alchemy", "Ian Boddy", "Drive" }, - { "The Chase", "Propaganda", "A Secret Wish" }, - { "Network 23", "Tangerine Dream", "Exit" }, - { "Czardasz", "Robert Pieculewicz", "Czardasz" }, - { "21st Century Common Man", "Tangerine Dream", "Tyger" }, - { "Voyager", "The Alan Parsons Project","Pyramid" }, - { "Twilight Painter", "Tangerine Dream", "Heartbreakers" } -}; -static int num_helpscreen_music = 7; -static int helpscreen_musicpos; + LoadHelpAnimInfo(); + LoadHelpTextInfo(); -#if 0 -void OLD_DrawHelpScreenElAction(int start) + HandleInfoScreen_Elements(MB_MENU_INITIALIZE); + + FadeToFront(); + InitAnimation(); +} + +void HandleInfoScreen_Elements(int button) { - int i = 0, j = 0; - int frame, graphic; - int xstart = SX+16, ystart = SY+64+2*32, ystep = TILEY+4; + static unsigned long info_delay = 0; + static int num_anims; + static int num_pages; + static int page; + int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN; + int button_released = !button; + int i; - while(helpscreen_action[j] != HA_END) + if (button == MB_MENU_INITIALIZE) { - if (i>=start+MAX_HELPSCREEN_ELS || i>=num_helpscreen_els) - break; - else if (i=start && helpscreen_delay[i-start]) - helpscreen_delay[i-start]--; + boolean new_element = TRUE; - while(helpscreen_action[j] != HA_NEXT) - j++; - j++; - i++; - continue; + num_anims = 0; + for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++) + { + if (helpanim_info[i].element == HELPANIM_LIST_NEXT) + new_element = TRUE; + else if (new_element) + { + num_anims++; + new_element = FALSE; + } } - j += 3*helpscreen_step[i-start]; - graphic = helpscreen_action[j++]; + num_pages = (num_anims + anims_per_page - 1) / anims_per_page; + page = 0; + } + else if (button == MB_MENU_LEAVE) + { + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); - if (helpscreen_frame[i-start]) - { - frame = helpscreen_action[j++] - helpscreen_frame[i-start]; - helpscreen_frame[i-start]--; - } - else - { - frame = 0; - helpscreen_frame[i-start] = helpscreen_action[j++]-1; - } + return; + } - helpscreen_delay[i-start] = helpscreen_action[j++] - 1; + if (button_released || button == MB_MENU_INITIALIZE) + { + if (button != MB_MENU_INITIALIZE) + page++; - if (helpscreen_action[j] == HA_NEXT) - { - if (!helpscreen_frame[i-start]) - helpscreen_step[i-start] = 0; - } - else + if (page >= num_pages) { - if (!helpscreen_frame[i-start]) - helpscreen_step[i-start]++; - while(helpscreen_action[j] != HA_NEXT) - j++; + FadeSoundsAndMusic(); + + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); + + return; } - j++; - DrawOldGraphicExt(drawto, xstart, ystart+(i-start)*ystep, graphic+frame); - i++; + DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE); } - - for(i=2;i<16;i++) + else { - MarkTileDirty(0,i); - MarkTileDirty(1,i); + if (DelayReached(&info_delay, GAME_FRAME_DELAY)) + if (page < num_pages) + DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE); + + PlayMenuSoundIfLoop(); } } -#endif -void DrawHelpScreenElAction(int start) +void DrawInfoScreen_Music() { - int i = 0, j = 0; - int xstart = mSX + 16; - int ystart = mSY + 64 + 2 * 32; - int ystep = TILEY + 4; - int graphic; - int frame_count; - int sync_frame; + ClearWindow(); + DrawHeadline(); + + LoadMusicInfo(); - while (helpscreen_action[j] != HA_END) + HandleInfoScreen_Music(MB_MENU_INITIALIZE); +} + +void HandleInfoScreen_Music(int button) +{ + static struct MusicFileInfo *list = NULL; + int ystart = 150, dy = 30; + int ybottom = SYSIZE - 20; + int button_released = !button; + + if (button == MB_MENU_INITIALIZE) { - if (i >= start + MAX_HELPSCREEN_ELS || i >= num_helpscreen_els) - break; - else if (i < start) + list = music_file_info; + + if (list == NULL) { - while (helpscreen_action[j] != HA_NEXT) - j++; + FadeSoundsAndMusic(); - j++; - i++; + ClearWindow(); + DrawHeadline(); - continue; - } + DrawTextSCentered(100, FONT_TEXT_1, "No music info for this level set."); - j += 2 * helpscreen_step[i-start]; - graphic = helpscreen_action[j++]; - frame_count = helpscreen_action[j++]; - if (frame_count == -1) - frame_count = 1000000; + DrawTextSCentered(ybottom, FONT_TEXT_4, + "Press any key or button for info menu"); - if (helpscreen_frame[i-start] == 0) - { - sync_frame = 0; - helpscreen_frame[i-start] = frame_count - 1; + return; } - else + } + else if (button == MB_MENU_LEAVE) + { + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); + + return; + } + + if (button_released || button == MB_MENU_INITIALIZE) + { + int y = 0; + + if (button != MB_MENU_INITIALIZE) + if (list != NULL) + list = list->next; + + if (list == NULL) { - sync_frame = frame_count - helpscreen_frame[i-start]; - helpscreen_frame[i-start]--; + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); + + return; } - if (helpscreen_action[j] == HA_NEXT) + FadeSoundsAndMusic(); + + ClearWindow(); + DrawHeadline(); + + if (list->is_sound) { - if (!helpscreen_frame[i-start]) - helpscreen_step[i-start] = 0; + int sound = list->music; + + if (sound_info[sound].loop) + PlaySoundLoop(sound); + else + PlaySound(sound); + + DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Sounds:"); } else { - if (!helpscreen_frame[i-start]) - helpscreen_step[i-start]++; - while(helpscreen_action[j] != HA_NEXT) - j++; + PlayMusic(list->music); + + DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Music:"); } - j++; -#if 1 - ClearRectangleOnBackground(drawto, xstart, ystart + (i - start) * ystep, - TILEX, TILEY); - DrawGraphicAnimationExt(drawto, xstart, ystart + (i - start) * ystep, - graphic, sync_frame, USE_MASKING); -#else - frame = getGraphicAnimationFrame(graphic, sync_frame); + if (strcmp(list->title, UNKNOWN_NAME) != 0) + { + if (strcmp(list->title_header, UNKNOWN_NAME) != 0) + DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->title_header); - DrawGraphicExt(drawto, xstart, ystart + (i-start) * ystep, - graphic, frame); -#endif + DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title); + } - i++; - } + if (strcmp(list->artist, UNKNOWN_NAME) != 0) + { + if (strcmp(list->artist_header, UNKNOWN_NAME) != 0) + DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->artist_header); + else + DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "by"); -#if 1 - redraw_mask |= REDRAW_FIELD; -#else - for(i=2; i<16; i++) - { - MarkTileDirty(0, i); - MarkTileDirty(1, i); - } -#endif + DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->artist); + } - FrameCounter++; -} + if (strcmp(list->album, UNKNOWN_NAME) != 0) + { + if (strcmp(list->album_header, UNKNOWN_NAME) != 0) + DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->album_header); + else + DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the album"); -void DrawHelpScreenElText(int start) -{ - int i; - int xstart = mSX + 56, ystart = mSY + 65 + 2 * 32, ystep = TILEY + 4; - int ybottom = SYSIZE - 20; + DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album); + } - SetMainBackgroundImage(IMG_BACKGROUND_INFO); - ClearWindow(); - DrawHeadline(); + if (strcmp(list->year, UNKNOWN_NAME) != 0) + { + if (strcmp(list->year_header, UNKNOWN_NAME) != 0) + DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->year_header); + else + DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the year"); - DrawTextFCentered(100, FONT_TEXT_1, "The game elements:"); + DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->year); + } - for(i=start; i < start + MAX_HELPSCREEN_ELS && i < num_helpscreen_els; i++) - { - DrawText(xstart, - ystart + (i - start) * ystep + (*helpscreen_eltext[i][1] ? 0 : 8), - helpscreen_eltext[i][0], FONT_TEXT_2); - DrawText(xstart, ystart + (i - start) * ystep + 16, - helpscreen_eltext[i][1], FONT_TEXT_2); + DrawTextSCentered(ybottom, FONT_TEXT_4, + "Press any key or button for next page"); } - DrawTextFCentered(ybottom, FONT_TEXT_4, - "Press any key or button for next page"); + if (list != NULL && list->is_sound && sound_info[list->music].loop) + PlaySoundLoop(list->music); } -void DrawHelpScreenMusicText(int num) +void DrawInfoScreen_Credits() { int ystart = 150, ystep = 30; int ybottom = SYSIZE - 20; - FadeSounds(); + FadeSoundsAndMusic(); + ClearWindow(); DrawHeadline(); - DrawTextFCentered(100, FONT_TEXT_1, "The game background music loops:"); - - DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2, "Excerpt from"); - DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_3, - "\"%s\"", helpscreen_music[num][0]); - DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_2, "by"); - DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_3, - "%s", helpscreen_music[num][1]); - DrawTextFCentered(ystart + 4 * ystep, FONT_TEXT_2, "from the album"); - DrawTextFCentered(ystart + 5 * ystep, FONT_TEXT_3, - "\"%s\"", helpscreen_music[num][2]); - - DrawTextFCentered(ybottom, FONT_TEXT_4, - "Press any key or button for next page"); + DrawTextSCentered(100, FONT_TEXT_1, "Credits:"); + DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2, "DOS port of the game:"); + DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_3, "Guido Schulz"); + DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2, "Additional toons:"); + DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_3, "Karl Hörnell"); + DrawTextSCentered(ystart + 5 * ystep, FONT_TEXT_2, + "...and many thanks to all contributors"); + DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2, "of new levels!"); -#if 0 - PlaySoundLoop(background_loop[num]); -#endif + DrawTextSCentered(ybottom, FONT_TEXT_4, + "Press any key or button for info menu"); } -void DrawHelpScreenCreditsText() +void HandleInfoScreen_Credits(int button) { - int ystart = 150, ystep = 30; - int ybottom = SYSIZE - 20; + int button_released = !button; - FadeSounds(); - ClearWindow(); - DrawHeadline(); + if (button == MB_MENU_LEAVE) + { + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); - DrawTextFCentered(100, FONT_TEXT_1, "Credits:"); - DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2, "DOS port of the game:"); - DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_3, "Guido Schulz"); - DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_2, "Additional toons:"); - DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_3, "Karl Hörnell"); - DrawTextFCentered(ystart + 5 * ystep, FONT_TEXT_2, - "...and many thanks to all contributors"); - DrawTextFCentered(ystart + 6 * ystep, FONT_TEXT_2, "of new levels!"); + return; + } + + if (button_released) + { + FadeSoundsAndMusic(); - DrawTextFCentered(ybottom, FONT_TEXT_4, - "Press any key or button for next page"); + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); + } + else + { + PlayMenuSoundIfLoop(); + } } -void DrawHelpScreenContactText() +void DrawInfoScreen_Program() { int ystart = 150, ystep = 30; int ybottom = SYSIZE - 20; @@ -1015,129 +1131,168 @@ void DrawHelpScreenContactText() ClearWindow(); DrawHeadline(); - DrawTextFCentered(100, FONT_TEXT_1, "Program information:"); + DrawTextSCentered(100, FONT_TEXT_1, "Program Information:"); - DrawTextFCentered(ystart + 0 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2, "This game is Freeware!"); - DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart + 1 * ystep, FONT_TEXT_2, "If you like it, send e-mail to:"); - DrawTextFCentered(ystart + 2 * ystep, FONT_TEXT_3, + DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_3, "info@artsoft.org"); - DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart + 3 * ystep, FONT_TEXT_2, "or SnailMail to:"); - DrawTextFCentered(ystart + 4 * ystep + 0, FONT_TEXT_3, + DrawTextSCentered(ystart + 4 * ystep + 0, FONT_TEXT_3, "Holger Schemel"); - DrawTextFCentered(ystart + 4 * ystep + 20, FONT_TEXT_3, + DrawTextSCentered(ystart + 4 * ystep + 20, FONT_TEXT_3, "Detmolder Strasse 189"); - DrawTextFCentered(ystart + 4 * ystep + 40, FONT_TEXT_3, + DrawTextSCentered(ystart + 4 * ystep + 40, FONT_TEXT_3, "33604 Bielefeld"); - DrawTextFCentered(ystart + 4 * ystep + 60, FONT_TEXT_3, + DrawTextSCentered(ystart + 4 * ystep + 60, FONT_TEXT_3, "Germany"); - DrawTextFCentered(ystart + 7 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart + 7 * ystep, FONT_TEXT_2, "If you have created new levels,"); - DrawTextFCentered(ystart + 8 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart + 8 * ystep, FONT_TEXT_2, "send them to me to include them!"); - DrawTextFCentered(ystart + 9 * ystep, FONT_TEXT_2, + DrawTextSCentered(ystart + 9 * ystep, FONT_TEXT_2, ":-)"); - DrawTextFCentered(ybottom, FONT_TEXT_4, - "Press any key or button for main menu"); + DrawTextSCentered(ybottom, FONT_TEXT_4, + "Press any key or button for info menu"); } -void DrawHelpScreen() +void HandleInfoScreen_Program(int button) { - int i; + int button_released = !button; - UnmapAllGadgets(); - CloseDoor(DOOR_CLOSE_2); + if (button == MB_MENU_LEAVE) + { + info_mode = INFO_MODE_MAIN; + DrawInfoScreen(); - for(i=0;i= 0 && y < num_page_entries) + if (IN_VIS_FIELD(x, y) && + mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x && + y >= 0 && y < num_page_entries) { if (button) { @@ -1535,13 +1695,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button, } } } - -#if 0 - if (game_status == GAME_MODE_LEVELS || game_status == GAME_MODE_SETUP) - DoAnimation(); - - BackToFront(); -#endif } void DrawChooseLevel() @@ -1549,6 +1702,9 @@ void DrawChooseLevel() SetMainBackgroundImage(IMG_BACKGROUND_LEVELS); DrawChooseTree(&leveldir_current); + + PlayMenuSound(); + PlayMenuMusic(); } void HandleChooseLevel(int mx, int my, int dx, int dy, int button) @@ -1556,13 +1712,12 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button) HandleChooseTree(mx, my, dx, dy, button, &leveldir_current); DoAnimation(); - BackToFront(); } void DrawHallOfFame(int highlight_position) { UnmapAllGadgets(); - FadeSounds(); + FadeSoundsAndMusic(); CloseDoor(DOOR_CLOSE_2); if (highlight_position < 0) @@ -1571,13 +1726,10 @@ void DrawHallOfFame(int highlight_position) FadeToFront(); InitAnimation(); - HandleHallOfFame(highlight_position,0, 0,0, MB_MENU_INITIALIZE); + PlayMenuSound(); + PlayMenuMusic(); -#if 0 - PlaySound(SND_BACKGROUND_SCORES); -#else - PlaySound_Menu_Start(SND_BACKGROUND_SCORES); -#endif + HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE); } static void drawHallOfFameList(int first_entry, int highlight_position) @@ -1590,7 +1742,7 @@ static void drawHallOfFameList(int first_entry, int highlight_position) DrawText(mSX + 80, mSY + 8, "Hall Of Fame", FONT_TITLE_1); DrawTextFCentered(46, FONT_TITLE_2, "HighScores of Level %d", level_nr); - for(i=0; i 0 && y < num_setup_info - 1 && - (setup_info[y].type & TYPE_SKIP_ENTRY)) + setup_info[y].type & TYPE_SKIP_ENTRY) y += dy; } - if (x == 0 && y >= 0 && y < num_setup_info && - (setup_info[y].type & ~TYPE_SKIP_ENTRY)) + if (IN_VIS_FIELD(x, y) && + y >= 0 && y < num_setup_info && setup_info[y].type & ~TYPE_SKIP_ENTRY) { if (button) { @@ -2154,8 +2319,8 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button) } else { - if ((setup_info[y].type & TYPE_KEYTEXT) && - (setup_info[y + 1].type & TYPE_KEY)) + if (setup_info[y].type & TYPE_KEYTEXT && + setup_info[y + 1].type & TYPE_KEY) y++; if (setup_info[y].type & TYPE_VALUE) @@ -2163,13 +2328,6 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button) } } } - -#if 0 - BackToFront(); - - if (game_status == GAME_MODE_SETUP) - DoAnimation(); -#endif } void DrawSetupScreen_Input() @@ -2192,11 +2350,11 @@ void DrawSetupScreen_Input() #if 0 DeactivateJoystickForCalibration(); - DrawTextFCentered(SYSIZE - 20, FONT_TEXT_4, + DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4, "Joysticks deactivated on this screen"); #endif - HandleSetupScreen_Input(0,0, 0,0, MB_MENU_INITIALIZE); + HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE); FadeToFront(); InitAnimation(); } @@ -2284,7 +2442,7 @@ static void drawPlayerSetupInputInfo(int player_nr) DrawText(mSX+32, mSY+10*32, "Snap Field:", FONT_VALUE_OLD); DrawText(mSX+32, mSY+12*32, "Place Bomb:", FONT_VALUE_OLD); - for (i=0; i<6; i++) + for (i = 0; i < 6; i++) { int ypos = 6 + i + (i > 3 ? i-3 : 0); @@ -2312,6 +2470,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) { drawPlayerSetupInputInfo(player_nr); drawCursor(choice, FC_RED); + return; } else if (button == MB_MENU_LEAVE) @@ -2319,6 +2478,8 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) setup_mode = SETUP_MODE_MAIN; DrawSetupScreen(); InitJoysticks(); + + return; } if (mx || my) /* mouse input */ @@ -2341,22 +2502,20 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1); } - if (y == 0 && ((x == 0 && !button) || ((x == 10 || x == 12) && button))) + if (IN_VIS_FIELD(x, y) && + y == 0 && ((x < 10 && !button) || ((x == 10 || x == 12) && button))) { static unsigned long delay = 0; if (!DelayReached(&delay, GADGET_FRAME_DELAY)) -#if 1 return; -#else - goto out; -#endif player_nr = (player_nr + (x == 10 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS; drawPlayerSetupInputInfo(player_nr); } - else if (x == 0 && y >= pos_start && y <= pos_end && + else if (IN_VIS_FIELD(x, y) && + y >= pos_start && y <= pos_end && !(y >= pos_empty1 && y <= pos_empty2)) { if (button) @@ -2413,15 +2572,6 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button) } } } - -#if 0 - BackToFront(); - - out: - - if (game_status == GAME_MODE_SETUP) - DoAnimation(); -#endif } void CustomizeKeyboard(int player_nr) @@ -2461,7 +2611,7 @@ void CustomizeKeyboard(int player_nr) DrawText(mSX + 4*32, mSY + (2+2*step_nr+1)*32, getKeyNameFromKey(*customize_step[step_nr].key), FONT_VALUE_OLD); - while(!finished) + while (!finished) { if (PendingEvent()) /* got event */ { @@ -2490,7 +2640,7 @@ void CustomizeKeyboard(int player_nr) key = *customize_step[step_nr].key; /* check if key already used */ - for (i=0; iclip_mask = None; @@ -3059,7 +3208,7 @@ void FreeScreenGadgets() } #endif - for (i=0; i= x1 && xx <= x2 && yy >= y1 && yy <= y2) DrawScreenField(xx, yy); DrawAllPlayers(); @@ -263,8 +263,8 @@ void BackToFront() if (redraw_mask & REDRAW_TILES) { - for(x=0; xelement_nr, player->GfxAction, move_dir); } +static boolean equalGraphics(int graphic1, int graphic2) +{ + struct GraphicInfo *g1 = &graphic_info[graphic1]; + struct GraphicInfo *g2 = &graphic_info[graphic2]; + + return (g1->bitmap == g2->bitmap && + g1->src_x == g2->src_x && + g1->src_y == g2->src_y && + g1->anim_frames == g2->anim_frames && + g1->anim_delay == g2->anim_delay && + g1->anim_mode == g2->anim_mode); +} + void DrawAllPlayers() { int i; - for(i=0; iis_pushing ? ACTION_PUSHING : - player->is_digging ? ACTION_DIGGING : - player->is_collecting ? ACTION_COLLECTING : - player->is_moving ? ACTION_MOVING : - player->is_snapping ? ACTION_SNAPPING : ACTION_DEFAULT); - -#if 0 - printf("::: '%s'\n", element_action_info[action].suffix); -#endif + action = (player->is_pushing ? ACTION_PUSHING : + player->is_digging ? ACTION_DIGGING : + player->is_collecting ? ACTION_COLLECTING : + player->is_moving ? ACTION_MOVING : + player->is_snapping ? ACTION_SNAPPING : + player->is_waiting ? player->action_waiting : ACTION_DEFAULT); InitPlayerGfxAnimation(player, action, move_dir); @@ -704,8 +714,7 @@ void DrawPlayer(struct PlayerInfo *player) /* in the case of changed player action or direction, prevent the current animation frame from being restarted for identical animations */ - if (player->Frame == 0 && - graphic_info[graphic].bitmap == graphic_info[last_player_graphic].bitmap) + if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic)) player->Frame = last_player_frame; #else @@ -1222,7 +1231,7 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame) getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); - for(i=0; i<4; i++) + for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; @@ -1267,7 +1276,7 @@ static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame) getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y); #endif - for(i=0; i<4; i++) + for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; @@ -1356,7 +1365,7 @@ void DrawLevelFieldCrumbledSandNeighbours(int x, int y) }; int i; - for(i=0; i<4; i++) + for (i = 0; i < 4; i++) { int xx = x + xy[i][0]; int yy = y + xy[i][1]; @@ -1604,7 +1613,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action) int ystep = (ystart < yend || xstep == 0 ? 1 : 0); int x, y; - for (x=xstart, y=ystart; x <= xend && y <= yend; x += xstep, y += ystep) + for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep) { int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2; int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2; @@ -1618,7 +1627,7 @@ void AnimateEnvelope(int envelope_nr, int anim_mode, int action) SetDrawtoField(DRAW_BACKBUFFER); - for (yy=0; yy < ysize; yy++) for (xx=0; xx < xsize; xx++) + for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++) DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr); DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height, @@ -1705,8 +1714,8 @@ void DrawLevel() SetDrawBackgroundMask(REDRAW_NONE); ClearWindow(); - for(x=BX1; x<=BX2; x++) - for(y=BY1; y<=BY2; y++) + for (x = BX1; x <= BX2; x++) + for (y = BY1; y <= BY2; y++) DrawScreenField(x, y); redraw_mask |= REDRAW_FIELD; @@ -1716,8 +1725,8 @@ void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y) { int x,y; - for(x=0; x MAX_REQUEST_LINE_FONT1_LEN) + { + max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN; + font_nr = FONT_LEVEL_NUMBER; + + break; + } + } #if 1 SetMouseCursor(CURSOR_DEFAULT); @@ -1995,15 +2022,15 @@ boolean Request(char *text, unsigned int req_state) game_status = GAME_MODE_PSEUDO_DOOR; /* write text for request */ - for(ty=0; ty < MAX_REQUEST_LINES; ty++) + for (ty = 0; ty < MAX_REQUEST_LINES; ty++) { - char text_line[MAX_REQUEST_LINE_LEN + 1]; - int tx, tl, tc; + char text_line[max_request_line_len + 1]; + int tx, tl, tc = 0; if (!*text) break; - for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++) + for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++) { tc = *(text + tx); if (!tc || tc == ' ') @@ -2020,9 +2047,9 @@ boolean Request(char *text, unsigned int req_state) strncpy(text_line, text, tl); text_line[tl] = 0; - DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2, - DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2), - text_line, FONT_TEXT_2); + DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2, + DY + 8 + ty * (getFontHeight(font_nr) + 2), + text_line, font_nr); text += tl + (tc == ' ' ? 1 : 0); } @@ -2077,7 +2104,7 @@ boolean Request(char *text, unsigned int req_state) SetMouseCursor(CURSOR_DEFAULT); #endif - while(result < 0) + while (result < 0) { if (PendingEvent()) { @@ -2332,7 +2359,7 @@ unsigned int MoveDoor(unsigned int door_state) PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE); } - for(x = start; x <= end && !(door_1_done && door_2_done); x += stepsize) + for (x = start; x <= end && !(door_1_done && door_2_done); x += stepsize) { Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap; GC gc = bitmap->stored_clip_gc; @@ -2649,7 +2676,7 @@ void CreateToolButtons() { int i; - for (i=0; i