// determine if the subsystem to lock on to has a direct line of sight int hud_lock_on_subsys_ok() { ship_subsys *subsys; vec3d subobj_pos; object *target_objp; int in_sight=0; Assert(Player_ai->target_objnum >= 0); target_objp = &Objects[Player_ai->target_objnum]; subsys = Player_ai->targeted_subsys; if ( !subsys ) { return 0; } vm_vec_unrotate(&subobj_pos, &subsys->system_info->pnt, &target_objp->orient); vm_vec_add2(&subobj_pos, &target_objp->pos); if ( Player->subsys_in_view < 0 ) { in_sight = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos); } else { in_sight = Player->subsys_in_view; } return in_sight; }
/** * Render one triangle of a shield hit effect on one ship. * Each frame, the triangle needs to be rotated into global coords. * * @param trip pointer to triangle in global array * @param orient orientation of object shield is associated with * @param pos center point of object * @param r Red colour * @param g Green colour * @param b Blue colour */ void render_shield_triangle(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b) { int j; vec3d pnt; vertex *verts[3]; vertex points[3]; if (trip->trinum == -1) return; // Means this is a quad, must have switched detail_level. for (j=0; j<3; j++ ) { // Rotate point into world coordinates vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient); vm_vec_add2(&pnt, pos); // Pnt is now the x,y,z world coordinates of this vert. // For this example, I am just drawing a sphere at that point. if (!Cmdline_nohtl) g3_transfer_vertex(&points[j],&pnt); else g3_rotate_vertex(&points[j], &pnt); points[j].texture_position.u = trip->verts[j].u; points[j].texture_position.v = trip->verts[j].v; Assert((trip->verts[j].u >= 0.0f) && (trip->verts[j].u <= UV_MAX)); Assert((trip->verts[j].v >= 0.0f) && (trip->verts[j].v <= UV_MAX)); verts[j] = &points[j]; } verts[0]->r = r; verts[0]->g = g; verts[0]->b = b; verts[1]->r = r; verts[1]->g = g; verts[1]->b = b; verts[2]->r = r; verts[2]->g = g; verts[2]->b = b; vec3d norm; Poly_count++; vm_vec_perp(&norm,&verts[0]->world,&verts[1]->world,&verts[2]->world); int flags=TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD; if (!Cmdline_nohtl) flags |= TMAP_HTL_3D_UNLIT; if ( vm_vec_dot(&norm,&verts[1]->world ) >= 0.0 ) { vertex *vertlist[3]; vertlist[0] = verts[2]; vertlist[1] = verts[1]; vertlist[2] = verts[0]; g3_draw_poly( 3, vertlist, flags); } else { g3_draw_poly( 3, verts, flags); } }
// Textured Poly // +0 int id // +4 int size // +8 vec3d normal // +20 vec3d center // +32 float radius // +36 int nverts // +40 int tmap_num // +44 nverts*(model_tmap_vert) vertlist (n,u,v) void moff_tmappoly(ubyte* p, polymodel* pm, model_octant* oct, int just_count) { int i, nv; model_tmap_vert* verts; nv = w(p + 36); if (nv < 0) return; verts = (model_tmap_vert*)(p + 44); if ((pm->version < 2003) && !just_count) { // Set the "normal_point" part of field to be the center of the polygon vec3d center_point; vm_vec_zero(¢er_point); Assert(Interp_verts != NULL); for (i = 0; i < nv; i++) { vm_vec_add2(¢er_point, Interp_verts[verts[i].vertnum]); } center_point.xyz.x /= nv; center_point.xyz.y /= nv; center_point.xyz.z /= nv; *vp(p + 20) = center_point; float rad = 0.0f; for (i = 0; i < nv; i++) { float dist = vm_vec_dist(¢er_point, Interp_verts[verts[i].vertnum]); if (dist > rad) { rad = dist; } } fl(p + 32) = rad; } // Put each face into a particular octant if (point_in_octant(pm, oct, vp(p + 20))) { if (just_count) oct->nverts++; else oct->verts[oct->nverts++] = vp(p + 20); return; } }
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; }
float dock_calc_max_semilatus_rectum_parallel_to_axis(object *objp, axis_type axis) { Assert(objp != NULL); vec3d local_line_end; vec3d *world_line_start, world_line_end; dock_function_info dfi; // to calculate the semilatus rectum, we need a directrix that will be parallel to the axis // the first endpoint is simply the position of the object world_line_start = &objp->pos; // the second endpoint extends in the axis direction vm_vec_zero(&local_line_end); switch(axis) { case X_AXIS: local_line_end.xyz.x = 1.0f; break; case Y_AXIS: local_line_end.xyz.y = 1.0f; break; case Z_AXIS: local_line_end.xyz.z = 1.0f; break; default: Int3(); return 0.0f; } // rotate and move the endpoint to go through the axis of the actual object vm_vec_rotate(&world_line_end, &local_line_end, &objp->orient); vm_vec_add2(&world_line_end, &objp->pos); // now we have a unit vector starting at the object's position and pointing along the chosen axis // (although the length doesn't matter, as it's calculated as an endless line) // now determine the semilatus rectum // set parameters and call function for the semilatus rectum squared dfi.parameter_variables.vecp_value = world_line_start; dfi.parameter_variables.vecp_value2 = &world_line_end; dock_evaluate_all_docked_objects(objp, &dfi, dock_calc_max_semilatus_rectum_squared_parallel_to_directrix_helper); // the semilatus rectum is the square root of our result return fl_sqrt(dfi.maintained_variables.float_value); }
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; }
// get a point on the hermite curve. void herm_spline::herm_get_point(vec3d *out, float u, int k) { float a = ( (2.0f * u * u * u) - (3.0f * u * u) + 1 ); float b = ( (-2.0f * u * u * u) + (3.0f * u * u) ); float c = ( (u * u * u) - (2.0f * u * u) + u ); float d = ( (u * u * u) - (u * u) ); vec3d va; vm_vec_copy_scale(&va, &pts[k], a); vec3d vb; vm_vec_copy_scale(&vb, &pts[k+1], b); vec3d vc; vm_vec_copy_scale(&vc, &d_pts[k], c); vec3d vd; vm_vec_copy_scale(&vd, &d_pts[k+1], d); vm_vec_add(out, &va, &vb); vm_vec_add2(out, &vc); vm_vec_add2(out, &vd); }
// the derivative of a point on the hermite curve void herm_spline::herm_get_deriv(vec3d *deriv, float u, int k) { float a = ( (6.0f * u * u) - (6.0f * u) ); float b = ( (-6.0f * u * u) + (6.0f * u) ); float c = ( (3.0f * u * u) - (4.0f * u) + 1 ); float d = ( (3.0f * u * u) - (2.0f * u) ); vec3d va; vm_vec_copy_scale(&va, &pts[k], a); vec3d vb; vm_vec_copy_scale(&vb, &pts[k+1], b); vec3d vc; vm_vec_copy_scale(&vc, &d_pts[k], c); vec3d vd; vm_vec_copy_scale(&vd, &d_pts[k+1], d); vm_vec_add(deriv, &va, &vb); vm_vec_add2(deriv, &vc); vm_vec_add2(deriv, &vd); }
void render_low_detail_shield_bitmap(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b) { int j; vec3d pnt; vertex verts[4]; for (j=0; j<4; j++ ) { // Rotate point into world coordinates vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient); vm_vec_add2(&pnt, pos); // Pnt is now the x,y,z world coordinates of this vert. if(!Cmdline_nohtl) g3_transfer_vertex(&verts[j], &pnt); else g3_rotate_vertex(&verts[j], &pnt); verts[j].texture_position.u = trip->verts[j].u; verts[j].texture_position.v = trip->verts[j].v; } verts[0].r = r; verts[0].g = g; verts[0].b = b; verts[1].r = r; verts[1].g = g; verts[1].b = b; verts[2].r = r; verts[2].g = g; verts[2].b = b; verts[3].r = r; verts[3].g = g; verts[3].b = b; vec3d norm; vm_vec_perp(&norm, &trip->verts[0].pos, &trip->verts[1].pos, &trip->verts[2].pos); vertex *vertlist[4]; if ( vm_vec_dot(&norm, &trip->verts[1].pos ) < 0.0 ) { vertlist[0] = &verts[3]; vertlist[1] = &verts[2]; vertlist[2] = &verts[1]; vertlist[3] = &verts[0]; g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_HTL_3D_UNLIT); } else { vertlist[0] = &verts[0]; vertlist[1] = &verts[1]; vertlist[2] = &verts[2]; vertlist[3] = &verts[3]; g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_HTL_3D_UNLIT); } }
// ----------------------------------------------------------------------------- //return the position & orientation of a gun on the control center object void calc_controlcen_gun_point(vms_vector *gun_point,vms_vector *gun_dir,object *obj,int gun_num) { vms_matrix m; Assert(obj->type == OBJ_CNTRLCEN); Assert(obj->render_type==RT_POLYOBJ); Assert(gun_num < N_controlcen_guns); //instance gun position & orientation vm_copy_transpose_matrix(&m,&obj->orient); vm_vec_rotate(gun_point,&controlcen_gun_points[gun_num],&m); vm_vec_add2(gun_point,&obj->pos); vm_vec_rotate(gun_dir,&controlcen_gun_dirs[gun_num],&m); }
// What we're doing here is projecting each object extent onto the directrix, calculating the distance between the // projected point and the origin, and then taking the maximum distance as the semilatus rectum. We're actually // maintaining the square of the distance rather than the actual distance, as it's faster to calculate and it gives // the same result in a greater-than or less-than comparison. When we're done calculating everything for all // objects (i.e. when we return to the parent function) we take the square root of the final value. void dock_calc_max_semilatus_rectum_squared_parallel_to_directrix_helper(object *objp, dock_function_info *infop) { vec3d world_point, local_point[6], nearest; polymodel *pm; int i; float temp, dist_squared; // line parameters vec3d *line_start = infop->parameter_variables.vecp_value; vec3d *line_end = infop->parameter_variables.vecp_value2; // We must find world coordinates for each of the six endpoints on the three axes of the object. I looked up // which axis is front/back, left/right, and up/down, as well as which endpoint is which. It doesn't really // matter, though, as all we need are the distances. // grab our model Assert(objp->type == OBJ_SHIP); pm = model_get(Ship_info[Ships[objp->instance].ship_info_index].model_num); // set up the points we want to check memset(local_point, 0, sizeof(vec3d) * 6); local_point[0].xyz.x = pm->maxs.xyz.x; // right point (max x) local_point[1].xyz.x = pm->mins.xyz.x; // left point (min x) local_point[2].xyz.y = pm->maxs.xyz.y; // top point (max y) local_point[3].xyz.y = pm->mins.xyz.y; // bottom point (min y) local_point[4].xyz.z = pm->maxs.xyz.z; // front point (max z) local_point[5].xyz.z = pm->mins.xyz.z; // rear point (min z) // check points for (i = 0; i < 6; i++) { // calculate position of point vm_vec_rotate(&world_point, &local_point[i], &objp->orient); vm_vec_add2(&world_point, &objp->pos); // find the nearest point along the line vm_vec_dist_squared_to_line(&world_point, line_start, line_end, &nearest, &temp); // find the distance squared between the origin of the line and the point on the line dist_squared = vm_vec_dist_squared(line_start, &nearest); // update with farthest distance squared if (dist_squared > infop->maintained_variables.float_value) infop->maintained_variables.float_value = dist_squared; } }
//given an object and a gun number, return position in 3-space of gun //fills in gun_point void calc_gun_point(vms_vector *gun_point,object *obj,int gun_num) { polymodel *pm; robot_info *r; vms_vector pnt; vms_matrix m; int mn; //submodel number Assert(obj->render_type==RT_POLYOBJ || obj->render_type==RT_MORPH); Assert(obj->id < N_robot_types); r = &Robot_info[obj->id]; pm =&Polygon_models[r->model_num]; if (gun_num >= r->n_guns) { mprintf((1, "Bashing gun num %d to 0.\n", gun_num)); //Int3(); gun_num = 0; } // Assert(gun_num < r->n_guns); pnt = r->gun_points[gun_num]; mn = r->gun_submodels[gun_num]; //instance up the tree for this gun while (mn != 0) { vms_vector tpnt; vm_angles_2_matrix(&m,&obj->rtype.pobj_info.anim_angles[mn]); vm_transpose_matrix(&m); vm_vec_rotate(&tpnt,&pnt,&m); vm_vec_add(&pnt,&tpnt,&pm->submodel_offsets[mn]); mn = pm->submodel_parents[mn]; } //now instance for the entire object vm_copy_transpose_matrix(&m,&obj->orient); vm_vec_rotate(gun_point,&pnt,&m); vm_vec_add2(gun_point,&obj->pos); }
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 }
// Return true if objp will collide with some large object. // Don't check for an object this ship is docked to. int collide_predict_large_ship(object *objp, float distance) { object *objp2; vec3d cur_pos, goal_pos; ship_info *sip; sip = &Ship_info[Ships[objp->instance].ship_info_index]; cur_pos = objp->pos; vm_vec_scale_add(&goal_pos, &cur_pos, &objp->orient.vec.fvec, distance); for ( objp2 = GET_FIRST(&obj_used_list); objp2 != END_OF_LIST(&obj_used_list); objp2 = GET_NEXT(objp2) ) { if ((objp != objp2) && (objp2->type == OBJ_SHIP)) { if (Ship_info[Ships[objp2->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) { if (dock_check_find_docked_object(objp, objp2)) continue; if (cpls_aux(&goal_pos, objp2, objp)) return 1; } } else if (!(sip->flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) && (objp2->type == OBJ_ASTEROID)) { if (vm_vec_dist_quick(&objp2->pos, &objp->pos) < (distance + objp2->radius)*2.5f) { vec3d pos, delvec; int count; float d1; d1 = 2.5f * distance + objp2->radius; count = (int) (d1/(objp2->radius + objp->radius)); // Scale up distance, else looks like there would be a collision. pos = cur_pos; vm_vec_normalized_dir(&delvec, &goal_pos, &cur_pos); vm_vec_scale(&delvec, d1/count); for (; count>0; count--) { if (vm_vec_dist_quick(&pos, &objp2->pos) < objp->radius + objp2->radius) return 1; vm_vec_add2(&pos, &delvec); } } } } return 0; }
void get_turret_cam_pos(camera *cam, vec3d *pos) { object_h obj(cam->get_object_host()); if(!obj.IsValid()) return; ship* shipp = &Ships[cam->get_object_host()->instance]; ship_subsys* ssp = GET_FIRST(&shipp->subsys_list); while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) { if(ssp->system_info->subobj_num == cam->get_object_host_submodel()) { ship_get_global_turret_gun_info(cam->get_object_host(), ssp, pos, &normal_cache, 1, NULL); vec3d offset = vmd_zero_vector; offset.xyz.x = 0.0001f; vm_vec_add2(pos, &offset); // prevent beam turrets from crashing with a nullvec break; } ssp = GET_NEXT( ssp ); } }
// --------------------------------------------------------------------------------------------------- void set_view_target_from_segment(segment *sp) { vms_vector tv = ZERO_VECTOR; int v; if (Funky_chase_mode) { //set_chase_matrix(sp); } else { for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) vm_vec_add2(&tv,&Vertices[sp->verts[v]]); vm_vec_scale(&tv,F1_0/MAX_VERTICES_PER_SEGMENT); Ed_view_target = tv; } Update_flags |= UF_VIEWPOINT_MOVED; }
void orient_editor::OnOK() { vec3d delta, pos; object *ptr; UpdateData(TRUE); pos.xyz.x = convert(m_position_x); pos.xyz.y = convert(m_position_y); pos.xyz.z = convert(m_position_z); if ((((CButton *) GetDlgItem(IDC_POINT_TO_OBJECT))->GetCheck() == 1) || (((CButton *) GetDlgItem(IDC_POINT_TO_LOCATION))->GetCheck() == 1)) set_modified(); vm_vec_sub(&delta, &pos, &Objects[cur_object_index].pos); if (delta.xyz.x || delta.xyz.y || delta.xyz.z) set_modified(); ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (ptr->flags & OF_MARKED) { vm_vec_add2(&ptr->pos, &delta); update_object(ptr); } ptr = GET_NEXT(ptr); } ptr = GET_FIRST(&obj_used_list); while (ptr != END_OF_LIST(&obj_used_list)) { if (ptr->flags & OF_MARKED) object_moved(ptr); ptr = GET_NEXT(ptr); } theApp.record_window_data(&Object_wnd_data, this); CDialog::OnOK(); }
void warp_camera::do_frame(float in_frametime) { vec3d new_vel, delta_pos; apply_physics( c_damping, c_desired_vel.xyz.x, c_vel.xyz.x, in_frametime, &new_vel.xyz.x, &delta_pos.xyz.x ); apply_physics( c_damping, c_desired_vel.xyz.y, c_vel.xyz.y, in_frametime, &new_vel.xyz.y, &delta_pos.xyz.y ); apply_physics( c_damping, c_desired_vel.xyz.z, c_vel.xyz.z, in_frametime, &new_vel.xyz.z, &delta_pos.xyz.z ); c_vel = new_vel; vm_vec_add2( &c_pos, &delta_pos ); float ot = c_time+0.0f; c_time += in_frametime; if ( (ot < 0.667f) && ( c_time >= 0.667f ) ) { vec3d tmp; tmp.xyz.z = 4.739f; // always go this fast forward. // pick x and y velocities so they are always on a // circle with a 25 m radius. float tmp_angle = frand()*PI2; tmp.xyz.x = 22.0f * (float)sin(tmp_angle); tmp.xyz.y = -22.0f * (float)cos(tmp_angle); this->set_velocity( &tmp, 0 ); } if ( (ot < 3.0f ) && ( c_time >= 3.0f ) ) { vec3d tmp = ZERO_VECTOR; this->set_velocity( &tmp, 0 ); } }
void model_collide_preprocess_subobj(vec3d *pos, matrix *orient, polymodel *pm, polymodel_instance *pmi, int subobj_num) { submodel_instance *smi = &pmi->submodel[subobj_num]; smi->mc_base = *pos; smi->mc_orient = *orient; int i = pm->submodel[subobj_num].first_child; while ( i >= 0 ) { angles angs = pmi->submodel[i].angs; bsp_info * csm = &pm->submodel[i]; matrix tm = IDENTITY_MATRIX; vm_vec_unrotate(pos, &csm->offset, &smi->mc_orient ); vm_vec_add2(pos, &smi->mc_base); if( vm_matrix_same(&tm, &csm->orientation)) { // if submodel orientation matrix is identity matrix then don't bother with matrix ops vm_angles_2_matrix(&tm, &angs); } else { matrix rotation_matrix = csm->orientation; vm_rotate_matrix_by_angles(&rotation_matrix, &angs); matrix inv_orientation; vm_copy_transpose(&inv_orientation, &csm->orientation); vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation); } vm_matrix_x_matrix(orient, &smi->mc_orient, &tm); model_collide_preprocess_subobj(pos, orient, pm, pmi, i); i = csm->next_sibling; } }
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) }
// apply the EMP effect to all relevant ships void emp_apply(vec3d *pos, float inner_radius, float outer_radius, float emp_intensity, float emp_time, bool use_emp_time_for_capship_turrets) { float actual_intensity, actual_time; vec3d dist; float dist_mag; float scale_factor; object *target; ship_obj *so; missile_obj *mo; ship_subsys *moveup; weapon_info *wip_target; // all machines check to see if the blast hit a bomb. if so, shut it down (can't move anymore) for( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) { target = &Objects[mo->objnum]; if(target->type != OBJ_WEAPON){ continue; } Assert(target->instance >= 0); if(target->instance < 0){ continue; } Assert(Weapons[target->instance].weapon_info_index >= 0); if(Weapons[target->instance].weapon_info_index < 0){ continue; } // if we have a bomb weapon wip_target = &Weapon_info[Weapons[target->instance].weapon_info_index]; if((wip_target->weapon_hitpoints > 0) && !(wip_target->wi_flags2 & WIF2_NO_EMP_KILL)) { // get the distance between the detonation and the target object vm_vec_sub(&dist, &target->pos, pos); dist_mag = vm_vec_mag(&dist); // if the bomb was within 1/4 of the outer radius, castrate it if(dist_mag <= (outer_radius * 0.25f)){ // memset(&target->phys_info, 0, sizeof(physics_info)); Weapons[target->instance].weapon_flags |= WF_DEAD_IN_WATER; mprintf(("EMP killing weapon\n")); } } } // if I'm only a client in a multiplayer game, do nothing if(MULTIPLAYER_CLIENT){ return; } // See if there are any friendly ships present, if so return without preventing msg for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) { target = &Objects[so->objnum]; if(target->type != OBJ_SHIP){ continue; } Assert(Objects[so->objnum].instance >= 0); if(Objects[so->objnum].instance < 0){ continue; } Assert(Ships[Objects[so->objnum].instance].ship_info_index >= 0); if(Ships[Objects[so->objnum].instance].ship_info_index < 0){ continue; } // if the ship is a cruiser or cap ship, only apply the EMP effect to turrets if(Ship_info[Ships[target->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) { float capship_emp_time = use_emp_time_for_capship_turrets ? emp_time : MAX_TURRET_DISRUPT_TIME; moveup = &Ships[target->instance].subsys_list; if(moveup->next != NULL){ moveup = moveup->next; } while(moveup != &Ships[target->instance].subsys_list){ // if this is a turret, disrupt it if((moveup->system_info != NULL) && (moveup->system_info->type == SUBSYSTEM_TURRET)){ vec3d actual_pos; // get the distance to the subsys vm_vec_unrotate(&actual_pos, &moveup->system_info->pnt, &target->orient); vm_vec_add2(&actual_pos, &target->pos); vm_vec_sub(&dist, &actual_pos, pos); dist_mag = vm_vec_mag(&dist); // if for some reason, the object was outside the blast, radius if(dist_mag > outer_radius){ // next item moveup = moveup->next; continue; } // compute a scale factor for the emp effect scale_factor = 1.0f; if(dist_mag >= inner_radius){ scale_factor = 1.0f - (dist_mag / outer_radius); } scale_factor -= Ship_info[Ships[target->instance].ship_info_index].emp_resistance_mod; if (scale_factor < 0.0f) { moveup = moveup->next; continue; } // disrupt the turret ship_subsys_set_disrupted(moveup, (int)(capship_emp_time * scale_factor)); mprintf(("EMP disrupting subsys %s on ship %s (%f, %f)\n", moveup->system_info->subobj_name, Ships[Objects[so->objnum].instance].ship_name, scale_factor, capship_emp_time * scale_factor)); } // next item moveup = moveup->next; } } // otherwise coat the whole ship with the effect. mmmmmmmmm. else { // get the distance between the detonation and the target object vm_vec_sub(&dist, &target->pos, pos); dist_mag = vm_vec_mag(&dist); // if for some reason, the object was outside the blast, radius if(dist_mag > outer_radius){ continue; } // compute a scale factor for the emp effect scale_factor = 1.0f; if(dist_mag >= inner_radius){ scale_factor = 1.0f - (dist_mag / outer_radius); } scale_factor -= Ship_info[Ships[target->instance].ship_info_index].emp_resistance_mod; if (scale_factor < 0.0f) { continue; } // calculate actual EMP effect values actual_intensity = emp_intensity * scale_factor; actual_time = emp_time * scale_factor; mprintf(("EMP effect s : %f, i : %f, t : %f\n", scale_factor, actual_intensity, actual_time)); // if this effect happened to be on me, start it now if((target == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){ emp_start_local(actual_intensity, actual_time); } // if this is a multiplayer game, notify other players of the effect if(Game_mode & GM_MULTIPLAYER){ Assert(MULTIPLAYER_MASTER); send_emp_effect(target->net_signature, actual_intensity, actual_time); } // now be sure to start the emp effect for the ship itself emp_start_ship(target, actual_intensity, actual_time); } } }
do_endlevel_frame() { static fix timer; vms_vector save_last_pos; static fix explosion_wait1=0; static fix explosion_wait2=0; static fix bank_rate; static fix ext_expl_halflife; save_last_pos = ConsoleObject->last_pos; //don't let move code change this object_move_all(); ConsoleObject->last_pos = save_last_pos; if (ext_expl_playing) { external_explosion.lifeleft -= FrameTime; do_explosion_sequence(&external_explosion); if (external_explosion.lifeleft < ext_expl_halflife) mine_destroyed = 1; if (external_explosion.flags & OF_SHOULD_BE_DEAD) ext_expl_playing = 0; } if (cur_fly_speed != desired_fly_speed) { fix delta = desired_fly_speed - cur_fly_speed; fix frame_accel = fixmul(FrameTime,FLY_ACCEL); if (abs(delta) < frame_accel) cur_fly_speed = desired_fly_speed; else if (delta > 0) cur_fly_speed += frame_accel; else cur_fly_speed -= frame_accel; } //do big explosions if (!outside_mine) { if (Endlevel_sequence==EL_OUTSIDE) { vms_vector tvec; vm_vec_sub(&tvec,&ConsoleObject->pos,&mine_side_exit_point); if (vm_vec_dot(&tvec,&mine_exit_orient.fvec) > 0) { object *tobj; outside_mine = 1; tobj = object_create_explosion(exit_segnum,&mine_side_exit_point,i2f(50),VCLIP_BIG_PLAYER_EXPLOSION); if (tobj) { external_explosion = *tobj; tobj->flags |= OF_SHOULD_BE_DEAD; flash_scale = 0; //kill lights in mine ext_expl_halflife = tobj->lifeleft; ext_expl_playing = 1; } digi_link_sound_to_pos( SOUND_BIG_ENDLEVEL_EXPLOSION, exit_segnum, 0, &mine_side_exit_point, 0, i2f(3)/4 ); } } //do explosions chasing player if ((explosion_wait1-=FrameTime) < 0) { vms_vector tpnt; int segnum; object *expl; static int sound_count; vm_vec_scale_add(&tpnt,&ConsoleObject->pos,&ConsoleObject->orient.fvec,-ConsoleObject->size*5); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.rvec,(rand()-RAND_MAX/2)*15); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(rand()-RAND_MAX/2)*15); segnum = find_point_seg(&tpnt,ConsoleObject->segnum); if (segnum != -1) { expl = object_create_explosion(segnum,&tpnt,i2f(20),VCLIP_BIG_PLAYER_EXPLOSION); if (rand()<10000 || ++sound_count==7) { //pseudo-random digi_link_sound_to_pos( SOUND_TUNNEL_EXPLOSION, segnum, 0, &tpnt, 0, F1_0 ); sound_count=0; } } explosion_wait1 = 0x2000 + rand()/4; } } //do little explosions on walls if (Endlevel_sequence >= EL_FLYTHROUGH && Endlevel_sequence < EL_OUTSIDE) if ((explosion_wait2-=FrameTime) < 0) { vms_vector tpnt; fvi_query fq; fvi_info hit_data; //create little explosion on wall vm_vec_copy_scale(&tpnt,&ConsoleObject->orient.rvec,(rand()-RAND_MAX/2)*100); vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(rand()-RAND_MAX/2)*100); vm_vec_add2(&tpnt,&ConsoleObject->pos); if (Endlevel_sequence == EL_FLYTHROUGH) vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,rand()*200); else vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,rand()*60); //find hit point on wall fq.p0 = &ConsoleObject->pos; fq.p1 = &tpnt; fq.startseg = ConsoleObject->segnum; fq.rad = 0; fq.thisobjnum = 0; fq.ignore_obj_list = NULL; fq.flags = 0; find_vector_intersection(&fq,&hit_data); if (hit_data.hit_type==HIT_WALL && hit_data.hit_seg!=-1) object_create_explosion(hit_data.hit_seg,&hit_data.hit_pnt,i2f(3)+rand()*6,VCLIP_SMALL_EXPLOSION); explosion_wait2 = (0xa00 + rand()/8)/2; } switch (Endlevel_sequence) { case EL_OFF: return; case EL_FLYTHROUGH: { do_endlevel_flythrough(0); if (ConsoleObject->segnum == transition_segnum) { int objnum; Endlevel_sequence = EL_LOOKBACK; objnum = obj_create(OBJ_CAMERA, 0, ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0, CT_NONE,MT_NONE,RT_NONE); if (objnum == -1) { //can't get object, so abort mprintf((1, "Can't get object for endlevel sequence. Aborting endlevel sequence.\n")); stop_endlevel_sequence(); return; } Viewer = endlevel_camera = &Objects[objnum]; select_cockpit(CM_LETTERBOX); fly_objects[1] = fly_objects[0]; fly_objects[1].obj = endlevel_camera; fly_objects[1].speed = (5*cur_fly_speed)/4; fly_objects[1].offset_frac = 0x4000; vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,i2f(7)); timer=0x20000; } break; } case EL_LOOKBACK: { do_endlevel_flythrough(0); do_endlevel_flythrough(1); if (timer>0) { timer -= FrameTime; if (timer < 0) //reduce speed fly_objects[1].speed = fly_objects[0].speed; } if (endlevel_camera->segnum == exit_segnum) { vms_angvec cam_angles,exit_seg_angles; Endlevel_sequence = EL_OUTSIDE; timer = i2f(2); vm_vec_negate(&endlevel_camera->orient.fvec); vm_vec_negate(&endlevel_camera->orient.rvec); vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient); vm_extract_angles_matrix(&exit_seg_angles,&mine_exit_orient); bank_rate = (-exit_seg_angles.b - cam_angles.b)/2; ConsoleObject->control_type = endlevel_camera->control_type = CT_NONE; //_MARK_("Starting outside");//Commented out by KRB #ifdef SLEW_ON slew_obj = endlevel_camera; #endif } break; } case EL_OUTSIDE: { #ifndef SLEW_ON vms_angvec cam_angles; #endif vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifndef SLEW_ON vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,-2*cur_fly_speed)); vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.uvec,fixmul(FrameTime,-cur_fly_speed/10)); vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient); cam_angles.b += fixmul(bank_rate,FrameTime); vm_angles_2_matrix(&endlevel_camera->orient,&cam_angles); #endif timer -= FrameTime; if (timer < 0) { Endlevel_sequence = EL_STOPPED; vm_extract_angles_matrix(&player_angles,&ConsoleObject->orient); timer = i2f(3); } break; } case EL_STOPPED: { get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); timer -= FrameTime; if (timer < 0) { #ifdef SLEW_ON slew_obj = endlevel_camera; _do_slew_movement(endlevel_camera,1,1); timer += FrameTime; //make time stop break; #else #ifdef SHORT_SEQUENCE stop_endlevel_sequence(); #else Endlevel_sequence = EL_PANNING; vm_extract_angles_matrix(&camera_cur_angles,&endlevel_camera->orient); timer = i2f(3); if (Game_mode & GM_MULTI) { // try to skip part of the seq if multiplayer stop_endlevel_sequence(); return; } //mprintf((0,"Switching to pan...\n")); #endif //SHORT_SEQUENCE #endif //SLEW_ON } break; } #ifndef SHORT_SEQUENCE case EL_PANNING: { #ifndef SLEW_ON int mask; #endif get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifdef SLEW_ON _do_slew_movement(endlevel_camera,1,1); #else get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos); mask = chase_angles(&camera_cur_angles,&camera_desired_angles); vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles); if ((mask&5) == 5) { vms_vector tvec; Endlevel_sequence = EL_CHASING; //_MARK_("Done outside");//Commented out -KRB vm_vec_normalized_dir_quick(&tvec,&station_pos,&ConsoleObject->pos); vm_vector_2_matrix(&ConsoleObject->orient,&tvec,&surface_orient.uvec,NULL); desired_fly_speed *= 2; //mprintf((0,"Switching to chase...\n")); } #endif break; } case EL_CHASING: { fix d,speed_scale; #ifdef SLEW_ON _do_slew_movement(endlevel_camera,1,1); #endif get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos); chase_angles(&camera_cur_angles,&camera_desired_angles); #ifndef SLEW_ON vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles); #endif d = vm_vec_dist_quick(&ConsoleObject->pos,&endlevel_camera->pos); speed_scale = fixdiv(d,i2f(0x20)); if (d<f1_0) d=f1_0; get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos); chase_angles(&player_angles,&player_dest_angles); vm_angles_2_matrix(&ConsoleObject->orient,&player_angles); vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed)); #ifndef SLEW_ON vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,fixmul(speed_scale,cur_fly_speed))); if (vm_vec_dist(&ConsoleObject->pos,&station_pos) < i2f(10)) stop_endlevel_sequence(); #endif break; } #endif //ifdef SHORT_SEQUENCE } }
int _do_slew_movement(object *obj, int check_keys, int check_joy ) { int moved = 0; vms_vector svel, movement; //scaled velocity (per this frame) vms_matrix rotmat,new_pm; int joy_x,joy_y,btns; int joyx_moved,joyy_moved; vms_angvec rotang; if (keyd_pressed[KEY_PAD5]) vm_vec_zero(&obj->phys_info.velocity); if (check_keys) { obj->phys_info.velocity.x += VEL_SPEED * (key_down_time(KEY_PAD9) - key_down_time(KEY_PAD7)); obj->phys_info.velocity.y += VEL_SPEED * (key_down_time(KEY_PADMINUS) - key_down_time(KEY_PADPLUS)); obj->phys_info.velocity.z += VEL_SPEED * (key_down_time(KEY_PAD8) - key_down_time(KEY_PAD2)); rotang.pitch = (key_down_time(KEY_LBRACKET) - key_down_time(KEY_RBRACKET))/ROT_SPEED; rotang.bank = (key_down_time(KEY_PAD1) - key_down_time(KEY_PAD3))/ROT_SPEED; rotang.head = (key_down_time(KEY_PAD6) - key_down_time(KEY_PAD4))/ROT_SPEED; } else rotang.pitch = rotang.bank = rotang.head = 0; //check for joystick movement if (check_joy && joy_present) { joy_get_pos(&joy_x,&joy_y); btns=joy_get_btns(); joyx_moved = (abs(joy_x - old_joy_x)>JOY_NULL); joyy_moved = (abs(joy_y - old_joy_y)>JOY_NULL); if (abs(joy_x) < JOY_NULL) joy_x = 0; if (abs(joy_y) < JOY_NULL) joy_y = 0; if (btns) if (!rotang.pitch) rotang.pitch = fixmul(-joy_y * 512,FrameTime); else; else if (joyy_moved) obj->phys_info.velocity.z = -joy_y * 8192; if (!rotang.head) rotang.head = fixmul(joy_x * 512,FrameTime); if (joyx_moved) old_joy_x = joy_x; if (joyy_moved) old_joy_y = joy_y; } moved = rotang.pitch | rotang.bank | rotang.head; vm_angles_2_matrix(&rotmat,&rotang); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; vm_transpose_matrix(&new_pm); //make those columns rows moved |= obj->phys_info.velocity.x | obj->phys_info.velocity.y | obj->phys_info.velocity.z; svel = obj->phys_info.velocity; vm_vec_scale(&svel,FrameTime); //movement in this frame vm_vec_rotate(&movement,&svel,&new_pm); vm_vec_add2(&obj->pos,&movement); moved |= (movement.x || movement.y || movement.z); return moved; }
// ------------------------------------------------------------------ // swarm_update_direction() // // Check if we want to update the direction of a swarm missile. // void swarm_update_direction(object *objp, float frametime) { weapon_info *wip; weapon *wp; object *hobjp; swarm_info *swarmp; vec3d obj_to_target; float vel, target_dist, radius, missile_speed, missile_dist; physics_info *pi; Assert(objp->instance >= 0 && objp->instance < MAX_WEAPONS); wp = &Weapons[objp->instance]; if (wp->swarm_index == -1) { return; } wip = &Weapon_info[wp->weapon_info_index]; hobjp = wp->homing_object; pi = &Objects[wp->objnum].phys_info; swarmp = &Swarm_missiles[wp->swarm_index]; // check if homing is lost.. if it is then get a new path to move swarm missile along if ( swarmp->homing_objnum != -1 && hobjp == &obj_used_list ) { swarmp->change_timestamp = 1; swarmp->path_num = -1; swarmp->homing_objnum = -1; } if ( hobjp != &obj_used_list ) { swarmp->homing_objnum = OBJ_INDEX(hobjp); } if ( timestamp_elapsed(swarmp->change_timestamp) ) { if ( swarmp->path_num == -1 ) { if ( Objects[objp->parent].type != OBJ_SHIP ) { //AL: parent ship died... so just pick some random paths swarmp->path_num = myrand()%4; } else { ship *parent_shipp; parent_shipp = &Ships[Objects[objp->parent].instance]; swarmp->path_num = (parent_shipp->next_swarm_path++)%4; if ( parent_shipp->next_swarm_path%4 == 0 ) { swarmp->flags ^= SWARM_POSITIVE_PATH; } } vm_vec_scale_add(&swarmp->original_target, &objp->pos, &objp->orient.vec.fvec, SWARM_CONE_LENGTH); swarmp->circle_rvec = objp->orient.vec.rvec; swarmp->circle_uvec = objp->orient.vec.uvec; swarmp->change_count = 1; swarmp->change_time = fl2i(SWARM_CHANGE_DIR_TIME + SWARM_TIME_VARIANCE*(frand() - 0.5f) * 2); vm_vec_zero(&swarmp->last_offset); missile_speed = pi->speed; missile_dist = missile_speed * swarmp->change_time/1000.0f; if ( missile_dist < SWARM_DIST_OFFSET ) { missile_dist=i2fl(SWARM_DIST_OFFSET); } swarmp->angle_offset = (float)(asin(SWARM_DIST_OFFSET / missile_dist)); Assert(!_isnan(swarmp->angle_offset) ); } swarmp->change_timestamp = timestamp(swarmp->change_time); // check if swarm missile is homing, if so need to calculate a new target pos to turn towards if ( hobjp != &obj_used_list && f2fl(Missiontime - wp->creation_time) > 0.5f && ( f2fl(Missiontime - wp->creation_time) > wip->free_flight_time ) ) { swarmp->original_target = wp->homing_pos; // Calculate a rvec and uvec that will determine the displacement from the // intended target. Use crossprod to generate a right vector, from the missile // up vector and the vector connecting missile to the homing object. swarmp->circle_uvec = objp->orient.vec.uvec; swarmp->circle_rvec = objp->orient.vec.rvec; missile_speed = pi->speed; missile_dist = missile_speed * swarmp->change_time/1000.0f; if ( missile_dist < SWARM_DIST_OFFSET ) { missile_dist = i2fl(SWARM_DIST_OFFSET); } swarmp->angle_offset = (float)(asin(SWARM_DIST_OFFSET / missile_dist)); Assert(!_isnan(swarmp->angle_offset) ); } vm_vec_sub(&obj_to_target, &swarmp->original_target, &objp->pos); target_dist = vm_vec_mag_quick(&obj_to_target); swarmp->last_dist = target_dist; // If homing swarm missile is close to target, let missile home in on original target if ( target_dist < SWARM_DIST_STOP_SWARMING ) { swarmp->new_target = swarmp->original_target; goto swarm_new_target_calced; } radius = (float)tan(swarmp->angle_offset) * target_dist; vec3d rvec_component, uvec_component; swarmp->change_count++; if ( swarmp->change_count > 2 ) { swarmp->flags ^= SWARM_POSITIVE_PATH; swarmp->change_count = 0; } // pick a new path number to follow once at center if ( swarmp->change_count == 1 ) { swarmp->path_num = swarmp->path_num + myrand()%3; if ( swarmp->path_num > 3 ) { swarmp->path_num = 0; } } vm_vec_zero(&rvec_component); vm_vec_zero(&uvec_component); switch ( swarmp->path_num ) { case 0: // straight up and down if ( swarmp->flags & SWARM_POSITIVE_PATH ) vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, radius); else vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, -radius); break; case 1: // left/right if ( swarmp->flags & SWARM_POSITIVE_PATH ) vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, radius); else vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, -radius); break; case 2: // top/right - bottom/left if ( swarmp->flags & SWARM_POSITIVE_PATH ) { vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, radius); vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, radius); } else { vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, -radius); vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, -radius); } break; case 3: // top-left - bottom/right if ( swarmp->flags & SWARM_POSITIVE_PATH ) { vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, -radius); vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, radius); } else { vm_vec_copy_scale( &rvec_component, &swarmp->circle_rvec, radius); vm_vec_copy_scale( &uvec_component, &swarmp->circle_uvec, -radius); } break; default: Int3(); break; } swarmp->new_target = swarmp->original_target; vm_vec_zero(&swarmp->last_offset); vm_vec_add(&swarmp->last_offset, &uvec_component, &rvec_component); vm_vec_add2(&swarmp->new_target, &swarmp->last_offset); } else { if ( hobjp != &obj_used_list && f2fl(Missiontime - wp->creation_time) > 0.5f ) { swarmp->new_target = swarmp->original_target; if ( swarmp->last_dist < SWARM_DIST_STOP_SWARMING ) { swarmp->new_target = wp->homing_pos; goto swarm_new_target_calced; } vm_vec_add2(&swarmp->new_target, &swarmp->last_offset); } } swarm_new_target_calced: ai_turn_towards_vector(&swarmp->new_target, objp, frametime, wip->turn_time, NULL, NULL, 0.0f, 0); vel = vm_vec_mag(&objp->phys_info.desired_vel); vm_vec_copy_scale(&objp->phys_info.desired_vel, &objp->orient.vec.fvec, vel); }
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); } }
void draw_world(grs_canvas *screen_canvas,editor_view *v,segment *mine_ptr,int depth) { vms_vector viewer_position; #if DOUBLE_BUFFER grs_canvas temp_canvas; // mprintf(0, "\n"); // if ( screen_canvas == LargeViewBox->canvas ) { // CurrentBigCanvas ^= 1; // // gr_set_current_canvas( BigCanvas[CurrentBigCanvas] ); // // } else { gr_init_sub_canvas(&temp_canvas,canv_offscreen,0,0, screen_canvas->cv_bitmap.bm_w,screen_canvas->cv_bitmap.bm_h); gr_set_current_canvas(&temp_canvas); // } #else gr_set_current_canvas(screen_canvas); #endif //mprintf(0, "\n"); ui_mouse_hide(); //g3_set_points(Segment_points,Vertices); viewer_position = v->ev_matrix.fvec; vm_vec_scale(&viewer_position,-v->ev_dist); vm_vec_add2(&viewer_position,&Ed_view_target); gr_clear_canvas(0); g3_start_frame(); g3_set_view_matrix(&viewer_position,&v->ev_matrix,v->ev_zoom); render_start_frame(); gr_setcolor(PLAINSEG_COLOR); // Draw all segments or only connected segments. // We might want to draw all segments if we have broken the mine into pieces. if (Draw_all_segments) draw_mine_all(Segments, Automap_test); else draw_mine(mine_ptr,depth); // Draw the found segments if (!Automap_test) { draw_warning_segments(); draw_group_segments(); draw_found_segments(); draw_selected_segments(); draw_special_segments(); // Highlight group segment and side. if (current_group > -1) if (Groupsegp[current_group]) { gr_setcolor(GROUPSEG_COLOR); draw_segment(Groupsegp[current_group]); gr_setcolor(GROUPSIDE_COLOR); draw_seg_side(Groupsegp[current_group],Groupside[current_group]); } // Highlight marked segment and side. if (Markedsegp) { gr_setcolor(MARKEDSEG_COLOR); draw_segment(Markedsegp); gr_setcolor(MARKEDSIDE_COLOR); draw_seg_side(Markedsegp,Markedside); } // Highlight current segment and current side. gr_setcolor(CURSEG_COLOR); draw_segment(Cursegp); gr_setcolor(CURSIDE_COLOR); draw_seg_side(Cursegp,Curside); gr_setcolor(CUREDGE_COLOR); draw_side_edge(Cursegp,Curside,Curedge); // Draw coordinate axes if we are rendering the large view. if (Show_axes_flag) if (screen_canvas == LargeViewBox->canvas) draw_coordinate_axes(); // Label the window gr_set_fontcolor((v==current_view)?CRED:CWHITE, -1 ); if ( screen_canvas == LargeViewBox->canvas ) { gr_ustring( 5, 5, "USER VIEW" ); switch (Large_view_index) { case 0: gr_ustring( 85, 5, "-- TOP"); break; case 1: gr_ustring( 85, 5, "-- FRONT"); break; case 2: gr_ustring( 85, 5, "-- RIGHT"); break; } } else #if ORTHO_VIEWS else if ( screen_canvas == TopViewBox->canvas ) gr_ustring( 5, 5, "TOP" ); else if ( screen_canvas == FrontViewBox->canvas ) gr_ustring( 5, 5, "FRONT" ); else if ( screen_canvas == RightViewBox->canvas ) gr_ustring( 5, 5, "RIGHT" ); #else Error("Ortho views have been removed, what gives?\n"); #endif }
// ----------------------------------------------------------------------------------------------------------- // add rotational velocity & acceleration void do_physics_sim_rot(object *obj) { vms_angvec tangles; vms_matrix rotmat,new_orient; //fix rotdrag_scale; physics_info *pi; Assert(FrameTime > 0); //Get MATT if hit this! pi = &obj->mtype.phys_info; if (!(pi->rotvel.x || pi->rotvel.y || pi->rotvel.z || pi->rotthrust.x || pi->rotthrust.y || pi->rotthrust.z)) return; if (obj->mtype.phys_info.drag) { int count; vms_vector accel; fix drag,r,k; count = FrameTime / FT; r = FrameTime % FT; k = fixdiv(r,FT); drag = (obj->mtype.phys_info.drag*5)/2; if (obj->mtype.phys_info.flags & PF_USES_THRUST) { vm_vec_copy_scale(&accel,&obj->mtype.phys_info.rotthrust,fixdiv(f1_0,obj->mtype.phys_info.mass)); while (count--) { vm_vec_add2(&obj->mtype.phys_info.rotvel,&accel); vm_vec_scale(&obj->mtype.phys_info.rotvel,f1_0-drag); } //do linear scale on remaining bit of time vm_vec_scale_add2(&obj->mtype.phys_info.rotvel,&accel,k); vm_vec_scale(&obj->mtype.phys_info.rotvel,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.rotvel,total_drag); } } //now rotate object //unrotate object for bank caused by turn if (obj->mtype.phys_info.turnroll) { vms_matrix new_pm; tangles.p = tangles.h = 0; tangles.b = -obj->mtype.phys_info.turnroll; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } tangles.p = fixmul(obj->mtype.phys_info.rotvel.x,FrameTime); tangles.h = fixmul(obj->mtype.phys_info.rotvel.y,FrameTime); tangles.b = fixmul(obj->mtype.phys_info.rotvel.z,FrameTime); vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_orient,&obj->orient,&rotmat); obj->orient = new_orient; if (obj->mtype.phys_info.flags & PF_TURNROLL) set_object_turnroll(obj); //re-rotate object for bank caused by turn if (obj->mtype.phys_info.turnroll) { vms_matrix new_pm; tangles.p = tangles.h = 0; tangles.b = obj->mtype.phys_info.turnroll; vm_angles_2_matrix(&rotmat,&tangles); vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat); obj->orient = new_pm; } check_and_fix_matrix(&obj->orient); }
void dock_calc_docked_center_helper(object *objp, dock_function_info *infop) { // add object position and increment count vm_vec_add2(infop->maintained_variables.vecp_value, &objp->pos); infop->maintained_variables.int_value++; }
// ----------------------------------------------------------------------------------------------------------- //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 }
// Adds velocity to position // finds velocity and displacement in local coords void physics_sim_vel(vec3d * position, physics_info * pi, float sim_time, matrix *orient) { vec3d local_disp; // displacement in this frame vec3d local_v_in; // velocity in local coords at the start of this frame vec3d local_desired_vel; // desired velocity in local coords vec3d local_v_out; // velocity in local coords following this frame vec3d damp; // Maybe clear the reduced_damp flag. // This fixes the problem of the player getting near-instantaneous acceleration under unknown circumstances. // The larger problem is probably that PF_USE_VEL is getting stuck set. if ((pi->flags & PF_REDUCED_DAMP) && (timestamp_elapsed(pi->reduced_damp_decay))) { pi->flags &= ~PF_REDUCED_DAMP; } // Set up damping constants based on special conditions // ie. shockwave, collision, weapon, dead if (pi->flags & PF_DEAD_DAMP) { // side_slip_time_const is already quite large and now needs to be applied in all directions vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, pi->side_slip_time_const ); } else if (pi->flags & PF_REDUCED_DAMP) { // case of shock, weapon, collide, etc. if ( timestamp_elapsed(pi->reduced_damp_decay) ) { vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f ); } else { // damp is multiplied by fraction and not fraction^2, gives better collision separation float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME; damp.xyz.x = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left ); damp.xyz.y = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left ); damp.xyz.z = pi->side_slip_time_const * reduced_damp_fraction_time_left * REDUCED_DAMP_FACTOR; } } else { // regular damping if (pi->use_newtonian_damp) { vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, pi->side_slip_time_const ); } else { vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f ); } } // Note: CANNOT maintain a *local velocity* since a rotation can occur in this frame. // thus the local velocity of in the next frame can be different (this would require rotate to change local vel // and this is not desired // get local components of current velocity vm_vec_rotate (&local_v_in, &pi->vel, orient); // get local components of desired velocity vm_vec_rotate (&local_desired_vel, &pi->desired_vel, orient); // find updated LOCAL velocity and position in the local x direction apply_physics (damp.xyz.x, local_desired_vel.xyz.x, local_v_in.xyz.x, sim_time, &local_v_out.xyz.x, &local_disp.xyz.x); // find updated LOCAL velocity and position in the local y direction apply_physics (damp.xyz.y, local_desired_vel.xyz.y, local_v_in.xyz.y, sim_time, &local_v_out.xyz.y, &local_disp.xyz.y); // find updated LOCAL velocity and position in the local z direction // for player ship, damp should normally be zero, but may be altered in a shockwave // in death, shockwave,etc. we want damping time const large for all 3 axes // warp in test - make excessive speed drop exponentially from max allowed // become (0.01x in 3 sec) int special_warp_in = FALSE; float excess = local_v_in.xyz.z - pi->max_vel.xyz.z; if (excess > 5 && (pi->flags & PF_SPECIAL_WARP_IN)) { special_warp_in = TRUE; float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST)); local_v_out.xyz.z = pi->max_vel.xyz.z + excess * exp_factor; local_disp.xyz.z = (pi->max_vel.xyz.z * sim_time) + excess * (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor)); } else if (pi->flags & PF_SPECIAL_WARP_OUT) { float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST)); vec3d temp; vm_vec_rotate(&temp, &pi->prev_ramp_vel, orient); float deficeit = temp.xyz.z - local_v_in.xyz.z; local_v_out.xyz.z = local_v_in.xyz.z + deficeit * (1.0f - exp_factor); local_disp.xyz.z = (local_v_in.xyz.z * sim_time) + deficeit * (sim_time - (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor))); } else { apply_physics (damp.xyz.z, local_desired_vel.xyz.z, local_v_in.xyz.z, sim_time, &local_v_out.xyz.z, &local_disp.xyz.z); } // maybe turn off special warp in flag if ((pi->flags & PF_SPECIAL_WARP_IN) && (excess < 5)) { pi->flags &= ~(PF_SPECIAL_WARP_IN); } // update world position from local to world coords using orient vec3d world_disp; vm_vec_unrotate (&world_disp, &local_disp, orient); vm_vec_add2 (position, &world_disp); // update world velocity vm_vec_unrotate(&pi->vel, &local_v_out, orient); if (special_warp_in) { vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient); } }