void particle_move_all(float frametime)
{
	MONITOR_INC( NumParticles, Num_particles );	

	if ( !Particles_enabled )
		return;

	if ( Particles.empty() )
		return;

	for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); )
	{	
		particle* part = *p;
		if (part->age == 0.0f) {
			part->age = 0.00001f;
		} else {
			part->age += frametime;
		}

		bool remove_particle = false;

		// if its time expired, remove it
		if (part->age > part->max_life) {
			// special case, if max_life is 0 then we want it to render at least once
			if ( (part->age > frametime) || (part->max_life > 0.0f) ) {
				remove_particle = true;
			}
		}

		// if the particle is attached to an object which has become invalid, kill it
		if (part->attached_objnum >= 0) {
			// if the signature has changed, or it's bogus, kill it
			if ( (part->attached_objnum >= MAX_OBJECTS) || (part->attached_sig != Objects[part->attached_objnum].signature) ) {
				remove_particle = true;
			}
		}

		if (remove_particle)
		{
			part->signature = 0;
			delete part;

			// if we're sitting on the very last particle, popping-back will invalidate the iterator!
			if (p + 1 == Particles.end())
			{
				Particles.pop_back();
				break;
			}
			else
			{
				*p = Particles.back();
				Particles.pop_back();
				continue;
			}
		}

		// move as a regular particle
		vm_vec_scale_add2( &part->pos, &part->velocity, frametime );

		// next particle
		++p;
	}
}
Example #2
0
void credits_init()
{
	int i;
	credits_screen_buttons *b;

	// pre-initialize
	Credits_num_images = DEFAULT_NUM_IMAGES;
	Credits_artwork_index = -1;

	// this is moved up here so we can override it if desired
	strcpy_s(Credits_music_name, "Cinema");

	// parse credits early so as to set up any overrides (for music and such)
	Credits_parsed = false;
	credits_parse();

	// we could conceivably have specified a number of images but not an index,
	// so if that's the case, set the value here
	if (Credits_artwork_index < 0) {
		Credits_artwork_index = rand() % Credits_num_images;
	}

	int credits_spooled_music_index = event_music_get_spooled_music_index(Credits_music_name);	
	if(credits_spooled_music_index != -1){
		char *credits_wavfile_name = Spooled_music[credits_spooled_music_index].filename;		
		if(credits_wavfile_name != NULL){
			credits_load_music(credits_wavfile_name);
		}
	}

	// Use this id to trigger the start of music playing on the briefing screen
	Credits_music_begin_timestamp = timestamp(Credits_music_delay);

	Credits_frametime = 0;
	Credits_last_time = timer_get_milliseconds();
	
	if (!Credits_parsed)
	{
		Credit_text_parts.push_back(SCP_string("No credits available.\n"));
	}
	else
	{
		switch (SCP_credits_position)
		{
			case START:
				Credit_text_parts.insert(Credit_text_parts.begin(), fs2_open_credit_text);
				break;

			case END:
				Credit_text_parts.push_back(fs2_open_credit_text);
				break;

			default:
				Error(LOCATION, "Unimplemented credits position %d. Get a coder!", (int) SCP_credits_position);
				break;
		}
	}

	int ch;
	SCP_vector<SCP_string>::iterator iter;

	for (iter = Credit_text_parts.begin(); iter != Credit_text_parts.end(); ++iter)
	{
		for (SCP_string::iterator ii = iter->begin(); ii != iter->end(); ++ii)
		{
			ch = *ii;
			switch (ch)
			{
				case -4:
					ch = 129;
					break;

				case -28:
					ch = 132;
					break;

				case -10:
					ch = 148;
					break;

				case -23:
					ch = 130;
					break;

				case -30:
					ch = 131;
					break;

				case -25:
					ch = 135;
					break;

				case -21:
					ch = 137;
					break;

				case -24:
					ch = 138;
					break;

				case -17:
					ch = 139;
					break;

				case -18:
					ch = 140;
					break;

				case -60:
					ch = 142;
					break;

				case -55:
					ch = 144;
					break;

				case -12:
					ch = 147;
					break;

				case -14:
					ch = 149;
					break;

				case -5:
					ch = 150;
					break;

				case -7:
					ch = 151;
					break;

				case -42:
					ch = 153;
					break;

				case -36:
					ch = 154;
					break;

				case -31:
					ch = 160;
					break;

				case -19:
					ch = 161;
					break;

				case -13:
					ch = 162;
					break;

				case -6:
					ch = 163;
					break;

				case -32:
					ch = 133;
					break;

				case -22:
					ch = 136;
					break;

				case -20:
					ch = 141;
					break;
			}

			*ii = (char) ch;
		}
	}

	int temp_h;
	int h = 0;

	for (iter = Credit_text_parts.begin(); iter != Credit_text_parts.end(); ++iter)
	{
		gr_get_string_size(NULL, &temp_h, iter->c_str(), (int)iter->length());

		h = h + temp_h;
	}

	Credit_start_pos = i2fl(Credits_text_coords[gr_screen.res][CREDITS_H_COORD]);
	Credit_stop_pos = -i2fl(h);
	Credit_position = Credit_start_pos;

	Ui_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0);
	Ui_window.set_mask_bmap(Credits_bitmap_mask_fname[gr_screen.res]);
	common_set_interface_palette("InterfacePalette");  // set the interface palette

	for (i=0; i<NUM_BUTTONS; i++) {
		b = &Buttons[i][gr_screen.res];

		b->button.create(&Ui_window, "", b->x, b->y, 60, 30, (i < 2), 1);
		// set up callback for when a mouse first goes over a button
		b->button.set_highlight_action(common_play_highlight_sound);
		b->button.set_bmaps(b->filename);
		b->button.link_hotspot(b->hotspot);
	}

	// add some text
	Ui_window.add_XSTR("Technical Database", 1055, Buttons[TECH_DATABASE_BUTTON][gr_screen.res].xt,  Buttons[TECH_DATABASE_BUTTON][gr_screen.res].yt, &Buttons[TECH_DATABASE_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
	Ui_window.add_XSTR("Mission Simulator", 1056, Buttons[SIMULATOR_BUTTON][gr_screen.res].xt,  Buttons[SIMULATOR_BUTTON][gr_screen.res].yt, &Buttons[SIMULATOR_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
	Ui_window.add_XSTR("Cutscenes", 1057, Buttons[CUTSCENES_BUTTON][gr_screen.res].xt,  Buttons[CUTSCENES_BUTTON][gr_screen.res].yt, &Buttons[CUTSCENES_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
	Ui_window.add_XSTR("Credits", 1058, Buttons[CREDITS_BUTTON][gr_screen.res].xt,  Buttons[CREDITS_BUTTON][gr_screen.res].yt, &Buttons[CREDITS_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_GREEN);
	Ui_window.add_XSTR("Exit", 1420, Buttons[EXIT_BUTTON][gr_screen.res].xt,  Buttons[EXIT_BUTTON][gr_screen.res].yt, &Buttons[EXIT_BUTTON][gr_screen.res].button, UI_XSTR_COLOR_PINK);

	if (Player->flags & PLAYER_FLAGS_IS_MULTI) {
		Buttons[SIMULATOR_BUTTON][gr_screen.res].button.disable();
		Buttons[CUTSCENES_BUTTON][gr_screen.res].button.disable();
	}

	Buttons[EXIT_BUTTON][gr_screen.res].button.set_hotkey(KEY_CTRLED | KEY_ENTER);

	Background_bitmap = bm_load(Credits_bitmap_fname[gr_screen.res]);

	Credits_bmps.resize(Credits_num_images);
	for (i=0; i<Credits_num_images; i++) {
		Credits_bmps[i] = -1;
	}
}
Example #3
0
void credits_do_frame(float frametime)
{
	GR_DEBUG_SCOPE("Credits do frame");

	int i, k, next, percent, bm1, bm2;
	int bx1, by1, bw1, bh1;
	int bx2, by2, bw2, bh2;

	// Use this id to trigger the start of music playing on the credits screen
	if ( timestamp_elapsed(Credits_music_begin_timestamp) ) {
		Credits_music_begin_timestamp = 0;
		credits_start_music();
	}

	k = Ui_window.process();
	switch (k) {
	case KEY_ESC:
		gameseq_post_event(GS_EVENT_MAIN_MENU);
		key_flush();
		break;

	case KEY_CTRLED | KEY_UP:
	case KEY_SHIFTED | KEY_TAB:
		if ( !(Player->flags & PLAYER_FLAGS_IS_MULTI) ) {
			credits_screen_button_pressed(CUTSCENES_BUTTON);
			break;
		}
		// else, react like tab key.

	case KEY_CTRLED | KEY_DOWN:
	case KEY_TAB:
		credits_screen_button_pressed(TECH_DATABASE_BUTTON);
		break;

	default:
		break;
	} // end switch

	for (i=0; i<NUM_BUTTONS; i++){
		if (Buttons[i][gr_screen.res].button.pressed()){
			if (credits_screen_button_pressed(i)){
				return;
			}
		}
	}

	gr_reset_clip();	
	GR_MAYBE_CLEAR_RES(Background_bitmap);
	if (Background_bitmap >= 0) {
		gr_set_bitmap(Background_bitmap);
		gr_bitmap(0, 0, GR_RESIZE_MENU);
	} 

	percent = (int) (100.0f - (Credits_artwork_display_time - Credits_counter) * 100.0f / Credits_artwork_fade_time);
	if (percent < 0){
		percent = 0;
	}

	next = Credits_artwork_index + 1;
	if (next >= Credits_num_images){
		next = 0;
	}

	if (Credits_bmps[Credits_artwork_index] < 0) {
		char buf[40];

		if (gr_screen.res == GR_1024) {
			sprintf(buf, NOX("2_CrIm%.2d"), Credits_artwork_index);
		} else {
			sprintf(buf, NOX("CrIm%.2d"), Credits_artwork_index);
		}
		Credits_bmps[Credits_artwork_index] = bm_load(buf);
	}

	if (Credits_bmps[next] < 0) {
		char buf[40];

		if (gr_screen.res == GR_1024) {
			sprintf(buf, NOX("2_CrIm%.2d"), next);
		} else {
			sprintf(buf, NOX("CrIm%.2d"), next);
		}
		Credits_bmps[next] = bm_load(buf);
	}

	bm1 = Credits_bmps[Credits_artwork_index];
	bm2 = Credits_bmps[next];

	if((bm1 != -1) && (bm2 != -1)){
		GR_DEBUG_SCOPE("Render credits bitmap");

		Assert(percent >= 0 && percent <= 100);

		// get width and height
		bm_get_info(bm1, &bw1, &bh1, NULL, NULL, NULL);	
		bm_get_info(bm2, &bw2, &bh2, NULL, NULL, NULL);	
	
		// determine where to draw the coords
		bx1 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw1)/2);
		by1 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh1)/2);
		bx2 = Credits_image_coords[gr_screen.res][CREDITS_X_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_W_COORD] - bw2)/2);
		by2 = Credits_image_coords[gr_screen.res][CREDITS_Y_COORD] + ((Credits_image_coords[gr_screen.res][CREDITS_H_COORD] - bh2)/2);

		auto alpha = (float)percent / 100.0f;

		gr_set_bitmap(bm1, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f - alpha);
		gr_bitmap(bx1, by1, GR_RESIZE_MENU);

		gr_set_bitmap(bm2, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha);
		gr_bitmap(bx2, by2, GR_RESIZE_MENU);
	}

	Ui_window.draw();

	for (i=TECH_DATABASE_BUTTON; i<=CREDITS_BUTTON; i++){
		if (Buttons[i][gr_screen.res].button.button_down()){
			break;
		}
	}

	if (i > CREDITS_BUTTON){
		Buttons[CREDITS_BUTTON][gr_screen.res].button.draw_forced(2);
	}

	gr_set_clip(Credits_text_coords[gr_screen.res][CREDITS_X_COORD], Credits_text_coords[gr_screen.res][CREDITS_Y_COORD], Credits_text_coords[gr_screen.res][CREDITS_W_COORD], Credits_text_coords[gr_screen.res][CREDITS_H_COORD], GR_RESIZE_MENU);
	font::set_font(font::FONT1);
	gr_set_color_fast(&Color_normal);
	
	int y_offset = 0;
	for (SCP_vector<SCP_string>::iterator iter = Credit_text_parts.begin(); iter != Credit_text_parts.end(); ++iter)
	{
		size_t currentPos = 0;
		size_t lineEnd;
		do
		{
			int height;
			int width;
			lineEnd = iter->find('\n', currentPos);

			auto length = lineEnd - currentPos;
			if (lineEnd == SCP_string::npos)
			{
				length = std::numeric_limits<size_t>::max();
			}

			gr_get_string_size(&width, &height, iter->c_str() + currentPos, static_cast<int>(length));
			// Check if the text part is actually visible
			if (Credit_position + y_offset + height > 0.0f)
			{
				float x = static_cast<float>((gr_screen.clip_width_unscaled - width) / 2);
				gr_string(x, Credit_position + y_offset, iter->c_str() + currentPos, GR_RESIZE_MENU, static_cast<int>(length));
			}

			y_offset += height;
			currentPos = lineEnd + 1;
		} while (lineEnd < iter->length() && lineEnd != SCP_string::npos);
	}

	int temp_time;
	temp_time = timer_get_milliseconds();

	Credits_frametime = temp_time - Credits_last_time;
	Credits_last_time = temp_time;
	timestamp_inc(i2f(Credits_frametime) / TIMESTAMP_FREQUENCY);

	float fl_frametime = i2fl(Credits_frametime) / 1000.f;
	if (keyd_pressed[KEY_LSHIFT]) {
		Credit_position -= fl_frametime * Credits_scroll_rate * 4.0f;
	} else {
		Credit_position -= fl_frametime * Credits_scroll_rate;
	}

	if (Credit_position < Credit_stop_pos){
		Credit_position = Credit_start_pos;
	}

	Credits_counter += fl_frametime;
	while (Credits_counter >= Credits_artwork_display_time) {
		Credits_counter -= Credits_artwork_display_time;
		Credits_artwork_index = next;
	}

	gr_flip();
}
// ********************************************************************************************
// Engages autopilot
// This does:
//        * Control switched from player to AI
//        * Time compression to 32x
//        * Lock time compression -WMC
//        * Tell AI to fly to targeted Nav Point (for all nav-status wings/ships)
//		  * Sets max waypoint speed to the best-speed of the slowest ship tagged
bool StartAutopilot()
{
	// Check for support ship and dismiss it if it is not doing anything.
	// If the support ship is doing something then tell the user such.
	for ( object *objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
	{
		if ((objp->type == OBJ_SHIP) && !(objp->flags & OF_SHOULD_BE_DEAD))
		{
			Assertion((objp->instance >= 0) && (objp->instance < MAX_SHIPS),
				"objp does not have a valid pointer to a ship. Pointer is %d, which is smaller than 0 or bigger than %d",
				objp->instance, MAX_SHIPS);
			ship *shipp = &Ships[objp->instance];

			if (shipp->team != Player_ship->team)
				continue;

			Assertion((shipp->ship_info_index >= 0) && (shipp->ship_info_index < MAX_SHIP_CLASSES),
				"Ship '%s' does not have a valid pointer to a ship class. Pointer is %d, which is smaller than 0 or bigger than %d",
				shipp->ship_name, shipp->ship_info_index, MAX_SHIP_CLASSES);
			ship_info *sip = &Ship_info[shipp->ship_info_index];

			if ( !(sip->flags & SIF_SUPPORT) )
				continue;

			// don't deal with dying or departing support ships
			if ( shipp->flags & (SF_DYING | SF_DEPARTING) )
				continue;

			Assert(shipp->ai_index != -1);
			ai_info* support_ship_aip = &(Ai_info[Ships[objp->instance].ai_index]);

			// is support ship trying to rearm-repair
			if ( ai_find_goal_index( support_ship_aip->goals, AI_GOAL_REARM_REPAIR ) == -1 ) {
				// no, so tell it to depart
				ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WARP, -1, NULL, support_ship_aip );
			} else {
				// yes
				send_autopilot_msgID(NP_MSG_FAIL_SUPPORT_WORKING);
				return false;
			}
		}
	}
	if (!CanAutopilot())
		return false;

	AutoPilotEngaged = true;

	// find the ship that is "leading" all of the ships when the player starts
	// autopilot
	// by default the ship that is leading the autopilot session the player's
	// wing leader (if the player is the wing leader then it will be the
	// player).
	// TODO:implement a way to allow a FREDer to say a different ship is leader
	Autopilot_flight_leader = get_wing_leader(Player_ship->wingnum);
	if ( Autopilot_flight_leader == NULL ) {
		// force player to be the leader if he doesn't have a wing
		Autopilot_flight_leader = Player_obj;
	}

	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
		LockAPConv = timestamp(); // lock convergence instantly
	else
		LockAPConv = timestamp(3000); // 3 seconds before we lock convergence
	Player_use_ai = 1;
	set_time_compression(1);
	lock_time_compression(true);

	// determine speed cap
	int i,j, wcount=1, tc_factor=1;
	float speed_cap = 1000000.0; // 1m is a safe starting point
	float radius = Player_obj->radius, distance = 0.0f, ftemp;
	bool capshipPresent = false;
	int capship_counts[3]; // three size classes
	capship_counts[0] = 0;
	capship_counts[1] = 0;
	capship_counts[2] = 0;

	int capship_placed[3]; // three size classes
	capship_placed[0] = 0;
	capship_placed[1] = 0;
	capship_placed[2] = 0;

	float capship_spreads[3];
	capship_spreads[0] = 0.0f;
	capship_spreads[1] = 0.0f;
	capship_spreads[2] = 0.0f;

	SCP_vector<int> capIndexes;

	// empty the autopilot wings map
	autopilot_wings.clear();

	// vars for usage w/ cinematic
	vec3d pos, norm1, perp, tpos, rpos = Player_obj->pos, zero;
	memset(&zero, 0, sizeof(vec3d));


	// instantly turn player toward tpos
	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
	{
		vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
		vm_vector_2_matrix(&Player_obj->orient, &norm1, NULL, NULL);
	}

	for (i = 0; i < MAX_SHIPS; i++)
	{
		if (Ships[i].objnum != -1 && 
				(Ships[i].flags2 & SF2_NAVPOINT_CARRY || 
					(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
				)
			)
		{
			if (speed_cap > vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel))
				speed_cap = vm_vec_mag(&Ship_info[Ships[i].ship_info_index].max_vel);
		}
	}

	// damp speed_cap to 90% of actual -- to make sure ships stay in formation
	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
		speed_cap = 0.90f * speed_cap;

	if ( speed_cap < 1.0f ) {
		/* We need to deal with this so that incorrectly flagged ships will not
		cause the engine to fail to limit all the ships speeds correctly. */
		Warning(LOCATION, "Ship speed cap is way too small (%f)!\n"
			"This is normally caused by a ship that has nav-carry-status set, but cannot move itself (like a Cargo container).\n"
			"Speed cap has been set to 1.0 m/s.",
			speed_cap);
		speed_cap = 1.0f;
	}

	ramp_bias = speed_cap/50.0f;

	// assign ship goals
	// when assigning goals to individual ships only do so if Ships[shipnum].wingnum != -1 
	// we will assign wing goals below

	for (i = 0; i < MAX_SHIPS; i++)
	{
		if (Ships[i].objnum != -1 && 
				(Ships[i].flags2 & SF2_NAVPOINT_CARRY || 
					(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY)
				)
			)
		{
			// do we have capital ships in the area?
			if (Ship_info[Ships[i].ship_info_index].flags 
				& ( SIF_CRUISER | SIF_CAPITAL | SIF_SUPERCAP | SIF_CORVETTE | SIF_AWACS | SIF_GAS_MINER | SIF_FREIGHTER | SIF_TRANSPORT))
			{
				capshipPresent = true;

				capIndexes.push_back(i);
				// ok.. what size class

				if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP))
				{
					capship_counts[0]++;
					if (capship_spreads[0] < Objects[Ships[i].objnum].radius)
						capship_spreads[0] = Objects[Ships[i].objnum].radius;
				}
				else if (Ship_info[Ships[i].ship_info_index].flags & (SIF_CORVETTE))
				{
					capship_counts[1]++;
					if (capship_spreads[1] < Objects[Ships[i].objnum].radius)
						capship_spreads[1] = Objects[Ships[i].objnum].radius;
				}
				else
				{
					capship_counts[2]++;
					if (capship_spreads[2] < Objects[Ships[i].objnum].radius)
						capship_spreads[2] = Objects[Ships[i].objnum].radius;
				}
			}



			// check for bigger radius for usage later
			/*if (!vm_vec_cmp(&rpos, &Player_obj->pos)) 
				// want to make sure rpos isn't player pos - we can worry about it being largest object's later
			{
				rpos = Objects[Ships[i].objnum].pos;
			}*/

			if (Objects[Ships[i].objnum].radius > radius)
			{
				rpos = Objects[Ships[i].objnum].pos;
				radius = Objects[Ships[i].objnum].radius;
			}

			if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
			{// instantly turn the ship to match the direction player is looking
				//vm_vec_sub(&norm1, Navs[CurrentNav].GetPosition(), &Player_obj->pos);
				vm_vector_2_matrix(&Objects[Ships[i].objnum].orient, &norm1, NULL, NULL);
			}

			// snap wings into formation
			if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS &&  // only if using cinematics 
				(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY) // only if in a wing
				&& Autopilot_flight_leader != &Objects[Ships[i].objnum]) //only if not flight leader's object
			{	
				ai_info	*aip = &Ai_info[Ships[i].ai_index];
				int wingnum = aip->wing, wing_index = get_wing_index(&Objects[Ships[i].objnum], wingnum);
				vec3d goal_point;
				object *leader_objp = get_wing_leader(wingnum);
				
				if (leader_objp != &Objects[Ships[i].objnum])
				{
					// not leader.. get our position relative to leader
					get_absolute_wing_pos_autopilot(&goal_point, leader_objp, wing_index, aip->ai_flags & AIF_FORMATION_OBJECT);
				}
				else
				{
					ai_clear_wing_goals(wingnum);
					j = 1+int( (float)floor(double(wcount-1)/2.0) );
					switch (wcount % 2)
					{
						case 1: // back-left
							vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
							//vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec);
							vm_vec_normalize(&perp);
							vm_vec_scale(&perp, -166.0f*j); // 166m is supposedly the optimal range according to tolwyn
							vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
							break;

						default: //back-right
						case 0:
							vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
							//vm_vec_sub(&perp, &perp, &Player_obj->orient.vec.fvec);
							vm_vec_normalize(&perp);
							vm_vec_scale(&perp, 166.0f*j);
							vm_vec_add(&goal_point, &Autopilot_flight_leader->pos, &perp);
							break;
					}
					autopilot_wings[wingnum] = wcount;
					wcount++;
				}
				Objects[Ships[i].objnum].pos = goal_point;			
				if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos) > distance)
				{
					distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[i].objnum].pos);
				}
			}
			// lock primary and secondary weapons
			if ( LockWeaponsDuringAutopilot )
				Ships[i].flags2 |= (SF2_PRIMARIES_LOCKED | SF2_SECONDARIES_LOCKED);

			// clear the ship goals and cap the waypoint speed
			ai_clear_ship_goals(&Ai_info[Ships[i].ai_index]);
			Ai_info[Ships[i].ai_index].waypoint_speed_cap = (int)speed_cap;

			
			// if they're not part of a wing set their goal
			if (Ships[i].wingnum == -1 || The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
			{ 
				if (Navs[CurrentNav].flags & NP_WAYPOINT)
				{
					ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), &Ai_info[Ships[i].ai_index] );
					//fixup has to wait until after wing goals
				}
				else
				{
					ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, &Ai_info[Ships[i].ai_index] );
				}

			}
		}
	}

	// assign wing goals
	if (!(The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS))
	{
		for (i = 0; i < MAX_WINGS; i++)
		{
			if (Wings[i].flags & WF_NAV_CARRY )
			{	
				//ai_add_ship_goal_player( int type, int mode, int submode, char *shipname, ai_info *aip );

				//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_STAY_NEAR_SHIP, 0, target_shipname, wingnum );
				//ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, target_shipname, wingnum );
				//ai_clear_ship_goals( &(Ai_info[Ships[num].ai_index]) );
				
				ai_clear_wing_goals( i );
				if (Navs[CurrentNav].flags & NP_WAYPOINT)
				{
					
					ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_WAYPOINTS_ONCE, 0, ((waypoint_list*)Navs[CurrentNav].target_obj)->get_name(), i );

					// "fix up" the goal
					for (j = 0; j < MAX_AI_GOALS; j++)
					{
						if (Wings[i].ai_goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
							Wings[i].ai_goals[j].ai_mode == AIM_WAYPOINTS )
						{
							autopilot_ai_waypoint_goal_fixup(&(Wings[i].ai_goals[j]));
						}
					}
				}
				else
				{
					ai_add_wing_goal_player( AIG_TYPE_PLAYER_WING, AI_GOAL_FLY_TO_SHIP, 0, ((ship*)Navs[CurrentNav].target_obj)->ship_name, i );

				}
			}
		}
	}

	// fixup has to go down here because ships are assigned goals during wing goals as well
	for (i = 0; i < MAX_SHIPS; i++)
	{
		if (Ships[i].objnum != -1)
		{
			if (Ships[i].flags2 & SF2_NAVPOINT_CARRY || 
				(Ships[i].wingnum != -1 && Wings[Ships[i].wingnum].flags & WF_NAV_CARRY))
				for (j = 0; j < MAX_AI_GOALS; j++)
				{
					if (Ai_info[Ships[i].ai_index].goals[j].ai_mode == AI_GOAL_WAYPOINTS_ONCE ||
						Ai_info[Ships[i].ai_index].goals[j].ai_mode == AIM_WAYPOINTS)
					{
						autopilot_ai_waypoint_goal_fixup( &(Ai_info[Ships[i].ai_index].goals[j]) );

						
						// formation fixup
						//ai_form_on_wing(&Objects[Ships[i].objnum], &Objects[Player_ship->objnum]);
					}
				}
		}
	}
	start_dist = DistanceTo(CurrentNav);

	// ----------------------------- setup cinematic -----------------------------
	if (The_mission.flags & MISSION_FLAG_USE_AP_CINEMATICS)
	{	
		if (capshipPresent)
		{
			// position capships

			vec3d right, front, up, offset;
			for (SCP_vector<int>::iterator idx = capIndexes.begin(); idx != capIndexes.end(); ++idx)
			{
				vm_vec_add(&right, &Autopilot_flight_leader->orient.vec.rvec, &zero);
				vm_vec_add(&front, &Autopilot_flight_leader->orient.vec.fvec, &zero);
				vm_vec_add(&up, &Autopilot_flight_leader->orient.vec.uvec, &zero);
				vm_vec_add(&offset, &zero, &zero);
				if (Ship_info[Ships[*idx].ship_info_index].flags & (SIF_CAPITAL | SIF_SUPERCAP))
				{
					//0 - below - three lines of position

					// front/back to zero
					vm_vec_add(&front, &zero, &zero);

					// position below
					vm_vec_scale(&up, capship_spreads[0]); // scale the up vector by the radius of the largest ship in this formation part


					switch (capship_placed[0] % 3)
					{
						case 1: // right
							vm_vec_scale(&right, capship_spreads[0]);
							break;
							
						case 2: // left
							vm_vec_scale(&right, -capship_spreads[0]);
							break;

						default: // straight
						case 0:
							vm_vec_add(&right, &zero, &zero);
							vm_vec_scale(&up, 1.5); // add an extra half-radius
							break;
					}
		
					// scale by  row
					vm_vec_scale(&right, (1+((float)floor((float)capship_placed[0]/3)))); 
					vm_vec_scale(&up, -(1+((float)floor((float)capship_placed[0]/3))));

					capship_placed[0]++;
				}
				else if (Ship_info[Ships[*idx].ship_info_index].flags & SIF_CORVETTE)
				{
					//1 above - 3 lines of position
					// front/back to zero
					vm_vec_add(&front, &zero, &zero);

					// position below
					vm_vec_scale(&up, capship_spreads[1]); // scale the up vector by the radius of the largest ship in this formation part


					switch (capship_placed[1] % 3)
					{
						case 1: // right
							vm_vec_scale(&right, capship_spreads[1]); 
							break;
							
						case 2: // left
							vm_vec_scale(&right, -capship_spreads[1]); 
							break;

						default: // straight
						case 0:
							vm_vec_add(&right, &zero, &zero);
							vm_vec_scale(&up, 1.5); // add an extra half-radius
							break;
					}
		
					// scale by  row
					vm_vec_scale(&right, (1+((float)floor((float)capship_placed[1]/3)))); 
					vm_vec_scale(&up, (1+((float)floor((float)capship_placed[1]/3))));

					// move ourselves up and out of the way of the smaller ships
					vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.uvec, &zero);
					vm_vec_scale(&perp, capship_spreads[2]);
					vm_vec_add(&up, &up, &perp);

					capship_placed[1]++;
				}
				else
				{
					//2 either side - 6 lines of position (right (dir, front, back), left (dir, front, back) )
					// placing pattern: right, left, front right, front left, rear right, rear left

					// up/down to zero
					vm_vec_add(&up, &zero, &zero);


					switch (capship_placed[2] % 6)
					{
						case 5:  // rear left
							vm_vec_scale(&right, -capship_spreads[2]);
							vm_vec_scale(&front, -capship_spreads[2]); 
							break;

						case 4:  // rear right
							vm_vec_scale(&right, capship_spreads[2]); 
							vm_vec_scale(&front, -capship_spreads[2]); 
							break;

						case 3:  // front left
							vm_vec_scale(&right, -capship_spreads[2]); 
							vm_vec_scale(&front, capship_spreads[2]); 
							break;

						case 2:  // front right
							vm_vec_scale(&right, capship_spreads[2]); 
							vm_vec_scale(&front, capship_spreads[2]);
							break;

						case 1:  // straight left
							vm_vec_scale(&right, 1.5);
							vm_vec_scale(&right, -capship_spreads[2]);
							vm_vec_add(&front, &zero, &zero);
							break;

						default: // straight right
						case 0:
							vm_vec_scale(&right, 1.5);
							vm_vec_scale(&right, capship_spreads[2]);
							vm_vec_add(&front, &zero, &zero);
							break;
					}
					// these ships seem to pack a little too tightly
					vm_vec_scale(&right, 2*(1+((float)floor((float)capship_placed[2]/3)))); 
					vm_vec_scale(&front, 2*(1+((float)floor((float)capship_placed[2]/3))));

					// move "out" by 166*(wcount-1) so we don't bump into fighters
					vm_vec_add(&perp, &Autopilot_flight_leader->orient.vec.rvec, &zero);
					vm_vec_scale(&perp, 166.0f*float(wcount-1));
					if ( (capship_placed[2] % 2) == 0)
						vm_vec_add(&right, &right, &perp);
					else
						vm_vec_sub(&right, &right, &perp);

					capship_placed[2]++;
				}

				// integrate the up/down componant
				vm_vec_add(&offset, &offset, &up);

				//integrate the left/right componant
				vm_vec_add(&offset, &offset, &right);

				//integrate the left/right componant
				vm_vec_add(&offset, &offset, &front);

				// global scale the position by 50%
				//vm_vec_scale(&offset, 1.5);

				vm_vec_add(&Objects[Ships[*idx].objnum].pos, &Autopilot_flight_leader->pos, &offset);

				if (vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos) > distance)
				{
					distance = vm_vec_dist_quick(&Autopilot_flight_leader->pos, &Objects[Ships[*idx].objnum].pos);
				}
			}
		}

		ftemp = floor(Autopilot_flight_leader->phys_info.max_vel.xyz.z/speed_cap);
		if (ftemp >= 2.0f && ftemp < 4.0f)
			tc_factor = 2;
		else if (ftemp >= 4.0f && ftemp < 8.0f)
			tc_factor = 4;
		else if (ftemp >= 8.0f)
			tc_factor = 8;



		tpos = *Navs[CurrentNav].GetPosition();
		// determine distance toward nav at which camera will be
		vm_vec_sub(&pos, &tpos, &Autopilot_flight_leader->pos);
		vm_vec_normalize(&pos); // pos is now a unit vector in the direction we will be moving the camera
		//norm1 = pos;
		vm_vec_scale(&pos, 5*speed_cap*tc_factor); // pos is now scaled by 5 times the speed (5 seconds ahead)
		vm_vec_add(&pos, &pos, &Autopilot_flight_leader->pos); // pos is now 5*speed cap in front of player ship

		switch (myrand()%24) 
		// 8 different ways of getting perp points
		// 4 of which will not be used when capships are present (anything below, or straight above)
		{

			case 1: // down
			case 9:
			case 16:
				if (capship_placed[0] == 0)
					vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec);
				else
				{	// become up-left
					vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.uvec);
					vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec);
				}
				break;

			case 2: // up
			case 10:
			case 23:
				vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				if (capshipPresent) // become up-right
					vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.rvec);
				break;

			case 3: // left
			case 11:
			case 22:
				vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				break;

			case 4: // up-left
			case 12:
			case 21:
				vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			case 5: // up-right
			case 13:
			case 20:
				vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			case 6: // down-left
			case 14:
			case 19:
				vm_vec_sub(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				if (capship_placed[0] < 2)
					vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				else
					vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			case 7: // down-right
			case 15:
			case 18:
				vm_vec_add(&perp, &zero, &Autopilot_flight_leader->orient.vec.rvec);
				if (capship_placed[0] < 1)
					vm_vec_sub(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				else
					vm_vec_add(&perp, &perp, &Autopilot_flight_leader->orient.vec.uvec);
				break;

			default:
			case 0: // right
			case 8:
			case 17:
				perp = Autopilot_flight_leader->orient.vec.rvec;
				break;

		}
		vm_vec_normalize(&perp);
		//vm_vec_scale(&perp, 2*radius+distance);

		vm_vec_scale(&perp,  Autopilot_flight_leader->radius+radius);

		// randomly scale up/down by up to 20%
		j = 20-myrand()%40; // [-20,20]

		vm_vec_scale(&perp, 1.0f+(float(j)/100.0f));
		vm_vec_add(&cameraPos, &pos, &perp);

		if (capshipPresent)
		{
			vm_vec_normalize(&perp);

			// place it behind
			//vm_vec_copy_scale(&norm1, &Player_obj->orient.vec.fvec, -2*(Player_obj->radius+radius*(1.0f+(float(j)/100.0f))));
			//vm_vec_add(&cameraTarget, &cameraTarget, &norm1);

			vm_vec_copy_scale(&cameraTarget,&perp, radius/5.0f);

			//vm_vec_scale(&cameraTarget, Player_obj->radius+radius*(1.0f+(float(j)/100.0f)));

			//vm_vec_add(&cameraTarget, &pos, &cameraTarget);
			//CameraSpeed = (radius+distance)/25;

			//vm_vec_add(&cameraTarget, &zero, &perp);
			//vm_vec_scale(&CameraVelocity, (radius+distance/100.f));
			//vm_vec_scale(&CameraVelocity, 1.0f/float(NPS_TICKRATE*tc_factor));
		}
		else
		{
			vm_vec_add(&cameraTarget, &zero, &zero);
			//CameraSpeed = 0;
		}
		//CameraMoving = false;


		EndAPCinematic = timestamp((10000*tc_factor)+NPS_TICKRATE); // 10 objective seconds before end of cinematic 
		MoveCamera = timestamp((5500*tc_factor)+NPS_TICKRATE);
		camMovingTime = int(4.5*float(tc_factor));
		set_time_compression((float)tc_factor);
	}

	return true;
}
Example #5
0
void credits_parse_table(const char* filename)
{	
	try
	{
		read_file_text(filename, CF_TYPE_TABLES);
		reset_parse();

		// any metadata?
		if (optional_string("$Music:"))
		{
			stuff_string(Credits_music_name, F_NAME, NAME_LENGTH);
		}
		if (optional_string("$Number of Images:"))
		{
			int temp;
			stuff_int(&temp);
			if (temp > 0)
				Credits_num_images = temp;
		}
		if (optional_string("$Start Image Index:"))
		{
			stuff_int(&Credits_artwork_index);

			// bounds check
			if (Credits_artwork_index < 0)
			{
				Credits_artwork_index = 0;
			}
			else if (Credits_artwork_index >= Credits_num_images)
			{
				Credits_artwork_index = Credits_num_images - 1;
			}
		}
		if (optional_string("$Text scroll rate:"))
		{
			stuff_float(&Credits_scroll_rate);
			if (Credits_scroll_rate < 0.01f)
				Credits_scroll_rate = 0.01f;
		}
		if (optional_string("$Artworks display time:"))
		{
			stuff_float(&Credits_artwork_display_time);
			if (Credits_artwork_display_time < 0.01f)
				Credits_artwork_display_time = 0.01f;
		}
		if (optional_string("$Artworks fade time:"))
		{
			stuff_float(&Credits_artwork_fade_time);
			if (Credits_artwork_fade_time < 0.01f)
				Credits_artwork_fade_time = 0.01f;
		}
		if (optional_string("$SCP Credits position:"))
		{
			char mode[NAME_LENGTH];

			stuff_string(mode, F_NAME, NAME_LENGTH);

			if (!stricmp(mode, "Start"))
				SCP_credits_position = START;
			else if (!stricmp(mode, "End"))
				SCP_credits_position = END;
			else
				Warning(LOCATION, "Unknown credits position mode \"%s\".", mode);
		}

		ignore_white_space();

		SCP_string credits_text;
		SCP_string line;

		SCP_vector<int> charNum;
		SCP_vector<const char*> lines;
		int numLines = -1;

		bool first_run = true;
		while (!check_for_eof_raw() && !check_for_string_raw("#end"))
		{
			// Read in a line of text			
			stuff_string_line(line);

			// This is a bit odd but it means if a total conversion uses different credits the 
			// Volition credit won't happen
			// Also don't append the default credits anymore when there was already a parsed table
			if (first_run && !Credits_parsed && !line.compare(mod_check))
			{
				credits_text.append(unmodified_credits);
			}

			first_run = false;

			if (line.empty())
			{
				// If the line is empty then just append a newline, don't bother with splitting it first
				credits_text.append("\n");
			}
			else
			{
				// split_str doesn't take care of this.
				charNum.clear();

				// Split the string into multiple lines if it's too long
				numLines = split_str(line.c_str(), Credits_text_coords[gr_screen.res][2], charNum, lines, -1);

				// Make sure that we have valid data
				Assertion(lines.size() == (size_t)numLines, "split_str reported %d lines but vector contains " SIZE_T_ARG " entries!", numLines, lines.size());

				Assertion(lines.size() <= charNum.size(),
					"Something has gone wrong while splitting strings. Got " SIZE_T_ARG " lines but only " SIZE_T_ARG " chacter lengths.",
					lines.size(), charNum.size());

				// Now add all splitted lines to the credit text and append a newline to the end
				for (int i = 0; i < numLines; i++)
				{
					credits_text.append(SCP_string(lines[i], charNum[i]));
					credits_text.append("\n");
				}
			}
		}

		Credit_text_parts.push_back(credits_text);

		Credits_parsed = true;
	}
	catch (const parse::ParseException& e)
	{
		mprintf(("TABLES: Unable to parse '%s'!  Error message = %s.\n", filename, e.what()));
		return;
	}
}
Example #6
0
static void find_capture_device()
{
	const char *user_device = os_config_read_string( "Sound", "CaptureDevice", NULL );
	const char *default_device = (const char*) alcGetString( NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER );

	// in case they are the same, we only want to test it once
	if ( (user_device && default_device) && !strcmp(user_device, default_device) ) {
		user_device = NULL;
	}

    if ( alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE ) {
		const char *all_devices = (const char*) alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);

		const char *str_list = all_devices;
		int ext_length = 0;

		if ( (str_list != NULL) && ((ext_length = strlen(str_list)) > 0) ) {
			while (ext_length) {
				OALdevice new_device(str_list);

				if (user_device && !strcmp(str_list, user_device)) {
					new_device.type = OAL_DEVICE_USER;
				} else if (default_device && !strcmp(str_list, default_device)) {
					new_device.type = OAL_DEVICE_DEFAULT;
				}

				CaptureDevices.push_back( new_device );

				str_list += (ext_length + 1);
				ext_length = strlen(str_list);
			}
		}
	} else {
		if (default_device) {
			OALdevice new_device(default_device);
			new_device.type = OAL_DEVICE_DEFAULT;

			CaptureDevices.push_back( new_device );
		}

		if (user_device) {
			OALdevice new_device(user_device);
			new_device.type = OAL_DEVICE_USER;

			CaptureDevices.push_back( new_device );
		}
	}

	if ( CaptureDevices.empty() ) {
		return;
	}

	std::sort( CaptureDevices.begin(), CaptureDevices.end(), openal_device_sort_func );


	// for each device that we have available, try and figure out which to use
	for (size_t idx = 0; idx < CaptureDevices.size(); idx++) {
		const ALCchar *device_name = CaptureDevices[idx].device_name.c_str();

		ALCdevice *device = alcCaptureOpenDevice(device_name, 22050, AL_FORMAT_MONO8, 22050 * 2);

		if (device == NULL) {
			continue;
		}

		if (alcGetError(device) != ALC_NO_ERROR) {
			alcCaptureCloseDevice(device);
			continue;
		}

		// ok, we should be good with this one
		Capture_device = CaptureDevices[idx].device_name;

		alcCaptureCloseDevice(device);

		break;
	}
}
Example #7
0
void simple_effects::get_uniforms(SCP_vector<SCP_string>& uniforms)
{
	for (unsigned int i = 0; i < effects.size(); i++)
		uniforms.push_back(SCP_string(effects[i].uniform_name.c_str()));
}
/*
 * red_alert_clear()
 *
 * clear all red alert "wingman" data
 * Allows data to be cleared from outside REDALERT_INTERNAL code
 */
