/** * 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); }
// ---------------------------------------------------------------------------- // afterburners_start() will be 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. // // parameters: *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 < Num_ship_classes); sip = &Ship_info[shipp->ship_info_index]; // When the ship has no afterburner, leave without doing anything. // Caller should have tested ship equipment before deciding to start afterburners. if (!(sip->flags & SIF_AFTERBURNER)) { nprintf(("Warning", "Ship type %s does not have afterburner capability\n", sip->name)); return; } // bail if afterburners are locked if (shipp->flags2 & SF2_AFTERBURNER_LOCKED) { return; } if (objp->phys_info.flags & PF_GLIDING) { return; } if ((objp->flags & OF_PLAYER_SHIP) && (objp == Player_obj)) { unsigned int now; now = timer_get_milliseconds(); if ((now - Player_afterburner_start_time) < 1300) { if (Viewer_mode & VM_NOT_COCKPIT) { snd_play_3d(&Snds[SND_ABURN_FAIL], &objp->pos, &View_position, objp->radius); } else { snd_play(&Snds[SND_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; // Check if there is enough afterburner fuel if ((shipp->afterburner_fuel < MIN_AFTERBURNER_FUEL_TO_ENGAGE) && !MULTIPLAYER_CLIENT) { if (objp == Player_obj) { if (Viewer_mode & VM_NOT_COCKPIT) { snd_play_3d(&Snds[SND_ABURN_FAIL], &objp->pos, &View_position, objp->radius); } else { snd_play(&Snds[SND_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 = Snds[SND_ABURN_LOOP].default_volume; snd_set_volume(Player_afterburner_loop_id, Player_afterburner_vol); if (percent_left > AFTERBURNER_PERCENT_FOR_LOOP_SND) { Player_afterburner_loop_delay = timestamp(AFTERBURNER_LOOP_DELAY); } else { Player_afterburner_loop_delay = 0; } if (Viewer_mode & VM_NOT_COCKPIT) { snd_play_3d(&Snds[SND_ABURN_ENGAGE], &objp->pos, &View_position, objp->radius); } else { snd_play(&Snds[SND_ABURN_ENGAGE], 0.0f, 1.0f, SND_PRIORITY_MUST_PLAY); } joy_ff_afterburn_on(); } else { snd_play_3d(&Snds[SND_ABURN_ENGAGE], &objp->pos, &View_position, objp->radius); } objp->phys_info.flags |= PF_AFTERBURNER_WAIT; }
/** * 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 ); } }
/** * 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; }