+ EL_CHAR('P'),
+ EL_CHAR('Q'),
+ EL_CHAR('R'),
+ EL_CHAR('S'),
+
+ EL_CHAR('T'),
+ EL_CHAR('U'),
+ EL_CHAR('V'),
+ EL_CHAR('W'),
+
+ EL_CHAR('X'),
+ EL_CHAR('Y'),
+ EL_CHAR('Z'),
+ EL_CHAR('['),
+
+ EL_CHAR('\\'),
+ EL_CHAR(']'),
+ EL_CHAR('^'),
+ EL_CHAR('_'),
+
+ EL_CHAR('©'),
+ EL_CHAR('Ä'),
+ EL_CHAR('Ö'),
+ EL_CHAR('Ü'),
+
+ EL_CHAR('°'),
+ EL_CHAR('®'),
+ EL_CHAR(FONT_ASCII_CURSOR),
+ EL_CHAR(FONT_ASCII_BUTTON),
+
+ EL_CHAR(FONT_ASCII_UP),
+ EL_CHAR(FONT_ASCII_DOWN),
+ EL_CHAR(' '),
+ EL_CHAR(' ')
+};
+static int *editor_hl_chars_ptr = editor_hl_chars;
+static int *editor_el_chars_ptr = editor_el_chars;
+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_hl_steel_chars[] =
+{
+ EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
+ EL_STEEL_CHAR('T'),
+ EL_STEEL_CHAR('X'),
+ EL_STEEL_CHAR('T'),
+};
+
+static int editor_el_steel_chars[] =
+{
+ EL_STEEL_CHAR(' '),
+ EL_STEEL_CHAR('!'),
+ EL_STEEL_CHAR('"'),
+ EL_STEEL_CHAR('#'),
+
+ EL_STEEL_CHAR('$'),
+ EL_STEEL_CHAR('%'),
+ EL_STEEL_CHAR('&'),
+ EL_STEEL_CHAR('\''),
+
+ EL_STEEL_CHAR('('),
+ EL_STEEL_CHAR(')'),
+ EL_STEEL_CHAR('*'),
+ EL_STEEL_CHAR('+'),
+
+ EL_STEEL_CHAR(','),
+ EL_STEEL_CHAR('-'),
+ EL_STEEL_CHAR('.'),
+ EL_STEEL_CHAR('/'),
+
+ EL_STEEL_CHAR('0'),
+ EL_STEEL_CHAR('1'),
+ EL_STEEL_CHAR('2'),
+ EL_STEEL_CHAR('3'),
+
+ EL_STEEL_CHAR('4'),
+ EL_STEEL_CHAR('5'),
+ EL_STEEL_CHAR('6'),
+ EL_STEEL_CHAR('7'),
+
+ EL_STEEL_CHAR('8'),
+ EL_STEEL_CHAR('9'),
+ EL_STEEL_CHAR(':'),
+ EL_STEEL_CHAR(';'),
+
+ EL_STEEL_CHAR('<'),
+ EL_STEEL_CHAR('='),
+ EL_STEEL_CHAR('>'),
+ EL_STEEL_CHAR('?'),
+
+ EL_STEEL_CHAR('@'),
+ EL_STEEL_CHAR('A'),
+ EL_STEEL_CHAR('B'),
+ EL_STEEL_CHAR('C'),
+
+ EL_STEEL_CHAR('D'),
+ EL_STEEL_CHAR('E'),
+ EL_STEEL_CHAR('F'),
+ EL_STEEL_CHAR('G'),
+
+ EL_STEEL_CHAR('H'),
+ EL_STEEL_CHAR('I'),
+ EL_STEEL_CHAR('J'),
+ EL_STEEL_CHAR('K'),
+
+ EL_STEEL_CHAR('L'),
+ EL_STEEL_CHAR('M'),
+ EL_STEEL_CHAR('N'),
+ EL_STEEL_CHAR('O'),
+
+ EL_STEEL_CHAR('P'),
+ EL_STEEL_CHAR('Q'),
+ EL_STEEL_CHAR('R'),
+ EL_STEEL_CHAR('S'),
+
+ EL_STEEL_CHAR('T'),
+ EL_STEEL_CHAR('U'),
+ EL_STEEL_CHAR('V'),
+ EL_STEEL_CHAR('W'),
+
+ EL_STEEL_CHAR('X'),
+ EL_STEEL_CHAR('Y'),
+ EL_STEEL_CHAR('Z'),
+ EL_STEEL_CHAR('['),
+
+ EL_STEEL_CHAR('\\'),
+ EL_STEEL_CHAR(']'),
+ EL_STEEL_CHAR('^'),
+ EL_STEEL_CHAR('_'),
+
+ EL_STEEL_CHAR('©'),
+ EL_STEEL_CHAR('Ä'),
+ EL_STEEL_CHAR('Ö'),
+ EL_STEEL_CHAR('Ü'),
+
+ EL_STEEL_CHAR('°'),
+ EL_STEEL_CHAR('®'),
+ EL_STEEL_CHAR(FONT_ASCII_CURSOR),
+ EL_STEEL_CHAR(FONT_ASCII_BUTTON),
+
+ EL_STEEL_CHAR(FONT_ASCII_UP),
+ EL_STEEL_CHAR(FONT_ASCII_DOWN),
+ EL_STEEL_CHAR(' '),
+ EL_STEEL_CHAR(' ')
+};
+static int *editor_hl_steel_chars_ptr = editor_hl_steel_chars;
+static int *editor_el_steel_chars_ptr = editor_el_steel_chars;
+static int num_editor_hl_steel_chars = SIZEOF_ARRAY_INT(editor_hl_steel_chars);
+static int num_editor_el_steel_chars = SIZEOF_ARRAY_INT(editor_el_steel_chars);
+
+static int editor_hl_custom[] =
+{
+ EL_INTERNAL_CASCADE_CE_ACTIVE,
+ EL_CHAR('C'),
+ EL_CHAR('E'),
+ EL_EMPTY,
+};
+
+static int editor_el_custom[] =
+{
+ EL_CUSTOM_START + 0,
+ EL_CUSTOM_START + 1,
+ EL_CUSTOM_START + 2,
+ EL_CUSTOM_START + 3,
+
+ EL_CUSTOM_START + 4,
+ EL_CUSTOM_START + 5,
+ EL_CUSTOM_START + 6,
+ EL_CUSTOM_START + 7,
+
+ EL_CUSTOM_START + 8,
+ EL_CUSTOM_START + 9,
+ EL_CUSTOM_START + 10,
+ EL_CUSTOM_START + 11,
+
+ EL_CUSTOM_START + 12,
+ EL_CUSTOM_START + 13,
+ EL_CUSTOM_START + 14,
+ EL_CUSTOM_START + 15,
+
+ EL_CUSTOM_START + 16,
+ EL_CUSTOM_START + 17,
+ EL_CUSTOM_START + 18,
+ EL_CUSTOM_START + 19,
+
+ EL_CUSTOM_START + 20,
+ EL_CUSTOM_START + 21,
+ EL_CUSTOM_START + 22,
+ EL_CUSTOM_START + 23,
+
+ EL_CUSTOM_START + 24,
+ EL_CUSTOM_START + 25,
+ EL_CUSTOM_START + 26,
+ EL_CUSTOM_START + 27,
+
+ EL_CUSTOM_START + 28,
+ EL_CUSTOM_START + 29,
+ EL_CUSTOM_START + 30,
+ EL_CUSTOM_START + 31,
+
+ EL_CUSTOM_START + 32,
+ EL_CUSTOM_START + 33,
+ EL_CUSTOM_START + 34,
+ EL_CUSTOM_START + 35,
+
+ EL_CUSTOM_START + 36,
+ EL_CUSTOM_START + 37,
+ EL_CUSTOM_START + 38,
+ EL_CUSTOM_START + 39,
+
+ EL_CUSTOM_START + 40,
+ EL_CUSTOM_START + 41,
+ EL_CUSTOM_START + 42,
+ EL_CUSTOM_START + 43,
+
+ EL_CUSTOM_START + 44,
+ EL_CUSTOM_START + 45,
+ EL_CUSTOM_START + 46,
+ EL_CUSTOM_START + 47,
+
+ EL_CUSTOM_START + 48,
+ EL_CUSTOM_START + 49,
+ EL_CUSTOM_START + 50,
+ EL_CUSTOM_START + 51,
+
+ EL_CUSTOM_START + 52,
+ EL_CUSTOM_START + 53,
+ EL_CUSTOM_START + 54,
+ EL_CUSTOM_START + 55,
+
+ EL_CUSTOM_START + 56,
+ EL_CUSTOM_START + 57,
+ EL_CUSTOM_START + 58,
+ EL_CUSTOM_START + 59,
+
+ EL_CUSTOM_START + 60,
+ EL_CUSTOM_START + 61,
+ EL_CUSTOM_START + 62,
+ EL_CUSTOM_START + 63,
+
+ EL_CUSTOM_START + 64,
+ EL_CUSTOM_START + 65,
+ EL_CUSTOM_START + 66,
+ EL_CUSTOM_START + 67,
+
+ EL_CUSTOM_START + 68,
+ EL_CUSTOM_START + 69,
+ EL_CUSTOM_START + 70,
+ EL_CUSTOM_START + 71,
+
+ EL_CUSTOM_START + 72,
+ EL_CUSTOM_START + 73,
+ EL_CUSTOM_START + 74,
+ EL_CUSTOM_START + 75,
+
+ EL_CUSTOM_START + 76,
+ EL_CUSTOM_START + 77,
+ EL_CUSTOM_START + 78,
+ EL_CUSTOM_START + 79,
+
+ EL_CUSTOM_START + 80,
+ EL_CUSTOM_START + 81,
+ EL_CUSTOM_START + 82,
+ EL_CUSTOM_START + 83,
+
+ EL_CUSTOM_START + 84,
+ EL_CUSTOM_START + 85,
+ EL_CUSTOM_START + 86,
+ EL_CUSTOM_START + 87,
+
+ EL_CUSTOM_START + 88,
+ EL_CUSTOM_START + 89,
+ EL_CUSTOM_START + 90,
+ EL_CUSTOM_START + 91,
+
+ EL_CUSTOM_START + 92,
+ EL_CUSTOM_START + 93,
+ EL_CUSTOM_START + 94,
+ EL_CUSTOM_START + 95,
+
+ EL_CUSTOM_START + 96,
+ EL_CUSTOM_START + 97,
+ EL_CUSTOM_START + 98,
+ EL_CUSTOM_START + 99,
+
+ EL_CUSTOM_START + 100,
+ EL_CUSTOM_START + 101,
+ EL_CUSTOM_START + 102,
+ EL_CUSTOM_START + 103,
+
+ EL_CUSTOM_START + 104,
+ EL_CUSTOM_START + 105,
+ EL_CUSTOM_START + 106,
+ EL_CUSTOM_START + 107,
+
+ EL_CUSTOM_START + 108,
+ EL_CUSTOM_START + 109,
+ EL_CUSTOM_START + 110,
+ EL_CUSTOM_START + 111,
+
+ EL_CUSTOM_START + 112,
+ EL_CUSTOM_START + 113,
+ EL_CUSTOM_START + 114,
+ EL_CUSTOM_START + 115,
+
+ EL_CUSTOM_START + 116,
+ EL_CUSTOM_START + 117,
+ EL_CUSTOM_START + 118,
+ EL_CUSTOM_START + 119,
+
+ EL_CUSTOM_START + 120,
+ EL_CUSTOM_START + 121,
+ EL_CUSTOM_START + 122,
+ EL_CUSTOM_START + 123,
+
+ EL_CUSTOM_START + 124,
+ EL_CUSTOM_START + 125,
+ EL_CUSTOM_START + 126,
+ EL_CUSTOM_START + 127,
+
+ EL_CUSTOM_START + 128,
+ EL_CUSTOM_START + 129,
+ EL_CUSTOM_START + 130,
+ EL_CUSTOM_START + 131,
+
+ EL_CUSTOM_START + 132,
+ EL_CUSTOM_START + 133,
+ EL_CUSTOM_START + 134,
+ EL_CUSTOM_START + 135,
+
+ EL_CUSTOM_START + 136,
+ EL_CUSTOM_START + 137,
+ EL_CUSTOM_START + 138,
+ EL_CUSTOM_START + 139,
+
+ EL_CUSTOM_START + 140,
+ EL_CUSTOM_START + 141,
+ EL_CUSTOM_START + 142,
+ EL_CUSTOM_START + 143,
+
+ EL_CUSTOM_START + 144,
+ EL_CUSTOM_START + 145,
+ EL_CUSTOM_START + 146,
+ EL_CUSTOM_START + 147,
+
+ EL_CUSTOM_START + 148,
+ EL_CUSTOM_START + 149,
+ EL_CUSTOM_START + 150,
+ EL_CUSTOM_START + 151,
+
+ EL_CUSTOM_START + 152,
+ EL_CUSTOM_START + 153,
+ EL_CUSTOM_START + 154,
+ EL_CUSTOM_START + 155,
+
+ EL_CUSTOM_START + 156,
+ EL_CUSTOM_START + 157,
+ EL_CUSTOM_START + 158,
+ EL_CUSTOM_START + 159,
+
+ EL_CUSTOM_START + 160,
+ EL_CUSTOM_START + 161,
+ EL_CUSTOM_START + 162,
+ EL_CUSTOM_START + 163,
+
+ EL_CUSTOM_START + 164,
+ EL_CUSTOM_START + 165,
+ EL_CUSTOM_START + 166,
+ EL_CUSTOM_START + 167,
+
+ EL_CUSTOM_START + 168,
+ EL_CUSTOM_START + 169,
+ EL_CUSTOM_START + 170,
+ EL_CUSTOM_START + 171,
+
+ EL_CUSTOM_START + 172,
+ EL_CUSTOM_START + 173,
+ EL_CUSTOM_START + 174,
+ EL_CUSTOM_START + 175,
+
+ EL_CUSTOM_START + 176,
+ EL_CUSTOM_START + 177,
+ EL_CUSTOM_START + 178,
+ EL_CUSTOM_START + 179,
+
+ EL_CUSTOM_START + 180,
+ EL_CUSTOM_START + 181,
+ EL_CUSTOM_START + 182,
+ EL_CUSTOM_START + 183,
+
+ EL_CUSTOM_START + 184,
+ EL_CUSTOM_START + 185,
+ EL_CUSTOM_START + 186,
+ EL_CUSTOM_START + 187,
+
+ EL_CUSTOM_START + 188,
+ EL_CUSTOM_START + 189,
+ EL_CUSTOM_START + 190,
+ EL_CUSTOM_START + 191,
+
+ EL_CUSTOM_START + 192,
+ EL_CUSTOM_START + 193,
+ EL_CUSTOM_START + 194,
+ EL_CUSTOM_START + 195,
+
+ EL_CUSTOM_START + 196,
+ EL_CUSTOM_START + 197,
+ EL_CUSTOM_START + 198,
+ EL_CUSTOM_START + 199,
+
+ EL_CUSTOM_START + 200,
+ EL_CUSTOM_START + 201,
+ EL_CUSTOM_START + 202,
+ EL_CUSTOM_START + 203,
+
+ EL_CUSTOM_START + 204,
+ EL_CUSTOM_START + 205,
+ EL_CUSTOM_START + 206,
+ EL_CUSTOM_START + 207,
+
+ EL_CUSTOM_START + 208,
+ EL_CUSTOM_START + 209,
+ EL_CUSTOM_START + 210,
+ EL_CUSTOM_START + 211,
+
+ EL_CUSTOM_START + 212,
+ EL_CUSTOM_START + 213,
+ EL_CUSTOM_START + 214,
+ EL_CUSTOM_START + 215,
+
+ EL_CUSTOM_START + 216,
+ EL_CUSTOM_START + 217,
+ EL_CUSTOM_START + 218,
+ EL_CUSTOM_START + 219,
+
+ EL_CUSTOM_START + 220,
+ EL_CUSTOM_START + 221,
+ EL_CUSTOM_START + 222,
+ EL_CUSTOM_START + 223,
+
+ EL_CUSTOM_START + 224,
+ EL_CUSTOM_START + 225,
+ EL_CUSTOM_START + 226,
+ EL_CUSTOM_START + 227,
+
+ EL_CUSTOM_START + 228,
+ EL_CUSTOM_START + 229,
+ EL_CUSTOM_START + 230,
+ EL_CUSTOM_START + 231,
+
+ EL_CUSTOM_START + 232,
+ EL_CUSTOM_START + 233,
+ EL_CUSTOM_START + 234,
+ EL_CUSTOM_START + 235,
+
+ EL_CUSTOM_START + 236,
+ EL_CUSTOM_START + 237,
+ EL_CUSTOM_START + 238,
+ EL_CUSTOM_START + 239,
+
+ EL_CUSTOM_START + 240,
+ EL_CUSTOM_START + 241,
+ EL_CUSTOM_START + 242,
+ EL_CUSTOM_START + 243,
+
+ EL_CUSTOM_START + 244,
+ EL_CUSTOM_START + 245,
+ EL_CUSTOM_START + 246,
+ EL_CUSTOM_START + 247,
+
+ EL_CUSTOM_START + 248,
+ EL_CUSTOM_START + 249,
+ EL_CUSTOM_START + 250,
+ EL_CUSTOM_START + 251,
+
+ EL_CUSTOM_START + 252,
+ EL_CUSTOM_START + 253,
+ EL_CUSTOM_START + 254,
+ EL_CUSTOM_START + 255
+};
+static int *editor_hl_custom_ptr = editor_hl_custom;
+static int *editor_el_custom_ptr = editor_el_custom;
+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_group[] =
+{
+ EL_INTERNAL_CASCADE_GE_ACTIVE,
+ EL_CHAR('G'),
+ EL_CHAR('E'),
+ EL_EMPTY,
+};
+
+static int editor_el_group[] =
+{
+ EL_GROUP_START + 0,
+ EL_GROUP_START + 1,
+ EL_GROUP_START + 2,
+ EL_GROUP_START + 3,
+
+ EL_GROUP_START + 4,
+ EL_GROUP_START + 5,
+ EL_GROUP_START + 6,
+ EL_GROUP_START + 7,
+
+ EL_GROUP_START + 8,
+ EL_GROUP_START + 9,
+ EL_GROUP_START + 10,
+ EL_GROUP_START + 11,
+
+ EL_GROUP_START + 12,
+ EL_GROUP_START + 13,
+ EL_GROUP_START + 14,
+ EL_GROUP_START + 15,
+
+ EL_GROUP_START + 16,
+ EL_GROUP_START + 17,
+ EL_GROUP_START + 18,
+ EL_GROUP_START + 19,
+
+ EL_GROUP_START + 20,
+ EL_GROUP_START + 21,
+ EL_GROUP_START + 22,
+ EL_GROUP_START + 23,
+
+ EL_GROUP_START + 24,
+ EL_GROUP_START + 25,
+ EL_GROUP_START + 26,
+ EL_GROUP_START + 27,
+
+ EL_GROUP_START + 28,
+ EL_GROUP_START + 29,
+ EL_GROUP_START + 30,
+ EL_GROUP_START + 31
+};
+static int *editor_hl_group_ptr = editor_hl_group;
+static int *editor_el_group_ptr = editor_el_group;
+static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group);
+static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group);
+
+static int editor_hl_reference[] =
+{
+ EL_INTERNAL_CASCADE_REF_ACTIVE,
+ EL_CHAR('R'),
+ EL_CHAR('E'),
+ EL_CHAR('F')
+};
+
+static int editor_el_reference[] =
+{
+ EL_TRIGGER_PLAYER,
+ EL_TRIGGER_ELEMENT,
+ EL_TRIGGER_CE_VALUE,
+ EL_TRIGGER_CE_SCORE,
+
+ EL_SELF,
+ EL_ANY_ELEMENT,
+ EL_CURRENT_CE_VALUE,
+ EL_CURRENT_CE_SCORE,
+
+ EL_PREV_CE_8,
+ EL_PREV_CE_7,
+ EL_PREV_CE_6,
+ EL_PREV_CE_5,
+
+ EL_PREV_CE_4,
+ EL_PREV_CE_3,
+ EL_PREV_CE_2,
+ EL_PREV_CE_1,
+
+ EL_NEXT_CE_1,
+ EL_NEXT_CE_2,
+ EL_NEXT_CE_3,
+ EL_NEXT_CE_4,
+
+ EL_NEXT_CE_5,
+ EL_NEXT_CE_6,
+ EL_NEXT_CE_7,
+ EL_NEXT_CE_8,
+};
+static int *editor_hl_reference_ptr = editor_hl_reference;
+static int *editor_el_reference_ptr = editor_el_reference;
+static int num_editor_hl_reference = SIZEOF_ARRAY_INT(editor_hl_reference);
+static int num_editor_el_reference = SIZEOF_ARRAY_INT(editor_el_reference);
+
+static int editor_hl_user_defined[] =
+{
+ EL_INTERNAL_CASCADE_USER_ACTIVE,
+ EL_CHAR('M'),
+ EL_CHAR('Y'),
+ EL_EMPTY,
+};
+
+static int *editor_hl_user_defined_ptr = editor_hl_user_defined;
+static int *editor_el_user_defined_ptr = NULL;
+static int num_editor_hl_user_defined=SIZEOF_ARRAY_INT(editor_hl_user_defined);
+static int num_editor_el_user_defined = 0;
+
+static int editor_hl_dynamic[] =
+{
+ EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
+ EL_CHAR('U'),
+ EL_CHAR('S'),
+ EL_CHAR('E'),
+};
+
+static int *editor_hl_dynamic_ptr = editor_hl_dynamic;
+static int *editor_el_dynamic_ptr = NULL;
+static int num_editor_hl_dynamic = SIZEOF_ARRAY_INT(editor_hl_dynamic);
+static int num_editor_el_dynamic = 0;
+
+static int editor_hl_empty[] = { EL_EMPTY };
+static int *editor_el_empty = NULL; /* dynamically allocated */
+
+static int *editor_hl_empty_ptr = editor_hl_empty;
+static int *editor_el_empty_ptr = NULL;
+static int num_editor_hl_empty = 0;
+static int num_editor_el_empty = 0; /* dynamically determined, if needed */
+
+static boolean use_el_empty = FALSE;
+
+static int *editor_elements = NULL; /* dynamically allocated */
+static int num_editor_elements = 0; /* dynamically determined */
+
+static boolean setup_editor_show_always = TRUE;
+static boolean setup_editor_cascade_never = FALSE;
+
+static int editor_hl_unused[] = { EL_EMPTY };
+static int *editor_hl_unused_ptr = editor_hl_unused;
+static int num_editor_hl_unused = 0;
+
+static struct
+{
+ boolean *setup_value;
+ boolean *setup_cascade_value;
+
+ int **headline_list;
+ int *headline_list_size;
+
+ int **element_list;
+ int *element_list_size;
+
+ boolean last_setup_value;
+}
+editor_elements_info[] =
+{
+ {
+ &setup_editor_show_always,
+ &setup_editor_cascade_never,
+ &editor_hl_unused_ptr, &num_editor_hl_unused,
+ &editor_el_players_ptr, &num_editor_el_players
+ },
+ {
+ &setup.editor.el_boulderdash,
+ &setup.editor_cascade.el_bd,
+ &editor_hl_boulderdash_ptr, &num_editor_hl_boulderdash,
+ &editor_el_boulderdash_ptr, &num_editor_el_boulderdash
+ },
+ {
+ &setup.editor.el_emerald_mine,
+ &setup.editor_cascade.el_em,
+ &editor_hl_emerald_mine_ptr, &num_editor_hl_emerald_mine,
+ &editor_el_emerald_mine_ptr, &num_editor_el_emerald_mine
+ },
+ {
+ &setup.editor.el_emerald_mine_club,
+ &setup.editor_cascade.el_emc,
+ &editor_hl_emerald_mine_club_ptr, &num_editor_hl_emerald_mine_club,
+ &editor_el_emerald_mine_club_ptr, &num_editor_el_emerald_mine_club
+ },
+ {
+ &setup.editor.el_more,
+ &setup.editor_cascade.el_rnd,
+ &editor_hl_rnd_ptr, &num_editor_hl_rnd,
+ &editor_el_rnd_ptr, &num_editor_el_rnd
+ },
+ {
+ &setup.editor.el_sokoban,
+ &setup.editor_cascade.el_sb,
+ &editor_hl_sokoban_ptr, &num_editor_hl_sokoban,
+ &editor_el_sokoban_ptr, &num_editor_el_sokoban
+ },
+ {
+ &setup.editor.el_supaplex,
+ &setup.editor_cascade.el_sp,
+ &editor_hl_supaplex_ptr, &num_editor_hl_supaplex,
+ &editor_el_supaplex_ptr, &num_editor_el_supaplex
+ },
+ {
+ &setup.editor.el_diamond_caves,
+ &setup.editor_cascade.el_dc,
+ &editor_hl_diamond_caves_ptr, &num_editor_hl_diamond_caves,
+ &editor_el_diamond_caves_ptr, &num_editor_el_diamond_caves
+ },
+ {
+ &setup.editor.el_dx_boulderdash,
+ &setup.editor_cascade.el_dx,
+ &editor_hl_dx_boulderdash_ptr, &num_editor_hl_dx_boulderdash,
+ &editor_el_dx_boulderdash_ptr, &num_editor_el_dx_boulderdash
+ },
+ {
+ &setup.editor.el_chars,
+ &setup.editor_cascade.el_chars,
+ &editor_hl_chars_ptr, &num_editor_hl_chars,
+ &editor_el_chars_ptr, &num_editor_el_chars
+ },
+ {
+ &setup.editor.el_steel_chars,
+ &setup.editor_cascade.el_steel_chars,
+ &editor_hl_steel_chars_ptr, &num_editor_hl_steel_chars,
+ &editor_el_steel_chars_ptr, &num_editor_el_steel_chars
+ },
+ {
+ &setup.editor.el_custom,
+ &setup.editor_cascade.el_ce,
+ &editor_hl_custom_ptr, &num_editor_hl_custom,
+ &editor_el_custom_ptr, &num_editor_el_custom
+ },
+ {
+ &setup.editor.el_custom,
+ &setup.editor_cascade.el_ge,
+ &editor_hl_group_ptr, &num_editor_hl_group,
+ &editor_el_group_ptr, &num_editor_el_group
+ },
+ {
+ &setup.editor.el_custom,
+ &setup.editor_cascade.el_ref,
+ &editor_hl_reference_ptr, &num_editor_hl_reference,
+ &editor_el_reference_ptr, &num_editor_el_reference
+ },
+ {
+ &setup.editor.el_user_defined,
+ &setup.editor_cascade.el_user,
+ &editor_hl_user_defined_ptr, &num_editor_hl_user_defined,
+ &editor_el_user_defined_ptr, &num_editor_el_user_defined
+ },
+ {
+ &setup.editor.el_dynamic,
+ &setup.editor_cascade.el_dynamic,
+ &editor_hl_dynamic_ptr, &num_editor_hl_dynamic,
+ &editor_el_dynamic_ptr, &num_editor_el_dynamic,
+ },
+ {
+ &use_el_empty,
+ &use_el_empty,
+ &editor_hl_empty_ptr, &num_editor_hl_empty,
+ &editor_el_empty_ptr, &num_editor_el_empty,
+ },
+ {
+ NULL,
+ NULL,
+ NULL, NULL,
+ NULL, NULL
+ }
+};
+
+
+/*
+ -----------------------------------------------------------------------------
+ functions
+ -----------------------------------------------------------------------------
+*/
+
+static int getMaxInfoTextLength()
+{
+ return (SXSIZE / getFontWidth(FONT_TEXT_2));
+}
+
+static int getTextWidthForGadget(char *text)
+{
+ if (text == NULL)
+ return 0;
+
+ return (getTextWidth(text, FONT_TEXT_1) + ED_GADGET_TEXT_DISTANCE);
+}
+
+static int getTextWidthForDrawingArea(char *text)
+{
+ if (text == NULL)
+ return 0;
+
+ return (getTextWidth(text, FONT_TEXT_1) + ED_DRAWINGAREA_TEXT_DISTANCE);
+}
+
+static int getRightGadgetBorder(struct GadgetInfo *gi, char *text)
+{
+ return (gi->x + gi->width + getTextWidthForGadget(text));
+}
+
+static char *getElementInfoText(int element)
+{
+ char *info_text = NULL;
+
+ if (element < MAX_NUM_ELEMENTS)
+ {
+ if (strlen(element_info[element].description) > 0)
+ info_text = element_info[element].description;
+ else if (element_info[element].custom_description != NULL)
+ info_text = element_info[element].custom_description;
+ else if (element_info[element].editor_description != NULL)
+ info_text = element_info[element].editor_description;
+ }
+
+ if (info_text == NULL)
+ info_text = INFOTEXT_UNKNOWN_ELEMENT;
+
+ return info_text;
+}
+
+char *getElementDescriptionFilename(int element)
+{
+ char *docs_dir = options.docs_directory;
+ char *elements_subdir = "elements";
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ checked_free(filename);
+
+ /* 1st try: look for element description file for exactly this element */
+ sprintf(basename, "%s.txt", element_info[element].token_name);
+ filename = getPath3(docs_dir, elements_subdir, basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ /* 2nd try: look for element description file for this element's class */
+ sprintf(basename, "%s.txt", element_info[element].class_name);
+ filename = getPath3(docs_dir, elements_subdir, basename);
+ if (fileExists(filename))
+ return filename;
+
+ return NULL;
+}
+
+static void InitDynamicEditorElementList(int **elements, int *num_elements)
+{
+ boolean element_found[NUM_FILE_ELEMENTS];
+ int i, x, y;
+
+ /* initialize list of used elements to "not used" */
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ element_found[i] = FALSE;
+
+ /* find all elements used in current level */
+ for (y = 0; y < lev_fieldy; y++)
+ for (x = 0; x < lev_fieldx; x++)
+ if (Feld[x][y] < NUM_FILE_ELEMENTS) /* should always be true */
+ element_found[Feld[x][y]] = TRUE;
+
+ *num_elements = 0;
+
+ /* count number of elements used in current level */
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ if (element_found[i])
+ (*num_elements)++;
+
+ /* add space for up to 3 more elements for padding that may be needed */
+ *num_elements += 3;
+
+ /* free memory for old list of elements, if needed */
+ checked_free(*elements);
+
+ /* allocate memory for new list of elements */
+ *elements = checked_malloc(*num_elements * sizeof(int));
+
+ *num_elements = 0;
+
+ /* add all elements used in current level (non-custom/group elements) */
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+ (*elements)[(*num_elements)++] = i;
+
+ /* add all elements used in current level (custom/group elements) */
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+ (*elements)[(*num_elements)++] = i;
+
+ while (*num_elements % 4) /* pad with empty elements, if needed */
+ (*elements)[(*num_elements)++] = EL_EMPTY;
+}
+
+static void ReinitializeElementList()
+{
+ static boolean initialization_needed = TRUE;
+ int pos = 0;
+ int i, j;
+
+ if (initialization_needed)
+ {
+ LoadSetup_EditorCascade(); /* load last editor cascade state */
+
+ /* initialize editor cascade element from saved cascade state */
+ for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
+ {
+ int *cascade_element = &(*editor_elements_info[i].headline_list)[0];
+ boolean cascade_value = *editor_elements_info[i].setup_cascade_value;
+
+ if (IS_EDITOR_CASCADE(*cascade_element))
+ *cascade_element =
+ (cascade_value ? EL_CASCADE_ACTIVE(*cascade_element) :
+ EL_CASCADE_INACTIVE(*cascade_element));
+ }
+
+ initialization_needed = FALSE;
+ }
+
+ checked_free(editor_elements);
+
+ /* reload optional user defined element list for each invocation of editor */
+ LoadUserDefinedEditorElementList(&editor_el_user_defined_ptr,
+ &num_editor_el_user_defined);
+
+ /* initialize dynamic level element list for each invocation of editor */
+ InitDynamicEditorElementList(&editor_el_dynamic_ptr,
+ &num_editor_el_dynamic);
+
+ /* initialize list of empty elements (used for padding, if needed) */
+ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
+ editor_el_empty[i] = EL_EMPTY;
+
+ /* do some sanity checks for each element from element list */
+ for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
+ {
+ for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
+ {
+ int element = (*editor_elements_info[i].element_list)[j];
+
+ if (element >= NUM_FILE_ELEMENTS)
+ Error(ERR_WARN, "editor element %d is runtime element", element);
+
+ if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
+ Error(ERR_WARN, "no element description for element %d", element);
+ }
+ }
+
+ num_editor_elements = 0;
+ use_el_empty = FALSE;
+
+ /* 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)
+ {
+ if (setup.editor.el_headlines)
+ {
+ num_editor_elements += *editor_elements_info[i].headline_list_size;
+
+ for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
+ {
+ int element = (*editor_elements_info[i].headline_list)[j];
+
+ if (IS_EDITOR_CASCADE_INACTIVE(element))
+ found_inactive_cascade = TRUE;
+ }
+ }
+
+ if (found_inactive_cascade)
+ continue;
+
+ num_editor_elements += *editor_elements_info[i].element_list_size;
+ }
+ }
+
+ if (num_editor_elements < ED_NUM_ELEMENTLIST_BUTTONS)
+ {
+ /* offer at least as many elements as element buttons exist */
+ use_el_empty = TRUE;
+ num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS - num_editor_elements;
+
+ num_editor_elements += num_editor_el_empty;
+ }
+
+ editor_elements = checked_malloc(num_editor_elements * sizeof(int));
+
+ /* fill element list */
+ for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
+ {
+ boolean found_inactive_cascade = FALSE;
+
+ if (*editor_elements_info[i].setup_value)
+ {
+ if (setup.editor.el_headlines)
+ {
+ for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
+ {
+ int element = (*editor_elements_info[i].headline_list)[j];
+
+ editor_elements[pos++] = element;
+
+ if (IS_EDITOR_CASCADE_INACTIVE(element))
+ found_inactive_cascade = TRUE;
+ }
+ }
+
+ if (found_inactive_cascade)
+ continue;
+
+ for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
+ editor_elements[pos++] = (*editor_elements_info[i].element_list)[j];
+ }
+ }
+
+ /* (this function is also called before editor gadgets are initialized!) */
+ AdjustElementListScrollbar();
+}
+
+void PrintEditorElementList()
+{
+ boolean *stop = &setup.editor.el_user_defined;
+ int i, j;
+
+ for (i = 0; editor_elements_info[i].setup_value != stop; i++)
+ {
+ int cascade_element = (*editor_elements_info[i].headline_list)[0];
+
+ if (IS_EDITOR_CASCADE(cascade_element))
+ {
+ int cascade_element_show = EL_CASCADE_INACTIVE(cascade_element);
+ char *headline = element_info[cascade_element_show].editor_description;
+
+ printf_line_with_prefix("# ", "-", 77);
+ printf("# %s\n", headline);
+ printf_line_with_prefix("# ", "-", 77);
+ }
+
+ for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
+ {
+ int element = (*editor_elements_info[i].headline_list)[j];
+
+ if (IS_EDITOR_CASCADE(element))
+ element = EL_CHAR_MINUS;
+
+ printf("# %s\n", element_info[element].token_name);
+ }
+
+ if (j > 0)
+ printf("#\n");
+
+ for (j = 0; j < *editor_elements_info[i].element_list_size; j++)
+ {
+ int element = (*editor_elements_info[i].element_list)[j];
+
+ printf("# %s\n", element_info[element].token_name);
+ }
+
+ if (j > 0)
+ printf("#\n");
+ }
+}
+
+static void ReinitializeElementListButtons()
+{
+ static boolean last_setup_value_headlines = FALSE;
+ 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;
+
+ FreeLevelEditorGadgets();
+ 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;
+
+ initialization_needed = FALSE;
+}
+
+static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
+ boolean input)
+{
+ int border_graphic =
+ (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
+ Bitmap *src_bitmap;
+ int src_x, src_y;
+ int bx = (input ? 4 : 8);
+ int by = (input ? 4 : 8);
+ int bx2 = TILEX - bx;
+ int by2 = TILEY - by;
+ int i;
+
+ getFixedGraphicSource(border_graphic, 0, &src_bitmap, &src_x, &src_y);
+
+ BlitBitmap(src_bitmap, drawto, src_x, src_y,
+ bx, by, dest_x - bx, dest_y - by);
+ BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y,
+ bx, by, dest_x + width, dest_y - by);
+ BlitBitmap(src_bitmap, drawto, src_x, src_y + by2,
+ bx, by, dest_x - bx, dest_y + height);
+ BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y + by2,
+ bx, by, dest_x + width, dest_y + height);
+
+ for (i = 0; i < width / MINI_TILEX; i++)
+ {
+ BlitBitmap(src_bitmap, drawto, src_x + bx, src_y, MINI_TILEX, by,
+ dest_x + i * MINI_TILEX, dest_y - by);
+ BlitBitmap(src_bitmap, drawto, src_x + bx, src_y + by2, MINI_TILEX, by,
+ dest_x + i * MINI_TILEX, dest_y + height);
+ }
+
+ for (i = 0; i < height / MINI_TILEY; i++)
+ {
+ BlitBitmap(src_bitmap, drawto, src_x, src_y + by, bx, MINI_TILEY,
+ dest_x - bx, dest_y + i * MINI_TILEY);
+ BlitBitmap(src_bitmap, drawto, src_x + bx2, src_y + by, bx, MINI_TILEY,
+ dest_x + width, dest_y + i * MINI_TILEY);
+ }
+
+ ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
+}
+
+static void DrawDrawingArea(int id)
+{
+ struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
+ int x, y;
+
+ int *value = drawingarea_info[id].value;
+ int area_xsize = drawingarea_info[id].area_xsize;
+ int area_ysize = drawingarea_info[id].area_ysize;
+
+ for (x = 0; x < area_xsize; x++)
+ for (y = 0; y < area_ysize; y++)
+ DrawMiniGraphicExt(drawto,
+ gi->x + x * MINI_TILEX,
+ gi->y + y * MINI_TILEY,
+ el2edimg(value[x * area_ysize + y]));
+}
+
+static void ScrollMiniLevel(int from_x, int from_y, int scroll)
+{
+ int x, y;
+ int dx = (scroll == ED_SCROLL_LEFT ? -1 : scroll == ED_SCROLL_RIGHT ? 1 : 0);
+ int dy = (scroll == ED_SCROLL_UP ? -1 : scroll == ED_SCROLL_DOWN ? 1 : 0);
+
+ BlitBitmap(drawto, drawto,
+ SX + (dx == -1 ? MINI_TILEX : 0),
+ SY + (dy == -1 ? MINI_TILEY : 0),
+ (ed_fieldx * MINI_TILEX) - (dx != 0 ? MINI_TILEX : 0),
+ (ed_fieldy * MINI_TILEY) - (dy != 0 ? MINI_TILEY : 0),
+ SX + (dx == +1 ? MINI_TILEX : 0),
+ SY + (dy == +1 ? MINI_TILEY : 0));
+
+ if (dx)
+ {
+ x = (dx == 1 ? 0 : ed_fieldx - 1);
+ for (y = 0; y < ed_fieldy; y++)
+ DrawMiniElementOrWall(x, y, from_x, from_y);
+ }
+ else if (dy)
+ {
+ y = (dy == 1 ? 0 : ed_fieldy - 1);
+ for (x = 0; x < ed_fieldx; x++)
+ DrawMiniElementOrWall(x, y, from_x, from_y);
+ }
+
+ redraw_mask |= REDRAW_FIELD;
+ BackToFront();
+}
+
+static void CreateControlButtons()
+{
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ struct GadgetInfo *gi;
+ unsigned int event_mask;
+ int i;
+
+ /* create toolbox buttons */
+ for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
+ {
+ int id = i;
+ int width, height;
+ int gd_xoffset, gd_yoffset;
+ int gd_x1, gd_x2, gd_y1, gd_y2;
+ int button_type;
+ int radio_button_nr;
+ boolean checked;
+
+ if (id == GADGET_ID_SINGLE_ITEMS ||
+ id == GADGET_ID_CONNECTED_ITEMS ||
+ id == GADGET_ID_LINE ||
+ id == GADGET_ID_ARC ||
+ id == GADGET_ID_TEXT ||
+ id == GADGET_ID_RECTANGLE ||
+ id == GADGET_ID_FILLED_BOX ||
+ id == GADGET_ID_FLOOD_FILL ||
+ id == GADGET_ID_GRAB_BRUSH ||
+ id == GADGET_ID_PICK_ELEMENT ||
+ id == GADGET_ID_CUSTOM_COPY_FROM ||
+ id == GADGET_ID_CUSTOM_COPY_TO ||
+ id == GADGET_ID_CUSTOM_EXCHANGE)
+ {
+ button_type = GD_TYPE_RADIO_BUTTON;
+ radio_button_nr = RADIO_NR_DRAWING_TOOLBOX;
+ checked = (id == drawing_function ? TRUE : FALSE);
+ event_mask = GD_EVENT_PRESSED;
+ }
+ else
+ {
+ button_type = GD_TYPE_NORMAL_BUTTON;
+ radio_button_nr = RADIO_NR_NONE;
+ checked = FALSE;
+
+ if (id == GADGET_ID_WRAP_LEFT ||
+ id == GADGET_ID_WRAP_RIGHT ||
+ id == GADGET_ID_WRAP_UP ||
+ id == GADGET_ID_WRAP_DOWN)
+ event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+ else
+ event_mask = GD_EVENT_RELEASED;
+ }
+
+ if (id < ED_NUM_CTRL1_BUTTONS)
+ {
+ int x = i % ED_CTRL1_BUTTONS_HORIZ;
+ int y = i / ED_CTRL1_BUTTONS_HORIZ;
+
+ gd_xoffset = ED_CTRL1_BUTTONS_XPOS + x * ED_CTRL1_BUTTON_XSIZE;
+ gd_yoffset = ED_CTRL1_BUTTONS_YPOS + y * ED_CTRL1_BUTTON_YSIZE;
+ width = ED_CTRL1_BUTTON_XSIZE;
+ height = ED_CTRL1_BUTTON_YSIZE;
+
+ gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
+ gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
+ gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_GFX_YPOS + gd_yoffset;
+ gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL1_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
+ }
+ else if (id < ED_NUM_CTRL1_2_BUTTONS)
+ {
+ int x = (i - ED_NUM_CTRL1_BUTTONS) % ED_CTRL2_BUTTONS_HORIZ;
+ int y = (i - ED_NUM_CTRL1_BUTTONS) / ED_CTRL2_BUTTONS_HORIZ;
+
+ gd_xoffset = ED_CTRL2_BUTTONS_XPOS + x * ED_CTRL2_BUTTON_XSIZE;
+ gd_yoffset = ED_CTRL2_BUTTONS_YPOS + y * ED_CTRL2_BUTTON_YSIZE;
+ width = ED_CTRL2_BUTTON_XSIZE;
+ height = ED_CTRL2_BUTTON_YSIZE;
+
+ gd_x1 = DOOR_GFX_PAGEX8 + gd_xoffset;
+ gd_x2 = DOOR_GFX_PAGEX7 + gd_xoffset;
+ gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL2_BUTTONS_GFX_YPOS + gd_yoffset;
+ gd_y2 = 0; /* no alternative graphic for these buttons */
+ }
+ else if (id < ED_NUM_CTRL1_3_BUTTONS)
+ {
+ int x = (i - ED_NUM_CTRL1_2_BUTTONS) % ED_CTRL3_BUTTONS_HORIZ + 1;
+ int y = (i - ED_NUM_CTRL1_2_BUTTONS) / ED_CTRL3_BUTTONS_HORIZ;
+
+ gd_xoffset = ED_CTRL3_BUTTONS_XPOS + x * ED_CTRL3_BUTTON_XSIZE;
+ gd_yoffset = ED_CTRL3_BUTTONS_YPOS + y * ED_CTRL3_BUTTON_YSIZE;
+ width = ED_CTRL3_BUTTON_XSIZE;
+ height = ED_CTRL3_BUTTON_YSIZE;
+
+ gd_x1 = DOOR_GFX_PAGEX6 + gd_xoffset;
+ gd_x2 = DOOR_GFX_PAGEX5 + gd_xoffset;
+ gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_GFX_YPOS + gd_yoffset;
+ gd_y2 = DOOR_GFX_PAGEY1 + ED_CTRL3_BUTTONS_ALT_GFX_YPOS + gd_yoffset;
+ }
+ else
+ {
+ int x = (i - ED_NUM_CTRL1_3_BUTTONS) % ED_CTRL4_BUTTONS_HORIZ;
+ int y = (i - ED_NUM_CTRL1_3_BUTTONS) / ED_CTRL4_BUTTONS_HORIZ + 3;
+
+ gd_xoffset = ED_CTRL4_BUTTONS_XPOS + x * ED_CTRL4_BUTTON_XSIZE;
+ gd_yoffset = ED_CTRL4_BUTTONS_YPOS + y * ED_CTRL4_BUTTON_YSIZE;
+ width = ED_CTRL4_BUTTON_XSIZE;
+ height = ED_CTRL4_BUTTON_YSIZE;
+
+ gd_x1 = DOOR_GFX_PAGEX6 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
+ gd_x2 = DOOR_GFX_PAGEX5 + ED_CTRL4_BUTTONS_GFX_XPOS + gd_xoffset;
+ gd_y1 = DOOR_GFX_PAGEY1 + ED_CTRL4_BUTTONS_GFX_YPOS + gd_yoffset;
+ gd_y2 = 0; /* no alternative graphic for these buttons */
+ }
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, control_info[i].text,
+ GDI_X, EX + gd_xoffset,
+ GDI_Y, EY + gd_yoffset,
+ GDI_WIDTH, width,
+ GDI_HEIGHT, height,
+ GDI_TYPE, button_type,
+ GDI_STATE, GD_BUTTON_UNPRESSED,
+ GDI_RADIO_NR, radio_button_nr,
+ GDI_CHECKED, checked,
+ GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
+ GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
+ GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
+ GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleControlButtons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ }
+
+ /* these values are not constant, but can change at runtime */
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].x = ED_SCROLL_UP_XPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_UP].y = ED_SCROLL_UP_YPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].x = ED_SCROLL_DOWN_XPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y = ED_SCROLL_DOWN_YPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].x = ED_SCROLL_LEFT_XPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_LEFT].y = ED_SCROLL_LEFT_YPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x = ED_SCROLL_RIGHT_XPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].y = ED_SCROLL_RIGHT_YPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].x = ED_SCROLL2_UP_XPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_UP].y = ED_SCROLL2_UP_YPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].x = ED_SCROLL2_DOWN_XPOS;
+ scrollbutton_pos[ED_SCROLLBUTTON_ID_LIST_DOWN].y = ED_SCROLL2_DOWN_YPOS;
+
+ /* create buttons for scrolling of drawing area and element list */
+ for (i = 0; i < ED_NUM_SCROLLBUTTONS; i++)
+ {
+ int id = scrollbutton_info[i].gadget_id;
+ int graphic = scrollbutton_info[i].graphic;
+ struct GraphicInfo *gd = &graphic_info[graphic];
+ int x, y, width, height;
+ int gd_x1, gd_x2, gd_y1, gd_y2;
+
+ x = scrollbutton_pos[i].x;
+ y = scrollbutton_pos[i].y;
+
+ event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+
+ if (id == GADGET_ID_SCROLL_LIST_UP ||
+ id == GADGET_ID_SCROLL_LIST_DOWN)
+ {
+ x += DX;
+ y += DY;
+ width = gd->width;
+ height = gd->height;
+ gd_x1 = gd->src_x;
+ gd_y1 = gd->src_y;
+ gd_x2 = gd->src_x + gd->pressed_xoffset;
+ gd_y2 = gd->src_y + gd->pressed_yoffset;
+ }
+ else
+ {
+ x += SX;
+ y += SY;
+ width = gd->width;
+ height = gd->height;
+ gd_x1 = gd->src_x;
+ gd_y1 = gd->src_y;
+ gd_x2 = gd->src_x + gd->pressed_xoffset;
+ gd_y2 = gd->src_y + gd->pressed_yoffset;
+ }
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, scrollbutton_info[i].infotext,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_WIDTH, width,
+ GDI_HEIGHT, 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, HandleControlButtons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ }
+
+ /* create buttons for element list */
+ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
+ {
+ struct GraphicInfo *gd = &graphic_info[IMG_EDITOR_PALETTE_BUTTON];
+ Bitmap *deco_bitmap;
+ int deco_x, deco_y, deco_xpos, deco_ypos;
+ int gd_xoffset, gd_yoffset;
+ int gd_x1, gd_y1, gd_x2, gd_y2;
+ int x = i % ED_ELEMENTLIST_BUTTONS_HORIZ;
+ int y = i / ED_ELEMENTLIST_BUTTONS_HORIZ;
+ int id = GADGET_ID_ELEMENTLIST_FIRST + i;
+ int element = editor_elements[i];
+
+ event_mask = GD_EVENT_RELEASED;
+
+ gd_xoffset = ED_ELEMENTLIST_XPOS + x * gd->width;
+ gd_yoffset = ED_ELEMENTLIST_YPOS + y * gd->height;
+
+ gd_x1 = gd->src_x;
+ gd_y1 = gd->src_y;
+ gd_x2 = gd->src_x + gd->pressed_xoffset;
+ gd_y2 = gd->src_y + gd->pressed_yoffset;
+
+ getMiniGraphicSource(el2edimg(element), &deco_bitmap, &deco_x, &deco_y);
+ deco_xpos = (gd->width - MINI_TILEX) / 2;
+ deco_ypos = (gd->height - MINI_TILEY) / 2;
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, getElementInfoText(element),
+ GDI_X, DX + gd_xoffset,
+ GDI_Y, DY + gd_yoffset,
+ GDI_WIDTH, gd->width,
+ GDI_HEIGHT, gd->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_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
+ GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
+ GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
+ GDI_DECORATION_SHIFTING, 1, 1,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleControlButtons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ }
+}
+
+static void CreateCounterButtons()
+{
+ int max_infotext_len = getMaxInfoTextLength();
+ int i;
+
+ /* these values are not constant, but can change at runtime */
+ counterbutton_info[ED_COUNTER_ID_SELECT_LEVEL].x = DX + 5 - SX;
+ counterbutton_info[ED_COUNTER_ID_SELECT_LEVEL].y = DY + 3 - SY;
+
+ for (i = 0; i < ED_NUM_COUNTERBUTTONS; i++)
+ {
+ int j;
+ int x = SX + counterbutton_info[i].x; /* down count button */
+ int y = SY + counterbutton_info[i].y;
+
+ /* determine horizontal position to the right of specified gadget */
+ if (counterbutton_info[i].gadget_id_align != GADGET_ID_NONE)
+ x = (right_gadget_border[counterbutton_info[i].gadget_id_align] +
+ ED_GADGET_TEXT_DISTANCE);
+
+ /* determine horizontal offset for leading text */
+ if (counterbutton_info[i].text_left != NULL)
+ x += getTextWidthForGadget(counterbutton_info[i].text_left);
+
+ for (j = 0; j < 2; j++)
+ {
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ struct GadgetInfo *gi;
+ int id = (j == 0 ?
+ counterbutton_info[i].gadget_id_down :
+ counterbutton_info[i].gadget_id_up);
+ int gd_xoffset;
+ int gd_x, gd_y, gd_x1, gd_x2, gd_y1, gd_y2;
+ int x_size, y_size;
+ unsigned int event_mask;
+ char infotext[max_infotext_len + 1];
+
+ event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+
+ if (i == ED_COUNTER_ID_SELECT_LEVEL)
+ {
+ int graphic = (j == 0 ?
+ IMG_EDITOR_BUTTON_GFX_PREV_LEVEL :
+ IMG_EDITOR_BUTTON_GFX_NEXT_LEVEL);
+ struct GraphicInfo *gd = &graphic_info[graphic];
+
+ gd_bitmap = gd->bitmap;
+
+ event_mask |= GD_EVENT_RELEASED;
+
+ if (j == 1)
+ x += 2 * ED_GADGET_DISTANCE;
+ y += ED_GADGET_DISTANCE;
+
+ gd_x1 = gd->src_x;
+ gd_y1 = gd->src_y;
+ gd_x2 = gd->src_x + gd->pressed_xoffset;
+ gd_y2 = gd->src_y + gd->pressed_yoffset;
+ x_size = gd->width;
+ y_size = gd->height;
+ }
+ else
+ {
+ gd_xoffset = (j == 0 ? ED_BUTTON_MINUS_XPOS : ED_BUTTON_PLUS_XPOS);
+ gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
+ gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
+ gd_y1 = DOOR_GFX_PAGEY1 + ED_BUTTON_COUNT_YPOS;
+ gd_y2 = gd_y1;
+ x_size = ED_BUTTON_COUNT_XSIZE;
+ y_size = ED_BUTTON_COUNT_YSIZE;
+ }
+
+ sprintf(infotext, "%s counter value by 1, 5 or 10",
+ (j == 0 ? "decrease" : "increase"));
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, infotext,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_WIDTH, x_size,
+ GDI_HEIGHT, y_size,
+ 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, HandleCounterButtons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, counterbutton_info[i].text_right);
+
+ x += gi->width + ED_GADGET_DISTANCE; /* text count button */
+
+ if (j == 0)
+ {
+ int font_type = FONT_INPUT_1;
+ int font_type_active = FONT_INPUT_1_ACTIVE;
+ int gd_width = ED_WIN_COUNT_XSIZE;
+
+ id = counterbutton_info[i].gadget_id_text;
+ event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
+
+ if (i == ED_COUNTER_ID_SELECT_LEVEL)
+ {
+ font_type = FONT_LEVEL_NUMBER;
+ font_type_active = FONT_LEVEL_NUMBER_ACTIVE;
+ x += 2 * ED_GADGET_DISTANCE;
+ y -= ED_GADGET_DISTANCE;
+
+ gd_x = DOOR_GFX_PAGEX6 + ED_WIN_COUNT2_XPOS;
+ gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT2_YPOS;
+ gd_width = ED_WIN_COUNT2_XSIZE;
+ }
+ else
+ {
+ gd_x = DOOR_GFX_PAGEX4 + ED_WIN_COUNT_XPOS;
+ gd_y = DOOR_GFX_PAGEY1 + ED_WIN_COUNT_YPOS;
+ }
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, "enter counter value",
+ GDI_X, x,
+ GDI_Y, y,
+ 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_TEXT_SIZE, 3, /* minimal counter text size */
+ GDI_TEXT_FONT, font_type,
+ GDI_TEXT_FONT_ACTIVE, font_type_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, gd_width,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleCounterButtons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, counterbutton_info[i].text_right);
+
+ x += gi->width + ED_GADGET_DISTANCE; /* up count button */
+ }
+ }
+ }
+}
+
+static void CreateDrawingAreas()
+{
+ int i;
+
+ /* these values are not constant, but can change at runtime */
+ drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_xsize = MAX_ED_FIELDX;
+ drawingarea_info[ED_DRAWING_ID_DRAWING_LEVEL].area_ysize = MAX_ED_FIELDY;
+
+ 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 + drawingarea_info[i].x;
+ int y = SY + drawingarea_info[i].y;
+ int area_xsize = drawingarea_info[i].area_xsize;
+ int area_ysize = drawingarea_info[i].area_ysize;
+
+ event_mask =
+ GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
+ GD_EVENT_OFF_BORDERS;
+
+ /* determine horizontal position to the right of specified gadget */
+ if (drawingarea_info[i].gadget_id_align != GADGET_ID_NONE)
+ x = (right_gadget_border[drawingarea_info[i].gadget_id_align] +
+ ED_DRAWINGAREA_TEXT_DISTANCE);
+
+ /* determine horizontal offset for leading text */
+ if (drawingarea_info[i].text_left != NULL)
+ x += getTextWidthForDrawingArea(drawingarea_info[i].text_left);
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_TYPE, GD_TYPE_DRAWING_AREA,
+ GDI_AREA_SIZE, area_xsize, area_ysize,
+ GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
+ GDI_CALLBACK_ACTION, HandleDrawingAreas,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, drawingarea_info[i].text_right);
+ }
+}
+
+static void CreateTextInputGadgets()
+{
+ int max_infotext_len = getMaxInfoTextLength();
+ int i;
+
+ for (i = 0; i < ED_NUM_TEXTINPUT; i++)
+ {
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ int gd_x, gd_y;
+ struct GadgetInfo *gi;
+ unsigned int event_mask;
+ char infotext[MAX_OUTPUT_LINESIZE + 1];
+ int id = textinput_info[i].gadget_id;
+
+ event_mask = GD_EVENT_TEXT_RETURN | 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", textinput_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 + textinput_info[i].x,
+ GDI_Y, SY + textinput_info[i].y,
+ 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,
+ 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, HandleTextInputGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ }
+}
+
+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 int 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 i, j;
+
+ for (i = 0; i < ED_NUM_SELECTBOX; i++)
+ {
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ int gd_x, gd_y;
+ struct GadgetInfo *gi;
+ unsigned int event_mask;
+ char infotext[MAX_OUTPUT_LINESIZE + 1];
+ int id = selectbox_info[i].gadget_id;
+ int x = SX + selectbox_info[i].x;
+ int y = SY + selectbox_info[i].y;
+
+ if (selectbox_info[i].size == -1) /* dynamically determine size */
+ {
+ /* (we cannot use -1 for uninitialized values if we directly compare
+ with results from strlen(), because the '<' and '>' operation will
+ implicitely cast -1 to an unsigned integer value!) */
+ selectbox_info[i].size = 0;
+
+ for (j = 0; selectbox_info[i].options[j].text != NULL; j++)
+ if (strlen(selectbox_info[i].options[j].text) > selectbox_info[i].size)
+ selectbox_info[i].size = strlen(selectbox_info[i].options[j].text);
+
+ selectbox_info[i].size++; /* add one character empty space */
+ }
+
+ event_mask = GD_EVENT_RELEASED |
+ GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
+
+ gd_x = DOOR_GFX_PAGEX4 + ED_SELECTBOX_XPOS;
+ gd_y = DOOR_GFX_PAGEY1 + ED_SELECTBOX_YPOS;
+
+ /* 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] +
+ ED_GADGET_TEXT_DISTANCE);
+
+ /* determine horizontal offset for leading text */
+ if (selectbox_info[i].text_left != NULL)
+ x += getTextWidthForGadget(selectbox_info[i].text_left);
+
+ sprintf(infotext, "Select %s", selectbox_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, x,
+ GDI_Y, y,
+ GDI_TYPE, GD_TYPE_SELECTBOX,
+ GDI_SELECTBOX_OPTIONS, selectbox_info[i].options,
+ GDI_TEXT_SIZE, selectbox_info[i].size,
+ 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_BORDER_SIZE_SELECTBUTTON, ED_SELECTBOX_BUTTON_XSIZE,
+ GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleSelectboxGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, selectbox_info[i].text_right);
+ }
+}
+
+static void CreateTextbuttonGadgets()
+{
+ int max_infotext_len = getMaxInfoTextLength();
+ int 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;
+ struct GadgetInfo *gi;
+ unsigned int event_mask;
+ char infotext[MAX_OUTPUT_LINESIZE + 1];
+ int id = textbutton_info[i].gadget_id;
+ int x = SX + textbutton_info[i].x;
+ int y = SY + 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;
+
+ if ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
+ (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE))
+ {
+ gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_TAB_XPOS;
+ gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_TAB_XPOS;
+ gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_YPOS;
+ gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_TAB_INACTIVE_YPOS;
+ }
+ else
+ {
+ gd_x1 = DOOR_GFX_PAGEX4 + ED_TEXTBUTTON_XPOS;
+ gd_x2 = DOOR_GFX_PAGEX3 + ED_TEXTBUTTON_XPOS;
+ gd_y1 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_YPOS;
+ gd_y2 = DOOR_GFX_PAGEY1 + ED_TEXTBUTTON_INACTIVE_YPOS;
+ }
+
+ sprintf(infotext, "%s", textbutton_info[i].infotext);
+ infotext[max_infotext_len] = '\0';
+
+ /* determine horizontal position to the right of specified gadget */
+ if (textbutton_info[i].gadget_id_align != GADGET_ID_NONE)
+ 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,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_TYPE, GD_TYPE_TEXT_BUTTON,
+ GDI_TEXT_VALUE, textbutton_info[i].text,
+ GDI_TEXT_SIZE, textbutton_info[i].size,
+ GDI_TEXT_FONT, FONT_INPUT_2_ACTIVE,
+ GDI_TEXT_FONT_ACTIVE, FONT_INPUT_2,
+ GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
+ GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y1,
+ GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y2,
+ GDI_BORDER_SIZE, ED_BORDER_TEXT_XSIZE, ED_BORDER_SIZE,
+ GDI_DESIGN_WIDTH, ED_WIN_COUNT_XSIZE,
+ GDI_DECORATION_SHIFTING, 1, 1,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleTextbuttonGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ 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 int 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;
+
+ if (i <= ED_GRAPHICBUTTON_ID_NEXT_CHANGE_PAGE)
+ {
+ gd_x1 = DOOR_GFX_PAGEX4 + graphicbutton_info[i].gd_x;
+ gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
+ gd_x2 = DOOR_GFX_PAGEX3 + graphicbutton_info[i].gd_x;
+ gd_y2 = gd_y1;
+ }
+ else /* (i <= ED_GRAPHICBUTTON_ID_PASTE_CHANGE_PAGE) */
+ {
+ gd_x1 = DOOR_GFX_PAGEX6 + graphicbutton_info[i].gd_x;
+ gd_y1 = DOOR_GFX_PAGEY1 + graphicbutton_info[i].gd_y;
+ gd_x2 = gd_x1 - ED_BUTTON_COUNT_XSIZE;
+ 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);
+ }
+}
+
+static void CreateScrollbarGadgets()
+{
+ int i;
+
+ /* these values are not constant, but can change at runtime */
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].x =
+ SX + ED_SCROLL_HORIZONTAL_XPOS;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].y =
+ SY + ED_SCROLL_HORIZONTAL_YPOS;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width =
+ ED_SCROLL_HORIZONTAL_XSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].height =
+ ED_SCROLL_HORIZONTAL_YSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_x = SX;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_y = SY;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_width = SXSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].wheel_height = SYSIZE;
+
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].x =
+ SX + ED_SCROLL_VERTICAL_XPOS;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].y =
+ SY + ED_SCROLL_VERTICAL_YPOS;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].width =
+ ED_SCROLL_VERTICAL_XSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height =
+ ED_SCROLL_VERTICAL_YSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_x = SX;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_y = SY;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_width = SXSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].wheel_height = SYSIZE;
+
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].x =
+ DX + ED_SCROLL2_VERTICAL_XPOS;
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].y =
+ DY + ED_SCROLL2_VERTICAL_YPOS;
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].width =
+ ED_SCROLL2_VERTICAL_XSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].height =
+ ED_SCROLL2_VERTICAL_YSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_x = DX;
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_y = DY;
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_width = DXSIZE;
+ scrollbar_pos[ED_SCROLLBAR_ID_LIST_VERTICAL].wheel_height = DYSIZE;
+
+ for (i = 0; i < ED_NUM_SCROLLBARS; i++)
+ {
+ int id = scrollbar_info[i].gadget_id;
+ int graphic = scrollbar_info[i].graphic;
+ struct GraphicInfo *gd = &graphic_info[graphic];
+ Bitmap *gd_bitmap = gd->bitmap;
+ int gd_x1, gd_x2, gd_y1, gd_y2;
+ struct GadgetInfo *gi;
+ int items_max, items_visible, item_position;
+ unsigned int event_mask;
+
+ if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
+ {
+ items_max = num_editor_elements / ED_ELEMENTLIST_BUTTONS_HORIZ;
+ items_visible = ED_ELEMENTLIST_BUTTONS_VERT;
+ item_position = element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ;
+ }
+ else /* drawing area scrollbars */
+ {
+ if (scrollbar_info[i].type == GD_TYPE_SCROLLBAR_HORIZONTAL)
+ {
+ items_max = MAX(lev_fieldx + 2, ed_fieldx);
+ items_visible = ed_fieldx;
+ item_position = 0;
+ }
+ else
+ {
+ items_max = MAX(lev_fieldy + 2, ed_fieldy);
+ items_visible = ed_fieldy;
+ item_position = 0;
+ }
+ }
+
+ event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
+
+ gd_x1 = gd->src_x;
+ gd_y1 = gd->src_y;
+ gd_x2 = gd->src_x + gd->pressed_xoffset;
+ gd_y2 = gd->src_y + gd->pressed_yoffset;
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, scrollbar_info[i].infotext,
+ GDI_X, scrollbar_pos[i].x,
+ GDI_Y, scrollbar_pos[i].y,
+ GDI_WIDTH, scrollbar_pos[i].width,
+ GDI_HEIGHT, scrollbar_pos[i].height,
+ GDI_TYPE, scrollbar_info[i].type,
+ GDI_SCROLLBAR_ITEMS_MAX, items_max,
+ GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
+ GDI_SCROLLBAR_ITEM_POSITION, item_position,
+ GDI_WHEEL_AREA_X, scrollbar_pos[i].wheel_x,
+ GDI_WHEEL_AREA_Y, scrollbar_pos[i].wheel_y,
+ GDI_WHEEL_AREA_WIDTH, scrollbar_pos[i].wheel_width,
+ GDI_WHEEL_AREA_HEIGHT, scrollbar_pos[i].wheel_height,
+ GDI_STATE, GD_BUTTON_UNPRESSED,
+ GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y1,
+ GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y2,
+ GDI_BORDER_SIZE, ED_BORDER_SIZE, ED_BORDER_SIZE,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleControlButtons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ }
+}
+
+static void CreateCheckbuttonGadgets()
+{
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ struct GadgetInfo *gi;
+ unsigned int event_mask;
+ int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
+ int i;
+
+ event_mask = GD_EVENT_PRESSED;
+
+ gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
+ gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
+ gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
+ gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
+ gd_y = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
+
+ for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
+ {
+ int id = checkbutton_info[i].gadget_id;
+ int x = SX + checkbutton_info[i].x;
+ int y = SY + checkbutton_info[i].y;
+
+ if (id == GADGET_ID_STICK_ELEMENT)
+ gd_y = DOOR_GFX_PAGEY1 + ED_STICKYBUTTON_YPOS;
+ else
+ gd_y = DOOR_GFX_PAGEY1 + ED_CHECKBUTTON_YPOS;
+
+ /* determine horizontal position to the right of specified gadget */
+ if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
+ x = (right_gadget_border[checkbutton_info[i].gadget_id_align] +
+ ED_GADGET_TEXT_DISTANCE);
+
+ /* determine horizontal offset for leading text */
+ if (checkbutton_info[i].text_left != NULL)
+ x += getTextWidthForGadget(checkbutton_info[i].text_left);
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, checkbutton_info[i].infotext,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
+ GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
+ GDI_TYPE, GD_TYPE_CHECK_BUTTON,
+ GDI_CHECKED, *checkbutton_info[i].value,
+ GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
+ GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
+ GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
+ GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleCheckbuttons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, checkbutton_info[i].text_right);
+ }
+}
+
+static void CreateRadiobuttonGadgets()
+{
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ struct GadgetInfo *gi;
+ unsigned int event_mask;
+ int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
+ int i;
+
+ event_mask = GD_EVENT_PRESSED;
+
+ gd_x1 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_UNCHECKED_XPOS;
+ gd_x2 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_UNCHECKED_XPOS;
+ gd_x3 = DOOR_GFX_PAGEX4 + ED_CHECKBUTTON_CHECKED_XPOS;
+ gd_x4 = DOOR_GFX_PAGEX3 + ED_CHECKBUTTON_CHECKED_XPOS;
+ gd_y = DOOR_GFX_PAGEY1 + ED_RADIOBUTTON_YPOS;
+
+ for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
+ {
+ int id = radiobutton_info[i].gadget_id;
+ int x = SX + radiobutton_info[i].x;
+ int y = SY + radiobutton_info[i].y;
+
+ int checked =
+ (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
+
+ /* determine horizontal position to the right of specified gadget */
+ if (radiobutton_info[i].gadget_id_align != GADGET_ID_NONE)
+ x = (right_gadget_border[radiobutton_info[i].gadget_id_align] +
+ ED_GADGET_TEXT_DISTANCE);
+
+ /* determine horizontal offset for leading text */
+ if (radiobutton_info[i].text_left != NULL)
+ x += getTextWidthForGadget(radiobutton_info[i].text_left);
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, radiobutton_info[i].infotext,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_WIDTH, ED_CHECKBUTTON_XSIZE,
+ GDI_HEIGHT, ED_CHECKBUTTON_YSIZE,
+ GDI_TYPE, GD_TYPE_RADIO_BUTTON,
+ GDI_RADIO_NR, radiobutton_info[i].radio_button_nr,
+ GDI_CHECKED, checked,
+ GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
+ GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
+ GDI_ALT_DESIGN_UNPRESSED, gd_bitmap, gd_x3, gd_y,
+ GDI_ALT_DESIGN_PRESSED, gd_bitmap, gd_x4, gd_y,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_INFO, HandleEditorGadgetInfoText,
+ GDI_CALLBACK_ACTION, HandleRadiobuttons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ level_editor_gadget[id] = gi;
+ right_gadget_border[id] =
+ getRightGadgetBorder(gi, radiobutton_info[i].text_right);
+ }
+}
+
+void CreateLevelEditorGadgets()
+{
+ int old_game_status = game_status;
+
+ /* setting 'game_status' is needed to get the right fonts for the editor */
+ game_status = GAME_MODE_EDITOR;
+
+ /* these values are not constant, but can change at runtime */
+ ed_fieldx = MAX_ED_FIELDX - 1;
+ ed_fieldy = MAX_ED_FIELDY - 1;
+
+ num_editor_gadgets = NUM_EDITOR_GADGETS;
+
+ // printf("::: allocating %d gadgets ...\n", num_editor_gadgets);
+
+ level_editor_gadget =
+ checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
+ right_gadget_border =
+ checked_calloc(num_editor_gadgets * sizeof(int));
+
+ editor_el_empty = checked_calloc(ED_NUM_ELEMENTLIST_BUTTONS * sizeof(int));
+ editor_el_empty_ptr = editor_el_empty;
+
+ ReinitializeElementList();
+
+ CreateControlButtons();
+ CreateScrollbarGadgets();
+
+ /* order of function calls is important because of cross-references */
+ CreateCheckbuttonGadgets();
+ CreateCounterButtons();
+ CreateRadiobuttonGadgets();
+ CreateTextInputGadgets();
+ CreateTextAreaGadgets();
+ CreateSelectboxGadgets();
+ CreateGraphicbuttonGadgets();
+ CreateTextbuttonGadgets();
+ CreateDrawingAreas();
+
+ game_status = old_game_status;
+}
+
+void FreeLevelEditorGadgets()
+{
+ int i;
+
+ // printf("::: freeing %d gadgets ...\n", num_editor_gadgets);
+
+ for (i = 0; i < num_editor_gadgets; i++)
+ {
+ FreeGadget(level_editor_gadget[i]);
+
+ level_editor_gadget[i] = NULL;
+ }
+
+ checked_free(level_editor_gadget);
+ checked_free(right_gadget_border);
+
+ checked_free(editor_el_empty);
+}
+
+static void MapCounterButtons(int id)
+{
+ int gadget_id_down = counterbutton_info[id].gadget_id_down;
+ int gadget_id_text = counterbutton_info[id].gadget_id_text;
+ int gadget_id_up = counterbutton_info[id].gadget_id_up;
+ struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
+ struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
+ struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
+ int xoffset_left = getTextWidthForGadget(counterbutton_info[id].text_left);
+ int xoffset_right = ED_GADGET_TEXT_DISTANCE;
+ int yoffset_above = MINI_TILEX + ED_GADGET_DISTANCE;
+ int yoffset = ED_BORDER_SIZE;
+ int x_left = gi_down->x - xoffset_left;
+ int x_right; /* set after gadget position was modified */
+ int y_above = gi_down->y - yoffset_above;
+ int x = gi_down->x;
+ int y; /* set after gadget position was modified */
+
+ /* counter limits must be changed first to prevent value truncation */
+ ModifyEditorCounterLimits(id, counterbutton_info[id].min_value,
+ counterbutton_info[id].max_value);
+
+ /* right text position might have changed after setting position above */
+ x_right = gi_up->x + gi_up->width + xoffset_right;
+
+ ModifyEditorCounterValue(id, *counterbutton_info[id].value);
+
+ /* set position for "value[1,2,3,4]" counter gadgets (score in most cases) */
+ if (id >= ED_COUNTER_ID_ELEMENT_VALUE1 &&
+ id <= ED_COUNTER_ID_ELEMENT_VALUE4)
+ {
+ ModifyGadget(gi_down, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
+ ModifyGadget(gi_text, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
+ ModifyGadget(gi_up, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
+ }
+
+ /* vertical position might have changed after setting position above */
+ y = gi_up->y + yoffset;
+
+ if (counterbutton_info[id].text_above)
+ DrawText(x, y_above, counterbutton_info[id].text_above, FONT_TEXT_1);
+
+ if (counterbutton_info[id].text_left)
+ DrawText(x_left, y, counterbutton_info[id].text_left, FONT_TEXT_1);
+
+ if (counterbutton_info[id].text_right)
+ DrawText(x_right, y, counterbutton_info[id].text_right, FONT_TEXT_1);
+
+ MapGadget(gi_down);
+ MapGadget(gi_text);
+ MapGadget(gi_up);
+}
+
+static void MapControlButtons()
+{
+ int counter_id;
+ int i;
+
+ /* map toolbox buttons (excluding special CE toolbox buttons) */
+ for (i = 0; i < ED_NUM_CTRL1_2_BUTTONS; i++)
+ MapGadget(level_editor_gadget[i]);
+
+ /* map buttons to select elements */
+ for (i = 0; i < ED_NUM_ELEMENTLIST_BUTTONS; i++)
+ MapGadget(level_editor_gadget[GADGET_ID_ELEMENTLIST_FIRST + i]);
+ MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL]);
+ MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_UP]);
+ MapGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_DOWN]);
+
+ /* map buttons to select level */
+ counter_id = ED_COUNTER_ID_SELECT_LEVEL;
+ counterbutton_info[counter_id].min_value = leveldir_current->first_level;
+ counterbutton_info[counter_id].max_value = leveldir_current->last_level;
+ MapCounterButtons(counter_id);
+}
+
+static void MapDrawingArea(int id)
+{
+ struct GadgetInfo *gi = level_editor_gadget[drawingarea_info[id].gadget_id];
+ int area_xsize = gi->drawing.area_xsize;
+ int area_ysize = gi->drawing.area_ysize;
+ int xoffset_left= getTextWidthForDrawingArea(drawingarea_info[id].text_left);
+ int xoffset_below= getTextWidth(drawingarea_info[id].text_below,FONT_TEXT_1);
+ int x_left = gi->x - xoffset_left;
+ int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
+ int x_below = gi->x + (gi->width - xoffset_below) / 2;
+ int y_side = gi->y + (gi->height - getFontHeight(FONT_TEXT_1)) / 2;
+ int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
+
+ if (drawingarea_info[id].text_left)
+ DrawText(x_left, y_side, drawingarea_info[id].text_left, FONT_TEXT_1);
+
+ if (drawingarea_info[id].text_right)
+ DrawText(x_right, y_side, drawingarea_info[id].text_right, FONT_TEXT_1);
+
+ if (drawingarea_info[id].text_below)
+ DrawText(x_below, y_below, drawingarea_info[id].text_below, FONT_TEXT_1);
+
+ if (id != ED_DRAWING_ID_DRAWING_LEVEL)
+ {
+ DrawElementBorder(gi->x, gi->y,
+ area_xsize * MINI_TILEX, area_ysize * MINI_TILEY, TRUE);
+
+ DrawDrawingArea(id);
+ }
+
+ MapGadget(gi);
+}
+
+static void MapTextInputGadget(int id)
+{
+ struct GadgetInfo *gi = level_editor_gadget[textinput_info[id].gadget_id];
+ int xoffset_above = 0;
+ int yoffset_above = -(MINI_TILEX + ED_GADGET_DISTANCE);
+ int x_above = textinput_info[id].x + xoffset_above;
+ int y_above = textinput_info[id].y + yoffset_above;
+
+ if (textinput_info[id].text_above)
+ DrawTextS(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)
+ DrawTextS(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];
+ int xoffset_left = getTextWidthForGadget(selectbox_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 (selectbox_info[id].text_left)
+ DrawText(x_left, y, selectbox_info[id].text_left, FONT_TEXT_1);
+
+ if (selectbox_info[id].text_right)
+ DrawText(x_right, y, selectbox_info[id].text_right, FONT_TEXT_1);
+
+ ModifyEditorSelectboxValue(id, *selectbox_info[id].value);
+
+ MapGadget(gi);
+}
+
+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];
+ 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;
+ boolean checked =
+ (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
+
+ if (radiobutton_info[id].text_left)
+ DrawText(x_left, y, radiobutton_info[id].text_left, FONT_TEXT_1);
+
+ if (radiobutton_info[id].text_right)
+ DrawText(x_right, y, radiobutton_info[id].text_right, FONT_TEXT_1);
+
+ ModifyGadget(gi, GDI_CHECKED, checked, GDI_END);
+
+ MapGadget(gi);
+}
+
+static void MapCheckbuttonGadget(int id)
+{
+ struct GadgetInfo *gi = level_editor_gadget[checkbutton_info[id].gadget_id];
+ int xoffset_left = getTextWidthForGadget(checkbutton_info[id].text_left);
+ int xoffset_right = ED_GADGET_TEXT_DISTANCE;
+ int yoffset = ED_BORDER_SIZE;
+ int x_left, x_right, y; /* set after gadget position was modified */
+
+ /* set position for gadgets with dynamically determined position */
+ if (checkbutton_info[id].x != -1) /* do not change dynamic positions */
+ ModifyGadget(gi, GDI_X, SX + checkbutton_info[id].x, GDI_END);
+ ModifyGadget(gi, GDI_Y, SY + checkbutton_info[id].y, GDI_END);
+
+ x_left = gi->x - xoffset_left;
+ x_right = gi->x + gi->width + xoffset_right;
+ y = gi->y + yoffset;
+
+ if (checkbutton_info[id].text_left)
+ DrawText(x_left, y, checkbutton_info[id].text_left, FONT_TEXT_1);
+
+ if (checkbutton_info[id].text_right)
+ DrawText(x_right, y, checkbutton_info[id].text_right, FONT_TEXT_1);
+
+ ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value, GDI_END);
+
+ MapGadget(gi);
+}
+
+static void MapMainDrawingArea()
+{
+ boolean no_horizontal_scrollbar = (lev_fieldx + 2 <= ed_fieldx);
+ boolean no_vertical_scrollbar = (lev_fieldy + 2 <= ed_fieldy);
+ int i;
+
+ for (i=ED_SCROLLBUTTON_ID_AREA_FIRST; i <= ED_SCROLLBUTTON_ID_AREA_LAST; i++)
+ {
+ if (((i == ED_SCROLLBUTTON_ID_AREA_LEFT ||
+ i == ED_SCROLLBUTTON_ID_AREA_RIGHT) &&
+ no_horizontal_scrollbar) ||
+ ((i == ED_SCROLLBUTTON_ID_AREA_UP ||
+ i == ED_SCROLLBUTTON_ID_AREA_DOWN) &&
+ no_vertical_scrollbar))
+ continue;
+
+ MapGadget(level_editor_gadget[scrollbutton_info[i].gadget_id]);
+ }
+
+ for (i = ED_SCROLLBAR_ID_AREA_FIRST; i <= ED_SCROLLBAR_ID_AREA_LAST; i++)
+ {
+ if ((i == ED_SCROLLBAR_ID_AREA_HORIZONTAL && no_horizontal_scrollbar) ||
+ (i == ED_SCROLLBAR_ID_AREA_VERTICAL && no_vertical_scrollbar))
+ continue;
+
+ MapGadget(level_editor_gadget[scrollbar_info[i].gadget_id]);
+ }
+
+ MapDrawingArea(ED_DRAWING_ID_DRAWING_LEVEL);
+}
+
+static void MapOrUnmapLevelEditorToolboxCustomGadgets(boolean map)
+{
+ int i;
+
+ for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
+ {
+ if (i == GADGET_ID_CUSTOM_COPY_FROM ||
+ i == GADGET_ID_CUSTOM_COPY_TO ||
+ i == GADGET_ID_CUSTOM_EXCHANGE ||
+ i == GADGET_ID_CUSTOM_COPY ||
+ i == GADGET_ID_CUSTOM_PASTE)
+ {
+ if (map)
+ MapGadget(level_editor_gadget[i]);
+ else
+ UnmapGadget(level_editor_gadget[i]);
+ }
+ }
+}
+
+static void MapLevelEditorToolboxCustomGadgets()
+{
+ MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
+}
+
+static void UnmapLevelEditorToolboxCustomGadgets()
+{
+ MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
+}
+
+static void MapOrUnmapLevelEditorToolboxDrawingGadgets(boolean map)
+{
+ Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+ int i;
+
+ for (i = 0; i < ED_NUM_CTRL1_BUTTONS; i++)
+ {
+ if (i != GADGET_ID_SINGLE_ITEMS &&
+ i != GADGET_ID_PROPERTIES &&
+ i != GADGET_ID_PICK_ELEMENT)
+ {
+ struct GadgetInfo *gi = level_editor_gadget[i];
+
+ if (map)
+ MapGadget(gi);
+ else
+ {
+ UnmapGadget(gi);
+
+ BlitBitmap(gd_bitmap, drawto,
+ DOOR_GFX_PAGEX6 + ED_CTRL_NO_BUTTONS_GFX_XPOS,
+ DOOR_GFX_PAGEY1 + ED_CTRL_NO_BUTTONS_GFX_YPOS,
+ gi->width, gi->height, gi->x, gi->y);
+
+ redraw_mask |= REDRAW_DOOR_3;
+ }
+ }
+ }
+}
+
+static void MapLevelEditorToolboxDrawingGadgets()
+{
+ MapOrUnmapLevelEditorToolboxDrawingGadgets(TRUE);
+}
+
+static void UnmapLevelEditorToolboxDrawingGadgets()
+{
+ MapOrUnmapLevelEditorToolboxDrawingGadgets(FALSE);
+}
+
+static void UnmapDrawingArea(int id)
+{
+ UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
+}
+
+static void UnmapLevelEditorFieldGadgets()
+{
+ int i;
+
+ for (i = 0; i < num_editor_gadgets; i++)
+ if (IN_GFX_FIELD_FULL(level_editor_gadget[i]->x,
+ level_editor_gadget[i]->y))
+ UnmapGadget(level_editor_gadget[i]);
+}
+
+void UnmapLevelEditorGadgets()
+{
+ int i;
+
+ for (i = 0; i < num_editor_gadgets; i++)
+ UnmapGadget(level_editor_gadget[i]);
+}
+
+static void ResetUndoBuffer()
+{
+ undo_buffer_position = -1;
+ undo_buffer_steps = -1;
+ CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
+
+ level.changed = FALSE;
+}
+
+static void DrawEditModeWindow()
+{
+ ModifyEditorElementList();
+ RedrawDrawingElements();
+
+ if (edit_mode == ED_MODE_INFO)
+ DrawLevelInfoWindow();
+ else if (edit_mode == ED_MODE_PROPERTIES)
+ DrawPropertiesWindow();
+ else /* edit_mode == ED_MODE_DRAWING */
+ DrawDrawingWindow();
+}
+
+static boolean LevelChanged()
+{
+ boolean field_changed = FALSE;
+ int x, y;
+
+ for (y = 0; y < lev_fieldy; y++)
+ for (x = 0; x < lev_fieldx; x++)
+ if (Feld[x][y] != level.field[x][y])
+ field_changed = TRUE;
+
+ return (level.changed || field_changed);
+}
+
+static boolean PrepareSavingIntoPersonalLevelSet()
+{
+ static LevelDirTree *last_copied_leveldir = NULL;
+ static LevelDirTree *last_written_leveldir = NULL;
+ static int last_copied_level_nr = -1;
+ static int last_written_level_nr = -1;
+ LevelDirTree *leveldir_former = leveldir_current;
+ int level_nr_former = level_nr;
+ int new_level_nr;
+
+ // remember last mod/save so that for current session, we write
+ // back to the same personal copy, asking only about overwrite.
+ if (leveldir_current == last_copied_leveldir &&
+ level_nr == last_copied_level_nr)
+ {
+ // "cd" to personal level set dir (as used when writing last copy)
+ leveldir_current = last_written_leveldir;
+ level_nr = last_written_level_nr;
+
+ return TRUE;
+ }
+
+ if (!Request("This level is read only! "
+ "Save into personal level set?", REQ_ASK))
+ return FALSE;
+
+ // "cd" to personal level set dir (for writing copy the first time)
+ leveldir_current =
+ getTreeInfoFromIdentifier(leveldir_first, getLoginName());
+
+ // find unused level number
+ for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
+ {
+ static char *level_filename = NULL;
+
+ setString(&level_filename, getDefaultLevelFilename(new_level_nr));
+
+ if (!fileExists(level_filename))
+ break;
+ }
+
+ last_copied_leveldir = leveldir_former;
+ last_copied_level_nr = level_nr_former;
+
+ last_written_leveldir = leveldir_current;
+ last_written_level_nr = level_nr = new_level_nr;
+
+ return TRUE;
+}
+
+static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name)
+{
+ static char *filename_levelinfo = NULL, *mod_name = NULL;
+ FILE *file;
+
+ // annotate this copy-and-mod in personal levelinfo.conf
+ setString(&filename_levelinfo,
+ getPath2(getCurrentLevelDir(), LEVELINFO_FILENAME));
+
+ if ((file = fopen(filename_levelinfo, MODE_APPEND)))
+ {
+ fprintf(file, "\n");
+ fprintf(file, "# level %d was modified from:\n", level_nr);
+ fprintf(file, "# - previous level set name: %s\n",
+ former_name);
+ fprintf(file, "# - level within previous set: %d \"%s\"\n",
+ level.file_info.nr, level.name);
+ fprintf(file, "# - previous author: %s\n",
+ level.author);
+ fprintf(file, "# - previous save date: ");
+
+ if (level.creation_date.src == DATE_SRC_LEVELFILE)
+ {
+ fprintf(file, "%04d-%02d-%02d\n",
+ level.creation_date.year,
+ level.creation_date.month,
+ level.creation_date.day);
+ }
+ else
+ {
+ fprintf(file, "not recorded\n");
+ }
+
+ fclose(file);
+ }
+
+ if (level_nr > leveldir_current->last_level)
+ {
+ static char *temp_levelinfo = NULL;
+ FILE *temp_file = NULL;
+ char line[MAX_LINE_LEN];
+
+ setString(&temp_levelinfo,
+ getPath2(getCurrentLevelDir(),
+ getStringCat2(LEVELINFO_FILENAME, ".new")));
+
+ if ((file = fopen(filename_levelinfo, MODE_READ)) &&
+ (temp_file = fopen(temp_levelinfo, MODE_WRITE)))
+ {
+ while (fgets(line, MAX_LINE_LEN, file))
+ {
+ if (!strPrefix(line, "levels:"))
+ fputs(line, temp_file);
+ else
+ fprintf(temp_file, "%-32s%d\n", "levels:", level_nr + 9);
+ }
+ }
+
+ if (temp_file)
+ fclose(temp_file);
+
+ if (file)
+ fclose(file);
+
+ // needs error handling; also, ok on dos/win?
+ unlink(filename_levelinfo);
+ rename(temp_levelinfo, filename_levelinfo);
+ }
+
+ // else: allow the save even if annotation failed
+
+ // now... spray graffiti on the old level vital statistics
+ // user can change these; just trying to set a good baseline
+
+ // don't truncate names for fear of making offensive or silly:
+ // long-named original author only recorded in levelinfo.conf.
+ // try to fit "Joe after Bob", "Joe (ed.)", then just "Joe"
+ if (!strEqual(level.author, leveldir_current->author))
+ {
+ setString(&mod_name, getStringCat3(leveldir_current->author,
+ " after ", level.author));
+
+ if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
+ setString(&mod_name,
+ getStringCat2(leveldir_current->author, " (ed.)"));
+
+ if (strlen(mod_name) > MAX_LEVEL_AUTHOR_LEN)
+ setString(&mod_name, leveldir_current->author);
+
+ strncpy(level.author, mod_name, MAX_LEVEL_AUTHOR_LEN);
+
+ // less worried about truncation here
+ setString(&mod_name, getStringCat2("Mod: ", level.name));
+ strncpy(level.name, mod_name, MAX_LEVEL_NAME_LEN);
+ }
+}
+
+static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
+ short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
+{
+ int x, y;
+
+ for (x = 0; x < lev_fieldx; x++)
+ for (y = 0; y < lev_fieldy; y++)
+ dst[x][y] = src[x][y];
+}
+
+static int setSelectboxValue(int selectbox_id, int new_value)
+{
+ int new_index_value = 0;
+ int i;
+
+ for (i = 0; selectbox_info[selectbox_id].options[i].text != NULL; i++)
+ if (selectbox_info[selectbox_id].options[i].value == new_value)
+ new_index_value = i;
+
+ *selectbox_info[selectbox_id].value =
+ selectbox_info[selectbox_id].options[new_index_value].value;
+
+ return new_index_value;
+}
+
+static void setSelectboxSpecialActionVariablesIfNeeded()
+{
+ int i;
+
+ /* change action mode and arg variables according to action type variable */
+ for (i = 0; action_arg_options[i].value != -1; i++)
+ {
+ if (action_arg_options[i].value == custom_element_change.action_type)
+ {
+ int mode = action_arg_options[i].mode;
+
+ /* only change if corresponding selectbox has changed */
+ if (selectbox_info[ED_SELECTBOX_ID_ACTION_MODE].options !=
+ action_arg_modes[mode])
+ custom_element_change.action_mode = -1;
+
+ /* only change if corresponding selectbox has changed */
+ if (selectbox_info[ED_SELECTBOX_ID_ACTION_ARG].options !=
+ action_arg_options[i].options)
+ custom_element_change.action_arg = -1;
+
+ break;
+ }
+ }
+}
+
+static void setSelectboxSpecialActionOptions()
+{
+ int i;
+
+ /* change action mode and arg selectbox according to action type selectbox */
+ for (i = 0; action_arg_options[i].value != -1; i++)
+ {
+ if (action_arg_options[i].value == custom_element_change.action_type)
+ {
+ int mode = action_arg_options[i].mode;
+
+ ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_MODE,
+ action_arg_modes[mode]);
+ ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_MODE,
+ custom_element_change.action_mode);
+
+ ModifyEditorSelectboxOptions(ED_SELECTBOX_ID_ACTION_ARG,
+ action_arg_options[i].options);
+ ModifyEditorSelectboxValue(ED_SELECTBOX_ID_ACTION_ARG,
+ custom_element_change.action_arg);
+ break;
+ }
+ }
+}
+
+static void copy_custom_element_settings(int element_from, int element_to)
+{
+ struct ElementInfo *ei_from = &element_info[element_from];
+ struct ElementInfo *ei_to = &element_info[element_to];
+
+ copyElementInfo(ei_from, ei_to);
+}
+
+static void replace_custom_element_in_settings(int element_from,
+ int element_to)
+{
+ int i, j, x, y;
+
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[i];
+
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ if (ei->content.e[x][y] == element_from)
+ ei->content.e[x][y] = element_to;
+
+ for (j = 0; j < ei->num_change_pages; j++)
+ {
+ struct ElementChangeInfo *change = &ei->change_page[j];
+
+ if (change->target_element == element_from)
+ change->target_element = element_to;
+
+ if (change->initial_trigger_element == element_from)
+ change->initial_trigger_element = element_to;
+
+ if (change->action_element == element_from)
+ change->action_element = element_to;
+
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ if (change->target_content.e[x][y] == element_from)
+ change->target_content.e[x][y] = element_to;
+ }
+
+ if (ei->group != NULL) /* group or internal */
+ for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
+ if (ei->group->element[j] == element_from)
+ ei->group->element[j] = element_to;
+ }
+}
+
+static void replace_custom_element_in_playfield(int element_from,
+ int element_to)
+{
+ int x, y;
+
+ for (x = 0; x < lev_fieldx; x++)
+ for (y = 0; y < lev_fieldy; y++)
+ if (Feld[x][y] == element_from)
+ Feld[x][y] = element_to;
+}
+
+static boolean CopyCustomElement(int element_old, int element_new,
+ int copy_mode)
+{
+ if (copy_mode == GADGET_ID_CUSTOM_COPY)
+ {
+ element_new = (IS_CUSTOM_ELEMENT(element_old) ?
+ EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
+ copy_mode = GADGET_ID_CUSTOM_COPY_TO;
+ }
+ else if (copy_mode == GADGET_ID_CUSTOM_PASTE)
+ {
+ element_old = (IS_CUSTOM_ELEMENT(element_new) ?
+ EL_INTERNAL_CLIPBOARD_CUSTOM : EL_INTERNAL_CLIPBOARD_GROUP);
+ copy_mode = GADGET_ID_CUSTOM_COPY_TO;
+
+ level.changed = TRUE;
+ }
+ else if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
+ {
+ Request("Please choose custom element!", REQ_CONFIRM);
+
+ return FALSE;
+ }
+ else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
+ {
+ Request("Please choose group element!", REQ_CONFIRM);
+
+ return FALSE;
+ }
+ else
+ {
+ level.changed = TRUE;
+ }
+
+ if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
+ {
+ copy_custom_element_settings(element_new, element_old);
+ }
+ else if (copy_mode == GADGET_ID_CUSTOM_COPY_TO)
+ {
+ copy_custom_element_settings(element_old, element_new);
+ }
+ else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
+ {
+ copy_custom_element_settings(element_old, EL_INTERNAL_DUMMY);
+ copy_custom_element_settings(element_new, element_old);
+ copy_custom_element_settings(EL_INTERNAL_DUMMY, element_new);
+
+ replace_custom_element_in_settings(element_old, EL_INTERNAL_DUMMY);
+ replace_custom_element_in_settings(element_new, element_old);
+ replace_custom_element_in_settings(EL_INTERNAL_DUMMY, element_new);
+
+ replace_custom_element_in_playfield(element_old, EL_INTERNAL_DUMMY);
+ replace_custom_element_in_playfield(element_new, element_old);
+ replace_custom_element_in_playfield(EL_INTERNAL_DUMMY, element_new);
+ }
+
+ UpdateCustomElementGraphicGadgets();
+ DrawPropertiesWindow();
+
+ return TRUE;
+}
+
+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 options for special action options */
+ setSelectboxSpecialActionOptions();
+
+ /* needed to initially set selectbox value variables to reliable defaults */
+ for (i = 0; i < ED_NUM_SELECTBOX; i++)
+ setSelectboxValue(i, *selectbox_info[i].value);
+
+ for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
+ custom_element_properties[i] = HAS_PROPERTY(element, i);
+
+ for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+ custom_element_change_events[i] = HAS_CHANGE_EVENT(element, i);
+
+ /* ---------- element settings: configure (custom elements) ------------- */
+
+ /* set accessible layer selectbox help value */
+ custom_element.access_type =
+ (IS_WALKABLE(element) ? EP_WALKABLE :
+ IS_PASSABLE(element) ? EP_PASSABLE :
+ custom_element.access_type);
+ custom_element.access_layer =
+ (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
+ IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
+ IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
+ custom_element.access_layer);
+ custom_element.access_protected =
+ (IS_PROTECTED(element) ? 1 : 0);
+ custom_element_properties[EP_ACCESSIBLE] =
+ (IS_ACCESSIBLE_OVER(element) ||
+ IS_ACCESSIBLE_INSIDE(element) ||
+ IS_ACCESSIBLE_UNDER(element));
+
+ /* set walk-to-object action selectbox help value */
+ custom_element.walk_to_action =
+ (IS_DIGGABLE(element) ? EP_DIGGABLE :
+ IS_COLLECTIBLE_ONLY(element) ? EP_COLLECTIBLE_ONLY :
+ IS_DROPPABLE(element) ? EP_DROPPABLE :
+ IS_THROWABLE(element) ? EP_THROWABLE :
+ IS_PUSHABLE(element) ? EP_PUSHABLE :
+ custom_element.walk_to_action);
+ custom_element_properties[EP_WALK_TO_OBJECT] =
+ (IS_DIGGABLE(element) ||
+ IS_COLLECTIBLE_ONLY(element) ||
+ IS_DROPPABLE(element) ||
+ IS_THROWABLE(element) ||
+ IS_PUSHABLE(element));
+
+ /* set smash targets selectbox help value */
+ custom_element.smash_targets =
+ (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
+ CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
+ CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
+ custom_element.smash_targets);
+ custom_element_properties[EP_CAN_SMASH] =
+ (CAN_SMASH_EVERYTHING(element) ||
+ CAN_SMASH_ENEMIES(element) ||
+ CAN_SMASH_PLAYER(element));
+
+ /* set deadliness selectbox help value */
+ custom_element.deadliness =
+ (DONT_TOUCH(element) ? EP_DONT_TOUCH :
+ DONT_GET_HIT_BY(element) ? EP_DONT_GET_HIT_BY :
+ DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
+ DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
+ custom_element.deadliness);
+ custom_element_properties[EP_DEADLY] =
+ (DONT_TOUCH(element) ||
+ DONT_GET_HIT_BY(element) ||
+ DONT_COLLIDE_WITH(element) ||
+ DONT_RUN_INTO(element));
+
+ /* ---------- element settings: advanced (custom elements) --------------- */
+
+ /* 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_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_ENTERED_BY_PLAYER) ? CE_ENTERED_BY_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
+ HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
+ HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
+ HAS_CHANGE_EVENT(element, CE_BLOCKED) ? CE_BLOCKED :
+ HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
+ HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
+ HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES) ? CE_VALUE_CHANGES :
+ HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
+ HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
+ HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
+ custom_element_change.direct_action);
+
+ /* 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_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_PUSHES_X) ? CE_PLAYER_PUSHES_X :
+ HAS_CHANGE_EVENT(element, CE_PLAYER_ENTERS_X) ? CE_PLAYER_ENTERS_X :
+ HAS_CHANGE_EVENT(element, CE_PLAYER_LEAVES_X) ? CE_PLAYER_LEAVES_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_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 :
+ HAS_CHANGE_EVENT(element, CE_HIT_BY_X) ? CE_HIT_BY_X :
+ HAS_CHANGE_EVENT(element, CE_SWITCH_OF_X) ? CE_SWITCH_OF_X :
+ HAS_CHANGE_EVENT(element, CE_CHANGE_OF_X) ? CE_CHANGE_OF_X :
+ HAS_CHANGE_EVENT(element, CE_EXPLOSION_OF_X) ? CE_EXPLOSION_OF_X :
+ HAS_CHANGE_EVENT(element, CE_MOVE_OF_X) ? CE_MOVE_OF_X :
+ HAS_CHANGE_EVENT(element, CE_CREATION_OF_X) ? CE_CREATION_OF_X :
+ HAS_CHANGE_EVENT(element, CE_VALUE_CHANGES_OF_X) ? CE_VALUE_CHANGES_OF_X :
+ HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
+ HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
+ HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
+ custom_element_change.other_action);
+}
+
+static void CopyGroupElementPropertiesToEditor(int element)
+{
+ group_element_info = *element_info[element].group;
+ custom_element = element_info[element]; /* needed for description */
+}
+
+static void CopyClassicElementPropertiesToEditor(int element)
+{
+ if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
+ custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
+ getMoveIntoAcidProperty(&level, element);
+
+ if (MAYBE_DONT_COLLIDE_WITH(element))
+ custom_element_properties[EP_DONT_COLLIDE_WITH] =
+ getDontCollideWithProperty(&level, element);
+}
+
+static void CopyElementPropertiesToEditor(int element)
+{
+ if (IS_CUSTOM_ELEMENT(element))
+ CopyCustomElementPropertiesToEditor(element);
+ else if (IS_GROUP_ELEMENT(element))
+ CopyGroupElementPropertiesToEditor(element);
+ else
+ CopyClassicElementPropertiesToEditor(element);
+}
+
+static void CopyCustomElementPropertiesToGame(int element)
+{
+ int i;
+ int access_type_and_layer;
+
+ /* mark that this custom element has been modified */
+ custom_element.modified_settings = TRUE;
+ level.changed = TRUE;
+
+ if (level.use_custom_template)
+ {
+ if (Request("Copy and modify level template?", REQ_ASK))
+ {
+ level.use_custom_template = FALSE;
+ ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
+ GDI_CHECKED, FALSE, GDI_END);
+ }
+ else
+ {
+ LoadLevelTemplate(-1); /* this resets all element modifications ... */
+
+ DrawEditModeWindow(); /* ... and copies them to 'custom_element' */
+ }
+ }
+
+ element_info[element] = custom_element;
+ *element_info[element].change = custom_element_change;
+
+ /* ---------- element settings: configure (custom elements) ------------- */
+
+ /* set accessible property from checkbox and selectbox */
+ custom_element_properties[EP_WALKABLE_OVER] = FALSE;
+ custom_element_properties[EP_WALKABLE_INSIDE] = FALSE;
+ custom_element_properties[EP_WALKABLE_UNDER] = FALSE;
+ custom_element_properties[EP_PASSABLE_OVER] = FALSE;
+ custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
+ custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
+ access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
+ EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
+ (custom_element.access_layer - EP_ACCESSIBLE_OVER));
+ custom_element_properties[access_type_and_layer] =
+ custom_element_properties[EP_ACCESSIBLE];
+ custom_element_properties[EP_PROTECTED] =
+ (custom_element.access_protected != 0 &&
+ custom_element_properties[EP_ACCESSIBLE]);
+
+ /* set walk-to-object property from checkbox and selectbox */
+ custom_element_properties[EP_DIGGABLE] = FALSE;
+ custom_element_properties[EP_COLLECTIBLE_ONLY] = FALSE;
+ custom_element_properties[EP_DROPPABLE] = FALSE;
+ custom_element_properties[EP_THROWABLE] = FALSE;
+ custom_element_properties[EP_PUSHABLE] = FALSE;
+ custom_element_properties[custom_element.walk_to_action] =
+ custom_element_properties[EP_WALK_TO_OBJECT];
+
+ /* set smash property from checkbox and selectbox */
+ custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
+ custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
+ custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
+ custom_element_properties[custom_element.smash_targets] =
+ custom_element_properties[EP_CAN_SMASH];
+
+ /* set deadliness property from checkbox and selectbox */
+ custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
+ custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
+ custom_element_properties[EP_DONT_GET_HIT_BY] = FALSE;
+ custom_element_properties[EP_DONT_TOUCH] = FALSE;
+ custom_element_properties[custom_element.deadliness] =
+ custom_element_properties[EP_DEADLY];
+
+ /* ---------- element settings: advanced (custom elements) --------------- */
+
+ /* set player change event from checkbox and selectbox */
+ 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_SNAPPED_BY_PLAYER] = FALSE;
+ custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
+ custom_element_change_events[CE_ENTERED_BY_PLAYER] = FALSE;
+ custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
+ custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
+ custom_element_change_events[CE_SWITCHED] = FALSE;
+ custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
+ custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
+ custom_element_change_events[CE_BLOCKED] = FALSE;
+ custom_element_change_events[CE_IMPACT] = FALSE;
+ custom_element_change_events[CE_SMASHED] = FALSE;
+ custom_element_change_events[CE_VALUE_CHANGES] = FALSE;
+ custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
+ custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
+ custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
+ 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_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_SNAPS_X] = FALSE;
+ custom_element_change_events[CE_PLAYER_PUSHES_X] = FALSE;
+ custom_element_change_events[CE_PLAYER_ENTERS_X] = FALSE;
+ custom_element_change_events[CE_PLAYER_LEAVES_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_TOUCHING_X] = FALSE;
+ custom_element_change_events[CE_HITTING_X] = FALSE;
+ custom_element_change_events[CE_DIGGING_X] = FALSE;
+ custom_element_change_events[CE_HIT_BY_X] = FALSE;
+ custom_element_change_events[CE_SWITCH_OF_X] = FALSE;
+ custom_element_change_events[CE_CHANGE_OF_X] = FALSE;
+ custom_element_change_events[CE_EXPLOSION_OF_X] = FALSE;
+ custom_element_change_events[CE_MOVE_OF_X] = FALSE;
+ custom_element_change_events[CE_CREATION_OF_X] = FALSE;
+ custom_element_change_events[CE_VALUE_CHANGES_OF_X] = FALSE;
+ custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
+ custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
+ custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
+ custom_element_change_events[custom_element_change.other_action] =
+ custom_element_change_events[CE_BY_OTHER_ACTION];
+
+ for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
+ SET_PROPERTY(element, i, custom_element_properties[i]);
+
+ for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+ SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
+
+ /* copy change events also to special level editor variable */
+ custom_element = element_info[element];
+ custom_element_change = *element_info[element].change;
+}
+
+static void CopyGroupElementPropertiesToGame(int element)
+{
+ element_info[element] = custom_element;
+ *element_info[element].group = group_element_info;
+
+ /* mark that this group element has been modified */
+ element_info[element].modified_settings = TRUE;
+ level.changed = TRUE;
+}
+
+static void CopyClassicElementPropertiesToGame(int element)
+{
+ if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
+ setMoveIntoAcidProperty(&level, element,
+ custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
+
+ if (MAYBE_DONT_COLLIDE_WITH(element))
+ setDontCollideWithProperty(&level, element,
+ custom_element_properties[EP_DONT_COLLIDE_WITH]);
+}
+
+static void CopyElementPropertiesToGame(int element)
+{
+ if (IS_CUSTOM_ELEMENT(element))
+ CopyCustomElementPropertiesToGame(element);
+ else if (IS_GROUP_ELEMENT(element))
+ CopyGroupElementPropertiesToGame(element);
+ else
+ CopyClassicElementPropertiesToGame(element);
+}
+
+void CheckElementDescriptions()
+{
+ int i;
+
+ for (i = 0; i < NUM_FILE_ELEMENTS; i++)
+ if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
+ Error(ERR_WARN, "no element description for element '%s'", EL_NAME(i));
+}
+
+static boolean playfield_area_changed = FALSE;
+
+void DrawLevelEd()
+{
+ int old_sx = SX;
+ int old_sy = SY;
+ int old_sxsize = SXSIZE;
+ int old_sysize = SYSIZE;
+
+ StopAnimation();
+
+ CloseDoor(DOOR_CLOSE_ALL);
+
+ FadeOut(REDRAW_FIELD);
+
+ /* needed after playing if editor playfield area has different size */
+ ClearRectangle(drawto, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
+
+ /* needed if different viewport properties defined for editor */
+ ChangeViewportPropertiesIfNeeded();
+
+ if (old_sx != SX ||
+ old_sy != SY ||
+ old_sxsize != SXSIZE ||
+ old_sysize != SYSIZE)
+ playfield_area_changed = TRUE;
+ else
+ playfield_area_changed = FALSE;
+
+ OpenDoor(DOOR_OPEN_1 | DOOR_OPEN_2 | DOOR_NO_DELAY);
+
+#if DEBUG
+ CheckElementDescriptions();
+#endif
+
+ if (level_editor_test_game)
+ {
+ CopyPlayfield(level.field, Feld);
+ CopyPlayfield(FieldBackup, level.field);
+
+ level_editor_test_game = FALSE;
+ }
+ else
+ {
+ edit_mode = ED_MODE_DRAWING;
+ edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL;
+ edit_mode_properties = ED_MODE_PROPERTIES_INFO;
+
+ ResetUndoBuffer();
+
+ level_xpos = -1;
+ level_ypos = -1;
+ }
+
+ /* copy default editor door content to main double buffer */
+ BlitBitmap(graphic_info[IMG_BACKGROUND_PALETTE].bitmap, drawto,
+ graphic_info[IMG_BACKGROUND_PALETTE].src_x,
+ graphic_info[IMG_BACKGROUND_PALETTE].src_y,
+ DXSIZE, DYSIZE, DX, DY);
+
+ /* draw bigger door */
+ DrawSpecialEditorDoor();
+
+ /* draw new control window */
+ BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
+ DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
+
+ redraw_mask |= REDRAW_ALL;
+
+ FreeLevelEditorGadgets();
+ CreateLevelEditorGadgets();
+
+ ReinitializeElementList(); /* update dynamic level element list */
+ ReinitializeElementListButtons(); /* custom element may look different */
+
+ InitElementPropertiesGfxElement();
+
+ UnmapAllGadgets();
+ MapControlButtons();
+
+ DrawEditModeWindow();
+
+ FadeIn(playfield_area_changed ? REDRAW_ALL : REDRAW_FIELD);
+
+ /* copy actual editor door content to door double buffer for OpenDoor() */
+ BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
+}
+
+static void AdjustDrawingAreaGadgets()
+{
+ int ed_xsize = lev_fieldx + 2;
+ int ed_ysize = lev_fieldy + 2;
+ int max_ed_fieldx = MAX_ED_FIELDX;
+ int max_ed_fieldy = MAX_ED_FIELDY;
+ boolean horizontal_scrollbar_needed;
+ boolean vertical_scrollbar_needed;
+ int x, y, width, height;
+ int xoffset, yoffset;
+
+ /* check if we need any scrollbars */
+ horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
+ vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
+
+ /* check if we have a smaller editor field because of scrollbars */
+ if (horizontal_scrollbar_needed)
+ max_ed_fieldy = MAX_ED_FIELDY - 1;
+ if (vertical_scrollbar_needed)
+ max_ed_fieldx = MAX_ED_FIELDX - 1;
+
+ /* check again if we now need more scrollbars because of less space */
+ horizontal_scrollbar_needed = (ed_xsize > max_ed_fieldx);
+ vertical_scrollbar_needed = (ed_ysize > max_ed_fieldy);
+
+ /* check if editor field gets even smaller after adding new scrollbars */
+ if (horizontal_scrollbar_needed)
+ max_ed_fieldy = MAX_ED_FIELDY - 1;
+ if (vertical_scrollbar_needed)
+ max_ed_fieldx = MAX_ED_FIELDX - 1;
+
+ ed_fieldx = (ed_xsize < MAX_ED_FIELDX ? ed_xsize : max_ed_fieldx);
+ ed_fieldy = (ed_ysize < MAX_ED_FIELDY ? ed_ysize : max_ed_fieldy);
+
+ ModifyGadget(level_editor_gadget[GADGET_ID_DRAWING_LEVEL],
+ GDI_WIDTH, ed_fieldx * MINI_TILEX,
+ GDI_HEIGHT, ed_fieldy * MINI_TILEY,
+ GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
+ GDI_END);
+
+ xoffset = (ed_fieldx == MAX_ED_FIELDX ? ED_SCROLLBUTTON_XSIZE : 0);
+ yoffset = (ed_fieldy == MAX_ED_FIELDY ? ED_SCROLLBUTTON_YSIZE : 0);
+
+ x = SX + scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_RIGHT].x + xoffset;
+ y = SX + scrollbutton_pos[ED_SCROLLBUTTON_ID_AREA_DOWN].y + yoffset;
+
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_RIGHT], GDI_X, x, GDI_END);
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_DOWN], GDI_Y, y, GDI_END);
+
+ width = scrollbar_pos[ED_SCROLLBAR_ID_AREA_HORIZONTAL].width + xoffset;
+ height = scrollbar_pos[ED_SCROLLBAR_ID_AREA_VERTICAL].height + yoffset;
+
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_HORIZONTAL],
+ GDI_WIDTH, width,
+ GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldx,
+ GDI_END);
+ ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_VERTICAL],
+ GDI_HEIGHT, height,
+ GDI_SCROLLBAR_ITEMS_VISIBLE, ed_fieldy,
+ GDI_END);
+}
+
+static void AdjustLevelScrollPosition()
+{
+ if (level_xpos < -1)
+ level_xpos = -1;
+ if (level_xpos > lev_fieldx - ed_fieldx + 1)
+ level_xpos = lev_fieldx - ed_fieldx + 1;
+ if (lev_fieldx < ed_fieldx - 2)
+ level_xpos = -1;