/** * Called when a ship disengages the afterburners. * * @param *objp pointer to the object starting afterburners * @param key_released OPTIONAL parameter (default value 0) This is only used for the player object, to manage starting/stopping */ void afterburners_stop(object *objp, int key_released) { Assert( objp != NULL ); Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS ); ship_info *sip; ship *shipp; shipp = &Ships[objp->instance]; Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) ); sip = &Ship_info[shipp->ship_info_index]; if ( (objp->flags[Object::Object_Flags::Player_ship]) && key_released ) { objp->phys_info.flags &= ~PF_AFTERBURNER_WAIT; } if ( !(sip->flags[Ship::Info_Flags::Afterburner]) ) { nprintf(("Warning","Ship type %s does not have afterburner capability\n", sip->name)); return; } if ( !(objp->phys_info.flags & PF_AFTERBURNER_ON) ) { return; } Script_system.SetHookObjects(1, "Ship", objp); Script_system.RunCondition(CHA_AFTERBURNEND, 0, NULL, objp); Script_system.RemHookVars(1, "Ship"); objp->phys_info.flags &= ~PF_AFTERBURNER_ON; //Do anim model_anim_start_type(shipp, TRIGGER_TYPE_AFTERBURNER, ANIMATION_SUBTYPE_ALL, -1); if ( objp == Player_obj ) { if ( !key_released ) { snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_FAIL)) ); } if ( Player_afterburner_loop_id > -1 ) { Player_disengage_timer = timestamp(DISENGAGE_TIME); } joy_ff_afterburn_off(); } }
void cmeasure_maybe_alert_success(object *objp) { //Is this a countermeasure, and does it have a parent if ( objp->type != OBJ_WEAPON || objp->parent < 0) { return; } Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags[Weapon::Info_Flags::Cmeasure]); if ( objp->parent == OBJ_INDEX(Player_obj) ) { hud_start_text_flash(XSTR("Evaded", 1430), 800); snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, SND_MISSILE_EVADED_POPUP))); } else if ( Objects[objp->parent].flags[Object::Object_Flags::Player_ship] ) { send_countermeasure_success_packet( objp->parent ); } }
// target the next ship in the escort list void hud_escort_target_next() { int objnum; if ( Num_escort_ships == 0 ) { snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL), 0.0f ); return; } Last_target_index++; if ( Last_target_index >= Num_escort_ships ) { Last_target_index = 0; } objnum = Escort_ships[Last_target_index].objnum; set_target_objnum( Player_ai, objnum); hud_restore_subsystem_target(&Ships[Objects[objnum].instance]); }
void HudGaugeRadarDradis::doLoopSnd() { if (!this->m_loop_snd.isValid()) { return; } if (!this->shouldDoSounds()) { if (loop_sound_handle >= 0 && snd_is_playing(loop_sound_handle)) { snd_stop(loop_sound_handle); loop_sound_handle = -1; } } else if (this->loop_sound_handle < 0 || !snd_is_playing(this->loop_sound_handle)) { loop_sound_handle = snd_play(gamesnd_get_game_sound(m_loop_snd), 0.0f, loop_sound_volume); } }
/** * Start the sequence of a piece of debris writhing in unholy agony!!! */ static void debris_start_death_roll(object *debris_obj, debris *debris_p) { if (debris_p->is_hull) { // tell everyone else to blow up the piece of debris if( MULTIPLAYER_MASTER ) send_debris_update_packet(debris_obj,DEBRIS_UPDATE_NUKE); int fireball_type = fireball_ship_explosion_type(&Ship_info[debris_p->ship_info_index]); if(fireball_type < 0) { fireball_type = FIREBALL_EXPLOSION_LARGE1 + rand()%FIREBALL_NUM_LARGE_EXPLOSIONS; } fireball_create( &debris_obj->pos, fireball_type, FIREBALL_LARGE_EXPLOSION, OBJ_INDEX(debris_obj), debris_obj->radius*1.75f); // only play debris destroy sound if hull piece and it has been around for at least 2 seconds if ( Missiontime > debris_p->time_started + 2*F1_0 ) { snd_play_3d( gamesnd_get_game_sound(SND_MISSILE_IMPACT1), &debris_obj->pos, &View_position, debris_obj->radius ); } } debris_obj->flags.set(Object::Object_Flags::Should_be_dead); }
// ------------------------------------------------------------------ // hud_shield_equalize() // // Equalize all shield quadrants for an object // void hud_shield_equalize(object *objp, player *pl) { float penalty; Assert(objp != NULL); if (objp == NULL) return; Assert(pl != NULL); if (pl == NULL) return; Assert(objp->type == OBJ_SHIP); if (objp->type != OBJ_SHIP) return; // Goober5000 - quick out if we have no shields if (objp->flags[Object::Object_Flags::No_shields]) return; // maybe impose a 2% penalty - server side and single player only if (!MULTIPLAYER_CLIENT && ((pl->shield_penalty_stamp < 0) || timestamp_elapsed_safe(pl->shield_penalty_stamp, 1000)) ) { penalty = 0.02f; // reset the penalty timestamp pl->shield_penalty_stamp = timestamp(1000); } else { penalty = 0.0f; } shield_balance(objp, 1, penalty); // beep if (objp == Player_obj) { snd_play(gamesnd_get_game_sound(SND_SHIELD_XFER_OK)); } }
// ---------------------------------------------------------------------- // hud_add_remove_ship_escort() // void hud_add_remove_ship_escort(int objnum, int supress_feedback) { int in_escort, i; // no ships on the escort list in multiplayer dogfight if(MULTI_DOGFIGHT){ return; } if ( objnum < 0 ) { Int3(); return; } if ( Objects[objnum].type != OBJ_SHIP ) { if ( !supress_feedback ) { snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL)); } return; } in_escort = 0; for ( i = 0; i < Num_escort_ships; i++ ) { if ( Escort_ships[i].obj_signature == Objects[objnum].signature ) { in_escort = 1; break; } } if ( in_escort ) { hud_remove_ship_from_escort_index(i, objnum); return; } hud_add_ship_to_escort(objnum, supress_feedback); }
/** * Do various updates to debris: check if time to die, start fireballs * Maybe delete debris if it's very far away from player. * * @param obj pointer to debris object * @param frame_time time elapsed since last debris_move() called */ void debris_process_post(object * obj, float frame_time) { int i, num; num = obj->instance; int objnum = OBJ_INDEX(obj); Assert( Debris[num].objnum == objnum ); debris *db = &Debris[num]; if ( db->is_hull ) { MONITOR_INC(NumHullDebris,1); radar_plot_object( obj ); if ( timestamp_elapsed(db->sound_delay) ) { obj_snd_assign(objnum, SND_DEBRIS, &vmd_zero_vector, 0); db->sound_delay = 0; } } else { MONITOR_INC(NumSmallDebris,1); } if ( db->lifeleft >= 0.0f) { db->lifeleft -= frame_time; if ( db->lifeleft < 0.0f ) { debris_start_death_roll(obj, db); } } maybe_delete_debris(db); // Make this debris go away if it's very far away. // ================== DO THE ELECTRIC ARCING STUFF ===================== if ( db->arc_frequency <= 0 ) { return; // If arc_frequency <= 0, this piece has no arcs on it } if ( !timestamp_elapsed(db->fire_timeout) && timestamp_elapsed(db->next_fireball)) { db->next_fireball = timestamp_rand(db->arc_frequency,db->arc_frequency*2 ); db->arc_frequency += 100; if (db->is_hull) { int n, n_arcs = ((rand()>>5) % 3)+1; // Create 1-3 sparks vec3d v1, v2, v3, v4; if ( Cmdline_old_collision_sys ) { submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 ); submodel_get_two_random_points( db->model_num, db->submodel_num, &v3, &v4 ); } else { submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 ); submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v3, &v4 ); } n = 0; int a = 100, b = 1000; int lifetime = (myrand()%((b)-(a)+1))+(a); // Create the spark effects for (i=0; i<MAX_DEBRIS_ARCS; i++ ) { if ( !timestamp_valid( db->arc_timestamp[i] ) ) { db->arc_timestamp[i] = timestamp(lifetime); // live up to a second switch( n ) { case 0: db->arc_pts[i][0] = v1; db->arc_pts[i][1] = v2; break; case 1: db->arc_pts[i][0] = v2; db->arc_pts[i][1] = v3; break; case 2: db->arc_pts[i][0] = v2; db->arc_pts[i][1] = v4; break; default: Int3(); } n++; if ( n == n_arcs ) break; // Don't need to create anymore } } // rotate v2 out of local coordinates into world. // Use v2 since it is used in every bolt. See above switch(). vec3d snd_pos; vm_vec_unrotate(&snd_pos, &v2, &obj->orient); vm_vec_add2(&snd_pos, &obj->pos ); //Play a sound effect if ( lifetime > 750 ) { // 1.00 second effect snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius ); } else if ( lifetime > 500 ) { // 0.75 second effect snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius ); } else if ( lifetime > 250 ) { // 0.50 second effect snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius ); } else if ( lifetime > 100 ) { // 0.25 second effect snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius ); } else { // 0.10 second effect snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius ); } }
void shield_transfer(object *objp, int quadrant, float rate) { Assert(objp); Assert(objp->type == OBJ_SHIP); Assert(quadrant >= 0 && quadrant < objp->n_quadrants); Assert((0.0f < rate) && (rate <= 1.0f)); // The energy to Xfer to the quadrant float xfer_amount = shield_get_max_strength(objp) * rate; // The max amount of energy a quad can have float max_quadrant_val = shield_get_max_quad(objp); if ((objp->shield_quadrant[quadrant] + xfer_amount) > max_quadrant_val) { xfer_amount = max_quadrant_val - objp->shield_quadrant[quadrant]; } Assert(xfer_amount >= 0); if (xfer_amount == 0) { // TODO: provide a feedback sound return; } else if (objp == Player_obj) { snd_play(gamesnd_get_game_sound(SND_SHIELD_XFER_OK)); } float energy_avail = 0.0f; // Energy available from the other quadrants that we can transfer for (int i = 0; i < objp->n_quadrants; i++) { if (i == quadrant) continue; energy_avail += objp->shield_quadrant[i]; } // Percent energy to take from each quadrant float percent_to_take = xfer_amount / energy_avail; if (percent_to_take > 1.0f) { percent_to_take = 1.0f; } for (int i = 0; i < objp->n_quadrants; i++) { float delta; if (i == quadrant) { // Don't take energy from our target continue; } delta = percent_to_take * objp->shield_quadrant[i]; objp->shield_quadrant[i] -= delta; Assert(objp->shield_quadrant[i] >= 0); objp->shield_quadrant[quadrant] += delta; if (objp->shield_quadrant[quadrant] > max_quadrant_val) { // Already reached the max quadrant value. Clamp and bail before losing more any energy. objp->shield_quadrant[quadrant] = max_quadrant_val; break; } } }
/** * Called when a ship engages the afterburners. * This function should only be called once when afterburners first start. This is * to start an appropriate sound effect and do any one-time initializations. * * @param *objp pointer to the object starting afterburners */ void afterburners_start(object *objp) { ship_info *sip; ship *shipp; float percent_left; Assert( objp != NULL ); if(objp->type == OBJ_OBSERVER) return; Assert( objp->type == OBJ_SHIP); Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS ); shipp = &Ships[objp->instance]; Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) ); sip = &Ship_info[shipp->ship_info_index]; // bail if afterburners are locked if (shipp->flags[Ship::Ship_Flags::Afterburner_locked]) { return; } if ( (objp->flags[Object::Object_Flags::Player_ship]) && (objp == Player_obj) ) { unsigned int now; now = timer_get_milliseconds(); if ( (now - Player_afterburner_start_time) < 1300 ) { snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_FAIL)) ); return; } if ( objp->phys_info.flags & PF_AFTERBURNER_WAIT ){ return; } } if ( objp->phys_info.flags & PF_AFTERBURNER_ON ) { return; // afterburners are already engaged, nothing to do here } //boosters take precedence if (objp->phys_info.flags & PF_BOOSTER_ON) return; if ( !(sip->flags[Ship::Info_Flags::Afterburner]) ) { return; } // Check if there is enough afterburner fuel if ( (shipp->afterburner_fuel < MIN_AFTERBURNER_FUEL_TO_ENGAGE) && !MULTIPLAYER_CLIENT ) { if ( objp == Player_obj ) { snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_FAIL)) ); } return; } objp->phys_info.flags |= PF_AFTERBURNER_ON; objp->phys_info.afterburner_decay = timestamp(ABURN_DECAY_TIME); percent_left = shipp->afterburner_fuel / sip->afterburner_fuel_capacity; //Do anim model_anim_start_type(shipp, TRIGGER_TYPE_AFTERBURNER, ANIMATION_SUBTYPE_ALL, 1); if ( objp == Player_obj ) { Player_afterburner_start_time = timer_get_milliseconds(); Player_disengage_timer = 1; Player_afterburner_vol = AFTERBURNER_DEFAULT_VOL; if ( percent_left > AFTERBURNER_PERCENT_FOR_LOOP_SND ) { Player_afterburner_loop_delay = timestamp(AFTERBURNER_LOOP_DELAY); } else { Player_afterburner_loop_delay = 0; } snd_play( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_ENGAGE)), 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY ); joy_ff_afterburn_on(); } else { snd_play_3d( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_ENGAGE)), &objp->pos, &View_position, objp->radius ); } Script_system.SetHookObjects(1, "Ship", objp); Script_system.RunCondition(CHA_AFTERBURNSTART, 0, NULL, objp); Script_system.RemHookVars(1, "Ship"); objp->phys_info.flags |= PF_AFTERBURNER_WAIT; }
/** * Update the state of the afterburner fuel remaining for an object using the afterburner. * * For the player ship, key_up_time() is called for the afterburner key to * detect when afterburners disengage. * * @param *objp pointer to the object starting afterburners * @param fl_frametime time in seconds of the last frame */ void afterburners_update(object *objp, float fl_frametime) { Assert( objp != NULL ); Assert( objp->type == OBJ_SHIP ); Assert( objp->instance >= 0 && objp->instance < MAX_SHIPS ); ship_info *sip; ship *shipp; static int volume_chg_timer = 1; shipp = &Ships[objp->instance]; Assert( shipp->ship_info_index >= 0 && shipp->ship_info_index < static_cast<int>(Ship_info.size()) ); sip = &Ship_info[shipp->ship_info_index]; if ( (objp->flags[Object::Object_Flags::Player_ship] ) && (Game_mode & GM_DEAD) ) { return; } if ( !(sip->flags[Ship::Info_Flags::Afterburner]) ) { return; // nothing to update, afterburners are not even on the ship } //shut the afterburners off if we're using the booster tertiary if ( objp->phys_info.flags & PF_BOOSTER_ON) { if (objp==Player_obj) afterburner_stop_sounds(); afterburners_stop(objp); return; } if ( objp == Player_obj ) { if ( !timestamp_elapsed(Player_disengage_timer) ) { float remaining; remaining = timestamp_until(Player_disengage_timer) / i2fl(DISENGAGE_TIME); if ( remaining <= 0 ) { afterburner_stop_sounds(); } else { snd_set_volume( Player_afterburner_loop_id, remaining*Player_afterburner_vol); } } else { if ( Player_disengage_timer != 1 ) { afterburner_stop_sounds(); } } } // single player, multiplayer servers, and clients for their own ships if(!(Game_mode & GM_MULTIPLAYER) || MULTIPLAYER_MASTER || (objp == Player_obj)) { if ( !(objp->phys_info.flags & PF_AFTERBURNER_ON) ) { // Recover afterburner fuel if ( shipp->afterburner_fuel < sip->afterburner_fuel_capacity ) { float recharge_scale; recharge_scale = Energy_levels[shipp->engine_recharge_index] * 2.0f * The_mission.ai_profile->afterburner_recharge_scale[Game_skill_level]; shipp->afterburner_fuel += (sip->afterburner_recover_rate * fl_frametime * recharge_scale); if ( shipp->afterburner_fuel > sip->afterburner_fuel_capacity){ shipp->afterburner_fuel = sip->afterburner_fuel_capacity; } } return; } else { // Check if there is enough afterburner fuel if ( shipp->afterburner_fuel <= 0 ) { shipp->afterburner_fuel = 0.0f; afterburners_stop(objp); return; } } // afterburners are firing at this point // Reduce the afterburner fuel shipp->afterburner_fuel -= (sip->afterburner_burn_rate * fl_frametime); if ( shipp->afterburner_fuel < 0.0f ) { shipp->afterburner_fuel = 0.0f; } } if ( objp == Player_obj ) { if ( timestamp_elapsed(Player_afterburner_loop_delay) ) { Player_afterburner_vol = AFTERBURNER_DEFAULT_VOL; Player_afterburner_loop_delay = 0; if ( Player_afterburner_loop_id == -1 ) { Player_afterburner_loop_id = snd_play_looping( gamesnd_get_game_sound(ship_get_sound(objp, GameSounds::ABURN_LOOP)), 0.0f , -1, -1); snd_set_volume(Player_afterburner_loop_id, Player_afterburner_vol); } } // Reduce the volume of the afterburner sound if near the end if ( timestamp_elapsed(volume_chg_timer) ) { float percent_afterburner_left; percent_afterburner_left = shipp->afterburner_fuel / sip->afterburner_fuel_capacity; volume_chg_timer = timestamp(AFTERBURNER_VOLUME_UPDATE); if ( percent_afterburner_left < AFTERBURNER_PERCENT_VOL_ATTENUATE ) { Player_afterburner_vol = percent_afterburner_left*(1/AFTERBURNER_PERCENT_VOL_ATTENUATE)*AFTERBURNER_DEFAULT_VOL; snd_set_volume(Player_afterburner_loop_id, Player_afterburner_vol); } } // end if (timestamp_elapsed(volume_chg_timer)) } }
// hud_calculate_lock_position() will determine where on the screen to draw the lock // indicator, and will determine when a lock has occurred. If the lock indicator is not // on the screen yet, hud_calculate_lock_start_pos() is called to pick a starting location void hud_calculate_lock_position(float frametime) { ship_weapon *swp; weapon_info *wip; static float pixels_moved_while_locking; static float pixels_moved_while_degrading; static int Need_new_start_pos = 0; static double accumulated_x_pixels, accumulated_y_pixels; double int_portion; static float last_dist_to_target; static int catching_up; static int maintain_lock_count = 0; static float catch_up_distance = 0.0f; double hypotenuse, delta_x, delta_y; swp = &Player_ship->weapons; wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]]; if (Player->target_in_lock_cone) { if (!Players[Player_num].lock_indicator_visible) { hud_calculate_lock_start_pos(); last_dist_to_target = 0.0f; Players[Player_num].lock_indicator_x = Players[Player_num].lock_indicator_start_x; Players[Player_num].lock_indicator_y = Players[Player_num].lock_indicator_start_y; Players[Player_num].lock_indicator_visible = 1; Players[Player_num].lock_time_to_target = i2fl(wip->min_lock_time); catching_up = 0; } Need_new_start_pos = 1; if (Player_ai->current_target_is_locked) { Players[Player_num].lock_indicator_x = Player->current_target_sx; Players[Player_num].lock_indicator_y = Player->current_target_sy; return; } delta_x = Players[Player_num].lock_indicator_x - Player->current_target_sx; delta_y = Players[Player_num].lock_indicator_y - Player->current_target_sy; if (!delta_y && !delta_x) { hypotenuse = 0; } else { hypotenuse = _hypot(delta_y, delta_x); } Players[Player_num].lock_dist_to_target = (float)hypotenuse; if (last_dist_to_target == 0) { last_dist_to_target = Players[Player_num].lock_dist_to_target; } //nprintf(("Alan","dist to target: %.2f\n",Players[Player_num].lock_dist_to_target)); //nprintf(("Alan","last to target: %.2f\n\n",last_dist_to_target)); if (catching_up) { //nprintf(("Alan","IN CATCH UP MODE catch_up_dist is %.2f\n",catch_up_distance)); if ( Players[Player_num].lock_dist_to_target < catch_up_distance ) catching_up = 0; } else { //nprintf(("Alan","IN NORMAL MODE\n")); if ( (Players[Player_num].lock_dist_to_target - last_dist_to_target) > 2.0f ) { catching_up = 1; catch_up_distance = last_dist_to_target + wip->catchup_pixel_penalty; } } last_dist_to_target = Players[Player_num].lock_dist_to_target; if (!catching_up) { Players[Player_num].lock_time_to_target -= frametime; if (Players[Player_num].lock_time_to_target < 0.0f) Players[Player_num].lock_time_to_target = 0.0f; } float lock_pixels_per_sec; if (Players[Player_num].lock_time_to_target > 0) { lock_pixels_per_sec = Players[Player_num].lock_dist_to_target / Players[Player_num].lock_time_to_target; } else { lock_pixels_per_sec = i2fl(wip->lock_pixels_per_sec); } if (lock_pixels_per_sec > wip->lock_pixels_per_sec) { lock_pixels_per_sec = i2fl(wip->lock_pixels_per_sec); } if (catching_up) { pixels_moved_while_locking = wip->catchup_pixels_per_sec * frametime; } else { pixels_moved_while_locking = lock_pixels_per_sec * frametime; } if ((delta_x != 0) && (hypotenuse != 0)) { accumulated_x_pixels += pixels_moved_while_locking * delta_x/hypotenuse; } if ((delta_y != 0) && (hypotenuse != 0)) { accumulated_y_pixels += pixels_moved_while_locking * delta_y/hypotenuse; } if (fl_abs((float)accumulated_x_pixels) > 1.0f) { modf(accumulated_x_pixels, &int_portion); Players[Player_num].lock_indicator_x -= (int)int_portion; if ( fl_abs((float)Players[Player_num].lock_indicator_x - (float)Player->current_target_sx) < fl_abs((float)int_portion) ) Players[Player_num].lock_indicator_x = Player->current_target_sx; accumulated_x_pixels -= int_portion; } if (fl_abs((float)accumulated_y_pixels) > 1.0f) { modf(accumulated_y_pixels, &int_portion); Players[Player_num].lock_indicator_y -= (int)int_portion; if ( fl_abs((float)Players[Player_num].lock_indicator_y - (float)Player->current_target_sy) < fl_abs((float)int_portion) ) Players[Player_num].lock_indicator_y = Player->current_target_sy; accumulated_y_pixels -= int_portion; } if ( Missile_track_loop == -1 ) { if (wip->hud_tracking_snd.isValid()) { Missile_track_loop = snd_play_looping( gamesnd_get_game_sound(wip->hud_tracking_snd), 0.0f , -1, -1); } else { Missile_track_loop = snd_play_looping( gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::MISSILE_TRACKING)), 0.0f , -1, -1); } } if (!Players[Player_num].lock_time_to_target) { if ( (Players[Player_num].lock_indicator_x == Player->current_target_sx) && (Players[Player_num].lock_indicator_y == Player->current_target_sy) ) { if (maintain_lock_count++ > 1) { Player_ai->current_target_is_locked = 1; } } else { maintain_lock_count = 0; } } } else { if ( Missile_track_loop > -1 ) { snd_stop(Missile_track_loop); Missile_track_loop = -1; } Player_ai->current_target_is_locked = 0; if (!Players[Player_num].lock_indicator_visible) { return; } catching_up = 0; last_dist_to_target = 0.0f; if (Need_new_start_pos) { hud_calculate_lock_start_pos(); Need_new_start_pos = 0; accumulated_x_pixels = 0.0f; accumulated_y_pixels = 0.0f; } delta_x = Players[Player_num].lock_indicator_x - Players[Player_num].lock_indicator_start_x; delta_y = Players[Player_num].lock_indicator_y - Players[Player_num].lock_indicator_start_y; if (!delta_y && !delta_x) { hypotenuse = 0; } else { hypotenuse = _hypot(delta_y, delta_x); } Players[Player_num].lock_time_to_target += frametime; if (Players[Player_num].lock_time_to_target > wip->min_lock_time) Players[Player_num].lock_time_to_target = i2fl(wip->min_lock_time); pixels_moved_while_degrading = 2.0f * wip->lock_pixels_per_sec * frametime; if ((delta_x != 0) && (hypotenuse != 0)) accumulated_x_pixels += pixels_moved_while_degrading * delta_x/hypotenuse; if ((delta_y != 0) && (hypotenuse != 0)) accumulated_y_pixels += pixels_moved_while_degrading * delta_y/hypotenuse; if (fl_abs((float)accumulated_x_pixels) > 1.0f) { modf(accumulated_x_pixels, &int_portion); Players[Player_num].lock_indicator_x -= (int)int_portion; if ( fl_abs((float)Players[Player_num].lock_indicator_x - (float)Players[Player_num].lock_indicator_start_x) < fl_abs((float)int_portion) ) Players[Player_num].lock_indicator_x = Players[Player_num].lock_indicator_start_x; accumulated_x_pixels -= int_portion; } if (fl_abs((float)accumulated_y_pixels) > 1.0f) { modf(accumulated_y_pixels, &int_portion); Players[Player_num].lock_indicator_y -= (int)int_portion; if ( fl_abs((float)Players[Player_num].lock_indicator_y - (float)Players[Player_num].lock_indicator_start_y) < fl_abs((float)int_portion) ) Players[Player_num].lock_indicator_y = Players[Player_num].lock_indicator_start_y; accumulated_y_pixels -= int_portion; } if ( (Players[Player_num].lock_indicator_x == Players[Player_num].lock_indicator_start_x) && (Players[Player_num].lock_indicator_y == Players[Player_num].lock_indicator_start_y) ) { Players[Player_num].lock_indicator_visible = 0; } } }
// hud_do_lock_indicator() manages missle locking, both the non-rendering calculations and the 2D HUD rendering void hud_do_lock_indicator(float frametime) { ship_weapon *swp; weapon_info *wip; // if i'm a multiplayer observer, bail here if((Game_mode & GM_MULTIPLAYER) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){ return; } Assert(Player_ai->target_objnum >= 0); // be sure to unset this flag, then possibly set later in this function so that // threat indicators work properly. Player_ai->ai_flags.remove(AI::AI_Flags::Seek_lock); if ( hud_abort_lock() ) { hud_lock_reset(); return; } // if there is an EMP effect active, never update lock if(emp_active_local()){ hud_lock_reset(); return; } swp = &Player_ship->weapons; wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]]; Lock_start_dist = wip->min_lock_time * wip->lock_pixels_per_sec; // if secondary weapons change, reset the lock if ( hud_lock_secondary_weapon_changed(swp) ) { hud_lock_reset(); } Player_ai->last_secondary_index = swp->current_secondary_bank; object *tobjp = &Objects[Player_ai->target_objnum]; vec3d dir_to_target; vm_vec_normalized_dir(&dir_to_target, &tobjp->pos, &Player_obj->pos); if ( !(wip->is_locked_homing()) ) { hud_lock_reset(); return; } // Allow locking on ships and bombs (only targeted weapon allowed is a bomb, so don't bother checking flags) if ( (Objects[Player_ai->target_objnum].type != OBJ_SHIP) && (Objects[Player_ai->target_objnum].type != OBJ_WEAPON) ) { hud_lock_reset(); return; } // Javelins must lock on engines if locking on a ship and those must be in sight if (wip->wi_flags[Weapon::Info_Flags::Homing_javelin] && tobjp->type == OBJ_SHIP && Player->locking_subsys != NULL) { vec3d subobj_pos; vm_vec_unrotate(&subobj_pos, &Player->locking_subsys->system_info->pnt, &tobjp->orient); vm_vec_add2(&subobj_pos, &tobjp->pos); int target_subsys_in_sight = ship_subsystem_in_sight(tobjp, Player->locking_subsys, &Player_obj->pos, &subobj_pos); if (!target_subsys_in_sight || Player->locking_subsys->system_info->type != SUBSYSTEM_ENGINE) { Player->locking_subsys = ship_get_closest_subsys_in_sight(&Ships[tobjp->instance], SUBSYSTEM_ENGINE, &Player_obj->pos); } } if (wip->wi_flags[Weapon::Info_Flags::Homing_javelin] && tobjp->type == OBJ_SHIP && Player->locking_subsys == NULL) { Player->locking_subsys = ship_get_closest_subsys_in_sight(&Ships[tobjp->instance], SUBSYSTEM_ENGINE, &Player_obj->pos); if (Player->locking_subsys == NULL) { hud_lock_reset(); return; } } hud_lock_determine_lock_point(&lock_world_pos); if ( !hud_lock_has_homing_point() ) { Player->target_in_lock_cone=0; } hud_lock_check_if_target_in_lock_cone(); // check if the target is within range of the current secondary weapon. If it is not, // a lock will not be detected if ( !hud_lock_target_in_range() ) { Player->target_in_lock_cone = 0; } // If locking on a subsystem, and not in sight... can't lock // Changed by MK on 4/3/98. It was confusing me that my hornets would not lock on my target. // It will now be confusing that they lock, but don't home on your subsystem, but I think that's preferable. // Often you really care about destroying the target, not just the subsystem. /*if ( Player_ai->targeted_subsys ) { if ( !hud_lock_on_subsys_ok() ) { Player->target_in_lock_cone=0; } }*/ if ( !Player->target_in_lock_cone ) { Player->locking_on_center=0; Player->locking_subsys_parent=-1; Player->locking_subsys=NULL; } hud_calculate_lock_position(frametime); if (!Players[Player_num].lock_indicator_visible) return; if (Player_ai->current_target_is_locked) { if ( Missile_track_loop > -1 ) { snd_stop(Missile_track_loop); Missile_track_loop = -1; if (wip->hud_locked_snd.isValid()) { Missile_lock_loop = snd_play(gamesnd_get_game_sound(wip->hud_locked_snd)); } else { Missile_lock_loop = snd_play(gamesnd_get_game_sound(ship_get_sound(Player_obj, GameSounds::MISSILE_LOCK))); } } } else { Player_ai->ai_flags.set(AI::AI_Flags::Seek_lock); // set this flag so multiplayer's properly track lock on other ships if ( Missile_lock_loop != -1 && snd_is_playing(Missile_lock_loop) ) { snd_stop(Missile_lock_loop); Missile_lock_loop = -1; } } }
void HudGaugeRadarDradis::doBeeps() { if (!this->shouldDoSounds()) { return; } if (Missiontime == 0 || Missiontime == Frametime) { // don't play sounds in first frame return; } if (!arrival_beep_snd.isValid() && !departure_beep_snd.isValid() && !m_stealth_arrival_snd.isValid() && !stealth_departure_snd.isValid()) { return; } bool departure_happened = false; bool stealth_departure_happened = false; bool arrival_happened = false; bool stealth_arrival_happened = false; for (int i = 0; i < MAX_SHIPS; i++) { ship * shipp = &Ships[i]; if (shipp->objnum >= 0) { if (shipp->radar_visible_since >= 0 || shipp->radar_last_contact >= 0) { if (shipp->radar_visible_since == Missiontime) { if (shipp->radar_current_status == DISTORTED) { stealth_arrival_happened = true; } else { arrival_happened = true; } } else if (shipp->radar_visible_since < 0 && shipp->radar_last_contact == Missiontime) { if (shipp->radar_last_status == DISTORTED) { stealth_departure_happened = true; } else { departure_happened = true; } } } } } if (timestamp_elapsed(arrival_beep_next_check)) { if (arrival_beep_snd.isValid() && arrival_happened) { snd_play(gamesnd_get_game_sound(arrival_beep_snd)); arrival_beep_next_check = timestamp(arrival_beep_delay); } else if (m_stealth_arrival_snd.isValid() && stealth_arrival_happened) { snd_play(gamesnd_get_game_sound(m_stealth_arrival_snd)); arrival_beep_next_check = timestamp(arrival_beep_delay); } } if (timestamp_elapsed(departure_beep_next_check)) { if (departure_beep_snd.isValid() && departure_happened) { snd_play(gamesnd_get_game_sound(departure_beep_snd)); departure_beep_next_check = timestamp(departure_beep_delay); } else if (stealth_departure_snd.isValid() && stealth_departure_happened) { snd_play(gamesnd_get_game_sound(stealth_departure_snd)); departure_beep_next_check = timestamp(departure_beep_delay); } } }
void HudGaugeRadarDradis::render(float /*frametime*/) { float sensors_str; int ok_to_blit_radar; ok_to_blit_radar = 1; sensors_str = ship_get_subsystem_strength(Player_ship, SUBSYSTEM_SENSORS); if (ship_subsys_disrupted(Player_ship, SUBSYSTEM_SENSORS)) sensors_str = MIN_SENSOR_STR_TO_RADAR - 1; // note that on lowest skill level, there is no radar effects due to sensors damage if ((Game_skill_level == 0) || (sensors_str > SENSOR_STR_RADAR_NO_EFFECTS)) { Radar_static_playing = 0; Radar_static_next = 0; Radar_death_timer = 0; Radar_avail_prev_frame = 1; } else if (sensors_str < MIN_SENSOR_STR_TO_RADAR) { if (Radar_avail_prev_frame) { Radar_death_timer = timestamp(2000); Radar_static_next = 1; } Radar_avail_prev_frame = 0; } else { Radar_death_timer = 0; if (Radar_static_next == 0) Radar_static_next = 1; } if (timestamp_elapsed(Radar_death_timer)) ok_to_blit_radar = 0; setupViewHtl(); //WMC - This strikes me as a bit hackish bool g3_yourself = !g3_in_frame(); if(g3_yourself) g3_start_frame(1); drawSweeps(); if (timestamp_elapsed(Radar_static_next)) { Radar_static_playing ^= 1; Radar_static_next = timestamp_rand(50, 750); } // if the emp effect is active, always draw the radar wackily if (emp_active_local()) Radar_static_playing = 1; if (ok_to_blit_radar) { if (Radar_static_playing) { drawBlipsSorted(1); // passing 1 means to draw distorted if (Radar_static_looping == -1) Radar_static_looping = snd_play_looping(gamesnd_get_game_sound(GameSounds::STATIC)); } else { drawBlipsSorted(0); if (Radar_static_looping != -1) { snd_stop(Radar_static_looping); Radar_static_looping = -1; } } } else { if (Radar_static_looping != -1) { snd_stop(Radar_static_looping); Radar_static_looping = -1; } } if(g3_yourself) g3_end_frame(); doneDrawingHtl(); }
// try to add a ship to the escort list, if slot available void hud_add_ship_to_escort(int objnum, int supress_feedback) { escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST]; int num_complete_escorts, idx, found; // get complete escort list hud_create_complete_escort_list(complete_escorts, &num_complete_escorts); // ensure the complete escort list is not full already if (num_complete_escorts == MAX_COMPLETE_ESCORT_LIST) { return; } // check if ship is already on complete escort list found = 0; for (idx=0; idx<num_complete_escorts; idx++) { if (complete_escorts[idx].obj_signature == Objects[objnum].signature) { found = 1; break; } } // add new ship into complete list if ( !found ) { complete_escorts[num_complete_escorts].objnum = objnum; complete_escorts[num_complete_escorts].obj_signature = Objects[objnum].signature; complete_escorts[num_complete_escorts].priority = Ships[Objects[objnum].instance].escort_priority; complete_escorts[num_complete_escorts].escort_hit_timer = 0; complete_escorts[num_complete_escorts].escort_hit_next_flash = 0; complete_escorts[num_complete_escorts].escort_show_bright = false; // add him to escort list Ships[Objects[objnum].instance].flags.set(Ship::Ship_Flags::Escort); num_complete_escorts++; } // sort escort list by priority insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func); // merge list merge_escort_lists(complete_escorts, num_complete_escorts); // maybe do feedback if ( (Num_escort_ships == Max_escort_ships) && !supress_feedback) { found = 0; // search thru list for objnum for (idx=0; idx<Num_escort_ships; idx++) { if (Escort_ships[idx].objnum == objnum) { found = 1; break; } } if (!found) { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), Num_escort_ships); snd_play( gamesnd_get_game_sound(GameSounds::TARGET_FAIL)); } } hud_gauge_popup_start(HUD_ESCORT_VIEW); }