indexing description: "[ Level Editor ]" date: "$Date$" revision: "$Revision$" class BB_LEVELEDIT inherit BB_CONSTANTS EM_WIDGET_SCENE create make feature {NONE} -- Initialization make is -- create level editor local color_background: EM_COLOR_BACKGROUND i, j: INTEGER label: EM_LABEL do current_level := "" make_widget_scene create color_background.make_from_color (create {EM_COLOR}.make_with_rgb (255, 0, 0)) create blocks.make (Number_of_rows, Number_of_columns) from i := 1 until i > Number_of_rows loop from j := 1 until j > Number_of_columns loop blocks.put (create {BB_LEVELEDIT_BLOCK}.make (i, j), i, j) blocks.item (i, j).mouse_click_event_subscribe (agent block_mouse_click (i, j, ?)) blocks.item (i, j).mouse_moved_event.subscribe (agent block_mouse_move (i, j, ?)) add_widget (blocks.item (i, j)) j := j + 1 end i := i + 1 end create not_selected_border.make (create {EM_COLOR}.make_black, 1) create selected_border.make (create {EM_COLOR}.make_black, 3) create color_buttons.make (-1, 9) from i := -1 until i > 9 loop color_buttons.put (create {EM_LABEL}.make_from_text (i.out), i) color_buttons.item (i).set_border (not_selected_border) color_buttons.item (i).set_dimension (30, 30) color_buttons.item (i).align_center color_buttons.item (i).set_position ((i * 40) + 50, 440) color_buttons.item (i).mouse_clicked_event.subscribe (agent color_mouse_click (i, ?)) add_widget (color_buttons.item (i)) i := i + 1 end color_buttons.item (-1).set_background_color (create {EM_COLOR}.make_with_rgb (164, 164, 164)) color_buttons.item (0).set_background_color (create {EM_COLOR}.make_white) color_buttons.item (1).set_background_color (create {EM_COLOR}.make_with_rgb (120, 209, 134)) color_buttons.item (2).set_background_color (create {EM_COLOR}.make_with_rgb (251, 191, 70)) color_buttons.item (3).set_background_color (create {EM_COLOR}.make_with_rgb (116, 211, 209)) color_buttons.item (4).set_background_color (create {EM_COLOR}.make_with_rgb (72, 158, 255)) color_buttons.item (5).set_background_color (create {EM_COLOR}.make_with_rgb (73, 102, 251)) color_buttons.item (6).set_background_color (create {EM_COLOR}.make_with_rgb (207, 74, 253)) color_buttons.item (7).set_background_color (create {EM_COLOR}.make_with_rgb (255, 73, 217)) color_buttons.item (8).set_background_color (create {EM_COLOR}.make_with_rgb (254, 73, 70)) color_buttons.item (9).set_background_color (create {EM_COLOR}.make_with_rgb (200, 128, 129)) color_buttons.item (0).set_border (selected_border) selected_hits := 0 is_painting := false create label.make_from_text ("Password") label.resize_to_optimal_dimension label.set_position (650, 20) add_widget (label) create password_textbox.make_empty password_textbox.set_dimension (140, 20) password_textbox.set_position (650, 40) add_widget (password_textbox) create label.make_from_text ("Image") label.resize_to_optimal_dimension label.set_position (650, 80) add_widget (label) create background_image_textbox.make_empty background_image_textbox.set_dimension (140, 20) background_image_textbox.set_position (650, 100) add_widget (background_image_textbox) create label.make_from_text ("Music (only .ogg)") label.resize_to_optimal_dimension label.set_position (650, 140) add_widget (label) create background_music_textbox.make_empty background_music_textbox.set_dimension (140, 20) background_music_textbox.set_position (650, 160) add_widget (background_music_textbox) create item_list.make_empty item_list.set_to_string_agent (agent item_to_string (?)) item_list.selection_changed_event.subscribe (agent item_selection_changed) item_list.put ([-1,"No Item"]) item_list.put ([0,"Random"]) item_list.put ([1,"Large Bar"]) item_list.put ([2,"Small Bar"]) item_list.put ([3,"Fast Bar"]) item_list.put ([4,"Slow Bar"]) item_list.put ([5,"Life +1"]) item_list.put ([6,"Invert Steering"]) item_list.put ([7,"Freeze Steering"]) item_list.put ([8,"Points"]) item_list.put ([9,"Life -1"]) item_list.put ([10,"Invulnerable"]) item_list.put ([11,"Fast Ball"]) item_list.put ([12,"Slow Ball"]) item_list.put ([13,"Fly Away"]) item_list.put ([14,"High Angle"]) item_list.put ([15,"Low Angle"]) item_list.put ([16,"Loose Points"]) item_list.put ([17,"Split Ball 2"]) item_list.put ([18,"Split Ball 4"]) item_list.put ([19,"Split Ball 6"]) item_list.put ([20,"Artillery"]) item_list.put ([21,"Transparent Ball"]) item_list.put ([22,"Next Level"]) item_list.put ([23,"Stick on Bar"]) item_list.put ([24,"Destroy All"]) item_list.put ([25,"Destroy Random"]) item_list.put ([26,"Disappear"]) item_list.put ([27,"Bad Item"]) item_list.put ([28,"Good Item"]) item_list.put ([29,"Russian Roulette"]) item_list.put ([30,"Transparent Bar"]) item_list.put ([31,"Random Direction Ball"]) item_list.put ([32,"Drive Left"]) item_list.put ([33,"Drive Right"]) create item_box.make_from_widget (item_list) item_box.set_position (470, 450) item_box.set_dimension (170, 120) add_widget (item_box) create custom_button.make_from_dimension (130, 20) custom_button.set_text ("Manage level set") custom_button.set_position (660, 400) custom_button.clicked_event.subscribe (agent custom_click) add_widget (custom_button) create new_button.make_from_dimension (130, 20) new_button.set_text ("New") new_button.set_position (660, 460) new_button.clicked_event.subscribe (agent new_click) add_widget (new_button) create load_button.make_from_dimension (130, 20) load_button.set_text ("Load") load_button.set_position (660, 490) load_button.clicked_event.subscribe (agent load_click) add_widget (load_button) create save_button.make_from_dimension (130, 20) save_button.set_text ("Save") save_button.set_position (660, 520) save_button.clicked_event.subscribe (agent save_click) add_widget (save_button) create back_button.make_from_dimension (130, 20) back_button.set_text ("Back") back_button.set_position (660, 550) back_button.clicked_event.subscribe (agent back_click) add_widget (back_button) create shift_up_button.make_from_dimension (30, 30) shift_up_button.set_text ("/\") shift_up_button.set_position (710, 200) shift_up_button.clicked_event.subscribe (agent shift_up_click) add_widget (shift_up_button) create shift_down_button.make_from_dimension (30, 30) shift_down_button.set_text ("\/") shift_down_button.set_position (710, 260) shift_down_button.clicked_event.subscribe (agent shift_down_click) add_widget (shift_down_button) create shift_left_button.make_from_dimension (30, 30) shift_left_button.set_text ("<") shift_left_button.set_position (680, 230) shift_left_button.clicked_event.subscribe (agent shift_left_click) add_widget (shift_left_button) create shift_right_button.make_from_dimension (30, 30) shift_right_button.set_text (">") shift_right_button.set_position (740, 230) shift_right_button.clicked_event.subscribe (agent shift_right_click) add_widget (shift_right_button) create label.make_from_text ("Block Field:%N- Left click: select block%N- Right click: toggle paint mode%N %NColor Select Buttons:%N- Left click: paint select block%N- Right click: select color for paint mode") label.enable_multilined label.resize_to_optimal_dimension label.set_position (10, 480) add_widget (label) Bitmap_factory.create_bitmap_from_image ("./images/paint_cursor.png") create paint_cursor.make_from_surface (Bitmap_factory.last_bitmap, 8, 8) end feature -- Miscellaneous item_to_string (an_item: TUPLE [INTEGER, STRING]): STRING is -- convert `an_item' into a string for displaying in itemlist do Result := an_item.item (2).out end clear_screen is -- clear level editor screen local i, j: INTEGER do from i := 1 until i > Number_of_rows loop from j := 1 until j > Number_of_columns loop blocks.item (i, j).set_hits (0) blocks.item (i, j).set_item (0) j := j + 1 end i := i + 1 end end load_level (level_file_path: STRING) is -- load level from `level_file_path' require level_file_path_not_void: level_file_path /= Void local level_file: PLAIN_TEXT_FILE line: STRING line_number: INTEGER block_parameters: LIST [STRING] do clear_screen create level_file.make_open_read (level_file_path) from level_file.start line_number := 1 until level_file.end_of_file loop level_file.read_line line := level_file.last_string if not line.substring (1, 2).is_equal ("//") and not line.is_equal ("") then inspect line_number when 1 then -- password password_textbox.set_text (line.out) when 2 then -- background image background_image_textbox.set_text (line.out) when 3 then -- background music background_music_textbox.set_text (line.out) else -- blocks block_parameters := line.split (' ') blocks.item (block_parameters.i_th (2).to_integer, block_parameters.i_th (1).to_integer).set_hits (block_parameters.i_th (3).to_integer) blocks.item (block_parameters.i_th (2).to_integer, block_parameters.i_th (1).to_integer).set_item (block_parameters.i_th (4).to_integer) end line_number := line_number + 1 end end level_file.close end save_level (level_file_path: STRING) is -- save level to `level_file_path' require level_file_path_not_void: level_file_path /= Void local level_file: PLAIN_TEXT_FILE i, j: INTEGER do create level_file.make_open_write (level_file_path) if password_textbox.text.is_equal ("") then level_file.put_string (current_level) else level_file.put_string (password_textbox.text) end level_file.put_new_line if background_image_textbox.text.is_equal ("") then level_file.put_string ("background.jpg") else level_file.put_string (background_image_textbox.text) end level_file.put_new_line if background_music_textbox.text.is_equal ("") then level_file.put_string ("background.ogg") else level_file.put_string (background_music_textbox.text) end level_file.put_new_line from i := 1 until i > Number_of_rows loop from j := 1 until j > Number_of_columns loop if blocks.item (i, j).hits /= 0 then level_file.put_integer (j) level_file.put_string (" ") level_file.put_integer (i) level_file.put_string (" ") level_file.put_integer (blocks.item (i, j).hits) level_file.put_string (" ") level_file.put_integer (blocks.item (i, j).item) level_file.put_new_line end j := j + 1 end i := i + 1 end end feature -- Events shift_up_click is -- shift all blocks 1 row up local i, j: INTEGER do -- move all blocks 1 row up from i := 1 until i = Number_of_rows loop from j := 1 until j > Number_of_columns loop blocks.item (i, j).set_item (blocks.item (i + 1, j).item) blocks.item (i, j).set_hits (blocks.item (i + 1, j).hits) j := j + 1 end i := i + 1 end -- clear last row from j := 1 until j > Number_of_columns loop blocks.item (Number_of_rows, j).set_item (0) blocks.item (Number_of_rows, j).set_hits (0) j := j + 1 end end shift_down_click is -- shift all blocks 1 row down local i, j: INTEGER do -- move all blocks 1 row down from i := Number_of_rows until i = 1 loop from j := 1 until j > Number_of_columns loop blocks.item (i, j).set_item (blocks.item (i - 1, j).item) blocks.item (i, j).set_hits (blocks.item (i - 1, j).hits) j := j + 1 end i := i - 1 end -- clear first row from j := 1 until j > Number_of_columns loop blocks.item (1, j).set_item (0) blocks.item (1, j).set_hits (0) j := j + 1 end end shift_left_click is -- shift all blocks 1 column left local i, j: INTEGER do -- move all blocks 1 column left from j := 1 until j = Number_of_columns loop from i := 1 until i > Number_of_rows loop blocks.item (i, j).set_item (blocks.item (i, j + 1).item) blocks.item (i, j).set_hits (blocks.item (i, j + 1).hits) i := i + 1 end j := j + 1 end -- clear last column from i := 1 until i > Number_of_rows loop blocks.item (i, Number_of_columns).set_item (0) blocks.item (i, Number_of_columns).set_hits (0) i := i + 1 end end shift_right_click is -- shift all blocks 1 column right local i, j: INTEGER do -- move all blocks 1 column right from j := Number_of_columns until j = 1 loop from i := 1 until i > Number_of_rows loop blocks.item (i, j).set_item (blocks.item (i, j - 1).item) blocks.item (i, j).set_hits (blocks.item (i, j - 1).hits) i := i + 1 end j := j - 1 end -- clear first column from i := 1 until i > Number_of_rows loop blocks.item (i, 1).set_item (0) blocks.item (i, 1).set_hits (0) i := i + 1 end end item_selection_changed (an_item: TUPLE [INTEGER, STRING]) is -- item list selection changed event do if an_item /= Void and selected_block /= Void then selected_block.set_item (an_item.integer_item (1)) end end custom_click is -- handle manage custom level set button click event do set_next_scene (create {BB_LEVELEDIT_CUSTOM}.make) start_next_scene end new_click is -- handle load button click event do clear_screen current_level := "" end load_click is -- handle load button click event local file_dialog: EM_FILE_DIALOG do create file_dialog.make file_dialog.show file_dialog.button_clicked_event.subscribe (agent handle_file_load_dialog_button_clicked (file_dialog)) file_dialog.set_directory ("./levels") file_dialog.set_title ("Load Level") end save_click is -- handle save button click event local file_dialog: EM_FILE_DIALOG do create file_dialog.make file_dialog.show file_dialog.button_clicked_event.subscribe (agent handle_file_save_dialog_button_clicked (file_dialog)) file_dialog.set_directory ("./levels") file_dialog.set_title ("Save Level") end back_click is -- handle back button click event do Video_subsystem.default_cursor.show set_next_scene (create {BB_MAINMENU}.make) start_next_scene end block_mouse_click (a_y: INTEGER; a_x: INTEGER; mousebutton_event: EM_MOUSEBUTTON_EVENT) is -- handle mouse click event require valid_x: a_x >= 1 and a_x <= Number_of_columns valid_y: a_y >= 1 and a_y <= Number_of_rows mousebutton_event_not_void: mousebutton_event /= Void local list_item_found: BOOLEAN list_item: TUPLE [INTEGER, STRING] do if mousebutton_event.is_right_button then is_painting := not is_painting if is_painting then paint_cursor.show else Video_subsystem.default_cursor.show end elseif mousebutton_event.is_left_button then if selected_block /= Void then selected_block.set_border_not_selected end selected_block := blocks.item (a_y, a_x) selected_block.set_border_selected if mousebutton_event.is_right_button then selected_block.set_hits (selected_hits) end from item_list.elements.start list_item_found := False until item_list.elements.after or list_item_found loop list_item ?= item_list.elements.item_for_iteration if list_item.integer_item (1) = selected_block.item then list_item_found := True end item_list.elements.forth end if list_item_found then item_list.set_selected_element (list_item) end end end block_mouse_move (a_y: INTEGER; a_x: INTEGER; mousemove_event: EM_MOUSEMOTION_EVENT) is -- handle mouse move event require valid_x: a_x >= 1 and a_x <= Number_of_columns valid_y: a_y >= 1 and a_y <= Number_of_rows mousemove_event_not_void: mousemove_event /= Void do if is_painting then if selected_block /= Void then selected_block.set_border_not_selected end selected_block := blocks.item (a_y, a_x) selected_block.set_border_selected selected_block.set_hits (selected_hits) end end color_mouse_click (hits: INTEGER; mousebutton_event: EM_MOUSEBUTTON_EVENT) is -- handle mouse click event require valid_hits: hits >= -1 and hits <= 9 mousebutton_event_not_void: mousebutton_event /= Void local i: INTEGER do if mousebutton_event.is_right_button then from i := -1 until i > 9 loop color_buttons.item (i).set_border (not_selected_border) i := i + 1 end color_buttons.item (hits).set_border (selected_border) selected_hits := hits elseif mousebutton_event.is_left_button then if selected_block /= Void then selected_block.set_hits (hits) end end end handle_file_load_dialog_button_clicked (a_file_dialog: EM_FILE_DIALOG) is -- Handle click of a button on 'a_file_dialog'. do if a_file_dialog.was_ok_clicked then current_level := a_file_dialog.filename load_level (a_file_dialog.absolute_filename) end end handle_file_save_dialog_button_clicked (a_file_dialog: EM_FILE_DIALOG) is -- Handle click of a button on 'a_file_dialog'. do if a_file_dialog.was_ok_clicked then current_level := a_file_dialog.filename save_level (a_file_dialog.absolute_filename) end end feature {NONE} -- Implementation menu_background: EM_BITMAP_BACKGROUND -- background bitmap blocks: ARRAY2[BB_LEVELEDIT_BLOCK] -- blocks selected_block: BB_LEVELEDIT_BLOCK -- currently selected block color_buttons: ARRAY[EM_LABEL] -- buttons to select hits selected_hits: INTEGER -- selected block hits for painting is_painting: BOOLEAN -- painting mode activated? selected_border: EM_LINE_BORDER -- border for selected color not_selected_border: EM_LINE_BORDER -- border for not selected color current_level: STRING -- current level password_textbox: EM_TEXTBOX -- level password textbox background_image_textbox: EM_TEXTBOX -- background image textbox background_music_textbox: EM_TEXTBOX -- background music textbox item_list: EM_TEXTLIST [TUPLE[INTEGER,STRING]] -- item list item_box: EM_SCROLLPANEL -- item selection box custom_button: EM_BUTTON -- custom level set button new_button: EM_BUTTON -- new button load_button: EM_BUTTON -- load button save_button: EM_BUTTON -- save button back_button: EM_BUTTON -- back button shift_up_button: EM_BUTTON -- shift up button shift_down_button: EM_BUTTON -- shift down button shift_left_button: EM_BUTTON -- shift left button shift_right_button: EM_BUTTON -- shift right button paint_cursor: EM_CURSOR -- cursor while painting end