void red_alert_clear()
{
	Red_alert_wingman_status.clear();
}
/*
 * Record the current state of the players wingman & ships with the "red-alert-carry" flag
 * Wingmen without the red-alert-carry flag are only stored if they survive
 * dead wingmen must still be handled in red_alert_bash_wingman_status
 */
void red_alert_store_wingman_status()
{
	ship				*shipp;
	red_alert_ship_status	ras;
	ship_obj			*so;
	object			*ship_objp;

	// store the mission filename for the red alert precursor mission
	Red_alert_precursor_mission = Game_current_mission_filename;

	// Pyro3d - Clear list of stored red alert ships 
	// Probably not the best solution, but it prevents an assertion in change_ship_type()
	Red_alert_wingman_status.clear();

	// store status for all existing ships
	for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
		ship_objp = &Objects[so->objnum];
		Assert(ship_objp->type == OBJ_SHIP);
		shipp = &Ships[ship_objp->instance];

		if ( shipp->flags & SF_DYING ) {
			continue;
		}

		if ( !(shipp->flags & SF_FROM_PLAYER_WING) && !(shipp->flags & SF_RED_ALERT_STORE_STATUS) ) {
			continue;
		}

		ras.name = shipp->ship_name;
		ras.hull = Objects[shipp->objnum].hull_strength;
		ras.ship_class = shipp->ship_info_index;
		red_alert_store_weapons(&ras, &shipp->weapons);
		red_alert_store_subsys_status(&ras, shipp);

		Red_alert_wingman_status.push_back( ras );
		// niffiwan: trying to track down red alert bug creating HUGE pilot files 
		Assert( (Red_alert_wingman_status.size() <= MAX_SHIPS) );
	}

	// store exited ships that did not die
	for (int idx=0; idx<(int)Ships_exited.size(); idx++) {
		if (Ships_exited[idx].flags & SEF_RED_ALERT_CARRY) {
			ras.name = Ships_exited[idx].ship_name;
			ras.hull = float(Ships_exited[idx].hull_strength);

			// if a ship has been destroyed or removed manually by the player, then mark it as such ...
			if ( Ships_exited[idx].flags & SEF_DESTROYED ) {
				ras.ship_class = RED_ALERT_DESTROYED_SHIP_CLASS;
			}
			else if (Ships_exited[idx].flags & SEF_PLAYER_DELETED) {
				ras.ship_class = RED_ALERT_PLAYER_DEL_SHIP_CLASS;
			}
			// ... otherwise we want to make sure and carry over the ship class
			else {
				Assert( Ships_exited[idx].ship_class >= 0 );
				ras.ship_class = Ships_exited[idx].ship_class;
			}

			red_alert_store_weapons(&ras, NULL);
			red_alert_store_subsys_status(&ras, NULL);

			Red_alert_wingman_status.push_back( ras );
			// niffiwan: trying to track down red alert bug creating HUGE pilot files 
			Assert( (Red_alert_wingman_status.size() <= MAX_SHIPS) );
		}
	}

	Assert( !Red_alert_wingman_status.empty() );
}
void fs2netd_spew_table_checksums(const char *outfile)
{
	char full_name[MAX_PATH_LEN];
	FILE *out = NULL;
	char description[512] = { 0 };
	char filename[65] = { 0 };
	size_t offset = 0;
	char *p = NULL;

	if ( Table_valid_status.empty() ) {
		return;
	}

	cf_create_default_path_string(full_name, sizeof(full_name) - 1, CF_TYPE_ROOT, outfile);

	// open the outfile
	out = fopen(full_name, "wt");

	if (out == NULL) {
		return;
	}

	p = Cmdline_spew_table_crcs;

	while (*p && (offset < sizeof(description))) {
		if (*p == '"' && offset < sizeof(description)-1) {
			description[offset++] = '"';
			description[offset++] = '"';
		} else {
			description[offset++] = *p;
		}

		p++;
	}

	// header
	fprintf(out, "filename,CRC32,description\r\n");

	// do all the checksums
	for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) {
		offset = 0;
		p = tvs->name;

		while (*p && (offset < sizeof(filename))) {
			if (*p == '"' && offset < sizeof(filename)-1) {
				filename[offset++] = '"';
				filename[offset++] = '"';
			} else {
				filename[offset++] = *p;
			}

			p++;
		}

		if (offset < sizeof(filename)) {
			filename[offset] = '\0';
		} else {
			filename[sizeof(filename)-1] = '\0';
		}

		fprintf(out, "\"%s\",%u,\"%s\"\r\n", filename, tvs->crc32, description);
	}

	fflush(out);
	fclose(out);
}
void hud_clear_msg_buffer()
{
	HUD_msg_buffer.clear();
}
int fs2netd_update_valid_tables()
{
	int rc;
	int hacked = 0;

	if ( !Logged_in ) {
		return -1;
	}

	// if there are no tables to check with then bail
	if ( Table_valid_status.empty() ) {
		return -1;
	}

	// if we're a standalone, show a dialog saying "validating tables"
	if (Game_mode & GM_STANDALONE_SERVER) {
		std_create_gen_dialog("Validating tables");
		std_gen_set_text("Querying FS2NetD:", 1);
	}

	do_full_packet = true;

	In_process = true;

	if (Is_standalone) {
		do { rc = fs2netd_update_valid_tables_do(); } while (!rc);
	} else {
		rc = popup_till_condition(fs2netd_update_valid_tables_do, XSTR("&Cancel", 779), XSTR("Starting table validation", 1592));
	}

	In_process = false;
	Local_timeout = -1;

	switch (rc) {
		// canceled by popup
		case 0:
			return -1;

		// timed out
		case 1: {
			if ( !Is_standalone ) {
				popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Table validation timed out!", 1593));
			}

			return -1;
		}

		// no tables
		case 2: {
			if ( !Is_standalone ) {
				popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No tables are available from the server for validation!", 1594));
			}

			return -1;
		}
	}

	// output the status of table validity to multi.log
	for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) {
		if (tvs->valid) {
			ml_printf("FS2NetD Table Check: '%s' -- Valid!", tvs->name);
		} else {
			ml_printf("FS2NetD Table Check: '%s' -- INVALID (0x%x)!", tvs->name, tvs->crc32);
			hacked = 1;
		}
	}

	// if we're a standalone, kill the validate dialog
	if (Game_mode & GM_STANDALONE_SERVER) {
		std_destroy_gen_dialog();
	}

	return hacked;
}
int fs2netd_get_valid_missions_do()
{
	if (Local_timeout == -1) {
		Local_timeout = timer_get_seconds() + 30;
	}

	// get the available CRCs from the server if we need to
	if ( FS2NetD_file_list.empty() ) {
		int rc = FS2NetD_GetMissionsList(FS2NetD_file_list, do_full_packet);

		do_full_packet = false;

		// communications error
		if (rc < 0) {
			Local_timeout = -1;
			return 4;
		}

		// no missions
		if ( rc && FS2NetD_file_list.empty() ) {
			Local_timeout = -1;
			return 2;
		}

		// if timeout passes then bail on crc failure
		if ( timer_get_seconds() > Local_timeout ) {
			Local_timeout = -1;
			return 1;
		}
	}
	// we should have the CRCs, or there were no missions, so process them
	else {
		static char **file_names = NULL;
		static int idx = 0, count = 0;

		bool found = false;
		int file_index = 0;
		char valid_status = MVALID_STATUS_UNKNOWN;
		char full_name[MAX_FILENAME_LEN], wild_card[10];
		char val_text[MAX_FILENAME_LEN+15];
		uint checksum = 0;

		if (file_names == NULL) {
			// allocate filename space	
			file_names = (char**) vm_malloc( sizeof(char*) * 1024, memory::quiet_alloc); // 1024 files should be safe!

			if (file_names == NULL) {
				Local_timeout = -1;
				return 3;
			}

			memset( wild_card, 0, sizeof(wild_card) );
			strcpy_s( wild_card, NOX("*") );
			strcat_s( wild_card, FS_MISSION_FILE_EXT );

			idx = count = cf_get_file_list(1024, file_names, CF_TYPE_MISSIONS, wild_card);
		}

		// drop idx first thing
		idx--;

		// we should be done validating, or just not have nothing to validate
		if (idx < 0) {
			for (idx = 0; idx < count; idx++) {
				if (file_names[idx] != NULL) {
					vm_free(file_names[idx]);
					file_names[idx] = NULL;
				}
			}

			vm_free(file_names);
			file_names = NULL;

			idx = count = 0;

			Local_timeout = -1;
			return 4;
		}


		// verify all filenames that we know about with their CRCs
		// NOTE: that this is done for one file per frame, since this is inside of a popup
		memset( full_name, 0, MAX_FILENAME_LEN );
		strncpy( full_name, cf_add_ext(file_names[idx], FS_MISSION_FILE_EXT), sizeof(full_name) - 1 );

		memset( val_text, 0, sizeof(val_text) );
		snprintf( val_text, sizeof(val_text) - 1, "Validating:  %s", full_name );

		if (Is_standalone) {
			if ( std_gen_is_active() ) {
				std_gen_set_text(val_text, 1);
			}
		} else {
			popup_change_text(val_text);
		}

		cf_chksum_long(full_name, &checksum);

		// try and find the file
		file_index = multi_create_lookup_mission(full_name);

		found = false;

		if (file_index >= 0) {
			for (SCP_vector<file_record>::iterator fr = FS2NetD_file_list.begin(); fr != FS2NetD_file_list.end() && !found; ++fr) {
				if ( !stricmp(full_name, fr->name) ) {
					if (fr->crc32 == checksum) {
						found = true;
						valid_status = MVALID_STATUS_VALID;
					} else {
						valid_status = MVALID_STATUS_INVALID;
					}

					Multi_create_mission_list[file_index].valid_status = valid_status;
				}
			}

			if (found) {
				ml_printf("FS2NetD Mission Validation: %s  =>  Valid!", full_name);
			} else {
				ml_printf("FS2NetD Mission Validation: %s  =>  INVALID! -- 0x%08x", full_name, checksum);
			}
		}
	}

	return 0;
}
Example #14
0
// initializes hardware device from perferred/default/enumerated list
bool openal_init_device(SCP_string *playback, SCP_string *capture)
{
	if ( !Playback_device.empty() ) {
		if (playback) {
			*playback = Playback_device;
		}

		if (capture) {
			*capture = Capture_device;
		}

		return true;
	}

	if (playback) {
		playback->erase();
	}

	if (capture) {
		capture->erase();
	}

	// initialize default setup first, for version check...

	ALCdevice *device = alcOpenDevice(NULL);

	if (device == NULL) {
		return false;
	}

	ALCcontext *context = alcCreateContext(device, NULL);

	if (context == NULL) {
		alcCloseDevice(device);
		return false;
	}

	alcMakeContextCurrent(context);

	// version check (for 1.0 or 1.1)
	ALCint AL_minor_version = 0;
	alcGetIntegerv(NULL, ALC_MINOR_VERSION, sizeof(ALCint), &AL_minor_version);

	if (AL_minor_version < 1) {
		os::dialogs::Message(os::dialogs::MESSAGEBOX_ERROR,
			"OpenAL 1.1 or newer is required for proper operation. On Linux and Windows OpenAL Soft is recommended. If you are on Mac OS X you need to upgrade your OS.");

		alcMakeContextCurrent(NULL);
		alcDestroyContext(context);
		alcCloseDevice(device);

		return false;
	}

	alcGetError(device);

	// close default device
	alcMakeContextCurrent(NULL);
	alcDestroyContext(context);
	alcCloseDevice(device);


	// go through and find out what devices we actually want to use ...
	find_playback_device();
	find_capture_device();

	if ( Playback_device.empty() ) {
		return false;
	}


#ifndef NDEBUG
	if ( !PlaybackDevices.empty() ) {
		nprintf(("OpenAL", "  Available Playback Devices:\n"));

		for (size_t idx = 0; idx < PlaybackDevices.size(); idx++) {
			nprintf(("OpenAL", "    %s", PlaybackDevices[idx].device_name.c_str()));

			if (PlaybackDevices[idx].type == OAL_DEVICE_USER) {
				nprintf(("OpenAL", "  *preferred*\n"));
			} else if (PlaybackDevices[idx].type == OAL_DEVICE_DEFAULT) {
				nprintf(("OpenAL", "  *default*\n"));
			} else {
				nprintf(("OpenAL", "\n"));
			}
		}
	}

	if ( !CaptureDevices.empty() ) {
		if ( !PlaybackDevices.empty() ) {
			nprintf(("OpenAL", "\n"));
		}

		nprintf(("OpenAL", "  Available Capture Devices:\n"));

		for (size_t idx = 0; idx < CaptureDevices.size(); idx++) {
			nprintf(("OpenAL", "    %s", CaptureDevices[idx].device_name.c_str()));

			if (CaptureDevices[idx].type == OAL_DEVICE_USER) {
				nprintf(("OpenAL", "  *preferred*\n"));
			} else if (CaptureDevices[idx].type == OAL_DEVICE_DEFAULT) {
				nprintf(("OpenAL", "  *default*\n"));
			} else {
				nprintf(("OpenAL", "\n"));
			}
		}

		nprintf(("OpenAL", "\n"));
	}
#endif


	// cleanup
	PlaybackDevices.clear();
	CaptureDevices.clear();


	if (playback) {
		*playback = Playback_device;
	}

	if (capture) {
		*capture = Capture_device;
	}

	return true;
}
void particle_render_all()
{
	ubyte flags;
	float pct_complete;
	float alpha;
	vertex pos;
	vec3d ts, te, temp;
	int rotate = 1;
	int framenum, cur_frame;
	bool render_batch = false;
	int tmap_flags = TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD;

	if ( !Particles_enabled )
		return;

	MONITOR_INC( NumParticlesRend, Num_particles );	

	if ( Particles.empty() )
		return;

	for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); ++p) {
		particle* part = *p;
		// skip back-facing particles (ripped from fullneb code)
		// Wanderer - add support for attached particles
		vec3d p_pos;
		if (part->attached_objnum >= 0) {
			vm_vec_unrotate(&p_pos, &part->pos, &Objects[part->attached_objnum].orient);
			vm_vec_add2(&p_pos, &Objects[part->attached_objnum].pos);
		} else {
			p_pos = part->pos;
		}

		if ( vm_vec_dot_to_point(&Eye_matrix.vec.fvec, &Eye_position, &p_pos) <= 0.0f ) {
			continue;
		}

		// calculate the alpha to draw at
		alpha = get_current_alpha(&p_pos);

		// if it's transparent then just skip it
		if (alpha <= 0.0f) {
			continue;
		}

		// make sure "rotate" is enabled for this particle
		rotate = 1;

		// if this is a tracer style particle, calculate tracer vectors
		if (part->tracer_length > 0.0f) {			
			ts = p_pos;
			temp = part->velocity;
			vm_vec_normalize_quick(&temp);
			vm_vec_scale_add(&te, &ts, &temp, part->tracer_length);

			// don't bother rotating
			rotate = 0;
		}

		// rotate the vertex
		if (rotate) {
			flags = g3_rotate_vertex( &pos, &p_pos );

			if ( flags ) {
				continue;
			}

			if (!Cmdline_nohtl)
				g3_transfer_vertex(&pos, &p_pos);
		}

		// pct complete for the particle
		pct_complete = part->age / part->max_life;

		// figure out which frame we should be using
		if (part->nframes > 1) {
			framenum = fl2i(pct_complete * part->nframes + 0.5);
			CLAMP(framenum, 0, part->nframes-1);

			cur_frame = part->reverse ? (part->nframes - framenum - 1) : framenum;
		} else {
			cur_frame = 0;
		}

		if (part->type == PARTICLE_DEBUG) {
			gr_set_color( 255, 0, 0 );
			g3_draw_sphere_ez( &p_pos, part->radius );
		} else {
			framenum = part->optional_data;

			Assert( cur_frame < part->nframes );

			// if this is a tracer style particle
			if (part->tracer_length > 0.0f) {
				batch_add_laser( framenum + cur_frame, &ts, part->radius, &te, part->radius );
			}
			// draw as a regular bitmap
			else {
				batch_add_bitmap( framenum + cur_frame, tmap_flags, &pos, part->particle_index % 8, part->radius, alpha );
			}

			render_batch = true;
		}
	}

	profile_begin("Batch Render");
	if (render_batch) {
		batch_render_all(Particle_buffer_object);
	}
	profile_end("Batch Render");
}
/*
 * Take the red alert status information, and adjust the red alert ships accordingly
 * "red alert ships" are wingmen and any ship with the red-alert-carry flag
 * Wingmen without red alert data still need to be handled / removed
 */
