Пример #1
0
// called from the game loop to check if we should actually do the red-alert
void red_alert_maybe_move_to_next_mission()
{
	// if the timestamp is invalid, do nothing.
	if ( !timestamp_valid(Red_alert_new_mission_timestamp) )
		return;

	// return if the timestamp hasn't elapsed yet
	if ( !timestamp_elapsed(Red_alert_new_mission_timestamp) )
		return;

	// basic premise here is to stop the current mission, and then set the next mission in the campaign
	// which better be a red alert mission
	if ( Game_mode & GM_CAMPAIGN_MODE ) {
		red_alert_store_wingman_status();
		mission_goal_fail_incomplete();
		mission_campaign_store_goals_and_events_and_variables();
		scoring_level_close();
		mission_campaign_eval_next_mission();
		mission_campaign_mission_over();

		// CD CHECK
		gameseq_post_event(GS_EVENT_START_GAME);
	} else {
		gameseq_post_event(GS_EVENT_END_GAME);
	}
}
Пример #2
0
// ----------------------------------------------------------------------------
// update_reduced_damp_timestamp()
//
void update_reduced_damp_timestamp( physics_info *pi, float impulse )
{

	// Compute duration of reduced damp from present
	// Compare with current value and increase if greater, otherwise ignore
	int reduced_damp_decay_time;
	reduced_damp_decay_time = (int) (REDUCED_DAMP_TIME * impulse / (REDUCED_DAMP_VEL * pi->mass));
	if ( reduced_damp_decay_time > REDUCED_DAMP_TIME )
		reduced_damp_decay_time = REDUCED_DAMP_TIME;

	// Reset timestamp if larger than current (if any)
	if ( timestamp_valid( pi->reduced_damp_decay ) ) {
		int time_left = timestamp_until( pi->reduced_damp_decay );
		if ( time_left > 0 ) {
			// increment old time, but apply cap
			int new_time = reduced_damp_decay_time + time_left;
			if ( new_time < REDUCED_DAMP_TIME ) {
				pi->reduced_damp_decay = timestamp( new_time );
			}
		} else {
			pi->reduced_damp_decay = timestamp( reduced_damp_decay_time );
		}
	} else {
		// set if not valid
		pi->reduced_damp_decay = timestamp( reduced_damp_decay_time );
	}

}
Пример #3
0
/**
 * Render debris
 */
void debris_render(object * obj)
{
	int			i, num, swapped;
	polymodel	*pm;
	debris		*db;


	swapped = -1;
	pm = NULL;	
	num = obj->instance;

	Assert(num >= 0 && num < MAX_DEBRIS_PIECES);
	db = &Debris[num];

	Assert(db->flags & DEBRIS_USED);

	texture_info *tbase = NULL;
	
	model_clear_instance( db->model_num );
	
	// Swap in a different texture depending on the species
	if (db->species >= 0)
	{
		pm = model_get( db->model_num );

		//WMC - Someday, we should have glowing debris.
		if ( pm != NULL && (pm->n_textures == 1) ) {
			tbase = &pm->maps[0].textures[TM_BASE_TYPE];
			swapped = tbase->GetTexture();
			tbase->SetTexture(Species_info[db->species].debris_texture.bitmap_id);
		}
	}

	// Only render electrical arcs if within 500m of the eye (for a 10m piece)
	if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f )	{
		for (i=0; i<MAX_DEBRIS_ARCS; i++ )	{
			if ( timestamp_valid( db->arc_timestamp[i] ) )	{
				model_add_arc( db->model_num, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_NORMAL );
			}
		}
	}

	if ( db->is_hull )	{
		MONITOR_INC(NumHullDebrisRend,1);
		submodel_render( db->model_num, db->submodel_num, &obj->orient, &obj->pos );
	} else {
		MONITOR_INC(NumSmallDebrisRend,1);
		submodel_render( db->model_num, db->submodel_num, &obj->orient, &obj->pos, MR_NO_LIGHTING );
	}

	if (tbase != NULL && (swapped!=-1) && pm)	{
		tbase->SetTexture(swapped);
	}
}
Пример #4
0
/**
 * Do various updates to debris:  check if time to die, start fireballs
 * Maybe delete debris if it's very far away from player.
 *
 * @param obj			pointer to debris object
 * @param frame_time	time elapsed since last debris_move() called
 */
