From c781e660ed2fe6ad36c9eee0a77d64ee07163030 Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Sat, 30 Aug 2003 03:42:30 +0200 Subject: [PATCH] rnd-20030830-1-src --- src/conftime.h | 2 +- src/editor.c | 884 +++++++++++++++++++++++++++++++++--------- src/files.c | 338 +++++++++++++--- src/files.h | 3 + src/game.c | 370 +++++++++--------- src/init.c | 6 + src/libgame/gadgets.c | 567 +++++++++++++++++++-------- src/libgame/gadgets.h | 29 +- src/libgame/setup.c | 9 +- src/libgame/system.h | 2 + src/libgame/text.c | 28 ++ src/libgame/text.h | 1 + src/main.h | 59 ++- src/screens.c | 2 + 14 files changed, 1689 insertions(+), 611 deletions(-) diff --git a/src/conftime.h b/src/conftime.h index e72f2c2b..728e804b 100644 --- a/src/conftime.h +++ b/src/conftime.h @@ -1 +1 @@ -#define COMPILE_DATE_STRING "[2003-08-24 19:50]" +#define COMPILE_DATE_STRING "[2003-08-30 03:37]" diff --git a/src/editor.c b/src/editor.c index 4a47194a..636e21dc 100644 --- a/src/editor.c +++ b/src/editor.c @@ -98,10 +98,6 @@ #define ED_SETTINGS2_YPOS (ED_SETTINGS1_YPOS + 12 * TILEY - 2) /* values for counter gadgets */ -#define ED_COUNT_PUSH_DELAY_RND_XPOS (ED_SETTINGS_XPOS(1) + 16 * MINI_TILEX) -#define ED_COUNT_MOVE_DELAY_RND_XPOS ED_COUNT_PUSH_DELAY_RND_XPOS -#define ED_COUNT_CHANGE_DELAY_RND_XPOS (ED_SETTINGS_XPOS(1) + 13 * MINI_TILEX) - #define ED_COUNTER_YSTART (ED_SETTINGS1_YPOS + 2 * TILEY) #define ED_COUNTER_YDISTANCE (3 * MINI_TILEY) #define ED_COUNTER_YPOS(n) (ED_COUNTER_YSTART + \ @@ -121,11 +117,9 @@ 6 * (n / 4) * MINI_TILEY) /* custom change target */ -#define ED_AREA_ELEM_CONTENT2_XPOS (20 * MINI_TILEX) #define ED_AREA_ELEM_CONTENT2_YPOS (ED_SETTINGS_YPOS(2) + \ ED_GADGET_DISTANCE) /* optional custom graphic */ -#define ED_AREA_ELEM_CONTENT3_XPOS (24 * MINI_TILEX) #define ED_AREA_ELEM_CONTENT3_YPOS (ED_SETTINGS_YPOS(1) + \ ED_GADGET_DISTANCE) /* custom element content */ @@ -133,7 +127,6 @@ #define ED_AREA_ELEM_CONTENT4_YPOS (ED_SETTINGS_YPOS(12) + \ ED_GADGET_DISTANCE - MINI_TILEY) /* custom change trigger element */ -#define ED_AREA_ELEM_CONTENT5_XPOS (28 * MINI_TILEX) #define ED_AREA_ELEM_CONTENT5_YPOS (ED_SETTINGS_YPOS(7) + \ ED_GADGET_DISTANCE) /* extended custom change target */ @@ -142,7 +135,6 @@ ED_GADGET_DISTANCE - MINI_TILEY) /* values for random placement background drawing area */ -#define ED_AREA_RANDOM_BACKGROUND_XPOS (29 * MINI_TILEX) #define ED_AREA_RANDOM_BACKGROUND_YPOS (31 * MINI_TILEY) /* values for scrolling gadgets for drawing area */ @@ -325,36 +317,42 @@ #define GADGET_ID_ELEMENT_CONTENT_DOWN (GADGET_ID_COUNTER_FIRST + 24) #define GADGET_ID_ELEMENT_CONTENT_TEXT (GADGET_ID_COUNTER_FIRST + 25) #define GADGET_ID_ELEMENT_CONTENT_UP (GADGET_ID_COUNTER_FIRST + 26) -#define GADGET_ID_CUSTOM_SCORE_DOWN (GADGET_ID_COUNTER_FIRST + 27) -#define GADGET_ID_CUSTOM_SCORE_TEXT (GADGET_ID_COUNTER_FIRST + 28) -#define GADGET_ID_CUSTOM_SCORE_UP (GADGET_ID_COUNTER_FIRST + 29) -#define GADGET_ID_CUSTOM_GEMCOUNT_DOWN (GADGET_ID_COUNTER_FIRST + 30) -#define GADGET_ID_CUSTOM_GEMCOUNT_TEXT (GADGET_ID_COUNTER_FIRST + 31) -#define GADGET_ID_CUSTOM_GEMCOUNT_UP (GADGET_ID_COUNTER_FIRST + 32) -#define GADGET_ID_PUSH_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 33) -#define GADGET_ID_PUSH_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 34) -#define GADGET_ID_PUSH_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 35) -#define GADGET_ID_PUSH_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 36) -#define GADGET_ID_PUSH_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 37) -#define GADGET_ID_PUSH_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 38) -#define GADGET_ID_MOVE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 39) -#define GADGET_ID_MOVE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 40) -#define GADGET_ID_MOVE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 41) -#define GADGET_ID_MOVE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 42) -#define GADGET_ID_MOVE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 43) -#define GADGET_ID_MOVE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 44) -#define GADGET_ID_CHANGE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 45) -#define GADGET_ID_CHANGE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 46) -#define GADGET_ID_CHANGE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 47) -#define GADGET_ID_CHANGE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 48) -#define GADGET_ID_CHANGE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 49) -#define GADGET_ID_CHANGE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 50) -#define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 51) -#define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 52) -#define GADGET_ID_CHANGE_CONT_RND_UP (GADGET_ID_COUNTER_FIRST + 53) +#define GADGET_ID_ENVELOPE_XSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 27) +#define GADGET_ID_ENVELOPE_XSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 28) +#define GADGET_ID_ENVELOPE_XSIZE_UP (GADGET_ID_COUNTER_FIRST + 29) +#define GADGET_ID_ENVELOPE_YSIZE_DOWN (GADGET_ID_COUNTER_FIRST + 30) +#define GADGET_ID_ENVELOPE_YSIZE_TEXT (GADGET_ID_COUNTER_FIRST + 31) +#define GADGET_ID_ENVELOPE_YSIZE_UP (GADGET_ID_COUNTER_FIRST + 32) +#define GADGET_ID_CUSTOM_SCORE_DOWN (GADGET_ID_COUNTER_FIRST + 33) +#define GADGET_ID_CUSTOM_SCORE_TEXT (GADGET_ID_COUNTER_FIRST + 34) +#define GADGET_ID_CUSTOM_SCORE_UP (GADGET_ID_COUNTER_FIRST + 35) +#define GADGET_ID_CUSTOM_GEMCOUNT_DOWN (GADGET_ID_COUNTER_FIRST + 36) +#define GADGET_ID_CUSTOM_GEMCOUNT_TEXT (GADGET_ID_COUNTER_FIRST + 37) +#define GADGET_ID_CUSTOM_GEMCOUNT_UP (GADGET_ID_COUNTER_FIRST + 38) +#define GADGET_ID_PUSH_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 39) +#define GADGET_ID_PUSH_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 40) +#define GADGET_ID_PUSH_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 41) +#define GADGET_ID_PUSH_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 42) +#define GADGET_ID_PUSH_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 43) +#define GADGET_ID_PUSH_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 44) +#define GADGET_ID_MOVE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 45) +#define GADGET_ID_MOVE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 46) +#define GADGET_ID_MOVE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 47) +#define GADGET_ID_MOVE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 48) +#define GADGET_ID_MOVE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 49) +#define GADGET_ID_MOVE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 50) +#define GADGET_ID_CHANGE_DELAY_FIX_DOWN (GADGET_ID_COUNTER_FIRST + 51) +#define GADGET_ID_CHANGE_DELAY_FIX_TEXT (GADGET_ID_COUNTER_FIRST + 52) +#define GADGET_ID_CHANGE_DELAY_FIX_UP (GADGET_ID_COUNTER_FIRST + 53) +#define GADGET_ID_CHANGE_DELAY_RND_DOWN (GADGET_ID_COUNTER_FIRST + 54) +#define GADGET_ID_CHANGE_DELAY_RND_TEXT (GADGET_ID_COUNTER_FIRST + 55) +#define GADGET_ID_CHANGE_DELAY_RND_UP (GADGET_ID_COUNTER_FIRST + 56) +#define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 57) +#define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 58) +#define GADGET_ID_CHANGE_CONT_RND_UP (GADGET_ID_COUNTER_FIRST + 59) /* drawing area identifiers */ -#define GADGET_ID_DRAWING_AREA_FIRST (GADGET_ID_COUNTER_FIRST + 54) +#define GADGET_ID_DRAWING_AREA_FIRST (GADGET_ID_COUNTER_FIRST + 60) #define GADGET_ID_DRAWING_LEVEL (GADGET_ID_DRAWING_AREA_FIRST + 0) #define GADGET_ID_ELEMENT_CONTENT_0 (GADGET_ID_DRAWING_AREA_FIRST + 1) @@ -380,8 +378,13 @@ #define GADGET_ID_LEVEL_AUTHOR (GADGET_ID_TEXT_INPUT_FIRST + 1) #define GADGET_ID_ELEMENT_NAME (GADGET_ID_TEXT_INPUT_FIRST + 2) +/* text area identifiers */ +#define GADGET_ID_TEXT_AREA_FIRST (GADGET_ID_TEXT_INPUT_FIRST + 3) + +#define GADGET_ID_ENVELOPE_INFO (GADGET_ID_TEXT_AREA_FIRST + 0) + /* selectbox identifiers */ -#define GADGET_ID_SELECTBOX_FIRST (GADGET_ID_TEXT_INPUT_FIRST + 3) +#define GADGET_ID_SELECTBOX_FIRST (GADGET_ID_TEXT_AREA_FIRST + 1) #define GADGET_ID_CUSTOM_WALK_TO_ACTION (GADGET_ID_SELECTBOX_FIRST + 0) #define GADGET_ID_CUSTOM_CONSISTENCY (GADGET_ID_SELECTBOX_FIRST + 1) @@ -398,17 +401,26 @@ #define GADGET_ID_CHANGE_COLLIDE_ACTION (GADGET_ID_SELECTBOX_FIRST + 12) #define GADGET_ID_CHANGE_OTHER_ACTION (GADGET_ID_SELECTBOX_FIRST + 13) #define GADGET_ID_CHANGE_POWER (GADGET_ID_SELECTBOX_FIRST + 14) +#define GADGET_ID_SELECT_CHANGE_PAGE (GADGET_ID_SELECTBOX_FIRST + 15) /* textbutton identifiers */ -#define GADGET_ID_TEXTBUTTON_FIRST (GADGET_ID_SELECTBOX_FIRST + 15) +#define GADGET_ID_TEXTBUTTON_FIRST (GADGET_ID_SELECTBOX_FIRST + 16) #define GADGET_ID_PROPERTIES_INFO (GADGET_ID_TEXTBUTTON_FIRST + 0) #define GADGET_ID_PROPERTIES_CONFIG (GADGET_ID_TEXTBUTTON_FIRST + 1) #define GADGET_ID_PROPERTIES_ADVANCED (GADGET_ID_TEXTBUTTON_FIRST + 2) #define GADGET_ID_SAVE_AS_TEMPLATE (GADGET_ID_TEXTBUTTON_FIRST + 3) +#define GADGET_ID_ADD_CHANGE_PAGE (GADGET_ID_TEXTBUTTON_FIRST + 4) +#define GADGET_ID_DEL_CHANGE_PAGE (GADGET_ID_TEXTBUTTON_FIRST + 5) + +/* graphicbutton identifiers */ +#define GADGET_ID_GRAPHICBUTTON_FIRST (GADGET_ID_TEXTBUTTON_FIRST + 6) + +#define GADGET_ID_PREV_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 0) +#define GADGET_ID_NEXT_CHANGE_PAGE (GADGET_ID_GRAPHICBUTTON_FIRST + 1) /* gadgets for scrolling of drawing area */ -#define GADGET_ID_SCROLLING_FIRST (GADGET_ID_TEXTBUTTON_FIRST + 4) +#define GADGET_ID_SCROLLING_FIRST (GADGET_ID_GRAPHICBUTTON_FIRST + 2) #define GADGET_ID_SCROLL_UP (GADGET_ID_SCROLLING_FIRST + 0) #define GADGET_ID_SCROLL_DOWN (GADGET_ID_SCROLLING_FIRST + 1) @@ -479,17 +491,19 @@ #define ED_COUNTER_ID_LEVEL_RANDOM 6 #define ED_COUNTER_ID_ELEMENT_SCORE 7 #define ED_COUNTER_ID_ELEMENT_CONTENT 8 -#define ED_COUNTER_ID_CUSTOM_SCORE 9 -#define ED_COUNTER_ID_CUSTOM_GEMCOUNT 10 -#define ED_COUNTER_ID_PUSH_DELAY_FIX 11 -#define ED_COUNTER_ID_PUSH_DELAY_RND 12 -#define ED_COUNTER_ID_MOVE_DELAY_FIX 13 -#define ED_COUNTER_ID_MOVE_DELAY_RND 14 -#define ED_COUNTER_ID_CHANGE_DELAY_FIX 15 -#define ED_COUNTER_ID_CHANGE_DELAY_RND 16 -#define ED_COUNTER_ID_CHANGE_CONT_RND 17 - -#define ED_NUM_COUNTERBUTTONS 18 +#define ED_COUNTER_ID_ENVELOPE_XSIZE 9 +#define ED_COUNTER_ID_ENVELOPE_YSIZE 10 +#define ED_COUNTER_ID_CUSTOM_SCORE 11 +#define ED_COUNTER_ID_CUSTOM_GEMCOUNT 12 +#define ED_COUNTER_ID_PUSH_DELAY_FIX 13 +#define ED_COUNTER_ID_PUSH_DELAY_RND 14 +#define ED_COUNTER_ID_MOVE_DELAY_FIX 15 +#define ED_COUNTER_ID_MOVE_DELAY_RND 16 +#define ED_COUNTER_ID_CHANGE_DELAY_FIX 17 +#define ED_COUNTER_ID_CHANGE_DELAY_RND 18 +#define ED_COUNTER_ID_CHANGE_CONT_RND 19 + +#define ED_NUM_COUNTERBUTTONS 20 #define ED_COUNTER_ID_LEVEL_FIRST ED_COUNTER_ID_LEVEL_XSIZE #define ED_COUNTER_ID_LEVEL_LAST ED_COUNTER_ID_LEVEL_RANDOM @@ -533,6 +547,14 @@ #define ED_TEXTINPUT_ID_LEVEL_FIRST ED_TEXTINPUT_ID_LEVEL_NAME #define ED_TEXTINPUT_ID_LEVEL_LAST ED_TEXTINPUT_ID_LEVEL_AUTHOR +/* values for text area gadgets */ +#define ED_TEXTAREA_ID_ENVELOPE_INFO 0 + +#define ED_NUM_TEXTAREAS 1 + +#define ED_TEXTAREA_ID_LEVEL_FIRST ED_TEXTAREA_ID_ENVELOPE +#define ED_TEXTAREA_ID_LEVEL_LAST ED_TEXTAREA_ID_ENVELOPE + /* values for selectbox gadgets */ #define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE 0 #define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER 1 @@ -549,22 +571,40 @@ #define ED_SELECTBOX_ID_CHANGE_COLLIDE_ACTION 12 #define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION 13 #define ED_SELECTBOX_ID_CHANGE_POWER 14 +#define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE 15 -#define ED_NUM_SELECTBOX 15 +#define ED_NUM_SELECTBOX 16 #define ED_SELECTBOX_ID_CUSTOM_FIRST ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE #define ED_SELECTBOX_ID_CUSTOM_LAST ED_SELECTBOX_ID_CUSTOM_CONSISTENCY #define ED_SELECTBOX_ID_CHANGE_FIRST ED_SELECTBOX_ID_CHANGE_TIME_UNITS -#define ED_SELECTBOX_ID_CHANGE_LAST ED_SELECTBOX_ID_CHANGE_POWER +#define ED_SELECTBOX_ID_CHANGE_LAST ED_SELECTBOX_ID_SELECT_CHANGE_PAGE /* values for textbutton gadgets */ #define ED_TEXTBUTTON_ID_PROPERTIES_INFO 0 #define ED_TEXTBUTTON_ID_PROPERTIES_CONFIG 1 #define ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED 2 #define ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE 3 +#define ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE 4 +#define ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE 5 + +#define ED_NUM_TEXTBUTTONS 6 + +#define ED_TEXTBUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO +#define ED_TEXTBUTTON_ID_PROPERTIES_LAST ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED -#define ED_NUM_TEXTBUTTON 4 +#define ED_TEXTBUTTON_ID_CHANGE_FIRST ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE +#define ED_TEXTBUTTON_ID_CHANGE_LAST ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE + +/* values for graphicbutton gadgets */ +#define ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE 0 +#define ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE 1 + +#define ED_NUM_GRAPHICBUTTONS 2 + +#define ED_GRAPHICBUTTON_ID_CHANGE_FIRST ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE +#define ED_GRAPHICBUTTON_ID_CHANGE_LAST ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE /* values for checkbutton gadgets */ #define ED_CHECKBUTTON_ID_DOUBLE_SPEED 0 @@ -726,6 +766,7 @@ static boolean random_placement_background_restricted = FALSE; static boolean stick_element_properties_window = FALSE; static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES]; static boolean custom_element_change_events[NUM_CHANGE_EVENTS]; +static struct ElementChangeInfo custom_element_change; static struct ElementInfo custom_element; static struct @@ -758,7 +799,7 @@ static struct "playfield size:", NULL, "width", }, { - ED_SETTINGS_XPOS(0) + 2 * DXSIZE, ED_COUNTER_YPOS(2), + -1, ED_COUNTER_YPOS(2), MIN_LEV_FIELDY, MAX_LEV_FIELDY, GADGET_ID_LEVEL_YSIZE_DOWN, GADGET_ID_LEVEL_YSIZE_UP, GADGET_ID_LEVEL_YSIZE_TEXT, GADGET_ID_LEVEL_XSIZE_UP, @@ -816,6 +857,22 @@ static struct &level.num_yamyam_contents, NULL, NULL, "number of content areas" }, + { + ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(0), + MIN_ENVELOPE_XSIZE, MAX_ENVELOPE_XSIZE, + GADGET_ID_ENVELOPE_XSIZE_DOWN, GADGET_ID_ENVELOPE_XSIZE_UP, + GADGET_ID_ENVELOPE_XSIZE_TEXT, GADGET_ID_NONE, + &level.envelope_xsize, + NULL, NULL, "width", + }, + { + -1, ED_SETTINGS_YPOS(0), + MIN_ENVELOPE_YSIZE, MAX_ENVELOPE_YSIZE, + GADGET_ID_ENVELOPE_YSIZE_DOWN, GADGET_ID_ENVELOPE_YSIZE_UP, + GADGET_ID_ENVELOPE_YSIZE_TEXT, GADGET_ID_ENVELOPE_XSIZE_UP, + &level.envelope_ysize, + NULL, " ", "height", + }, /* ---------- element settings: configure (custom elements) ------------- */ @@ -825,10 +882,10 @@ static struct GADGET_ID_CUSTOM_SCORE_DOWN, GADGET_ID_CUSTOM_SCORE_UP, GADGET_ID_CUSTOM_SCORE_TEXT, GADGET_ID_NONE, &custom_element.collect_score, - NULL, "score", NULL + NULL, "score", " " }, { - ED_SETTINGS_XPOS(13) + 10, ED_SETTINGS_YPOS(3), + -1, ED_SETTINGS_YPOS(3), MIN_COLLECT_COUNT, MAX_COLLECT_COUNT, GADGET_ID_CUSTOM_GEMCOUNT_DOWN, GADGET_ID_CUSTOM_GEMCOUNT_UP, GADGET_ID_CUSTOM_GEMCOUNT_TEXT, GADGET_ID_CUSTOM_SCORE_UP, @@ -844,7 +901,7 @@ static struct NULL, "push delay", NULL }, { - ED_COUNT_PUSH_DELAY_RND_XPOS, ED_SETTINGS_YPOS(4), + -1, ED_SETTINGS_YPOS(4), 0, 999, GADGET_ID_PUSH_DELAY_RND_DOWN, GADGET_ID_PUSH_DELAY_RND_UP, GADGET_ID_PUSH_DELAY_RND_TEXT, GADGET_ID_PUSH_DELAY_FIX_UP, @@ -860,7 +917,7 @@ static struct NULL, "move delay", NULL }, { - ED_COUNT_MOVE_DELAY_RND_XPOS, ED_SETTINGS_YPOS(7), + -1, ED_SETTINGS_YPOS(7), 0, 999, GADGET_ID_MOVE_DELAY_RND_DOWN, GADGET_ID_MOVE_DELAY_RND_UP, GADGET_ID_MOVE_DELAY_RND_TEXT, GADGET_ID_MOVE_DELAY_FIX_UP, @@ -875,15 +932,15 @@ static struct 0, 999, GADGET_ID_CHANGE_DELAY_FIX_DOWN, GADGET_ID_CHANGE_DELAY_FIX_UP, GADGET_ID_CHANGE_DELAY_FIX_TEXT, GADGET_ID_NONE, - &custom_element.change.delay_fixed, + &custom_element_change.delay_fixed, NULL, "delay", NULL, }, { - ED_COUNT_CHANGE_DELAY_RND_XPOS+20, ED_SETTINGS_YPOS(3), + -1, ED_SETTINGS_YPOS(3), 0, 999, GADGET_ID_CHANGE_DELAY_RND_DOWN, GADGET_ID_CHANGE_DELAY_RND_UP, GADGET_ID_CHANGE_DELAY_RND_TEXT, GADGET_ID_CHANGE_DELAY_FIX_UP, - &custom_element.change.delay_random, + &custom_element_change.delay_random, NULL, "+random", NULL }, { @@ -891,7 +948,7 @@ static struct 0, 100, GADGET_ID_CHANGE_CONT_RND_DOWN, GADGET_ID_CHANGE_CONT_RND_UP, GADGET_ID_CHANGE_CONT_RND_TEXT, GADGET_ID_NONE, - &custom_element.change.random, + &custom_element_change.random, NULL, "use random change:", "(%)" }, }; @@ -902,7 +959,7 @@ static struct int gadget_id; int size; char *value; - char *infotext; + char *text_above, *infotext; } textinput_info[ED_NUM_TEXTINPUT] = { { @@ -910,21 +967,39 @@ static struct GADGET_ID_LEVEL_NAME, MAX_LEVEL_NAME_LEN, level.name, - "Title" + "Title:", "Title" }, { ED_SETTINGS_XPOS(0), ED_COUNTER_YPOS(1), GADGET_ID_LEVEL_AUTHOR, MAX_LEVEL_AUTHOR_LEN, level.author, - "Author" + "Author:", "Author" }, { 5 * MINI_TILEX, 5 * MINI_TILEY - ED_BORDER_SIZE, GADGET_ID_ELEMENT_NAME, MAX_ELEMENT_NAME_LEN - 2, /* currently 2 chars less editable */ custom_element.description, - "Element name" + NULL, "Element name" + } +}; + +static struct +{ + int x, y; + int gadget_id; + int xsize, ysize; + char *value; + char *text_above, *infotext; +} textarea_info[ED_NUM_TEXTAREAS] = +{ + { + ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(2), + GADGET_ID_ENVELOPE_INFO, + MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE, + level.envelope, + "Envelope Info:", "Envelope Info" } }; @@ -1028,7 +1103,7 @@ static struct ValueTextInfo options_consistency[] = static struct ValueTextInfo options_time_units[] = { - { 50, "seconds" }, + { FRAMES_PER_SECOND, "seconds" }, { 1, "frames" }, { -1, NULL } }; @@ -1071,6 +1146,12 @@ static struct ValueTextInfo options_change_power[] = { -1, NULL } }; +static char options_change_page_strings[MAX_CHANGE_PAGES][10]; +static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] = +{ + { -1, NULL } +}; + static struct { int x, y; @@ -1093,7 +1174,7 @@ static struct "player can", NULL, "type of access to this field" }, { - ED_SETTINGS_XPOS(11), ED_SETTINGS_YPOS(1), + -1, ED_SETTINGS_YPOS(1), GADGET_ID_CUSTOM_ACCESS_LAYER, GADGET_ID_CUSTOM_ACCESS_TYPE, -1, options_access_layer, @@ -1133,7 +1214,7 @@ static struct "move/fall speed", NULL, "speed of element movement" }, { - ED_SETTINGS_XPOS(7), ED_SETTINGS_YPOS(9), + -1, ED_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_SMASH_TARGETS, GADGET_ID_CUSTOM_CAN_SMASH, -1, options_smash_targets, @@ -1172,7 +1253,7 @@ static struct GADGET_ID_CHANGE_TIME_UNITS, GADGET_ID_NONE, -1, options_time_units, - &custom_element.change.delay_frames, + &custom_element_change.delay_frames, "delay time given in", NULL, "delay time units for change" }, { @@ -1180,7 +1261,7 @@ static struct GADGET_ID_CHANGE_PLAYER_ACTION, GADGET_ID_NONE, -1, options_change_player_action, - &custom_element.change_player_action, + &custom_element_change.player_action, NULL, "by player", "type of player contact" }, { @@ -1188,7 +1269,7 @@ static struct GADGET_ID_CHANGE_COLLIDE_ACTION, GADGET_ID_NONE, -1, options_change_collide_action, - &custom_element.change_collide_action, + &custom_element_change.collide_action, NULL, NULL, "change after impact or smash" }, { @@ -1196,7 +1277,7 @@ static struct GADGET_ID_CHANGE_OTHER_ACTION, GADGET_ID_NONE, -1, options_change_other_action, - &custom_element.change_other_action, + &custom_element_change.other_action, NULL, "element:", "type of other element action" }, { @@ -1204,9 +1285,17 @@ static struct GADGET_ID_CHANGE_POWER, GADGET_ID_NONE, -1, options_change_power, - &custom_element.change.power, + &custom_element_change.power, "power:", NULL, "power of extended change" }, + { + ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(14), + GADGET_ID_SELECT_CHANGE_PAGE, GADGET_ID_NONE, + 3, + options_change_page, + &custom_element.current_change_page, + NULL, NULL, "element config page" + }, }; static struct @@ -1215,28 +1304,71 @@ static struct int gadget_id; int gadget_id_align; int size; - char *text, *infotext; -} textbutton_info[ED_NUM_TEXTBUTTON] = + char *text; + char *text_left, *text_right, *infotext; +} textbutton_info[ED_NUM_TEXTBUTTONS] = { { ED_SETTINGS_XPOS(0), ED_COUNTER_YPOS(1), GADGET_ID_PROPERTIES_INFO, GADGET_ID_NONE, - 11, "Information", "Show information about element" + 11, "Information", + NULL, NULL, "Show information about element" }, { ED_SETTINGS_XPOS(0) + 166, ED_COUNTER_YPOS(1), GADGET_ID_PROPERTIES_CONFIG, GADGET_ID_NONE, - 11, "Configure", "Configure element properties" + 11, "Configure", + NULL, NULL, "Configure element properties" }, { ED_SETTINGS_XPOS(0) + 332, ED_COUNTER_YPOS(1), GADGET_ID_PROPERTIES_ADVANCED, GADGET_ID_NONE, - 11, "Advanced", "Advanced element configuration" + 11, "Advanced", + NULL, NULL, "Advanced element configuration" }, { - ED_SETTINGS_XPOS(0) + 262, ED_SETTINGS_YPOS(13), + -1, ED_SETTINGS_YPOS(13), GADGET_ID_SAVE_AS_TEMPLATE, GADGET_ID_CUSTOM_USE_TEMPLATE, - -1, "Save as template", "Save current settings as new template" + -1, "Save as template", + " ", NULL, "Save current settings as new template" + }, + { + -1, ED_SETTINGS_YPOS(14), + GADGET_ID_ADD_CHANGE_PAGE, GADGET_ID_NEXT_CHANGE_PAGE, + -1, "New", + " ", NULL, "Add new config page" + }, + { + -1, ED_SETTINGS_YPOS(14), + GADGET_ID_DEL_CHANGE_PAGE, GADGET_ID_ADD_CHANGE_PAGE, + -1, "Delete", + NULL, NULL, "Delete current config page" + }, +}; + +static struct +{ + int gd_x, gd_y; + int x, y; + int width, height; + int gadget_id; + int gadget_id_align; + char *text_left, *text_right, *infotext; +} graphicbutton_info[ED_NUM_GRAPHICBUTTONS] = +{ + { + ED_BUTTON_MINUS_XPOS, ED_BUTTON_COUNT_YPOS, + ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(14), + ED_BUTTON_COUNT_XSIZE, ED_BUTTON_COUNT_YSIZE, + GADGET_ID_PREV_CHANGE_PAGE, GADGET_ID_NONE, + NULL, NULL, "select previous config page" + }, + { + ED_BUTTON_PLUS_XPOS, ED_BUTTON_COUNT_YPOS, + -1, ED_SETTINGS_YPOS(14), + ED_BUTTON_COUNT_XSIZE, ED_BUTTON_COUNT_YSIZE, + GADGET_ID_NEXT_CHANGE_PAGE, GADGET_ID_SELECT_CHANGE_PAGE, + NULL, "config page", "select next config page" }, }; @@ -1280,10 +1412,10 @@ static struct }, { ED_SCROLLBUTTON2_XPOS, ED_SCROLLBUTTON2_YPOS + 1 * ED_SCROLLBUTTON2_YSIZE, - ED_SCROLL2_DOWN_XPOS, ED_SCROLL2_DOWN_YPOS, + ED_SCROLL2_DOWN_XPOS, ED_SCROLL2_DOWN_YPOS, GADGET_ID_SCROLL_LIST_DOWN, "scroll element list down ('Page Down')" - } + }, }; static struct @@ -1334,14 +1466,14 @@ static struct } radiobutton_info[ED_NUM_RADIOBUTTONS] = { { - ED_SETTINGS_XPOS(0) + 160, ED_COUNTER2_YPOS(8), + -1, ED_COUNTER2_YPOS(8), GADGET_ID_RANDOM_PERCENTAGE, GADGET_ID_LEVEL_RANDOM_UP, RADIO_NR_RANDOM_ELEMENTS, &random_placement_method, RANDOM_USE_PERCENTAGE, " ", "percentage", "use percentage for random elements" }, { - ED_SETTINGS_XPOS(0) + 340, ED_COUNTER2_YPOS(8), + -1, ED_COUNTER2_YPOS(8), GADGET_ID_RANDOM_QUANTITY, GADGET_ID_RANDOM_PERCENTAGE, RADIO_NR_RANDOM_ELEMENTS, &random_placement_method, RANDOM_USE_QUANTITY, @@ -1367,7 +1499,7 @@ static struct NULL, "double speed movement", "set movement speed of player" }, { - ED_SETTINGS_XPOS(0) + 340, ED_COUNTER_YPOS(6) - MINI_TILEY, + -1, ED_COUNTER_YPOS(6) - MINI_TILEY, GADGET_ID_GRAVITY, GADGET_ID_DOUBLE_SPEED, &level.gravity, " ", "gravity", "set level gravity" @@ -1424,7 +1556,7 @@ static struct NULL, "can fall", "element can fall down" }, { - ED_SETTINGS_XPOS(6), ED_SETTINGS_YPOS(9), + -1, ED_SETTINGS_YPOS(9), GADGET_ID_CUSTOM_CAN_SMASH, GADGET_ID_CUSTOM_CAN_FALL, &custom_element_properties[EP_CAN_SMASH], " ", NULL, "element can smash other elements" @@ -1454,13 +1586,13 @@ static struct NULL, "by fire", "element can explode by fire/explosion" }, { - ED_SETTINGS_XPOS(7), ED_SETTINGS_YPOS(13), + -1, ED_SETTINGS_YPOS(13), GADGET_ID_CUSTOM_EXPLODE_SMASH, GADGET_ID_CUSTOM_EXPLODE_FIRE, &custom_element.can_explode_smashed, " ", "smashed", "element can explode when smashed" }, { - ED_SETTINGS_XPOS(13), ED_SETTINGS_YPOS(13), + -1, ED_SETTINGS_YPOS(13), GADGET_ID_CUSTOM_EXPLODE_IMPACT, GADGET_ID_CUSTOM_EXPLODE_SMASH, &custom_element.can_explode_impact, " ", "impact", "element can explode on impact" @@ -1477,7 +1609,7 @@ static struct { ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(2), GADGET_ID_CUSTOM_CAN_CHANGE, GADGET_ID_NONE, - &custom_element_properties[EP_CAN_CHANGE], + &custom_element_change.can_change, NULL, "element changes to:", "element can change to other element" }, { @@ -1507,25 +1639,25 @@ static struct { ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(8), GADGET_ID_CHANGE_USE_EXPLOSION, GADGET_ID_NONE, - &custom_element.change.explode, + &custom_element_change.explode, NULL, "explode instead of change", "element explodes instead of change" }, { ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(9), GADGET_ID_CHANGE_USE_CONTENT, GADGET_ID_NONE, - &custom_element.change.use_content, + &custom_element_change.use_content, NULL, "use extended change target:","element changes to more elements" }, { ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(11), GADGET_ID_CHANGE_ONLY_COMPLETE, GADGET_ID_NONE, - &custom_element.change.only_complete, + &custom_element_change.only_complete, NULL, "only use complete change", "only use complete extended content" }, { ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(12), GADGET_ID_CHANGE_USE_RANDOM, GADGET_ID_NONE, - &custom_element.change.use_random_change, + &custom_element_change.use_random_change, NULL, NULL, "use random value for new content" }, { @@ -1617,7 +1749,7 @@ static struct /* ---------- custom graphic --------------------------------------------- */ { - ED_AREA_ELEM_CONTENT3_XPOS, ED_AREA_ELEM_CONTENT3_YPOS, + -1, ED_AREA_ELEM_CONTENT3_YPOS, 1, 1, GADGET_ID_CUSTOM_GRAPHIC, GADGET_ID_CUSTOM_USE_GRAPHIC, NULL, NULL, NULL @@ -1635,7 +1767,7 @@ static struct /* ---------- custom change target --------------------------------------- */ { - ED_AREA_ELEM_CONTENT2_XPOS, ED_AREA_ELEM_CONTENT2_YPOS, + -1, ED_AREA_ELEM_CONTENT2_YPOS, 1, 1, GADGET_ID_CUSTOM_CHANGE_TARGET, GADGET_ID_CUSTOM_CAN_CHANGE, NULL, "after/when:", NULL @@ -1653,7 +1785,7 @@ static struct /* ---------- custom change trigger (element causing change) ------------- */ { - ED_AREA_ELEM_CONTENT5_XPOS, ED_AREA_ELEM_CONTENT5_YPOS, + -1, ED_AREA_ELEM_CONTENT5_YPOS, 1, 1, GADGET_ID_CUSTOM_CHANGE_TRIGGER, GADGET_ID_CHANGE_OTHER_ACTION, NULL, NULL, NULL @@ -1662,7 +1794,7 @@ static struct /* ---------- random background (for random painting) -------------------- */ { - ED_AREA_RANDOM_BACKGROUND_XPOS, ED_AREA_RANDOM_BACKGROUND_YPOS, + -1, ED_AREA_RANDOM_BACKGROUND_YPOS, 1, 1, GADGET_ID_RANDOM_BACKGROUND, GADGET_ID_RANDOM_RESTRICTED, NULL, NULL, NULL @@ -1708,8 +1840,10 @@ static void CopyLevelToUndoBuffer(int); static void HandleDrawingAreas(struct GadgetInfo *); static void HandleCounterButtons(struct GadgetInfo *); static void HandleTextInputGadgets(struct GadgetInfo *); +static void HandleTextAreaGadgets(struct GadgetInfo *); static void HandleSelectboxGadgets(struct GadgetInfo *); static void HandleTextbuttonGadgets(struct GadgetInfo *); +static void HandleGraphicbuttonGadgets(struct GadgetInfo *); static void HandleRadiobuttons(struct GadgetInfo *); static void HandleCheckbuttons(struct GadgetInfo *); static void HandleControlButtons(struct GadgetInfo *); @@ -1733,7 +1867,7 @@ static int edit_mode_properties; static int element_shift = 0; -static int editor_el_boulderdash[] = +static int editor_hl_boulderdash[] = { EL_CHAR('B'), EL_CHAR('O'), @@ -1749,7 +1883,10 @@ static int editor_el_boulderdash[] = EL_CHAR('A'), EL_CHAR('S'), EL_CHAR('H'), +}; +static int editor_el_boulderdash[] = +{ EL_PLAYER_1, EL_EMPTY, EL_SAND, @@ -1775,9 +1912,10 @@ static int editor_el_boulderdash[] = EL_BD_FIREFLY_DOWN, EL_EMPTY, }; +static int num_editor_hl_boulderdash = SIZEOF_ARRAY_INT(editor_hl_boulderdash); static int num_editor_el_boulderdash = SIZEOF_ARRAY_INT(editor_el_boulderdash); -static int editor_el_emerald_mine[] = +static int editor_hl_emerald_mine[] = { EL_CHAR('E'), EL_CHAR('M'), @@ -1793,7 +1931,10 @@ static int editor_el_emerald_mine[] = EL_CHAR('I'), EL_CHAR('N'), EL_CHAR('E'), +}; +static int editor_el_emerald_mine[] = +{ EL_PLAYER_1, EL_PLAYER_2, EL_PLAYER_3, @@ -1869,15 +2010,19 @@ static int editor_el_emerald_mine[] = EL_EM_GATE_3_GRAY, EL_EM_GATE_4_GRAY, }; -static int num_editor_el_emerald_mine = SIZEOF_ARRAY_INT(editor_el_emerald_mine); +static int num_editor_hl_emerald_mine=SIZEOF_ARRAY_INT(editor_hl_emerald_mine); +static int num_editor_el_emerald_mine=SIZEOF_ARRAY_INT(editor_el_emerald_mine); -static int editor_el_more[] = +static int editor_hl_more[] = { EL_CHAR('M'), EL_CHAR('O'), EL_CHAR('R'), EL_CHAR('E'), +}; +static int editor_el_more[] = +{ EL_KEY_1, EL_KEY_2, EL_KEY_3, @@ -1973,9 +2118,10 @@ static int editor_el_more[] = EL_EMC_WALL_6, EL_EMC_WALL_7, }; +static int num_editor_hl_more = SIZEOF_ARRAY_INT(editor_hl_more); static int num_editor_el_more = SIZEOF_ARRAY_INT(editor_el_more); -static int editor_el_sokoban[] = +static int editor_hl_sokoban[] = { EL_CHAR('S'), EL_CHAR('O'), @@ -1986,15 +2132,19 @@ static int editor_el_sokoban[] = EL_CHAR('B'), EL_CHAR('A'), EL_CHAR('N'), +}; +static int editor_el_sokoban[] = +{ EL_SOKOBAN_OBJECT, EL_SOKOBAN_FIELD_EMPTY, EL_SOKOBAN_FIELD_FULL, EL_STEELWALL, }; +static int num_editor_hl_sokoban = SIZEOF_ARRAY_INT(editor_hl_sokoban); static int num_editor_el_sokoban = SIZEOF_ARRAY_INT(editor_el_sokoban); -static int editor_el_supaplex[] = +static int editor_hl_supaplex[] = { EL_CHAR('S'), EL_CHAR('U'), @@ -2005,7 +2155,10 @@ static int editor_el_supaplex[] = EL_CHAR('L'), EL_CHAR('E'), EL_CHAR('X'), +}; +static int editor_el_supaplex[] = +{ EL_SP_EMPTY, EL_SP_ZONK, EL_SP_BASE, @@ -2056,9 +2209,10 @@ static int editor_el_supaplex[] = EL_SP_CHIP_TOP, EL_SP_CHIP_BOTTOM, }; +static int num_editor_hl_supaplex = SIZEOF_ARRAY_INT(editor_hl_supaplex); static int num_editor_el_supaplex = SIZEOF_ARRAY_INT(editor_el_supaplex); -static int editor_el_diamond_caves[] = +static int editor_hl_diamond_caves[] = { EL_CHAR('D'), EL_CHAR('I'), @@ -2079,7 +2233,10 @@ static int editor_el_diamond_caves[] = EL_CHAR(' '), EL_CHAR('I'), EL_CHAR('I'), +}; +static int editor_el_diamond_caves[] = +{ EL_PEARL, EL_CRYSTAL, EL_WALL_PEARL, @@ -2140,9 +2297,10 @@ static int editor_el_diamond_caves[] = EL_EXTRA_TIME, EL_EMPTY, }; +static int num_editor_hl_diamond_caves = SIZEOF_ARRAY_INT(editor_hl_diamond_caves); static int num_editor_el_diamond_caves = SIZEOF_ARRAY_INT(editor_el_diamond_caves); -static int editor_el_dx_boulderdash[] = +static int editor_hl_dx_boulderdash[] = { EL_CHAR('D'), EL_CHAR('X'), @@ -2163,7 +2321,10 @@ static int editor_el_dx_boulderdash[] = EL_CHAR('A'), EL_CHAR('S'), EL_CHAR('H'), +}; +static int editor_el_dx_boulderdash[] = +{ EL_SPRING, EL_TUBE_RIGHT_DOWN, EL_TUBE_HORIZONTAL_DOWN, @@ -2184,15 +2345,19 @@ static int editor_el_dx_boulderdash[] = EL_EMPTY, EL_EMPTY }; +static int num_editor_hl_dx_boulderdash = SIZEOF_ARRAY_INT(editor_hl_dx_boulderdash); static int num_editor_el_dx_boulderdash = SIZEOF_ARRAY_INT(editor_el_dx_boulderdash); -static int editor_el_chars[] = +static int editor_hl_chars[] = { EL_CHAR('T'), EL_CHAR('E'), EL_CHAR('X'), EL_CHAR('T'), +}; +static int editor_el_chars[] = +{ EL_CHAR(' '), EL_CHAR('!'), EL_CHAR('"'), @@ -2283,9 +2448,10 @@ static int editor_el_chars[] = EL_CHAR(FONT_ASCII_CURSOR), EL_CHAR(' ') }; +static int num_editor_hl_chars = SIZEOF_ARRAY_INT(editor_hl_chars); static int num_editor_el_chars = SIZEOF_ARRAY_INT(editor_el_chars); -static int editor_el_custom[] = +static int editor_hl_custom[] = { EL_CHAR('C'), EL_CHAR('U'), @@ -2306,7 +2472,10 @@ static int editor_el_custom[] = EL_CHAR('N'), EL_CHAR('T'), EL_CHAR('S'), +}; +static int editor_el_custom[] = +{ EL_CUSTOM_START + 0, EL_CUSTOM_START + 1, EL_CUSTOM_START + 2, @@ -2467,8 +2636,13 @@ static int editor_el_custom[] = EL_CUSTOM_START + 126, EL_CUSTOM_START + 127 }; +static int num_editor_hl_custom = SIZEOF_ARRAY_INT(editor_hl_custom); static int num_editor_el_custom = SIZEOF_ARRAY_INT(editor_el_custom); +static int editor_hl_custom_more[] = +{ +}; + static int editor_el_custom_more[] = { EL_CUSTOM_START + 128, @@ -2631,6 +2805,7 @@ static int editor_el_custom_more[] = EL_CUSTOM_START + 254, EL_CUSTOM_START + 255 }; +static int num_editor_hl_custom_more = SIZEOF_ARRAY_INT(editor_hl_custom_more); static int num_editor_el_custom_more = SIZEOF_ARRAY_INT(editor_el_custom_more); static int *editor_elements = NULL; /* dynamically allocated */ @@ -2639,6 +2814,10 @@ static int num_editor_elements = 0; /* dynamically determined */ static struct { boolean *setup_value; + + int *headline_list; + int *headline_list_size; + int *element_list; int *element_list_size; @@ -2646,28 +2825,61 @@ static struct } editor_elements_info[] = { - { &setup.editor.el_boulderdash, editor_el_boulderdash, - &num_editor_el_boulderdash }, - { &setup.editor.el_emerald_mine, editor_el_emerald_mine, - &num_editor_el_emerald_mine }, - { &setup.editor.el_more, editor_el_more, - &num_editor_el_more }, - { &setup.editor.el_sokoban, editor_el_sokoban, - &num_editor_el_sokoban }, - { &setup.editor.el_supaplex, editor_el_supaplex, - &num_editor_el_supaplex }, - { &setup.editor.el_diamond_caves, editor_el_diamond_caves, - &num_editor_el_diamond_caves }, - { &setup.editor.el_dx_boulderdash, editor_el_dx_boulderdash, - &num_editor_el_dx_boulderdash }, - { &setup.editor.el_chars, editor_el_chars, - &num_editor_el_chars }, - { &setup.editor.el_custom, editor_el_custom, - &num_editor_el_custom }, - { &setup.editor.el_custom_more, editor_el_custom_more, - &num_editor_el_custom_more }, - { NULL, NULL, - NULL } + { + &setup.editor.el_boulderdash, + editor_hl_boulderdash, &num_editor_hl_boulderdash, + editor_el_boulderdash, &num_editor_el_boulderdash + }, + { + &setup.editor.el_emerald_mine, + editor_hl_emerald_mine, &num_editor_hl_emerald_mine, + editor_el_emerald_mine, &num_editor_el_emerald_mine + }, + { + &setup.editor.el_more, + editor_hl_more, &num_editor_hl_more, + editor_el_more, &num_editor_el_more + }, + { + &setup.editor.el_sokoban, + editor_hl_sokoban, &num_editor_hl_sokoban, + editor_el_sokoban, &num_editor_el_sokoban + }, + { + &setup.editor.el_supaplex, + editor_hl_supaplex, &num_editor_hl_supaplex, + editor_el_supaplex, &num_editor_el_supaplex + }, + { + &setup.editor.el_diamond_caves, + editor_hl_diamond_caves, &num_editor_hl_diamond_caves, + editor_el_diamond_caves, &num_editor_el_diamond_caves + }, + { + &setup.editor.el_dx_boulderdash, + editor_hl_dx_boulderdash, &num_editor_hl_dx_boulderdash, + editor_el_dx_boulderdash, &num_editor_el_dx_boulderdash + }, + { + &setup.editor.el_chars, + editor_hl_chars, &num_editor_hl_chars, + editor_el_chars, &num_editor_el_chars + }, + { + &setup.editor.el_custom, + editor_hl_custom, &num_editor_hl_custom, + editor_el_custom, &num_editor_el_custom + }, + { + &setup.editor.el_custom_more, + editor_hl_custom_more, &num_editor_hl_custom_more, + editor_el_custom_more, &num_editor_el_custom_more + }, + { + NULL, + NULL, NULL, + NULL, NULL + } }; @@ -2689,8 +2901,15 @@ static void ReinitializeElementList() /* determine size of element list */ for (i=0; editor_elements_info[i].setup_value != NULL; i++) + { if (*editor_elements_info[i].setup_value) + { + if (setup.editor.el_headlines) + num_editor_elements += *editor_elements_info[i].headline_list_size; + num_editor_elements += *editor_elements_info[i].element_list_size; + } + } if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS) { @@ -2705,9 +2924,17 @@ static void ReinitializeElementList() /* fill element list */ for (i=0; editor_elements_info[i].setup_value != NULL; i++) + { if (*editor_elements_info[i].setup_value) - for (j=0; j<*editor_elements_info[i].element_list_size; j++) + { + 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].element_list_size; j++) editor_elements[pos++] = editor_elements_info[i].element_list[j]; + } + } /* correct position of element list scrollbar */ if (element_shift < 0) @@ -2718,14 +2945,20 @@ static void ReinitializeElementList() static void ReinitializeElementListButtons() { + static boolean last_setup_value_headlines = FALSE; static boolean initialization_needed = TRUE; int i; if (!initialization_needed) /* check if editor element setup has changed */ + { + if (last_setup_value_headlines != setup.editor.el_headlines) + initialization_needed = TRUE; + 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; + } if (!initialization_needed) return; @@ -2734,6 +2967,7 @@ static void ReinitializeElementListButtons() CreateLevelEditorGadgets(); /* 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++) editor_elements_info[i].last_setup_value = *editor_elements_info[i].setup_value; @@ -2834,16 +3068,16 @@ static void DrawDrawingArea(int id) el2edimg(custom_element.content[x][y])); else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TARGET) DrawMiniGraphicExt(drawto, gi->x, gi->y, - el2edimg(custom_element.change.target_element)); + 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++) DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY, - el2edimg(custom_element.change.content[x][y])); + el2edimg(custom_element_change.content[x][y])); else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER) DrawMiniGraphicExt(drawto, gi->x, gi->y, - el2edimg(custom_element.change.trigger_element)); + el2edimg(custom_element_change.trigger_element)); else if (id >= ED_DRAWING_ID_ELEMENT_CONTENT_0 && id <= ED_DRAWING_ID_ELEMENT_CONTENT_7) { @@ -3221,7 +3455,7 @@ static void CreateCounterButtons() GDI_INFO_TEXT, "enter counter value", GDI_X, x, GDI_Y, y, - GDI_TYPE, GD_TYPE_TEXTINPUT_NUMERIC, + GDI_TYPE, GD_TYPE_TEXT_INPUT_NUMERIC, GDI_NUMBER_VALUE, 0, GDI_NUMBER_MIN, counterbutton_info[i].min_value, GDI_NUMBER_MAX, counterbutton_info[i].max_value, @@ -3325,7 +3559,7 @@ static void CreateTextInputGadgets() GDI_INFO_TEXT, infotext, GDI_X, SX + textinput_info[i].x, GDI_Y, SY + textinput_info[i].y, - GDI_TYPE, GD_TYPE_TEXTINPUT_ALPHANUMERIC, + GDI_TYPE, GD_TYPE_TEXT_INPUT_ALPHANUMERIC, GDI_TEXT_VALUE, textinput_info[i].value, GDI_TEXT_SIZE, textinput_info[i].size, GDI_TEXT_FONT, FONT_INPUT_1, @@ -3346,6 +3580,55 @@ static void CreateTextInputGadgets() } } +static void CreateTextAreaGadgets() +{ + int max_infotext_len = getMaxInfoTextLength(); + int i; + + for (i=0; ix - xoffset_left; + int x_right = gi->x + gi->width + xoffset_right; + int y = gi->y + yoffset; + + /* only show button to delete change pages when more than minimum pages */ + if (id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE && + custom_element.num_change_pages == MIN_CHANGE_PAGES) + return; + + if (textbutton_info[id].text_left) + DrawText(x_left, y, textbutton_info[id].text_left, FONT_TEXT_1); + + if (textbutton_info[id].text_right) + DrawText(x_right, y, textbutton_info[id].text_right, FONT_TEXT_1); + + MapGadget(gi); +} + +static void MapGraphicbuttonGadget(int id) +{ + struct GadgetInfo *gi= level_editor_gadget[graphicbutton_info[id].gadget_id]; + int xoffset_left = getTextWidthForGadget(graphicbutton_info[id].text_left); + int xoffset_right = ED_GADGET_TEXT_DISTANCE; + int yoffset = ED_BORDER_SIZE; + int x_left = gi->x - xoffset_left; + int x_right = gi->x + gi->width + xoffset_right; + int y = gi->y + yoffset; + + if (graphicbutton_info[id].text_left) + DrawText(x_left, y, graphicbutton_info[id].text_left, FONT_TEXT_1); + + if (graphicbutton_info[id].text_right) + DrawText(x_right, y, graphicbutton_info[id].text_right, FONT_TEXT_1); MapGadget(gi); } @@ -3873,19 +4266,12 @@ static void MapTextbuttonGadget(int id) static void MapRadiobuttonGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[radiobutton_info[id].gadget_id]; -#if 0 - int xoffset_right = ED_XOFFSET_CHECKBOX; - int yoffset_right = ED_BORDER_SIZE; - int x = radiobutton_info[id].x + xoffset_right; - int y = radiobutton_info[id].y + yoffset_right; -#else int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; -#endif boolean checked = (*radiobutton_info[id].value == radiobutton_info[id].checked_value); @@ -3903,19 +4289,12 @@ static void MapRadiobuttonGadget(int id) static void MapCheckbuttonGadget(int id) { struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id]; -#if 0 - int xoffset_right = ED_XOFFSET_CHECKBOX; - int yoffset_right = ED_BORDER_SIZE; - int x = checkbutton_info[id].x + xoffset_right; - int y = checkbutton_info[id].y + yoffset_right; -#else int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left); int xoffset_right = ED_GADGET_TEXT_DISTANCE; int yoffset = ED_BORDER_SIZE; int x_left = gi->x - xoffset_left; int x_right = gi->x + gi->width + xoffset_right; int y = gi->y + yoffset; -#endif /* special case needed for "sticky" gadget */ ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, @@ -4041,7 +4420,7 @@ static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY], dst[x][y] = src[x][y]; } -static int SetSelectboxValue(int selectbox_id, int new_value) +static int setSelectboxValue(int selectbox_id, int new_value) { int new_index_value = 0; int i; @@ -4059,15 +4438,32 @@ static int SetSelectboxValue(int selectbox_id, int new_value) 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++) + { + sprintf(options_change_page_strings[i], "%d", i + 1); + + options_change_page[i].value = i; + options_change_page[i].text = options_change_page_strings[i]; + } + + options_change_page[i].value = -1; + options_change_page[i].text = NULL; /* needed here to initialize combined element properties */ InitElementPropertiesEngine(level.game_version); + element_info[element].change = + &element_info[element].change_page[current_change_page]; + custom_element = element_info[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++) - SetSelectboxValue(i, *selectbox_info[i].value); + setSelectboxValue(i, *selectbox_info[i].value); for (i=0; i < NUM_ELEMENT_PROPERTIES; i++) custom_element_properties[i] = HAS_PROPERTY(element, i); @@ -4149,22 +4545,22 @@ static void CopyCustomElementPropertiesToEditor(int element) /* ---------- element settings: advanced (custom elements) --------------- */ /* set change by player selectbox help value */ - custom_element.change_player_action = + custom_element_change.player_action = (HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER : HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER : - custom_element.change_player_action); + custom_element_change.player_action); /* set change by collision selectbox help value */ - custom_element.change_collide_action = + custom_element_change.collide_action = (HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED : HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT : HAS_CHANGE_EVENT(element, CE_COLLISION) ? CE_COLLISION : - custom_element.change_collide_action); + custom_element_change.collide_action); /* set change by other element action selectbox help value */ - custom_element.change_other_action = + custom_element_change.other_action = (HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DROPPED) ? CE_OTHER_GETS_DROPPED : HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED : HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PUSHED) ? CE_OTHER_GETS_PUSHED : @@ -4173,7 +4569,7 @@ static void CopyCustomElementPropertiesToEditor(int element) HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING : HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING : HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING : - custom_element.change_other_action); + custom_element_change.other_action); } static void CopyCustomElementPropertiesToGame(int element) @@ -4201,6 +4597,7 @@ static void CopyCustomElementPropertiesToGame(int element) } element_info[element] = custom_element; + *element_info[element].change = custom_element_change; /* ---------- element settings: configure (custom elements) ------------- */ @@ -4268,14 +4665,14 @@ static void CopyCustomElementPropertiesToGame(int element) custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE; custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE; custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE; - custom_element_change_events[custom_element.change_player_action] = + custom_element_change_events[custom_element_change.player_action] = custom_element_change_events[CE_BY_PLAYER]; /* set collision change event from checkbox and selectbox */ custom_element_change_events[CE_COLLISION] = FALSE; custom_element_change_events[CE_IMPACT] = FALSE; custom_element_change_events[CE_SMASHED] = FALSE; - custom_element_change_events[custom_element.change_collide_action] = + custom_element_change_events[custom_element_change.collide_action] = custom_element_change_events[CE_BY_COLLISION]; /* set other element action change event from checkbox and selectbox */ @@ -4287,7 +4684,7 @@ static void CopyCustomElementPropertiesToGame(int element) custom_element_change_events[CE_OTHER_GETS_PUSHED] = FALSE; custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE; custom_element_change_events[CE_OTHER_GETS_DROPPED] = FALSE; - custom_element_change_events[custom_element.change_other_action] = + custom_element_change_events[custom_element_change.other_action] = custom_element_change_events[CE_BY_OTHER]; for (i=0; i < NUM_ELEMENT_PROPERTIES; i++) @@ -4298,6 +4695,7 @@ static void CopyCustomElementPropertiesToGame(int element) /* copy change events also to special level editor variable */ custom_element = element_info[element]; + custom_element_change = *element_info[element].change; } void DrawLevelEd() @@ -4471,7 +4869,7 @@ static void ModifyEditorCounter(int counter_id, int new_value) ModifyGadget(gi, GDI_NUMBER_VALUE, new_value, GDI_END); if (counter_value != NULL) - *counter_value = gi->text.number_value; + *counter_value = gi->textinput.number_value; } static void ModifyEditorCounterLimits(int counter_id, int min, int max) @@ -4486,7 +4884,7 @@ static void ModifyEditorSelectbox(int selectbox_id, int new_value) { int gadget_id = selectbox_info[selectbox_id].gadget_id; struct GadgetInfo *gi = level_editor_gadget[gadget_id]; - int new_index_value = SetSelectboxValue(selectbox_id, new_value); + int new_index_value = setSelectboxValue(selectbox_id, new_value); ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END); } @@ -4662,6 +5060,19 @@ static void DrawElementContentAreas() DrawText(x, y + 2 * MINI_TILEY, "smashed", FONT_TEXT_1); } +static void DrawEnvelopeTextArea() +{ + int id = ED_TEXTAREA_ID_ENVELOPE_INFO; + struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id]; + + UnmapGadget(gi); + DrawBackground(gi->x, gi->y, gi->width, gi->height); + + ModifyGadget(gi, GDI_AREA_SIZE, level.envelope_xsize, level.envelope_ysize, + GDI_END); + MapTextAreaGadget(ED_TEXTAREA_ID_ENVELOPE_INFO); +} + char *getElementDescriptionFilename(int element) { char *docs_dir = options.docs_directory; @@ -5069,7 +5480,8 @@ static boolean checkPropertiesConfig() if (IS_GEM(properties_element) || IS_CUSTOM_ELEMENT(properties_element) || - HAS_CONTENT(properties_element)) + HAS_CONTENT(properties_element) || + properties_element == EL_ENVELOPE) return TRUE; else for (i=0; elements_with_counter[i].element != -1; i++) @@ -5121,6 +5533,15 @@ static void DrawPropertiesConfig() if (IS_GEM(properties_element)) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS); + if (properties_element == EL_ENVELOPE) + { + /* display counter to choose size of envelope text area */ + MapCounterButtons(ED_COUNTER_ID_ENVELOPE_XSIZE); + MapCounterButtons(ED_COUNTER_ID_ENVELOPE_YSIZE); + + DrawEnvelopeTextArea(); + } + if (IS_CUSTOM_ELEMENT(properties_element)) { /* draw stickybutton gadget */ @@ -5183,7 +5604,13 @@ static void DrawPropertiesAdvanced() MapSelectboxGadget(i); /* draw textbutton gadgets */ - MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE); + for (i=ED_TEXTBUTTON_ID_CHANGE_FIRST; i<=ED_TEXTBUTTON_ID_CHANGE_LAST; i++) + MapTextbuttonGadget(i); + + /* draw graphicbutton gadgets */ + for (i = ED_GRAPHICBUTTON_ID_CHANGE_FIRST; + i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++) + MapGraphicbuttonGadget(i); /* draw drawing area gadgets */ DrawPropertiesAdvancedDrawingAreas(); @@ -6039,19 +6466,19 @@ static void HandleDrawingAreas(struct GadgetInfo *gi) } else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET) { - custom_element.change.target_element = new_element; + custom_element_change.target_element = new_element; CopyCustomElementPropertiesToGame(properties_element); } else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT) { - custom_element.change.content[sx][sy] = new_element; + custom_element_change.content[sx][sy] = new_element; CopyCustomElementPropertiesToGame(properties_element); } else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER) { - custom_element.change.trigger_element = new_element; + custom_element_change.trigger_element = new_element; CopyCustomElementPropertiesToGame(properties_element); } @@ -6166,11 +6593,11 @@ static void HandleDrawingAreas(struct GadgetInfo *gi) else if (id == GADGET_ID_CUSTOM_CONTENT) PickDrawingElement(button, custom_element.content[sx][sy]); else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET) - PickDrawingElement(button, custom_element.change.target_element); + PickDrawingElement(button, custom_element_change.target_element); else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT) - PickDrawingElement(button, custom_element.change.content[sx][sy]); + PickDrawingElement(button, custom_element_change.content[sx][sy]); else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER) - PickDrawingElement(button, custom_element.change.trigger_element); + PickDrawingElement(button, custom_element_change.trigger_element); else if (id == GADGET_ID_RANDOM_BACKGROUND) PickDrawingElement(button, random_placement_background_element); else if (id >= GADGET_ID_ELEMENT_CONTENT_0 && @@ -6216,7 +6643,7 @@ static void HandleCounterButtons(struct GadgetInfo *gi) } if (gadget_id == counterbutton_info[counter_id].gadget_id_text) - *counter_value = gi->text.number_value; + *counter_value = gi->textinput.number_value; else ModifyEditorCounter(counter_id, *counter_value + step); @@ -6226,6 +6653,11 @@ static void HandleCounterButtons(struct GadgetInfo *gi) DrawElementContentAreas(); break; + case ED_COUNTER_ID_ENVELOPE_XSIZE: + case ED_COUNTER_ID_ENVELOPE_YSIZE: + DrawEnvelopeTextArea(); + break; + case ED_COUNTER_ID_LEVEL_XSIZE: case ED_COUNTER_ID_LEVEL_YSIZE: lev_fieldx = level.fieldx; @@ -6254,7 +6686,7 @@ static void HandleTextInputGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; - strcpy(textinput_info[type_id].value, gi->text.value); + strcpy(textinput_info[type_id].value, gi->textinput.value); if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME) { @@ -6264,6 +6696,13 @@ static void HandleTextInputGadgets(struct GadgetInfo *gi) } } +static void HandleTextAreaGadgets(struct GadgetInfo *gi) +{ + int type_id = gi->custom_type_id; + + strcpy(textarea_info[type_id].value, gi->textarea.value); +} + static void HandleSelectboxGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; @@ -6271,19 +6710,26 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi) *selectbox_info[type_id].value = selectbox_info[type_id].options[gi->selectbox.index].value; - if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST && - type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) || - (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST && - type_id <= ED_SELECTBOX_ID_CHANGE_LAST)) + if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE) + { + element_info[properties_element].current_change_page = gi->selectbox.index; + + DrawPropertiesWindow(); + } + else if ((type_id >= ED_SELECTBOX_ID_CUSTOM_FIRST && + type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) || + (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST && + type_id <= ED_SELECTBOX_ID_CHANGE_LAST)) CopyCustomElementPropertiesToGame(properties_element); } static void HandleTextbuttonGadgets(struct GadgetInfo *gi) { int type_id = gi->custom_type_id; + int i; - if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_INFO && - type_id <= ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED) + if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_FIRST && + type_id <= ED_TEXTBUTTON_ID_PROPERTIES_LAST) { edit_mode_properties = gi->custom_type_id; @@ -6300,6 +6746,56 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi) if (new_template) Request("Tem- plate saved !", REQ_CONFIRM); } + else if (type_id == ED_TEXTBUTTON_ID_ADD_CHANGE_PAGE && + custom_element.num_change_pages < MAX_CHANGE_PAGES) + { + struct ElementInfo *ei = &element_info[properties_element]; + + setElementChangePages(ei, ei->num_change_pages + 1); + + /* set new change page to be new current change page */ + ei->current_change_page = ei->num_change_pages - 1; + ei->change = &ei->change_page[ei->current_change_page]; + + setElementChangeInfoToDefaults(ei->change); + + DrawPropertiesWindow(); + } + else if (type_id == ED_TEXTBUTTON_ID_DEL_CHANGE_PAGE && + custom_element.num_change_pages > MIN_CHANGE_PAGES) + { + struct ElementInfo *ei = &element_info[properties_element]; + + /* copy all change pages after change page to be deleted */ + for (i = ei->current_change_page; i < ei->num_change_pages - 1; i++) + ei->change_page[i] = ei->change_page[i + 1]; + + setElementChangePages(ei, ei->num_change_pages - 1); + + DrawPropertiesWindow(); + } +} + +static void HandleGraphicbuttonGadgets(struct GadgetInfo *gi) +{ + int type_id = gi->custom_type_id; + + if (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE || + type_id == ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE) + { + struct ElementInfo *ei = &element_info[properties_element]; + int step = BUTTON_STEPSIZE(gi->event.button); + + step *= (type_id == ED_GRAPHICBUTTON_ID_PREV_CHANGE_PAGE ? -1 : +1); + ei->current_change_page += step; + + if (ei->current_change_page < 0) + ei->current_change_page = 0; + else if (ei->current_change_page >= ei->num_change_pages) + ei->current_change_page = ei->num_change_pages - 1; + + DrawPropertiesWindow(); + } } static void HandleRadiobuttons(struct GadgetInfo *gi) @@ -6956,13 +7452,13 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi) getElementInfoText(custom_element.content[sx][sy])); else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET) DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s", - getElementInfoText(custom_element.change.target_element)); + getElementInfoText(custom_element_change.target_element)); else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT) DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s", - getElementInfoText(custom_element.change.content[sx][sy])); + getElementInfoText(custom_element_change.content[sx][sy])); else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER) DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s", - getElementInfoText(custom_element.change.trigger_element)); + getElementInfoText(custom_element_change.trigger_element)); else if (id == GADGET_ID_RANDOM_BACKGROUND) DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s", getElementInfoText(random_placement_background_element)); diff --git a/src/files.c b/src/files.c index e17ef526..4ef0174a 100644 --- a/src/files.c +++ b/src/files.c @@ -47,6 +47,56 @@ /* level file functions */ /* ========================================================================= */ +void setElementChangePages(struct ElementInfo *ei, int change_pages) +{ + int change_page_size = sizeof(struct ElementChangeInfo); + + ei->num_change_pages = MAX(1, change_pages); + + ei->change_page = + checked_realloc(ei->change_page, ei->num_change_pages * change_page_size); + + if (ei->current_change_page >= ei->num_change_pages) + ei->current_change_page = ei->num_change_pages - 1; + + ei->change = &ei->change_page[ei->current_change_page]; +} + +void setElementChangeInfoToDefaults(struct ElementChangeInfo *change) +{ + int x, y; + + change->can_change = FALSE; + + change->events = CE_BITMASK_DEFAULT; + change->target_element = EL_EMPTY_SPACE; + + change->delay_fixed = 0; + change->delay_random = 0; + change->delay_frames = -1; /* later set to reliable default value */ + + change->trigger_element = EL_EMPTY_SPACE; + + change->explode = FALSE; + change->use_content = FALSE; + change->only_complete = FALSE; + change->use_random_change = FALSE; + change->random = 0; + change->power = CP_NON_DESTRUCTIVE; + + for(x=0; x<3; x++) + for(y=0; y<3; y++) + change->content[x][y] = EL_EMPTY_SPACE; + + change->player_action = 0; + change->collide_action = 0; + change->other_action = 0; + + change->pre_change_function = NULL; + change->change_function = NULL; + change->post_change_function = NULL; +} + static void setLevelInfoToDefaults(struct LevelInfo *level) { int i, j, x, y; @@ -87,6 +137,10 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) strcpy(level->name, NAMELESS_LEVEL_NAME); strcpy(level->author, ANONYMOUS_NAME); + level->envelope[0] = '\0'; + level->envelope_xsize = MAX_ENVELOPE_XSIZE; + level->envelope_ysize = MAX_ENVELOPE_YSIZE; + for(i=0; iscore[i] = 10; @@ -100,11 +154,17 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) 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++) + { + setElementChangePages(&element_info[i], 1); + setElementChangeInfoToDefaults(element_info[i].change); + } + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; - for(j=0; jtarget_element = custom_target_element; else Error(ERR_WARN, "invalid custom element number %d", element); } @@ -515,29 +554,29 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level) element_info[element].content[x][y] = checkLevelElement(getFile16BitBE(file)); - element_info[element].change.events = getFile32BitBE(file); + element_info[element].change->events = getFile32BitBE(file); - element_info[element].change.target_element = + element_info[element].change->target_element = checkLevelElement(getFile16BitBE(file)); - element_info[element].change.delay_fixed = getFile16BitBE(file); - element_info[element].change.delay_random = getFile16BitBE(file); - element_info[element].change.delay_frames = getFile16BitBE(file); + element_info[element].change->delay_fixed = getFile16BitBE(file); + element_info[element].change->delay_random = getFile16BitBE(file); + element_info[element].change->delay_frames = getFile16BitBE(file); - element_info[element].change.trigger_element = + element_info[element].change->trigger_element = checkLevelElement(getFile16BitBE(file)); - element_info[element].change.explode = getFile8Bit(file); - element_info[element].change.use_content = getFile8Bit(file); - element_info[element].change.only_complete = getFile8Bit(file); - element_info[element].change.use_random_change = getFile8Bit(file); + element_info[element].change->explode = getFile8Bit(file); + element_info[element].change->use_content = getFile8Bit(file); + element_info[element].change->only_complete = getFile8Bit(file); + element_info[element].change->use_random_change = getFile8Bit(file); - element_info[element].change.random = getFile8Bit(file); - element_info[element].change.power = getFile8Bit(file); + element_info[element].change->random = getFile8Bit(file); + element_info[element].change->power = getFile8Bit(file); for(y=0; y<3; y++) for(x=0; x<3; x++) - element_info[element].change.content[x][y] = + element_info[element].change->content[x][y] = checkLevelElement(getFile16BitBE(file)); element_info[element].slippery_type = getFile8Bit(file); @@ -680,6 +719,170 @@ void LoadLevelFromFilename(struct LevelInfo *level, char *filename) fclose(file); } +#if 1 + +static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) +{ + if (leveldir_current == NULL) /* only when dumping level */ + return; + + /* determine correct game engine version of current level */ + if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) || + IS_LEVELCLASS_USER(leveldir_current)) + { +#if 0 + printf("\n::: This level is private or contributed: '%s'\n", filename); +#endif + + /* For user contributed and private levels, use the version of + the game engine the levels were created for. + Since 2.0.1, the game engine version is now directly stored + in the level file (chunk "VERS"), so there is no need anymore + to set the game version from the file version (except for old, + pre-2.0 levels, where the game version is still taken from the + file format version used to store the level -- see above). */ + + /* do some special adjustments to support older level versions */ + if (level->file_version == FILE_VERSION_1_0) + { + Error(ERR_WARN, "level file '%s'has version number 1.0", filename); + Error(ERR_WARN, "using high speed movement for player"); + + /* player was faster than monsters in (pre-)1.0 levels */ + level->double_speed = TRUE; + } + + /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */ + if (level->game_version == VERSION_IDENT(2,0,1)) + level->em_slippery_gems = TRUE; + } + else + { +#if 0 + printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n", + leveldir_current->sort_priority, filename); +#endif + + /* Always use the latest version of the game engine for all but + user contributed and private levels; this allows for actual + corrections in the game engine to take effect for existing, + converted levels (from "classic" or other existing games) to + make the game emulation more accurate, while (hopefully) not + breaking existing levels created from other players. */ + + level->game_version = GAME_VERSION_ACTUAL; + + /* Set special EM style gems behaviour: EM style gems slip down from + normal, steel and growing wall. As this is a more fundamental change, + it seems better to set the default behaviour to "off" (as it is more + natural) and make it configurable in the level editor (as a property + of gem style elements). Already existing converted levels (neither + private nor contributed levels) are changed to the new behaviour. */ + + if (level->file_version < FILE_VERSION_2_0) + level->em_slippery_gems = TRUE; + } +} + +static void LoadLevel_InitElements(struct LevelInfo *level, char *filename) +{ + int i, j; + + /* map custom element change events that have changed in newer versions + (these following values have accidentally changed in version 3.0.1) */ + if (level->game_version <= VERSION_IDENT(3,0,0)) + { + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + /* order of checking events to be mapped is important */ + for (j=CE_BY_OTHER; j >= CE_BY_PLAYER; j--) + { + if (HAS_CHANGE_EVENT(element, j - 2)) + { + SET_CHANGE_EVENT(element, j - 2, FALSE); + SET_CHANGE_EVENT(element, j, TRUE); + } + } + + /* order of checking events to be mapped is important */ + for (j=CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION; j--) + { + if (HAS_CHANGE_EVENT(element, j - 1)) + { + SET_CHANGE_EVENT(element, j - 1, FALSE); + SET_CHANGE_EVENT(element, j, TRUE); + } + } + } + } + + /* initialize "can_change" field for old levels with only one change page */ + if (level->game_version <= VERSION_IDENT(3,0,2)) + { + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + if (CAN_CHANGE(element)) + element_info[element].change->can_change = TRUE; + } + } + + /* initialize element properties for level editor etc. */ + InitElementPropertiesEngine(level->game_version); +} + +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(x=0; xfieldx; x++) + { + int element = level->field[x][y]; + + if (level->game_version <= VERSION_IDENT(2,2,0)) + { + /* map game font elements */ + element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT : + element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT : + element == EL_CHAR(']') ? EL_CHAR_UUMLAUT : + element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element); + } + + if (level->game_version < VERSION_IDENT(3,0,0)) + { + /* map Supaplex gravity tube elements */ + element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT : + element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT : + element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP : + element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN : + element); + } + + level->field[x][y] = element; + } + } + + /* copy elements to runtime playfield array */ + for(x=0; xfield[x][y]; + + /* initialize level size variables for faster access */ + lev_fieldx = level->fieldx; + lev_fieldy = level->fieldy; + + /* determine border element for this level */ + SetBorderElement(); +} + +#else + static void LoadLevel_InitLevel(struct LevelInfo *level, char *filename) { int i, j, x, y; @@ -804,6 +1007,18 @@ static void LoadLevel_InitLevel(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)) + { + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + int element = EL_CUSTOM_START + i; + + if (CAN_CHANGE(element)) + element_info[element].change->can_change = TRUE; + } + } + /* copy elements to runtime playfield array */ for(x=0; xgame_version); } +#endif + void LoadLevelTemplate(int level_nr) { char *filename = getLevelFilename(level_nr); LoadLevelFromFilename(&level_template, filename); + LoadLevel_InitVersion(&level, filename); + LoadLevel_InitElements(&level, filename); + ActivateLevelTemplate(); } @@ -838,7 +1058,13 @@ void LoadLevel(int level_nr) if (level.use_custom_template) LoadLevelTemplate(-1); +#if 1 + LoadLevel_InitVersion(&level, filename); + LoadLevel_InitElements(&level, filename); + LoadLevel_InitPlayfield(&level, filename); +#else LoadLevel_InitLevel(&level, filename); +#endif } static void SaveLevel_VERS(FILE *file, struct LevelInfo *level) @@ -1015,12 +1241,12 @@ static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level, { int element = EL_CUSTOM_START + i; - if (element_info[element].change.target_element != EL_EMPTY_SPACE) + if (element_info[element].change->target_element != EL_EMPTY_SPACE) { if (check < num_changed_custom_elements) { putFile16BitBE(file, element); - putFile16BitBE(file, element_info[element].change.target_element); + putFile16BitBE(file, element_info[element].change->target_element); } check++; @@ -1076,27 +1302,27 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level, for(x=0; x<3; x++) putFile16BitBE(file, element_info[element].content[x][y]); - putFile32BitBE(file, element_info[element].change.events); + putFile32BitBE(file, element_info[element].change->events); - putFile16BitBE(file, element_info[element].change.target_element); + putFile16BitBE(file, element_info[element].change->target_element); - putFile16BitBE(file, element_info[element].change.delay_fixed); - putFile16BitBE(file, element_info[element].change.delay_random); - putFile16BitBE(file, element_info[element].change.delay_frames); + putFile16BitBE(file, element_info[element].change->delay_fixed); + putFile16BitBE(file, element_info[element].change->delay_random); + putFile16BitBE(file, element_info[element].change->delay_frames); - putFile16BitBE(file, element_info[element].change.trigger_element); + putFile16BitBE(file, element_info[element].change->trigger_element); - putFile8Bit(file, element_info[element].change.explode); - putFile8Bit(file, element_info[element].change.use_content); - putFile8Bit(file, element_info[element].change.only_complete); - putFile8Bit(file, element_info[element].change.use_random_change); + putFile8Bit(file, element_info[element].change->explode); + putFile8Bit(file, element_info[element].change->use_content); + putFile8Bit(file, element_info[element].change->only_complete); + putFile8Bit(file, element_info[element].change->use_random_change); - putFile8Bit(file, element_info[element].change.random); - putFile8Bit(file, element_info[element].change.power); + 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++) - putFile16BitBE(file, element_info[element].change.content[x][y]); + putFile16BitBE(file, element_info[element].change->content[x][y]); putFile8Bit(file, element_info[element].slippery_type); @@ -1839,8 +2065,9 @@ void SaveScore(int level_nr) #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 6 #define SETUP_TOKEN_EDITOR_EL_CHARS 7 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 8 +#define SETUP_TOKEN_EDITOR_EL_HEADLINES 9 -#define NUM_EDITOR_SETUP_TOKENS 9 +#define NUM_EDITOR_SETUP_TOKENS 10 /* shortcut setup */ #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0 @@ -1926,6 +2153,7 @@ static struct TokenInfo editor_setup_tokens[] = { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" }, { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" }, { TYPE_SWITCH, &sei.el_custom_more, "editor.el_custom_more" }, + { TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" }, }; static struct TokenInfo shortcut_setup_tokens[] = @@ -2023,6 +2251,8 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->editor.el_custom = TRUE; si->editor.el_custom_more = FALSE; + si->editor.el_headlines = TRUE; + si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME; si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME; si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE; diff --git a/src/files.h b/src/files.h index 5f5f67dc..1ae371db 100644 --- a/src/files.h +++ b/src/files.h @@ -16,6 +16,9 @@ #include "main.h" +void setElementChangePages(struct ElementInfo *, int); +void setElementChangeInfoToDefaults(struct ElementChangeInfo *); + boolean LevelFileExists(int); void LoadLevelFromFilename(struct LevelInfo *, char *); void LoadLevel(int); diff --git a/src/game.c b/src/game.c index 7b3017e9..184a258f 100644 --- a/src/game.c +++ b/src/game.c @@ -171,7 +171,6 @@ static void TestIfElementTouchesCustomElement(int, int); static boolean CheckTriggeredElementChange(int, int, int, int); static boolean CheckElementChange(int, int, int, int); -static void ChangeElementNow(int, int, int); static void PlaySoundLevel(int, int, int); static void PlaySoundLevelNearest(int, int, int); @@ -216,7 +215,7 @@ struct ChangingElementInfo void (*post_change_function)(int x, int y); }; -static struct ChangingElementInfo changing_element_list[] = +static struct ChangingElementInfo change_delay_list[] = { { EL_NUT_BREAKING, @@ -415,14 +414,16 @@ collect_count_list[] = { EL_UNDEFINED, 0 }, }; -static boolean changing_element[MAX_NUM_ELEMENTS]; static unsigned long trigger_events[MAX_NUM_ELEMENTS]; -#define IS_AUTO_CHANGING(e) (changing_element[e]) +#define IS_AUTO_CHANGING(e) (element_info[e].change_events & \ + CH_EVENT_BIT(CE_DELAY)) #define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0) #define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \ IS_JUST_CHANGING(x, y)) +#define CE_PAGE(e, ce) (element_info[e].event_page[ce]) + void GetPlayerConfig() { @@ -742,7 +743,7 @@ void DrawGameDoorValues() static void InitGameEngine() { - int i; + int i, j, k; /* set game engine from tape file when re-playing, else from level file */ game.engine_version = (tape.playing ? tape.engine_version : @@ -773,78 +774,82 @@ static void InitGameEngine() /* ---------- initialize changing elements ------------------------------- */ /* initialize changing elements information */ - for (i=0; ichange = &ei->change_page[0]; if (!IS_CUSTOM_ELEMENT(i)) { - element_info[i].change.target_element = EL_EMPTY_SPACE; - element_info[i].change.delay_fixed = 0; - element_info[i].change.delay_random = 0; - element_info[i].change.delay_frames = 1; + ei->change->target_element = EL_EMPTY_SPACE; + ei->change->delay_fixed = 0; + ei->change->delay_random = 0; + ei->change->delay_frames = 1; } - changing_element[i] = FALSE; -#else - changing_element[i].base_element = EL_UNDEFINED; - changing_element[i].next_element = EL_UNDEFINED; - changing_element[i].change_delay = -1; - changing_element[i].pre_change_function = NULL; - changing_element[i].change_function = NULL; - changing_element[i].post_change_function = NULL; -#endif + ei->change_events = CE_BITMASK_DEFAULT; + for (j=0; j < NUM_CHANGE_EVENTS; j++) + { + ei->event_page_num[j] = 0; + ei->event_page[j] = &ei->change_page[0]; + } } /* add changing elements from pre-defined list */ - for (i=0; changing_element_list[i].element != EL_UNDEFINED; i++) + for (i=0; change_delay_list[i].element != EL_UNDEFINED; i++) { - int element = changing_element_list[i].element; - struct ChangingElementInfo *ce = &changing_element_list[i]; - struct ElementChangeInfo *change = &element_info[element].change; + struct ChangingElementInfo *ch_delay = &change_delay_list[i]; + struct ElementInfo *ei = &element_info[ch_delay->element]; + + ei->change->target_element = ch_delay->target_element; + ei->change->delay_fixed = ch_delay->change_delay; + + ei->change->pre_change_function = ch_delay->pre_change_function; + ei->change->change_function = ch_delay->change_function; + ei->change->post_change_function = ch_delay->post_change_function; + + ei->change_events |= CH_EVENT_BIT(CE_DELAY); + } #if 1 - change->target_element = ce->target_element; - change->delay_fixed = ce->change_delay; - change->pre_change_function = ce->pre_change_function; - change->change_function = ce->change_function; - change->post_change_function = ce->post_change_function; + /* add change events from custom element configuration */ + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i]; - changing_element[element] = TRUE; -#else - changing_element[element].base_element = ce->base_element; - changing_element[element].next_element = ce->next_element; - changing_element[element].change_delay = ce->change_delay; - changing_element[element].pre_change_function = ce->pre_change_function; - changing_element[element].change_function = ce->change_function; - changing_element[element].post_change_function = ce->post_change_function; -#endif + 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++) + { + /* only add event page for the first page found with this event */ + if (ei->change_page[j].events & CH_EVENT_BIT(k) && + !(ei->change_events & CH_EVENT_BIT(k))) + { + ei->change_events |= CH_EVENT_BIT(k); + ei->event_page_num[k] = j; + ei->event_page[k] = &ei->change_page[j]; + } + } + } } - /* add changing elements from custom element configuration */ +#else + + /* add change events from custom element configuration */ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) { int element = EL_CUSTOM_START + i; -#if 0 - struct ElementChangeInfo *change = &element_info[element].change; -#endif /* only add custom elements that change after fixed/random frame delay */ - if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, CE_DELAY)) - continue; - -#if 1 - changing_element[element] = TRUE; -#else - changing_element[element].base_element = element; - changing_element[element].next_element = change->target_element; - changing_element[element].change_delay = (change->delay_fixed * - change->delay_frames); -#endif + if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY)) + element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY); } +#endif /* ---------- initialize trigger events ---------------------------------- */ @@ -852,11 +857,32 @@ static void InitGameEngine() for (i=0; inum_change_pages; j++) + { + if (!ei->change_page->can_change) + continue; + + if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER)) + { + int trigger_element = ei->change_page[j].trigger_element; + + trigger_events[trigger_element] |= ei->change_page[j].events; + } + } + } +#else /* add trigger events from element change event properties */ for (i=0; itrigger_element] |= + element_info[i].change->events; +#endif /* ---------- initialize push delay -------------------------------------- */ @@ -1236,16 +1262,19 @@ void InitGame() if (CAN_CHANGE(element)) { - content = element_info[element].change.target_element; - is_player = ELEM_IS_PLAYER(content); - - if (is_player && (found_rating < 3 || element < found_element)) + for (i=0; i < element_info[element].num_change_pages; i++) { - start_x = x; - start_y = y; + content = element_info[element].change_page[i].target_element; + is_player = ELEM_IS_PLAYER(content); - found_rating = 3; - found_element = element; + if (is_player && (found_rating < 3 || element < found_element)) + { + start_x = x; + start_y = y; + + found_rating = 3; + found_element = element; + } } } @@ -1266,16 +1295,19 @@ void InitGame() if (!CAN_CHANGE(element)) continue; - content = element_info[element].change.content[xx][yy]; - is_player = ELEM_IS_PLAYER(content); - - if (is_player && (found_rating < 1 || element < found_element)) + for (i=0; i < element_info[element].num_change_pages; i++) { - start_x = x + xx - 1; - start_y = y + yy - 1; + content = element_info[element].change_page[i].content[xx][yy]; + is_player = ELEM_IS_PLAYER(content); - found_rating = 1; - found_element = element; + if (is_player && (found_rating < 1 || element < found_element)) + { + start_x = x + xx - 1; + start_y = y + yy - 1; + + found_rating = 1; + found_element = element; + } } } } @@ -2865,24 +2897,12 @@ void Impact(int x, int y) PlaySoundLevel(x, y, SND_PEARL_BREAKING); return; } -#if 1 else if (impact && CheckElementChange(x, y, element, CE_IMPACT)) { PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT); return; } -#else - else if (impact && CAN_CHANGE(element) && - HAS_CHANGE_EVENT(element, CE_IMPACT)) - { - PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT); - - ChangeElementNow(x, y, element); - - return; - } -#endif if (impact && element == EL_AMOEBA_DROP) { @@ -3014,17 +3034,10 @@ void Impact(int x, int y) { ToggleLightSwitch(x, y + 1); } -#if 1 else { CheckElementChange(x, y + 1, smashed, CE_SMASHED); } -#else - else if (CAN_CHANGE(smashed) && HAS_CHANGE_EVENT(smashed, CE_SMASHED)) - { - ChangeElementNow(x, y + 1, smashed); - } -#endif } else { @@ -5314,7 +5327,7 @@ static void ChangeElementNowExt(int x, int y, int target_element) { /* check if element under player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ - if (IS_PLAYER(x, y) && + if (IS_PLAYER(x, y) && !PLAYER_PROTECTED(x, y) && IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element)) { Bang(x, y); @@ -5344,26 +5357,12 @@ static void ChangeElementNowExt(int x, int y, int target_element) RelocatePlayer(x, y, target_element); } -static void ChangeElementNow(int x, int y, int element) +static void ChangeElementNow(int x, int y, int element, int page) { - struct ElementChangeInfo *change = &element_info[element].change; - -#if 0 - if (element >= EL_CUSTOM_START + 17 && element <= EL_CUSTOM_START + 39) - printf("::: changing... [%d]\n", FrameCounter); -#endif - -#if 0 - /* prevent CheckTriggeredElementChange() from looping */ - Changing[x][y] = TRUE; -#endif + struct ElementChangeInfo *change = &element_info[element].change_page[page]; CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING); -#if 0 - Changing[x][y] = FALSE; -#endif - if (change->explode) { Bang(x, y); @@ -5460,42 +5459,21 @@ static void ChangeElementNow(int x, int y, int element) } } -static void ChangeElement(int x, int y) +static void ChangeElement(int x, int y, int page) { -#if 1 int element = MovingOrBlocked2Element(x, y); -#else - int element = Feld[x][y]; -#endif - struct ElementChangeInfo *change = &element_info[element].change; + struct ElementChangeInfo *change = &element_info[element].change_page[page]; if (ChangeDelay[x][y] == 0) /* initialize element change */ { -#if 1 ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames + RND(change->delay_random * change->delay_frames)) + 1; -#else - ChangeDelay[x][y] = changing_element[element].change_delay + 1; - - if (IS_CUSTOM_ELEMENT(element) && HAS_CHANGE_EVENT(element, CE_DELAY)) - { - int max_random_delay = element_info[element].change.delay_random; - int delay_frames = element_info[element].change.delay_frames; - - ChangeDelay[x][y] += RND(max_random_delay * delay_frames); - } -#endif ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); -#if 1 if (change->pre_change_function) change->pre_change_function(x, y); -#else - if (changing_element[element].pre_change_function) - changing_element[element].pre_change_function(x, y); -#endif } ChangeDelay[x][y]--; @@ -5507,20 +5485,11 @@ static void ChangeElement(int x, int y) if (IS_ANIMATED(graphic)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); -#if 1 if (change->change_function) change->change_function(x, y); -#else - if (changing_element[element].change_function) - changing_element[element].change_function(x, y); -#endif } else /* finish element change */ { -#if 0 - int next_element = changing_element[element].next_element; -#endif - if (IS_MOVING(x, y)) /* never change a running system ;-) */ { ChangeDelay[x][y] = 1; /* try change after next move step */ @@ -5528,27 +5497,17 @@ static void ChangeElement(int x, int y) return; } -#if 1 - ChangeElementNow(x, y, element); + ChangeElementNow(x, y, element, page); if (change->post_change_function) change->post_change_function(x, y); -#else - if (next_element != EL_UNDEFINED) - ChangeElementNow(x, y, next_element); - else - ChangeElementNow(x, y, element_info[element].change.target_element); - - if (changing_element[element].post_change_function) - changing_element[element].post_change_function(x, y); -#endif } } static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, int trigger_event) { - int i, x, y; + int i, j, x, y; if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event))) return FALSE; @@ -5557,12 +5516,40 @@ static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element, if (trigger_event == CE_OTHER_IS_CHANGING) Changing[lx][ly] = TRUE; - for (i=0; itrigger_element != trigger_element) + continue; +#endif + for (y=0; yMovPos == 0) - { -#if 0 - printf("Trying... Player frame reset\n"); -#endif - InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir); - } if (player->MovPos == 0) /* needed for tape.playing */ player->is_moving = FALSE; @@ -5871,7 +5860,7 @@ void GameActions() /* this may take place after moving, so 'element' may have changed */ if (IS_CHANGING(x, y)) { - ChangeElement(x, y); + ChangeElement(x, y, element_info[element].event_page_num[CE_DELAY]); element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]); } @@ -6710,8 +6699,9 @@ void TestIfElementTouchesCustomElement(int x, int y) { 0, +1 } }; boolean change_center_element = FALSE; + int center_element_change_page = 0; int center_element = Feld[x][y]; - int i; + int i, j; if (check_changing) /* prevent this function from running into a loop */ return; @@ -6731,17 +6721,47 @@ void TestIfElementTouchesCustomElement(int x, int y) /* check for change of center element (but change it only once) */ if (IS_CUSTOM_ELEMENT(center_element) && - border_element == element_info[center_element].change.trigger_element) - change_center_element = TRUE; + 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++) + { + struct ElementChangeInfo *change = + &element_info[center_element].change_page[j]; + + if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && + change->trigger_element == border_element) + { + change_center_element = TRUE; + center_element_change_page = j; + + break; + } + } + } /* check for change of border element */ if (IS_CUSTOM_ELEMENT(border_element) && - center_element == element_info[border_element].change.trigger_element) - CheckElementChange(xx, yy, border_element, CE_OTHER_IS_TOUCHING); + HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING)) + { + for (j=0; j < element_info[border_element].num_change_pages; j++) + { + struct ElementChangeInfo *change = + &element_info[border_element].change_page[j]; + + if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) && + change->trigger_element == center_element) + { + CheckElementChangeExt(xx,yy, border_element,CE_OTHER_IS_TOUCHING, j); + break; + } + } + } } if (change_center_element) - CheckElementChange(x, y, center_element, CE_OTHER_IS_TOUCHING); + CheckElementChangeExt(x, y, center_element, CE_OTHER_IS_TOUCHING, + center_element_change_page); check_changing = FALSE; } diff --git a/src/init.c b/src/init.c index c129a676..86b4ecae 100644 --- a/src/init.c +++ b/src/init.c @@ -2829,6 +2829,12 @@ void InitElementPropertiesEngine(int engine_version) element_info[i].token_name, element_info[i].crumbled[ACTION_DEFAULT]); #endif + + /* ---------- CAN_CHANGE ----------------------------------------------- */ + SET_PROPERTY(i, EP_CAN_CHANGE, FALSE); /* default: cannot change */ + 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); } #if 0 diff --git a/src/libgame/gadgets.c b/src/libgame/gadgets.c index 7b704120..aacadafa 100644 --- a/src/libgame/gadgets.c +++ b/src/libgame/gadgets.c @@ -105,6 +105,67 @@ static struct GadgetInfo *getGadgetInfoFromMousePosition(int mx, int my) return NULL; } +static void setTextAreaCursorExt(struct GadgetInfo *gi, boolean set_cursor_pos) +{ + char *text = gi->textarea.value; + int area_xsize = gi->textarea.xsize; + int area_ysize = gi->textarea.ysize; + int cursor_position = gi->textarea.cursor_position; + int cursor_x = gi->textarea.cursor_x; + int cursor_y = gi->textarea.cursor_y; + int pos = 0; + int x = 0; + int y = 0; + + while (*text) + { + if (set_cursor_pos) /* x/y => position */ + { + if (y == cursor_y && (x == cursor_x || (x < cursor_x && *text == '\n'))) + break; + } + else /* position => x/y */ + { + if (pos == cursor_position) + break; + } + + if (x + 1 >= area_xsize || *text == '\n') + { + if (y + 1 >= area_ysize) + break; + + x = 0; + y++; + } + else + x++; + + text++; + pos++; + } + + gi->textarea.cursor_x = x; + gi->textarea.cursor_y = y; + gi->textarea.cursor_x_preferred = x; + gi->textarea.cursor_position = pos; +} + +static void setTextAreaCursorXY(struct GadgetInfo *gi, int x, int y) +{ + gi->textarea.cursor_x = x; + gi->textarea.cursor_y = y; + + setTextAreaCursorExt(gi, TRUE); +} + +static void setTextAreaCursorPosition(struct GadgetInfo *gi, int pos) +{ + gi->textarea.cursor_position = pos; + + setTextAreaCursorExt(gi, FALSE); +} + static void default_callback_info(void *ptr) { return; @@ -173,8 +234,8 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) } break; - case GD_TYPE_TEXTINPUT_ALPHANUMERIC: - case GD_TYPE_TEXTINPUT_NUMERIC: + case GD_TYPE_TEXT_INPUT_ALPHANUMERIC: + case GD_TYPE_TEXT_INPUT_NUMERIC: { int i; char cursor_letter; @@ -190,7 +251,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) border_x, gi->height, gi->x, gi->y); /* middle part of gadget */ - for (i=0; i < gi->text.size + 1; i++) + for (i=0; i < gi->textinput.size + 1; i++) BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, font_width, gi->height, gi->x + border_x + i * font_width, gi->y); @@ -202,7 +263,7 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) gi->x + gi->width - border_x, gi->y); /* set text value */ - strcpy(text, gi->text.value); + strcpy(text, gi->textinput.value); strcat(text, " "); /* gadget text value */ @@ -210,19 +271,110 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) gi->x + border_x, gi->y + border_y, text, font_nr, BLIT_MASKED); - cursor_letter = gi->text.value[gi->text.cursor_position]; + cursor_letter = gi->textinput.value[gi->textinput.cursor_position]; cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); cursor_string[1] = '\0'; /* draw cursor, if active */ if (pressed) DrawTextExt(drawto, - gi->x + border_x + gi->text.cursor_position * font_width, + gi->x + border_x + + gi->textinput.cursor_position * font_width, gi->y + border_y, cursor_string, font_nr, BLIT_INVERSE); } break; + case GD_TYPE_TEXT_AREA: + { + int i; + char cursor_letter; + char cursor_string[2]; + int font_nr = (pressed ? gi->font_active : gi->font); + int font_width = getFontWidth(font_nr); + int font_height = getFontHeight(font_nr); + int border_x = gi->border.xsize; + int border_y = gi->border.ysize; + int gd_height = 2 * border_y + font_height; + + /* top left part of gadget border */ + BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y, + border_x, border_y, gi->x, gi->y); + + /* top middle part of gadget border */ + for (i=0; i < gi->textarea.xsize; i++) + BlitBitmapOnBackground(gd->bitmap, drawto, gd->x + border_x, gd->y, + font_width, border_y, + gi->x + border_x + i * font_width, gi->y); + + /* top right part of gadget border */ + BlitBitmapOnBackground(gd->bitmap, drawto, + gd->x + gi->border.width - border_x, gd->y, + border_x, border_y, + gi->x + gi->width - border_x, gi->y); + + /* left and right part of gadget border for each row */ + for (i=0; i < gi->textarea.ysize; i++) + { + BlitBitmapOnBackground(gd->bitmap, drawto, gd->x, gd->y + border_y, + border_x, font_height, + gi->x, gi->y + border_y + i * font_height); + BlitBitmapOnBackground(gd->bitmap, drawto, + gd->x + gi->border.width - border_x, + gd->y + border_y, + border_x, font_height, + gi->x + gi->width - border_x, + gi->y + border_y + i * font_height); + } + + /* bottom left part of gadget border */ + BlitBitmapOnBackground(gd->bitmap, drawto, + gd->x, gd->y + gd_height - border_y, + border_x, border_y, + gi->x, gi->y + gi->height - border_y); + + /* bottom middle part of gadget border */ + for (i=0; i < gi->textarea.xsize; i++) + BlitBitmapOnBackground(gd->bitmap, drawto, + gd->x + border_x, + gd->y + gd_height - border_y, + font_width, border_y, + gi->x + border_x + i * font_width, + gi->y + gi->height - border_y); + + /* bottom right part of gadget border */ + BlitBitmapOnBackground(gd->bitmap, drawto, + gd->x + gi->border.width - border_x, + gd->y + gd_height - border_y, + border_x, border_y, + gi->x + gi->width - border_x, + gi->y + gi->height - border_y); + + ClearRectangleOnBackground(drawto, + gi->x + border_x, + gi->y + border_y, + gi->width - 2 * border_x, + gi->height - 2 * border_y); + + /* gadget text value */ + DrawTextToTextArea(gi->x + border_x, gi->y + border_y, + gi->textarea.value, font_nr, + gi->textarea.xsize, gi->textarea.ysize); + + cursor_letter = gi->textarea.value[gi->textarea.cursor_position]; + cursor_string[0] = (cursor_letter != '\0' ? cursor_letter : ' '); + cursor_string[1] = '\0'; + + /* draw cursor, if active */ + if (pressed) + DrawTextExt(drawto, + gi->x + border_x + gi->textarea.cursor_x * font_width, + gi->y + border_y + gi->textarea.cursor_y * font_height, + cursor_string, + font_nr, BLIT_INVERSE); + } + break; + case GD_TYPE_SELECTBOX: { int i; @@ -367,7 +519,10 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) /* selectbox text values */ for (i=0; i < gi->selectbox.num_values; i++) { - int mask_mode; + int mask_mode = BLIT_MASKED; + + strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size); + text[gi->selectbox.size] = '\0'; if (i == gi->selectbox.current_index) { @@ -377,17 +532,11 @@ static void DrawGadget(struct GadgetInfo *gi, boolean pressed, boolean direct) gi->selectbox.width - 2 * border_x, font_height, gi->selectbox.inverse_color); - strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size); - text[1 + gi->selectbox.size] = '\0'; - - mask_mode = BLIT_INVERSE; - } - else - { - strncpy(text, gi->selectbox.options[i].text, gi->selectbox.size); + /* prevent use of cursor graphic by drawing at least two chars */ + strcat(text, " "); text[gi->selectbox.size] = '\0'; - mask_mode = BLIT_MASKED; + mask_mode = BLIT_INVERSE; } DrawTextExt(drawto, @@ -608,26 +757,26 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) break; case GDI_NUMBER_VALUE: - gi->text.number_value = va_arg(ap, long); - sprintf(gi->text.value, "%d", gi->text.number_value); - gi->text.cursor_position = strlen(gi->text.value); + gi->textinput.number_value = va_arg(ap, long); + sprintf(gi->textinput.value, "%d", gi->textinput.number_value); + gi->textinput.cursor_position = strlen(gi->textinput.value); break; case GDI_NUMBER_MIN: - gi->text.number_min = va_arg(ap, long); - if (gi->text.number_value < gi->text.number_min) + gi->textinput.number_min = va_arg(ap, long); + if (gi->textinput.number_value < gi->textinput.number_min) { - gi->text.number_value = gi->text.number_min; - sprintf(gi->text.value, "%d", gi->text.number_value); + gi->textinput.number_value = gi->textinput.number_min; + sprintf(gi->textinput.value, "%d", gi->textinput.number_value); } break; case GDI_NUMBER_MAX: - gi->text.number_max = va_arg(ap, long); - if (gi->text.number_value > gi->text.number_max) + gi->textinput.number_max = va_arg(ap, long); + if (gi->textinput.number_value > gi->textinput.number_max) { - gi->text.number_value = gi->text.number_max; - sprintf(gi->text.value, "%d", gi->text.number_value); + gi->textinput.number_value = gi->textinput.number_max; + sprintf(gi->textinput.value, "%d", gi->textinput.number_value); } break; @@ -635,15 +784,16 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) { int max_textsize = MAX_GADGET_TEXTSIZE; - if (gi->text.size) - max_textsize = MIN(gi->text.size, MAX_GADGET_TEXTSIZE - 1); + if (gi->textinput.size) + max_textsize = MIN(gi->textinput.size, MAX_GADGET_TEXTSIZE - 1); - strncpy(gi->text.value, va_arg(ap, char *), max_textsize); - gi->text.value[max_textsize] = '\0'; - gi->text.cursor_position = strlen(gi->text.value); + strncpy(gi->textinput.value, va_arg(ap, char *), max_textsize); + gi->textinput.value[max_textsize] = '\0'; + gi->textinput.cursor_position = strlen(gi->textinput.value); - /* same tag also used for textbutton definition */ - strcpy(gi->textbutton.value, gi->text.value); + /* same tag also used for other gadget definitions */ + strcpy(gi->textbutton.value, gi->textinput.value); + strcpy(gi->textarea.value, gi->textinput.value); } break; @@ -652,13 +802,13 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) int tag_value = va_arg(ap, int); int max_textsize = MIN(tag_value, MAX_GADGET_TEXTSIZE - 1); - gi->text.size = max_textsize; - gi->text.value[max_textsize] = '\0'; + gi->textinput.size = max_textsize; + gi->textinput.value[max_textsize] = '\0'; - /* same tag also used for textbutton and selectbox definition */ - strcpy(gi->textbutton.value, gi->text.value); - gi->textbutton.size = gi->text.size; - gi->selectbox.size = gi->text.size; + /* same tag also used for other gadget definitions */ + strcpy(gi->textbutton.value, gi->textinput.value); + gi->textbutton.size = gi->textinput.size; + gi->selectbox.size = gi->textinput.size; } break; @@ -759,6 +909,17 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->drawing.item_xsize = gi->width / gi->drawing.area_xsize; gi->drawing.item_ysize = gi->height / gi->drawing.area_ysize; } + + /* same tag also used for other gadget definitions */ + gi->textarea.xsize = gi->drawing.area_xsize; + gi->textarea.ysize = gi->drawing.area_ysize; + + if (gi->type & GD_TYPE_TEXT_AREA) /* force recalculation */ + { + gi->width = 0; + gi->height = 0; + } + break; case GDI_ITEM_SIZE: @@ -815,7 +976,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) /* adjust gadget values in relation to other gadget values */ - if (gi->type & GD_TYPE_TEXTINPUT) + if (gi->type & GD_TYPE_TEXT_INPUT) { int font_nr = gi->font_active; int font_width = getFontWidth(font_nr); @@ -823,7 +984,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) int border_xsize = gi->border.xsize; int border_ysize = gi->border.ysize; - gi->width = 2 * border_xsize + (gi->text.size + 1) * font_width; + gi->width = 2 * border_xsize + (gi->textinput.size + 1) * font_width; gi->height = 2 * border_ysize + font_height; } @@ -839,7 +1000,7 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) Bitmap *src_bitmap; int src_x, src_y; - gi->width = 2 * border_xsize + gi->text.size * font_width + button_size; + gi->width = 2 * border_xsize + gi->textinput.size*font_width +button_size; gi->height = 2 * border_ysize + font_height; if (gi->selectbox.options == NULL) @@ -870,9 +1031,9 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) gi->selectbox.open = FALSE; } - if (gi->type & GD_TYPE_TEXTINPUT_NUMERIC) + if (gi->type & GD_TYPE_TEXT_INPUT_NUMERIC) { - struct GadgetTextInput *text = &gi->text; + struct GadgetTextInput *text = &gi->textinput; int value = text->number_value; text->number_value = (value < text->number_min ? text->number_min : @@ -914,6 +1075,26 @@ static void HandleGadgetTags(struct GadgetInfo *gi, int first_tag, va_list ap) if (gs->item_position == gs->items_max - gs->items_visible) gs->position = gs->position_max; } + + if (gi->type & GD_TYPE_TEXT_AREA) + { + int font_nr = gi->font_active; + int font_width = getFontWidth(font_nr); + int font_height = getFontHeight(font_nr); + int border_xsize = gi->border.xsize; + int border_ysize = gi->border.ysize; + + if (gi->width == 0 || gi->height == 0) + { + gi->width = 2 * border_xsize + gi->textarea.xsize * font_width; + gi->height = 2 * border_ysize + gi->textarea.ysize * font_height; + } + else + { + gi->textarea.xsize = (gi->width - 2 * border_xsize) / font_width; + gi->textarea.ysize = (gi->height - 2 * border_ysize) / font_height; + } + } } void ModifyGadget(struct GadgetInfo *gi, int first_tag, ...) @@ -984,22 +1165,22 @@ void FreeGadget(struct GadgetInfo *gi) static void CheckRangeOfNumericInputGadget(struct GadgetInfo *gi) { - if (gi->type != GD_TYPE_TEXTINPUT_NUMERIC) + if (gi->type != GD_TYPE_TEXT_INPUT_NUMERIC) return; - gi->text.number_value = atoi(gi->text.value); + gi->textinput.number_value = atoi(gi->textinput.value); - if (gi->text.number_value < gi->text.number_min) - gi->text.number_value = gi->text.number_min; - if (gi->text.number_value > gi->text.number_max) - gi->text.number_value = gi->text.number_max; + if (gi->textinput.number_value < gi->textinput.number_min) + gi->textinput.number_value = gi->textinput.number_min; + if (gi->textinput.number_value > gi->textinput.number_max) + gi->textinput.number_value = gi->textinput.number_max; - sprintf(gi->text.value, "%d", gi->text.number_value); + sprintf(gi->textinput.value, "%d", gi->textinput.number_value); - if (gi->text.cursor_position < 0) - gi->text.cursor_position = 0; - else if (gi->text.cursor_position > strlen(gi->text.value)) - gi->text.cursor_position = strlen(gi->text.value); + if (gi->textinput.cursor_position < 0) + gi->textinput.cursor_position = 0; + else if (gi->textinput.cursor_position > strlen(gi->textinput.value)) + gi->textinput.cursor_position = strlen(gi->textinput.value); } /* global pointer to gadget actually in use (when mouse button pressed) */ @@ -1085,19 +1266,26 @@ void RemapAllGadgets() MultiMapGadgets(MULTIMAP_ALL | MULTIMAP_REMAP); } -boolean anyTextInputGadgetActive() +static boolean anyTextInputGadgetActive() { - return (last_gi && (last_gi->type & GD_TYPE_TEXTINPUT) && last_gi->mapped); + return (last_gi && (last_gi->type & GD_TYPE_TEXT_INPUT) && last_gi->mapped); } -boolean anySelectboxGadgetActive() +static boolean anyTextAreaGadgetActive() +{ + return (last_gi && (last_gi->type & GD_TYPE_TEXT_AREA) && last_gi->mapped); +} + +static boolean anySelectboxGadgetActive() { return (last_gi && (last_gi->type & GD_TYPE_SELECTBOX) && last_gi->mapped); } boolean anyTextGadgetActive() { - return (anyTextInputGadgetActive() || anySelectboxGadgetActive()); + return (anyTextInputGadgetActive() || + anyTextAreaGadgetActive() || + anySelectboxGadgetActive()); } void ClickOnGadget(struct GadgetInfo *gi, int button) @@ -1160,76 +1348,20 @@ void HandleGadgets(int mx, int my, int button) last_mx = mx; last_my = my; - /* special treatment for text and number input gadgets */ - if (anyTextInputGadgetActive() && button != 0 && !motion_status) - { - struct GadgetInfo *gi = last_gi; - - if (new_gi == last_gi) - { - int old_cursor_position = gi->text.cursor_position; - - /* if mouse button pressed inside activated text gadget, set cursor */ - gi->text.cursor_position = - (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font); - - if (gi->text.cursor_position < 0) - gi->text.cursor_position = 0; - else if (gi->text.cursor_position > strlen(gi->text.value)) - gi->text.cursor_position = strlen(gi->text.value); - - if (gi->text.cursor_position != old_cursor_position) - DrawGadget(gi, DG_PRESSED, gi->direct_draw); - } - else - { - /* if mouse button pressed outside text input gadget, deactivate it */ - CheckRangeOfNumericInputGadget(gi); - DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); - - gi->event.type = GD_EVENT_TEXT_LEAVING; - - if (gi->event_mask & GD_EVENT_TEXT_LEAVING) - gi->callback_action(gi); - - last_gi = NULL; - } - } - - /* special treatment for selectbox gadgets */ - if (anySelectboxGadgetActive() && button != 0 && !motion_status) + /* if mouse button pressed outside text or selectbox gadget, deactivate it */ + if (anyTextGadgetActive() && + button != 0 && !motion_status && new_gi != last_gi) { - struct GadgetInfo *gi = last_gi; - - if (new_gi == last_gi) - { - int old_index = gi->selectbox.current_index; - - /* if mouse button pressed inside activated selectbox, select value */ - if (my >= gi->selectbox.y && my < gi->selectbox.y + gi->selectbox.height) - gi->selectbox.current_index = - (my - gi->selectbox.y - gi->border.ysize) / getFontHeight(gi->font); - - if (gi->selectbox.current_index < 0) - gi->selectbox.current_index = 0; - else if (gi->selectbox.current_index > gi->selectbox.num_values - 1) - gi->selectbox.current_index = gi->selectbox.num_values - 1; + CheckRangeOfNumericInputGadget(last_gi); /* in case of numeric gadget */ - if (gi->selectbox.current_index != old_index) - DrawGadget(gi, DG_PRESSED, gi->direct_draw); - } - else - { - /* if mouse button pressed outside selectbox gadget, deactivate it */ - DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); + DrawGadget(last_gi, DG_UNPRESSED, last_gi->direct_draw); - gi->event.type = GD_EVENT_TEXT_LEAVING; + last_gi->event.type = GD_EVENT_TEXT_LEAVING; - if (gi->event_mask & GD_EVENT_TEXT_LEAVING) - gi->callback_action(gi); + if (last_gi->event_mask & GD_EVENT_TEXT_LEAVING) + last_gi->callback_action(last_gi); - last_gi = NULL; - } + last_gi = NULL; } gadget_pressed = @@ -1278,11 +1410,12 @@ void HandleGadgets(int mx, int my, int button) /* if mouse button released, no gadget needs to be handled anymore */ if (gadget_released) { - if ((last_gi->type & GD_TYPE_SELECTBOX) && + if (last_gi->type & GD_TYPE_SELECTBOX && (gadget_released_inside_select_line || - gadget_released_off_borders)) /* selectbox stays open */ + gadget_released_off_borders)) /* selectbox stays open */ gi->selectbox.stay_open = TRUE; - else if (!(last_gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */ + else if (!(last_gi->type & GD_TYPE_TEXT_INPUT || + last_gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ last_gi = NULL; } @@ -1306,6 +1439,36 @@ void HandleGadgets(int mx, int my, int button) if (last_x != gi->event.x || last_y != gi->event.y) changed_position = TRUE; } + else if (gi->type & GD_TYPE_TEXT_INPUT && button != 0 && !motion_status) + { + int old_cursor_position = gi->textinput.cursor_position; + + /* if mouse button pressed inside activated text gadget, set cursor */ + gi->textinput.cursor_position = + (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font); + + if (gi->textinput.cursor_position < 0) + gi->textinput.cursor_position = 0; + else if (gi->textinput.cursor_position > strlen(gi->textinput.value)) + gi->textinput.cursor_position = strlen(gi->textinput.value); + + if (gi->textinput.cursor_position != old_cursor_position) + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else if (gi->type & GD_TYPE_TEXT_AREA && button != 0 && !motion_status) + { + int old_cursor_position = gi->textarea.cursor_position; + int x = (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font); + int y = (my - gi->y - gi->border.ysize) / getFontHeight(gi->font); + + x = (x < 0 ? 0 : x >= gi->textarea.xsize ? gi->textarea.xsize - 1 : x); + y = (y < 0 ? 0 : y >= gi->textarea.ysize ? gi->textarea.ysize - 1 : y); + + setTextAreaCursorXY(gi, x, y); + + if (gi->textarea.cursor_position != old_cursor_position) + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } else if (gi->type & GD_TYPE_SELECTBOX) { int old_index = gi->selectbox.current_index; @@ -1338,15 +1501,6 @@ void HandleGadgets(int mx, int my, int button) { last_info_gi->event.type = GD_EVENT_INFO_LEAVING; last_info_gi->callback_info(last_info_gi); - -#if 0 - default_callback_info(NULL); - - printf("It seems that we are leaving gadget [%s]!\n", - (last_info_gi != NULL && - last_info_gi->info_text != NULL ? - last_info_gi->info_text : "")); -#endif } last_info_gi = new_gi; @@ -1542,7 +1696,8 @@ void HandleGadgets(int mx, int my, int button) } if (deactivate_gadget && - !(gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */ + !(gi->type & GD_TYPE_TEXT_INPUT || + gi->type & GD_TYPE_TEXT_AREA)) /* text input stays open */ DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); gi->state = GD_BUTTON_UNPRESSED; @@ -1569,70 +1724,160 @@ void HandleGadgets(int mx, int my, int button) new_gi->state = GD_BUTTON_UNPRESSED; } +static void insertCharIntoTextArea(struct GadgetInfo *gi, char c) +{ + char text[MAX_GADGET_TEXTSIZE]; + int cursor_position = gi->textarea.cursor_position; + + if (strlen(gi->textarea.value) == MAX_GADGET_TEXTSIZE) /* no space left */ + return; + + strcpy(text, gi->textarea.value); + strcpy(&gi->textarea.value[cursor_position + 1], &text[cursor_position]); + gi->textarea.value[cursor_position] = c; + + setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); +} + void HandleGadgetsKeyInput(Key key) { struct GadgetInfo *gi = last_gi; if (gi == NULL || !gi->mapped || - !((gi->type & GD_TYPE_TEXTINPUT) || (gi->type & GD_TYPE_SELECTBOX))) + !(gi->type & GD_TYPE_TEXT_INPUT || + gi->type & GD_TYPE_TEXT_AREA || + gi->type & GD_TYPE_SELECTBOX)) return; if (key == KSYM_Return) /* valid for both text input and selectbox */ { - if (gi->type & GD_TYPE_TEXTINPUT) + if (gi->type & GD_TYPE_TEXT_INPUT) CheckRangeOfNumericInputGadget(gi); else if (gi->type & GD_TYPE_SELECTBOX) gi->selectbox.index = gi->selectbox.current_index; - DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); + if (gi->type & GD_TYPE_TEXT_AREA) + { + insertCharIntoTextArea(gi, '\n'); - gi->event.type = GD_EVENT_TEXT_RETURN; + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else + { + DrawGadget(gi, DG_UNPRESSED, gi->direct_draw); + + gi->event.type = GD_EVENT_TEXT_RETURN; + + last_gi = NULL; + } if (gi->event_mask & GD_EVENT_TEXT_RETURN) gi->callback_action(gi); - - last_gi = NULL; } - else if (gi->type & GD_TYPE_TEXTINPUT) /* only valid for text input */ + else if (gi->type & GD_TYPE_TEXT_INPUT) /* only valid for text input */ { char text[MAX_GADGET_TEXTSIZE]; - int text_length = strlen(gi->text.value); - int cursor_pos = gi->text.cursor_position; + int text_length = strlen(gi->textinput.value); + int cursor_pos = gi->textinput.cursor_position; char letter = getCharFromKey(key); - boolean legal_letter = (gi->type == GD_TYPE_TEXTINPUT_NUMERIC ? + boolean legal_letter = (gi->type == GD_TYPE_TEXT_INPUT_NUMERIC ? letter >= '0' && letter <= '9' : letter != 0); - if (legal_letter && text_length < gi->text.size) + if (legal_letter && text_length < gi->textinput.size) { - strcpy(text, gi->text.value); - strcpy(&gi->text.value[cursor_pos + 1], &text[cursor_pos]); - gi->text.value[cursor_pos] = letter; - gi->text.cursor_position++; + strcpy(text, gi->textinput.value); + strcpy(&gi->textinput.value[cursor_pos + 1], &text[cursor_pos]); + gi->textinput.value[cursor_pos] = letter; + gi->textinput.cursor_position++; DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Left && cursor_pos > 0) { - gi->text.cursor_position--; + gi->textinput.cursor_position--; + DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Right && cursor_pos < text_length) { - gi->text.cursor_position++; + gi->textinput.cursor_position++; + DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_BackSpace && cursor_pos > 0) { - strcpy(text, gi->text.value); - strcpy(&gi->text.value[cursor_pos - 1], &text[cursor_pos]); - gi->text.cursor_position--; + strcpy(text, gi->textinput.value); + strcpy(&gi->textinput.value[cursor_pos - 1], &text[cursor_pos]); + gi->textinput.cursor_position--; + DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Delete && cursor_pos < text_length) { - strcpy(text, gi->text.value); - strcpy(&gi->text.value[cursor_pos], &text[cursor_pos + 1]); + strcpy(text, gi->textinput.value); + strcpy(&gi->textinput.value[cursor_pos], &text[cursor_pos + 1]); + + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + } + else if (gi->type & GD_TYPE_TEXT_AREA) /* only valid for text area */ + { + char text[MAX_GADGET_TEXTSIZE]; + int text_length = strlen(gi->textarea.value); + int area_ysize = gi->textarea.ysize; + int cursor_x_pref = gi->textarea.cursor_x_preferred; + int cursor_y = gi->textarea.cursor_y; + int cursor_pos = gi->textarea.cursor_position; + char letter = getCharFromKey(key); + boolean legal_letter = (letter != 0); + + if (legal_letter) + { + insertCharIntoTextArea(gi, letter); + + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else if (key == KSYM_Left && cursor_pos > 0) + { + setTextAreaCursorPosition(gi, gi->textarea.cursor_position - 1); + + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else if (key == KSYM_Right && cursor_pos < text_length) + { + setTextAreaCursorPosition(gi, gi->textarea.cursor_position + 1); + + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else if (key == KSYM_Up && cursor_y > 0) + { + setTextAreaCursorXY(gi, cursor_x_pref, cursor_y - 1); + gi->textarea.cursor_x_preferred = cursor_x_pref; + + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else if (key == KSYM_Down && cursor_y < area_ysize - 1) + { + setTextAreaCursorXY(gi, cursor_x_pref, cursor_y + 1); + gi->textarea.cursor_x_preferred = cursor_x_pref; + + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else if (key == KSYM_BackSpace && cursor_pos > 0) + { + strcpy(text, gi->textarea.value); + strcpy(&gi->textarea.value[cursor_pos - 1], &text[cursor_pos]); + + setTextAreaCursorPosition(gi, gi->textarea.cursor_position - 1); + + DrawGadget(gi, DG_PRESSED, gi->direct_draw); + } + else if (key == KSYM_Delete && cursor_pos < text_length) + { + strcpy(text, gi->textarea.value); + strcpy(&gi->textarea.value[cursor_pos], &text[cursor_pos + 1]); + DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } @@ -1644,11 +1889,13 @@ void HandleGadgetsKeyInput(Key key) if (key == KSYM_Up && index > 0) { gi->selectbox.current_index--; + DrawGadget(gi, DG_PRESSED, gi->direct_draw); } else if (key == KSYM_Down && index < num_values - 1) { gi->selectbox.current_index++; + DrawGadget(gi, DG_PRESSED, gi->direct_draw); } } diff --git a/src/libgame/gadgets.h b/src/libgame/gadgets.h index e486a2b7..160bd611 100644 --- a/src/libgame/gadgets.h +++ b/src/libgame/gadgets.h @@ -25,11 +25,12 @@ #define GD_TYPE_CHECK_BUTTON (1 << 2) #define GD_TYPE_RADIO_BUTTON (1 << 3) #define GD_TYPE_DRAWING_AREA (1 << 4) -#define GD_TYPE_TEXTINPUT_ALPHANUMERIC (1 << 5) -#define GD_TYPE_TEXTINPUT_NUMERIC (1 << 6) -#define GD_TYPE_SELECTBOX (1 << 7) -#define GD_TYPE_SCROLLBAR_VERTICAL (1 << 8) -#define GD_TYPE_SCROLLBAR_HORIZONTAL (1 << 9) +#define GD_TYPE_TEXT_INPUT_ALPHANUMERIC (1 << 5) +#define GD_TYPE_TEXT_INPUT_NUMERIC (1 << 6) +#define GD_TYPE_TEXT_AREA (1 << 7) +#define GD_TYPE_SELECTBOX (1 << 8) +#define GD_TYPE_SCROLLBAR_VERTICAL (1 << 9) +#define GD_TYPE_SCROLLBAR_HORIZONTAL (1 << 10) #define GD_TYPE_BUTTON (GD_TYPE_NORMAL_BUTTON | \ GD_TYPE_TEXT_BUTTON | \ @@ -37,8 +38,8 @@ GD_TYPE_RADIO_BUTTON) #define GD_TYPE_SCROLLBAR (GD_TYPE_SCROLLBAR_VERTICAL | \ GD_TYPE_SCROLLBAR_HORIZONTAL) -#define GD_TYPE_TEXTINPUT (GD_TYPE_TEXTINPUT_ALPHANUMERIC | \ - GD_TYPE_TEXTINPUT_NUMERIC) +#define GD_TYPE_TEXT_INPUT (GD_TYPE_TEXT_INPUT_ALPHANUMERIC | \ + GD_TYPE_TEXT_INPUT_NUMERIC) /* gadget events */ #define GD_EVENT_PRESSED (1 << 0) @@ -158,6 +159,17 @@ struct GadgetTextInput int size; /* maximal size of input text */ }; +struct GadgetTextArea +{ + char value[MAX_GADGET_TEXTSIZE]; /* text string in input field */ + int cursor_position; /* actual text cursor position */ + int cursor_x; /* actual x cursor position */ + int cursor_y; /* actual y cursor position */ + int cursor_x_preferred; /* "preferred" x cursor position */ + int size; /* maximal size of input text */ + int xsize, ysize; /* size of text area (in chars) */ +}; + struct GadgetSelectbox { struct ValueTextInfo *options; /* pointer to text/value array */ @@ -216,7 +228,8 @@ struct GadgetInfo gadget_function callback_action; /* function for gadget action */ struct GadgetDrawingArea drawing; /* fields for drawing area gadget */ struct GadgetTextButton textbutton; /* fields for text button gadget */ - struct GadgetTextInput text; /* fields for text input gadget */ + struct GadgetTextInput textinput; /* fields for text input gadget */ + struct GadgetTextArea textarea; /* fields for text area gadget */ struct GadgetSelectbox selectbox; /* fields for selectbox gadget */ struct GadgetScrollbar scrollbar; /* fields for scrollbar gadget */ struct GadgetInfo *next; /* next list entry */ diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 2a5eb1ab..4cd8921e 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -2365,9 +2365,10 @@ static void SaveUserLevelInfo() fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i)); fclose(file); - free(filename); SetFilePermissions(filename, PERMS_PRIVATE); + + free(filename); } char *getSetupValue(int type, void *value) @@ -2514,9 +2515,10 @@ void SaveLevelSetup_LastSeries() level_subdir)); fclose(file); - free(filename); SetFilePermissions(filename, PERMS_PRIVATE); + + free(filename); } static void checkSeriesInfo() @@ -2663,7 +2665,8 @@ void SaveLevelSetup_SeriesInfo() handicap_level_str)); fclose(file); - free(filename); SetFilePermissions(filename, PERMS_PRIVATE); + + free(filename); } diff --git a/src/libgame/system.h b/src/libgame/system.h index a9f1efa1..73ec0f79 100644 --- a/src/libgame/system.h +++ b/src/libgame/system.h @@ -485,6 +485,8 @@ struct SetupEditorInfo boolean el_chars; boolean el_custom; boolean el_custom_more; + + boolean el_headlines; }; struct SetupShortcutInfo diff --git a/src/libgame/text.c b/src/libgame/text.c index a4b60302..6b5f03e0 100644 --- a/src/libgame/text.c +++ b/src/libgame/text.c @@ -259,6 +259,9 @@ void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text, { char c = *text_ptr++; + if (c == '\n') + c = ' '; /* print space instaed of newline */ + getFontCharSource(font_nr, c, &src_bitmap, &src_x, &src_y); if (mask_mode == BLIT_INVERSE) /* special mode for text gadgets */ @@ -322,3 +325,28 @@ void DrawTextExt(DrawBuffer *dst_bitmap, int dst_x, int dst_y, char *text, dst_x += font_width; } } + +void DrawTextToTextArea(int x, int y, char *text, int font_nr, + int area_xsize, int area_ysize) +{ + int area_line = 0; + int font_height = getFontHeight(font_nr); + + if (text == NULL) + return; + + while (*text && area_line < area_ysize) + { + char buffer[MAX_OUTPUT_LINESIZE + 1]; + int i; + + for (i=0; i < area_xsize && *text; i++) + if ((buffer[i] = *text++) == '\n') + break; + buffer[i] = '\0'; + + DrawText(x, y + area_line * font_height, buffer, font_nr); + + area_line++; + } +} diff --git a/src/libgame/text.h b/src/libgame/text.h index fd1e8c57..c9c48943 100644 --- a/src/libgame/text.h +++ b/src/libgame/text.h @@ -66,5 +66,6 @@ void DrawTextF(int, int, int, char *, ...); void DrawTextFCentered(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); #endif /* TEXT_H */ diff --git a/src/main.h b/src/main.h index cab4e71d..8a0fca2c 100644 --- a/src/main.h +++ b/src/main.h @@ -184,10 +184,13 @@ #define CE_BITMASK_DEFAULT 0 #define CH_EVENT_BIT(c) (1 << (c)) -#define CH_EVENT_VAR(e) (element_info[e].change.events) +#define CH_EVENT_VAR(e) (element_info[e].change->events) +#define CH_ANY_EVENT_VAR(e) (element_info[e].change_events) #define HAS_CHANGE_EVENT(e,c) (IS_CUSTOM_ELEMENT(e) && \ (CH_EVENT_VAR(e) & CH_EVENT_BIT(c)) != 0) +#define HAS_ANY_CHANGE_EVENT(e,c) (IS_CUSTOM_ELEMENT(e) && \ + (CH_ANY_EVENT_VAR(e) & CH_EVENT_BIT(c)) != 0) #define SET_CHANGE_EVENT(e,c,v) (IS_CUSTOM_ELEMENT(e) ? \ ((v) ? \ (CH_EVENT_VAR(e) |= CH_EVENT_BIT(c)) : \ @@ -352,14 +355,28 @@ #define IS_LOOP_SOUND(s) (sound_info[s].loop) +/* fundamental game speed values */ +#define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */ +#define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */ +#define FRAMES_PER_SECOND (1000 / GAME_FRAME_DELAY) +#define MICROLEVEL_SCROLL_DELAY 50 /* delay for scrolling micro level */ +#define MICROLEVEL_LABEL_DELAY 250 /* delay for micro level label */ + /* boundaries of arrays etc. */ #define MAX_LEVEL_NAME_LEN 32 #define MAX_LEVEL_AUTHOR_LEN 32 #define MAX_ELEMENT_NAME_LEN 32 -#define MAX_TAPELEN (1000 * 50) /* max. time * framerate */ +#define MAX_TAPELEN (1000 * FRAMES_PER_SECOND) /* max.time x fps */ #define MAX_SCORE_ENTRIES 100 #define MAX_NUM_AMOEBA 100 #define MAX_INVENTORY_SIZE 1000 +#define MIN_ENVELOPE_XSIZE 1 +#define MIN_ENVELOPE_YSIZE 1 +#define MAX_ENVELOPE_XSIZE 30 +#define MAX_ENVELOPE_YSIZE 20 +#define MAX_ENVELOPE_TEXT_LEN (MAX_ENVELOPE_XSIZE * MAX_ENVELOPE_YSIZE) +#define MIN_CHANGE_PAGES 1 +#define MAX_CHANGE_PAGES 10 /* values for elements with content */ #define MIN_ELEMENT_CONTENTS 1 @@ -368,13 +385,6 @@ #define LEVEL_SCORE_ELEMENTS 16 /* level elements with score */ -/* fundamental game speed values */ -#define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */ -#define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */ -#define FRAMES_PER_SECOND (1000 / GAME_FRAME_DELAY) -#define MICROLEVEL_SCROLL_DELAY 50 /* delay for scrolling micro level */ -#define MICROLEVEL_LABEL_DELAY 250 /* delay for micro level label */ - /* often used screen positions */ #define SX 8 #define SY 8 @@ -1112,12 +1122,13 @@ struct LevelInfo boolean encoding_16bit_yamyam; /* yamyam contains 16-bit elements */ boolean encoding_16bit_amoeba; /* amoeba contains 16-bit elements */ - int fieldx; - int fieldy; + int fieldx, fieldy; int time; int gems_needed; char name[MAX_LEVEL_NAME_LEN + 1]; char author[MAX_LEVEL_AUTHOR_LEN + 1]; + char envelope[MAX_ENVELOPE_TEXT_LEN + 1]; + int envelope_xsize, envelope_ysize; int score[LEVEL_SCORE_ELEMENTS]; int yamyam_content[MAX_ELEMENT_CONTENTS][3][3]; int num_yamyam_contents; @@ -1135,7 +1146,7 @@ struct LevelInfo boolean use_custom_template; /* use custom properties from template file */ - boolean no_level_file; + boolean no_level_file; /* set for currently undefined levels */ }; struct TapeInfo @@ -1225,6 +1236,8 @@ struct DoorInfo struct ElementChangeInfo { + boolean can_change; /* use or ignore this change info */ + unsigned long events; /* bitfield for change events */ short target_element; /* target element after change */ @@ -1249,6 +1262,12 @@ struct ElementChangeInfo void (*pre_change_function)(int x, int y); void (*change_function)(int x, int y); void (*post_change_function)(int x, int y); + + /* ---------- internal values used in level editor ---------- */ + + int player_action; /* touched/pressed/pushed by player */ + int collide_action; /* collision/impact/smashed */ + int other_action; /* various change actions */ }; struct ElementInfo @@ -1297,7 +1316,18 @@ struct ElementInfo int content[3][3]; /* new elements after explosion */ - struct ElementChangeInfo change; + struct ElementChangeInfo *change_page; /* actual list of change pages */ + struct ElementChangeInfo *change; /* pointer to current change page */ + + int num_change_pages; /* actual number of change pages */ + int current_change_page; /* currently edited change page */ + + /* ---------- internal values used at runtime when playing ---------- */ + + unsigned long change_events; /* bitfield for combined change events */ + + int event_page_num[NUM_CHANGE_EVENTS]; /* page number for each event */ + struct ElementChangeInfo *event_page[NUM_CHANGE_EVENTS]; /* page for event */ /* ---------- internal values used in level editor ---------- */ @@ -1307,9 +1337,6 @@ struct ElementInfo int smash_targets; /* can smash player/enemies/everything */ int deadliness; /* deadly when running/colliding/touching */ int consistency; /* indestructible/can explode */ - int change_player_action; /* touched/pressed/pushed by player */ - int change_collide_action; /* collision/impact/smashed */ - int change_other_action; /* various change actions */ boolean can_explode_by_fire; /* element explodes by fire */ boolean can_explode_smashed; /* element explodes when smashed */ diff --git a/src/screens.c b/src/screens.c index 2b13ad56..0d3b008a 100644 --- a/src/screens.c +++ b/src/screens.c @@ -1813,6 +1813,8 @@ static struct TokenInfo setup_info_editor[] = { TYPE_SWITCH, &setup.editor.el_custom, "Custom:" }, { TYPE_SWITCH, &setup.editor.el_custom_more, "More Custom:" }, { TYPE_EMPTY, NULL, "" }, + { TYPE_SWITCH, &setup.editor.el_headlines, "Headlines:" }, + { TYPE_EMPTY, NULL, "" }, { TYPE_LEAVE_MENU, execSetupMain, "Back" }, { 0, NULL, NULL } }; -- 2.34.1