void digi_play_sample_3d( int sndnum, int angle, int volume, int no_dups ) { int vol; int i = sndnum, demo_angle; if (Newdemo_state == ND_STATE_RECORDING) { demo_angle = fixmuldiv(angle, F1_0, 255); if (no_dups) newdemo_record_sound_3d_once(sndnum, demo_angle, volume); else newdemo_record_sound_3d(sndnum, demo_angle, volume); } if (!digi_initialized) return; if (digi_paused) { digi_resume_all(); if (digi_paused) return; } if ( sndnum < 0 ) return; i = digi_xlat_sound(sndnum); if (i == -1) return; vol = fixmuldiv(volume, digi_volume, F1_0); ChangeSoundVolume( i, vol ); BeginSound(i, SOUND_RATE_11k); ChangeSoundStereoPosition(i, angle); }
void digi_start_sound_object(int i) { int vol; if (!digi_initialized) return; vol = fixmuldiv(SoundObjects[i].volume, digi_volume, F1_0); ChangeSoundVolume(SoundObjects[i].soundnum, fixmuldiv(SoundObjects[i].volume, digi_volume, F1_0)); BeginSoundLoop( SoundObjects[i].soundnum, SOUND_RATE_11k, 1, GetSoundLength(SoundObjects[i].soundnum) ); ChangeSoundStereoPosition(SoundObjects[i].soundnum, SoundObjects[i].pan); SoundObjects[i].flags |= SOF_PLAYING; }
//from a 2d point, compute the vector through that point void g3_point_2_vec(vms_vector *v, short sx, short sy) { vms_vector tempv; vms_matrix tempm; tempv.x = fixmuldiv(fixdiv((sx << 16) - Canv_w2, Canv_w2), Matrix_scale.z, Matrix_scale.x); tempv.y = -fixmuldiv(fixdiv((sy << 16) - Canv_h2, Canv_h2), Matrix_scale.z, Matrix_scale.y); tempv.z = f1_0; vm_vec_normalize(&tempv); vm_copy_transpose_matrix(&tempm, &Unscaled_matrix); vm_vec_rotate(v, &tempv, &tempm); }
//start the frame void g3_start_frame(void) { fix s; //set int w,h & fixed-point w,h/2 Canv_w2 = (Canvas_width = grd_curcanv->cv_bitmap.bm_w)<<15; Canv_h2 = (Canvas_height = grd_curcanv->cv_bitmap.bm_h)<<15; #ifdef __powerc fCanv_w2 = f2fl((Canvas_width = grd_curcanv->cv_bitmap.bm_w)<<15); fCanv_h2 = f2fl((Canvas_height = grd_curcanv->cv_bitmap.bm_h)<<15); #endif //compute aspect ratio for this canvas s = fixmuldiv(grd_curscreen->sc_aspect,Canvas_height,Canvas_width); if (s <= f1_0) { //scale x Window_scale.x = s; Window_scale.y = f1_0; } else { Window_scale.y = fixdiv(f1_0,s); Window_scale.x = f1_0; } Window_scale.z = f1_0; //always 1 #if DXX_USE_OGL ogl_start_frame(); #else init_interface_vars_to_assembler(); //for the texture-mapper #endif }
//draws the given model in the current canvas. The distance is set to //more-or-less fill the canvas. Note that this routine actually renders //into an off-screen canvas that it creates, then copies to the current //canvas. void draw_model_picture(int mn,vms_angvec *orient_angles) { vms_vector temp_pos=ZERO_VECTOR; vms_matrix temp_orient = IDENTITY_MATRIX; grs_canvas *save_canv = grd_curcanv,*temp_canv; Assert(mn>=0 && mn<N_polygon_models); temp_canv = gr_create_canvas(save_canv->cv_bitmap.bm_w,save_canv->cv_bitmap.bm_h); gr_set_current_canvas(temp_canv); gr_clear_canvas( BM_XRGB(0,0,0) ); g3_start_frame(); g3_set_view_matrix(&temp_pos,&temp_orient,0x9000); if (Polygon_models[mn].rad != 0) temp_pos.z = fixmuldiv(DEFAULT_VIEW_DIST,Polygon_models[mn].rad,BASE_MODEL_SIZE); else temp_pos.z = DEFAULT_VIEW_DIST; vm_angles_2_matrix(&temp_orient, orient_angles); PA_DFX(save_light = Lighting_on); PA_DFX(Lighting_on = 0); draw_polygon_model(&temp_pos,&temp_orient,NULL,mn,0,f1_0,NULL,NULL); PA_DFX (Lighting_on = save_light); gr_set_current_canvas(save_canv); gr_bitmap(0,0,&temp_canv->cv_bitmap); gr_free_canvas(temp_canv); }
//stop the redbook, so we can read off the CD void songs_stop_redbook(void) { int old_volume = GameCfg.MusicVolume*REDBOOK_VOLUME_SCALE/8; fix old_time = timer_get_fixed_seconds(); if (Redbook_playing) { //fade out volume int new_volume; do { fix t = timer_get_fixed_seconds(); new_volume = fixmuldiv(old_volume,(FADE_TIME - (t-old_time)),FADE_TIME); if (new_volume < 0) new_volume = 0; RBASetVolume(new_volume); } while (new_volume > 0); } RBAStop(); // Stop CD, if playing RBASetVolume(old_volume); //restore volume Redbook_playing = 0; }
void joy_set_btn_values( int btn, int state, fix timedown, int downcount, int upcount ) { joystick.buttons[btn].ignore = 1; joystick.buttons[btn].state = state; joystick.buttons[btn].timedown = fixmuldiv( timedown, 1193180, 65536 ); joystick.buttons[btn].downcount = downcount; joystick.buttons[btn].upcount = upcount; }
void digi_set_channel_volume(int channel, int volume) { if (!digi_initialised) return; LOCK(); if (SoundSlots[channel].playing) SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0); UNLOCK(); }
void digi_audio_set_channel_volume(int channel, int volume) { if (!digi_initialised) return; if (!SoundSlots[channel].playing) return; SoundSlots[channel].volume = fixmuldiv(volume, digi_volume, F1_0); }
//this routine will set the thrust for an object to a value that will //(hopefully) maintain the object's current velocity void set_thrust_from_velocity(object *obj) { fix k; Assert(obj->movement_type == MT_PHYSICS); k = fixmuldiv(obj->mtype.phys_info.mass,obj->mtype.phys_info.drag,(f1_0-obj->mtype.phys_info.drag)); vm_vec_copy_scale(&obj->mtype.phys_info.thrust,&obj->mtype.phys_info.velocity,k); }
object *object_create_debris(object *parent, int subobj_num) { int objnum; object *obj; polymodel *po; Assert((parent->type == OBJ_ROBOT) || (parent->type == OBJ_PLAYER) ); objnum = obj_create(OBJ_DEBRIS,0,parent->segnum,&parent->pos, &parent->orient,Polygon_models[parent->rtype.pobj_info.model_num].submodel_rads[subobj_num], CT_DEBRIS,MT_PHYSICS,RT_POLYOBJ); if ((objnum < 0 ) && (Highest_object_index >= MAX_OBJECTS-1)) { mprintf((1, "Can't create object in object_create_debris.\n")); Int3(); return NULL; } if ( objnum < 0 ) return NULL; // Not enough debris slots! obj = &Objects[objnum]; Assert(subobj_num < 32); //Set polygon-object-specific data obj->rtype.pobj_info.model_num = parent->rtype.pobj_info.model_num; obj->rtype.pobj_info.subobj_flags = 1<<subobj_num; obj->rtype.pobj_info.tmap_override = parent->rtype.pobj_info.tmap_override; //Set physics data for this object po = &Polygon_models[obj->rtype.pobj_info.model_num]; obj->mtype.phys_info.velocity.x = RAND_MAX/2 - rand(); obj->mtype.phys_info.velocity.y = RAND_MAX/2 - rand(); obj->mtype.phys_info.velocity.z = RAND_MAX/2 - rand(); vm_vec_normalize_quick(&obj->mtype.phys_info.velocity); vm_vec_scale(&obj->mtype.phys_info.velocity,i2f(10 + (30 * rand() / RAND_MAX))); vm_vec_add2(&obj->mtype.phys_info.velocity,&parent->mtype.phys_info.velocity); vm_vec_make(&obj->mtype.phys_info.rotvel,10*0x2000/3,10*0x4000/3,10*0x7000/3); vm_vec_zero(&obj->mtype.phys_info.rotthrust); obj->lifeleft = DEBRIS_LIFE; obj->mtype.phys_info.mass = fixmuldiv(parent->mtype.phys_info.mass,obj->size,parent->size); obj->mtype.phys_info.drag = 0; //fl2f(0.2); //parent->mtype.phys_info.drag; return obj; }
//added on 980905 by adb from original source to make sfx volume work void digi_audio_set_digi_volume( int dvolume ) { dvolume = fixmuldiv( dvolume, SOUND_MAX_VOLUME, 0x7fff); if ( dvolume > SOUND_MAX_VOLUME ) digi_volume = SOUND_MAX_VOLUME; else if ( dvolume < 0 ) digi_volume = 0; else digi_volume = dvolume; if ( !digi_initialised ) return; digi_sync_sounds(); }
//draws the given model in the current canvas. The distance is set to //more-or-less fill the canvas. Note that this routine actually renders //into an off-screen canvas that it creates, then copies to the current //canvas. void draw_model_picture(int mn,vms_angvec *orient_angles) { vms_vector temp_pos=ZERO_VECTOR; vms_matrix temp_orient = IDENTITY_MATRIX; Assert(mn>=0 && mn<N_polygon_models); gr_clear_canvas( BM_XRGB(0,0,0) ); g3_start_frame(); g3_set_view_matrix(&temp_pos,&temp_orient,0x9000); if (Polygon_models[mn].rad != 0) temp_pos.z = fixmuldiv(DEFAULT_VIEW_DIST,Polygon_models[mn].rad,BASE_MODEL_SIZE); else temp_pos.z = DEFAULT_VIEW_DIST; vm_angles_2_matrix(&temp_orient, orient_angles); draw_polygon_model(&temp_pos,&temp_orient,NULL,mn,0,f1_0,NULL,NULL); g3_end_frame(); }
//stop the redbook, so we can read off the CD void songs_stop_redbook(void) { int old_volume = gameConfig.nRedbookVolume*REDBOOK_VOLUME_SCALE/8; fix old_time = TimerGetFixedSeconds(); if (gameStates.sound.bRedbookPlaying) { //fade out volume int new_volume; do { fix t = TimerGetFixedSeconds(); new_volume = fixmuldiv(old_volume,(FADE_TIME - (t-old_time)),FADE_TIME); if (new_volume < 0) new_volume = 0; RBASetVolume(new_volume); } while (new_volume > 0); } RBAStop(); // Stop CD, if playing RBASetVolume(old_volume); //restore volume gameStates.sound.bRedbookPlaying = 0; }
void digi_get_sound_loc( vms_matrix * listener, vms_vector * listener_pos, int listener_seg, vms_vector * sound_pos, int sound_seg, fix max_volume, int *volume, int *pan, fix max_distance ) { vms_vector vector_to_sound; fix angle_from_ear, cosang,sinang; fix distance; fix path_distance; *volume = 0; *pan = 0; if (!digi_initialized) return; max_distance = (max_distance*5)/4; // Make all sounds travel 1.25 times as far. // Warning: Made the vm_vec_normalized_dir be vm_vec_normalized_dir_quick and got illegal values to acos in the fang computation. distance = vm_vec_normalized_dir_quick( &vector_to_sound, sound_pos, listener_pos ); if (distance < max_distance ) { int num_search_segs = f2i(max_distance/20); if ( num_search_segs < 1 ) num_search_segs = 1; path_distance = find_connected_distance(listener_pos, listener_seg, sound_pos, sound_seg, num_search_segs, WID_RENDPAST_FLAG ); //path_distance = distance; if ( path_distance > -1 ) { *volume = max_volume - (path_distance/f2i(max_distance)); //mprintf( (0, "Sound path distance %.2f, volume is %d / %d\n", f2fl(distance), *volume, max_volume )); if (*volume > 0 ) { angle_from_ear = vm_vec_delta_ang_norm(&listener->rvec,&vector_to_sound,&listener->uvec); fix_sincos(angle_from_ear,&sinang,&cosang); //mprintf( (0, "volume is %.2f\n", f2fl(*volume) )); if (Config_channels_reversed) cosang *= -1; *pan = fixmuldiv(cosang, 255, F1_0); } else { *volume = 0; } } } }
void Tactile_apply_force (vms_vector *force_vec,vms_matrix *orient) { int feedforce; fix feedmag,tempfix=0; vms_angvec feedang; vms_vector feedvec; unsigned short tempangle; int realangle; if (TactileStick==TACTILE_IMMERSION) { vm_vec_rotate (&feedvec,force_vec,orient); vm_extract_angles_vector(&feedang,&feedvec); feedmag=vm_vec_mag_quick (force_vec); feedforce=f2i(fixmuldiv (feedmag,i2f(100),MAX_FORCE)); mprintf ((0,"feedforce=%d\n",feedforce)); if (feedforce<0) feedforce=0; if (feedforce>100) feedforce=100; tempangle=(unsigned short)feedang.h; tempfix=tempangle; realangle=f2i(fixmul(tempfix,i2f(360))); realangle-=180; if (realangle<0) realangle+=360; Jolt (feedforce,realangle,feedforce*7); } }
void digi_play_sample( int sndnum, fix max_volume ) { OSErr err; int i, vol; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_sound(sndnum); if (!digi_initialized) return; if (digi_paused) { digi_resume_all(); if (digi_paused) return; } if ( sndnum < 0 ) return; i = digi_xlat_sound(sndnum); if (i == -1) return; vol = fixmuldiv(max_volume, digi_volume, F1_0); ChangeSoundVolume(i, vol ); err = BeginSound(i, SOUND_RATE_11k); ChangeSoundStereoPosition(i, 0); }
void digi_sync_sounds() { int i; int oldvolume, oldpan; SndCommand snd_cmd; if (!digi_initialized) return; for (i=0; i<MAX_SOUND_OBJECTS; i++ ) { if ( SoundObjects[i].flags & SOF_USED ) { oldvolume = SoundObjects[i].volume; oldpan = SoundObjects[i].pan; if ( !(SoundObjects[i].flags & SOF_PLAY_FOREVER) ) { // Check if its done. if (SoundObjects[i].flags & SOF_PLAYING) { if ( IsThisSoundFXFinished(SoundObjects[i].soundnum) ) { SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound continue; // Go on to next sound... } } } if ( SoundObjects[i].flags & SOF_LINK_TO_POS ) { digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &SoundObjects[i].link_type.pos.position, SoundObjects[i].link_type.pos.segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ ) { object * objp; objp = &Objects[SoundObjects[i].link_type.obj.objnum]; if ((objp->type==OBJ_NONE) || (objp->signature!=SoundObjects[i].link_type.obj.objsignature)) { // The object that this is linked to is dead, so just end this sound if it is looping. if ( (SoundObjects[i].flags & SOF_PLAYING) && (SoundObjects[i].flags & SOF_PLAY_FOREVER)) { EndSound(SoundObjects[i].soundnum); } SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound continue; // Go on to next sound... } else { digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &objp->pos, objp->segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); } } if (oldvolume != SoundObjects[i].volume) { if ( SoundObjects[i].volume < 1 ) { // Sound is too far away, so stop it from playing. if ((SoundObjects[i].flags & SOF_PLAYING)&&(SoundObjects[i].flags & SOF_PLAY_FOREVER)) { EndSound(SoundObjects[i].soundnum); SoundObjects[i].flags &= ~SOF_PLAYING; // Mark sound as not playing } } else { if (!(SoundObjects[i].flags & SOF_PLAYING)) { digi_start_sound_object(i); } else { int vol; vol = fixmuldiv(SoundObjects[i].volume, digi_volume,F1_0); ChangeSoundVolume(SoundObjects[i].soundnum, fixmuldiv(SoundObjects[i].volume,digi_volume,F1_0) ); } } } if (oldpan != SoundObjects[i].pan) { if (SoundObjects[i].flags & SOF_PLAYING) { ChangeSoundStereoPosition( SoundObjects[i].soundnum, SoundObjects[i].pan ); } } } } }
// ----------------------------------------------------------------------------------------------------------- //Simulate a physics object for this frame void do_physics_sim(object *obj) { int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs; int iseg; int try_again; int fate=0; vms_vector frame_vec; //movement in this frame vms_vector new_pos,ipos; //position after this frame int count=0; int objnum; int WallHitSeg, WallHitSide; fvi_info hit_info; fvi_query fq; vms_vector save_pos; int save_seg; fix drag; fix sim_time; vms_vector start_pos; int obj_stopped=0; fix moved_time; //how long objected moved before hit something physics_info *pi; int orig_segnum = obj->segnum; fix PhysTime = (FrameTime<F1_0/30?F1_0/30:FrameTime); Assert(obj->movement_type == MT_PHYSICS); #ifndef NDEBUG if (Dont_move_ai_objects) if (obj->control_type == CT_AI) return; #endif pi = &obj->mtype.phys_info; do_physics_sim_rot(obj); if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z)) return; objnum = obj-Objects; n_phys_segs = 0; /* As this engine was not designed for that high FPS as we intend, we use F1_0/30 max. for sim_time to ensure scaling and dot products stay accurate and reliable. The object position intended for this frame will be scaled down later, after the main collision-loop is done. This won't make collision results be equal in all FPS settings, but hopefully more accurate, the higher our FPS are. */ sim_time = PhysTime; //FrameTime; //debug_obj = obj; #ifdef EXTRA_DEBUG //check for correct object segment if(!get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask==0) { //Int3(); Removed by Rob 10/5/94 if (!update_object_seg(obj)) { if (!(Game_mode & GM_MULTI)) Int3(); compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } } #endif start_pos = obj->pos; n_ignore_objs = 0; Assert(obj->mtype.phys_info.brakes==0); //brakes not used anymore? //if uses thrust, cannot have zero drag Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0); //do thrust & drag // NOTE: this always must be dependent on FrameTime, if sim_time differs! if ((drag = obj->mtype.phys_info.drag) != 0) { int count; vms_vector accel; fix r,k,have_accel; count = FrameTime / FT; r = FrameTime % FT; k = fixdiv(r,FT); if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass)); have_accel = (accel.x || accel.y || accel.z); while (count--) { if (have_accel) vm_vec_add2(&obj->mtype.phys_info.velocity,&accel); vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag); } //do linear scale on remaining bit of time vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k); if (drag) vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag)); } else if (drag) { fix total_drag=f1_0; while (count--) total_drag = fixmul(total_drag,f1_0-drag); //do linear scale on remaining bit of time total_drag = fixmul(total_drag,f1_0-fixmul(k,drag)); vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag); } } do { try_again = 0; //Move the object vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time); if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) ) break; count++; // If retry count is getting large, then we are trying to do something stupid. if (count > 8) break; // in original code this was 3 for all non-player objects. still leave us some limit in case fvi goes apeshit. vm_vec_add(&new_pos,&obj->pos,&frame_vec); ignore_obj_list[n_ignore_objs] = -1; fq.p0 = &obj->pos; fq.startseg = obj->segnum; fq.p1 = &new_pos; fq.rad = obj->size; fq.thisobjnum = objnum; fq.ignore_obj_list = ignore_obj_list; fq.flags = FQ_CHECK_OBJS; if (obj->type == OBJ_WEAPON) fq.flags |= FQ_TRANSPOINT; if (obj->type == OBJ_PLAYER) fq.flags |= FQ_GET_SEGLIST; fate = find_vector_intersection(&fq,&hit_info); // Matt: Mike's hack. if (fate == HIT_OBJECT) { object *objp = &Objects[hit_info.hit_object]; if (((objp->type == OBJ_WEAPON) && (objp->id == PROXIMITY_ID)) || objp->type == OBJ_POWERUP) // do not increase count for powerups since they *should* not change our movement count--; } #ifndef NDEBUG if (fate == HIT_BAD_P0) { Int3(); } #endif if (obj->type == OBJ_PLAYER) { int i; if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0]) n_phys_segs--; for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1); ) phys_seglist[n_phys_segs++] = hit_info.seglist[i++]; } ipos = hit_info.hit_pnt; iseg = hit_info.hit_seg; WallHitSide = hit_info.hit_side; WallHitSeg = hit_info.hit_side_seg; if (iseg==-1) { //some sort of horrible error if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; break; } Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index)))); //if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0) // Int3(); save_pos = obj->pos; //save the object's position save_seg = obj->segnum; // update object's position and segment number obj->pos = ipos; if ( iseg != obj->segnum ) obj_relink(objnum, iseg ); //if start point not in segment, move object to center of segment if (get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask!=0) { int n; if ((n=find_object_seg(obj))==-1) { //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } return; } //calulate new sim time { //vms_vector moved_vec; vms_vector moved_vec_n; fix attempted_dist,actual_dist; actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos); if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) { //moved backwards //don't change position or sim_time obj->pos = save_pos; //iseg = obj->segnum; //don't change segment obj_relink(objnum, save_seg ); moved_time = 0; } else { fix old_sim_time; attempted_dist = vm_vec_mag(&frame_vec); old_sim_time = sim_time; sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist); moved_time = old_sim_time - sim_time; if (sim_time < 0 || sim_time>old_sim_time) { sim_time = old_sim_time; //WHY DOES THIS HAPPEN?? moved_time = 0; } } } switch( fate ) { case HIT_WALL: { vms_vector moved_v; fix hit_speed=0, wall_part=0; // Find hit speed vm_vec_sub(&moved_v,&obj->pos,&save_pos); wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm); if ((wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0) || obj->type == OBJ_WEAPON || obj->type == OBJ_DEBRIS) collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); if (obj->type == OBJ_PLAYER) scrape_player_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); Assert( WallHitSeg > -1 ); Assert( WallHitSide > -1 ); if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { Assert(! (obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE)); //can't be bounce and stick if (obj->mtype.phys_info.flags & PF_STICK) { //stop moving add_stuck_object(obj, WallHitSeg, WallHitSide); vm_vec_zero(&obj->mtype.phys_info.velocity); obj_stopped = 1; try_again = 0; } else { // Slide object along wall //We're constrained by wall, so subtract wall part from //velocity vector wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity); // if wall_part, make sure the value is sane enough to get usable velocity computed if (wall_part < 0 && wall_part > -f1_0) wall_part = -f1_0; if (wall_part > 0 && wall_part < f1_0) wall_part = f1_0; if (obj->mtype.phys_info.flags & PF_BOUNCE) //bounce off wall wall_part *= 2; //Subtract out wall part twice to achieve bounce vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part); try_again = 1; } } break; } case HIT_OBJECT: { vms_vector old_vel; // Mark the hit object so that on a retry the fvi code // ignores this object. Assert(hit_info.hit_object != -1); // Calculcate the hit point between the two objects. { vms_vector *ppos0, *ppos1, pos_hit; fix size0, size1; ppos0 = &Objects[hit_info.hit_object].pos; ppos1 = &obj->pos; size0 = Objects[hit_info.hit_object].size; size1 = obj->size; Assert(size0+size1 != 0); // Error, both sizes are 0, so how did they collide, anyway?!? //vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1)); //vm_vec_add2(&pos_hit, ppos0); vm_vec_sub(&pos_hit, ppos1, ppos0); vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1)); old_vel = obj->mtype.phys_info.velocity; collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit); } // Let object continue its movement if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { //obj->pos = save_pos; if (obj->mtype.phys_info.flags&PF_PERSISTENT || (old_vel.x == obj->mtype.phys_info.velocity.x && old_vel.y == obj->mtype.phys_info.velocity.y && old_vel.z == obj->mtype.phys_info.velocity.z)) { //if (Objects[hit_info.hit_object].type == OBJ_POWERUP) ignore_obj_list[n_ignore_objs++] = hit_info.hit_object; try_again = 1; } } break; } case HIT_NONE: break; #ifndef NDEBUG case HIT_BAD_P0: Int3(); // Unexpected collision type: start point not in specified segment. break; default: // Unknown collision type returned from find_vector_intersection!! Int3(); break; #endif } } while ( try_again ); // Pass retry count info to AI. if (obj->control_type == CT_AI) { if (count > 0) { Ai_local_info[objnum].retry_count = count-1; Total_retries += count-1; Total_sims++; } } // As sim_time may not base on FrameTime, scale actual object position to get accurate movement if (PhysTime/FrameTime > 0) { vms_vector md; vm_vec_sub(&md, &obj->pos, &start_pos); vm_vec_scale(&md, F1_0/((float)PhysTime/FrameTime)); vm_vec_add(&obj->pos,&start_pos, &md); //check for and update correct object segment if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0) { if (!update_object_seg(obj)) { if (!(Game_mode & GM_MULTI)) Int3(); compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } } } // After collision with objects and walls, set velocity from actual movement if (!obj_stopped && ((obj->type == OBJ_PLAYER) || (obj->type == OBJ_ROBOT) || (obj->type == OBJ_DEBRIS)) && ((fate == HIT_WALL) || (fate == HIT_OBJECT) || (fate == HIT_BAD_P0)) ) { vms_vector moved_vec; vm_vec_sub(&moved_vec,&obj->pos,&start_pos); vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime)); } fix_illegal_wall_intersection(obj, &start_pos); //Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0); //if (obj->control_type == CT_FLYING) if (obj->mtype.phys_info.flags & PF_LEVELLING) do_physics_align_object( obj ); //hack to keep player from going through closed doors if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (!cheats.ghostphysics) ) { int sidenum; sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]); if (sidenum != -1) { if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) { side *s; int vertnum,num_faces,i; fix dist; int vertex_list[6]; //bump object back s = &Segments[orig_segnum].sides[sidenum]; create_abs_vertex_lists( &num_faces, vertex_list, orig_segnum, sidenum, __FILE__,__LINE__); //let's pretend this wall is not triangulated vertnum = vertex_list[0]; for (i=1;i<4;i++) if (vertex_list[i] < vertnum) vertnum = vertex_list[i]; #ifdef COMPACT_SEGS { vms_vector _vn; get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn ); dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist); } #else dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist); #endif update_object_seg(obj); } } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #ifndef NDEBUG //if end point not in segment, move object to last pos, or segment center if (get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask!=0) { if (find_object_seg(obj)==-1) { int n; //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #endif }
object *object_create_explosion_sub(object *objp, short segnum, vms_vector * position, fix size, int vclip_type, fix maxdamage, fix maxdistance, fix maxforce, int parent ) { int objnum; object *obj; objnum = obj_create( OBJ_FIREBALL,vclip_type,segnum,position,&vmd_identity_matrix,size, CT_EXPLOSION,MT_NONE,RT_FIREBALL); if (objnum < 0 ) { mprintf((1, "Can't create object in object_create_explosion_sub.\n")); return NULL; } obj = &Objects[objnum]; //mprintf( 0, "Fireball created at %d, %d, %d\n", obj->pos.x, obj->pos.y, obj->pos.z ); //now set explosion-specific data obj->lifeleft = Vclip[vclip_type ].play_time; obj->ctype.expl_info.spawn_time = -1; obj->ctype.expl_info.delete_objnum = -1; obj->ctype.expl_info.delete_time = -1; if (maxdamage > 0) { fix dist, force; vms_vector pos_hit, vforce; fix damage; int i; object * obj0p = &Objects[0]; // -- now legal for badass explosions on a wall. Assert(objp != NULL); for (i=0; i<=Highest_object_index; i++ ) { // Weapons used to be affected by badass explosions, but this introduces serious problems. // When a smart bomb blows up, if one of its children goes right towards a nearby wall, it will // blow up, blowing up all the children. So I remove it. MK, 09/11/94 if ( (obj0p->type == OBJ_CNTRLCEN) || (obj0p->type==OBJ_PLAYER) || ((obj0p->type==OBJ_ROBOT) && ((Objects[parent].type != OBJ_ROBOT) || (Objects[parent].id != obj0p->id)))) { dist = vm_vec_dist_quick( &obj0p->pos, &obj->pos ); // Make damage be from 'maxdamage' to 0.0, where 0.0 is 'maxdistance' away; if ( dist < maxdistance ) { if (object_to_object_visibility(obj, obj0p, FQ_TRANSWALL)) { damage = maxdamage - fixmuldiv( dist, maxdamage, maxdistance ); force = maxforce - fixmuldiv( dist, maxforce, maxdistance ); // Find the force vector on the object vm_vec_sub( &vforce, &obj0p->pos, &obj->pos ); vm_vec_normalize_quick(&vforce); vm_vec_scale(&vforce, force ); // Find where the point of impact is... ( pos_hit ) vm_vec_scale(vm_vec_sub(&pos_hit, &obj->pos, &obj0p->pos), fixdiv(obj0p->size, obj0p->size + dist)); switch ( obj0p->type ) { case OBJ_ROBOT: phys_apply_force(obj0p,&vforce); // When a robot gets whacked by a badass force, he looks towards it because robots tend to get blasted from behind. { vms_vector neg_vforce; neg_vforce.x = vforce.x * -2 * (7 - Difficulty_level)/8; neg_vforce.y = vforce.y * -2 * (7 - Difficulty_level)/8; neg_vforce.z = vforce.z * -2 * (7 - Difficulty_level)/8; phys_apply_rot(obj0p,&neg_vforce); } if ( obj0p->shields >= 0 ) { if (apply_damage_to_robot(obj0p, damage, parent)) if ((objp != NULL) && (parent == Players[Player_num].objnum)) add_points_to_score(Robot_info[obj0p->id].score_value); } break; case OBJ_CNTRLCEN: if ( obj0p->shields >= 0 ) { apply_damage_to_controlcen(obj0p, damage, parent ); } break; case OBJ_PLAYER: { object * killer=NULL; vms_vector vforce2; if ((objp != NULL) && (Game_mode & GM_MULTI) && (objp->type == OBJ_PLAYER)) { // mprintf((0, "Damaged by player %d's explosion.\n", objp->id)); killer = objp; } vforce2 = vforce; if (parent > -1 ) { killer = &Objects[parent]; if (killer != ConsoleObject) // if someone else whacks you, cut force by 2x vforce2.x /= 2; vforce2.y /= 2; vforce2.z /= 2; } vforce2.x /= 2; vforce2.y /= 2; vforce2.z /= 2; phys_apply_force(obj0p,&vforce); phys_apply_rot(obj0p,&vforce2); if ( obj0p->shields >= 0 ) apply_damage_to_player(obj0p, killer, damage ); } break; default: Int3(); // Illegal object type } // end switch } else { ; // mprintf((0, "No badass: robot=%2i, dist=%7.3f, maxdistance=%7.3f .\n", i, f2fl(dist), f2fl(maxdistance))); } // end if (object_to_object_visibility... } // end if (dist < maxdistance) } obj0p++; } // end for } // end if (maxdamage... // mprintf(0, "\n"); return obj; }
// ----------------------------------------------------------------------------------------------------------- //Simulate a physics object for this frame do_physics_sim(object *obj) { int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs; int iseg; int try_again; int fate; vms_vector frame_vec; //movement in this frame vms_vector new_pos,ipos; //position after this frame int count=0; int objnum; int WallHitSeg, WallHitSide; fvi_info hit_info; fvi_query fq; vms_vector save_pos; int save_seg; fix drag; fix sim_time; vms_vector start_pos; int obj_stopped=0; fix moved_time; //how long objected moved before hit something vms_vector save_p0,save_p1; physics_info *pi; int orig_segnum = obj->segnum; Assert(obj->type != OBJ_NONE); Assert(obj->movement_type == MT_PHYSICS); #ifndef NDEBUG if (Dont_move_ai_objects) if (obj->control_type == CT_AI) return; #endif pi = &obj->mtype.phys_info; do_physics_sim_rot(obj); if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z)) return; objnum = obj-Objects; n_phys_segs = 0; disable_new_fvi_stuff = (obj->type != OBJ_PLAYER); sim_time = FrameTime; //debug_obj = obj; #ifdef EXTRA_DEBUG if (obj == debug_obj) { printf("object %d:\n start pos = %x %x %x\n",objnum,XYZ(&obj->pos)); printf(" thrust = %x %x %x\n",XYZ(&obj->mtype.phys_info.thrust)); printf(" sim_time = %x\n",sim_time); } //check for correct object segment if(!get_seg_masks(&obj->pos,obj->segnum,0).centermask==0) { #ifndef NDEBUG mprintf((0,"Warning: object %d not in given seg!\n",objnum)); #endif //Int3(); Removed by Rob 10/5/94 if (!update_object_seg(obj)) { #ifndef NDEBUG mprintf((0,"Warning: can't find seg for object %d - moving\n",objnum)); #endif if (!(Game_mode & GM_MULTI)) Int3(); compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } } #endif start_pos = obj->pos; n_ignore_objs = 0; Assert(obj->mtype.phys_info.brakes==0); //brakes not used anymore? //if uses thrust, cannot have zero drag Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0); //mprintf((0,"thrust=%x speed=%x\n",vm_vec_mag(&obj->mtype.phys_info.thrust),vm_vec_mag(&obj->mtype.phys_info.velocity))); //do thrust & drag if ((drag = obj->mtype.phys_info.drag) != 0) { int count; vms_vector accel; fix r,k; count = sim_time / FT; r = sim_time % FT; k = fixdiv(r,FT); if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass)); while (count--) { vm_vec_add2(&obj->mtype.phys_info.velocity,&accel); vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag); } //do linear scale on remaining bit of time vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k); vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag)); } else { fix total_drag=f1_0; while (count--) total_drag = fixmul(total_drag,f1_0-drag); //do linear scale on remaining bit of time total_drag = fixmul(total_drag,f1_0-fixmul(k,drag)); vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag); } } #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" velocity = %x %x %x\n",XYZ(&obj->mtype.phys_info.velocity)); #endif do { try_again = 0; //Move the object vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time); #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" pass %d, frame_vec = %x %x %x\n",count,XYZ(&frame_vec)); #endif if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) ) break; count++; // If retry count is getting large, then we are trying to do something stupid. if ( count > 3) { if (obj->type == OBJ_PLAYER) { if (count > 8) break; } else break; } vm_vec_add(&new_pos,&obj->pos,&frame_vec); #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" desired_pos = %x %x %x\n",XYZ(&new_pos)); #endif ignore_obj_list[n_ignore_objs] = -1; #ifdef EXTRA_DEBUG if (obj == debug_obj) { printf(" FVI parms: p0 = %8x %8x %8x, segnum=%x, size=%x\n",XYZ(&obj->pos),obj->segnum,obj->size); printf(" p1 = %8x %8x %8x\n",XYZ(&new_pos)); } #endif fq.p0 = &obj->pos; fq.startseg = obj->segnum; fq.p1 = &new_pos; fq.rad = obj->size; fq.thisobjnum = objnum; fq.ignore_obj_list = ignore_obj_list; fq.flags = FQ_CHECK_OBJS; if (obj->type == OBJ_WEAPON) fq.flags |= FQ_TRANSPOINT; if (obj->type == OBJ_PLAYER) fq.flags |= FQ_GET_SEGLIST; //@@ if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) //@@ Int3(); save_p0 = *fq.p0; save_p1 = *fq.p1; fate = find_vector_intersection(&fq,&hit_info); // Matt: Mike's hack. if (fate == HIT_OBJECT) { object *objp = &Objects[hit_info.hit_object]; if ((objp->type == OBJ_WEAPON) && (objp->id == PROXIMITY_ID)) count--; } #ifndef NDEBUG if (fate == HIT_BAD_P0) { mprintf((0,"Warning: Bad p0 in physics! Object = %i, type = %i [%s]\n", obj-Objects, obj->type, Object_type_names[obj->type])); Int3(); } #endif if (obj->type == OBJ_PLAYER) { int i; if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0]) n_phys_segs--; for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1); ) phys_seglist[n_phys_segs++] = hit_info.seglist[i++]; } #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" fate = %d, hit_pnt = %8x %8x %8x\n",fate,XYZ(&hit_info.hit_pnt));; #endif ipos = hit_info.hit_pnt; iseg = hit_info.hit_seg; WallHitSide = hit_info.hit_side; WallHitSeg = hit_info.hit_side_seg; if (iseg==-1) { //some sort of horrible error #ifndef NDEBUG mprintf((1,"iseg==-1 in physics! Object = %i, type = %i (%s)\n", obj-Objects, obj->type, Object_type_names[obj->type])); #endif //Int3(); //compute_segment_center(&ipos,&Segments[obj->segnum]); //ipos.x += objnum; //iseg = obj->segnum; //fate = HIT_NONE; if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; break; } Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index)))); //if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0) // Int3(); save_pos = obj->pos; //save the object's position save_seg = obj->segnum; // update object's position and segment number obj->pos = ipos; #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" new pos = %x %x %x\n",XYZ(&obj->pos)); #endif if ( iseg != obj->segnum ) obj_relink(objnum, iseg ); //if start point not in segment, move object to center of segment if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) { int n; if ((n=find_object_seg(obj))==-1) { //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } return; } //calulate new sim time { //vms_vector moved_vec; vms_vector moved_vec_n; fix attempted_dist,actual_dist; actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos); if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) { //moved backwards //don't change position or sim_time //******* mprintf((0,"Obj %d moved backwards\n",obj-Objects)); #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" Warning: moved backwards!\n"); #endif obj->pos = save_pos; //iseg = obj->segnum; //don't change segment obj_relink(objnum, save_seg ); moved_time = 0; } else { fix old_sim_time; //if (obj == debug_obj) // printf(" moved_vec = %x %x %x\n",XYZ(&moved_vec)); attempted_dist = vm_vec_mag(&frame_vec); old_sim_time = sim_time; sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist); moved_time = old_sim_time - sim_time; if (sim_time < 0 || sim_time>old_sim_time) { #ifndef NDEBUG mprintf((0,"Bogus sim_time = %x, old = %x\n",sim_time,old_sim_time)); if (obj == debug_obj) printf(" Bogus sim_time = %x, old = %x, attempted_dist = %x, actual_dist = %x\n",sim_time,old_sim_time,attempted_dist,actual_dist); //Int3(); Removed by Rob #endif sim_time = old_sim_time; //WHY DOES THIS HAPPEN?? moved_time = 0; } } #ifdef EXTRA_DEBUG if (obj == debug_obj) printf(" new sim_time = %x\n",sim_time); #endif } switch( fate ) { case HIT_WALL: { vms_vector moved_v; //@@fix total_d,moved_d; fix hit_speed,wall_part; // Find hit speed vm_vec_sub(&moved_v,&obj->pos,&save_pos); wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm); if (wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0) collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); else scrape_object_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt ); Assert( WallHitSeg > -1 ); Assert( WallHitSide > -1 ); if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { Assert(! (obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE)); //can't be bounce and stick if (obj->mtype.phys_info.flags & PF_STICK) { //stop moving // mprintf((0, "Object %i stuck at %i:%i\n", obj-Objects, WallHitSeg, WallHitSide)); add_stuck_object(obj, WallHitSeg, WallHitSide); vm_vec_zero(&obj->mtype.phys_info.velocity); obj_stopped = 1; try_again = 0; } else { // Slide object along wall //We're constrained by wall, so subtract wall part from //velocity vector wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity); if (obj->mtype.phys_info.flags & PF_BOUNCE) //bounce off wall wall_part *= 2; //Subtract out wall part twice to achieve bounce vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part); #ifdef EXTRA_DEBUG if (obj == debug_obj) { printf(" sliding - wall_norm %x %x %x\n",wall_part,XYZ(&hit_info.hit_wallnorm)); printf(" wall_part %x, new velocity = %x %x %x\n",wall_part,XYZ(&obj->mtype.phys_info.velocity)); } #endif try_again = 1; } } break; } case HIT_OBJECT: { vms_vector old_vel; // Mark the hit object so that on a retry the fvi code // ignores this object. Assert(hit_info.hit_object != -1); // Calculcate the hit point between the two objects. { vms_vector *ppos0, *ppos1, pos_hit; fix size0, size1; ppos0 = &Objects[hit_info.hit_object].pos; ppos1 = &obj->pos; size0 = Objects[hit_info.hit_object].size; size1 = obj->size; Assert(size0+size1 != 0); // Error, both sizes are 0, so how did they collide, anyway?!? //vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1)); //vm_vec_add2(&pos_hit, ppos0); vm_vec_sub(&pos_hit, ppos1, ppos0); vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1)); old_vel = obj->mtype.phys_info.velocity; collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit); } // Let object continue its movement if ( !(obj->flags&OF_SHOULD_BE_DEAD) ) { //obj->pos = save_pos; if (obj->mtype.phys_info.flags&PF_PERSISTENT || (old_vel.x == obj->mtype.phys_info.velocity.x && old_vel.y == obj->mtype.phys_info.velocity.y && old_vel.z == obj->mtype.phys_info.velocity.z)) { //if (Objects[hit_info.hit_object].type == OBJ_POWERUP) ignore_obj_list[n_ignore_objs++] = hit_info.hit_object; try_again = 1; } } break; } case HIT_NONE: break; #ifndef NDEBUG case HIT_BAD_P0: Int3(); // Unexpected collision type: start point not in specified segment. mprintf((0,"Warning: Bad p0 in physics!!!\n")); break; default: // Unknown collision type returned from find_vector_intersection!! Int3(); break; #endif } } while ( try_again ); // Pass retry count info to AI. if (obj->control_type == CT_AI) { if (count > 0) { Ai_local_info[objnum].retry_count = count-1; Total_retries += count-1; Total_sims++; } } if (! obj_stopped) { //Set velocity from actual movement vms_vector moved_vec; vm_vec_sub(&moved_vec,&obj->pos,&start_pos); vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime)); #ifdef BUMP_HACK if (obj==ConsoleObject && (obj->mtype.phys_info.velocity.x==0 && obj->mtype.phys_info.velocity.y==0 && obj->mtype.phys_info.velocity.z==0) && !(obj->mtype.phys_info.thrust.x==0 && obj->mtype.phys_info.thrust.y==0 && obj->mtype.phys_info.thrust.z==0)) { vms_vector center,bump_vec; //bump player a little towards center of segment to unstick compute_segment_center(¢er,&Segments[obj->segnum]); vm_vec_normalized_dir_quick(&bump_vec,¢er,&obj->pos); vm_vec_scale_add2(&obj->pos,&bump_vec,obj->size/5); } #endif } //Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0); //if (obj->control_type == CT_FLYING) if (obj->mtype.phys_info.flags & PF_LEVELLING) do_physics_align_object( obj ); //hack to keep player from going through closed doors if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (Physics_cheat_flag!=0xBADA55) ) { int sidenum; sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]); if (sidenum != -1) { if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) { side *s; int vertnum,num_faces,i; fix dist; int vertex_list[6]; //bump object back s = &Segments[orig_segnum].sides[sidenum]; create_abs_vertex_lists( &num_faces, vertex_list, orig_segnum, sidenum); //let's pretend this wall is not triangulated vertnum = vertex_list[0]; for (i=1;i<4;i++) if (vertex_list[i] < vertnum) vertnum = vertex_list[i]; #ifdef COMPACT_SEGS { vms_vector _vn; get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn ); dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist); } #else dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]); vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist); #endif update_object_seg(obj); } } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #ifndef NDEBUG //if end point not in segment, move object to last pos, or segment center if (get_seg_masks(&obj->pos,obj->segnum,0).centermask!=0) { if (find_object_seg(obj)==-1) { int n; //Int3(); if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) { obj->pos = obj->last_pos; obj_relink(objnum, n ); } else { compute_segment_center(&obj->pos,&Segments[obj->segnum]); obj->pos.x += objnum; } if (obj->type == OBJ_WEAPON) obj->flags |= OF_SHOULD_BE_DEAD; } } //--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL #endif }
void digi_sync_sounds() { int i; int oldvolume, oldpan; if (!digi_initialised) return; for (i=0; i<MAX_SOUND_OBJECTS; i++ ) { if ( SoundObjects[i].flags & SOF_USED ) { oldvolume = SoundObjects[i].volume; oldpan = SoundObjects[i].pan; if ( !(SoundObjects[i].flags & SOF_PLAY_FOREVER) ) { // Check if its done. if (SoundObjects[i].flags & SOF_PLAYING) { if (!SoundSlots[SoundObjects[i].handle].playing) { SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound continue; // Go on to next sound... } } } if ( SoundObjects[i].flags & SOF_LINK_TO_POS ) { digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &SoundObjects[i].lp_position, SoundObjects[i].lp_segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); } else if ( SoundObjects[i].flags & SOF_LINK_TO_OBJ ) { object * objp; objp = &Objects[SoundObjects[i].lo_objnum]; if ((objp->type==OBJ_NONE) || (objp->signature!=SoundObjects[i].lo_objsignature)) { // The object that this is linked to is dead, so just end this sound if it is looping. if ( (SoundObjects[i].flags & SOF_PLAYING) && (SoundObjects[i].flags & SOF_PLAY_FOREVER)) { DS_release_slot(SoundObjects[i].handle,1); } SoundObjects[i].flags = 0; // Mark as dead, so some other sound can use this sound continue; // Go on to next sound... } else { digi_get_sound_loc( &Viewer->orient, &Viewer->pos, Viewer->segnum, &objp->pos, objp->segnum, SoundObjects[i].max_volume, &SoundObjects[i].volume, &SoundObjects[i].pan, SoundObjects[i].max_distance ); } } if (oldvolume != SoundObjects[i].volume) { if ( SoundObjects[i].volume < MIN_VOLUME ) { // Sound is too far away, so stop it from playing. if ((SoundObjects[i].flags & SOF_PLAYING)&&(SoundObjects[i].flags & SOF_PLAY_FOREVER)) { DS_release_slot(SoundObjects[i].handle,1); SoundObjects[i].flags &= ~SOF_PLAYING; // Mark sound as not playing } } else { if (!(SoundObjects[i].flags & SOF_PLAYING)) { digi_start_sound_object(i); } else { SoundSlots[SoundObjects[i].handle].volume = fixmuldiv(SoundObjects[i].volume,digi_volume,F1_0); } } } if (oldpan != SoundObjects[i].pan) { if (SoundObjects[i].flags & SOF_PLAYING) SoundSlots[SoundObjects[i].handle].pan = SoundObjects[i].pan; } } } }