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; } }
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; } }
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; }
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; } }
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; } }
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; }
// 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(); }
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); } }