+Release Version 3.0.3 [08 SEP 2003]
+-----------------------------------
+ - fixed bug (missing array boundary check) which could crash the game
+ - fixed problem with setting mouse cursor in SDL version in fullscreen
+ - fixed problem with flickering when drawing toon animations
+ - fixed problem with player animation when snapping and moving
+ - fixed several nasty bugs that may have caused crashes on some systems
+ - added envelope content which gets displayed when collecting envelope
+ - added multiple change event pages for custom elements
+ - added support for loading various music formats through SDL_mixer
+
Release Version 3.0.2 [22 AUG 2003]
-----------------------------------
- fixed bug with messing up custom element properties in 3.0.0 levels
boolean ToonNeedsRedraw()
{
+#if 1
+ return TRUE;
+#else
return (game_status == GAME_MODE_INFO ||
+ game_status == GAME_MODE_LEVELS ||
+ game_status == GAME_MODE_SETUP ||
(game_status == GAME_MODE_MAIN &&
((redraw_mask & REDRAW_MICROLEVEL) ||
(redraw_mask & REDRAW_MICROLABEL))));
+#endif
}
void InitToons()
FONT_TEXT_1, GFX_SPECIAL_ARG_PREVIEW,
IMG_FONT_TEXT_1_PREVIEW
},
+ {
+ FONT_TEXT_1, GFX_SPECIAL_ARG_PLAYING,
+ IMG_FONT_TEXT_1_PLAYING
+ },
{
FONT_TEXT_1, GFX_SPECIAL_ARG_SCORES,
IMG_FONT_TEXT_1_SCORES
{ ".global_sync", "false", TYPE_BOOLEAN },
{ ".crumbled_like", ARG_UNDEFINED, TYPE_TOKEN },
{ ".diggable_like", ARG_UNDEFINED, TYPE_TOKEN },
+ { ".border_size", ARG_UNDEFINED, TYPE_INTEGER },
{ ".step_offset", "4", TYPE_INTEGER },
{ ".step_delay", "1", TYPE_INTEGER },
{ ".direction", ARG_UNDEFINED, TYPE_STRING },
{ ".position", ARG_UNDEFINED, TYPE_STRING },
{ ".draw_xoffset", "0", TYPE_INTEGER },
{ ".draw_yoffset", "0", TYPE_INTEGER },
+ { ".draw_masked", "false", TYPE_BOOLEAN },
{ ".name", ARG_UNDEFINED, TYPE_STRING },
{ NULL, NULL, 0 }
{ "font.text_1.PREVIEW.y", "160" },
{ "font.text_1.PREVIEW.width", "16" },
{ "font.text_1.PREVIEW.height", "16" },
+ { "font.text_1.PLAYING", "RocksFontEM.pcx" },
+ { "font.text_1.PLAYING.x", "0" },
+ { "font.text_1.PLAYING.y", "160" },
+ { "font.text_1.PLAYING.width", "16" },
+ { "font.text_1.PLAYING.height", "16" },
{ "font.text_1.SCORES", "RocksFontMedium.pcx" },
{ "font.text_1.SCORES.x", "0" },
{ "font.text_1.SCORES.y", "480" },
{ "editor.element_border_input.xpos", "0" },
{ "editor.element_border_input.ypos", "0" },
+ { "game.envelope_background", "RocksScreen.pcx" },
+ { "game.envelope_background.x", "0" },
+ { "game.envelope_background.y", "0" },
+ { "game.envelope_background.width", "560" },
+ { "game.envelope_background.height", "560" },
+
{ "background", UNDEFINED_FILENAME },
{ "background.MAIN", UNDEFINED_FILENAME },
{ "background.LEVELS", UNDEFINED_FILENAME },
#define IMG_FONT_TEXT_1 1227
#define IMG_FONT_TEXT_1_LEVELS 1228
#define IMG_FONT_TEXT_1_PREVIEW 1229
-#define IMG_FONT_TEXT_1_SCORES 1230
-#define IMG_FONT_TEXT_1_ACTIVE_SCORES 1231
-#define IMG_FONT_TEXT_2 1232
-#define IMG_FONT_TEXT_2_LEVELS 1233
-#define IMG_FONT_TEXT_2_PREVIEW 1234
-#define IMG_FONT_TEXT_2_SCORES 1235
-#define IMG_FONT_TEXT_2_ACTIVE_SCORES 1236
-#define IMG_FONT_TEXT_3 1237
-#define IMG_FONT_TEXT_3_LEVELS 1238
-#define IMG_FONT_TEXT_3_PREVIEW 1239
-#define IMG_FONT_TEXT_3_SCORES 1240
-#define IMG_FONT_TEXT_3_ACTIVE_SCORES 1241
-#define IMG_FONT_TEXT_4 1242
-#define IMG_FONT_TEXT_4_LEVELS 1243
-#define IMG_FONT_TEXT_4_SCORES 1244
-#define IMG_FONT_TEXT_4_ACTIVE_SCORES 1245
-#define IMG_FONT_INPUT_1 1246
-#define IMG_FONT_INPUT_1_MAIN 1247
-#define IMG_FONT_INPUT_1_ACTIVE 1248
-#define IMG_FONT_INPUT_1_ACTIVE_MAIN 1249
-#define IMG_FONT_INPUT_1_ACTIVE_SETUP 1250
-#define IMG_FONT_INPUT_2 1251
-#define IMG_FONT_INPUT_2_ACTIVE 1252
-#define IMG_FONT_OPTION_OFF 1253
-#define IMG_FONT_OPTION_ON 1254
-#define IMG_FONT_VALUE_1 1255
-#define IMG_FONT_VALUE_2 1256
-#define IMG_FONT_VALUE_OLD 1257
-#define IMG_FONT_LEVEL_NUMBER 1258
-#define IMG_FONT_TAPE_RECORDER 1259
-#define IMG_FONT_GAME_INFO 1260
-#define IMG_GLOBAL_BORDER 1261
-#define IMG_GLOBAL_DOOR 1262
-#define IMG_EDITOR_ELEMENT_BORDER 1263
-#define IMG_EDITOR_ELEMENT_BORDER_INPUT 1264
-#define IMG_BACKGROUND 1265
-#define IMG_BACKGROUND_MAIN 1266
-#define IMG_BACKGROUND_LEVELS 1267
-#define IMG_BACKGROUND_SCORES 1268
-#define IMG_BACKGROUND_EDITOR 1269
-#define IMG_BACKGROUND_INFO 1270
-#define IMG_BACKGROUND_SETUP 1271
-#define IMG_BACKGROUND_DOOR 1272
+#define IMG_FONT_TEXT_1_PLAYING 1230
+#define IMG_FONT_TEXT_1_SCORES 1231
+#define IMG_FONT_TEXT_1_ACTIVE_SCORES 1232
+#define IMG_FONT_TEXT_2 1233
+#define IMG_FONT_TEXT_2_LEVELS 1234
+#define IMG_FONT_TEXT_2_PREVIEW 1235
+#define IMG_FONT_TEXT_2_SCORES 1236
+#define IMG_FONT_TEXT_2_ACTIVE_SCORES 1237
+#define IMG_FONT_TEXT_3 1238
+#define IMG_FONT_TEXT_3_LEVELS 1239
+#define IMG_FONT_TEXT_3_PREVIEW 1240
+#define IMG_FONT_TEXT_3_SCORES 1241
+#define IMG_FONT_TEXT_3_ACTIVE_SCORES 1242
+#define IMG_FONT_TEXT_4 1243
+#define IMG_FONT_TEXT_4_LEVELS 1244
+#define IMG_FONT_TEXT_4_SCORES 1245
+#define IMG_FONT_TEXT_4_ACTIVE_SCORES 1246
+#define IMG_FONT_INPUT_1 1247
+#define IMG_FONT_INPUT_1_MAIN 1248
+#define IMG_FONT_INPUT_1_ACTIVE 1249
+#define IMG_FONT_INPUT_1_ACTIVE_MAIN 1250
+#define IMG_FONT_INPUT_1_ACTIVE_SETUP 1251
+#define IMG_FONT_INPUT_2 1252
+#define IMG_FONT_INPUT_2_ACTIVE 1253
+#define IMG_FONT_OPTION_OFF 1254
+#define IMG_FONT_OPTION_ON 1255
+#define IMG_FONT_VALUE_1 1256
+#define IMG_FONT_VALUE_2 1257
+#define IMG_FONT_VALUE_OLD 1258
+#define IMG_FONT_LEVEL_NUMBER 1259
+#define IMG_FONT_TAPE_RECORDER 1260
+#define IMG_FONT_GAME_INFO 1261
+#define IMG_GLOBAL_BORDER 1262
+#define IMG_GLOBAL_DOOR 1263
+#define IMG_EDITOR_ELEMENT_BORDER 1264
+#define IMG_EDITOR_ELEMENT_BORDER_INPUT 1265
+#define IMG_GAME_ENVELOPE_BACKGROUND 1266
+#define IMG_BACKGROUND 1267
+#define IMG_BACKGROUND_MAIN 1268
+#define IMG_BACKGROUND_LEVELS 1269
+#define IMG_BACKGROUND_SCORES 1270
+#define IMG_BACKGROUND_EDITOR 1271
+#define IMG_BACKGROUND_INFO 1272
+#define IMG_BACKGROUND_SETUP 1273
+#define IMG_BACKGROUND_DOOR 1274
-#define NUM_IMAGE_FILES 1273
+#define NUM_IMAGE_FILES 1275
#endif /* CONF_GFX_H */
-#define COMPILE_DATE_STRING "[2003-08-21 23:55]"
+#define COMPILE_DATE_STRING "[2003-09-08 00:04]"
#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 + \
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 */
#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) + \
+#define ED_AREA_ELEM_CONTENT5_YPOS (ED_SETTINGS_YPOS(6) + \
ED_GADGET_DISTANCE)
/* extended custom change target */
#define ED_AREA_ELEM_CONTENT6_XPOS (29 * MINI_TILEX)
-#define ED_AREA_ELEM_CONTENT6_YPOS (ED_SETTINGS_YPOS(10) + \
+#define ED_AREA_ELEM_CONTENT6_YPOS (ED_SETTINGS_YPOS(9) + \
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 */
#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)
#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)
#define GADGET_ID_CUSTOM_ACCESS_TYPE (GADGET_ID_SELECTBOX_FIRST + 8)
#define GADGET_ID_CUSTOM_ACCESS_LAYER (GADGET_ID_SELECTBOX_FIRST + 9)
#define GADGET_ID_CHANGE_TIME_UNITS (GADGET_ID_SELECTBOX_FIRST + 10)
-#define GADGET_ID_CHANGE_PLAYER_ACTION (GADGET_ID_SELECTBOX_FIRST + 11)
-#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_CHANGE_DIRECT_ACTION (GADGET_ID_SELECTBOX_FIRST + 11)
+#define GADGET_ID_CHANGE_OTHER_ACTION (GADGET_ID_SELECTBOX_FIRST + 12)
+#define GADGET_ID_CHANGE_POWER (GADGET_ID_SELECTBOX_FIRST + 13)
+#define GADGET_ID_SELECT_CHANGE_PAGE (GADGET_ID_SELECTBOX_FIRST + 14)
/* textbutton identifiers */
#define GADGET_ID_TEXTBUTTON_FIRST (GADGET_ID_SELECTBOX_FIRST + 15)
#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)
#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 23)
#define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 24)
#define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 25)
-#define GADGET_ID_CHANGE_BY_PLAYER (GADGET_ID_CHECKBUTTON_FIRST + 26)
-#define GADGET_ID_CHANGE_BY_COLLISION (GADGET_ID_CHECKBUTTON_FIRST + 27)
-#define GADGET_ID_CHANGE_BY_OTHER (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 26)
+#define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 27)
/* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 29)
+#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 28)
#define GADGET_ID_ELEMENTLIST_LAST (GADGET_ID_ELEMENTLIST_FIRST + \
ED_NUM_ELEMENTLIST_BUTTONS - 1)
#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
#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
#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS 8
#define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY 9
#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS 10
-#define ED_SELECTBOX_ID_CHANGE_PLAYER_ACTION 11
-#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_CHANGE_DIRECT_ACTION 11
+#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION 12
+#define ED_SELECTBOX_ID_CHANGE_POWER 13
+#define ED_SELECTBOX_ID_SELECT_CHANGE_PAGE 14
#define ED_NUM_SELECTBOX 15
#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_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_TEXTBUTTON 4
+#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
#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 16
#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 17
#define ED_CHECKBUTTON_ID_CHANGE_DELAY 18
-#define ED_CHECKBUTTON_ID_CHANGE_BY_PLAYER 19
-#define ED_CHECKBUTTON_ID_CHANGE_BY_COLLISION 20
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER 21
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 22
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 23
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 24
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 25
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 26
+#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 19
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 20
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 21
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 22
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 23
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 24
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 25
-#define ED_NUM_CHECKBUTTONS 27
+#define ED_NUM_CHECKBUTTONS 26
#define ED_CHECKBUTTON_ID_LEVEL_FIRST ED_CHECKBUTTON_ID_DOUBLE_SPEED
#define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
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
"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,
&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) ------------- */
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,
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,
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,
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
},
{
- ED_SETTINGS_XPOS(3), ED_SETTINGS_YPOS(12),
+ ED_SETTINGS_XPOS(3), ED_SETTINGS_YPOS(11),
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:", "(%)"
},
};
int gadget_id;
int size;
char *value;
- char *infotext;
+ char *text_above, *infotext;
} textinput_info[ED_NUM_TEXTINPUT] =
{
{
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"
}
};
static struct ValueTextInfo options_time_units[] =
{
- { 50, "seconds" },
+ { FRAMES_PER_SECOND, "seconds" },
{ 1, "frames" },
{ -1, NULL }
};
-static struct ValueTextInfo options_change_player_action[] =
-{
- { CE_TOUCHED_BY_PLAYER, "touched" },
- { CE_PRESSED_BY_PLAYER, "pressed" },
- { CE_PUSHED_BY_PLAYER, "pushed" },
- { CE_DROPPED_BY_PLAYER, "dropped" },
- { -1, NULL }
-};
-
-static struct ValueTextInfo options_change_collide_action[] =
+static struct ValueTextInfo options_change_direct_action[] =
{
- { CE_COLLISION, "on collision" },
- { CE_IMPACT, "on impact" },
- { CE_SMASHED, "when smashed" },
+ { CE_TOUCHED_BY_PLAYER, "touched by player" },
+ { CE_PRESSED_BY_PLAYER, "pressed by player" },
+ { CE_PUSHED_BY_PLAYER, "pushed by player" },
+ { CE_DROPPED_BY_PLAYER, "dropped by player" },
+ { CE_COLLISION, "collision" },
+ { CE_IMPACT, "impact" },
+ { CE_SMASHED, "smashed" },
{ -1, NULL }
};
static struct ValueTextInfo options_change_other_action[] =
{
- { CE_OTHER_IS_TOUCHING, "touching" },
- { CE_OTHER_IS_CHANGING, "change of" },
- { CE_OTHER_IS_EXPLODING, "explosion of" },
{ CE_OTHER_GETS_TOUCHED, "player touches" },
{ CE_OTHER_GETS_PRESSED, "player presses" },
{ CE_OTHER_GETS_PUSHED, "player pushes" },
+ { CE_OTHER_GETS_DIGGED, "player digs" },
{ CE_OTHER_GETS_COLLECTED, "player collects" },
{ CE_OTHER_GETS_DROPPED, "player drops" },
+ { CE_OTHER_IS_TOUCHING, "touching" },
+ { CE_OTHER_IS_CHANGING, "change of" },
+ { CE_OTHER_IS_EXPLODING, "explosion of" },
{ -1, NULL }
};
static struct ValueTextInfo options_change_power[] =
{
- { CP_NON_DESTRUCTIVE, "non-destructive" },
- { CP_HALF_DESTRUCTIVE, "half-destructive" },
- { CP_FULL_DESTRUCTIVE, "full-destructive" },
+ { CP_NON_DESTRUCTIVE, "empty" },
+ { CP_HALF_DESTRUCTIVE, "diggable" },
+ { CP_FULL_DESTRUCTIVE, "destructible" },
+ { -1, NULL }
+};
+
+static char options_change_page_strings[MAX_CHANGE_PAGES][10];
+static struct ValueTextInfo options_change_page[MAX_CHANGE_PAGES + 1] =
+{
{ -1, NULL }
};
-1,
options_access_type,
&custom_element.access_type,
- "player can", NULL, "type of access to this field"
+ "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,
&custom_element.access_layer,
- NULL, NULL, "layer of access for this field"
+ NULL, NULL, "layer of access for this field"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(2),
-1,
options_walk_to_action,
&custom_element.walk_to_action,
- NULL, NULL, "diggable/collectible/pushable"
+ NULL, NULL, "diggable/collectible/pushable"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(5),
-1,
options_move_pattern,
&custom_element.move_pattern,
- "can move", NULL, "element move direction"
+ "can move", NULL, "element move direction"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(6),
-1,
options_move_direction,
&custom_element.move_direction_initial,
- "starts moving", NULL, "initial element move direction"
+ "starts moving", NULL, "initial element move direction"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(8),
-1,
options_move_stepsize,
&custom_element.move_stepsize,
- "move/fall speed", NULL, "speed of element movement"
+ "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,
&custom_element.smash_targets,
- "can smash", NULL, "elements that can be smashed"
+ "can smash", NULL, "elements that can be smashed"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(10),
-1,
options_slippery_type,
&custom_element.slippery_type,
- "slippery", NULL, "where other elements fall down"
+ "slippery", NULL, "where other elements fall down"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(11),
-1,
options_deadliness,
&custom_element.deadliness,
- "deadly when", NULL, "deadliness of element"
+ "deadly when", NULL, "deadliness of element"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(12),
-1,
options_consistency,
&custom_element.consistency,
- NULL, NULL, "consistency/destructibility"
+ NULL, NULL, "consistency/destructibility"
},
/* ---------- element settings: advanced (custom elements) --------------- */
GADGET_ID_CHANGE_TIME_UNITS, GADGET_ID_NONE,
-1,
options_time_units,
- &custom_element.change.delay_frames,
- "delay time given in", NULL, "delay time units for change"
+ &custom_element_change.delay_frames,
+ "delay time given in", NULL, "delay time units for change"
},
{
ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(5),
- GADGET_ID_CHANGE_PLAYER_ACTION, GADGET_ID_NONE,
+ GADGET_ID_CHANGE_DIRECT_ACTION, GADGET_ID_NONE,
-1,
- options_change_player_action,
- &custom_element.change_player_action,
- NULL, "by player", "type of player contact"
+ options_change_direct_action,
+ &custom_element_change.direct_action,
+ NULL, NULL, "type of direct action"
},
{
ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(6),
- GADGET_ID_CHANGE_COLLIDE_ACTION, GADGET_ID_NONE,
- -1,
- options_change_collide_action,
- &custom_element.change_collide_action,
- NULL, NULL, "change after impact or smash"
- },
- {
- ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(7),
GADGET_ID_CHANGE_OTHER_ACTION, GADGET_ID_NONE,
-1,
options_change_other_action,
- &custom_element.change_other_action,
- NULL, "element:", "type of other element action"
+ &custom_element_change.other_action,
+ NULL, "element:", "type of other element action"
},
{
- ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(10),
+ ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(9),
GADGET_ID_CHANGE_POWER, GADGET_ID_NONE,
-1,
options_change_power,
- &custom_element.change.power,
- "power:", NULL, "power of extended change"
+ &custom_element_change.power,
+ "replace when", NULL, "which elements can be replaced"
+ },
+ {
+ ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(13),
+ GADGET_ID_SELECT_CHANGE_PAGE, GADGET_ID_NONE,
+ 3,
+ options_change_page,
+ &custom_element.current_change_page,
+ NULL, NULL, "element config page"
},
};
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(12),
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(13),
+ GADGET_ID_ADD_CHANGE_PAGE, GADGET_ID_NEXT_CHANGE_PAGE,
+ -1, "New",
+ " ", NULL, "Add new config page"
+ },
+ {
+ -1, ED_SETTINGS_YPOS(13),
+ 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(13),
+ 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(13),
+ 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"
},
};
},
{
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
} 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,
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"
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"
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"
{
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"
},
{
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(5),
- GADGET_ID_CHANGE_BY_PLAYER, GADGET_ID_NONE,
- &custom_element_change_events[CE_BY_PLAYER],
- NULL, NULL, "element changes by player contact"
+ GADGET_ID_CHANGE_BY_DIRECT_ACT, GADGET_ID_NONE,
+ &custom_element_change_events[CE_BY_DIRECT_ACTION],
+ NULL, NULL, "element changes by direct action"
},
{
ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(6),
- GADGET_ID_CHANGE_BY_COLLISION, GADGET_ID_NONE,
- &custom_element_change_events[CE_BY_COLLISION],
- NULL, NULL, "element changes by impact or smash"
- },
- {
- ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(7),
- GADGET_ID_CHANGE_BY_OTHER, GADGET_ID_NONE,
- &custom_element_change_events[CE_BY_OTHER],
+ GADGET_ID_CHANGE_BY_OTHER_ACT, GADGET_ID_NONE,
+ &custom_element_change_events[CE_BY_OTHER_ACTION],
NULL, NULL, "element changes by other element"
},
{
- ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(8),
+ ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(7),
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),
+ ED_SETTINGS_XPOS(1), ED_SETTINGS_YPOS(8),
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),
+ ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(10),
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),
+ ED_SETTINGS_XPOS(2), ED_SETTINGS_YPOS(11),
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"
},
{
- ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(13),
+ ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(12),
GADGET_ID_CUSTOM_USE_TEMPLATE, GADGET_ID_NONE,
&level.use_custom_template,
NULL, "use template", "use template for custom properties"
/* ---------- 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
/* ---------- 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
/* ---------- 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
/* ---------- 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
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 *);
static int element_shift = 0;
-static int editor_el_boulderdash[] =
+static int editor_hl_boulderdash[] =
{
EL_CHAR('B'),
EL_CHAR('O'),
EL_CHAR('A'),
EL_CHAR('S'),
EL_CHAR('H'),
+};
+static int editor_el_boulderdash[] =
+{
EL_PLAYER_1,
EL_EMPTY,
EL_SAND,
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'),
EL_CHAR('I'),
EL_CHAR('N'),
EL_CHAR('E'),
+};
+static int editor_el_emerald_mine[] =
+{
EL_PLAYER_1,
EL_PLAYER_2,
EL_PLAYER_3,
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,
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'),
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'),
EL_CHAR('L'),
EL_CHAR('E'),
EL_CHAR('X'),
+};
+static int editor_el_supaplex[] =
+{
EL_SP_EMPTY,
EL_SP_ZONK,
EL_SP_BASE,
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'),
EL_CHAR(' '),
EL_CHAR('I'),
EL_CHAR('I'),
+};
+static int editor_el_diamond_caves[] =
+{
EL_PEARL,
EL_CRYSTAL,
EL_WALL_PEARL,
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'),
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,
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('"'),
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'),
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,
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,
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 */
static struct
{
boolean *setup_value;
+
+ int *headline_list;
+ int *headline_list_size;
+
int *element_list;
int *element_list_size;
}
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
+ }
};
/* 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)
{
/* 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)
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;
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;
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)
{
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,
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,
}
}
+static void CreateTextAreaGadgets()
+{
+ int max_infotext_len = getMaxInfoTextLength();
+ int i;
+
+ for (i=0; i<ED_NUM_TEXTAREAS; i++)
+ {
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ int gd_x, gd_y;
+ struct GadgetInfo *gi;
+ unsigned long event_mask;
+ char infotext[MAX_OUTPUT_LINESIZE + 1];
+ int id = textarea_info[i].gadget_id;
+ int area_xsize = textarea_info[i].xsize;
+ int area_ysize = textarea_info[i].ysize;
+
+ event_mask = GD_EVENT_TEXT_LEAVING;
+
+ gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
+ gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
+
+ sprintf(infotext, "Enter %s", textarea_info[i].infotext);
+ infotext[max_infotext_len] = '\0';
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, infotext,
+ GDI_X, SX + textarea_info[i].x,
+ GDI_Y, SY + textarea_info[i].y,
+ GDI_TYPE, GD_TYPE_TEXT_AREA,
+ GDI_AREA_SIZE, area_xsize, area_ysize,
+ GDI_TEXT_FONT, FONT_INPUT_1,
+ GDI_TEXT_FONT_ACTIVE, FONT_INPUT_1_ACTIVE,
+ GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x, gd_y,
+ GDI_DESIGN_PRESSED, gd_bitmap, gd_x, gd_y,
+ GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
+ GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleTextAreaGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ }
+}
+
static void CreateSelectboxGadgets()
{
int max_infotext_len = getMaxInfoTextLength();
int max_infotext_len = getMaxInfoTextLength();
int i;
- for (i=0; i<ED_NUM_TEXTBUTTON; i++)
+ for (i=0; i<ED_NUM_TEXTBUTTONS; i++)
{
Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
int gd_x1, gd_x2, gd_y1, gd_y2;
x = (right_gadget_border[textbutton_info[i].gadget_id_align] +
ED_GADGET_TEXT_DISTANCE);
+ /* determine horizontal offset for leading text */
+ if (textbutton_info[i].text_left != NULL)
+ x += getTextWidthForGadget(textbutton_info[i].text_left);
+
gi = CreateGadget(GDI_CUSTOM_ID, id,
GDI_CUSTOM_TYPE_ID, i,
GDI_INFO_TEXT, infotext,
Error(ERR_EXIT, "cannot create gadget");
level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, textbutton_info[i].text_right);
+ }
+}
+
+static void CreateGraphicbuttonGadgets()
+{
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ struct GadgetInfo *gi;
+ unsigned long event_mask;
+ int i;
+
+ /* create buttons for scrolling of drawing area and element list */
+ for (i=0; i < ED_NUM_GRAPHICBUTTONS; i++)
+ {
+ int id = graphicbutton_info[i].gadget_id;
+ int gd_x1, gd_x2, gd_y1, gd_y2;
+ int x = SX + graphicbutton_info[i].x;
+ int y = SY + graphicbutton_info[i].y;
+
+ event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+
+ gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x;
+ gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x;
+ gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
+ gd_y2 = gd_y1;
+
+ /* determine horizontal position to the right of specified gadget */
+ if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
+ x = (right_gadget_border[graphicbutton_info[i].gadget_id_align] +
+ ED_GADGET_TEXT_DISTANCE);
+
+ /* determine horizontal offset for leading text */
+ if (graphicbutton_info[i].text_left != NULL)
+ x += getTextWidthForGadget(graphicbutton_info[i].text_left);
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, graphicbutton_info[i].infotext,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_WIDTH, graphicbutton_info[i].width,
+ GDI_HEIGHT, graphicbutton_info[i].height,
+ GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
+ GDI_STATE, GD_BUTTON_UNPRESSED,
+ GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
+ GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleGraphicbuttonGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, graphicbutton_info[i].text_right);
}
}
CreateCounterButtons();
CreateRadiobuttonGadgets();
CreateTextInputGadgets();
- CreateTextbuttonGadgets();
+ CreateTextAreaGadgets();
CreateSelectboxGadgets();
+ CreateGraphicbuttonGadgets();
+ CreateTextbuttonGadgets();
CreateDrawingAreas();
game_status = old_game_status;
static void MapTextInputGadget(int id)
{
struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
- char infotext[MAX_OUTPUT_LINESIZE + 1];
- int max_infotext_len = getMaxInfoTextLength();
int xoffset_above = 0;
int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
- int x = textinput_info[id].x + xoffset_above;
- int y = textinput_info[id].y + yoffset_above;
+ int x_above = textinput_info[id].x + xoffset_above;
+ int y_above = textinput_info[id].y + yoffset_above;
- if (textinput_info[id].infotext)
- {
- sprintf(infotext, "%s:", textinput_info[id].infotext);
- infotext[max_infotext_len] = '\0';
- DrawTextF(x, y, FONT_TEXT_1, infotext);
- }
+ if (textinput_info[id].text_above)
+ DrawTextF(x_above, y_above, FONT_TEXT_1, textinput_info[id].text_above);
ModifyGadget(gi, GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
MapGadget(gi);
}
+static void MapTextAreaGadget(int id)
+{
+ struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
+ int xoffset_above = 0;
+ int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
+ int x_above = textarea_info[id].x + xoffset_above;
+ int y_above = textarea_info[id].y + yoffset_above;
+
+ if (textarea_info[id].text_above)
+ DrawTextF(x_above, y_above, FONT_TEXT_1, textarea_info[id].text_above);
+
+ ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
+
+ MapGadget(gi);
+}
+
static void MapSelectboxGadget(int id)
{
struct GadgetInfo *gi = level_editor_gadget[selectbox_info[id].gadget_id];
static void MapTextbuttonGadget(int id)
{
struct GadgetInfo *gi = level_editor_gadget[textbutton_info[id].gadget_id];
+ int xoffset_left = getTextWidthForGadget(textbutton_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;
+
+ /* 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);
}
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);
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,
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;
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);
/* ---------- element settings: advanced (custom elements) --------------- */
- /* set change by player selectbox help value */
- 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 :
+ /* set "change by direct action" selectbox help value */
+ custom_element_change.direct_action =
+ (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_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);
-
- /* set change by collision selectbox help value */
- 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_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
HAS_CHANGE_EVENT(element, CE_COLLISION) ? CE_COLLISION :
- custom_element.change_collide_action);
+ HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
+ HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
+ custom_element_change.direct_action);
- /* set change by other element action selectbox help value */
- 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 :
- HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PRESSED) ? CE_OTHER_GETS_PRESSED :
+ /* set "change by other element action" selectbox help value */
+ custom_element_change.other_action =
+ (
HAS_CHANGE_EVENT(element, CE_OTHER_GETS_TOUCHED) ? CE_OTHER_GETS_TOUCHED :
- 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_GETS_PRESSED) ? CE_OTHER_GETS_PRESSED :
+ HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PUSHED) ? CE_OTHER_GETS_PUSHED :
+ HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DIGGED) ? CE_OTHER_GETS_DIGGED :
+ HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED :
+ HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DROPPED) ? CE_OTHER_GETS_DROPPED :
HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING :
- custom_element.change_other_action);
+ HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING :
+ HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING :
+ custom_element_change.other_action);
}
static void CopyCustomElementPropertiesToGame(int element)
}
element_info[element] = custom_element;
+ *element_info[element].change = custom_element_change;
/* ---------- element settings: configure (custom elements) ------------- */
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[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[CE_BY_COLLISION];
+ custom_element_change_events[custom_element_change.direct_action] =
+ custom_element_change_events[CE_BY_DIRECT_ACTION];
/* set other element action change event from checkbox and selectbox */
custom_element_change_events[CE_OTHER_IS_TOUCHING] = FALSE;
custom_element_change_events[CE_OTHER_GETS_TOUCHED] = FALSE;
custom_element_change_events[CE_OTHER_GETS_PRESSED] = FALSE;
custom_element_change_events[CE_OTHER_GETS_PUSHED] = FALSE;
+ custom_element_change_events[CE_OTHER_GETS_DIGGED] = 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[CE_BY_OTHER];
+ custom_element_change_events[custom_element_change.other_action] =
+ custom_element_change_events[CE_BY_OTHER_ACTION];
for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
SET_PROPERTY(element, i, custom_element_properties[i]);
/* copy change events also to special level editor variable */
custom_element = element_info[element];
+ custom_element_change = *element_info[element].change;
}
void DrawLevelEd()
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)
{
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);
}
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;
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++)
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 */
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();
}
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);
}
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 &&
}
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);
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;
{
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)
{
}
}
+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;
*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;
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)
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));
#define LEVEL_HEADER_UNUSED 13 /* unused level header bytes */
#define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */
#define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */
+#define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */
+#define LEVEL_CHUNK_CNT3_UNUSED 10 /* unused CNT3 chunk bytes */
#define LEVEL_CPART_CUS3_SIZE 134 /* size of CUS3 chunk part */
#define LEVEL_CPART_CUS3_UNUSED 15 /* unused CUS3 bytes / part */
+#define LEVEL_CPART_CUS4_SIZE ??? /* size of CUS4 chunk part */
+#define LEVEL_CPART_CUS4_UNUSED ??? /* unused CUS4 bytes / part */
#define TAPE_HEADER_SIZE 20 /* size of tape file header */
#define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */
-#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + x * LEVEL_CPART_CUS3_SIZE)
+#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
+#define LEVEL_CHUNK_CUS4_SIZE(x) (48 + 48 + (x) * 48)
/* file identifier strings */
#define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
/* 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->direct_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;
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; i<LEVEL_SCORE_ELEMENTS; i++)
level->score[i] = 10;
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; j<MAX_ELEMENT_NAME_LEN + 1; j++)
+ for(j=0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
element_info[element].description[j] = '\0';
if (element_info[element].custom_description != NULL)
strncpy(element_info[element].description,
for(y=0; y<3; y++)
element_info[element].content[x][y] = EL_EMPTY_SPACE;
- element_info[element].change.events = CE_BITMASK_DEFAULT;
- element_info[element].change.target_element = EL_EMPTY_SPACE;
-
- element_info[element].change.delay_fixed = 0;
- element_info[element].change.delay_random = 0;
- element_info[element].change.delay_frames = -1; /* use default */
-
- element_info[element].change.trigger_element = EL_EMPTY_SPACE;
-
- element_info[element].change.explode = FALSE;
- element_info[element].change.use_content = FALSE;
- element_info[element].change.only_complete = FALSE;
- element_info[element].change.use_random_change = FALSE;
- element_info[element].change.random = 0;
- element_info[element].change.power = CP_NON_DESTRUCTIVE;
-
- for(x=0; x<3; x++)
- for(y=0; y<3; y++)
- element_info[element].change.content[x][y] = EL_EMPTY_SPACE;
-
element_info[element].access_type = 0;
element_info[element].access_layer = 0;
element_info[element].walk_to_action = 0;
element_info[element].smash_targets = 0;
element_info[element].deadliness = 0;
element_info[element].consistency = 0;
- element_info[element].change_player_action = 0;
- element_info[element].change_collide_action = 0;
- element_info[element].change_other_action = 0;
element_info[element].can_explode_by_fire = FALSE;
element_info[element].can_explode_smashed = FALSE;
element_info[element].can_explode_impact = FALSE;
+ element_info[element].current_change_page = 0;
+
/* start with no properties at all */
for (j=0; j < NUM_EP_BITFIELDS; j++)
Properties[element][j] = EP_BITMASK_DEFAULT;
num_contents = getFile8Bit(file);
content_xsize = getFile8Bit(file);
content_ysize = getFile8Bit(file);
+
ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
return chunk_size;
}
+static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ int i;
+ int element;
+ int envelope_len;
+ int chunk_size_expected;
+
+ element = checkLevelElement(getFile16BitBE(file));
+ envelope_len = getFile16BitBE(file);
+ level->envelope_xsize = getFile8Bit(file);
+ level->envelope_ysize = getFile8Bit(file);
+
+ ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
+
+ chunk_size_expected = LEVEL_CHUNK_CNT3_HEADER + envelope_len;
+
+ if (chunk_size_expected != chunk_size)
+ {
+ ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
+ return chunk_size_expected;
+ }
+
+ for(i=0; i < envelope_len; i++)
+ level->envelope[i] = getFile8Bit(file);
+
+ return chunk_size;
+}
+
static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
{
int num_changed_custom_elements = getFile16BitBE(file);
int custom_target_element = getFile16BitBE(file);
if (IS_CUSTOM_ELEMENT(element))
- element_info[element].change.target_element = custom_target_element;
+ element_info[element].change->target_element = custom_target_element;
else
Error(ERR_WARN, "invalid custom element number %d", element);
}
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);
return chunk_size;
}
+static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ struct ElementInfo *ei;
+ int chunk_size_expected;
+ int element;
+ int i, x, y;
+
+ element = getFile16BitBE(file);
+
+ if (!IS_CUSTOM_ELEMENT(element))
+ {
+ Error(ERR_WARN, "invalid custom element number %d", element);
+
+ element = EL_DEFAULT; /* dummy element used for artwork config */
+ }
+
+ ei = &element_info[element];
+
+ for(i=0; i < MAX_ELEMENT_NAME_LEN; i++)
+ ei->description[i] = getFile8Bit(file);
+ ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+
+ Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
+ ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */
+
+ ei->num_change_pages = getFile8Bit(file);
+
+ /* some free bytes for future base property values and padding */
+ ReadUnusedBytesFromFile(file, 5);
+
+ chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
+ if (chunk_size_expected != chunk_size)
+ {
+ ReadUnusedBytesFromFile(file, chunk_size - 48);
+ return chunk_size_expected;
+ }
+
+ /* read custom property values */
+
+ ei->use_gfx_element = getFile8Bit(file);
+ ei->gfx_element = checkLevelElement(getFile16BitBE(file));
+
+ ei->collect_score = getFile8Bit(file);
+ ei->collect_count = getFile8Bit(file);
+
+ ei->push_delay_fixed = getFile16BitBE(file);
+ ei->push_delay_random = getFile16BitBE(file);
+ ei->move_delay_fixed = getFile16BitBE(file);
+ ei->move_delay_random = getFile16BitBE(file);
+
+ ei->move_pattern = getFile16BitBE(file);
+ ei->move_direction_initial = getFile8Bit(file);
+ ei->move_stepsize = getFile8Bit(file);
+
+ ei->slippery_type = getFile8Bit(file);
+
+ for(y=0; y<3; y++)
+ for(x=0; x<3; x++)
+ ei->content[x][y] = checkLevelElement(getFile16BitBE(file));
+
+ /* some free bytes for future custom property values and padding */
+ ReadUnusedBytesFromFile(file, 12);
+
+ /* read change property values */
+
+ for (i=0; i < ei->num_change_pages; i++)
+ {
+ struct ElementChangeInfo *change = &ei->change_page[i];
+
+ change->events = getFile32BitBE(file);
+
+ change->target_element = checkLevelElement(getFile16BitBE(file));
+
+ change->delay_fixed = getFile16BitBE(file);
+ change->delay_random = getFile16BitBE(file);
+ change->delay_frames = getFile16BitBE(file);
+
+ change->trigger_element = checkLevelElement(getFile16BitBE(file));
+
+ change->explode = getFile8Bit(file);
+ change->use_content = getFile8Bit(file);
+ change->only_complete = getFile8Bit(file);
+ change->use_random_change = getFile8Bit(file);
+
+ change->random = getFile8Bit(file);
+ change->power = getFile8Bit(file);
+
+ for(y=0; y<3; y++)
+ for(x=0; x<3; x++)
+ change->content[x][y] = checkLevelElement(getFile16BitBE(file));
+
+ change->can_change = getFile8Bit(file);
+
+ /* some free bytes for future change property values and padding */
+ ReadUnusedBytesFromFile(file, 9);
+ }
+
+ /* mark this custom element as modified */
+ ei->modified_settings = TRUE;
+
+ return chunk_size;
+}
+
void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
{
char cookie[MAX_LINE_LEN];
{ "BODY", -1, LoadLevel_BODY },
{ "CONT", -1, LoadLevel_CONT },
{ "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
+ { "CNT3", -1, LoadLevel_CNT3 },
{ "CUS1", -1, LoadLevel_CUS1 },
{ "CUS2", -1, LoadLevel_CUS2 },
{ "CUS3", -1, LoadLevel_CUS3 },
+ { "CUS4", -1, LoadLevel_CUS4 },
{ NULL, 0, NULL }
};
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 were 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 and copying events to be mapped is important */
+ for (j=CE_BY_OTHER_ACTION; 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 and copying 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);
+ }
+ }
+ }
+ }
+
+ /* some custom element change events get mapped since version 3.0.3 */
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+
+ if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER) ||
+ HAS_CHANGE_EVENT(element, CE_BY_COLLISION))
+ {
+ SET_CHANGE_EVENT(element, CE_BY_PLAYER, FALSE);
+ SET_CHANGE_EVENT(element, CE_BY_COLLISION, FALSE);
+
+ SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, 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; y<level->fieldy; y++)
+ {
+ for(x=0; x<level->fieldx; 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; x<MAX_LEV_FIELDX; x++)
+ for(y=0; y<MAX_LEV_FIELDY; y++)
+ Feld[x][y] = level->field[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;
}
}
+ /* 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; x<MAX_LEV_FIELDX; x++)
for(y=0; y<MAX_LEV_FIELDY; y++)
InitElementPropertiesEngine(level->game_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();
}
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)
putFile16BitBE(file, content_array[i][x][y]);
}
+static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
+{
+ int i;
+ int envelope_len = strlen(level->envelope) + 1;
+
+ putFile16BitBE(file, element);
+ putFile16BitBE(file, envelope_len);
+ putFile8Bit(file, level->envelope_xsize);
+ putFile8Bit(file, level->envelope_ysize);
+
+ WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
+
+ for(i=0; i < envelope_len; i++)
+ putFile8Bit(file, level->envelope[i]);
+}
+
#if 0
static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
int num_changed_custom_elements)
{
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++;
}
#endif
+#if 0
static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
int num_changed_custom_elements)
{
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);
if (check != num_changed_custom_elements) /* should not happen */
Error(ERR_WARN, "inconsistent number of custom element properties");
}
+#endif
+
+static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
+{
+ struct ElementInfo *ei = &element_info[element];
+ int i, x, y;
+
+ putFile16BitBE(file, element);
+
+ for(i=0; i < MAX_ELEMENT_NAME_LEN; i++)
+ putFile8Bit(file, ei->description[i]);
+
+ putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+ WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */
+
+ putFile8Bit(file, ei->num_change_pages);
+
+ /* some free bytes for future base property values and padding */
+ WriteUnusedBytesToFile(file, 5);
+
+ /* write custom property values */
+
+ putFile8Bit(file, ei->use_gfx_element);
+ putFile16BitBE(file, ei->gfx_element);
+
+ putFile8Bit(file, ei->collect_score);
+ putFile8Bit(file, ei->collect_count);
+
+ putFile16BitBE(file, ei->push_delay_fixed);
+ putFile16BitBE(file, ei->push_delay_random);
+ putFile16BitBE(file, ei->move_delay_fixed);
+ putFile16BitBE(file, ei->move_delay_random);
+
+ putFile16BitBE(file, ei->move_pattern);
+ putFile8Bit(file, ei->move_direction_initial);
+ putFile8Bit(file, ei->move_stepsize);
+
+ putFile8Bit(file, ei->slippery_type);
+
+ for(y=0; y<3; y++)
+ for(x=0; x<3; x++)
+ putFile16BitBE(file, ei->content[x][y]);
+
+ /* some free bytes for future custom property values and padding */
+ WriteUnusedBytesToFile(file, 12);
+
+ /* write change property values */
+
+ for (i=0; i < ei->num_change_pages; i++)
+ {
+ struct ElementChangeInfo *change = &ei->change_page[i];
+
+ putFile32BitBE(file, change->events);
+
+ putFile16BitBE(file, change->target_element);
+
+ putFile16BitBE(file, change->delay_fixed);
+ putFile16BitBE(file, change->delay_random);
+ putFile16BitBE(file, change->delay_frames);
+
+ putFile16BitBE(file, change->trigger_element);
+
+ putFile8Bit(file, change->explode);
+ putFile8Bit(file, change->use_content);
+ putFile8Bit(file, change->only_complete);
+ putFile8Bit(file, change->use_random_change);
+
+ putFile8Bit(file, change->random);
+ putFile8Bit(file, change->power);
+
+ for(y=0; y<3; y++)
+ for(x=0; x<3; x++)
+ putFile16BitBE(file, change->content[x][y]);
+
+ putFile8Bit(file, change->can_change);
+
+ /* some free bytes for future change property values and padding */
+ WriteUnusedBytesToFile(file, 9);
+ }
+}
static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
{
int body_chunk_size;
- int num_changed_custom_elements = 0;
- int level_chunk_CUS3_size;
int i, x, y;
FILE *file;
body_chunk_size =
level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
- /* check for non-standard custom elements and calculate "CUS3" chunk size */
- for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
- if (element_info[EL_CUSTOM_START + i].modified_settings)
- num_changed_custom_elements++;
- level_chunk_CUS3_size = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
-
putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
}
- if (num_changed_custom_elements > 0 && !level->use_custom_template)
+ /* check for envelope content */
+ if (strlen(level->envelope) > 0)
+ {
+ int envelope_len = strlen(level->envelope) + 1;
+
+ putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_HEADER + envelope_len);
+ SaveLevel_CNT3(file, level, EL_ENVELOPE);
+ }
+
+ /* check for non-default custom elements (unless using template level) */
+ if (!level->use_custom_template)
{
- putFileChunkBE(file, "CUS3", level_chunk_CUS3_size);
- SaveLevel_CUS3(file, level, num_changed_custom_elements);
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+
+ if (element_info[element].modified_settings)
+ {
+ int num_change_pages = element_info[element].num_change_pages;
+
+ putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
+ SaveLevel_CUS4(file, level, element);
+ }
+ }
}
fclose(file);
#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_CUSTOM_MORE 9
+#define SETUP_TOKEN_EDITOR_EL_HEADLINES 10
-#define NUM_EDITOR_SETUP_TOKENS 9
+#define NUM_EDITOR_SETUP_TOKENS 11
/* shortcut setup */
#define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
{ 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[] =
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;
#include "main.h"
+void setElementChangePages(struct ElementInfo *, int);
+void setElementChangeInfoToDefaults(struct ElementChangeInfo *);
+
boolean LevelFileExists(int);
void LoadLevelFromFilename(struct LevelInfo *, char *);
void LoadLevel(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);
void (*post_change_function)(int x, int y);
};
-static struct ChangingElementInfo changing_element_list[] =
+static struct ChangingElementInfo change_delay_list[] =
{
{
EL_NUT_BREAKING,
{ 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()
{
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 :
InitElementPropertiesEngine(game.engine_version);
#if 0
- printf("level %d: level version == %06d\n", level_nr, level.game_version);
- printf(" tape version == %06d [%s] [file: %06d]\n",
- tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
- tape.file_version);
- printf(" => game.engine_version == %06d\n", game.engine_version);
+ printf("level %d: level version == %06d\n", level_nr, level.game_version);
+ printf(" tape version == %06d [%s] [file: %06d]\n",
+ tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
+ tape.file_version);
+ printf(" => game.engine_version == %06d\n", game.engine_version);
#endif
/* ---------- initialize player's initial move delay --------------------- */
/* ---------- initialize changing elements ------------------------------- */
/* initialize changing elements information */
- for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ for (i=0; i < MAX_NUM_ELEMENTS; i++)
{
-#if 1
- element_info[i].change.pre_change_function = NULL;
- element_info[i].change.change_function = NULL;
- element_info[i].change.post_change_function = NULL;
+ struct ElementInfo *ei = &element_info[i];
+
+ /* this pointer might have been changed in the level editor */
+ ei->change = &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 ---------------------------------- */
for (i=0; i<MAX_NUM_ELEMENTS; i++)
trigger_events[i] = EP_BITMASK_DEFAULT;
+#if 1
+ /* add trigger events from element change event properties */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[i];
+
+ for (j=0; j < ei->num_change_pages; j++)
+ {
+ if (!ei->change_page->can_change)
+ continue;
+
+ if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION))
+ {
+ 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; i<MAX_NUM_ELEMENTS; i++)
- if (HAS_CHANGE_EVENT(i, CE_BY_OTHER))
- trigger_events[element_info[i].change.trigger_element] |=
- element_info[i].change.events;
+ if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION))
+ trigger_events[element_info[i].change->trigger_element] |=
+ element_info[i].change->events;
+#endif
/* ---------- initialize push delay -------------------------------------- */
JustStopped[x][y] = 0;
Stop[x][y] = FALSE;
Pushed[x][y] = FALSE;
- Changing[x][y] = FALSE;
+ Changed[x][y] = FALSE;
ExplodePhase[x][y] = 0;
ExplodeField[x][y] = EX_NO_EXPLOSION;
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;
+ }
}
}
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;
+ }
}
}
}
if (local_player->MovPos)
return;
+#if 1
+ if (tape.auto_play) /* tape might already be stopped here */
+ tape.auto_play_level_solved = TRUE;
+#else
if (tape.playing && tape.auto_play)
tape.auto_play_level_solved = TRUE;
+#endif
local_player->LevelSolved = FALSE;
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)
{
{
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
{
if (CAN_FALL(element) && y < lev_fieldy - 1)
{
- if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
+ if ((x > 0 && IS_PLAYER(x - 1, y)) ||
+ (x < lev_fieldx-1 && IS_PLAYER(x + 1, y)))
if (JustBeingPushed(x, y))
return;
Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
- if (DONT_COLLIDE_WITH(element) && IS_PLAYER(newx, newy) &&
+ if (DONT_COLLIDE_WITH(element) &&
+ IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) &&
!PLAYER_PROTECTED(newx, newy))
{
#if 1
{
/* 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);
RemoveField(x, y);
Feld[x][y] = target_element;
+ Changed[x][y] = TRUE; /* no more changes in this frame */
+
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
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;
+ struct ElementChangeInfo *change = &element_info[element].change_page[page];
- /* prevent CheckTriggeredElementChange() from looping */
- Changing[x][y] = TRUE;
+ Changed[x][y] = TRUE; /* no more changes in this frame */
CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING);
- Changing[x][y] = FALSE;
-
if (change->explode)
{
Bang(x, y);
something_has_changed = TRUE;
- /* for symmetry reasons, stop newly created border elements */
+ /* for symmetry reasons, freeze newly created border elements */
if (ex != x || ey != y)
- Stop[ex][ey] = TRUE;
+ Stop[ex][ey] = TRUE; /* no more moving in this frame */
}
}
}
}
-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]--;
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 */
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;
- for (i=0; i<MAX_NUM_ELEMENTS; i++)
+#if 0
+ /* prevent this function from running into a loop */
+ if (trigger_event == CE_OTHER_IS_CHANGING)
+ Changed[lx][ly] = TRUE;
+#endif
+
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
{
- if (!CAN_CHANGE(i) || !HAS_CHANGE_EVENT(i, trigger_event) ||
- element_info[i].change.trigger_element != trigger_element)
+ int element = EL_CUSTOM_START + i;
+
+#if 1
+ boolean change_element = FALSE;
+ int page;
+
+ if (!CAN_CHANGE(element) ||
+ !HAS_ANY_CHANGE_EVENT(element, trigger_event))
continue;
+ for (j=0; j < element_info[element].num_change_pages; j++)
+ {
+ if (element_info[element].change_page[j].trigger_element ==
+ trigger_element)
+ {
+ change_element = TRUE;
+ page = j;
+
+ break;
+ }
+ }
+
+ if (!change_element)
+ continue;
+
+#else
+ if (!CAN_CHANGE(element) ||
+ !HAS_ANY_CHANGE_EVENT(element, trigger_event) ||
+ element_info[element].change->trigger_element != trigger_element)
+ continue;
+#endif
+
for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
if (x == lx && y == ly) /* do not change trigger element itself */
continue;
- if (Changing[x][y]) /* do not change just changing elements */
+ if (Changed[x][y]) /* do not change already changed elements */
continue;
- if (Feld[x][y] == i)
+ if (Feld[x][y] == element)
{
ChangeDelay[x][y] = 1;
- ChangeElement(x, y);
+ ChangeElement(x, y, page);
+
+#if 0
+ Changed[x][y] = TRUE; /* prevent element from being changed again */
+#endif
}
}
}
+#if 0
+ /* reset change prevention array */
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ Changed[x][y] = FALSE;
+#endif
+
return TRUE;
}
-static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+static boolean CheckElementChangeExt(int x, int y, int element,
+ int trigger_event, int page)
{
- if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, trigger_event))
+ if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
return FALSE;
if (Feld[x][y] == EL_BLOCKED)
Blocked2Moving(x, y, &x, &y);
ChangeDelay[x][y] = 1;
- ChangeElement(x, y);
+ ChangeElement(x, y, page);
return TRUE;
}
+static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+{
+ int page = element_info[element].event_page_num[trigger_event];
+
+ return CheckElementChangeExt(x, y, element, trigger_event, page);
+}
+
static void PlayerActions(struct PlayerInfo *player, byte player_action)
{
static byte stored_player_action[MAX_PLAYERS];
CheckGravityMovement(player);
if (player->MovPos == 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;
for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
+ Changed[x][y] = FALSE;
+
Stop[x][y] = FALSE;
if (JustStopped[x][y] > 0)
JustStopped[x][y]--;
#if 1
/* reset finished pushing action (not done in ContinueMoving() to allow
- continous pushing animation for elements without push delay) */
+ continous pushing animation for elements with zero push delay) */
if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y))
{
ResetGfxAnimation(x, y);
/* 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]);
}
player->last_move_dir = player->MovDir;
player->is_moving = TRUE;
+#if 1
+ player->snapped = FALSE;
+#endif
}
else
{
void TestIfPlayerTouchesCustomElement(int x, int y)
{
+#if 0
static boolean check_changing = FALSE;
+#endif
static int xy[4][2] =
{
{ 0, -1 },
};
int i;
+#if 0
if (check_changing) /* prevent this function from running into a loop */
return;
check_changing = TRUE;
+#endif
for (i=0; i<4; i++)
{
}
}
+#if 0
check_changing = FALSE;
+#endif
}
void TestIfElementTouchesCustomElement(int x, int y)
{
+#if 0
static boolean check_changing = FALSE;
+#endif
static int xy[4][2] =
{
{ 0, -1 },
{ 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 0
if (check_changing) /* prevent this function from running into a loop */
return;
check_changing = TRUE;
+#endif
for (i=0; i<4; i++)
{
/* 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);
+#if 0
check_changing = FALSE;
+#endif
}
void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING);
+ CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED);
+
+ TestIfElementTouchesCustomElement(x, y);
+
break;
}
else if (IS_COLLECTIBLE(element))
el2edimg(EL_KEY_1 + key_nr));
redraw_mask |= REDRAW_DOOR_1;
}
+ else if (element == EL_ENVELOPE)
+ {
+ ShowEnvelope();
+ }
else if (IS_DROPPABLE(element)) /* can be collected and dropped */
{
int i;
CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED);
+ TestIfElementTouchesCustomElement(x, y);
+
break;
}
else if (IS_PUSHABLE(element))
{
player->is_digging = FALSE;
player->is_collecting = FALSE;
+#if 1
+ player->is_moving = FALSE;
+#endif
}
+#if 0
+ printf("::: trying to snap...\n");
+#endif
+
return FALSE;
}
player->MovDir = snap_direction;
+#if 1
+ player->is_digging = FALSE;
+ player->is_collecting = FALSE;
+#if 1
+ player->is_moving = FALSE;
+#endif
+#endif
+
if (DigField(player, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
return FALSE;
player->snapped = TRUE;
+#if 1
player->is_digging = FALSE;
player->is_collecting = FALSE;
+#if 1
+ player->is_moving = FALSE;
+#endif
+#endif
DrawLevelField(x, y);
BackToFront();
CheckTriggeredElementChange(jx, jy, new_element, CE_OTHER_GETS_DROPPED);
CheckElementChange(jx, jy, new_element, CE_DROPPED_BY_PLAYER);
+
+ TestIfElementTouchesCustomElement(jx, jy);
}
else /* player is dropping a dyna bomb */
{
{
for (act=0; act<NUM_ACTIONS; act++)
{
- if (graphic_info[element_info[i].graphic[act]].bitmap == NULL)
+ int graphic;
+
+ graphic = element_info[i].graphic[act];
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
element_info[i].graphic[act] = -1;
- if (graphic_info[element_info[i].crumbled[act]].bitmap == NULL)
+ graphic = element_info[i].crumbled[act];
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
element_info[i].crumbled[act] = -1;
for (dir=0; dir<NUM_DIRECTIONS; dir++)
{
- int graphic;
-
graphic = element_info[i].direction_graphic[act][dir];
- if (graphic_info[graphic].bitmap == NULL)
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
element_info[i].direction_graphic[act][dir] = -1;
graphic = element_info[i].direction_crumbled[act][dir];
- if (graphic_info[graphic].bitmap == NULL)
+ if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
element_info[i].direction_crumbled[act][dir] = -1;
}
}
graphic_info[graphic].offset_y = 0; /* ... will be corrected later */
graphic_info[graphic].crumbled_like = -1; /* do not use clone element */
graphic_info[graphic].diggable_like = -1; /* do not use clone element */
+ graphic_info[graphic].border_size = TILEX / 8; /* "CRUMBLED" border size */
/* optional x and y tile position of animation frame sequence */
if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
+ /* optional border size for "crumbling" diggable graphics */
+ if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
+ graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
+
/* this is only used for toon animations */
graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
graphic_info[graphic].step_delay = parameter[GFX_ARG_STEP_DELAY];
/* this is only used for drawing font characters */
graphic_info[graphic].draw_x = parameter[GFX_ARG_DRAW_XOFFSET];
graphic_info[graphic].draw_y = parameter[GFX_ARG_DRAW_YOFFSET];
+
+ /* this is only used for drawing envelope graphics */
+ graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
}
static void InitGraphicInfo()
graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
+#if 0
+ printf("::: graphic_info: %d entries\n", num_images);
+#endif
+
#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
if (clipmasks_initialized)
{
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
/* values for DrawGadget() */
#define DG_UNPRESSED 0
#define DG_PRESSED 1
+
#define DG_BUFFERED 0
#define DG_DIRECT 1
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;
}
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;
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);
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 */
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,
+ BLIT_ON_BACKGROUND);
+
+ 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;
/* 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)
{
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,
gi->active = (boolean)va_arg(ap, int);
break;
+ case GDI_DIRECT_DRAW:
+ /* take care here: "boolean" is typedef'ed as "unsigned char",
+ which gets promoted to "int" */
+ gi->direct_draw = (boolean)va_arg(ap, int);
+ break;
+
case GDI_CHECKED:
/* take care here: "boolean" is typedef'ed as "unsigned char",
which gets promoted to "int" */
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;
{
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;
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;
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:
/* 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);
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;
}
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)
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 :
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, ...)
void RedrawGadget(struct GadgetInfo *gi)
{
if (gi->mapped)
- DrawGadget(gi, gi->state, DG_DIRECT);
+ DrawGadget(gi, gi->state, gi->direct_draw);
}
struct GadgetInfo *CreateGadget(int first_tag, ...)
new_gadget->callback_info = default_callback_info;
new_gadget->callback_action = default_callback_action;
new_gadget->active = TRUE;
+ new_gadget->direct_draw = TRUE;
+
new_gadget->next = NULL;
va_start(ap, first_tag);
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) */
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)
last_mx = mx;
last_my = my;
- /* special treatment for text and number input gadgets */
- if (anyTextInputGadgetActive() && 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;
+ CheckRangeOfNumericInputGadget(last_gi); /* in case of numeric gadget */
- if (new_gi == last_gi)
- {
- int old_cursor_position = gi->text.cursor_position;
+ DrawGadget(last_gi, DG_UNPRESSED, last_gi->direct_draw);
- /* if mouse button pressed inside activated text gadget, set cursor */
- gi->text.cursor_position =
- (mx - gi->x - gi->border.xsize) / getFontWidth(gi->font);
+ last_gi->event.type = GD_EVENT_TEXT_LEAVING;
- 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 (last_gi->event_mask & GD_EVENT_TEXT_LEAVING)
+ last_gi->callback_action(last_gi);
- if (gi->text.cursor_position != old_cursor_position)
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
- }
- else
- {
- /* if mouse button pressed outside text input gadget, deactivate it */
- CheckRangeOfNumericInputGadget(gi);
- DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
-
- 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)
- {
- 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;
-
- if (gi->selectbox.current_index != old_index)
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
- }
- else
- {
- /* if mouse button pressed outside selectbox gadget, deactivate it */
- DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
-
- gi->event.type = GD_EVENT_TEXT_LEAVING;
-
- if (gi->event_mask & GD_EVENT_TEXT_LEAVING)
- gi->callback_action(gi);
-
- last_gi = NULL;
- }
+ last_gi = NULL;
}
gadget_pressed =
/* 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;
}
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;
gi->selectbox.current_index = gi->selectbox.num_values - 1;
if (gi->selectbox.current_index != old_index)
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
}
}
{
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;
rgi != gi)
{
rgi->checked = FALSE;
- DrawGadget(rgi, DG_UNPRESSED, DG_DIRECT);
+ DrawGadget(rgi, DG_UNPRESSED, rgi->direct_draw);
}
rgi = rgi->next;
}
}
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
gi->state = GD_BUTTON_PRESSED;
gi->event.type = GD_EVENT_PRESSED;
if (gi->type & GD_TYPE_BUTTON)
{
if (gadget_moving_inside && gi->state == GD_BUTTON_UNPRESSED)
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
else if (gadget_moving_off_borders && gi->state == GD_BUTTON_PRESSED)
- DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+ DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
}
else if (gi->type & GD_TYPE_SELECTBOX)
{
gi->selectbox.current_index = gi->selectbox.num_values - 1;
if (gi->selectbox.current_index != old_index)
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
}
else if (gi->type & GD_TYPE_SCROLLBAR)
{
changed_position = TRUE;
}
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
}
gi->state = (gadget_moving_inside || gi->type & GD_TYPE_SCROLLBAR ?
}
if (deactivate_gadget &&
- !(gi->type & GD_TYPE_TEXTINPUT)) /* text input stays open */
- DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+ !(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;
gi->event.type = GD_EVENT_RELEASED;
if (gadget_released_off_borders)
{
if (gi->type & GD_TYPE_SCROLLBAR)
- DrawGadget(gi, DG_UNPRESSED, DG_DIRECT);
+ DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
gi->event.type = GD_EVENT_RELEASED;
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, DG_DIRECT);
+ if (gi->type & GD_TYPE_TEXT_AREA)
+ {
+ insertCharIntoTextArea(gi, '\n');
+
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
+ }
+ else
+ {
+ DrawGadget(gi, DG_UNPRESSED, gi->direct_draw);
- gi->event.type = GD_EVENT_TEXT_RETURN;
+ 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, DG_DIRECT);
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
}
else if (key == KSYM_Left && cursor_pos > 0)
{
- gi->text.cursor_position--;
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ gi->textinput.cursor_position--;
+
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
}
else if (key == KSYM_Right && cursor_pos < text_length)
{
- gi->text.cursor_position++;
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ 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--;
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ 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]);
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+ 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);
}
}
else if (gi->type & GD_TYPE_SELECTBOX) /* only valid for selectbox */
if (key == KSYM_Up && index > 0)
{
gi->selectbox.current_index--;
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
}
else if (key == KSYM_Down && index < num_values - 1)
{
gi->selectbox.current_index++;
- DrawGadget(gi, DG_PRESSED, DG_DIRECT);
+
+ DrawGadget(gi, DG_PRESSED, gi->direct_draw);
}
}
}
#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 | \
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)
#define GDI_SCROLLBAR_ITEM_POSITION 39
#define GDI_INFO_TEXT 40
#define GDI_ACTIVE 41
+#define GDI_DIRECT_DRAW 42
typedef void (*gadget_function)(void *);
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 */
int radio_nr; /* number of radio button series */
boolean mapped; /* gadget is mapped on the screen */
boolean active; /* gadget is active */
+ boolean direct_draw; /* directly draw to frontbuffer */
int font; /* font to use when inactive */
int font_active; /* font to use when active */
struct GadgetBorder border; /* gadget border design */
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 */
return (access(filename, F_OK) == 0);
}
-boolean FileIsGraphic(char *filename)
+boolean fileHasPrefix(char *basename, char *prefix)
{
- if (strlen(filename) > 4 &&
- strcmp(&filename[strlen(filename) - 4], ".pcx") == 0)
+ static char *basename_lower = NULL;
+ int basename_length, prefix_length;
+
+ if (basename_lower != NULL)
+ free(basename_lower);
+
+ if (basename == NULL || prefix == NULL)
+ return FALSE;
+
+ basename_lower = getStringToLower(basename);
+ basename_length = strlen(basename_lower);
+ prefix_length = strlen(prefix);
+
+ if (basename_length > prefix_length + 1 &&
+ basename_lower[prefix_length] == '.' &&
+ strncmp(basename_lower, prefix, prefix_length) == 0)
return TRUE;
return FALSE;
}
-boolean FileIsSound(char *basename)
+boolean fileHasSuffix(char *basename, char *suffix)
{
- if (strlen(basename) > 4 &&
- strcmp(&basename[strlen(basename) - 4], ".wav") == 0)
+ static char *basename_lower = NULL;
+ int basename_length, suffix_length;
+
+ if (basename_lower != NULL)
+ free(basename_lower);
+
+ if (basename == NULL || suffix == NULL)
+ return FALSE;
+
+ basename_lower = getStringToLower(basename);
+ basename_length = strlen(basename_lower);
+ suffix_length = strlen(suffix);
+
+ if (basename_length > suffix_length + 1 &&
+ basename_lower[basename_length - suffix_length - 1] == '.' &&
+ strcmp(&basename_lower[basename_length - suffix_length], suffix) == 0)
return TRUE;
return FALSE;
}
-boolean FileIsMusic(char *basename)
+boolean FileIsGraphic(char *basename)
{
- /* "music" can be a WAV (loop) file or (if compiled with SDL) a MOD file */
+ return fileHasSuffix(basename, "pcx");
+}
+boolean FileIsSound(char *basename)
+{
+ return fileHasSuffix(basename, "wav");
+}
+
+boolean FileIsMusic(char *basename)
+{
if (FileIsSound(basename))
return TRUE;
#if defined(TARGET_SDL)
- if (strlen(basename) > 4 &&
- (strcmp(&basename[strlen(basename) - 4], ".mod") == 0 ||
- strcmp(&basename[strlen(basename) - 4], ".MOD") == 0 ||
- strncmp(basename, "mod.", 4) == 0 ||
- strncmp(basename, "MOD.", 4) == 0))
+ if (fileHasPrefix(basename, "mod") ||
+ fileHasSuffix(basename, "mod") ||
+ fileHasSuffix(basename, "s3m") ||
+ fileHasSuffix(basename, "it") ||
+ fileHasSuffix(basename, "xm") ||
+ fileHasSuffix(basename, "midi") ||
+ fileHasSuffix(basename, "mid") ||
+ fileHasSuffix(basename, "mp3") ||
+ fileHasSuffix(basename, "ogg"))
return TRUE;
#endif
void SDLSetMouseCursor(struct MouseCursorInfo *cursor_info)
{
static struct MouseCursorInfo *last_cursor_info = NULL;
+ static struct MouseCursorInfo *last_cursor_info2 = NULL;
static SDL_Cursor *cursor_default = NULL;
static SDL_Cursor *cursor_current = NULL;
+ /* if invoked for the first time, store the SDL default cursor */
if (cursor_default == NULL)
cursor_default = SDL_GetCursor();
+ /* only create new cursor if cursor info (custom only) has changed */
if (cursor_info != NULL && cursor_info != last_cursor_info)
{
cursor_current = create_cursor(cursor_info);
last_cursor_info = cursor_info;
}
- SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
+ /* only set new cursor if cursor info (custom or NULL) has changed */
+ if (cursor_info != last_cursor_info2)
+ SDL_SetCursor(cursor_info ? cursor_current : cursor_default);
+
+ last_cursor_info2 = cursor_info;
}
for (i=0; i<(depth + 1) * 3; i++)
printf(" ");
+#if 1
+ printf("filename == '%s' ['%s', '%s'] [%d])\n",
+ node->filename, node->fullpath, node->basepath, node->user_defined);
+#else
printf("filename == '%s' (%s) [%s] (%d)\n",
node->filename, node->name, node->identifier, node->sort_priority);
+#endif
if (node->node_group != NULL)
dumpTreeInfo(node->node_group, depth + 1);
#endif
}
+static void freeTreeInfo(TreeInfo *ldi)
+{
+ if (ldi->filename)
+ free(ldi->filename);
+ if (ldi->fullpath)
+ free(ldi->fullpath);
+ if (ldi->basepath)
+ free(ldi->basepath);
+ if (ldi->identifier)
+ free(ldi->identifier);
+
+ if (ldi->name)
+ free(ldi->name);
+ if (ldi->name_sorting)
+ free(ldi->name_sorting);
+ if (ldi->author)
+ free(ldi->author);
+
+ if (ldi->class_desc)
+ free(ldi->class_desc);
+
+ if (ldi->type == TREE_TYPE_LEVEL_DIR)
+ {
+ if (ldi->graphics_set)
+ free(ldi->graphics_set);
+ if (ldi->sounds_set)
+ free(ldi->sounds_set);
+ if (ldi->music_set)
+ free(ldi->music_set);
+
+ if (ldi->graphics_path)
+ free(ldi->graphics_path);
+ if (ldi->sounds_path)
+ free(ldi->sounds_path);
+ if (ldi->music_path)
+ free(ldi->music_path);
+ }
+}
+
void setSetupInfo(struct TokenInfo *token_info,
int token_nr, char *token_value)
{
ti_new->node_parent = node_parent;
ti_new->parent_link = TRUE;
+#if 1
+ setString(&ti_new->identifier, node_parent->identifier);
+ setString(&ti_new->name, ".. (parent directory)");
+ setString(&ti_new->name_sorting, ti_new->name);
+
+ setString(&ti_new->filename, "..");
+ setString(&ti_new->fullpath, node_parent->fullpath);
+
+ ti_new->sort_priority = node_parent->sort_priority;
+
+ setString(&ti_new->class_desc, getLevelClassDescription(ti_new));
+#else
ti_new->identifier = getStringCopy(node_parent->identifier);
ti_new->name = ".. (parent directory)";
ti_new->name_sorting = getStringCopy(ti_new->name);
ti_new->fullpath = getStringCopy(node_parent->fullpath);
ti_new->sort_priority = node_parent->sort_priority;
+
ti_new->class_desc = getLevelClassDescription(ti_new);
+#endif
pushTreeInfo(&node_parent->node_group, ti_new);
}
getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
*leveldir_new = ldi;
+#if 1
+ if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
+ setString(&leveldir_new->name, leveldir_new->filename);
+#else
if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
{
free(leveldir_new->name);
leveldir_new->name = getStringCopy(leveldir_new->filename);
}
+#endif
DrawInitText(leveldir_new->name, 150, FC_YELLOW);
if (node_parent == NULL) /* top level group */
{
- leveldir_new->basepath = level_directory;
- leveldir_new->fullpath = leveldir_new->filename;
+ leveldir_new->basepath = getStringCopy(level_directory);
+ leveldir_new->fullpath = getStringCopy(leveldir_new->filename);
}
else /* sub level group */
{
- leveldir_new->basepath = node_parent->basepath;
+ leveldir_new->basepath = getStringCopy(node_parent->basepath);
leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name);
}
leveldir_new->last_level =
leveldir_new->first_level + leveldir_new->levels - 1;
+#if 1
+ leveldir_new->user_defined =
+ (strcmp(leveldir_new->basepath, options.level_directory) != 0);
+#else
leveldir_new->user_defined =
(leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
+#endif
leveldir_new->color = LEVELCOLOR(leveldir_new);
+#if 1
+ setString(&leveldir_new->class_desc, getLevelClassDescription(leveldir_new));
+#else
leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
+#endif
leveldir_new->handicap_level = /* set handicap to default value */
(leveldir_new->user_defined ?
getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
*artwork_new = ldi;
+#if 1
+ if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
+ setString(&artwork_new->name, artwork_new->filename);
+#else
if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
{
free(artwork_new->name);
artwork_new->name = getStringCopy(artwork_new->filename);
}
+#endif
#if 0
DrawInitText(artwork_new->name, 150, FC_YELLOW);
artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name);
}
+#if 1
+ artwork_new->user_defined =
+ (strcmp(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)) != 0);
+#else
artwork_new->user_defined =
(artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE);
+#endif
/* (may use ".sort_priority" from "setup_file_hash" above) */
artwork_new->color = ARTWORKCOLOR(artwork_new);
+#if 1
+ setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new));
+#else
artwork_new->class_desc = getLevelClassDescription(artwork_new);
+#endif
if (setup_file_hash == NULL) /* (after determining ".user_defined") */
{
+#if 0
if (artwork_new->name != NULL)
+ {
free(artwork_new->name);
+ artwork_new->name = NULL;
+ }
+#endif
+
+#if 0
+ if (artwork_new->identifier != NULL)
+ {
+ free(artwork_new->identifier);
+ artwork_new->identifier = NULL;
+ }
+#endif
if (strcmp(artwork_new->filename, ".") == 0)
{
if (artwork_new->user_defined)
{
+#if 1
+ setString(&artwork_new->identifier, "private");
+#else
artwork_new->identifier = getStringCopy("private");
+#endif
artwork_new->sort_priority = ARTWORKCLASS_USER;
}
else
{
+#if 1
+ setString(&artwork_new->identifier, "classic");
+#else
artwork_new->identifier = getStringCopy("classic");
+#endif
artwork_new->sort_priority = ARTWORKCLASS_CLASSICS;
}
/* set to new values after changing ".sort_priority" */
artwork_new->color = ARTWORKCOLOR(artwork_new);
+#if 1
+ setString(&artwork_new->class_desc,
+ getLevelClassDescription(artwork_new));
+#else
artwork_new->class_desc = getLevelClassDescription(artwork_new);
+#endif
}
else
{
+#if 1
+ setString(&artwork_new->identifier, artwork_new->filename);
+#else
artwork_new->identifier = getStringCopy(artwork_new->filename);
+#endif
}
+#if 1
+ setString(&artwork_new->name, artwork_new->identifier);
+ setString(&artwork_new->name_sorting, artwork_new->name);
+#else
artwork_new->name = getStringCopy(artwork_new->identifier);
artwork_new->name_sorting = getStringCopy(artwork_new->name);
+#endif
}
DrawInitText(artwork_new->name, 150, FC_YELLOW);
setTreeInfoToDefaults(artwork_new, type);
+#if 1
+ setString(&artwork_new->filename, UNDEFINED_FILENAME);
+ setString(&artwork_new->fullpath, UNDEFINED_FILENAME);
+ setString(&artwork_new->basepath, UNDEFINED_FILENAME);
+
+ setString(&artwork_new->identifier, UNDEFINED_FILENAME);
+ setString(&artwork_new->name, UNDEFINED_FILENAME);
+ setString(&artwork_new->name_sorting, UNDEFINED_FILENAME);
+#else
artwork_new->filename = getStringCopy(UNDEFINED_FILENAME);
artwork_new->fullpath = getStringCopy(UNDEFINED_FILENAME);
artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME);
artwork_new->identifier = getStringCopy(UNDEFINED_FILENAME);
artwork_new->name = getStringCopy(UNDEFINED_FILENAME);
artwork_new->name_sorting = getStringCopy(UNDEFINED_FILENAME);
+#endif
return artwork_new;
}
static void SaveUserLevelInfo()
{
+ LevelDirTree *level_info;
char *filename;
FILE *file;
int i;
return;
}
+ level_info = newTreeInfo();
+
/* always start with reliable default values */
- setTreeInfoToDefaults(&ldi, TREE_TYPE_LEVEL_DIR);
+ setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR);
-#if 0
- /* !!! FIX ME !!! */
- setString(&ldi.name, getLoginName());
- setString(&ldi.author, getRealName());
- ldi.levels = 100;
- ldi.first_level = 1;
- ldi.sort_priority = LEVELCLASS_USER_START;
- ldi.readonly = FALSE;
- setString(&ldi.graphics_set, GFX_CLASSIC_SUBDIR);
- setString(&ldi.sounds_set, SND_CLASSIC_SUBDIR);
- setString(&ldi.music_set, MUS_CLASSIC_SUBDIR);
+#if 1
+ setString(&level_info->name, getLoginName());
+ setString(&level_info->author, getRealName());
+ level_info->levels = 100;
+ level_info->first_level = 1;
+ level_info->sort_priority = LEVELCLASS_USER_START;
+ level_info->readonly = FALSE;
+ setString(&level_info->graphics_set, GFX_CLASSIC_SUBDIR);
+ setString(&level_info->sounds_set, SND_CLASSIC_SUBDIR);
+ setString(&level_info->music_set, MUS_CLASSIC_SUBDIR);
#else
ldi.name = getStringCopy(getLoginName());
ldi.author = getStringCopy(getRealName());
fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
getCookie("LEVELINFO")));
+ ldi = *level_info;
for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
if (i != LEVELINFO_TOKEN_IDENTIFIER &&
i != LEVELINFO_TOKEN_NAME_SORTING &&
fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
fclose(file);
- free(filename);
SetFilePermissions(filename, PERMS_PRIVATE);
+
+ freeTreeInfo(level_info);
+ free(filename);
}
char *getSetupValue(int type, void *value)
level_subdir));
fclose(file);
- free(filename);
SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
}
static void checkSeriesInfo()
handicap_level_str));
fclose(file);
- free(filename);
SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
}
/* "ioctl()" expects pointer to 'int' value for stereo flag
(boolean is defined as 'char', which will not work here) */
unsigned int fragment_spec = 0;
- int fragment_size_query;
+ int fragment_size_query = -1;
int stereo = TRUE;
struct
{
if (leveldir_current == NULL) /* should never happen */
Error(ERR_EXIT, "leveldir_current == NULL");
+ memset(&snd_ctrl, 0, sizeof(SoundControl)); /* to make valgrind happy */
+
snd_ctrl.active = FALSE;
snd_ctrl.state = type;
snd_ctrl.data_len = strlen(set_identifier) + 1;
else if (stereo_position > SOUND_MAX_RIGHT)
stereo_position = SOUND_MAX_RIGHT;
+ memset(&snd_ctrl, 0, sizeof(SoundControl)); /* to make valgrind happy */
+
snd_ctrl.active = TRUE;
snd_ctrl.nr = nr;
snd_ctrl.volume = volume;
if (!audio.sound_available)
return;
+ memset(&snd_ctrl, 0, sizeof(SoundControl)); /* to make valgrind happy */
+
snd_ctrl.active = FALSE;
snd_ctrl.nr = nr;
snd_ctrl.state = state;
boolean el_chars;
boolean el_custom;
boolean el_custom_more;
+
+ boolean el_headlines;
};
struct SetupShortcutInfo
{
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 */
dst_x += font_width;
}
}
+
+void DrawTextToTextArea(int x, int y, char *text, int font_nr,
+ int area_xsize, int area_ysize, int mask_mode)
+{
+ 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';
+
+ DrawTextExt(drawto, x, y + area_line * font_height, buffer, font_nr,
+ mask_mode);
+
+ area_line++;
+ }
+
+ redraw_mask |= REDRAW_FIELD;
+}
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, int);
#endif /* TEXT_H */
/* toon animation functions */
/* ========================================================================= */
-static int get_toon_direction(char *direction_raw)
+static int get_toon_direction(char *direction_string_raw)
{
- static char *direction = NULL;
+ char *direction_string = getStringToLower(direction_string_raw);
+ int direction = (strcmp(direction_string, "left") == 0 ? MV_LEFT :
+ strcmp(direction_string, "right") == 0 ? MV_RIGHT :
+ strcmp(direction_string, "up") == 0 ? MV_UP :
+ strcmp(direction_string, "down") == 0 ? MV_DOWN :
+ MV_NO_MOVING);
- /* !!! MEMORY LEAK HERE! FIX IT! !!! */
- setString(&direction, getStringToLower(direction_raw));
+ free(direction_string);
- return (strcmp(direction, "left") == 0 ? MV_LEFT :
- strcmp(direction, "right") == 0 ? MV_RIGHT :
- strcmp(direction, "up") == 0 ? MV_UP :
- strcmp(direction, "down") == 0 ? MV_DOWN : MV_NO_MOVING);
+ return direction;
}
void InitToonScreen(Bitmap *save_buffer,
{
static unsigned long animstart_delay = -1;
static unsigned long animstart_delay_value = 0;
+ static boolean anim_running = FALSE;
static boolean anim_restart = TRUE;
static boolean reset_delay = TRUE;
static int toon_nr = 0;
{
case ANIM_START:
screen_info.prepare_backbuffer_function();
+
+ anim_running = TRUE;
anim_restart = TRUE;
reset_delay = TRUE;
return;
case ANIM_CONTINUE:
+ if (!anim_running)
+ return;
+
break;
case ANIM_STOP:
screen_info.update_function();
setup.direct_draw = draw_mode;
+ anim_running = FALSE;
+
return;
default:
short Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
boolean Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-boolean Changing[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+boolean Changed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
short JustStopped[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
short AmoebaCnt[MAX_NUM_AMOEBA];
{ ".EDITOR", GAME_MODE_EDITOR, },
{ ".INFO", GAME_MODE_INFO, },
{ ".SETUP", GAME_MODE_SETUP, },
+ { ".PLAYING", GAME_MODE_PLAYING, },
{ ".DOOR", GAME_MODE_PSEUDO_DOOR, },
{ ".PREVIEW", GAME_MODE_PSEUDO_PREVIEW, },
{ ".CRUMBLED", GAME_MODE_PSEUDO_CRUMBLED, },
#define CE_OTHER_GETS_PUSHED 13
#define CE_OTHER_GETS_COLLECTED 14
#define CE_OTHER_GETS_DROPPED 15
+#define CE_BY_PLAYER 16 /* obsolete; map'd to CE_BY_DIRECT_ACTION */
+#define CE_BY_COLLISION 17 /* obsolete; map'd to CE_BY_DIRECT_ACTION */
+#define CE_BY_OTHER_ACTION 18 /* activates other element events */
+#define CE_BY_DIRECT_ACTION 19 /* activates direct element events */
+#define CE_OTHER_GETS_DIGGED 20
-/* values for activating change events (also stored in level file!) */
-#define CE_BY_PLAYER 16
-#define CE_BY_COLLISION 17
-#define CE_BY_OTHER 18
-
-#define NUM_CHANGE_EVENTS 19
+#define NUM_CHANGE_EVENTS 21
#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)) : \
#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
#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
#define GFX_SPECIAL_ARG_EDITOR 3
#define GFX_SPECIAL_ARG_INFO 4
#define GFX_SPECIAL_ARG_SETUP 5
-#define GFX_SPECIAL_ARG_DOOR 6
-#define GFX_SPECIAL_ARG_PREVIEW 7
-#define GFX_SPECIAL_ARG_CRUMBLED 8
+#define GFX_SPECIAL_ARG_PLAYING 6
+#define GFX_SPECIAL_ARG_DOOR 7
+#define GFX_SPECIAL_ARG_PREVIEW 8
+#define GFX_SPECIAL_ARG_CRUMBLED 9
-#define NUM_SPECIAL_GFX_ARGS 9
+#define NUM_SPECIAL_GFX_ARGS 10
/* values for image configuration suffixes */
#define GFX_ARG_GLOBAL_SYNC 15
#define GFX_ARG_CRUMBLED_LIKE 16
#define GFX_ARG_DIGGABLE_LIKE 17
-#define GFX_ARG_STEP_OFFSET 18
-#define GFX_ARG_STEP_DELAY 19
-#define GFX_ARG_DIRECTION 20
-#define GFX_ARG_POSITION 21
-#define GFX_ARG_DRAW_XOFFSET 22
-#define GFX_ARG_DRAW_YOFFSET 23
-#define GFX_ARG_NAME 24
+#define GFX_ARG_BORDER_SIZE 18
+#define GFX_ARG_STEP_OFFSET 19
+#define GFX_ARG_STEP_DELAY 20
+#define GFX_ARG_DIRECTION 21
+#define GFX_ARG_POSITION 22
+#define GFX_ARG_DRAW_XOFFSET 23
+#define GFX_ARG_DRAW_YOFFSET 24
+#define GFX_ARG_DRAW_MASKED 25
+#define GFX_ARG_NAME 26
-#define NUM_GFX_ARGS 25
+#define NUM_GFX_ARGS 27
/* values for sound configuration suffixes */
#define GAME_MODE_EDITOR 3
#define GAME_MODE_INFO 4
#define GAME_MODE_SETUP 5
-#define GAME_MODE_PSEUDO_DOOR 6
-#define GAME_MODE_PSEUDO_PREVIEW 7
-#define GAME_MODE_PSEUDO_CRUMBLED 8
+#define GAME_MODE_PLAYING 6
+#define GAME_MODE_PSEUDO_DOOR 7
+#define GAME_MODE_PSEUDO_PREVIEW 8
+#define GAME_MODE_PSEUDO_CRUMBLED 9
/* there are no special config file suffixes for these modes */
-#define GAME_MODE_PLAYING 9
#define GAME_MODE_PSEUDO_TYPENAME 10
#define GAME_MODE_QUIT 11
#define PROGRAM_VERSION_MAJOR 3
#define PROGRAM_VERSION_MINOR 0
-#define PROGRAM_VERSION_PATCH 2
+#define PROGRAM_VERSION_PATCH 3
#define PROGRAM_VERSION_RELEASE 0
-#define PROGRAM_VERSION_STRING "3.0.2"
+#define PROGRAM_VERSION_STRING "3.0.3"
#define PROGRAM_TITLE_STRING "Rocks'n'Diamonds"
#define PROGRAM_AUTHOR_STRING "Holger Schemel"
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;
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
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 */
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 direct_action; /* change triggered by actions on element */
+ int other_action; /* change triggered by other element actions */
};
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 ---------- */
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 */
boolean anim_global_sync;
int crumbled_like; /* element for cloning crumble graphics */
int diggable_like; /* element for cloning digging graphics */
+ int border_size; /* border size for "crumbled" graphics */
int step_offset; /* optional step offset of toon animations */
int step_delay; /* optional step delay of toon animations */
int draw_x, draw_y; /* optional offset for drawing fonts chars */
+ int draw_masked; /* optional setting for drawing envelope gfx */
+
#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
Pixmap clip_mask; /* single-graphic-only clip mask for X11 */
GC clip_gc; /* single-graphic-only clip gc for X11 */
extern short Back[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
extern boolean Stop[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
extern boolean Pushed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern boolean Changing[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+extern boolean Changed[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
extern short JustStopped[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
extern short AmoebaNr[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
extern short AmoebaCnt[MAX_NUM_AMOEBA];
void HandleMainMenu(int mx, int my, int dx, int dy, int button)
{
- static int choice = 0;
+ static int choice = 5;
int x = 0;
int y = choice;
}
}
- BackToFront();
-
out:
if (game_status == GAME_MODE_MAIN)
DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, FALSE);
DoAnimation();
}
+
+ BackToFront();
}
#else
PlaySound_Menu_Continue(SND_BACKGROUND_INFO);
#endif
-
- DoAnimation();
}
+ DoAnimation();
BackToFront();
}
}
}
- BackToFront();
-
+#if 0
if (game_status == GAME_MODE_LEVELS || game_status == GAME_MODE_SETUP)
DoAnimation();
+
+ BackToFront();
+#endif
}
void DrawChooseLevel()
void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
{
HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
+
+ DoAnimation();
+ BackToFront();
}
void DrawHallOfFame(int highlight_position)
DrawText(mSX + dx2, sy, highscore[entry].Name, font_nr2);
DrawText(mSX + dx3, sy, int2str(highscore[entry].Score, 5), font_nr4);
}
+
+ redraw_mask |= REDRAW_FIELD;
}
void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
first_entry = 0;
drawHallOfFameList(first_entry, highlight_position);
-
- return;
}
}
else if (dy > 0)
first_entry = MAX(0, MAX_SCORE_ENTRIES - NUM_MENU_ENTRIES_ON_SCREEN);
drawHallOfFameList(first_entry, highlight_position);
-
- return;
}
}
-
- if (button_released)
+ else if (button_released)
{
FadeSound(SND_BACKGROUND_SCORES);
game_status = GAME_MODE_MAIN;
DrawMainMenu();
}
- BackToFront();
-
- if (game_status == GAME_MODE_SCORES)
- {
- DoAnimation();
#if 1
+ if (game_status == GAME_MODE_SCORES)
PlaySound_Menu_Continue(SND_BACKGROUND_SCORES);
#endif
- }
+
+ DoAnimation();
+ BackToFront();
}
{ 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 }
};
}
}
- BackToFront();
DoAnimation();
+ BackToFront();
/* don't eat all CPU time */
Delay(10);
}
}
+#if 0
BackToFront();
if (game_status == GAME_MODE_SETUP)
DoAnimation();
+#endif
}
void DrawSetupScreen_Input()
static unsigned long delay = 0;
if (!DelayReached(&delay, GADGET_FRAME_DELAY))
+#if 1
+ return;
+#else
goto out;
+#endif
player_nr = (player_nr + (x == 10 ? -1 : +1) + MAX_PLAYERS) % MAX_PLAYERS;
}
}
+#if 0
BackToFront();
out:
if (game_status == GAME_MODE_SETUP)
DoAnimation();
+#endif
}
void CustomizeKeyboard(int player_nr)
}
}
- BackToFront();
DoAnimation();
+ BackToFront();
/* don't eat all CPU time */
Delay(10);
}
- BackToFront();
DoAnimation();
+ BackToFront();
/* don't eat all CPU time */
Delay(10);
HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
else
HandleSetupScreen_Generic(mx, my, dx, dy, button);
+
+ DoAnimation();
+ BackToFront();
}
void HandleGameActions()
GDI_STATE, GD_BUTTON_UNPRESSED,
GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
+ GDI_DIRECT_DRAW, FALSE,
GDI_EVENT_MASK, event_mask,
GDI_CALLBACK_ACTION, HandleScreenGadgets,
GDI_END);
GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
+ GDI_DIRECT_DRAW, FALSE,
GDI_EVENT_MASK, event_mask,
GDI_CALLBACK_ACTION, HandleScreenGadgets,
GDI_END);
player->is_moving ? ACTION_MOVING :
player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
+#if 0
+ printf("::: '%s'\n", element_action_info[action].suffix);
+#endif
+
InitPlayerGfxAnimation(player, action, move_dir);
/* ----------------------------------------------------------------------- */
int sx = SCREENX(x), sy = SCREENY(y);
int element;
int width, height, cx, cy, i;
+#if 1
+ int crumbled_border_size = graphic_info[graphic].border_size;
+#else
int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
+#endif
static int xy[4][2] =
{
{ 0, -1 },
if (i == 1 || i == 2)
{
- width = snip;
+ width = crumbled_border_size;
height = TILEY;
- cx = (i == 2 ? TILEX - snip : 0);
+ cx = (i == 2 ? TILEX - crumbled_border_size : 0);
cy = 0;
}
else
{
width = TILEX;
- height = snip;
+ height = crumbled_border_size;
cx = 0;
- cy = (i == 3 ? TILEY - snip : 0);
+ cy = (i == 3 ? TILEY - crumbled_border_size : 0);
}
BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
if (i == 1 || i == 2)
{
- width = snip;
+ width = crumbled_border_size;
height = TILEY;
- cx = (i == 1 ? TILEX - snip : 0);
+ cx = (i == 1 ? TILEX - crumbled_border_size : 0);
cy = 0;
}
else
{
width = TILEX;
- height = snip;
+ height = crumbled_border_size;
cx = 0;
- cy = (i==0 ? TILEY-snip : 0);
+ cy = (i == 0 ? TILEY - crumbled_border_size : 0);
}
BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
{ EL_STEELWALL, EL_INVISIBLE_STEELWALL }
};
int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
- int steel_position = (x == -1 && y == -1 ? 0 :
- x == lev_fieldx && y == -1 ? 1 :
- x == -1 && y == lev_fieldy ? 2 :
- x == lev_fieldx && y == lev_fieldy ? 3 :
- x == -1 || x == lev_fieldx ? 4 :
- y == -1 || y == lev_fieldy ? 5 : 6);
+ int steel_position = (x == -1 && y == -1 ? 0 :
+ x == lev_fieldx && y == -1 ? 1 :
+ x == -1 && y == lev_fieldy ? 2 :
+ x == lev_fieldx && y == lev_fieldy ? 3 :
+ x == -1 || x == lev_fieldx ? 4 :
+ y == -1 || y == lev_fieldy ? 5 : 6);
return border[steel_position][steel_type];
}
DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
}
+#if 1
+void DrawEnvelopeBackground(int startx, int starty, int x, int y,
+ int xsize, int ysize, int font_nr)
+{
+ int font_width = getFontWidth(font_nr);
+ int font_height = getFontHeight(font_nr);
+ int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
+ Bitmap *src_bitmap;
+ int src_x, src_y;
+ int dst_x = SX + startx + x * font_width;
+ int dst_y = SY + starty + y * font_height;
+ int width = graphic_info[graphic].width;
+ int height = graphic_info[graphic].height;
+ int inner_width = MAX(width - 2 * font_width, font_width);
+ int inner_height = MAX(height - 2 * font_height, font_height);
+ int inner_sx = (width >= 3 * font_width ? font_width : 0);
+ int inner_sy = (height >= 3 * font_height ? font_height : 0);
+ boolean draw_masked = graphic_info[graphic].draw_masked;
+
+ getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+
+ if (src_bitmap == NULL || width < font_width || height < font_height)
+ {
+ ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
+ return;
+ }
+
+ src_x += (x == 0 ? 0 : x == xsize - 1 ? width - font_width :
+ inner_sx + (x - 1) * font_width % inner_width);
+ src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
+ inner_sy + (y - 1) * font_height % inner_height);
+
+ if (draw_masked)
+ {
+ SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
+ dst_x - src_x, dst_y - src_y);
+ BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
+ dst_x, dst_y);
+ }
+ else
+ BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
+ dst_x, dst_y);
+}
+
+#else
+
+void DrawEnvelopeBackground(int dst_x, int dst_y, int ex, int ey, int font_nr)
+{
+ int font_width = getFontWidth(font_nr);
+ int font_height = getFontHeight(font_nr);
+ int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
+ Bitmap *src_bitmap;
+ int src_x, src_y;
+ int width = graphic_info[graphic].width;
+ int height = graphic_info[graphic].height;
+ boolean draw_masked = graphic_info[graphic].draw_masked;
+
+ getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
+
+ if (src_bitmap == NULL)
+ {
+ ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
+ return;
+ }
+
+ src_x += (ex == -1 ? 0 : ex == +1 ? width - font_width : font_width);
+ src_y += (ey == -1 ? 0 : ey == +1 ? height - font_height : font_height);
+
+ if (draw_masked)
+ {
+ SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
+ dst_x - src_x, dst_y - src_y);
+ BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
+ dst_x, dst_y);
+ }
+ else
+ BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
+ dst_x, dst_y);
+}
+#endif
+
+void ShowEnvelope()
+{
+ int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
+ boolean draw_masked = graphic_info[graphic].draw_masked;
+ int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
+ int font_nr = FONT_TEXT_1;
+ int font_width = getFontWidth(font_nr);
+ int font_height = getFontHeight(font_nr);
+ boolean ffwd_delay = (tape.playing && tape.fast_forward);
+ int anim_delay = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+ int wait_delay = (ffwd_delay ? 500 : 1000);
+ int i, x, y;
+
+ /* open envelope window horizontally */
+ for (i = 0; i <= level.envelope_xsize; i++)
+ {
+ int xsize = i + 2;
+ int ysize = 2;
+ int startx = (SXSIZE - xsize * font_width) / 2;
+ int starty = (SYSIZE - ysize * font_height) / 2;
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+#if 1
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
+#else
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ {
+ int sx = SX + startx + x * font_width;
+ int sy = SY + starty + y * font_height;
+ int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
+ int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
+
+ DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
+ }
+#endif
+
+ redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ BackToFront();
+
+ Delay(anim_delay);
+ }
+
+ /* open envelope window vertically */
+ for (i = 0; i <= level.envelope_ysize; i++)
+ {
+ int xsize = level.envelope_xsize + 2;
+ int ysize = i + 2;
+ int startx = (SXSIZE - xsize * font_width) / 2;
+ int starty = (SYSIZE - ysize * font_height) / 2;
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+#if 1
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
+#else
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ {
+ int sx = SX + startx + x * font_width;
+ int sy = SY + starty + y * font_height;
+ int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
+ int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
+
+ DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
+ }
+#endif
+
+ DrawTextToTextArea(SX + startx + font_width,
+ SY + starty + font_height, level.envelope,
+ FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
+
+ redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ BackToFront();
+
+ Delay(anim_delay);
+ }
+
+ if (tape.playing)
+ Delay(wait_delay);
+ else
+ WaitForEventToContinue();
+
+ /* close envelope window vertically */
+ for (i = level.envelope_ysize; i >= 0; i--)
+ {
+ int xsize = level.envelope_xsize + 2;
+ int ysize = i + 2;
+ int startx = (SXSIZE - xsize * font_width) / 2;
+ int starty = (SYSIZE - ysize * font_height) / 2;
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+#if 1
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
+#else
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ {
+ int sx = SX + startx + x * font_width;
+ int sy = SY + starty + y * font_height;
+ int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
+ int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
+
+ DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
+ }
+#endif
+
+ DrawTextToTextArea(SX + startx + font_width,
+ SY + starty + font_height, level.envelope,
+ FONT_TEXT_1, level.envelope_xsize, i, mask_mode);
+
+ redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ BackToFront();
+
+ Delay(anim_delay);
+ }
+
+ /* close envelope window horizontally */
+ for (i = level.envelope_xsize; i >= 0; i--)
+ {
+ int xsize = i + 2;
+ int ysize = 2;
+ int startx = (SXSIZE - xsize * font_width) / 2;
+ int starty = (SYSIZE - ysize * font_height) / 2;
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
+
+ SetDrawtoField(DRAW_BACKBUFFER);
+
+#if 1
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ DrawEnvelopeBackground(startx, starty, x, y, xsize, ysize, font_nr);
+#else
+ for (y=0; y < ysize; y++) for (x=0; x < xsize; x++)
+ {
+ int sx = SX + startx + x * font_width;
+ int sy = SY + starty + y * font_height;
+ int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
+ int ey = (y == 0 ? -1 : y == ysize - 1 ? +1 : 0);
+
+ DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
+ }
+#endif
+
+ redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
+ BackToFront();
+
+ Delay(anim_delay);
+ }
+
+ SetDrawtoField(DRAW_BUFFERED);
+
+ redraw_mask |= REDRAW_FIELD;
+ BackToFront();
+}
+
void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
{
Bitmap *src_bitmap = graphic_info[graphic].bitmap;
game_status = last_game_status; /* restore current game status */
}
-int REQ_in_range(int x, int y)
+void WaitForEventToContinue()
{
- if (y > DY+249 && y < DY+278)
+ boolean still_wait = TRUE;
+
+ /* simulate releasing mouse button over last gadget, if still pressed */
+ if (button_status)
+ HandleGadgets(-1, -1, 0);
+
+ button_status = MB_RELEASED;
+
+ while (still_wait)
{
- if (x > DX+1 && x < DX+48)
- return 1;
- else if (x > DX+51 && x < DX+98)
- return 2;
+ if (PendingEvent())
+ {
+ Event event;
+
+ NextEvent(&event);
+
+ switch (event.type)
+ {
+ case EVENT_BUTTONPRESS:
+ case EVENT_KEYPRESS:
+ still_wait = FALSE;
+ break;
+
+ case EVENT_KEYRELEASE:
+ ClearPlayerAction();
+ break;
+
+ default:
+ HandleOtherEvents(&event);
+ break;
+ }
+ }
+ else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
+ {
+ still_wait = FALSE;
+ }
+
+ DoAnimation();
+
+ /* don't eat all CPU time */
+ Delay(10);
}
- return 0;
}
#define MAX_REQUEST_LINES 13
unsigned int old_door_state;
int last_game_status = game_status; /* save current game status */
+#if 1
+ SetMouseCursor(CURSOR_DEFAULT);
+#endif
+
#if defined(PLATFORM_UNIX)
/* pause network game while waiting for request to answer */
if (options.network &&
SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
+#if 0
SetMouseCursor(CURSOR_DEFAULT);
+#endif
while(result < 0)
{
void DrawMiniElement(int, int, int);
void DrawMiniElementOrWall(int, int, int, int);
+void ShowEnvelope();
+
void getMicroGraphicSource(int, Bitmap **, int *, int *);
void DrawMicroElement(int, int, int);
void DrawLevel(void);
void DrawMiniLevel(int, int, int, int);
void DrawMicroLevel(int, int, boolean);
+void WaitForEventToContinue();
boolean Request(char *, unsigned int);
unsigned int OpenDoor(unsigned int);
unsigned int CloseDoor(unsigned int);