#using scripts\codescripts\struct; #using scripts\shared\array_shared; #using scripts\shared\flag_shared; #using scripts\shared\flagsys_shared; #using scripts\shared\gameobjects_shared; #using scripts\shared\lui_shared; #using scripts\shared\objpoints_shared; #using scripts\shared\system_shared; #using scripts\shared\trigger_shared; #using scripts\shared\util_shared; #using scripts\shared\callbacks_shared; #using scripts\cp\_util; #precache( "material", "compass_waypoint_target" ); #precache( "material", "compass_waypoint_captureneutral" ); #precache( "material", "compass_waypoint_capture" ); #precache( "material", "compass_waypoint_defend" ); #precache( "material", "compass_waypoint_captureneutral_a" ); #precache( "material", "compass_waypoint_capture_a" ); #precache( "material", "compass_waypoint_defend_a" ); #precache( "material", "compass_waypoint_captureneutral_b" ); #precache( "material", "compass_waypoint_capture_b" ); #precache( "material", "compass_waypoint_defend_b" ); #precache( "material", "compass_waypoint_captureneutral_c" ); #precache( "material", "compass_waypoint_capture_c" ); #precache( "material", "compass_waypoint_defend_c" ); #precache( "material", "waypoint_return" ); #precache( "material", "objective_arrow" ); #precache( "eventstring", "comms_event_message" ); #precache( "string", "CP_SH_CAIRO_PLAYER_READY" ); #precache( "lui_menu_data", "obj_x" ); #precache( "lui_menu_data", "obj_y" ); #namespace objectives; class cObjective { var m_str_type; var m_a_game_obj; var m_a_targets; var m_str_lui_menu; constructor() { } function init( str_type, a_target_list, b_done = false ) { m_a_targets = []; m_a_game_obj = []; m_str_type = str_type; if ( b_done ) { gobj_id = gameobjects::get_next_obj_id(); m_a_game_obj = array( gobj_id ); Objective_Add( gobj_id, "done", (0,0,0), iString(str_type) ); } else { if ( isdefined( a_target_list ) && a_target_list.size > 0 ) { foreach( target in a_target_list ) { add_target( target ); } } else { gobj_id = gameobjects::get_next_obj_id(); m_a_game_obj = array( gobj_id ); Objective_Add( gobj_id, "active", (0,0,0), iString(str_type) ); } } } function update_value( str_menu_data_name, value ) { gobj_id = m_a_game_obj[0]; Objective_SetUIModelValue( gobj_id, str_menu_data_name, value ); } function update_counter( x_val, y_val ) { update_value( "obj_x", x_val ); if ( isdefined( y_val ) ) { update_value( "obj_y", y_val ); } } function add_target( target ) { // do not add a target twice. if ( IsInArray( m_a_targets, target ) ) { return; } gobj_id = undefined; if ( m_a_targets.size < m_a_game_obj.size ) { gobj_id = m_a_game_obj[m_a_game_obj.size-1]; } else { gobj_id = gameobjects::get_next_obj_id(); array::add( m_a_game_obj, gobj_id ); } //Objective_Add can take in an entity or a vector for its 'target' if ( IsVec( target ) || IsEntity( target ) ) { Objective_Add( gobj_id, "active", target, iString(m_str_type) ); } else { Objective_Add( gobj_id, "active", target.origin, iString(m_str_type) ); } array::add( m_a_targets, target ); assert( m_a_targets.size == m_a_game_obj.size ); } function complete( a_target_or_list ) { if ( a_target_or_list.size > 0 ) { // find specific targets to remove their objective foreach ( target in a_target_or_list ) { for ( i = m_a_targets.size - 1; i >= 0; i-- ) { if ( m_a_targets[ i ] == target ) { Objective_State( m_a_game_obj[ i ], "done" ); ArrayRemoveIndex( m_a_game_obj, i ); ArrayRemoveIndex( m_a_targets, i ); break; } } } } else { foreach ( n_gobj_id in m_a_game_obj ) { Objective_State( n_gobj_id, "done" ); } for ( i = m_a_targets.size - 1; i >= 0; i-- ) { ArrayRemoveIndex( m_a_game_obj, i ); ArrayRemoveIndex( m_a_targets, i ); } } if ( m_a_game_obj.size == 0 ) { ArrayRemoveValue( level.a_objectives, self, true ); } } //hide waypoint function hide( e_player ) { if(isdefined( e_player) ) { Assert( IsPlayer( e_player ), "Passed a non-player entity into cObjective::hide()" ); foreach( obj_id in m_a_game_obj ) { Objective_SetInvisibleToPlayer( obj_id, e_player ); } } else { foreach( obj_id in m_a_game_obj ) { Objective_SetInvisibleToAll( obj_id ); } } } //show waypoint function show( e_player ) { if(isdefined( e_player) ) { Assert( IsPlayer( e_player ), "Passed a non-player entity into cObjective::show()" ); foreach( obj_id in m_a_game_obj ) { Objective_SetVisibleToPlayer( obj_id, e_player ); } } else { foreach( obj_id in m_a_game_obj ) { Objective_SetVisibleToAll( obj_id ); } } } function hide_for_target( e_target ) { foreach( i, obj_id in m_a_game_obj ) { ent = m_a_targets[i]; if ( isdefined( ent ) && ent == e_target ) { Objective_State( obj_id, "invisible" ); return; } } } function show_for_target( e_target ) { foreach( i, obj_id in m_a_game_obj ) { ent = m_a_targets[i]; if ( isdefined( ent ) && ent == e_target ) { Objective_State( obj_id, "active" ); return; } } } function get_id_for_target( e_target ) { foreach( i, obj_id in m_a_game_obj ) { ent = m_a_targets[i]; if ( isdefined( ent ) && ent == e_target ) { return obj_id; } } return -1; } function is_breadcrumb() { return false; } } class cBreadcrumbObjective : cObjective { var m_a_player_game_obj; // array of objective ids, one per player var m_str_first_trig_targetname; // the targetname of the first trigger in the breadcrumb sequence var m_done; // at least one of the players has reached the end of their breadcrumb trail constructor() { } function init( str_type, a_target_list, b_done = false ) { // call the parent version cObjective::init( str_type, a_target_list, b_done ); // init some fields m_str_first_trig_targetname = ""; m_done = b_done; // create objectives for max players m_a_player_game_obj = []; for ( i = 0; i < 4; i++ ) { obj_id = gameobjects::get_next_obj_id(); m_a_player_game_obj[i] = obj_id; if ( m_done ) { Objective_Add( obj_id, "done", ( 0, 0, 0 ), iString( m_str_type ) ); } else { Objective_Add( obj_id, "empty", ( 0, 0, 0 ), iString( m_str_type ) ); } } // hide the actual objective, since each player now has their own obj_id = m_a_game_obj[0]; Objective_SetInvisibleToAll( obj_id ); } function complete( a_target_or_list ) { // kill the threads level notify( "breadcrumb_" + m_str_type + "_complete" ); // destroy the objectives for ( i = 0; i < 4; i++ ) { obj_id = m_a_player_game_obj[i]; Objective_State( obj_id, "done" ); } foreach( player in level.players ) { player.v_current_active_breadcrumb = undefined; } // call the parent version cObjective::complete( a_target_or_list ); } function hide( e_player ) { if ( isdefined( e_player ) ) { Assert( IsPlayer( e_player ), "Passed a non-player entity into cBreadcrumbObjective::hide()" ); entnum = e_player GetEntityNumber(); obj_id = m_a_player_game_obj[entnum]; Objective_SetInvisibleToPlayer( obj_id, e_player ); } else { for ( i = 0; i < 4; i++ ) { obj_id = m_a_player_game_obj[i]; Objective_SetInvisibleToPlayerByIndex( obj_id, i ); } } } function show( e_player ) { if ( isdefined( e_player ) ) { Assert( IsPlayer( e_player ), "Passed a non-player entity into cBreadcrumbObjective::hide()" ); entnum = e_player GetEntityNumber(); obj_id = m_a_player_game_obj[entnum]; Objective_SetVisibleToPlayer( obj_id, e_player ); } else { for ( i = 0; i < 4; i++ ) { obj_id = m_a_player_game_obj[i]; Objective_SetVisibleToPlayerByIndex( obj_id, i ); } } } function start( str_trig_targetname ) { // remember the name of the first trigger m_str_first_trig_targetname = str_trig_targetname; m_done = false; // create individual objectives for each player foreach( player in level.players ) { add_player( player ); } } function add_player( player ) { // activate the objective entnum = player GetEntityNumber(); obj_id = m_a_player_game_obj[entnum]; Objective_SetInvisibleToAll( obj_id ); Objective_SetVisibleToPlayer( obj_id, player ); Objective_State( obj_id, "active" ); // spawn a thread to track the player's movement along the breadcrumb trail thread do_player_breadcrumb( player ); } function private set_player_objective( player, target ) { entnum = player GetEntityNumber(); obj_id = m_a_player_game_obj[entnum]; n_breadcrumb_height = 72; v_pos = target; if ( !IsVec( target ) ) { v_pos = target.origin; if ( isdefined( target.script_height ) ) { n_breadcrumb_height = target.script_height; } } v_pos = util::ground_position( v_pos, 300, n_breadcrumb_height ); // cache off the breadcrumb for other systems look up player.v_current_active_breadcrumb = v_pos; Objective_Position( obj_id, v_pos ); Objective_State( obj_id, "active" ); } function do_player_breadcrumb( player ) { level endon( "breadcrumb_" + m_str_type ); level endon( "breadcrumb_" + m_str_type + "_complete" ); player endon( "death" ); str_trig_targetname = m_str_first_trig_targetname; entnum = player GetEntityNumber(); obj_id = m_a_player_game_obj[entnum]; Objective_SetVisibleToPlayer( obj_id, player ); do { t_current = GetEnt( str_trig_targetname, "targetname" ); if ( isdefined( t_current ) ) { if ( isdefined( t_current.target ) ) { if ( isdefined( t_current.script_flag_true ) ) { Objective_SetInvisibleToPlayer( obj_id, player ); level flag::wait_till( t_current.script_flag_true ); Objective_SetVisibleToPlayer( obj_id, player ); } s_current = struct::get( t_current.target, "targetname" ); if ( isdefined( s_current ) ) { set_player_objective( player, s_current ); } else { set_player_objective( player, t_current ); } } else { set_player_objective( player, t_current ); } str_trig_targetname = t_current.target; //assert( !trigger::is_trigger_once( t_current ), "Trigger at " + t_current.origin + " in breadcrumb chain '" + m_str_first_trig_targetname + "' should not be set to TRIGGER_ONCE." ); t_current trigger::wait_till( undefined, undefined, player ); } else { str_trig_targetname = undefined; } } while ( isdefined( str_trig_targetname ) ); Objective_SetInvisibleToPlayer( obj_id, player ); foreach( player in level.players ) { player.v_current_active_breadcrumb = undefined; } // done m_done = true; } function is_breadcrumb() { return true; } function is_done() { // we're done if at least one of the players has made it to the final breadcrumb return m_done; } } function autoexec __init__sytem__() { system::register("objectives",&__init__,undefined,undefined); } function __init__() { level.a_objectives = []; // Declares an array of objectives to hold the objective strings. level.n_obj_index = 0; // This is the objective number associated with the objective strings. callback::on_spawned( &on_player_spawned ); } /@ "Name: set( , , )" "Summary: Used for all objective-related tasks." "CallOn: NA" "Example: objectives::set( "cp_level_lotus_hakim", level.ai_hakim );" "SPMP: singleplayer" @/ function set( str_obj_type, a_target_or_list, b_breadcrumb ) { if(!isdefined(level.a_objectives))level.a_objectives=[]; if(!isdefined(b_breadcrumb))b_breadcrumb=false; // Make an array out if it, if it's only one objective. if ( !isdefined( a_target_or_list ) ) a_target_or_list = []; else if ( !IsArray( a_target_or_list ) ) a_target_or_list = array( a_target_or_list );; o_objective = undefined; if ( isdefined( level.a_objectives[str_obj_type] ) ) { // TODO Slone: Clear old targets here? o_objective = level.a_objectives[str_obj_type]; if ( isdefined( a_target_or_list ) ) { foreach( target in a_target_or_list ) { [[o_objective]]->add_target( target ); } } } else { if ( b_breadcrumb ) { o_objective = new cBreadcrumbObjective(); } else { o_objective = new cObjective(); } [[o_objective]]->init( str_obj_type, a_target_or_list ); level.a_objectives[ str_obj_type ] = o_objective; } return o_objective; } // Mark just one of many targets for this objective as complete. // // str_obj_type: the objective string ID we'd like to remove. // a_target_or_list: the object from which we'd like to remove the marker. // /@ "Name: complete( , )" "Summary: Mark specific targets for this objective as complete." "CallOn: NA" "MandatoryArg: The objective string ID we'd like to remove." "OptionalArg: The target or targets from which we'd like to remove the marker." "Example: objectives::complete( "cp_level_lotus_minigun", self );" "SPMP: singleplayer" @/ function complete( str_obj_type, a_target_or_list ) { // Make an array out if it, if it's only one objective. if ( !isdefined( a_target_or_list ) ) a_target_or_list = []; else if ( !IsArray( a_target_or_list ) ) a_target_or_list = array( a_target_or_list );; if ( isdefined( level.a_objectives[str_obj_type] ) ) { o_objective = level.a_objectives[str_obj_type]; [[o_objective]]->complete( a_target_or_list ); } else { if ( str_obj_type == "cp_waypoint_breadcrumb" ) { o_objective = new cBreadcrumbObjective(); } else { o_objective = new cObjective(); } [[o_objective]]->init( str_obj_type, undefined, true ); level.a_objectives[ str_obj_type ] = o_objective; } } /@ "Name: set( , )" "Summary: Set the objective and automatically set the counter to [0 of a_targets.size]" "CallOn: NA" "Example: objectives::set( "objective_kill_targets", a_targets );" "SPMP: singleplayer" @/ function set_with_counter( str_obj_id, a_targets ) { if ( !isdefined( a_targets ) ) a_targets = []; else if ( !IsArray( a_targets ) ) a_targets = array( a_targets );; o_obj = set( str_obj_id, a_targets ); [[o_obj]]->update_counter( 0, a_targets.size ); } /@ "Name: update_counter( , , )" "Summary: Set the values on an objective with a counter." "CallOn: NA" "Example: objectives::update_counter( "objective_kill_targets", 2, a_targets.size );" "SPMP: singleplayer" @/ function update_counter( str_obj_id, x_val, y_val ) { o_obj = level.a_objectives[ str_obj_id ]; if ( isdefined( o_obj ) ) { [[o_obj]]->update_counter( x_val, y_val ); } } /@ "Name: set_value( , , )" "Summary: Set the LUI model values on an objective." "CallOn: NA" "Example: objectives::set_value( "objective_kill_targets", "num_targets", a_targets.size );" "SPMP: singleplayer" @/ function set_value( str_obj_id, str_menu_data_name, value ) { o_obj = level.a_objectives[ str_obj_id ]; if ( isdefined( o_obj ) ) { [[o_obj]]->update_value( str_menu_data_name, value ); } } /@ "Name: breadcrumb( , [str_obj_id] )" "Summary: Automatically advances a chain of triggered objective structs." "Module: Objectives" "CallOn: Level" "MandatoryArg: The first trigger in the string of breadcrumbs." "OptionalArg: [str_obj_id] The objective string ID we'd like to hide the marker and menu entry of. Default behavior hides for ALL players." "Example: objectives::breadcrumb( "trig_breadcrumb" );" "SPMP: singleplayer" @/ function breadcrumb( str_trig_targetname, str_obj_id = "cp_waypoint_breadcrumb", b_complete_on_first_player_finish = true ) { level notify( "breadcrumb_" + str_obj_id ); level endon( "breadcrumb_" + str_obj_id ); if ( isdefined( level.a_objectives[ str_obj_id ] ) ) { complete( str_obj_id ); } o_objective = set( str_obj_id, undefined, true ); [[o_objective]]->start( str_trig_targetname ); while ( ![[o_objective]]->is_done() ) { wait 0.05; } if ( b_complete_on_first_player_finish ) { complete( str_obj_id ); } } /@ "Name: hide( , )" "Summary: Hide the objective marker and menu entry for an objective." "CallOn: NA" "MandatoryArg: The objective string ID we'd like to hide the marker and menu entry of. Default behavior hides for ALL players" "OptionalArg: The specific player you would like to hide the objective waypoint from." "Example: objectives::hide( "objective_to_do_things", e_player_2 );" "SPMP: singleplayer" @/ function hide( str_obj_type, e_player ) { if ( isdefined( level.a_objectives[str_obj_type] ) ) { o_objective = level.a_objectives[str_obj_type]; [[o_objective]]->hide( e_player ); } else { Assert( false, "Attempting to hide a marker on an objective that does not exist." ); } } /@ "Name: hide_for_target( , )" "Summary: Hide the objective marker for a specific target." "CallOn: NA" "MandatoryArg: The objective string ID we'd like to hide the marker." "MandatoryArg: The target for which you want to hide the objective marker." "Example: objectives::hide_for_target( "tank_marker", vh_tank_3 );" "SPMP: singleplayer" @/ function hide_for_target( str_obj_type, e_target ) { if ( isdefined( level.a_objectives[str_obj_type] ) ) { o_objective = level.a_objectives[str_obj_type]; [[o_objective]]->hide_for_target( e_target ); } else { Assert( false, "Attempting to hide a marker on an objective that does not exist." ); } } /@ "Name: show( , )" "Summary: Show the objective marker and menu entry for an objective." "CallOn: NA" "MandatoryArg: The objective string ID we'd like to show the marker and menu entry of. Default behavior shows for ALL players" "OptionalArg: The specific player you would like to show the objective waypoint to." "Example: objectives::show( "objective_to_do_things", e_player_2 );" "SPMP: singleplayer" @/ function show( str_obj_type, e_player ) { if ( isdefined( level.a_objectives[str_obj_type] ) ) { o_objective = level.a_objectives[str_obj_type]; [[o_objective]]->show( e_player ); } else { Assert( false, "Attempting to show a marker on an objective that does not exist." ); } } /@ "Name: show_for_target( , )" "Summary: Show the objective marker for a specific target." "CallOn: NA" "MandatoryArg: The objective string ID we'd like to show the marker." "MandatoryArg: The target for which you want to show the objective marker." "Example: objectives::show_for_target( "tank_marker", vh_tank_3 );" "SPMP: singleplayer" @/ function show_for_target( str_obj_type, e_target ) { if ( isdefined( level.a_objectives[str_obj_type] ) ) { o_objective = level.a_objectives[str_obj_type]; [[o_objective]]->show_for_target( e_target ); } else { Assert( false, "Attempting to hide a marker on an objective that does not exist." ); } } /@ "Name: get_id_for_target( , )" "Summary: Get objective ID for a specific target." "CallOn: NA" "MandatoryArg: The objective string ID." "MandatoryArg: The target for which you want the ID." "Example: id = objectives::get_id_for_target( "tank_marker", vh_tank_3 );" "SPMP: singleplayer" @/ function get_id_for_target( str_obj_type, e_target ) { id = -1; if ( isdefined( level.a_objectives[str_obj_type] ) ) { o_objective = level.a_objectives[str_obj_type]; id = [[o_objective]]->get_id_for_target( e_target ); } if ( id < 0 ) { Assert( false, "get_id_for_target called for an objective that does not exist." ); } return id; } /@ "Name: event_message( )" "Summary: Show an event message on the HUD." "MandatoryArg: The localized string to show." "Example: objectives::event_message( "Kill the quadtank" );" @/ function event_message( istr_message ) { foreach ( player in level.players ) { util::show_event_message( player, istring( istr_message ) ); } } //str_obj_type - the icon type ( target, capture, defend, defend_b, etc ) //str_obj_name - a unique identifier for this icon. Creating a new icon with a name already in use, will destroy/override the previous icon //v_pos - the position the icon will be placed function create_temp_icon( str_obj_type, str_obj_name, v_pos, v_offset=(0,0,0) ) { switch( str_obj_type ) { case "target": str_shader = "waypoint_targetneutral"; break; case "capture": str_shader = "waypoint_capture"; break; case "capture_a": str_shader = "waypoint_capture_a"; break; case "capture_b": str_shader = "waypoint_capture_b"; break; case "capture_c": str_shader = "waypoint_capture_c"; break; case "defend": str_shader = "waypoint_defend"; break; case "defend_a": str_shader = "waypoint_defend_a"; break; case "defend_b": str_shader = "waypoint_defend_b"; break; case "defend_c": str_shader = "waypoint_defend_c"; break; case "return": str_shader = "waypoint_return"; break; default: AssertMsg( "Type '" + str_obj_type + "' not supported. Please see create_temp_icon() in _objectives.gsc for supported types." ); break; } nextObjPoint = objpoints::create( str_obj_name, v_pos + v_offset, "all", str_shader ); nextObjPoint setWayPoint( true, str_shader ); return nextObjPoint; } function destroy_temp_icon() { objpoints::delete( self ); } function private on_player_spawned() // self = player { // find any active breadcrumbs, and initialize them on this player if ( isdefined( level.a_objectives ) ) { foreach( o_objective in level.a_objectives ) { if ( [[o_objective]]->is_breadcrumb() && ![[o_objective]]->is_done() ) { [[o_objective]]->add_player( self ); } } } }