GADGET_ID_INVENTORY_SIZE_DOWN,
GADGET_ID_INVENTORY_SIZE_TEXT,
GADGET_ID_INVENTORY_SIZE_UP,
+ GADGET_ID_MM_BALL_CONTENT_DOWN,
+ GADGET_ID_MM_BALL_CONTENT_TEXT,
+ GADGET_ID_MM_BALL_CONTENT_UP,
GADGET_ID_CUSTOM_SCORE_DOWN,
GADGET_ID_CUSTOM_SCORE_TEXT,
GADGET_ID_CUSTOM_SCORE_UP,
GADGET_ID_MOVE_DELAY_RND_DOWN,
GADGET_ID_MOVE_DELAY_RND_TEXT,
GADGET_ID_MOVE_DELAY_RND_UP,
+ GADGET_ID_STEP_DELAY_FIX_DOWN,
+ GADGET_ID_STEP_DELAY_FIX_TEXT,
+ GADGET_ID_STEP_DELAY_FIX_UP,
+ GADGET_ID_STEP_DELAY_RND_DOWN,
+ GADGET_ID_STEP_DELAY_RND_TEXT,
+ GADGET_ID_STEP_DELAY_RND_UP,
GADGET_ID_EXPLOSION_DELAY_DOWN,
GADGET_ID_EXPLOSION_DELAY_TEXT,
GADGET_ID_EXPLOSION_DELAY_UP,
GADGET_ID_ARTWORK_ELEMENT,
GADGET_ID_EXPLOSION_ELEMENT,
GADGET_ID_INVENTORY_CONTENT,
+ GADGET_ID_MM_BALL_CONTENT,
GADGET_ID_CUSTOM_GRAPHIC,
GADGET_ID_CUSTOM_CONTENT,
GADGET_ID_CUSTOM_MOVE_ENTER,
// selectbox identifiers
GADGET_ID_TIME_OR_STEPS,
+ GADGET_ID_TIME_SCORE_BASE,
GADGET_ID_GAME_ENGINE_TYPE,
GADGET_ID_LEVELSET_SAVE_MODE,
GADGET_ID_WIND_DIRECTION,
GADGET_ID_PLAYER_SPEED,
+ GADGET_ID_MM_BALL_CHOICE_MODE,
GADGET_ID_CUSTOM_WALK_TO_ACTION,
GADGET_ID_CUSTOM_EXPLOSION_TYPE,
GADGET_ID_CUSTOM_DEADLINESS,
// checkbuttons/radiobuttons for level/element properties
GADGET_ID_AUTO_COUNT_GEMS,
+ GADGET_ID_RATE_TIME_OVER_SCORE,
GADGET_ID_USE_LEVELSET_ARTWORK,
GADGET_ID_COPY_LEVEL_TEMPLATE,
GADGET_ID_RANDOM_PERCENTAGE,
GADGET_ID_SB_OBJECTS_NEEDED,
GADGET_ID_AUTO_EXIT_SOKOBAN,
GADGET_ID_SOLVED_BY_ONE_PLAYER,
+ GADGET_ID_FINISH_DIG_COLLECT,
+ GADGET_ID_KEEP_WALKABLE_CE,
GADGET_ID_CONTINUOUS_SNAPPING,
GADGET_ID_BLOCK_SNAP_FIELD,
GADGET_ID_BLOCK_LAST_FIELD,
ED_COUNTER_ID_ENVELOPE_XSIZE,
ED_COUNTER_ID_ENVELOPE_YSIZE,
ED_COUNTER_ID_INVENTORY_SIZE,
+ ED_COUNTER_ID_MM_BALL_CONTENT,
ED_COUNTER_ID_CUSTOM_SCORE,
ED_COUNTER_ID_CUSTOM_GEMCOUNT,
ED_COUNTER_ID_CUSTOM_VALUE_FIX,
ED_COUNTER_ID_DROP_DELAY_RND,
ED_COUNTER_ID_MOVE_DELAY_FIX,
ED_COUNTER_ID_MOVE_DELAY_RND,
+ ED_COUNTER_ID_STEP_DELAY_FIX,
+ ED_COUNTER_ID_STEP_DELAY_RND,
ED_COUNTER_ID_EXPLOSION_DELAY,
ED_COUNTER_ID_IGNITION_DELAY,
ED_COUNTER_ID_GROUP_CONTENT,
enum
{
ED_SELECTBOX_ID_TIME_OR_STEPS,
+ ED_SELECTBOX_ID_TIME_SCORE_BASE,
ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
ED_SELECTBOX_ID_WIND_DIRECTION,
ED_SELECTBOX_ID_PLAYER_SPEED,
+ ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
enum
{
ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
+ ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
+ ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
+ ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
};
#define ED_CHECKBUTTON_ID_LEVEL_FIRST ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
-#define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
+#define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
#define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
#define ED_CHECKBUTTON_ID_LEVELSET_LAST ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
ED_DRAWING_ID_ARTWORK_ELEMENT,
ED_DRAWING_ID_EXPLOSION_ELEMENT,
ED_DRAWING_ID_INVENTORY_CONTENT,
+ ED_DRAWING_ID_MM_BALL_CONTENT,
ED_DRAWING_ID_CUSTOM_GRAPHIC,
ED_DRAWING_ID_CUSTOM_CONTENT,
ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
GADGET_ID_LEVEL_TIMESCORE_DOWN, GADGET_ID_LEVEL_TIMESCORE_UP,
GADGET_ID_LEVEL_TIMESCORE_TEXT, GADGET_ID_NONE,
&level.score[SC_TIME_BONUS],
- "score for each second/step left:", NULL, NULL
+ "score for time or steps left:", NULL, NULL
},
{
- ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(12),
+ ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(13),
0, 9999,
GADGET_ID_LEVEL_RANDOM_SEED_DOWN, GADGET_ID_LEVEL_RANDOM_SEED_UP,
GADGET_ID_LEVEL_RANDOM_SEED_TEXT, GADGET_ID_NONE,
&level.initial_inventory_size[0],
NULL, NULL, "number of inventory elements"
},
+ {
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3),
+ MIN_ELEMENTS_IN_GROUP, MAX_MM_BALL_CONTENTS,
+ GADGET_ID_MM_BALL_CONTENT_DOWN, GADGET_ID_MM_BALL_CONTENT_UP,
+ GADGET_ID_MM_BALL_CONTENT_TEXT, GADGET_ID_NONE,
+ &level.num_mm_ball_contents,
+ NULL, NULL, "number of content elements"
+ },
// ---------- element settings: configure 1 (custom elements) ---------------
NULL, "+random", NULL
},
{
- ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(12),
+ ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(6),
+ 0, 999,
+ GADGET_ID_STEP_DELAY_FIX_DOWN, GADGET_ID_STEP_DELAY_FIX_UP,
+ GADGET_ID_STEP_DELAY_FIX_TEXT, GADGET_ID_NONE,
+ &custom_element.step_delay_fixed,
+ NULL, "step delay", NULL
+ },
+ {
+ -1, ED_ELEMENT_SETTINGS_YPOS(6),
+ 0, 999,
+ GADGET_ID_STEP_DELAY_RND_DOWN, GADGET_ID_STEP_DELAY_RND_UP,
+ GADGET_ID_STEP_DELAY_RND_TEXT, GADGET_ID_STEP_DELAY_FIX_UP,
+ &custom_element.step_delay_random,
+ NULL, "+random", NULL
+ },
+ {
+ ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(13),
0, 999,
GADGET_ID_EXPLOSION_DELAY_DOWN, GADGET_ID_EXPLOSION_DELAY_UP,
GADGET_ID_EXPLOSION_DELAY_TEXT, GADGET_ID_NONE,
NULL, "explosion delay", NULL
},
{
- ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(13),
+ ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(14),
0, 999,
GADGET_ID_IGNITION_DELAY_DOWN, GADGET_ID_IGNITION_DELAY_UP,
GADGET_ID_IGNITION_DELAY_TEXT, GADGET_ID_NONE,
{ -1, NULL }
};
+static struct ValueTextInfo options_time_score_base[] =
+{
+ { 1, "per second/step" },
+ { 10, "per 10 seconds/steps" },
+
+ { -1, NULL }
+};
+
static struct ValueTextInfo options_game_engine_type[] =
{
{ GAME_ENGINE_TYPE_RND, "Rocks'n'Diamonds" },
{ CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]" },
{ CE_CLICKED_BY_MOUSE, "clicked by mouse" },
{ CE_PRESSED_BY_MOUSE, "pressed by mouse" },
+ { CE_UNDEFINED, " " },
+ { CE_HEADLINE_SPECIAL_EVENTS, "[static states]" },
+ { CE_NEXT_TO_PLAYER, "next to player" },
{ -1, NULL }
};
{ CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]" },
{ CE_MOUSE_CLICKED_ON_X, "mouse clicked on" },
{ CE_MOUSE_PRESSED_ON_X, "mouse pressed on" },
+ { CE_UNDEFINED, " " },
+ { CE_HEADLINE_SPECIAL_EVENTS, "[static states]" },
+ { CE_PLAYER_NEXT_TO_X, "player next to" },
+ { CE_NEXT_TO_X, "next to" },
{ -1, NULL }
};
static struct ValueTextInfo options_change_trigger_page[] =
{
- { (1 << 0), "1" },
- { (1 << 1), "2" },
- { (1 << 2), "3" },
- { (1 << 3), "4" },
- { (1 << 4), "5" },
- { (1 << 5), "6" },
- { (1 << 6), "7" },
- { (1 << 7), "8" },
- { (1 << 8), "9" },
- { (1 << 9), "10" },
- { (1 << 10), "11" },
- { (1 << 11), "12" },
- { (1 << 12), "13" },
- { (1 << 13), "14" },
- { (1 << 14), "15" },
- { (1 << 15), "16" },
- { (1 << 16), "17" },
- { (1 << 17), "18" },
- { (1 << 18), "19" },
- { (1 << 19), "20" },
- { (1 << 20), "21" },
- { (1 << 21), "22" },
- { (1 << 22), "23" },
- { (1 << 23), "24" },
- { (1 << 24), "25" },
- { (1 << 25), "26" },
- { (1 << 26), "27" },
- { (1 << 27), "28" },
- { (1 << 28), "29" },
- { (1 << 29), "30" },
- { (1 << 30), "31" },
- { (1 << 31), "32" },
+ { (1u << 0), "1" },
+ { (1u << 1), "2" },
+ { (1u << 2), "3" },
+ { (1u << 3), "4" },
+ { (1u << 4), "5" },
+ { (1u << 5), "6" },
+ { (1u << 6), "7" },
+ { (1u << 7), "8" },
+ { (1u << 8), "9" },
+ { (1u << 9), "10" },
+ { (1u << 10), "11" },
+ { (1u << 11), "12" },
+ { (1u << 12), "13" },
+ { (1u << 13), "14" },
+ { (1u << 14), "15" },
+ { (1u << 15), "16" },
+ { (1u << 16), "17" },
+ { (1u << 17), "18" },
+ { (1u << 18), "19" },
+ { (1u << 19), "20" },
+ { (1u << 20), "21" },
+ { (1u << 21), "22" },
+ { (1u << 22), "23" },
+ { (1u << 23), "24" },
+ { (1u << 24), "25" },
+ { (1u << 25), "26" },
+ { (1u << 26), "27" },
+ { (1u << 27), "28" },
+ { (1u << 28), "29" },
+ { (1u << 29), "30" },
+ { (1u << 30), "31" },
+ { (1u << 31), "32" },
{ CH_PAGE_ANY, "any" },
{ -1, NULL }
NULL, NULL, "(0 => no limit)", "time or step limit"
},
{
- ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(11),
+ -1, ED_LEVEL_SETTINGS_YPOS(10),
+ GADGET_ID_TIME_SCORE_BASE, GADGET_ID_LEVEL_TIMESCORE_UP,
+ -1,
+ options_time_score_base,
+ &level.time_score_base,
+ NULL, NULL, NULL, "time score for 1 or 10 seconds/steps"
+ },
+ {
+ ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(12),
GADGET_ID_GAME_ENGINE_TYPE, GADGET_ID_NONE,
-1,
options_game_engine_type,
&level.initial_player_stepsize[0],
NULL, "initial player speed:", NULL, "initial player speed"
},
+ {
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4),
+ GADGET_ID_MM_BALL_CHOICE_MODE, GADGET_ID_NONE,
+ -1,
+ options_group_choice_mode,
+ &level.mm_ball_choice_mode,
+ NULL, "choice type:", NULL, "type of content choice"
+ },
// ---------- element settings: configure 1 (custom elements) ---------------
NULL, " can", ":", "leave behind or change element"
},
{
- -1, ED_ELEMENT_SETTINGS_YPOS(7),
+ -1, ED_ELEMENT_SETTINGS_YPOS(8),
GADGET_ID_CUSTOM_SMASH_TARGETS, GADGET_ID_CUSTOM_CAN_SMASH,
-1,
options_smash_targets,
NULL, "can smash", NULL, "elements that can be smashed"
},
{
- ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(8),
+ ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(9),
GADGET_ID_CUSTOM_SLIPPERY_TYPE, GADGET_ID_NONE,
-1,
options_slippery_type,
NULL, "slippery", NULL, "where other elements fall down"
},
{
- ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(9),
+ ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(10),
GADGET_ID_CUSTOM_DEADLINESS, GADGET_ID_NONE,
-1,
options_deadliness,
NULL, "deadly when", NULL, "deadliness of element"
},
{
- ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(10),
+ ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(11),
GADGET_ID_CUSTOM_EXPLOSION_TYPE, GADGET_ID_NONE,
-1,
options_explosion_type,
NULL, NULL,
"automatically count gems needed", "set counter to number of gems"
},
+ {
+ ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(11),
+ GADGET_ID_RATE_TIME_OVER_SCORE, GADGET_ID_NONE,
+ &level.rate_time_over_score,
+ NULL, NULL,
+ "rate time/steps used over score", "sort high scores by playing time/steps"
+ },
{
ED_LEVEL_SETTINGS_XPOS(0), ED_LEVEL_SETTINGS_YPOS(7),
GADGET_ID_USE_LEVELSET_ARTWORK, GADGET_ID_NONE,
NULL, NULL,
"only one player must enter exit", "level solved by first player in exit"
},
+ {
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(3),
+ GADGET_ID_FINISH_DIG_COLLECT, GADGET_ID_NONE,
+ &level.finish_dig_collect,
+ NULL, NULL,
+ "CE action on finished dig/collect", "only finished dig/collect triggers CE"
+ },
+ {
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(4),
+ GADGET_ID_KEEP_WALKABLE_CE, GADGET_ID_NONE,
+ &level.keep_walkable_ce,
+ NULL, NULL,
+ "keep walkable CE changed to player", "keep CE changing to player if walkable"
+ },
{
ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9),
GADGET_ID_CONTINUOUS_SNAPPING, GADGET_ID_NONE,
NULL, "element can move with some pattern"
},
{
- ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(7),
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(8),
GADGET_ID_CUSTOM_CAN_FALL, GADGET_ID_NONE,
&custom_element_properties[EP_CAN_FALL],
NULL, NULL,
"can fall", "element can fall down"
},
{
- -1, ED_ELEMENT_SETTINGS_YPOS(7),
+ -1, ED_ELEMENT_SETTINGS_YPOS(8),
GADGET_ID_CUSTOM_CAN_SMASH, GADGET_ID_CUSTOM_CAN_FALL,
&custom_element_properties[EP_CAN_SMASH],
NULL, " ",
NULL, "element can smash other elements"
},
{
- ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(8),
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9),
GADGET_ID_CUSTOM_SLIPPERY, GADGET_ID_NONE,
&custom_element_properties[EP_SLIPPERY],
NULL, NULL,
NULL, "other elements can fall down from it"
},
{
- ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(9),
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10),
GADGET_ID_CUSTOM_DEADLY, GADGET_ID_NONE,
&custom_element_properties[EP_DEADLY],
NULL, NULL,
NULL, "element can kill the player"
},
{
- ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(10),
+ ED_ELEMENT_SETTINGS_XPOS(0), ED_ELEMENT_SETTINGS_YPOS(11),
GADGET_ID_CUSTOM_CAN_EXPLODE, GADGET_ID_NONE,
&custom_element_properties[EP_CAN_EXPLODE],
NULL, NULL,
NULL, "element can explode"
},
{
- ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(11),
+ ED_ELEMENT_SETTINGS_XPOS(1), ED_ELEMENT_SETTINGS_YPOS(12),
GADGET_ID_CUSTOM_EXPLODE_FIRE, GADGET_ID_NONE,
&custom_element_properties[EP_EXPLODES_BY_FIRE],
NULL, NULL,
"by fire", "element can explode by fire/explosion"
},
{
- -1, ED_ELEMENT_SETTINGS_YPOS(11),
+ -1, ED_ELEMENT_SETTINGS_YPOS(12),
GADGET_ID_CUSTOM_EXPLODE_SMASH, GADGET_ID_CUSTOM_EXPLODE_FIRE,
&custom_element_properties[EP_EXPLODES_SMASHED],
NULL, " ",
"smashed", "element can explode when smashed"
},
{
- -1, ED_ELEMENT_SETTINGS_YPOS(11),
+ -1, ED_ELEMENT_SETTINGS_YPOS(12),
GADGET_ID_CUSTOM_EXPLODE_IMPACT, GADGET_ID_CUSTOM_EXPLODE_SMASH,
&custom_element_properties[EP_EXPLODES_IMPACT],
NULL, " ",
NULL, NULL, NULL, NULL, "content for initial inventory"
},
+ // ---------- gray ball content -----------------------------------------
+
+ {
+ ED_AREA_1X1_SETTINGS_XPOS(0), ED_AREA_1X1_SETTINGS_YPOS(2),
+ ED_AREA_1X1_SETTINGS_XOFF, ED_AREA_1X1_SETTINGS_YOFF,
+ GADGET_ID_MM_BALL_CONTENT, GADGET_ID_NONE,
+ &level.mm_ball_content[0], MAX_MM_BALL_CONTENTS, 1,
+ "content:", NULL, NULL, NULL, "content for gray ball"
+ },
+
// ---------- element settings: configure 1 (custom elements) ---------------
// ---------- custom graphic ------------------------------------------------
// ---------- custom content (when exploding) -------------------------------
{
- -1, ED_AREA_3X3_SETTINGS_YPOS(10),
+ -1, ED_AREA_3X3_SETTINGS_YPOS(11),
0, ED_AREA_3X3_SETTINGS_YOFF,
GADGET_ID_CUSTOM_CONTENT, GADGET_ID_NONE, // align three rows
&custom_element.content.e[0][0], 3, 3,
static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
+static int editor_hl_empty_space[] =
+{
+ EL_INTERNAL_CASCADE_ES_ACTIVE,
+ EL_CHAR('E'),
+ EL_CHAR('S'),
+ EL_EMPTY,
+};
+
+static int editor_el_empty_space[] =
+{
+ EL_EMPTY_SPACE_1,
+ EL_EMPTY_SPACE_2,
+ EL_EMPTY_SPACE_3,
+ EL_EMPTY_SPACE_4,
+
+ EL_EMPTY_SPACE_5,
+ EL_EMPTY_SPACE_6,
+ EL_EMPTY_SPACE_7,
+ EL_EMPTY_SPACE_8,
+
+ EL_EMPTY_SPACE_9,
+ EL_EMPTY_SPACE_10,
+ EL_EMPTY_SPACE_11,
+ EL_EMPTY_SPACE_12,
+
+ EL_EMPTY_SPACE_13,
+ EL_EMPTY_SPACE_14,
+ EL_EMPTY_SPACE_15,
+ EL_EMPTY_SPACE_16
+};
+static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
+static int *editor_el_empty_space_ptr = editor_el_empty_space;
+static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
+static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
+
static int editor_hl_reference[] =
{
EL_INTERNAL_CASCADE_REF_ACTIVE,
&editor_hl_group_ptr, &num_editor_hl_group,
&editor_el_group_ptr, &num_editor_el_group
},
+ {
+ &setup_editor_el_custom,
+ &setup.editor_cascade.el_es,
+ &editor_hl_empty_space_ptr, &num_editor_hl_empty_space,
+ &editor_el_empty_space_ptr, &num_editor_el_empty_space
+ },
{
&setup_editor_el_custom,
&setup.editor_cascade.el_ref,
}
};
+static struct XY xy_directions[] =
+{
+ { -1, 0 },
+ { +1, 0 },
+ { 0, -1 },
+ { 0, +1 }
+};
+
// ----------------------------------------------------------------------------
// functions
static char *getElementDescriptionFilenameExt(char *basename)
{
- char *elements_subdir = "elements";
+ char *elements_subdir = ELEMENTS_DIRECTORY;
static char *elements_subdir2 = NULL;
static char *filename = NULL;
if (filename != NULL)
return filename;
+ // 3rd try: look for generic fallback text file for any element
+ filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
+ if (filename != NULL)
+ return filename;
+
return NULL;
}
// determine size of element list
for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
{
- boolean found_inactive_cascade = FALSE;
-
if (*editor_elements_info[i].setup_value)
{
+ boolean found_inactive_cascade = FALSE;
+
if (setup.editor.el_headlines)
{
// required for correct padding of palette headline buttons
int graphic;
struct GraphicInfo *gd;
int gd_x1, gd_x2, gd_y1, gd_y2;
- unsigned int event_mask;
+ unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
char infotext[max_infotext_len + 1];
- event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
-
if (i == ED_COUNTER_ID_SELECT_LEVEL)
{
graphic = (j == 0 ?
for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
{
struct GadgetInfo *gi;
- unsigned int event_mask;
int id = drawingarea_info[i].gadget_id;
int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
int area_ysize = drawingarea_info[i].area_ysize;
int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
-
- event_mask =
+ unsigned int event_mask =
GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
int gd_x2 = gd->src_x + gd->active_xoffset;
int gd_y2 = gd->src_y + gd->active_yoffset;
struct GadgetInfo *gi;
- unsigned int event_mask;
+ unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
char infotext[MAX_OUTPUT_LINESIZE + 1];
int id = textinput_info[i].gadget_id;
int x, y;
y = ED_SETTINGS_Y(textinput_info[i].y);
}
- event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
-
sprintf(infotext, "Enter %s", textinput_info[i].infotext);
infotext[max_infotext_len] = '\0';
int gd_x2 = gd->src_x + gd->active_xoffset;
int gd_y2 = gd->src_y + gd->active_yoffset;
struct GadgetInfo *gi;
- unsigned int event_mask;
+ unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
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;
-
sprintf(infotext, "Enter %s", textarea_info[i].infotext);
infotext[max_infotext_len] = '\0';
int gd_y2 = gd->src_y + gd->active_yoffset;
int selectbox_button_xsize = gd2->width;
struct GadgetInfo *gi;
- unsigned int event_mask;
char infotext[MAX_OUTPUT_LINESIZE + 1];
int id = selectbox_info[i].gadget_id;
int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
+ unsigned int event_mask =
+ GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
if (selectbox_info[i].size == -1) // dynamically determine size
{
selectbox_info[i].size++; // add one character empty space
}
- event_mask = GD_EVENT_RELEASED |
- GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
-
// determine horizontal position to the right of specified gadget
if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
int border_xsize = gd->border_size + gd->draw_xoffset;
int border_ysize = gd->border_size;
struct GadgetInfo *gi;
- unsigned int event_mask;
+ unsigned int event_mask = GD_EVENT_RELEASED;
char infotext[MAX_OUTPUT_LINESIZE + 1];
int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
if (textbutton_info[i].size == -1) // dynamically determine size
textbutton_info[i].size = strlen(textbutton_info[i].text);
- event_mask = GD_EVENT_RELEASED;
-
sprintf(infotext, "%s", textbutton_info[i].infotext);
infotext[max_infotext_len] = '\0';
static void CreateGraphicbuttonGadgets(void)
{
struct GadgetInfo *gi;
- unsigned int event_mask;
int i;
// create buttons for scrolling of drawing area and element list
int gd_y1 = gd->src_y;
int gd_x2 = gd->src_x + gd->pressed_xoffset;
int gd_y2 = gd->src_y + gd->pressed_yoffset;
-
- event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+ unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
// determine horizontal position to the right of specified gadget
if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
int gd_y2 = gd->src_y + gd->pressed_yoffset;
struct GadgetInfo *gi;
int items_max, items_visible, item_position;
- unsigned int event_mask;
+ unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
{
}
}
- event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
-
gi = CreateGadget(GDI_CUSTOM_ID, id,
GDI_CUSTOM_TYPE_ID, i,
GDI_IMAGE_ID, graphic,
static void CreateCheckbuttonGadgets(void)
{
struct GadgetInfo *gi;
- unsigned int event_mask;
int i;
- event_mask = GD_EVENT_PRESSED;
-
for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
{
int id = checkbutton_info[i].gadget_id;
int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
+ unsigned int event_mask = GD_EVENT_PRESSED;
// determine horizontal position to the right of specified gadget
if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
struct GadgetInfo *gi;
- unsigned int event_mask;
int i;
- event_mask = GD_EVENT_PRESSED;
-
for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
{
int id = radiobutton_info[i].gadget_id;
int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
+ unsigned int event_mask = GD_EVENT_PRESSED;
int checked =
(*radiobutton_info[i].value == radiobutton_info[i].checked_value);
return TRUE;
}
- if (!Request("This level is read only! "
+ if (!Request("This level is read-only! "
"Save into personal level set?", REQ_ASK))
return FALSE;
// 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_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
+ 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_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
// set "change by other element action" selectbox help value
custom_element_change.other_action =
- (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
+ (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
+ HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
+ HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
custom_element = element_info[element]; // needed for description
}
+static void CopyEmptyElementPropertiesToEditor(int element)
+{
+ custom_element = element_info[element];
+}
+
static void CopyClassicElementPropertiesToEditor(int element)
{
- if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
+ if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
getMoveIntoAcidProperty(&level, element);
CopyCustomElementPropertiesToEditor(element);
else if (IS_GROUP_ELEMENT(element))
CopyGroupElementPropertiesToEditor(element);
+ else if (IS_EMPTY_ELEMENT(element))
+ CopyEmptyElementPropertiesToEditor(element);
else
CopyClassicElementPropertiesToEditor(element);
}
// ---------- element settings: advanced (custom elements) ------------------
// set player change event from checkbox and selectbox
+ custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
custom_element_change_events[CE_BY_DIRECT_ACTION];
// set other element action change event from checkbox and selectbox
+ custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
+ custom_element_change_events[CE_NEXT_TO_X] = FALSE;
custom_element_change_events[CE_TOUCHING_X] = FALSE;
custom_element_change_events[CE_HITTING_X] = FALSE;
custom_element_change_events[CE_DIGGING_X] = FALSE;
InitElementPropertiesGfxElement();
}
+static void CopyEmptyElementPropertiesToGame(int element)
+{
+ // mark that this empty element has been modified
+ custom_element.modified_settings = TRUE;
+ level.changed = TRUE;
+
+ if (level.use_custom_template)
+ AskToCopyAndModifyLevelTemplate();
+
+ element_info[element] = custom_element;
+
+ // needed here to restore runtime value "element_info[element].gfx_element"
+ InitElementPropertiesGfxElement();
+}
+
static void CopyClassicElementPropertiesToGame(int element)
{
- if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
+ if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
setMoveIntoAcidProperty(&level, element,
custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
CopyCustomElementPropertiesToGame(element);
else if (IS_GROUP_ELEMENT(element))
CopyGroupElementPropertiesToGame(element);
+ else if (IS_EMPTY_ELEMENT(element))
+ CopyEmptyElementPropertiesToGame(element);
else
CopyClassicElementPropertiesToGame(element);
}
int i;
// draw two config tabulators for player elements
- if (ELEM_IS_PLAYER(properties_element))
+ if (IS_PLAYER_ELEMENT(properties_element))
id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
// draw two config and one "change" tabulator for custom elements
// use "config 1" and "config 2" instead of "config" for players and CEs
if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
- (ELEM_IS_PLAYER(properties_element) ||
+ (IS_PLAYER_ELEMENT(properties_element) ||
IS_CUSTOM_ELEMENT(properties_element)))
continue;
DrawText(x, y + 2 * tilesize, "active", font_nr);
}
-static void DrawAndroidElementArea(int element)
+static void DrawAndroidElementArea(void)
{
int id = ED_DRAWING_ID_ANDROID_CONTENT;
int num_elements = level.num_android_clone_elements;
MapDrawingArea(id);
}
-static void DrawGroupElementArea(int element)
+static void DrawGroupElementArea(void)
{
int id = ED_DRAWING_ID_GROUP_CONTENT;
int num_elements = group_element_info.num_elements;
MapDrawingArea(id);
}
+static void DrawMMBallContentArea(void)
+{
+ int id = ED_DRAWING_ID_MM_BALL_CONTENT;
+ int num_elements = level.num_mm_ball_contents;
+ int border_size = ED_DRAWINGAREA_BORDER_SIZE;
+ int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
+ int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
+ int xsize = MAX_MM_BALL_CONTENTS;
+ int ysize = 1;
+
+ if (drawingarea_info[id].text_left != NULL)
+ sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
+
+ UnmapDrawingArea(id);
+
+ ModifyEditorDrawingArea(id, num_elements, 1);
+
+ // delete content areas in case of reducing number of them
+ DrawBackground(sx, sy,
+ xsize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
+ ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
+
+ MapDrawingArea(id);
+}
+
static void DrawEnvelopeTextArea(int envelope_nr)
{
int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
if (IS_GEM(element) ||
IS_CUSTOM_ELEMENT(element) ||
IS_GROUP_ELEMENT(element) ||
+ IS_EMPTY_ELEMENT(element) ||
IS_BALLOON_ELEMENT(element) ||
IS_ENVELOPE(element) ||
IS_MM_MCDUFFIN(element) ||
IS_DF_LASER(element) ||
- ELEM_IS_PLAYER(element) ||
+ IS_PLAYER_ELEMENT(element) ||
HAS_EDITOR_CONTENT(element) ||
CAN_GROW(element) ||
COULD_MOVE_INTO_ACID(element) ||
MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
}
else if (properties_element == EL_EMC_ANDROID)
- DrawAndroidElementArea(properties_element);
+ DrawAndroidElementArea();
+ else if (properties_element == EL_MM_GRAY_BALL)
+ {
+ MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
+ MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
+
+ DrawMMBallContentArea();
+ }
}
- if (ELEM_IS_PLAYER(properties_element))
+ if (IS_PLAYER_ELEMENT(properties_element))
{
int player_nr = GET_PLAYER_NR(properties_element);
// draw checkbutton gadgets
MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
// draw counter gadgets
MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
if (COULD_MOVE_INTO_ACID(properties_element) &&
- !ELEM_IS_PLAYER(properties_element) &&
+ !IS_PLAYER_ELEMENT(properties_element) &&
(!IS_CUSTOM_ELEMENT(properties_element) ||
edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
{
checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
- ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
+ ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
IS_BALLOON_ELEMENT(properties_element) ||
HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
// draw drawing area gadgets
- DrawGroupElementArea(properties_element);
+ DrawGroupElementArea();
// draw text input gadgets
MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
draw_footer_line = TRUE;
}
+ else if (IS_EMPTY_ELEMENT(properties_element))
+ {
+ // draw stickybutton gadget
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
+
+ // draw checkbutton gadgets
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
+
+ // draw textbutton gadgets
+ MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
+
+ // draw drawing area gadgets
+ MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+
+ draw_footer_line = TRUE;
+ }
// draw little footer border line above CE/GE use/save template gadgets
if (draw_footer_line)
int font_height = getFontHeight(font_nr);
int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
int max_chars_per_line = max_text_width / font_width;
- char buffer[max_chars_per_line + 1];
if (strlen(element_name) <= max_chars_per_line)
DrawTextS(x, y, font_nr, element_name);
else
{
+ char buffer[max_chars_per_line + 1];
int next_pos = max_chars_per_line;
strncpy(buffer, element_name, max_chars_per_line);
edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
- !ELEM_IS_PLAYER(properties_element) &&
+ !IS_PLAYER_ELEMENT(properties_element) &&
!IS_CUSTOM_ELEMENT(properties_element))
edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
- (ELEM_IS_PLAYER(properties_element) ||
+ (IS_PLAYER_ELEMENT(properties_element) ||
IS_CUSTOM_ELEMENT(properties_element)))
edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
static int getClosedTube(int x, int y)
{
- static int xy[4][2] =
- {
- { -1, 0 },
- { +1, 0 },
- { 0, -1 },
- { 0, +1 }
- };
+ struct XY *xy = xy_directions;
int element_old = IntelliDrawBuffer[x][y];
int direction_old = getOpenDirectionFromTube(element_old);
int direction_new = MV_NONE;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int dir = MV_DIR_FROM_BIT(i);
int dir_opposite = MV_DIR_OPPOSITE(dir);
static int getClosedBelt(int x, int y)
{
- static int xy[4][2] =
- {
- { -1, 0 },
- { +1, 0 },
- { 0, -1 },
- { 0, +1 }
- };
+ struct XY *xy = xy_directions;
int element_old = IntelliDrawBuffer[x][y];
int nr = getBeltNrFromBeltElement(element_old);
int direction_old = getOpenDirectionFromBelt(element_old);
for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int dir = MV_DIR_FROM_BIT(i);
int dir_opposite = MV_DIR_OPPOSITE(dir);
static int getClosedPool(int x, int y)
{
- static int xy[4][2] =
- {
- { -1, 0 },
- { +1, 0 },
- { 0, -1 },
- { 0, +1 }
- };
+ struct XY *xy = xy_directions;
int element_old = IntelliDrawBuffer[x][y];
int direction_old = getOpenDirectionFromPool(element_old);
int direction_new = MV_NONE;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int dir = MV_DIR_FROM_BIT(i);
int dir_opposite = MV_DIR_OPPOSITE(dir);
static int getClosedPillar(int x, int y)
{
- static int xy[4][2] =
- {
- { -1, 0 },
- { +1, 0 },
- { 0, -1 },
- { 0, +1 }
- };
+ struct XY *xy = xy_directions;
int element_old = IntelliDrawBuffer[x][y];
int direction_old = getOpenDirectionFromPillar(element_old);
int direction_new = MV_NONE;
for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int dir = MV_DIR_FROM_BIT(i);
int dir_opposite = MV_DIR_OPPOSITE(dir);
static int getClosedSteel2(int x, int y)
{
- static int xy[4][2] =
- {
- { -1, 0 },
- { +1, 0 },
- { 0, -1 },
- { 0, +1 }
- };
+ struct XY *xy = xy_directions;
int element_old = IntelliDrawBuffer[x][y];
int direction_old = getOpenDirectionFromSteel2(element_old);
int direction_new = MV_NONE;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int dir = MV_DIR_FROM_BIT(i);
int dir_opposite = MV_DIR_OPPOSITE(dir);
static int getClosedChip(int x, int y)
{
- static int xy[4][2] =
- {
- { -1, 0 },
- { +1, 0 },
- { 0, -1 },
- { 0, +1 }
- };
+ struct XY *xy = xy_directions;
int element_old = IntelliDrawBuffer[x][y];
int direction_old = getOpenDirectionFromChip(element_old);
int direction_new = MV_NONE;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int dir = MV_DIR_FROM_BIT(i);
int dir_opposite = MV_DIR_OPPOSITE(dir);
static void SetElementIntelliDraw(int x, int y, int new_element,
boolean change_level, int button)
{
- static int xy[4][2] =
- {
- { -1, 0 },
- { +1, 0 },
- { 0, -1 },
- { 0, +1 }
- };
+ struct XY *xy = xy_directions;
static int last_x = -1;
static int last_y = -1;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
IS_BELT(IntelliDrawBuffer[last_x][last_y]))
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
ptr++;
}
+ // remap some (historic, now obsolete) elements
+ element = getMappedElement(element);
+
if (element >= NUM_FILE_ELEMENTS)
element = EL_UNKNOWN;
lev_fieldx = level.fieldx = brush_width;
lev_fieldy = level.fieldy = brush_height;
+ boolean use_em_engine = TRUE;
+ boolean use_sp_engine = TRUE;
+ boolean use_mm_engine = TRUE;
+
+ for (x = 0; x < MAX_LEV_FIELDX; x++)
+ {
+ for (y = 0; y < MAX_LEV_FIELDY; y++)
+ {
+ int element = Tile[x][y];
+
+ if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
+ use_em_engine = FALSE;
+
+ if (!IS_SP_ELEMENT(element))
+ use_sp_engine = FALSE;
+
+ if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
+ use_mm_engine = FALSE;
+ }
+ }
+
+ level.game_engine_type = (use_em_engine ? GAME_ENGINE_TYPE_EM :
+ use_sp_engine ? GAME_ENGINE_TYPE_SP :
+ use_mm_engine ? GAME_ENGINE_TYPE_MM :
+ GAME_ENGINE_TYPE_RND);
+
+ // update element selection list
+ ReinitializeElementList();
+ ModifyEditorElementList();
+
SetBorderElement();
DrawEditModeWindow();
static int start_sx;
static int last_sx, last_sy;
static boolean typing = FALSE;
- int letter_element = EL_CHAR_ASCII0 + letter;
+ int letter_element;
int lx = 0, ly = 0;
// map lower case letters to upper case and convert special characters
CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
}
+static void DrawAreaElementHighlight(boolean highlighted)
+{
+ DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+
+ if (!highlighted)
+ return;
+
+ int x, y;
+
+ for (x = 0; x < ed_fieldx; x++)
+ {
+ for (y = 0; y < ed_fieldy; y++)
+ {
+ int lx = x + level_xpos;
+ int ly = y + level_ypos;
+
+ if (!IN_LEV_FIELD(lx, ly))
+ continue;
+
+ if (Tile[lx][ly] != new_element1)
+ continue;
+
+ int sx = SX + x * ed_tilesize;
+ int sy = SY + y * ed_tilesize;
+ int from_sx = sx;
+ int from_sy = sy;
+ int to_sx = sx + ed_tilesize - 1;
+ int to_sy = sy + ed_tilesize - 1;
+
+ DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx, from_sy);
+ DrawSimpleWhiteLine(drawto, to_sx, from_sy, to_sx, to_sy);
+ DrawSimpleWhiteLine(drawto, to_sx, to_sy, from_sx, to_sy);
+ DrawSimpleWhiteLine(drawto, from_sx, to_sy, from_sx, from_sy);
+ }
+ }
+}
+
static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
{
char *template_filename_old = getLocalLevelTemplateFilename();
static void HandleDrawingAreas(struct GadgetInfo *gi)
{
static boolean started_inside_drawing_area = FALSE;
- static int last_sx = -1, last_sy = -1;
- static int last_sx2 = -1, last_sy2 = -1;
int id = gi->custom_id;
int type_id = gi->custom_type_id;
boolean button_press_event;
int dx = sx2 % 2;
int dy = sy2 % 2;
int lx = 0, ly = 0;
- int min_lx = 0, min_ly = 0;
- int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
int x, y;
button_press_event = (gi->event.type == GD_EVENT_PRESSED);
if (draw_level)
{
+ int min_lx = 0, min_ly = 0;
+ int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
+
// get positions inside level field
lx = sx + level_xpos;
ly = sy + level_ypos;
sy2 = sy * 2 + dy;
}
- if (button_release_event)
- {
- last_sx = -1;
- last_sy = -1;
- last_sx2 = -1;
- last_sy2 = -1;
- }
- else if (!button_press_event)
+ if (!button_press_event && !button_release_event)
{
+ static int last_sx = -1;
+ static int last_sy = -1;
+ static int last_sx2 = -1;
+ static int last_sy2 = -1;
int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
isHiresTileElement(old_element) &&
if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
(sx2 == last_sx2 && sy2 == last_sy2))
return;
- }
- last_sx = sx;
- last_sy = sy;
- last_sx2 = sx2;
- last_sy2 = sy2;
+ last_sx = sx;
+ last_sy = sy;
+ last_sx2 = sx2;
+ last_sy2 = sy2;
+ }
if (button_press_event)
started_inside_drawing_area = inside_drawing_area;
if (!IS_VALID_BUTTON(button))
return;
- if (!button && !button_release_event)
- return;
-
// handle info callback for each invocation of action callback
gi->callback_info(gi);
if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
!inside_drawing_area)
DeleteBrushFromCursor();
- }
- if (!button || button_release_event)
break;
+ }
if (draw_with_brush)
{
{
SetDrawModeHiRes(new_element);
- if (ELEM_IS_PLAYER(new_element))
+ if (IS_PLAYER_ELEMENT(new_element))
{
// remove player at old position
for (y = 0; y < lev_fieldy; y++)
{
int old_element = Tile[x][y];
- if (ELEM_IS_PLAYER(old_element))
+ if (IS_PLAYER_ELEMENT(old_element))
{
int replaced_with_element =
(old_element == EL_SOKOBAN_FIELD_PLAYER &&
if (button_release_event)
CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
- if (button)
- {
- SetDrawModeHiRes(new_element);
+ SetDrawModeHiRes(new_element);
- if (getDrawModeHiRes())
- {
- sx = sx2;
- sy = sy2;
- }
+ if (getDrawModeHiRes())
+ {
+ sx = sx2;
+ sy = sy2;
+ }
- if (!button_press_event)
- DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
+ if (!button_press_event)
+ DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
- last_sx = sx;
- last_sy = sy;
- }
+ last_sx = sx;
+ last_sy = sy;
}
break;
break;
case ED_COUNTER_ID_ANDROID_CONTENT:
- DrawAndroidElementArea(properties_element);
+ DrawAndroidElementArea();
break;
case ED_COUNTER_ID_GROUP_CONTENT:
- DrawGroupElementArea(properties_element);
+ DrawGroupElementArea();
CopyGroupElementPropertiesToGame(properties_element);
break;
DrawPlayerInitialInventoryArea(properties_element);
break;
+ case ED_COUNTER_ID_MM_BALL_CONTENT:
+ DrawMMBallContentArea();
+ break;
+
case ED_COUNTER_ID_ENVELOPE_XSIZE:
case ED_COUNTER_ID_ENVELOPE_YSIZE:
DrawEnvelopeTextArea(-1);
if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
leveldir_current->readonly)
{
- Request("This level set is read only!", REQ_CONFIRM);
+ Request("This level set is read-only!", REQ_CONFIRM);
return;
}
boolean template_related_changes_found = FALSE;
int i;
- // check if any custom or group elements have been changed
+ // check if any custom, group or empty elements have been changed
for (i = 0; i < NUM_FILE_ELEMENTS; i++)
- if ((IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)) &&
+ if ((IS_CUSTOM_ELEMENT(i) ||
+ IS_GROUP_ELEMENT(i) ||
+ IS_EMPTY_ELEMENT(i)) &&
element_info[i].modified_settings)
template_related_changes_found = TRUE;
}
else
{
- ChangeEditModeWindow(last_edit_mode);
+ ChangeEditModeWindow(ED_MODE_DRAWING);
ClickOnGadget(level_editor_gadget[last_level_drawing_function],
MB_LEFTBUTTON);
}
else
{
- ChangeEditModeWindow(last_edit_mode);
+ ChangeEditModeWindow(ED_MODE_DRAWING);
}
break;
id <= GADGET_ID_ELEMENTLIST_LAST)
{
int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
- int new_element = editor_elements[element_position + element_shift];
+
+ new_element = editor_elements[element_position + element_shift];
if (IS_EDITOR_CASCADE(new_element))
{
ClickOnGadget(level_editor_gadget[i], button);
}
-void HandleLevelEditorIdle(void)
+static void HandleLevelEditorIdle_Properties(void)
{
int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
int x = editor.settings.element_graphic.x + element_border;
int y = editor.settings.element_graphic.y + element_border;
- static unsigned int action_delay = 0;
- unsigned int action_delay_value = GameFrameDelay;
+ static DelayCounter action_delay = { 0 };
int i;
- if (edit_mode != ED_MODE_PROPERTIES)
- return;
+ action_delay.value = GameFrameDelay;
- if (!DelayReached(&action_delay, action_delay_value))
+ if (!DelayReached(&action_delay))
return;
for (i = 0; i < ED_NUM_SELECTBOX; i++)
FrameCounter++; // increase animation frame counter
}
+static void HandleLevelEditorIdle_Drawing(void)
+{
+ static boolean last_highlighted = FALSE;
+ boolean highlighted = (GetKeyModState() & KMOD_Alt);
+
+ if (highlighted != last_highlighted)
+ {
+ DrawAreaElementHighlight(highlighted);
+
+ last_highlighted = highlighted;
+
+ redraw_mask |= REDRAW_FIELD;
+ }
+}
+
+void HandleLevelEditorIdle(void)
+{
+ if (edit_mode == ED_MODE_PROPERTIES)
+ HandleLevelEditorIdle_Properties();
+ else if (edit_mode == ED_MODE_DRAWING)
+ HandleLevelEditorIdle_Drawing();
+}
+
static void ClearEditorGadgetInfoText(void)
{
DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
{
char infotext[MAX_OUTPUT_LINESIZE + 1];
- char shortcut[MAX_OUTPUT_LINESIZE + 1];
int max_infotext_len = getMaxInfoTextLength();
if (gi == NULL || strlen(gi->info_text) == 0)
if (key)
{
+ char shortcut[MAX_OUTPUT_LINESIZE + 1];
+
if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
sprintf(shortcut, " ('.' or '%c')", key);
else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
{
- static int start_lx, start_ly;
int id = gi->custom_id;
int type_id = gi->custom_type_id;
int sx = gi->event.x;
int actual_drawing_function = drawing_function;
int max_infotext_len = getMaxInfoTextLength();
char infotext[MAX_OUTPUT_LINESIZE + 1];
- char *text;
infotext[0] = '\0'; // start with empty info text
{
if (button_status) // if (gi->state == GD_BUTTON_PRESSED)
{
+ static int start_lx = 0;
+ static int start_ly = 0;
+ char *text;
+
if (gi->event.type == GD_EVENT_PRESSED)
{
start_lx = lx;