void debris_process_post(object * obj, float frame_time)
{
	int i, num;
	num = obj->instance;

	int objnum = OBJ_INDEX(obj);
	Assert( Debris[num].objnum == objnum );
	debris *db = &Debris[num];

	if ( db->is_hull ) {
		MONITOR_INC(NumHullDebris,1);
		radar_plot_object( obj );

		if ( timestamp_elapsed(db->sound_delay) ) {
			obj_snd_assign(objnum, SND_DEBRIS, &vmd_zero_vector, 0);
			db->sound_delay = 0;
		}
	} else {
		MONITOR_INC(NumSmallDebris,1);
	}

	if ( db->lifeleft >= 0.0f) {
		db->lifeleft -= frame_time;
		if ( db->lifeleft < 0.0f )	{
			debris_start_death_roll(obj, db);
		}
	}

	maybe_delete_debris(db);	//	Make this debris go away if it's very far away.

	// ================== DO THE ELECTRIC ARCING STUFF =====================
	if ( db->arc_frequency <= 0 )	{
		return;			// If arc_frequency <= 0, this piece has no arcs on it
	}

	if ( !timestamp_elapsed(db->fire_timeout) && timestamp_elapsed(db->next_fireball))	{		

		db->next_fireball = timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
		db->arc_frequency += 100;	

		if (db->is_hull)	{

			int n, n_arcs = ((rand()>>5) % 3)+1;		// Create 1-3 sparks

			vec3d v1, v2, v3, v4;

			if ( Cmdline_old_collision_sys ) {
				submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 );
				submodel_get_two_random_points( db->model_num, db->submodel_num, &v3, &v4 );
			} else {
				submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 );
				submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v3, &v4 );
			}

			n = 0;

			int a = 100, b = 1000;
			int lifetime = (myrand()%((b)-(a)+1))+(a);

			// Create the spark effects
			for (i=0; i<MAX_DEBRIS_ARCS; i++ )	{
				if ( !timestamp_valid( db->arc_timestamp[i] ) )	{

					db->arc_timestamp[i] = timestamp(lifetime);	// live up to a second

					switch( n )	{
					case 0:
						db->arc_pts[i][0] = v1;
						db->arc_pts[i][1] = v2;
						break;
					case 1:
						db->arc_pts[i][0] = v2;
						db->arc_pts[i][1] = v3;
						break;

					case 2:
						db->arc_pts[i][0] = v2;
						db->arc_pts[i][1] = v4;
						break;

					default:
						Int3();
					}
						
					n++;
					if ( n == n_arcs )
						break;	// Don't need to create anymore
				}
			}

	
			// rotate v2 out of local coordinates into world.
			// Use v2 since it is used in every bolt.  See above switch().
			vec3d snd_pos;
			vm_vec_unrotate(&snd_pos, &v2, &obj->orient);
			vm_vec_add2(&snd_pos, &obj->pos );

			//Play a sound effect
			if ( lifetime > 750 )	{
				// 1.00 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  500 )	{
				// 0.75 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  250 )	{
				// 0.50 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  100 )	{
				// 0.25 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
			} else {
				// 0.10 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
			}
		}
