// Try and find a new locking point void hud_lock_get_new_lock_pos(object *target_objp, vector *lock_world_pos) { ship *target_shipp=NULL; int lock_in_range=0; float best_lock_dot=-1.0f, lock_dot=-1.0f; ship_subsys *ss; vector subsys_world_pos, vec_to_lock; if ( target_objp->type == OBJ_SHIP ) { target_shipp = &Ships[target_objp->instance]; } // if a large ship, lock to pos closest to center and within range if ( (target_shipp) && (Ship_info[target_shipp->ship_info_index].flags & (SIF_BIG_SHIP|SIF_HUGE_SHIP)) ) { // check all the subsystems and the center of the ship // assume best lock pos is the center of the ship *lock_world_pos=target_objp->pos; Player->locking_on_center=1; Player->locking_subsys=NULL; Player->locking_subsys_parent=-1; lock_in_range = hud_lock_world_pos_in_range(lock_world_pos, &vec_to_lock); vm_vec_normalize(&vec_to_lock); if ( lock_in_range ) { best_lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock); } // take center if reasonable dot if ( best_lock_dot > 0.95 ) { return; } // iterate through subsystems to see if we can get a better choice ss = GET_FIRST(&target_shipp->subsys_list); while ( ss != END_OF_LIST( &target_shipp->subsys_list ) ) { // get world pos of subsystem get_subsystem_world_pos(target_objp, ss, &subsys_world_pos); if ( hud_lock_world_pos_in_range(&subsys_world_pos, &vec_to_lock) ) { vm_vec_normalize(&vec_to_lock); lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock); if ( lock_dot > best_lock_dot ) { best_lock_dot=lock_dot; Player->locking_on_center=0; Player->locking_subsys=ss; Player->locking_subsys_parent=Player_ai->target_objnum; *lock_world_pos=subsys_world_pos; } } ss = GET_NEXT( ss ); } } else { // if small ship (or weapon), just go for the center *lock_world_pos = target_objp->pos; Player->locking_on_center=1; Player->locking_subsys=NULL; Player->locking_subsys_parent=-1; } }
void supernova_get_eye(vec3d *eye_pos, matrix *eye_orient) { // supernova camera pos vec3d Supernova_camera_pos; static matrix Supernova_camera_orient; vec3d at; vec3d sun_temp, sun_vec; vec3d view; // set the controls for the heart of the sun stars_get_sun_pos(0, &sun_temp); vm_vec_add2(&sun_temp, &Player_obj->pos); vm_vec_sub(&sun_vec, &sun_temp, &Player_obj->pos); vm_vec_normalize(&sun_vec); // always set the camera pos vec3d move; matrix whee; vm_vector_2_matrix(&whee, &move, NULL, NULL); vm_vec_scale_add(&Supernova_camera_pos, &Player_obj->pos, &whee.vec.rvec, sn_cam_distance); vm_vec_scale_add2(&Supernova_camera_pos, &whee.vec.uvec, 30.0f); //cam->set_position(&Supernova_camera_pos); *eye_pos = Supernova_camera_pos; // if we're no longer moving the camera if(Supernova_time < (SUPERNOVA_CUT_TIME - SUPERNOVA_CAMERA_MOVE_TIME)) { // *eye_pos = Supernova_camera_pos; //cam->set_rotation(&Supernova_camera_orient); *eye_orient = Supernova_camera_orient; } // otherwise move it else { // get a vector somewhere between the supernova shockwave and the player ship at = Player_obj->pos; vm_vec_scale_add2(&at, &sun_vec, sn_distance); vm_vec_sub(&move, &Player_obj->pos, &at); vm_vec_normalize(&move); // linearly move towards the player pos float pct = ((SUPERNOVA_CUT_TIME - Supernova_time) / SUPERNOVA_CAMERA_MOVE_TIME); vm_vec_scale_add2(&at, &move, sn_distance * pct); vm_vec_sub(&view, &at, &Supernova_camera_pos); vm_vec_normalize(&view); vm_vector_2_matrix(&Supernova_camera_orient, &view, NULL, NULL); //cam->set_rotation(&Supernova_camera_orient); *eye_orient = Supernova_camera_orient; } //return supernova_camera; }
// output top and bottom vectors // fvec == forward vector (eye viewpoint basically. in world coords) // pos == world coordinate of the point we're calculating "around" // w == width of the diff between top and bottom around pos void trail_calc_facing_pts( vec3d *top, vec3d *bot, vec3d *fvec, vec3d *pos, float w ) { vec3d uvec, rvec; vm_vec_sub( &rvec, &Eye_position, pos ); if (!IS_VEC_NULL(&rvec)) vm_vec_normalize( &rvec ); vm_vec_crossprod(&uvec,fvec,&rvec); if (!IS_VEC_NULL(&uvec)) vm_vec_normalize(&uvec); vm_vec_scale_add( top, pos, &uvec, w * 0.5f ); vm_vec_scale_add( bot, pos, &uvec, -w * 0.5f ); }
// add some jitter to a flak gun's aiming direction, take into account range to target so that we're never _too_ far off // assumes dir is normalized void flak_jitter_aim(vec3d* dir, float dist_to_target, float weapon_subsys_strength) { vec3d rand_twist_pre, rand_twist_post; matrix temp; vec3d final_aim; float error_val; // get the matrix needed to rotate the base direction to the actual direction vm_vector_2_matrix(&temp, dir, NULL, NULL); // error value error_val = Flak_error + (Flak_error * 0.65f * (1.0f - weapon_subsys_strength)); // scale the rvec by some random value and make it the "pre-twist" value float rand_dist = frand_range(0.0f, error_val); // no jitter - so do nothing if (rand_dist <= 0.0f) { return; } vm_vec_copy_scale(&rand_twist_pre, &temp.vec.rvec, rand_dist); // now rotate the twist vector around the x axis (the base aim axis) at a random angle vm_rot_point_around_line(&rand_twist_post, &rand_twist_pre, fl_radian(359.0f * frand_range(0.0f, 1.0f)), &vmd_zero_vector, dir); // add the resulting vector to the base aim vector and normalize final_aim = *dir; vm_vec_scale(&final_aim, dist_to_target); vm_vec_add(dir, &final_aim, &rand_twist_post); vm_vec_normalize(dir); }
/* This works like any other clip plane... if this is enabled and you rotate a point, the CC_OFF_USER bit will be set in the clipping codes. It is completely handled by most g3_draw primitives, except maybe lines. As far as performance, when enabled, it will slow down each point rotation (or g3_code_vertex call) by a vector subtraction and dot product. It won't slow anything down for polys that are completely clipped on or off by the plane, and will slow each clipped polygon by not much more than any other clipping we do. */ void g3_start_user_clip_plane( vector *plane_point, vector *plane_normal ) { float mag = vm_vec_mag( plane_normal ); if ( (mag < 0.1f) || (mag > 1.5f ) ) { // Invalid plane_normal passed in. Get Allender (since it is // probably a ship warp in bug:) or John. Int3(); return; } G3_user_clip = 1; if(!Cmdline_nohtl) { G3_user_clip_normal = *plane_normal; G3_user_clip_point = *plane_point; // return; gr_start_clip(); } vm_vec_rotate(&G3_user_clip_normal, plane_normal, &View_matrix ); vm_vec_normalize(&G3_user_clip_normal); vector tempv; vm_vec_sub(&tempv,plane_point,&View_position); vm_vec_rotate(&G3_user_clip_point,&tempv,&View_matrix ); }
void HudGaugeRadarOrb::drawContactHtl(vec3d *pnt, int rad) { vec3d p; p=*pnt; vm_vec_normalize(&p); float size = fl_sqrt(vm_vec_dist(&Orb_eye_position, pnt) * 8.0f); if (size < i2fl(rad)) size = i2fl(rad); if (rad == Radar_blip_radius_target) { if (radar_target_id_flags & RTIF_PULSATE) { // use mask to make the darn thing work faster size *= 1.3f + (sinf(10 * f2fl(Missiontime)) * 0.3f); } if (radar_target_id_flags & RTIF_BLINK) { if (Missiontime & 8192) return; } g3_render_sphere(pnt,size/100.0f); } else { g3_render_sphere(pnt,size/300.0f); } //g3_draw_htl_line(&p,pnt); g3_render_line_3d(false, &p, pnt); }
void HudGaugeRadarOrb::drawContact(vec3d *pnt, int rad) { vertex verts[2]; vec3d p; p=*pnt; vm_vec_normalize(&p); g3_rotate_vertex(&verts[0], &p); g3_project_vertex(&verts[0]); g3_rotate_vertex(&verts[1], pnt); g3_project_vertex(&verts[1]); float size = fl_sqrt(vm_vec_dist(&Orb_eye_position, pnt) * 8.0f); if (size < i2fl(rad)) size = i2fl(rad); if (rad == Radar_blip_radius_target) { g3_draw_sphere(&verts[1],size/100.0f); } else { g3_draw_sphere(&verts[1],size/300.0f); } g3_draw_line(&verts[0],&verts[1]); }
// ------------------------------------------------------------------------------------------------------ int ObjectMoveDown(void) { object *obj; vms_vector uvec; vms_vector newpos; if (Cur_object_index == -1) { editor_status("No current object, cannot move."); return 1; } obj = &Objects[Cur_object_index]; extract_up_vector_from_segment(&Segments[obj->segnum], &uvec); vm_vec_normalize(&uvec); vm_vec_sub(&newpos, &obj->pos, vm_vec_scale(&uvec, OBJ_SCALE)); if (!verify_object_seg(obj, &newpos)) obj->pos = newpos; Update_flags |= UF_WORLD_CHANGED; return 1; }
void HudGaugeRadarDradis::plotBlip(blip* b, vec3d *pos, float *alpha) { *pos = b->position; vm_vec_normalize(pos); if (ship_is_tagged(b->objp)) { *alpha = 1.0f; return; } float fade_multi = 1.5f; if (b->objp->type == OBJ_SHIP) { if (Ships[b->objp->instance].flags[Ship::Ship_Flags::Stealth]) { fade_multi *= 2.0f; } } b->time_since_update += flFrametime; // If the blip has been pinged by the local x-axis sweep, update if (std::abs(vm_vec_dot(&sweep_normal_x, pos)) < 0.01f) { b->time_since_update = 0.0f; } *alpha = ((sweep_duration - b->time_since_update)/sweep_duration)*fade_multi/2.0f; if (*alpha < 0.0f) { *alpha = 0.0f; } }
// if i'm an observer, zoom to near my targted object (if any) void multi_obs_zoom_to_target() { vec3d direct; float dist; // if i'm not an observer, do nothing if (!(Game_mode & GM_MULTIPLAYER) || (Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type != OBJ_OBSERVER)) { return; } // if I have no targeted object, do nothing if (Player_ai->target_objnum == -1) { return; } // get the normalized direction vector between the observer and the targeted object vm_vec_sub(&direct, &Objects[Player_ai->target_objnum].pos, &Player_obj->pos); dist = vm_vec_mag(&direct); vm_vec_normalize(&direct); // orient the guy correctly vm_vec_ang_2_matrix(&Player_obj->orient, &direct, 0.0f); // keep about 3 object radii away when moving dist -= (Objects[Player_ai->target_objnum].radius * 3.0f); // get the movement vector vm_vec_scale(&direct, dist); // move vm_vec_add2(&Player_obj->pos, &direct); }
vms_vector *vm_vec_interp(vms_vector *result, vms_vector *v0, vms_vector *v1, fix scale) { vms_vector tvec; vm_vec_sub(&tvec, v1, v0); vm_vec_scale_add(result, v0, &tvec, scale); vm_vec_normalize(result); return result; }
void supernova_do_particles() { int idx; vec3d a, b, ta, tb; vec3d norm, sun_temp; // no player ship if((Player_obj == NULL) || (Player_ship == NULL)) { return; } // timestamp if((Supernova_particle_stamp == -1) || timestamp_elapsed(Supernova_particle_stamp)) { Supernova_particle_stamp = timestamp(sn_particles); // get particle norm stars_get_sun_pos(0, &sun_temp); vm_vec_add2(&sun_temp, &Player_obj->pos); vm_vec_sub(&norm, &Player_obj->pos, &sun_temp); vm_vec_normalize(&norm); particle_emitter whee; whee.max_life = 1.0f; whee.min_life = 0.6f; whee.max_vel = 50.0f; whee.min_vel = 25.0f; whee.normal_variance = 0.75f; whee.num_high = 5; whee.num_low = 2; whee.min_rad = 0.5f; whee.max_rad = 1.25f; // emit for(idx=0; idx<10; idx++) { if ( Cmdline_old_collision_sys ) { submodel_get_two_random_points(Ship_info[Player_ship->ship_info_index].model_num, 0, &ta, &tb); } else { submodel_get_two_random_points_better(Ship_info[Player_ship->ship_info_index].model_num, 0, &ta, &tb); } // rotate into world space vm_vec_unrotate(&a, &ta, &Player_obj->orient); vm_vec_add2(&a, &Player_obj->pos); whee.pos = a; whee.vel = norm; vm_vec_scale(&whee.vel, 30.0f); vm_vec_add2(&whee.vel, &Player_obj->phys_info.vel); whee.normal = norm; particle_emit(&whee, PARTICLE_FIRE, 0); vm_vec_unrotate(&b, &tb, &Player_obj->orient); vm_vec_add2(&b, &Player_obj->pos); whee.pos = b; particle_emit(&whee, PARTICLE_FIRE, 0); } } }
// ----------------------------------------------------------------------------------------------------------------- // Return true if side is planar, else return false. int side_is_planar_p(segment *sp, int side) { sbyte *vp; vms_vector *v0,*v1,*v2,*v3; vms_vector va,vb; vp = Side_to_verts[side]; v0 = &Vertices[sp->verts[vp[0]]]; v1 = &Vertices[sp->verts[vp[1]]]; v2 = &Vertices[sp->verts[vp[2]]]; v3 = &Vertices[sp->verts[vp[3]]]; vm_vec_normalize(vm_vec_normal(&va,v0,v1,v2)); vm_vec_normalize(vm_vec_normal(&vb,v0,v2,v3)); // If the two vectors are very close to being the same, then generate one quad, else generate two triangles. return (vm_vec_dist(&va,&vb) < F1_0/1000); }
void nav_warp(bool prewarp=false) { /* ok... find our end distance - norm1 is still a unit vector in the direction from the flight leader to the navpoint */ vec3d targetPos, tpos=Autopilot_flight_leader->pos, pos, velocity; /* calculate a vector that we can use to make a path from the flight leader's location to the nav point */ vm_vec_sub(&pos, Navs[CurrentNav].GetPosition(), &Autopilot_flight_leader->pos); vm_vec_normalize(&pos); velocity = pos; // make a copy for later when we do setup veleocity vector vm_vec_scale(&pos, 250.0f); // we move by increments of 250 /* using the vector of the flight leaders's path, simulate moving the flight along this path by checking the autopilot conditions as specific intervals along the path*/ while (CanAutopilot(tpos)) { vm_vec_add(&tpos, &tpos, &pos); } vm_vec_sub(&targetPos, &tpos, &Autopilot_flight_leader->pos); /* targetPos is actually a vector that describes the exact 3D movement that the flgith leader needs to execute to reach the location that the auto pilot is to shut off */ // Check if we are actually just setting up for the cinimatic shot of the // flight flying on autopilot. Only jump halfway. Also we also need to // put the camera in the correct position to show the player this cinimatic if (prewarp) { vm_vec_scale(&targetPos, 0.5); vm_vec_add(&cameraPos, &cameraPos, &targetPos); } /* calcuate the speed that everyone is supposed to be going so that there is no need for anyone to accelerate or decelerate (most obvious with the player's fighter slowing down as it changes the camera pan speed). */ Assert( Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap > 0 ); vm_vec_scale(&velocity, (float)Ai_info[Ships[Autopilot_flight_leader->instance].ai_index].waypoint_speed_cap); // Find all ships that are supposed to autopilot with the player and move them // to the cinimatic location or the final destination for (int 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))) { vm_vec_add(&Objects[Ships[i].objnum].pos, &Objects[Ships[i].objnum].pos, &targetPos); Objects[Ships[i].objnum].phys_info.vel = velocity; } } // retime all collision pairs obj_collide_retime_cached_pairs(); }
// Project the viewer's position onto the grid plane. If more than threshold distance // from grid center, move grid center. void maybe_create_new_grid(grid* gridp, vector *pos, matrix *orient, int force) { int roundoff; plane tplane; vector gpos, tmp, c; float dist_to_plane; float square_size, ux, uy, uz; ux = tplane.A = gridp->gmatrix.v.uvec.xyz.x; uy = tplane.B = gridp->gmatrix.v.uvec.xyz.y; uz = tplane.C = gridp->gmatrix.v.uvec.xyz.z; tplane.D = gridp->planeD; compute_point_on_plane(&c, &tplane, pos); dist_to_plane = fl_abs(vm_dist_to_plane(pos, &gridp->gmatrix.v.uvec, &c)); square_size = 1.0f; while (dist_to_plane >= 25.0f) { square_size *= 10.0f; dist_to_plane /= 10.0f; } if (fvi_ray_plane(&gpos, &gridp->center, &gridp->gmatrix.v.uvec, pos, &orient->v.fvec, 0.0f)<0.0f) { vector p; vm_vec_scale_add(&p,pos,&orient->v.fvec, 100.0f ); compute_point_on_plane(&gpos, &tplane, &p ); } if (vm_vec_dist(&gpos, &c) > 50.0f * square_size) { vm_vec_sub(&tmp, &gpos, &c); vm_vec_normalize(&tmp); vm_vec_scale_add(&gpos, &c, &tmp, 50.0f * square_size); } roundoff = (int) square_size * 10; if (!ux) gpos.xyz.x = fl_roundoff(gpos.xyz.x, roundoff); if (!uy) gpos.xyz.y = fl_roundoff(gpos.xyz.y, roundoff); if (!uz) gpos.xyz.z = fl_roundoff(gpos.xyz.z, roundoff); if ((square_size != gridp->square_size) || (gpos.xyz.x != gridp->center.xyz.x) || (gpos.xyz.y != gridp->center.xyz.y) || (gpos.xyz.z != gridp->center.xyz.z) || force) { gridp->square_size = square_size; gridp->center = gpos; modify_grid(gridp); } }
void curve_dir(vms_equation *coeffs, int degree, fix t0, vms_vector *dir) { fix t2; if (degree!=3) printf("ERROR: for Hermite Curves degree must be 3\n"); t2 = fixmul(t0,t0); dir->x = fixmul(3*F1_0,fixmul(coeffs->x3,t2)) + fixmul(2*F1_0,fixmul(coeffs->x2,t0)) + coeffs->x1; dir->y = fixmul(3*F1_0,fixmul(coeffs->y3,t2)) + fixmul(2*F1_0,fixmul(coeffs->y2,t0)) + coeffs->y1; dir->z = fixmul(3*F1_0,fixmul(coeffs->z3,t2)) + fixmul(2*F1_0,fixmul(coeffs->z2,t0)) + coeffs->z1; vm_vec_normalize( dir ); }
//from a 2d point, compute the vector through that point. // This can be called outside of a g3_start_frame/g3_end_frame // pair as long g3_start_frame was previously called. void g3_point_to_vec_delayed(vector *v,int sx,int sy) { vector tempv; tempv.xyz.x = ((float)sx - Canv_w2) / Canv_w2; tempv.xyz.y = -((float)sy - Canv_h2) / Canv_h2; tempv.xyz.z = 1.0f; tempv.xyz.x = tempv.xyz.x * Matrix_scale.xyz.z / Matrix_scale.xyz.x; tempv.xyz.y = tempv.xyz.y * Matrix_scale.xyz.z / Matrix_scale.xyz.y; vm_vec_normalize(&tempv); vm_vec_unrotate(v, &tempv, &Unscaled_matrix); }
//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); }
void HudGaugeRadarOrb::plotBlip(blip *b, vec3d *scaled_pos) { *scaled_pos = b->position; if (IS_VEC_NULL_SQ_SAFE(scaled_pos)) { vm_vec_make(scaled_pos, 1.0f, 0.0f, 0.0f); } else { vm_vec_normalize(scaled_pos); } float scale = b->dist / Radar_bright_range; if (scale > 1.25f) scale = 1.25f; if (scale < .75f) scale = .75f; vm_vec_scale(scaled_pos, scale); }
int HudGaugeRadarOrb::calcAlpha(vec3d* pt) { Assert(pt); Assert(Player_obj); vec3d new_pt; vec3d fvec = { { { 0.0f, 0.0f, 1.0f } } }; vm_vec_unrotate(&new_pt, pt, &Player_obj->orient); vm_vec_normalize(&new_pt); float dot = vm_vec_dot(&fvec, &new_pt); float angle = fabs(acosf(dot)); int alpha = int(angle*192.0f/PI); return alpha; }
int ObjectMoveFurther(void) { vms_vector result; if (Cur_object_index == -1) { editor_status("Cur_object_index == -1, cannot move that peculiar object...aborting!"); return 1; } // move_object_to_mouse_click_delta(+4*F1_0); // Move four units further from eye vm_vec_sub(&result, &Objects[Cur_object_index].pos, &Viewer->pos); vm_vec_normalize(&result); move_object_to_vector(&result, 4*F1_0); return 1; }
void physics_apply_whack(vec3d *impulse, vec3d *pos, physics_info *pi, matrix *orient, float mass) { vec3d local_torque, torque; // vec3d npos; // Detect null vector. if ((fl_abs(impulse->xyz.x) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.y) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.z) <= WHACK_LIMIT)) return; // first do the rotational velocity // calculate the torque on the body based on the point on the // object that was hit and the momentum being applied to the object vm_vec_crossprod(&torque, pos, impulse); vm_vec_rotate ( &local_torque, &torque, orient ); vec3d delta_rotvel; vm_vec_rotate( &delta_rotvel, &local_torque, &pi->I_body_inv ); vm_vec_scale ( &delta_rotvel, (float) ROTVEL_WHACK_CONST ); vm_vec_add2( &pi->rotvel, &delta_rotvel ); //mprintf(("Whack: %7.3f %7.3f %7.3f\n", pi->rotvel.xyz.x, pi->rotvel.xyz.y, pi->rotvel.xyz.z)); // instant whack on the velocity // reduce damping on all axes pi->flags |= PF_REDUCED_DAMP; update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) ); // find time for shake from weapon to end int dtime = timestamp_until(pi->afterburner_decay); if (dtime < WEAPON_SHAKE_TIME) { pi->afterburner_decay = timestamp( WEAPON_SHAKE_TIME ); } // Goober5000 - pi->mass should probably be just mass, as specified in the header vm_vec_scale_add2( &pi->vel, impulse, 1.0f / mass ); if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) { // Get DaveA nprintf(("Physics", "speed reset in physics_apply_whack [speed: %f]\n", vm_vec_mag(&pi->vel))); vm_vec_normalize(&pi->vel); vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED); } vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient ); // set so velocity will ramp starting from current speed // ramped velocity is now affected by collision }
void initial_status::undock(object *objp1, object *objp2) { vec3d v; int ship_num, other_ship_num; if (objp1 == NULL || objp2 == NULL) return; vm_vec_sub(&v, &objp2->pos, &objp1->pos); vm_vec_normalize(&v); ship_num = get_ship_from_obj(OBJ_INDEX(objp1)); other_ship_num = get_ship_from_obj(OBJ_INDEX(objp2)); if (ship_class_compare(Ships[ship_num].ship_info_index, Ships[other_ship_num].ship_info_index) <= 0) vm_vec_scale_add2(&objp2->pos, &v, objp2->radius * 2.0f); else vm_vec_scale_add2(&objp1->pos, &v, objp1->radius * -2.0f); ai_do_objects_undocked_stuff(objp1, objp2); // check to see if one of these ships has an arrival cue of false. If so, then // reset it back to default value of true. be sure to correctly update before // and after setting data. // Goober5000 - but don't reset it if it's part of a wing! Ship_editor_dialog.update_data(1); if ( Ships[ship_num].arrival_cue == Locked_sexp_false && Ships[ship_num].wingnum < 0 ) { Ships[ship_num].arrival_cue = Locked_sexp_true; } else if ( Ships[other_ship_num].arrival_cue == Locked_sexp_false && Ships[other_ship_num].wingnum < 0 ) { Ships[other_ship_num].arrival_cue = Locked_sexp_true; } // if this ship is no longer docked, ensure its dock leader flag is clear if (!object_is_docked(&Objects[Ships[ship_num].objnum])) Ships[ship_num].flags.remove(Ship::Ship_Flags::Dock_leader); // same for the other ship if (!object_is_docked(&Objects[Ships[other_ship_num].objnum])) Ships[other_ship_num].flags.remove(Ship::Ship_Flags::Dock_leader); Ship_editor_dialog.initialize_data(1); }
// radar is damaged, so make blips dance around void HudGaugeRadarOrb::blipDrawDistorted(blip *b, vec3d *pos) { float scale; float dist=vm_vec_normalize(pos); vec3d out; float distortion_angle=20; // maybe alter the effect if EMP is active if(emp_active_local()) { scale = emp_current_intensity(); distortion_angle *= frand_range(-3.0f,3.0f)*frand_range(0.0f, scale); dist *= frand_range(MAX(0.75f, 0.75f*scale), MIN(1.25f, 1.25f*scale)); if (dist > 1.25f) dist = 1.25f; if (dist < 0.75f) dist = 0.75f; } vm_vec_random_cone(&out,pos,distortion_angle); vm_vec_scale(&out,dist); drawContactHtl(&out,b->rad); }
// radar is damaged, so make blips dance around void HudGaugeRadarDradis::blipDrawDistorted(blip *b, vec3d *pos, float alpha) { float temp_scale; float dist = vm_vec_normalize(pos); vec3d out; float distortion_angle=20; // maybe alter the effect if EMP is active if (emp_active_local()) { temp_scale = emp_current_intensity(); dist *= frand_range(MAX(0.75f, 0.75f*temp_scale), MIN(1.25f, 1.25f*temp_scale)); distortion_angle *= frand_range(-3.0f,3.0f)*frand_range(0.0f, temp_scale); if (dist > 1.0f) dist = 1.0f; if (dist < 0.1f) dist = 0.1f; } vm_vec_random_cone(&out, pos, distortion_angle); vm_vec_scale(&out, dist); drawContact(&out, -1, unknown_contact_icon, b->dist, alpha, 1.0f); }
// blip is for a target immune to sensors, so cause to flicker in/out with mild distortion void HudGaugeRadarOrb::blipDrawFlicker(blip *b, vec3d *pos) { int flicker_index; float dist=vm_vec_normalize(pos); vec3d out; float distortion_angle=10; if ( (b-Blips) & 1 ) { flicker_index=0; } else { flicker_index=1; } if ( timestamp_elapsed(Radar_flicker_timer[flicker_index]) ) { Radar_flicker_timer[flicker_index] = timestamp_rand(50,1000); Radar_flicker_on[flicker_index] ^= 1; } if ( !Radar_flicker_on[flicker_index] ) { return; } if ( rand() & 1 ) { distortion_angle *= frand_range(0.1f,2.0f); dist *= frand_range(0.75f, 1.25f); if (dist > 1.25f) dist = 1.25f; if (dist < 0.75f) dist = 0.75f; } vm_vec_random_cone(&out,pos,distortion_angle); vm_vec_scale(&out,dist); drawContactHtl(&out,b->rad); }
void physics_collide_whack( vec3d *impulse, vec3d *world_delta_rotvel, physics_info *pi, matrix *orient, bool is_landing ) { vec3d body_delta_rotvel; // Detect null vector. if ((fl_abs(impulse->xyz.x) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.y) <= WHACK_LIMIT) && (fl_abs(impulse->xyz.z) <= WHACK_LIMIT)) return; vm_vec_rotate( &body_delta_rotvel, world_delta_rotvel, orient ); // vm_vec_scale( &body_delta_rotvel, (float) ROTVEL_COLLIDE_WHACK_CONST ); vm_vec_add2( &pi->rotvel, &body_delta_rotvel ); update_reduced_damp_timestamp( pi, vm_vec_mag(impulse) ); // find time for shake from weapon to end if (!is_landing) { int dtime = timestamp_until(pi->afterburner_decay); if (dtime < WEAPON_SHAKE_TIME) { pi->afterburner_decay = timestamp( WEAPON_SHAKE_TIME ); } } pi->flags |= PF_REDUCED_DAMP; vm_vec_scale_add2( &pi->vel, impulse, 1.0f / pi->mass ); // check that collision does not give ship too much speed // reset if too high if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) { // Get DaveA nprintf(("Physics", "speed reset in physics_collide_whack [speed: %f]\n", vm_vec_mag(&pi->vel))); vm_vec_normalize(&pi->vel); vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED); } vm_vec_rotate( &pi->prev_ramp_vel, &pi->vel, orient ); // set so velocity will ramp starting from current speed // ramped velocity is now affected by collision // rotate previous ramp velocity (in model coord) to be same as vel (in world coords) }
// blip is for a target immune to sensors, so cause to flicker in/out with mild distortion void HudGaugeRadarDradis::blipDrawFlicker(blip *b, vec3d *pos, float alpha) { int flicker_index; float dist=vm_vec_normalize(pos); vec3d out; float distortion_angle=10; if ((b-Blips) & 1) flicker_index=0; else flicker_index=1; if (timestamp_elapsed(Radar_flicker_timer[flicker_index])) { Radar_flicker_timer[flicker_index] = timestamp_rand(50,1000); Radar_flicker_on[flicker_index] ^= 1; } if (!Radar_flicker_on[flicker_index]) return; if (rand() & 1) { distortion_angle *= frand_range(0.1f,2.0f); dist *= frand_range(0.75f, 1.25f); if (dist > 1.0f) dist = 1.0f; if (dist < 0.1f) dist = 0.1f; } vm_vec_random_cone(&out,pos,distortion_angle); vm_vec_scale(&out,dist); drawContact(&out, -1, unknown_contact_icon, b->dist, alpha, 1.0f); }
void HudGaugeRadarDradis::plotBlip(blip* b, vec3d *pos, float *alpha) { *pos = b->position; vm_vec_normalize(pos); if (ship_is_tagged(b->objp)) { *alpha = 1.0f; return; } float fade_multi = 1.5f; if (b->objp->type == OBJ_SHIP) { if (Ships[b->objp->instance].flags2 & SF2_STEALTH) { fade_multi *= 2.0f; } } *alpha = 1.0f - (sweep_percent /(PI*2))*fade_multi/2.0f; if (*alpha < 0.0f) { *alpha = 0.0f; } }
void physics_apply_shock(vec3d *direction_vec, float pressure, physics_info *pi, matrix *orient, vec3d *min, vec3d *max, float radius) { vec3d normal; vec3d local_torque, temp_torque, torque; vec3d impact_vec; vec3d area; vec3d sin; if (radius > MAX_RADIUS) { return; } vm_vec_normalize_safe ( direction_vec ); area.xyz.x = (max->xyz.y - min->xyz.z) * (max->xyz.z - min->xyz.z); area.xyz.y = (max->xyz.x - min->xyz.x) * (max->xyz.z - min->xyz.z); area.xyz.z = (max->xyz.x - min->xyz.x) * (max->xyz.y - min->xyz.y); normal.xyz.x = vm_vec_dotprod( direction_vec, &orient->vec.rvec ); normal.xyz.y = vm_vec_dotprod( direction_vec, &orient->vec.uvec ); normal.xyz.z = vm_vec_dotprod( direction_vec, &orient->vec.fvec ); sin.xyz.x = fl_sqrt( fl_abs(1.0f - normal.xyz.x*normal.xyz.x) ); sin.xyz.y = fl_sqrt( fl_abs(1.0f - normal.xyz.y*normal.xyz.y) ); sin.xyz.z = fl_sqrt( fl_abs(1.0f - normal.xyz.z*normal.xyz.z) ); vm_vec_make( &torque, 0.0f, 0.0f, 0.0f ); // find the torque exerted due to the shockwave hitting each face // model the effect of the shockwave as if the shockwave were a plane of projectiles, // all moving in the direction direction_vec. then find the torque as the cross prod // of the force (pressure * area * normal * sin * scale * mass) // normal takes account the fraction of the surface exposed to the shockwave // the sin term is not technically needed but "feels" better // scale factors out the increase in area with larger objects // more massive objects get less rotation // find torque due to forces on the right/left face if ( normal.xyz.x < 0.0f ) // normal < 0, hits the right face vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, max->xyz.x * pressure * area.xyz.x * normal.xyz.x * sin.xyz.x / pi->mass ); else // normal > 0, hits the left face vm_vec_copy_scale( &impact_vec, &orient->vec.rvec, min->xyz.x * pressure * area.xyz.x * -normal.xyz.x * sin.xyz.x / pi->mass ); vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec ); vm_vec_add2( &torque, &temp_torque ); // find torque due to forces on the up/down face if ( normal.xyz.y < 0.0f ) vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, max->xyz.y * pressure * area.xyz.y * normal.xyz.y * sin.xyz.y / pi->mass ); else vm_vec_copy_scale( &impact_vec, &orient->vec.uvec, min->xyz.y * pressure * area.xyz.y * -normal.xyz.y * sin.xyz.y / pi->mass ); vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec ); vm_vec_add2( &torque, &temp_torque ); // find torque due to forces on the forward/backward face if ( normal.xyz.z < 0.0f ) vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, max->xyz.z * pressure * area.xyz.z * normal.xyz.z * sin.xyz.z / pi->mass ); else vm_vec_copy_scale( &impact_vec, &orient->vec.fvec, min->xyz.z * pressure * area.xyz.z * -normal.xyz.z * sin.xyz.z / pi->mass ); vm_vec_crossprod( &temp_torque, &impact_vec, direction_vec ); vm_vec_add2( &torque, &temp_torque ); // compute delta rotvel, scale according to blast and radius float scale; if (radius < MIN_RADIUS) { scale = 1.0f; } else { scale = (MAX_RADIUS - radius)/(MAX_RADIUS-MIN_RADIUS); } // set shockwave shake amplitude, duration, flag pi->shockwave_shake_amp = (float)(MAX_SHAKE*(pressure/STD_PRESSURE)*scale); pi->shockwave_decay = timestamp( SW_BLAST_DURATION ); pi->flags |= PF_IN_SHOCKWAVE; // safety dance if (!(IS_VEC_NULL_SQ_SAFE(&torque))) { vec3d delta_rotvel; vm_vec_rotate( &local_torque, &torque, orient ); vm_vec_copy_normalize(&delta_rotvel, &local_torque); vm_vec_scale(&delta_rotvel, (float)(MAX_ROTVEL*(pressure/STD_PRESSURE)*scale)); // nprintf(("Physics", "rotvel scale %f\n", (MAX_ROTVEL*(pressure/STD_PRESSURE)*scale))); vm_vec_add2(&pi->rotvel, &delta_rotvel); } // set reduced translational damping, set flags float velocity_scale = (float)MAX_VEL*scale; pi->flags |= PF_REDUCED_DAMP; update_reduced_damp_timestamp( pi, velocity_scale*pi->mass ); vm_vec_scale_add2( &pi->vel, direction_vec, velocity_scale ); vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient); // set so velocity will ramp starting from current speed // check that kick from shockwave is not too large if (!(pi->flags & PF_USE_VEL) && (vm_vec_mag_squared(&pi->vel) > MAX_SHIP_SPEED*MAX_SHIP_SPEED)) { // Get DaveA nprintf(("Physics", "speed reset in physics_apply_shock [speed: %f]\n", vm_vec_mag(&pi->vel))); vm_vec_normalize(&pi->vel); vm_vec_scale(&pi->vel, (float)RESET_SHIP_SPEED); } }