// NODE VIEWER - test script for placing and editing node paths // Rob Bray 06/11/09 USING "rage_builtins.sch" USING "globals.sch" #IF IS_FINAL_BUILD script endscript #endif #IF IS_DEBUG_BUILD USING "brains.sch" USING "script_player.sch" USING "commands_script.sch" USING "commands_pad.sch" USING "commands_graphics.sch" USING "commands_camera.sch" USING "commands_streaming.sch" USING "commands_interiors.sch" USING "commands_object.sch" USING "commands_audio.sch" USING "script_drawing.sch" // CONSTANTS CONST_INT NUMBER_OF_NODES_PER_SET 12 CONST_INT NUMBER_OF_SETS 2 CONST_INT NUMBER_OF_SUB_MENU_ITEMS 4 CONST_INT SPHERE_ALPHA 170 CONST_INT BOX_ALPHA 115 CONST_FLOAT POINT_NODE_SIZE 1.65 CONST_FLOAT BOX_NODE_SIZE 1.4 CONST_FLOAT POINT_NODE_TEXT_OFFSET 1.95 CONST_FLOAT BOX_NODE_TEXT_OFFSET 1.65 // ENUMS ENUM VIEWER_STATE_ENUM STATE_MENU = 0, STATE_FLYCAM ENDENUM VIEWER_STATE_ENUM current_viewer_state = STATE_MENU ENUM SUB_MENU_ENUM SUB_MENU_HIDDEN = 0, SUB_MENU_EDIT, SUB_MENU_COPY, SUB_MENU_DELETE ENDENUM SUB_MENU_ENUM current_sub_menu_selection = SUB_MENU_HIDDEN ENUM NODE_TYPE_ENUM TYPE_FREE_NODE = 0, TYPE_POINT_NODE, TYPE_BOX_FIRST_NODE, TYPE_BOX_SECOND_NODE ENDENUM ENUM AUDIO_CONFIRM_ENUM AUDIO_CONFIRM_CHANGE = 0, AUDIO_CONFIRM_EDIT ENDENUM // STRUCTURES STRUCT NODE_STRUCT NODE_TYPE_ENUM type VECTOR v_coords TEXT_LABEL_31 tl_label INT i_creation_number INT i_box_counterpart_index ENDSTRUCT STRUCT NODE_SET_STRUCT NODE_STRUCT nodes[NUMBER_OF_NODES_PER_SET] TEXT_LABEL_31 tl_name BOOL b_open //INT i_creation_number INT i_node_creation_counter ENDSTRUCT // GLOBALS NODE_SET_STRUCT node_sets[NUMBER_OF_SETS] CAMERA_INDEX debug_cam CAMERA_INDEX point_cam CAMERA_INDEX menu_cam INT i_current_set_index = -1 INT i_current_node_index = -1 INT i_set_creation_counter INT i_white = INT_COLOUR(255, 255, 255, 255) INT i_red = INT_COLOUR(255, 0, 0, 255) BOOL b_do_update_widget BOOL b_update_label BOOL b_update_name BOOL b_show_quit_confirm BOOL b_set_menu_cam BOOL b_equidistant_drop BOOL b_draw_help = TRUE BOOL b_quit_tool VECTOR v_cam_coords //VECTOR v_cam_rot FLOAT f_distance_travelled FLOAT f_distance_to_travel_for_next_drop = 50.0 VECTOR v_last_cam_coords WIDGET_GROUP_ID w_nodes_group TEXT_WIDGET_ID w_node_label TEXT_WIDGET_ID w_set_name // FUNCTIONS // play audio confirmation of action PROC DO_SOUND(AUDIO_CONFIRM_ENUM confirm_type) IF confirm_type = AUDIO_CONFIRM_EDIT PLAY_SOUND_FRONTEND(-1, "AK47_COCK_PULL") ELIF confirm_type = AUDIO_CONFIRM_CHANGE PLAY_SOUND_FRONTEND(-1, "GENERAL_WEAPONS_MP5_SLAM") ENDIF ENDPROC // create a new set PROC CREATE_NEW_SET(INT i_index) INT i // fill set attributes REPEAT NUMBER_OF_NODES_PER_SET i node_sets[i_index].nodes[i].type = TYPE_FREE_NODE node_sets[i_index].nodes[i].v_coords = <<0,0,0>> node_sets[i_index].nodes[i].tl_label = "" //node_sets[i_index].nodes[i].i_creation_number = -1 node_sets[i_index].nodes[i].i_box_counterpart_index = -1 ENDREPEAT node_sets[i_index].b_open = TRUE node_sets[i_index].tl_name = "Set " node_sets[i_index].tl_name += i_set_creation_counter //node_sets[i_index].i_creation_number = i_set_creation_counter node_sets[i_index].i_node_creation_counter = 0 i_set_creation_counter++ ENDPROC // copy data from one set to another FUNC BOOL COPY_SET_DATA_INTO_SLOT(INT i_from_index, INT i_to_index) INT i IF i_from_index >= 0 AND i_to_index >= 0 IF node_sets[i_from_index].b_open IF NOT node_sets[i_to_index].b_open // fill set attributes REPEAT NUMBER_OF_NODES_PER_SET i node_sets[i_to_index].nodes[i].type = node_sets[i_from_index].nodes[i].type node_sets[i_to_index].nodes[i].v_coords = node_sets[i_from_index].nodes[i].v_coords node_sets[i_to_index].nodes[i].tl_label = node_sets[i_from_index].nodes[i].tl_label node_sets[i_to_index].nodes[i].i_creation_number = node_sets[i_from_index].nodes[i].i_creation_number node_sets[i_to_index].nodes[i].i_box_counterpart_index = node_sets[i_from_index].nodes[i].i_box_counterpart_index ENDREPEAT node_sets[i_to_index].b_open = TRUE TEXT_LABEL_63 tl_name = "(Copy) " tl_name += node_sets[i_from_index].tl_name INT i_name_length = GET_LENGTH_OF_LITERAL_STRING(node_sets[i_to_index].tl_name) IF i_name_length >= 15 tl_name = GET_FIRST_N_CHARACTERS_OF_STRING(tl_name, 15) ENDIF node_sets[i_to_index].tl_name = tl_name //node_sets[i_to_index].i_creation_number = i_set_creation_counter node_sets[i_to_index].i_node_creation_counter = node_sets[i_from_index].i_node_creation_counter RETURN TRUE ELSE PRINTSTRING("Attempting to copy to an open set") PRINTNL() ENDIF ELSE PRINTSTRING("Attempting to copy from a closed set") PRINTNL() ENDIF ELSE PRINTSTRING("One or both copy slots do not exist") PRINTNL() ENDIF RETURN FALSE ENDFUNC // delete a set PROC DELETE_SET(INT i_index) IF i_index >= 0 IF node_sets[i_index].b_open node_sets[i_index].b_open = FALSE ENDIF ENDIF ENDPROC // fill the data of initial sets (temp for testing) PROC FILL_INITIAL_SETS() INT i REPEAT NUMBER_OF_SETS i CREATE_NEW_SET(i) ENDREPEAT ENDPROC // get the first available index of a free set FUNC INT GET_FREE_SET_INDEX() INT i REPEAT NUMBER_OF_SETS i IF NOT node_sets[i].b_open // only return sets that are not open RETURN i ENDIF ENDREPEAT RETURN -1 ENDFUNC // get next open set iterating through array FUNC INT GET_NEXT_OPEN_SET(INT i_index) INT i IF i_index >= 0 FOR i = i_index TO (NUMBER_OF_SETS - 1) IF node_sets[i].b_open // only return open sets AND i <> i_index // don't return this index RETURN i ENDIF ENDFOR // loop round if not found any FOR i = 0 TO i_index IF node_sets[i].b_open // only return open sets AND i <> i_index // don't return this index RETURN i ENDIF ENDFOR ENDIF RETURN -1 ENDFUNC // get previous open set iterating through array FUNC INT GET_PREVIOUS_OPEN_SET(INT i_index) INT i IF i_index >= 0 FOR i = i_index TO 0 STEP -1 IF node_sets[i].b_open // only return open sets AND i <> i_index // don't return this index RETURN i ENDIF ENDFOR // loop round if not found any FOR i = (NUMBER_OF_SETS - 1) TO i_index STEP -1 IF node_sets[i].b_open // only return open sets AND i <> i_index // don't return this index RETURN i ENDIF ENDFOR ENDIF RETURN -1 ENDFUNC // set the current set index PROC SET_CURRENT_SET_INDEX(INT i_index) i_current_set_index = i_index b_do_update_widget = TRUE ENDPROC // set set name PROC SET_SET_NAME(INT i_index, STRING s_name) node_sets[i_index].tl_name = "" node_sets[i_index].tl_name += s_name ENDPROC // set the current node index PROC SET_CURRENT_NODE_INDEX(INT i_index) i_current_node_index = i_index b_do_update_widget = TRUE ENDPROC // get the node at a specific index FUNC NODE_STRUCT GET_NODE_AT_INDEX(INT i_index) //PRINTSTRING("GET_NODE_AT_INDEX - Index = ") //PRINTINT(i_index) //PRINTSTRING(" i_current_set_index = ") //PRINTINT(i_current_set_index) //PRINTNL() RETURN node_sets[i_current_set_index].nodes[i_index] ENDFUNC // get the index of the closest node to the specified index FUNC INT GET_CLOSEST_NODE_INDEX_TO_NODE(INT i_index) INT i NODE_STRUCT this_node = GET_NODE_AT_INDEX(i_index) INT i_closest_index = -1 FLOAT f_closest_distance = -1 FLOAT f_distance REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT check_node = GET_NODE_AT_INDEX(i) IF check_node.type <> TYPE_FREE_NODE // only check active nodes AND i <> i_index // don't check specified index f_distance = GET_DISTANCE_BETWEEN_COORDS(this_node.v_coords, check_node.v_coords) IF f_distance <= f_closest_distance OR f_closest_distance = -1 // if closer than previous closest, set to return this index i_closest_index = i f_closest_distance = f_distance ENDIF ENDIF ENDREPEAT RETURN i_closest_index ENDFUNC // get the node with the lowest creation number FUNC INT GET_FIRST_NODE_INDEX() INT i INT i_closest_index = -1 INT i_closest_creation_number = -1 REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT check_node = GET_NODE_AT_INDEX(i) IF check_node.type <> TYPE_FREE_NODE // only check active nodes IF check_node.i_creation_number < i_closest_creation_number OR i_closest_creation_number = -1 i_closest_index = i i_closest_creation_number = check_node.i_creation_number ENDIF ENDIF ENDREPEAT RETURN i_closest_index ENDFUNC // get next node in order of creation FUNC INT GET_NEXT_NODE_INDEX_IN_ORDER(INT i_index, BOOL b_loop = FALSE) INT i NODE_STRUCT this_node = GET_NODE_AT_INDEX(i_index) INT i_closest_index = -1 INT i_closest_creation_number = -1 REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT check_node = GET_NODE_AT_INDEX(i) IF check_node.type <> TYPE_FREE_NODE // only check active nodes AND i <> i_index // don't check specified index IF check_node.i_creation_number > this_node.i_creation_number AND (check_node.i_creation_number < i_closest_creation_number OR i_closest_creation_number = -1) i_closest_index = i i_closest_creation_number = check_node.i_creation_number ENDIF ENDIF ENDREPEAT // if loop around, find lowest IF b_loop IF i_closest_index = -1 REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT check_node = GET_NODE_AT_INDEX(i) IF check_node.type <> TYPE_FREE_NODE // only check active nodes AND i <> i_index // don't check specified index IF check_node.i_creation_number < this_node.i_creation_number AND (check_node.i_creation_number < i_closest_creation_number OR i_closest_creation_number = -1) i_closest_index = i i_closest_creation_number = check_node.i_creation_number ENDIF ENDIF ENDREPEAT ENDIF ENDIF RETURN i_closest_index ENDFUNC // get previous node in order of creation FUNC INT GET_PREVIOUS_NODE_INDEX_IN_ORDER(INT i_index, BOOL b_loop = FALSE) INT i NODE_STRUCT this_node = GET_NODE_AT_INDEX(i_index) INT i_closest_index = -1 INT i_closest_creation_number = -1 REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT check_node = GET_NODE_AT_INDEX(i) IF check_node.type <> TYPE_FREE_NODE // only check active nodes AND i <> i_index // don't check specified index IF check_node.i_creation_number < this_node.i_creation_number AND (check_node.i_creation_number > i_closest_creation_number OR i_closest_creation_number = -1) i_closest_index = i i_closest_creation_number = check_node.i_creation_number ENDIF ENDIF ENDREPEAT // if loop around, find highest IF b_loop IF i_closest_index = -1 REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT check_node = GET_NODE_AT_INDEX(i) IF check_node.type <> TYPE_FREE_NODE // only check active nodes AND i <> i_index // don't check specified index IF check_node.i_creation_number > this_node.i_creation_number AND (check_node.i_creation_number > i_closest_creation_number OR i_closest_creation_number = -1) i_closest_index = i i_closest_creation_number = check_node.i_creation_number ENDIF ENDIF ENDREPEAT ENDIF ENDIF RETURN i_closest_index ENDFUNC // get coords FUNC VECTOR GET_NODE_COORDS_AT_INDEX(INT i_index) RETURN node_sets[i_current_set_index].nodes[i_index].v_coords ENDFUNC // get label FUNC TEXT_LABEL GET_NODE_LABEL_AT_INDEX(INT i_index) RETURN node_sets[i_current_set_index].nodes[i_index].tl_label ENDFUNC // set node coords PROC SET_NODE_COORDS_AT_INDEX(INT i_index, VECTOR v_coords) node_sets[i_current_set_index].nodes[i_index].v_coords = v_coords ENDPROC // set node type PROC SET_NODE_TYPE_AT_INDEX(INT i_index, NODE_TYPE_ENUM type) node_sets[i_current_set_index].nodes[i_index].type = type ENDPROC // set node label PROC SET_NODE_LABEL_AT_INDEX(INT i_index, STRING s_label) node_sets[i_current_set_index].nodes[i_index].tl_label = "" node_sets[i_current_set_index].nodes[i_index].tl_label += s_label ENDPROC // set node box counterpart PROC SET_NODE_BOX_COUNTERPART_AT_INDEX(INT i_index, INT i_counterpart_index) node_sets[i_current_set_index].nodes[i_index].i_box_counterpart_index = i_counterpart_index ENDPROC // delete node PROC DELETE_NODE_AT_INDEX(INT i_index) node_sets[i_current_set_index].nodes[i_index].type = TYPE_FREE_NODE ENDPROC // get the first available index of a free node in a set FUNC INT GET_FREE_NODE_INDEX() INT i REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT check_node = GET_NODE_AT_INDEX(i) IF check_node.type = TYPE_FREE_NODE RETURN i ENDIF ENDREPEAT RETURN -1 ENDFUNC // set camera to look down on the specified coords PROC CAM_LOOK_DOWN_ON_COORDS(VECTOR v_coords) SET_CAM_COORD(debug_cam, <>) SET_CAM_ROT(debug_cam, <<-89, 0, 0>>) ENDPROC // point cam at node if not on screen PROC POINT_CAM_AT_NODE(INT i_index) VECTOR v_node_coords = GET_NODE_COORDS_AT_INDEX(i_index) IF NOT IS_SPHERE_VISIBLE(v_node_coords, POINT_NODE_SIZE) IF GET_DISTANCE_BETWEEN_COORDS(v_node_coords, v_cam_coords) >= 120.0 // if further than 120m away, jump cam pos over there CAM_LOOK_DOWN_ON_COORDS(v_node_coords) ELSE // otherwise just point at it SET_CAM_COORD(point_cam, v_cam_coords) POINT_CAM_AT_COORD(point_cam, v_node_coords) WAIT(0) SET_CAM_ROT(debug_cam, GET_CAM_ROT(point_cam)) ENDIF ENDIF ENDPROC // create a node PROC CREATE_NODE(NODE_STRUCT &node, NODE_SET_STRUCT &set) // fill node attributes node.type = TYPE_POINT_NODE node.v_coords = v_cam_coords node.tl_label = "Node " node.tl_label += set.i_node_creation_counter node.i_creation_number = set.i_node_creation_counter node.i_box_counterpart_index = -1 // increment creation counter set.i_node_creation_counter++ ENDPROC // create a new node at the current debug cam coords PROC PLACE_NEW_NODE(NODE_SET_STRUCT &set) // find a free index INT i_index = GET_FREE_NODE_INDEX() IF i_index >= 0 // create the node CREATE_NODE(node_sets[i_current_set_index].nodes[i_index], set) // set this node as current SET_CURRENT_NODE_INDEX(i_index) DO_SOUND(AUDIO_CONFIRM_EDIT) ELSE SCRIPT_ASSERT("Maximum number of nodes for this set reached") ENDIF ENDPROC // move the currently selected node PROC MOVE_CURRENT_NODE() IF i_current_node_index >= 0 // set the node coords SET_NODE_COORDS_AT_INDEX(i_current_node_index, v_cam_coords) DO_SOUND(AUDIO_CONFIRM_EDIT) ELSE PRINTSTRING("Attempting to move a node which does not exist") PRINTNL() ENDIF ENDPROC // delete the currently selected node PROC DELETE_CURRENT_NODE() IF i_current_node_index >= 0 NODE_STRUCT current_node = GET_NODE_AT_INDEX(i_current_node_index) IF current_node.type = TYPE_POINT_NODE // if a point node, can just delete it DELETE_NODE_AT_INDEX(i_current_node_index) ELIF current_node.type = TYPE_BOX_FIRST_NODE OR current_node.type = TYPE_BOX_SECOND_NODE // if a box node, have to delete its counterpart too IF current_node.i_box_counterpart_index >= 0 DELETE_NODE_AT_INDEX(current_node.i_box_counterpart_index) ENDIF DELETE_NODE_AT_INDEX(i_current_node_index) ENDIF // set currently selected node as the closest to the deleted one INT i_closest_node = GET_CLOSEST_NODE_INDEX_TO_NODE(i_current_node_index) SET_CURRENT_NODE_INDEX(i_closest_node) IF i_current_node_index >= 0 POINT_CAM_AT_NODE(i_current_node_index) ENDIF DO_SOUND(AUDIO_CONFIRM_CHANGE) ELSE PRINTSTRING("Attempting to delete a node which does not exist") PRINTNL() ENDIF ENDPROC // place currently selected node on ground PROC PLACE_CURRENT_NODE_ON_GROUND() IF i_current_node_index >= 0 NODE_STRUCT current_node = GET_NODE_AT_INDEX(i_current_node_index) VECTOR v_current_coords = current_node.v_coords // get ground level FLOAT f_ground_z IF GET_GROUND_Z_FOR_3D_COORD(v_current_coords, f_ground_z) // move the node SET_NODE_COORDS_AT_INDEX(i_current_node_index, <>) DO_SOUND(AUDIO_CONFIRM_EDIT) ENDIF ELSE PRINTSTRING("Attempting to move a node which does not exist") PRINTNL() ENDIF ENDPROC // change currently selected node and the one created before that into a box or vice versa PROC CONVERT_CURRENT_AND_PRECEDING_NODES_TO_BOX() IF i_current_node_index >= 0 NODE_STRUCT current_node = GET_NODE_AT_INDEX(i_current_node_index) IF current_node.type = TYPE_POINT_NODE // convert to box INT i_preceding_node_index = GET_PREVIOUS_NODE_INDEX_IN_ORDER(i_current_node_index) IF i_preceding_node_index >= 0 NODE_STRUCT preceding_node = GET_NODE_AT_INDEX(i_preceding_node_index) IF preceding_node.type = TYPE_POINT_NODE // setup preceding node as first box node SET_NODE_TYPE_AT_INDEX(i_preceding_node_index, TYPE_BOX_FIRST_NODE) SET_NODE_BOX_COUNTERPART_AT_INDEX(i_preceding_node_index, i_current_node_index) // setup current node as second box node SET_NODE_TYPE_AT_INDEX(i_current_node_index, TYPE_BOX_SECOND_NODE) SET_NODE_BOX_COUNTERPART_AT_INDEX(i_current_node_index, i_preceding_node_index) DO_SOUND(AUDIO_CONFIRM_EDIT) ELSE PRINTSTRING("Preceding node is already a box") PRINTNL() ENDIF ELSE PRINTSTRING("Couldn't find preceding node") PRINTNL() ENDIF ELIF current_node.type = TYPE_BOX_FIRST_NODE OR current_node.type = TYPE_BOX_SECOND_NODE // change this node back to a point SET_NODE_TYPE_AT_INDEX(i_current_node_index, TYPE_POINT_NODE) // change the box's counterpart back to a point IF current_node.i_box_counterpart_index >= 0 NODE_STRUCT counterpart_node = GET_NODE_AT_INDEX(current_node.i_box_counterpart_index) IF counterpart_node.type = TYPE_BOX_FIRST_NODE OR counterpart_node.type = TYPE_BOX_SECOND_NODE SET_NODE_TYPE_AT_INDEX(current_node.i_box_counterpart_index, TYPE_POINT_NODE) SET_NODE_BOX_COUNTERPART_AT_INDEX(current_node.i_box_counterpart_index, -1) ENDIF ENDIF // reset this node's counterpart SET_NODE_BOX_COUNTERPART_AT_INDEX(i_current_node_index, -1) DO_SOUND(AUDIO_CONFIRM_EDIT) ENDIF ELSE PRINTSTRING("Attempting to convert a node which does not exist") PRINTNL() ENDIF ENDPROC // set current node to next one along PROC GO_TO_NEXT_NODE() IF i_current_node_index >= 0 INT i_next_node = GET_NEXT_NODE_INDEX_IN_ORDER(i_current_node_index, TRUE) IF i_next_node >= 0 SET_CURRENT_NODE_INDEX(i_next_node) POINT_CAM_AT_NODE(i_current_node_index) DO_SOUND(AUDIO_CONFIRM_CHANGE) ENDIF ENDIF ENDPROC // set current node to previous one along PROC GO_TO_PREVIOUS_NODE() IF i_current_node_index >= 0 INT i_previous_node = GET_PREVIOUS_NODE_INDEX_IN_ORDER(i_current_node_index, TRUE) IF i_previous_node >= 0 SET_CURRENT_NODE_INDEX(i_previous_node) POINT_CAM_AT_NODE(i_current_node_index) DO_SOUND(AUDIO_CONFIRM_CHANGE) ENDIF ENDIF ENDPROC // debug cam coords and rot to menu cam PROC COPY_DEBUG_CAM_TO_MENU_CAM() SET_CAM_COORD(menu_cam, GET_CAM_COORD(debug_cam)) SET_CAM_ROT(menu_cam, GET_CAM_ROT(debug_cam)) SET_CAM_FOV(menu_cam, GET_CAM_FOV(debug_cam)) ENDPROC // menu cam coords and rot to debug cam PROC COPY_MENU_CAM_TO_DEBUG_CAM() SET_CAM_COORD(debug_cam, GET_CAM_COORD(menu_cam)) SET_CAM_ROT(debug_cam, GET_CAM_ROT(menu_cam)) SET_CAM_FOV(debug_cam, GET_CAM_FOV(menu_cam)) ENDPROC // jump the camera to the first node in the set PROC JUMP_VIEW_TO_FIRST_NODE_IN_SET() INT i_first_node_index = GET_FIRST_NODE_INDEX() SET_CURRENT_NODE_INDEX(i_first_node_index) IF i_first_node_index >= 0 VECTOR v_first_coords = GET_NODE_COORDS_AT_INDEX(i_first_node_index) CAM_LOOK_DOWN_ON_COORDS(v_first_coords) COPY_DEBUG_CAM_TO_MENU_CAM() ENDIF ENDPROC // select next set PROC GO_TO_NEXT_SET() IF i_current_set_index >= 0 INT i_next_set_index = GET_NEXT_OPEN_SET(i_current_set_index) IF i_next_set_index >= 0 SET_CURRENT_SET_INDEX(i_next_set_index) JUMP_VIEW_TO_FIRST_NODE_IN_SET() ENDIF ENDIF ENDPROC // select previous set PROC GO_TO_PREVIOUS_SET() IF i_current_set_index >= 0 INT i_previous_set_index = GET_PREVIOUS_OPEN_SET(i_current_set_index) IF i_previous_set_index >= 0 SET_CURRENT_SET_INDEX(i_previous_set_index) JUMP_VIEW_TO_FIRST_NODE_IN_SET() ENDIF ENDIF ENDPROC // go into set submenu PROC DO_SUB_MENU() IF i_current_set_index >= 0 current_sub_menu_selection = SUB_MENU_EDIT ENDIF ENDPROC // select next submenu item PROC GO_TO_NEXT_SUB_MENU_ITEM() INT i_next_menu_pos i_next_menu_pos = ENUM_TO_INT(current_sub_menu_selection) + 1 IF i_next_menu_pos > (NUMBER_OF_SUB_MENU_ITEMS -1) i_next_menu_pos = 1 ENDIF current_sub_menu_selection = INT_TO_ENUM(SUB_MENU_ENUM, i_next_menu_pos) ENDPROC // select previous submenu item PROC GO_TO_PREVIOUS_SUB_MENU_ITEM() INT i_next_menu_pos i_next_menu_pos = ENUM_TO_INT(current_sub_menu_selection) - 1 IF i_next_menu_pos < 1 i_next_menu_pos = NUMBER_OF_SUB_MENU_ITEMS -1 ENDIF current_sub_menu_selection = INT_TO_ENUM(SUB_MENU_ENUM, i_next_menu_pos) ENDPROC // create new set from menu PROC DO_CREATE_SET() INT i_slot = GET_FREE_SET_INDEX() IF i_slot >= 0 CREATE_NEW_SET(i_slot) SET_CURRENT_SET_INDEX(i_slot) ELSE PRINTSTRING("Could not find a free set index") PRINTNL() ENDIF ENDPROC // go into edit from menu PROC DO_EDIT_SET() IF i_current_set_index >= 0 RENDER_SCRIPT_CAMS(FALSE, FALSE) IF i_current_node_index = -1 // set debug cam pos to game cam pos if no node selected SET_CAM_COORD(debug_cam, GET_GAMEPLAY_CAM_COORD()) SET_CAM_ROT(debug_cam, GET_GAMEPLAY_CAM_ROT()) SET_CAM_FOV(debug_cam, GET_GAMEPLAY_CAM_FOV()) ENDIF v_last_cam_coords = v_cam_coords b_equidistant_drop = FALSE SET_DEBUG_CAM_ACTIVE(TRUE, TRUE) current_sub_menu_selection = SUB_MENU_HIDDEN current_viewer_state = STATE_FLYCAM ENDIF ENDPROC // delete set from menu PROC DO_DELETE_SET() IF i_current_set_index >= 0 DELETE_SET(i_current_set_index) i_current_set_index = GET_PREVIOUS_OPEN_SET(i_current_set_index) b_do_update_widget = TRUE current_sub_menu_selection = SUB_MENU_HIDDEN ELSE PRINTSTRING("Attempting to delete a set which does not exist") PRINTNL() ENDIF ENDPROC // copy the current set into a free slot PROC DO_COPY_SET() IF i_current_set_index >= 0 INT i_slot = GET_FREE_SET_INDEX() IF i_slot >= 0 IF COPY_SET_DATA_INTO_SLOT(i_current_set_index, i_slot) SET_CURRENT_SET_INDEX(i_slot) ELSE PRINTSTRING("Copy failed") PRINTNL() ENDIF ELSE PRINTSTRING("Could not find a free set index") PRINTNL() ENDIF current_sub_menu_selection = SUB_MENU_HIDDEN ELSE PRINTSTRING("Attempting to copy a set which does not exist") PRINTNL() ENDIF ENDPROC // toggle equidistant drop PROC TOGGLE_EQUIDISTANT_DROP() IF NOT b_equidistant_drop b_equidistant_drop = TRUE ELSE b_equidistant_drop = FALSE ENDIF f_distance_travelled = 0.0 ENDPROC // back into menu from fly cam PROC GO_TO_MENU() // save the set NODEVIEWER_SAVE_SET(0, i_current_set_index, node_sets[i_current_set_index], SIZE_OF(NODE_SET_STRUCT)) RENDER_SCRIPT_CAMS(TRUE, FALSE) //SET_CURRENT_NODE_INDEX(-1) b_equidistant_drop = FALSE f_distance_travelled = 0.0 SET_DEBUG_CAM_ACTIVE(FALSE, TRUE) current_viewer_state = STATE_MENU ENDPROC // check the control pad and perform desired action PROC HANDLE_USER_ACTIONS() SWITCH current_viewer_state CASE STATE_MENU IF NOT b_show_quit_confirm // if haven't selected a set yet IF current_sub_menu_selection = SUB_MENU_HIDDEN // dpad down - next set IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, DPADDOWN) GO_TO_NEXT_SET() ENDIF // dpad up - previous set IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, DPADUP) GO_TO_PREVIOUS_SET() ENDIF // square - create set IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, SQUARE) DO_CREATE_SET() ENDIF // cross - select set, go to submenu IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, CROSS) DO_SUB_MENU() ENDIF // triangle - quit IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, TRIANGLE) b_show_quit_confirm = TRUE ENDIF ELSE // dpad down - next submenu item IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, DPADDOWN) GO_TO_NEXT_SUB_MENU_ITEM() ENDIF // dpad up - previous submenu item IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, DPADUP) GO_TO_PREVIOUS_SUB_MENU_ITEM() ENDIF // if in sub menu, perform action based on what is selected in sub menu IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, CROSS) SWITCH current_sub_menu_selection CASE SUB_MENU_EDIT // edit - go into fly cam DO_EDIT_SET() BREAK CASE SUB_MENU_COPY // copy DO_COPY_SET() BREAK CASE SUB_MENU_DELETE // delete - get rid of all data in current set DO_DELETE_SET() BREAK ENDSWITCH ENDIF // triangle - back out of sub menu IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, TRIANGLE) current_sub_menu_selection = SUB_MENU_HIDDEN ENDIF ENDIF ELSE // controls for quit // cross - confirm quit IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, CROSS) b_quit_tool = TRUE ENDIF // triangle - cancel quit IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, TRIANGLE) b_show_quit_confirm = FALSE ENDIF ENDIF BREAK // controls for dropping / editing in flycam CASE STATE_FLYCAM // edit functions IF IS_BUTTON_PRESSED(DEBUG_PAD, LEFTSHOULDER1) // cross - move node IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, RIGHTSHOULDER1) MOVE_CURRENT_NODE() ENDIF // square - put node on ground IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, RIGHTSHOCK) PLACE_CURRENT_NODE_ON_GROUND() ENDIF // rstick - convert last two nodes into a box IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, LEFTSHOCK) CONVERT_CURRENT_AND_PRECEDING_NODES_TO_BOX() ENDIF // edit not held ELSE // r1 - create new node IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, RIGHTSHOULDER1) PLACE_NEW_NODE(node_sets[i_current_set_index]) ENDIF // triangle - delete node IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, TRIANGLE) DELETE_CURRENT_NODE() ENDIF // dpad right - next node IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, DPADRIGHT) GO_TO_NEXT_NODE() ENDIF // dpad left - previous node IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, DPADLEFT) GO_TO_PREVIOUS_NODE() ENDIF // select - toggle equidistant drop IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, SELECT) TOGGLE_EQUIDISTANT_DROP() ENDIF // start - go back into menu IF IS_BUTTON_JUST_PRESSED(DEBUG_PAD, START) GO_TO_MENU() ENDIF ENDIF BREAK ENDSWITCH ENDPROC // update distance travelled for equidistant drop amd drop if gone over limit PROC UPDATE_EQUIDISTANT_DROP() IF b_equidistant_drop f_distance_travelled += GET_DISTANCE_BETWEEN_COORDS(v_cam_coords, v_last_cam_coords) IF f_distance_travelled >= f_distance_to_travel_for_next_drop PLACE_NEW_NODE(node_sets[i_current_set_index]) f_distance_travelled = 0.0 ENDIF ELSE // reset distance to 0 if turned off IF f_distance_travelled > 0.0 f_distance_travelled = 0.0 ENDIF ENDIF v_last_cam_coords = v_cam_coords ENDPROC // return the correct size to draw a debug sphere FUNC FLOAT GET_SIZE_TO_DRAW_SPHERE(NODE_TYPE_ENUM type) IF type = TYPE_POINT_NODE RETURN POINT_NODE_SIZE ELIF type = TYPE_BOX_FIRST_NODE OR type = TYPE_BOX_SECOND_NODE RETURN BOX_NODE_SIZE ENDIF RETURN POINT_NODE_SIZE ENDFUNC // return correct amount to offset text label FUNC FLOAT GET_TEXT_OFFSET(NODE_TYPE_ENUM type) IF type = TYPE_POINT_NODE RETURN POINT_NODE_TEXT_OFFSET ELIF type = TYPE_BOX_FIRST_NODE OR type = TYPE_BOX_SECOND_NODE RETURN BOX_NODE_TEXT_OFFSET ENDIF RETURN POINT_NODE_TEXT_OFFSET ENDFUNC // draw shadow under camera PROC DRAW_SHADOW() FLOAT f_ground_z IF GET_GROUND_Z_FOR_3D_COORD(v_cam_coords, f_ground_z) DRAW_DEBUG_SPHERE(<>, 2.0, 0, 0, 0, 185) ENDIF ENDPROC // draw all the nodes in the current set PROC DRAW_NODES_GROUP() INT i REPEAT NUMBER_OF_NODES_PER_SET i NODE_STRUCT node = GET_NODE_AT_INDEX(i) // draw sphere and text at each node coords IF node.type <> TYPE_FREE_NODE IF i = i_current_node_index AND current_viewer_state = STATE_FLYCAM // selected DRAW_DEBUG_SPHERE(node.v_coords, GET_SIZE_TO_DRAW_SPHERE(node.type), 255, 0, 0, SPHERE_ALPHA) DRAW_DEBUG_TEXT(node.tl_label, <>, 255, 0, 0, SPHERE_ALPHA) ELSE // unselected DRAW_DEBUG_SPHERE(node.v_coords, GET_SIZE_TO_DRAW_SPHERE(node.type), 0, 155, 255, SPHERE_ALPHA) DRAW_DEBUG_TEXT(node.tl_label, <>, 0, 155, 255, SPHERE_ALPHA) ENDIF ENDIF // draw a box for any box nodes IF node.type = TYPE_BOX_FIRST_NODE IF node.i_box_counterpart_index >= 0 NODE_STRUCT second_node = GET_NODE_AT_INDEX(node.i_box_counterpart_index) IF second_node.type = TYPE_BOX_SECOND_NODE // setup the correct order to draw the points (for command to work first vector must be lowest, second highest) VECTOR v_first_box_coords = <<0,0,0>> VECTOR v_second_box_coords = <<0,0,0>> IF node.v_coords.x < second_node.v_coords.x v_first_box_coords.x = node.v_coords.x v_second_box_coords.x = second_node.v_coords.x ELSE v_first_box_coords.x = second_node.v_coords.x v_second_box_coords.x = node.v_coords.x ENDIF IF node.v_coords.y < second_node.v_coords.y v_first_box_coords.y = node.v_coords.y v_second_box_coords.y = second_node.v_coords.y ELSE v_first_box_coords.y = second_node.v_coords.y v_second_box_coords.y = node.v_coords.y ENDIF IF node.v_coords.z < second_node.v_coords.z v_first_box_coords.z = node.v_coords.z v_second_box_coords.z = second_node.v_coords.z ELSE v_first_box_coords.z = second_node.v_coords.z v_second_box_coords.z = node.v_coords.z ENDIF // do the box IF (i = i_current_node_index OR node.i_box_counterpart_index = i_current_node_index) AND current_viewer_state = STATE_FLYCAM // selected DRAW_DEBUG_BOX(v_first_box_coords, v_second_box_coords, 255, 0, 0, BOX_ALPHA) ELSE // unselected DRAW_DEBUG_BOX(v_first_box_coords, v_second_box_coords, 0, 155, 255, BOX_ALPHA) ENDIF ENDIF ENDIF ENDIF ENDREPEAT ENDPROC PROC DRAW_SUB_MENU_ITEM(SUB_MENU_ENUM item, FLOAT f_y_pos) INT i_colour IF current_sub_menu_selection = item i_colour = i_red ELSE i_colour = i_white ENDIF STRING s_text SWITCH item CASE SUB_MENU_EDIT s_text = "EDIT" BREAK CASE SUB_MENU_COPY s_text = "COPY" BREAK CASE SUB_MENU_DELETE s_text = "DELETE" BREAK ENDSWITCH DEBUG_DISPLAY_LITERAL_TEXT(s_text, 0.25, f_y_pos, 0.3, 0.3, 0.0, 1.0, i_colour) ENDPROC // draw the sub menu popup PROC DRAW_SUB_MENU(FLOAT f_y_pos) DRAW_SUB_MENU_ITEM(SUB_MENU_EDIT, f_y_pos) DRAW_SUB_MENU_ITEM(SUB_MENU_COPY, f_y_pos + 0.02) DRAW_SUB_MENU_ITEM(SUB_MENU_DELETE, f_y_pos + 0.04) ENDPROC // draw the menu screen PROC DRAW_MENU() INT i // draw the background DRAW_RECT(0.25, 0.5, 0.5, 1.0, 0, 0, 0, 220) // draw the title DEBUG_DISPLAY_LITERAL_TEXT("NODE VIEWER", 0.06, 0.06, 0.75, 0.75, 0.0, 1.0, i_white) IF NOT b_show_quit_confirm // draw the list of node sets REPEAT NUMBER_OF_SETS i IF node_sets[i].b_open // draw set name IF i = i_current_set_index DEBUG_DISPLAY_LITERAL_TEXT(node_sets[i].tl_name, 0.06, 0.135 + (i*0.05), 0.4, 0.4, 0.0, 1.0, i_red) ELSE DEBUG_DISPLAY_LITERAL_TEXT(node_sets[i].tl_name, 0.06, 0.135 + (i*0.05), 0.4, 0.4, 0.0, 1.0, i_white) ENDIF ENDIF ENDREPEAT // draw the edit submenu IF current_sub_menu_selection <> SUB_MENU_HIDDEN DRAW_SUB_MENU(0.135 + (i_current_set_index*0.05)) ENDIF ELSE // show the message to confirm quit DEBUG_DISPLAY_LITERAL_TEXT("Press Cross to confirm quit or Triangle to return", 0.06, 0.5, 0.32, 0.32, 0.0, 0.5, i_white) ENDIF ENDPROC // draw control help PROC DRAW_HELP() SWITCH current_viewer_state CASE STATE_FLYCAM IF IS_BUTTON_PRESSED(DEBUG_PAD, LEFTSHOULDER1) // edit menu DEBUG_DISPLAY_LITERAL_TEXT("R1: move node", 0.06, 0.77, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("R3: set node on ground", 0.06, 0.80, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("L3: convert this and preceding nodes to box", 0.06, 0.83, 0.3, 0.3, 0.0, 1.0, i_white) ELSE DEBUG_DISPLAY_LITERAL_TEXT("R1: create node", 0.06, 0.77, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Triangle: delete node", 0.06, 0.80, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Dpad left/right: change selected node", 0.06, 0.83, 0.3, 0.3, 0.0, 1.0, i_white) IF b_equidistant_drop DEBUG_DISPLAY_LITERAL_TEXT("Select: Disable equidistant drop", 0.06, 0.86, 0.3, 0.3, 0.0, 1.0, i_white) ELSE DEBUG_DISPLAY_LITERAL_TEXT("Select: Enable equidistant drop", 0.06, 0.86, 0.3, 0.3, 0.0, 1.0, i_white) ENDIF DEBUG_DISPLAY_LITERAL_TEXT("Hold L1: edit node functions", 0.06, 0.89, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Start: return to menu", 0.06, 0.92, 0.3, 0.3, 0.0, 1.0, i_white) ENDIF // display state of equidistant drop IF b_equidistant_drop DEBUG_DISPLAY_LITERAL_TEXT("Equidistant drop ON", 0.06, 0.06, 0.3, 0.3, 0.0, 1.0, i_red) ELSE DEBUG_DISPLAY_LITERAL_TEXT("Equidistant drop OFF", 0.06, 0.06, 0.3, 0.3, 0.0, 1.0, i_red) ENDIF BREAK CASE STATE_MENU IF NOT b_show_quit_confirm IF current_sub_menu_selection = SUB_MENU_HIDDEN DEBUG_DISPLAY_LITERAL_TEXT("Square: create new set", 0.06, 0.77, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Cross: select set", 0.06, 0.80, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Dpad up/down: navigate sets", 0.06, 0.83, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Triangle: quit tool", 0.06, 0.86, 0.3, 0.3, 0.0, 1.0, i_white) ELSE DEBUG_DISPLAY_LITERAL_TEXT("Cross: select option", 0.06, 0.77, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Dpad up/down: navigate menu", 0.06, 0.80, 0.3, 0.3, 0.0, 1.0, i_white) DEBUG_DISPLAY_LITERAL_TEXT("Triangle: go back", 0.06, 0.83, 0.3, 0.3, 0.0, 1.0, i_white) ENDIF ENDIF BREAK ENDSWITCH ENDPROC // create widget PROC CREATE_NODES_WIDGET() w_nodes_group = START_WIDGET_GROUP("Node Viewer") ADD_WIDGET_STRING("Current Set") w_set_name = ADD_TEXT_WIDGET("Name") ADD_WIDGET_BOOL("Update Name", b_update_name) ADD_WIDGET_STRING("Current Node") w_node_label = ADD_TEXT_WIDGET("Label") ADD_WIDGET_BOOL("Update Label", b_update_label) ADD_WIDGET_STRING("Other Commands") ADD_WIDGET_BOOL("Use equidistant drop", b_equidistant_drop) ADD_WIDGET_FLOAT_SLIDER("Distance for eq. drop", f_distance_to_travel_for_next_drop, 20, 200, 1) ADD_WIDGET_BOOL("Show Help", b_draw_help) ADD_WIDGET_BOOL("Quit", b_quit_tool) STOP_WIDGET_GROUP() b_do_update_widget = TRUE ENDPROC // update widget PROC UPDATE_NODES_WIDGET() // update with data of current node IF b_do_update_widget IF i_current_node_index >= 0 NODE_STRUCT current_node = GET_NODE_AT_INDEX(i_current_node_index) SET_CONTENTS_OF_TEXT_WIDGET(w_node_label, current_node.tl_label) ELSE SET_CONTENTS_OF_TEXT_WIDGET(w_node_label, "") ENDIF IF i_current_set_index >= 0 SET_CONTENTS_OF_TEXT_WIDGET(w_set_name, node_sets[i_current_set_index].tl_name) ELSE SET_CONTENTS_OF_TEXT_WIDGET(w_set_name, "") ENDIF b_do_update_widget = FALSE ENDIF // change set name from text box IF b_update_name IF i_current_set_index >= 0 SET_SET_NAME(i_current_set_index, GET_CONTENTS_OF_TEXT_WIDGET(w_set_name)) ENDIF b_update_name = FALSE ENDIF // change node label from text box IF b_update_label IF i_current_node_index >= 0 SET_NODE_LABEL_AT_INDEX(i_current_node_index, GET_CONTENTS_OF_TEXT_WIDGET(w_node_label)) ENDIF b_update_label = FALSE ENDIF ENDPROC SCRIPT SET_SCRIPT_AS_NO_LONGER_NEEDED("nodeviewer") CREATE_NODES_WIDGET() REGISTER_SCRIPT_WITH_AUDIO() NODEVIEWER_INIT() INT i REPEAT NUMBER_OF_SETS i NODEVIEWER_LOAD_SET(0, i, node_sets[i], SIZE_OF(NODE_SET_STRUCT)) ENDREPEAT i_current_node_index = -1 INT j REPEAT COUNT_OF(node_sets) j IF node_sets[j].b_open i_current_set_index = j ENDIF ENDREPEAT // player control off IF IS_PLAYER_PLAYING(PLAYER_ID()) SET_PLAYER_CONTROL(PLAYER_ID(), FALSE, SPC_AMBIENT_SCRIPT) DISPLAY_HUD(FALSE) DISPLAY_RADAR(FALSE) ENDIF IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_ENTITY_PROOFS(PLAYER_PED_ID(), TRUE, TRUE, TRUE, TRUE, TRUE) ENDIF // get debug cam debug_cam = GET_DEBUG_CAM() // other cams point_cam = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA") SET_CAM_ACTIVE(point_cam, TRUE) menu_cam = CREATE_CAM("DEFAULT_SCRIPTED_CAMERA") SET_CAM_ACTIVE(menu_cam, TRUE) // debug drawing active SET_DEBUG_LINES_AND_SPHERES_DRAWING_ACTIVE(TRUE) WHILE TRUE // deal with input HANDLE_USER_ACTIONS() IF current_viewer_state = STATE_FLYCAM // get current cam coords v_cam_coords = GET_CAM_COORD(debug_cam) //v_cam_rot = GET_CAM_ROT(debug_cam) //f_cam_fov = GET_CAM_FOV(debug_cam) // update menu cam IF NOT b_set_menu_cam b_set_menu_cam = TRUE ELSE COPY_DEBUG_CAM_TO_MENU_CAM() ENDIF // draw shadow under camera DRAW_SHADOW() // update distance travelled for equidistant dropped UPDATE_EQUIDISTANT_DROP() ENDIF // draw all the nodes in the current set IF i_current_set_index >= 0 DRAW_NODES_GROUP() ENDIF IF current_viewer_state = STATE_MENU // draw menu DRAW_MENU() ENDIF IF b_draw_help DRAW_HELP() ENDIF // update the widget UPDATE_NODES_WIDGET() // quit IF b_quit_tool IF IS_PLAYER_PLAYING(PLAYER_ID()) SET_PLAYER_CONTROL(PLAYER_ID(), TRUE, SPC_AMBIENT_SCRIPT) DISPLAY_HUD(TRUE) DISPLAY_RADAR(TRUE) ENDIF IF NOT IS_PED_INJURED(PLAYER_PED_ID()) SET_ENTITY_PROOFS(PLAYER_PED_ID(), FALSE, FALSE, FALSE, FALSE, FALSE) ENDIF RENDER_SCRIPT_CAMS(FALSE, FALSE) SET_DEBUG_CAM_ACTIVE(FALSE, FALSE) DELETE_WIDGET_GROUP(w_nodes_group) UNREGISTER_SCRIPT_WITH_AUDIO() TERMINATE_THIS_THREAD() ENDIF WAIT(0) ENDWHILE ENDSCRIPT #ENDIF