Пример #5
0
// called from HUD code to see if we're red-alerting
int red_alert_in_progress()
{
	// it is specifically a question of whether the timestamp is running
	return timestamp_valid(Red_alert_new_mission_timestamp);
}
// function which evaluates and processes the given event
void mission_process_event( int event )
{
	int store_flags = Mission_events[event].flags;
	int store_formula = Mission_events[event].formula;
	int store_result = Mission_events[event].result;
	int store_count = Mission_events[event].count;

	int result, sindex;
	bool bump_timestamp = false; 
	Log_event = false;

	Directive_count = 0;
	Event_index = event;
	sindex = Mission_events[event].formula;
	result = Mission_events[event].result;

	// if chained, insure that previous event is true and next event is false
	if (Mission_events[event].chain_delay >= 0) {  // this indicates it's chained
		// What everyone expected the chaining behavior to be, as specified in Karajorma's original fix to Mantis #82
		if (Alternate_chaining_behavior) {
			if (event > 0){
				if (!Mission_events[event - 1].result || ((fix) Mission_events[event - 1].satisfied_time + i2f(Mission_events[event].chain_delay) > Missiontime)){
					sindex = -1;  // bypass evaluation
				}
			}
		}
		// Volition's original chaining behavior as used in retail and demonstrated in e.g. btm-01.fsm (or btm-01.fs2 in the Port)
		else {
			if (event > 0){
				if (!Mission_events[event - 1].result || ((fix) Mission_events[event - 1].timestamp + i2f(Mission_events[event].chain_delay) > Missiontime)){
					sindex = -1;  // bypass evaluation
				}
			}

			if ((event < Num_mission_events - 1) && Mission_events[event + 1].result && (Mission_events[event + 1].chain_delay >= 0)){
				sindex = -1;  // bypass evaluation
			}
		}
	}

	if (sindex >= 0) {
		Sexp_useful_number = 1;
		if (Snapshot_all_events || Mission_events[event].mission_log_flags != 0) {
			Log_event = true;
			
			Current_event_log_buffer = &Mission_events[event].event_log_buffer;
			Current_event_log_variable_buffer = &Mission_events[event].event_log_variable_buffer;
			Current_event_log_argument_buffer = &Mission_events[event].event_log_argument_buffer;
		}
		result = eval_sexp(sindex);

		// if the directive count is a special value, deal with that first.  Mark the event as a special
		// event, and unmark it when the directive is true again.
		if ( (Directive_count == DIRECTIVE_WING_ZERO) && !(Mission_events[event].flags & MEF_DIRECTIVE_SPECIAL) ) {			
			// make it special - which basically just means that its true until the next wave arrives
			mission_event_set_directive_special(event);

			Directive_count = 0;
		} else if ( (Mission_events[event].flags & MEF_DIRECTIVE_SPECIAL) && Directive_count > 1 ) {			
			// make it non special
			mission_event_unset_directive_special(event);
		}

		if (Mission_events[event].count || (Directive_count > 1)){
			Mission_events[event].count = Directive_count;
		}

		if (Sexp_useful_number){
			Mission_events[event].flags |= MEF_CURRENT;
		}

		if ((Mission_events[event].mission_log_flags != 0) || Snapshot_all_events){
			maybe_write_to_event_log(result);
		}
	}

	Log_event = false;

	Event_index = -1;
	Mission_events[event].result = result;

	// if the sexpression is known false, then no need to evaluate anymore
	if ((sindex >= 0) && (Sexp_nodes[sindex].value == SEXP_KNOWN_FALSE)) {
		Mission_events[event].timestamp = (int) Missiontime;
		Mission_events[event].satisfied_time = Missiontime;
		// _argv[-1] - repeat_count of -1 would mean repeat indefinitely, so set to 0 instead.
		Mission_events[event].repeat_count = 0;
		Mission_events[event].formula = -1;
		return;
	}

	if (result && !Mission_events[event].satisfied_time) {
		Mission_events[event].satisfied_time = Missiontime;
		if ( Mission_events[event].objective_text ) {
			Mission_directive_sound_timestamp = timestamp(DIRECTIVE_SOUND_DELAY);
		}
	}

	// decrement the trigger count.  When at 0, set the repeat count to 0 so we don't eval this function anymore
	if (result && (Mission_events[event].trigger_count != 0) && (Mission_events[event].flags & MEF_USING_TRIGGER_COUNT) ) {
		if (Mission_events[event].trigger_count > 0)
			Mission_events[event].trigger_count--;
		if (Mission_events[event].trigger_count == 0) {
			 Mission_events[event].repeat_count = 0;
		}
		else {
			bump_timestamp = true;
		}
	}

	// decrement the repeat count.  When at 0, don't eval this function anymore
	if ( result || timestamp_valid(Mission_events[event].timestamp) ) {
		// _argv[-1] - negative repeat count means repeat indefinitely.
		if ( Mission_events[event].repeat_count > 0 )
			Mission_events[event].repeat_count--;
		if ( Mission_events[event].repeat_count == 0 ) {
			Mission_events[event].timestamp = (int)Missiontime;
			Mission_events[event].formula = -1;

			if(Game_mode & GM_MULTIPLAYER){
				// multiplayer missions (scoring is scaled in the multi_team_maybe_add_score() function)
				multi_team_maybe_add_score(Mission_events[event].score, Mission_events[event].team);
				multi_player_maybe_add_score(Mission_events[event].score, Mission_events[event].team);
			} else {
				// deal with the player's score
				Player->stats.m_score += (int)(Mission_events[event].score * scoring_get_scale_factor());			
			}
		}
		// Set the timestamp for the next check on this event unless we only have a trigger count and no repeat count and 
		// this event didn't trigger this frame. 
		else if (bump_timestamp || (!((Mission_events[event].repeat_count == -1) && (Mission_events[event].flags & MEF_USING_TRIGGER_COUNT) && (Mission_events[event].trigger_count != 0)))) {
			// set the timestamp to time out 'interval' seconds in the future.  
			Mission_events[event].timestamp = timestamp( Mission_events[event].interval * 1000 );
		}
	}

	// see if anything has changed	
	if(MULTIPLAYER_MASTER && ((store_flags != Mission_events[event].flags) || (store_formula != Mission_events[event].formula) || (store_result != Mission_events[event].result) || (store_count != Mission_events[event].count)) ){
		send_event_update_packet(event);
	}
}
void mission_eval_goals()
{
	int i, result;

	// before checking whether or not we should evaluate goals, we should run through the events and
	// process any whose timestamp is valid and has expired.  This would catch repeating events only
	for (i=0; i<Num_mission_events; i++) {
		if (Mission_events[i].formula != -1) {
			if ( !timestamp_valid(Mission_events[i].timestamp) || !timestamp_elapsed(Mission_events[i].timestamp) ){
				continue;
			}

			// if we get here, then the timestamp on the event has popped -- we should reevaluate
			PROFILE("Repeating events", mission_process_event(i));
		}
	}
	
	if ( !timestamp_elapsed(Mission_goal_timestamp) ){
		return;
	}

	// first evaluate the players goals
	for (i=0; i<Num_goals; i++) {
		// don't evaluate invalid goals
		if (Mission_goals[i].type & INVALID_GOAL){
			continue;
		}

		if (Mission_goals[i].satisfied == GOAL_INCOMPLETE) {
			result = eval_sexp(Mission_goals[i].formula);
			if ( Sexp_nodes[Mission_goals[i].formula].value == SEXP_KNOWN_FALSE ) {
				mission_goal_status_change( i, GOAL_FAILED );

			} else if (result) {
				mission_goal_status_change(i, GOAL_COMPLETE );
			} // end if result

		}	// end if goals[i].satsified != GOAL_COMPLETE
	} // end for

	// now evaluate any mission events
	for (i=0; i<Num_mission_events; i++) {
		if ( Mission_events[i].formula != -1 ) {
			// only evaluate this event if the timestamp is not valid.  We do this since
			// we will evaluate repeatable events at the top of the file so we can get
			// the exact interval that the designer asked for.
			if ( !timestamp_valid( Mission_events[i].timestamp) ){
				PROFILE("Nonrepeating events", mission_process_event( i ));
			}
		}
	}

	// send and remaining sexp data to the clients
	if (MULTIPLAYER_MASTER) {
		multi_sexp_flush_packet();
	}

	if (The_mission.game_type & MISSION_TYPE_TRAINING){
		Mission_goal_timestamp = timestamp(GOAL_TIMESTAMP_TRAINING);
	} else {
		Mission_goal_timestamp = timestamp(GOAL_TIMESTAMP);
	}

	if ( !hud_disabled() && hud_gauge_active(HUD_DIRECTIVES_VIEW) ) {
		mission_maybe_play_directive_success_sound();
	}

   // update goal status if playing on a multiplayer standalone server
	if (Game_mode & GM_STANDALONE_SERVER){
		std_multi_update_goals();
	}
	
	Snapshot_all_events = false;
}
Пример #8
0
void mission_eval_goals()
{
	int i, result, goal_changed = 0;

	// before checking whether or not we should evaluate goals, we should run through the events and
	// process any whose timestamp is valid and has expired.  This would catch repeating events only
	for (i=0; i<Num_mission_events; i++) {
		if (Mission_events[i].formula != -1) {
			if ( !timestamp_valid(Mission_events[i].timestamp) || !timestamp_elapsed(Mission_events[i].timestamp) ){
				continue;
			}

			// if we get here, then the timestamp on the event has popped -- we should reevaluate
			mission_process_event(i);
		}
	}
	
	if ( !timestamp_elapsed(Mission_goal_timestamp) ){
		return;
	}

	// first evaluate the players goals
	for (i=0; i<Num_goals; i++) {
		// don't evaluate invalid goals
		if (Mission_goals[i].type & INVALID_GOAL){
			continue;
		}

		if (Mission_goals[i].satisfied == GOAL_INCOMPLETE) {
			result = eval_sexp(Mission_goals[i].formula);
			if ( Sexp_nodes[Mission_goals[i].formula].value == SEXP_KNOWN_FALSE ) {
				goal_changed = 1;
				mission_goal_status_change( i, GOAL_FAILED );

			} else if (result) {
				goal_changed = 1;
				mission_goal_status_change(i, GOAL_COMPLETE );
			} // end if result
			
			// tell the player how to end the mission
			//if ( goal_changed && mission_evaluate_primary_goals() != PRIMARY_GOALS_INCOMPLETE ) {
			//	HUD_sourced_printf(HUD_SOURCE_IMPORTANT, "Press %s to end mission and return to base", textify_scancode(Control_config[END_MISSION].key_id) );
			//}
		}	// end if goals[i].satsified != GOAL_COMPLETE
	} // end for

	// now evaluate any mission events
	for (i=0; i<Num_mission_events; i++) {
		if ( Mission_events[i].formula != -1 ) {
			// only evaluate this event if the timestamp is not valid.  We do this since
			// we will evaluate repeatable events at the top of the file so we can get
			// the exact interval that the designer asked for.
			if ( !timestamp_valid( Mission_events[i].timestamp) ){
				mission_process_event( i );
			}
		}
	}

	if (The_mission.game_type & MISSION_TYPE_TRAINING){
		Mission_goal_timestamp = timestamp(GOAL_TIMESTAMP_TRAINING);
	} else {
		Mission_goal_timestamp = timestamp(GOAL_TIMESTAMP);
	}

	if ( !hud_disabled() && hud_gauge_active(HUD_DIRECTIVES_VIEW) ) {
		mission_maybe_play_directive_success_sound();
	}

   // update goal status if playing on a multiplayer standalone server
	if (Game_mode & GM_STANDALONE_SERVER){
		std_multi_update_goals();
	}
}
Пример #9
0
// function which evaluates and processes the given event
void mission_process_event( int event )
{
	int store_flags = Mission_events[event].flags;
	int store_formula = Mission_events[event].formula;
	int store_result = Mission_events[event].result;
	int store_count = Mission_events[event].count;

	int result, sindex;

	Directive_count = 0;
	Event_index = event;
	sindex = Mission_events[event].formula;
	result = Mission_events[event].result;

	// if chained, insure that previous event is true and next event is false
	if (Mission_events[event].chain_delay >= 0) {  // this indicates it's chained
		if (event > 0){
			if (!Mission_events[event - 1].result || ((fix) Mission_events[event - 1].timestamp + i2f(Mission_events[event].chain_delay) > Missiontime)){
				sindex = -1;  // bypass evaluation
			}
		}

		if ((event < Num_mission_events - 1) && Mission_events[event + 1].result && (Mission_events[event + 1].chain_delay >= 0)){
			sindex = -1;  // bypass evaluation
		}
	}

	if (sindex >= 0) {
		Sexp_useful_number = 1;
		result = eval_sexp(sindex);

		// if the directive count is a special value, deal with that first.  Mark the event as a special
		// event, and unmark it when the directive is true again.
		if ( (Directive_count == DIRECTIVE_WING_ZERO) && !(Mission_events[event].flags & MEF_DIRECTIVE_SPECIAL) ) {			
			// make it special - which basically just means that its true until the next wave arrives
			mission_event_set_directive_special(event);

			Directive_count = 0;
		} else if ( (Mission_events[event].flags & MEF_DIRECTIVE_SPECIAL) && Directive_count > 1 ) {			
			// make it non special
			mission_event_unset_directive_special(event);
		}

		if (Mission_events[event].count || (Directive_count > 1)){
			Mission_events[event].count = Directive_count;
		}

		if (Sexp_useful_number){
			Mission_events[event].flags |= MEF_CURRENT;
		}
	}

	Event_index = 0;
	Mission_events[event].result = result;

	// if the sexpression is known false, then no need to evaluate anymore
	if ((sindex >= 0) && (Sexp_nodes[sindex].value == SEXP_KNOWN_FALSE)) {
		Mission_events[event].timestamp = (int) Missiontime;
		Mission_events[event].satisfied_time = Missiontime;
		Mission_events[event].repeat_count = -1;
		Mission_events[event].formula = -1;
		return;
	}

	if (result && !Mission_events[event].satisfied_time) {
		Mission_events[event].satisfied_time = Missiontime;
		if ( Mission_events[event].objective_text ) {
			Mission_directive_sound_timestamp = timestamp(DIRECTIVE_SOUND_DELAY);
		}
	}

	// decrement the repeat count.  When at 0, don't eval this function anymore
	if ( result || timestamp_valid(Mission_events[event].timestamp) ) {
		Mission_events[event].repeat_count--;
		if ( Mission_events[event].repeat_count <= 0 ) {
			Mission_events[event].timestamp = (int)Missiontime;
			Mission_events[event].formula = -1;

			if(Game_mode & GM_MULTIPLAYER){
				// squad war
				multi_team_maybe_add_score((int)(Mission_events[event].score * scoring_get_scale_factor()), Mission_events[event].team);
			} else {
				// deal with the player's score
				Player->stats.m_score += (int)(Mission_events[event].score * scoring_get_scale_factor());			
			}
		} else {
			// set the timestamp to time out 'interval' seconds in the future.  We must also reset the
			// value at the sexpresion node to unknown so that it will get reevaled
			Mission_events[event].timestamp = timestamp( Mission_events[event].interval * 1000 );
//			Sexp_nodes[Mission_events[event].formula].value = SEXP_UNKNOWN;
		}
	}

	// see if anything has changed	
	if(MULTIPLAYER_MASTER && ((store_flags != Mission_events[event].flags) || (store_formula != Mission_events[event].formula) || (store_result != Mission_events[event].result) || (store_count != Mission_events[event].count)) ){
		send_event_update_packet(event);
	}	
}