void red_alert_bash_wingman_status()
{
	int j;
	ship_obj			*so;

	SCP_vector<red_alert_ship_status>::iterator rasii;
	SCP_vector<p_object>::iterator poii;

	SCP_hash_map<int, int> Wing_pobjects_deleted;
	SCP_hash_map<int, int>::iterator ii;

	if ( !(Game_mode & GM_CAMPAIGN_MODE) ) {
		return;
	}

	if ( Red_alert_wingman_status.empty() ) {
		return;
	}

	// go through all ships in the game, and see if there is red alert status data for any

	so = GET_FIRST(&Ship_obj_list);
	for ( ; so != END_OF_LIST(&Ship_obj_list); )
	{
		object *ship_objp = &Objects[so->objnum];
		Assert(ship_objp->type == OBJ_SHIP);
		ship *shipp = &Ships[ship_objp->instance];

		if ( !(shipp->flags & SF_FROM_PLAYER_WING) && !(shipp->flags & SF_RED_ALERT_STORE_STATUS) ) {
			so = GET_NEXT(so);
			continue;
		}

		bool ship_data_restored = false;
		int ship_state = RED_ALERT_DESTROYED_SHIP_CLASS;

		for ( rasii = Red_alert_wingman_status.begin(); rasii != Red_alert_wingman_status.end(); ++rasii )
		{
			red_alert_ship_status *ras = &(*rasii);

			// red-alert data matches this ship!
			if ( !stricmp(ras->name.c_str(), shipp->ship_name)  )
			{
				// we only want to restore ships which haven't been destroyed, or were removed by the player
				if ( (ras->ship_class != RED_ALERT_DESTROYED_SHIP_CLASS) && (ras->ship_class != RED_ALERT_PLAYER_DEL_SHIP_CLASS) )
				{
					// if necessary, restore correct ship class
					if ( ras->ship_class != shipp->ship_info_index )
					{
						if (ras->ship_class >= 0 && ras->ship_class < MAX_SHIP_CLASSES)
							change_ship_type(SHIP_INDEX(shipp), ras->ship_class);
						else
							mprintf(("Invalid ship class specified in red alert data for ship %s. Using mission defaults.\n", shipp->ship_name));
					}

					// restore hull (but not shields)
					if (ras->hull >= 0.0f && ras->hull <= ship_objp->hull_strength)
						ship_objp->hull_strength = ras->hull;
					else
						mprintf(("Invalid health in red alert data for ship %s. Using mission defaults.\n", shipp->ship_name));

					// restore weapons and subsys
					red_alert_bash_weapons(ras, &shipp->weapons);
					red_alert_bash_subsys_status(ras, shipp);

					ship_data_restored = true;
				}
				// must be destroyed or deleted
				else
				{
					ship_state = ras->ship_class;
				}

				// we won't have two ships with the same name, so bail
				break;
			}
		}

		// remove ship if it was destroyed, or if there's no red-alert data for it
		if ( !ship_data_restored ) {
			// we need to be a little tricky here because deletion invalidates the ship_obj
			ship_obj *next_so = GET_NEXT(so);
			red_alert_delete_ship(shipp, ship_state);
			so = next_so;
		} else {
			so = GET_NEXT(so);
		}
	}

	// NOTE: in retail, red alert data was not loaded for ships that arrived later in the mission
	if (!Red_alert_applies_to_delayed_ships)
		return;

	// go through all ships yet to arrive, and see if there is red alert status data for any

	for ( poii = Parse_objects.begin(); poii != Parse_objects.end(); ++poii )
	{
		p_object *pobjp = &(*poii);

		// objects that have already arrived would have been handled in the above loop
		if ( pobjp->created_object != NULL )
			continue;

		// if we're in a wing, check whether we're in the player wing
		bool from_player_wing = false;
		if (pobjp->wingnum >= 0)
		{
			for (j = 0; j < MAX_STARTING_WINGS; j++)
			{
				if (!stricmp(Starting_wing_names[j], Wings[pobjp->wingnum].name))
				{
					from_player_wing = true;
					break;
				}
			}
		}

		// same condition as in ship_obj loop
		if ( !from_player_wing && !(pobjp->flags & P_SF_RED_ALERT_STORE_STATUS) ) {
			continue;
		}

		bool ship_data_restored = false;
		int ship_state = RED_ALERT_DESTROYED_SHIP_CLASS;

		for ( rasii = Red_alert_wingman_status.begin(); rasii != Red_alert_wingman_status.end(); ++rasii )
		{
			red_alert_ship_status *ras = &(*rasii);

			// red-alert data matches this ship!
			if ( !stricmp(ras->name.c_str(), pobjp->name)  )
			{
				// we only want to restore ships which haven't been destroyed, or were removed by the player
				if ( (ras->ship_class != RED_ALERT_DESTROYED_SHIP_CLASS) && (ras->ship_class != RED_ALERT_PLAYER_DEL_SHIP_CLASS) )
				{
					// if necessary, restore correct ship class
					if ( ras->ship_class != pobjp->ship_class )
					{
						if (ras->ship_class >= 0 && ras->ship_class < MAX_SHIP_CLASSES)
							swap_parse_object(pobjp, ras->ship_class);
						else
						{
							mprintf(("Invalid ship class specified in red alert data for ship %s. Using mission defaults.\n", pobjp->name));
							
							// We will break anyway to this should work
							break;
						}
					}

					// restore hull (but not shields)
					if (ras->hull >= 0.0f && ras->hull <= (pobjp->initial_hull * pobjp->ship_max_hull_strength / 100.0f))
						pobjp->initial_hull = (int) (ras->hull * 100.0f / pobjp->ship_max_hull_strength);
					else
						mprintf(("Invalid health in red alert data for ship %s. Using mission defaults.\n", pobjp->name));

					// restore weapons and subsys
					red_alert_bash_weapons(ras, pobjp);
					red_alert_bash_subsys_status(ras, pobjp);

					ship_data_restored = true;
				}
				// must be destroyed or deleted
				else
				{
					ship_state = ras->ship_class;
				}

				// we won't have two ships with the same name, so bail
				break;
			}
		}

		// remove ship if it was destroyed, or if there's no red-alert data for it
		if ( !ship_data_restored )
		{
			red_alert_delete_ship(pobjp, ship_state);

			if (pobjp->wingnum >= 0)
				Wing_pobjects_deleted[pobjp->wingnum]++;
		}
	}

	// if all parse objects in a wing have been removed, decrement the count for that wing
	for (ii = Wing_pobjects_deleted.begin(); ii != Wing_pobjects_deleted.end(); ++ii)
	{
		wing *wingp = &Wings[ii->first];

		if (wingp->num_waves > 0 && wingp->wave_count == ii->second)
		{			
			wingp->current_wave++;
			wingp->red_alert_skipped_ships += wingp->wave_count;

			if (wingp->num_waves == 0)
			{
				wingp->flags |= WF_WING_GONE;
				wingp->flags |= WF_NEVER_EXISTED;
			}

			// look through all ships yet to arrive...
			for (p_object *pobjp = GET_FIRST(&Ship_arrival_list); pobjp != END_OF_LIST(&Ship_arrival_list); pobjp = GET_NEXT(pobjp))
			{
				// ...and mark the ones in this wing
				if (pobjp->wingnum == ii->first)
				{
					// no waves left to arrive, so mark ships accordingly
					if (wingp->num_waves == 0)
						pobjp->flags |= P_SF_CANNOT_ARRIVE;
					// we skipped one complete wave, so clear the flag so the next wave creates all ships
					else
						pobjp->flags2 &= ~P2_RED_ALERT_DELETED;
				}
			}
		}
	}
}
// Creates a single particle. See the PARTICLE_?? defines for types.
particle *particle_create( particle_info *pinfo )
{
	if ( !Particles_enabled )
	{
		return NULL;
	}

	particle* new_particle = new particle();
	int fps = 1;
	
	new_particle->pos = pinfo->pos;
	new_particle->velocity = pinfo->vel;
	new_particle->age = 0.0f;
	new_particle->max_life = pinfo->lifetime;
	new_particle->radius = pinfo->rad;
	new_particle->type = pinfo->type;
	new_particle->optional_data = pinfo->optional_data;
	new_particle->tracer_length = pinfo->tracer_length;
	new_particle->attached_objnum = pinfo->attached_objnum;
	new_particle->attached_sig = pinfo->attached_sig;
	new_particle->reverse = pinfo->reverse;
	new_particle->particle_index = (int)Particles.size();

	switch (pinfo->type) {
		case PARTICLE_BITMAP:
		case PARTICLE_BITMAP_PERSISTENT: {
			if (pinfo->optional_data < 0) {
				Int3();
				delete new_particle;
				return NULL;
			}

			bm_get_info( pinfo->optional_data, NULL, NULL, NULL, &new_particle->nframes, &fps );

			if ( new_particle->nframes > 1 )	{
				// Recalculate max life for ani's
				new_particle->max_life = i2fl(new_particle->nframes) / i2fl(fps);
			}

			break;
		}

		case PARTICLE_FIRE: {
			if (Anim_bitmap_id_fire < 0) {
				delete new_particle;
				return NULL;
			}

			new_particle->optional_data = Anim_bitmap_id_fire;
			new_particle->nframes = Anim_num_frames_fire;

			break;
		}

		case PARTICLE_SMOKE: {
			if (Anim_bitmap_id_smoke < 0) {
				delete new_particle;
				return NULL;
			}

			new_particle->optional_data = Anim_bitmap_id_smoke;
			new_particle->nframes = Anim_num_frames_smoke;

			break;
		}

		case PARTICLE_SMOKE2: {
			if (Anim_bitmap_id_smoke2 < 0) {
				delete new_particle;
				return NULL;
			}

			new_particle->optional_data = Anim_bitmap_id_smoke2;
			new_particle->nframes = Anim_num_frames_smoke2;

			break;
		}

		default:
			new_particle->nframes = 1;
			break;
	}
	
	new_particle->signature = ++lastSignature;
	Particles.push_back( new_particle );

#ifndef NDEBUG
	if (Particles.size() > (uint)Num_particles_hwm) {
		Num_particles_hwm = (int)Particles.size();

		nprintf(("Particles", "Num_particles high water mark = %i\n", Num_particles_hwm));
	}
#endif

	return Particles.back();
}
Example #18
0
static void find_playback_device()
{
	const char *user_device = os_config_read_string( "Sound", "PlaybackDevice", NULL );
	const char *default_device = (const char*) alcGetString( NULL, ALC_DEFAULT_DEVICE_SPECIFIER );

	// in case they are the same, we only want to test it once
	if ( (user_device && default_device) && !strcmp(user_device, default_device) ) {
		user_device = NULL;
	}

    if ( alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATION_EXT") == AL_TRUE ) {
		const char *all_devices = NULL;

        if ( alcIsExtensionPresent(NULL, (const ALCchar*)"ALC_ENUMERATE_ALL_EXT") == AL_TRUE ) {
			all_devices = (const char*) alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
		} else {
			all_devices = (const char*) alcGetString(NULL, ALC_DEVICE_SPECIFIER);
		}

		const char *str_list = all_devices;
		int ext_length = 0;

		if ( (str_list != NULL) && ((ext_length = strlen(str_list)) > 0) ) {
			while (ext_length) {
				OALdevice new_device(str_list);

				if (user_device && !strcmp(str_list, user_device)) {
					new_device.type = OAL_DEVICE_USER;
				} else if (default_device && !strcmp(str_list, default_device)) {
					new_device.type = OAL_DEVICE_DEFAULT;
				}

				PlaybackDevices.push_back( new_device );

				str_list += (ext_length + 1);
				ext_length = strlen(str_list);
			}
		}
	} else {
		if (default_device) {
			OALdevice new_device(default_device);
			new_device.type = OAL_DEVICE_DEFAULT;

			PlaybackDevices.push_back( new_device );
		}

		if (user_device) {
			OALdevice new_device(user_device);
			new_device.type = OAL_DEVICE_USER;

			PlaybackDevices.push_back( new_device );
		}
	}

	if ( PlaybackDevices.empty() ) {
		return;
	}

	std::sort( PlaybackDevices.begin(), PlaybackDevices.end(), openal_device_sort_func );


	ALCdevice *device = NULL;
	ALCcontext *context = NULL;

	// for each device that we have available, try and figure out which to use
	for (size_t idx = 0; idx < PlaybackDevices.size(); idx++) {
		OALdevice *pdev = &PlaybackDevices[idx];

		// open our specfic device
		device = alcOpenDevice( (const ALCchar*) pdev->device_name.c_str() );

		if (device == NULL) {
			continue;
		}

		context = alcCreateContext(device, NULL);

		if (context == NULL) {
			alcCloseDevice(device);
			continue;
		}

		alcMakeContextCurrent(context);
		alcGetError(device);

		// check how many sources we can create
		static const int MIN_SOURCES = 48;	// MAX_CHANNELS + 16 spare
		int si = 0;

		for (si = 0; si < MIN_SOURCES; si++) {
			ALuint source_id = 0;
			alGenSources(1, &source_id);

			if (alGetError() != AL_NO_ERROR) {
				break;
			}

			alDeleteSources(1, &source_id);
		}

		if (si == MIN_SOURCES) {
			// ok, it supports our minimum requirements
			pdev->usable = true;

			// need this for the future
			Playback_device = pdev->device_name;

			// done
			break;
		} else {
			// clean up for next pass
			alcMakeContextCurrent(NULL);
			alcDestroyContext(context);
			alcCloseDevice(device);

			context = NULL;
			device = NULL;
		}
	}

	alcMakeContextCurrent(NULL);

	if (context) {
		alcDestroyContext(context);
	}

	if (device) {
		alcCloseDevice(device);
	}
}