// Return true if object A is expected to collide with object B within time duration // For purposes of this check, the first object moves from current location to predicted // location. The second object is assumed to be where it will be at time duration, NOT // where it currently is. // radius_scale is used to control the precision of the check. // If 0.0, then use polygon models to perform check, slow and accurate // If !0.0, then use as a scale on the radius of the objects. 1.0 is Descent style // collisions. Larger values can be used to be sloppy about the collisions which // is useful if a moving object wants to prevent a collision. int objects_will_collide(object *A, object *B, float duration, float radius_scale) { object A_future; vec3d hitpos; A_future = *A; vm_vec_scale_add2(&A_future.pos, &A->phys_info.vel, duration); if (radius_scale == 0.0f) { return ship_check_collision_fast(B, &A_future, &hitpos ); } else { float size_A, size_B, dist, r; vec3d nearest_point; size_A = A->radius * radius_scale; size_B = B->radius * radius_scale; // If A is moving, check along vector. if (A->phys_info.speed != 0.0f) { r = find_nearest_point_on_line(&nearest_point, &A->pos, &A_future.pos, &B->pos); if (r < 0) { nearest_point = A->pos; } else if (r > 1) { nearest_point = A_future.pos; } dist = vm_vec_dist_quick(&B->pos, &nearest_point); return (dist < size_A + size_B); } else { return vm_vec_dist_quick(&B->pos, &A->pos) < size_A + size_B; } } }
// ---------------------------------------------------------------------------------------------- void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_render_vertices, short *render_vertices, int objnum) { int vv; if (obj_intensity) { fix obji_64 = obj_intensity*64; // for pretty dim sources, only process vertices in object's own segment. if (obji_64 <= F1_0*8) { short *vp = Segments[obj_seg].verts; for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++) { int vertnum; vms_vector *vertpos; fix dist; vertnum = vp[vv]; vertpos = &Vertices[vertnum]; dist = vm_vec_dist_quick(obj_pos, vertpos); dist = fixmul(dist/4, dist/4); if (dist < obji_64) { if (dist < MIN_LIGHT_DIST) dist = MIN_LIGHT_DIST; Dynamic_light[vertnum] += fixdiv(obj_intensity, dist); } } } else { for (vv=FrameCount&1; vv<n_render_vertices; vv+=2) { int vertnum; vms_vector *vertpos; fix dist; int apply_light; vertnum = render_vertices[vv]; vertpos = &Vertices[vertnum]; dist = vm_vec_dist_quick(obj_pos, vertpos); apply_light = 0; if (dist < obji_64) { if (dist < MIN_LIGHT_DIST) dist = MIN_LIGHT_DIST; Dynamic_light[vertnum] += fixdiv(obj_intensity, dist); } } } } }
static float get_current_alpha(vec3d *pos) { float dist; float alpha; const float inner_radius = 30.0f; const float magic_num = 2.75f; // determine what alpha to draw this bitmap with // higher alpha the closer the bitmap gets to the eye dist = vm_vec_dist_quick(&Eye_position, pos); // if the point is inside the inner radius, alpha is based on distance to the player's eye, // becoming more transparent as it gets close if (dist <= inner_radius) { // alpha per meter between the magic # and the inner radius alpha = 0.99999f / (inner_radius - magic_num); // above value times the # of meters away we are alpha *= (dist - magic_num); return (alpha < 0.05f) ? 0.0f : alpha; } return 0.99999f; }
unsigned int DistanceTo(int nav) { if (nav >= MAX_NAVPOINTS || nav < 0) return 0xFFFFFFFF; return (uint)vm_vec_dist_quick(&Player_obj->pos, Navs[nav].GetPosition()); }
// 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; }
/** * Render jump node * * @param pos World position * @param view_pos Viewer's world position, can be NULL */ void CJumpNode::RenderDEPRECATED(vec3d *pos, vec3d *view_pos) { Assert(pos != NULL); // Assert(view_pos != NULL); - view_pos can be NULL if(m_flags & JN_HIDE) return; if(m_modelnum < 0) return; matrix node_orient = IDENTITY_MATRIX; int mr_flags = MR_NO_LIGHTING; if(!(m_flags & JN_SHOW_POLYS)) { mr_flags |= MR_NO_CULL | MR_NO_POLYS | MR_SHOW_OUTLINE_PRESET; } if ( Fred_running ) { gr_set_color_fast(&m_display_color); model_render_DEPRECATED(m_modelnum, &node_orient, pos, mr_flags ); } else { if (m_flags & JN_USE_DISPLAY_COLOR) { gr_set_color_fast(&m_display_color); } else if ( view_pos != NULL) { int alpha_index = HUD_color_alpha; // generate alpha index based on distance to jump this float dist; dist = vm_vec_dist_quick(view_pos, pos); // linearly interpolate alpha. At 1000m or less, full intensity. At 10000m or more 1/2 intensity. if ( dist < 1000 ) { alpha_index = HUD_COLOR_ALPHA_USER_MAX - 2; } else if ( dist > 10000 ) { alpha_index = HUD_COLOR_ALPHA_USER_MIN; } else { alpha_index = fl2i( HUD_COLOR_ALPHA_USER_MAX - 2 + (dist-1000) * (HUD_COLOR_ALPHA_USER_MIN-HUD_COLOR_ALPHA_USER_MAX-2) / (9000) + 0.5f); if ( alpha_index < HUD_COLOR_ALPHA_USER_MIN ) { alpha_index = HUD_COLOR_ALPHA_USER_MIN; } } gr_set_color_fast(&HUD_color_defaults[alpha_index]); } else { gr_set_color(HUD_color_red, HUD_color_green, HUD_color_blue); } model_render_DEPRECATED(m_modelnum, &node_orient, pos, mr_flags ); } }
/** * Render debris */ void debris_render(object * obj) { int i, num, swapped; polymodel *pm; debris *db; swapped = -1; pm = NULL; num = obj->instance; Assert(num >= 0 && num < MAX_DEBRIS_PIECES); db = &Debris[num]; Assert(db->flags & DEBRIS_USED); texture_info *tbase = NULL; model_clear_instance( db->model_num ); // Swap in a different texture depending on the species if (db->species >= 0) { pm = model_get( db->model_num ); //WMC - Someday, we should have glowing debris. if ( pm != NULL && (pm->n_textures == 1) ) { tbase = &pm->maps[0].textures[TM_BASE_TYPE]; swapped = tbase->GetTexture(); tbase->SetTexture(Species_info[db->species].debris_texture.bitmap_id); } } // Only render electrical arcs if within 500m of the eye (for a 10m piece) if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) { for (i=0; i<MAX_DEBRIS_ARCS; i++ ) { if ( timestamp_valid( db->arc_timestamp[i] ) ) { model_add_arc( db->model_num, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_NORMAL ); } } } if ( db->is_hull ) { MONITOR_INC(NumHullDebrisRend,1); submodel_render( db->model_num, db->submodel_num, &obj->orient, &obj->pos ); } else { MONITOR_INC(NumSmallDebrisRend,1); submodel_render( db->model_num, db->submodel_num, &obj->orient, &obj->pos, MR_NO_LIGHTING ); } if (tbase != NULL && (swapped!=-1) && pm) { tbase->SetTexture(swapped); } }
int asteroid_editor::query_modified() { int i; for (i=0; i<1 /*MAX_ASTEROID_FIELDS*/; i++) { if (a_field[i].num_initial_asteroids != Asteroid_field.num_initial_asteroids) return 1; if (vm_vec_dist_quick(&a_field[i].vel, &Asteroid_field.vel) == 0.0f) return 1; if (a_field[i].min_bound.x != Asteroid_field.min_bound.x) return 1; if (a_field[i].min_bound.y != Asteroid_field.min_bound.y) return 1; if (a_field[i].min_bound.z != Asteroid_field.min_bound.z) return 1; if (a_field[i].max_bound.x != Asteroid_field.max_bound.x) return 1; if (a_field[i].max_bound.y != Asteroid_field.max_bound.y) return 1; if (a_field[i].max_bound.z != Asteroid_field.max_bound.z) return 1; if (a_field[i].has_inner_bound != Asteroid_field.has_inner_bound) return 1; if (a_field[i].field_type != Asteroid_field.field_type) return 1; if (a_field[i].has_inner_bound) { if (a_field[i].inner_max_bound.x != Asteroid_field.inner_max_bound.x) return 1; if (a_field[i].inner_max_bound.y != Asteroid_field.inner_max_bound.y) return 1; if (a_field[i].inner_max_bound.z != Asteroid_field.inner_max_bound.z) return 1; if (a_field[i].inner_min_bound.x != Asteroid_field.inner_min_bound.x) return 1; if (a_field[i].inner_min_bound.y != Asteroid_field.inner_min_bound.y) return 1; if (a_field[i].inner_min_bound.z != Asteroid_field.inner_min_bound.z) return 1; } } return 0; }
// Creates a bunch of particles. You pass a structure // rather than a bunch of parameters. void particle_emit( particle_emitter *pe, int type, int optional_data, float range ) { int i, n; if ( !Particles_enabled ) return; int n1, n2; // Account for detail int percent = get_percent(Detail.num_particles); //Particle rendering drops out too soon. Seems to be around 150 m. Is it detail level controllable? I'd like it to be 500-1000 float min_dist = 125.0f; float dist = vm_vec_dist_quick( &pe->pos, &Eye_position ) / range; if ( dist > min_dist ) { percent = fl2i( i2fl(percent)*min_dist / dist ); if ( percent < 1 ) { return; } } //mprintf(( "Dist = %.1f, percent = %d%%\n", dist, percent )); n1 = (pe->num_low*percent)/100; n2 = (pe->num_high*percent)/100; // How many to emit? n = (rand() % (n2-n1+1)) + n1; if ( n < 1 ) return; for (i=0; i<n; i++ ) { // Create a particle vec3d tmp_vel; vec3d normal; // What normal the particle emit arond float radius = (( pe->max_rad - pe->min_rad ) * frand()) + pe->min_rad; float speed = (( pe->max_vel - pe->min_vel ) * frand()) + pe->min_vel; float life = (( pe->max_life - pe->min_life ) * frand()) + pe->min_life; normal.xyz.x = pe->normal.xyz.x + (frand()*2.0f - 1.0f)*pe->normal_variance; normal.xyz.y = pe->normal.xyz.y + (frand()*2.0f - 1.0f)*pe->normal_variance; normal.xyz.z = pe->normal.xyz.z + (frand()*2.0f - 1.0f)*pe->normal_variance; vm_vec_normalize_safe( &normal ); vm_vec_scale_add( &tmp_vel, &pe->vel, &normal, speed ); particle_create( &pe->pos, &tmp_vel, life, radius, type, optional_data ); } }
// Return true if the vector from *start_pos to *end_pos is within objp->radius*radius_scale of *objp int vector_object_collision(vec3d *start_pos, vec3d *end_pos, object *objp, float radius_scale) { float dist, r; vec3d nearest_point; r = find_nearest_point_on_line(&nearest_point, start_pos, end_pos, &objp->pos); if ((r >= 0.0f) && (r <= 1.0f)) { dist = vm_vec_dist_quick(&objp->pos, &nearest_point); return (dist < objp->radius * radius_scale); } else return 0; }
// Return true if object A is expected to collide with object B within time duration // For purposes of this check, the first object moves from current location to predicted // location. The second object is assumed to be where it will be at time duration, NOT // where it currently is. // radius_scale is used to control the precision of the check. // If 0.0, then use polygon models to perform check, slow and accurate // If !0.0, then use as a scale on the radius of the objects. 1.0 is Descent style // collisions. Larger values can be used to be sloppy about the collisions which // is useful if a moving object wants to prevent a collision. int objects_will_collide(object *A, object *B, float duration, float radius_scale) { vec3d prev_pos; vec3d hitpos; int ret; prev_pos = A->pos; vm_vec_scale_add2(&A->pos, &A->phys_info.vel, duration); if (radius_scale == 0.0f) { ret = ship_check_collision_fast(B, A, &hitpos); } else { float size_A, size_B, dist, r; vec3d nearest_point; size_A = A->radius * radius_scale; size_B = B->radius * radius_scale; // If A is moving, check along vector. if (A->phys_info.speed != 0.0f) { r = find_nearest_point_on_line(&nearest_point, &prev_pos, &A->pos, &B->pos); if (r < 0) { nearest_point = prev_pos; } else if (r > 1) { nearest_point = A->pos; } dist = vm_vec_dist_quick(&B->pos, &nearest_point); ret = (dist < size_A + size_B); } else { ret = vm_vec_dist_quick(&B->pos, &prev_pos) < size_A + size_B; } } // Reset the position to the previous value A->pos = prev_pos; return ret; }
/** * If debris piece *db is far away from all players, make it go away very soon. * In single player game, delete if MAX_DEBRIS_DIST from player. * In multiplayer game, delete if MAX_DEBRIS_DIST from all players. */ void maybe_delete_debris(debris *db) { object *objp; if (timestamp_elapsed(db->next_distance_check) && timestamp_elapsed(db->must_survive_until)) { if (!(Game_mode & GM_MULTIPLAYER)) { // In single player game, just check against player. if (vm_vec_dist_quick(&Player_obj->pos, &Objects[db->objnum].pos) > MAX_DEBRIS_DIST) db->lifeleft = 0.1f; else db->next_distance_check = timestamp(DEBRIS_DISTANCE_CHECK_TIME); } else { for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) { if (objp->flags[Object::Object_Flags::Player_ship]) { if (vm_vec_dist_quick(&objp->pos, &Objects[db->objnum].pos) < MAX_DEBRIS_DIST) { db->next_distance_check = timestamp(DEBRIS_DISTANCE_CHECK_TIME); return; } } } db->lifeleft = 0.1f; } } }
// ------------------------------------------------------------------------------------ // shockwave_render() // // Draw the shockwave identified by handle // // input: objp => pointer to shockwave object // void shockwave_render(object *objp) { shockwave *sw; shockwave_info *si; vertex p; Assert(objp->type == OBJ_SHOCKWAVE); Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES); sw = &Shockwaves[objp->instance]; si = &Shockwave_info[sw->shockwave_info_index]; if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){ return; } if ( (sw->current_bitmap < 0) && (sw->model_id < 0) ) return; // turn off fogging if(The_mission.flags & MISSION_FLAG_FULLNEB){ gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0); } if (sw->model_id > -1) { float model_Interp_scale_xyz = sw->radius / 50.0f; model_set_warp_globals( model_Interp_scale_xyz, model_Interp_scale_xyz, model_Interp_scale_xyz, -1, 1.0f - (sw->radius/sw->outer_radius) ); float dist = vm_vec_dist_quick( &sw->pos, &Eye_position ); model_set_detail_level((int)(dist / (sw->radius * 10.0f))); model_render( sw->model_id, &Objects[sw->objnum].orient, &sw->pos, MR_NO_LIGHTING | MR_NO_FOGGING | MR_NORMAL | MR_CENTER_ALPHA | MR_NO_CULL, sw->objnum); model_set_warp_globals(); }else{ if (!Cmdline_nohtl) { g3_transfer_vertex(&p, &sw->pos); } else { g3_rotate_vertex(&p, &sw->pos); } gr_set_bitmap(sw->current_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.3f ); g3_draw_rotated_bitmap(&p, fl_radian(sw->rot_angles.p), sw->radius, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT); } }
void bng_process_segment(object *objp, fix damage, segment *segp, int depth, byte *visited) { int i, sidenum; if (depth > MAX_BLAST_GLASS_DEPTH) return; depth++; for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) { int tm; fix dist; vms_vector pnt; // Process only walls which have glass. if ((tm=segp->sides[sidenum].tmap_num2) != 0) { int ec, db; tm &= 0x3fff; //tm without flags if ((((ec=TmapInfo[tm].eclip_num)!=-1) && ((db=Effects[ec].dest_bm_num)!=-1 && !(Effects[ec].flags&EF_ONE_SHOT))) || (ec==-1 && (TmapInfo[tm].destroyed!=-1))) { compute_center_point_on_side(&pnt, segp, sidenum); dist = vm_vec_dist_quick(&pnt, &objp->pos); if (dist < damage/2) { dist = find_connected_distance(&pnt, segp-Segments, &objp->pos, objp->segnum, MAX_BLAST_GLASS_DEPTH, WID_RENDPAST_FLAG); if ((dist > 0) && (dist < damage/2)) check_effect_blowup(segp, sidenum, &pnt, &Objects[objp->ctype.laser_info.parent_num], 1); } } } } for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) { int segnum = segp->children[i]; if (segnum != -1) { if (!visited[segnum]) { if (WALL_IS_DOORWAY(segp, i) & WID_FLY_FLAG) { visited[segnum] = 1; bng_process_segment(objp, damage, &Segments[segnum], depth, visited); } } } } }
// Determine is ship is visible by team // Goober5000 - now accounts for primitive sensors int ship_is_visible_by_team(object *target, ship *viewer) { Assert(target); Assert(viewer); Assert(target->type == OBJ_SHIP); // not visible if viewer has primitive sensors if (viewer->flags[Ship::Ship_Flags::Primitive_sensors]) return 0; // not visible if out of range if ((Hud_max_targeting_range > 0) && (vm_vec_dist_quick(&target->pos, &Objects[viewer->objnum].pos) > Hud_max_targeting_range)) return 0; // now evaluate this the old way int ship_num = target->instance; int team = viewer->team; return (int)Ship_visibility_by_team[team][ship_num]; }
void shockwave_render(object *objp, draw_list *scene) { shockwave *sw; vertex p; Assert(objp->type == OBJ_SHOCKWAVE); Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES); sw = &Shockwaves[objp->instance]; if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){ return; } if ( (sw->current_bitmap < 0) && (sw->model_id < 0) ) return; if (sw->model_id > -1) { vec3d scale; scale.xyz.x = scale.xyz.y = scale.xyz.z = sw->radius / 50.0f; model_render_params render_info; render_info.set_warp_params(-1, 1.0f - (sw->radius/sw->outer_radius), scale); float dist = vm_vec_dist_quick( &sw->pos, &Eye_position ); render_info.set_detail_level_lock((int)(dist / (sw->radius * 10.0f))); render_info.set_flags(MR_NO_LIGHTING | MR_NO_FOGGING | MR_NORMAL | MR_CENTER_ALPHA | MR_NO_CULL | MR_NO_BATCH); render_info.set_object_number(sw->objnum); model_render_queue( &render_info, scene, sw->model_id, &Objects[sw->objnum].orient, &sw->pos); if ( Cmdline_fb_explosions ) { g3_transfer_vertex(&p, &sw->pos); distortion_add_bitmap_rotated( Shockwave_info[1].bitmap_id+shockwave_get_framenum(objp->instance, 94), TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } } else { if (!Cmdline_nohtl) { g3_transfer_vertex(&p, &sw->pos); } else { g3_rotate_vertex(&p, &sw->pos); } if ( Cmdline_fb_explosions ) { distortion_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } batch_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD, &p, fl_radians(sw->rot_angles.p), sw->radius ); } }
/** * Draw the shockwave identified by handle * * @param objp pointer to shockwave object */ void shockwave_render_DEPRECATED(object *objp) { shockwave *sw; vertex p; Assert(objp->type == OBJ_SHOCKWAVE); Assert(objp->instance >= 0 && objp->instance < MAX_SHOCKWAVES); memset(&p, 0, sizeof(p)); sw = &Shockwaves[objp->instance]; if( (sw->delay_stamp != -1) && !timestamp_elapsed(sw->delay_stamp)){ return; } if ( (sw->current_bitmap < 0) && (sw->model_id < 0) ) return; // turn off fogging if(The_mission.flags & MISSION_FLAG_FULLNEB){ gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0); } if (sw->model_id > -1) { float model_Interp_scale_xyz = sw->radius / 50.0f; model_set_warp_globals( model_Interp_scale_xyz, model_Interp_scale_xyz, model_Interp_scale_xyz, -1, 1.0f - (sw->radius/sw->outer_radius) ); float dist = vm_vec_dist_quick( &sw->pos, &Eye_position ); model_set_detail_level((int)(dist / (sw->radius * 10.0f))); model_render_DEPRECATED( sw->model_id, &Objects[sw->objnum].orient, &sw->pos, MR_DEPRECATED_NO_LIGHTING | MR_DEPRECATED_NO_FOGGING | MR_DEPRECATED_NORMAL | MR_DEPRECATED_CENTER_ALPHA | MR_DEPRECATED_NO_CULL, sw->objnum); model_set_warp_globals(); if(Cmdline_fb_explosions) { g3_transfer_vertex(&p, &sw->pos); distortion_add_bitmap_rotated( Shockwave_info[1].bitmap_id+shockwave_get_framenum(objp->instance, 94), TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } }else{ if (!Cmdline_nohtl) { g3_transfer_vertex(&p, &sw->pos); } else { g3_rotate_vertex(&p, &sw->pos); } if(Cmdline_fb_explosions) { distortion_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD | TMAP_FLAG_DISTORTION, &p, fl_radians(sw->rot_angles.p), sw->radius, ((sw->time_elapsed/sw->total_time)>0.9f)?(1.0f-(sw->time_elapsed/sw->total_time))*10.0f:1.0f ); } batch_add_bitmap_rotated( sw->current_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD, &p, fl_radians(sw->rot_angles.p), sw->radius ); } }
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 } }
void warpin_queue_render(draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d) { vec3d center; vec3d vecs[5]; vertex verts[5]; vm_vec_scale_add( ¢er, pos, &orient->vec.fvec, -(max_radius/2.5f)/3.0f ); if (Warp_glow_bitmap >= 0) { float r = radius; bool render_it = true; #define OUT_PERCENT1 0.80f #define OUT_PERCENT2 0.90f #define IN_PERCENT1 0.10f #define IN_PERCENT2 0.20f if (Cmdline_warp_flash) { if ( (life_percent >= IN_PERCENT1) && (life_percent < IN_PERCENT2) ) { r *= (life_percent - IN_PERCENT1) / (IN_PERCENT2 - IN_PERCENT1); //render_it = true; } else if ( (life_percent >= OUT_PERCENT1) && (life_percent < OUT_PERCENT2) ) { r *= (OUT_PERCENT2 - life_percent) / (OUT_PERCENT2 - OUT_PERCENT1); //render_it = true; } } if (render_it) { // Add in noise int noise_frame = fl2i(Missiontime/15.0f) % NOISE_NUM_FRAMES; r *= (0.40f + Noise[noise_frame] * 0.30f); // Bobboau's warp thingie, toggled by cmdline if (Cmdline_warp_flash) { r += powf((2.0f * life_percent) - 1.0f, 24.0f) * max_radius * 1.5f; } vecs[4] = center; verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f; g3_transfer_vertex( &verts[4], &vecs[4] ); float alpha = (The_mission.flags[Mission::Mission_Flags::Fullneb]) ? (1.0f - neb2_get_fog_intensity(obj)) : 1.0f; batch_add_bitmap(Warp_glow_bitmap, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_EMISSIVE , &verts[4], 0, r, alpha); } } if ( (Warp_model >= 0) && (warp_3d || Cmdline_3dwarp) ) { model_render_params render_info; float scale = radius / 25.0f; vec3d warp_scale; warp_scale.xyz.x = warp_scale.xyz.y = warp_scale.xyz.z = scale; float dist = vm_vec_dist_quick( pos, &Eye_position ); render_info.set_warp_params(texture_bitmap_num, radius/max_radius, warp_scale); render_info.set_detail_level_lock((int)(dist / (radius * 10.0f))); render_info.set_flags(MR_NO_LIGHTING | MR_NORMAL | MR_NO_FOGGING | MR_NO_CULL | MR_NO_BATCH); model_render_queue( &render_info, scene, Warp_model, orient, pos); } else { float Grid_depth = radius/2.5f; // gr_set_bitmap( texture_bitmap_num, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f ); vm_vec_scale_add( &vecs[0], ¢er, &orient->vec.uvec, radius ); vm_vec_scale_add2( &vecs[0], &orient->vec.rvec, -radius ); vm_vec_scale_add2( &vecs[0], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[1], ¢er, &orient->vec.uvec, radius ); vm_vec_scale_add2( &vecs[1], &orient->vec.rvec, radius ); vm_vec_scale_add2( &vecs[1], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[2], ¢er, &orient->vec.uvec, -radius ); vm_vec_scale_add2( &vecs[2], &orient->vec.rvec, radius ); vm_vec_scale_add2( &vecs[2], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[3], ¢er, &orient->vec.uvec, -radius ); vm_vec_scale_add2( &vecs[3], &orient->vec.rvec, -radius ); vm_vec_scale_add2( &vecs[3], &orient->vec.fvec, Grid_depth ); // vm_vec_scale_add( &vecs[4], ¢er, &orient->vec.fvec, -Grid_depth ); vecs[4] = center; verts[0].texture_position.u = 0.01f; verts[0].texture_position.v = 0.01f; verts[1].texture_position.u = 0.99f; verts[1].texture_position.v = 0.01f; verts[2].texture_position.u = 0.99f; verts[2].texture_position.v = 0.99f; verts[3].texture_position.u = 0.01f; verts[3].texture_position.v = 0.99f; verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f; g3_transfer_vertex( &verts[0], &vecs[0] ); g3_transfer_vertex( &verts[1], &vecs[1] ); g3_transfer_vertex( &verts[2], &vecs[2] ); g3_transfer_vertex( &verts[3], &vecs[3] ); g3_transfer_vertex( &verts[4], &vecs[4] ); warpin_batch_draw_face( texture_bitmap_num, &verts[0], &verts[4], &verts[1] ); warpin_batch_draw_face( texture_bitmap_num, &verts[1], &verts[4], &verts[2] ); warpin_batch_draw_face( texture_bitmap_num, &verts[4], &verts[3], &verts[2] ); warpin_batch_draw_face( texture_bitmap_num, &verts[0], &verts[3], &verts[4] ); } if (Warp_ball_bitmap > -1 && Cmdline_warp_flash == 1) { //flash_ball warp_ball(20, .1f,.25f, &vmd_z_vector, &vmd_zero_vector, 4.0f, 0.5f); flash_ball warp_ball(20, .1f,.25f, &orient->vec.fvec, pos, 4.0f, 0.5f); float adg = (2.0f * life_percent) - 1.0f; float pct = (powf(adg, 4.0f) - powf(adg, 128.0f)) * 4.0f; if (pct > 0.00001f) { warp_ball.render(Warp_ball_bitmap, max_radius * pct * 0.5f, adg * adg, adg * adg * 6.0f); } } }
object *object_create_explosion_sub(object *objp, short segnum, vms_vector * position, fix size, int vclip_type, fix maxdamage, fix maxdistance, fix maxforce, int parent ) { int objnum; object *obj; objnum = obj_create( OBJ_FIREBALL,vclip_type,segnum,position,&vmd_identity_matrix,size, CT_EXPLOSION,MT_NONE,RT_FIREBALL); if (objnum < 0 ) { mprintf((1, "Can't create object in object_create_explosion_sub.\n")); return NULL; } obj = &Objects[objnum]; //mprintf( 0, "Fireball created at %d, %d, %d\n", obj->pos.x, obj->pos.y, obj->pos.z ); //now set explosion-specific data obj->lifeleft = Vclip[vclip_type ].play_time; obj->ctype.expl_info.spawn_time = -1; obj->ctype.expl_info.delete_objnum = -1; obj->ctype.expl_info.delete_time = -1; if (maxdamage > 0) { fix dist, force; vms_vector pos_hit, vforce; fix damage; int i; object * obj0p = &Objects[0]; // -- now legal for badass explosions on a wall. Assert(objp != NULL); for (i=0; i<=Highest_object_index; i++ ) { // Weapons used to be affected by badass explosions, but this introduces serious problems. // When a smart bomb blows up, if one of its children goes right towards a nearby wall, it will // blow up, blowing up all the children. So I remove it. MK, 09/11/94 if ( (obj0p->type == OBJ_CNTRLCEN) || (obj0p->type==OBJ_PLAYER) || ((obj0p->type==OBJ_ROBOT) && ((Objects[parent].type != OBJ_ROBOT) || (Objects[parent].id != obj0p->id)))) { dist = vm_vec_dist_quick( &obj0p->pos, &obj->pos ); // Make damage be from 'maxdamage' to 0.0, where 0.0 is 'maxdistance' away; if ( dist < maxdistance ) { if (object_to_object_visibility(obj, obj0p, FQ_TRANSWALL)) { damage = maxdamage - fixmuldiv( dist, maxdamage, maxdistance ); force = maxforce - fixmuldiv( dist, maxforce, maxdistance ); // Find the force vector on the object vm_vec_sub( &vforce, &obj0p->pos, &obj->pos ); vm_vec_normalize_quick(&vforce); vm_vec_scale(&vforce, force ); // Find where the point of impact is... ( pos_hit ) vm_vec_scale(vm_vec_sub(&pos_hit, &obj->pos, &obj0p->pos), fixdiv(obj0p->size, obj0p->size + dist)); switch ( obj0p->type ) { case OBJ_ROBOT: phys_apply_force(obj0p,&vforce); // When a robot gets whacked by a badass force, he looks towards it because robots tend to get blasted from behind. { vms_vector neg_vforce; neg_vforce.x = vforce.x * -2 * (7 - Difficulty_level)/8; neg_vforce.y = vforce.y * -2 * (7 - Difficulty_level)/8; neg_vforce.z = vforce.z * -2 * (7 - Difficulty_level)/8; phys_apply_rot(obj0p,&neg_vforce); } if ( obj0p->shields >= 0 ) { if (apply_damage_to_robot(obj0p, damage, parent)) if ((objp != NULL) && (parent == Players[Player_num].objnum)) add_points_to_score(Robot_info[obj0p->id].score_value); } break; case OBJ_CNTRLCEN: if ( obj0p->shields >= 0 ) { apply_damage_to_controlcen(obj0p, damage, parent ); } break; case OBJ_PLAYER: { object * killer=NULL; vms_vector vforce2; if ((objp != NULL) && (Game_mode & GM_MULTI) && (objp->type == OBJ_PLAYER)) { // mprintf((0, "Damaged by player %d's explosion.\n", objp->id)); killer = objp; } vforce2 = vforce; if (parent > -1 ) { killer = &Objects[parent]; if (killer != ConsoleObject) // if someone else whacks you, cut force by 2x vforce2.x /= 2; vforce2.y /= 2; vforce2.z /= 2; } vforce2.x /= 2; vforce2.y /= 2; vforce2.z /= 2; phys_apply_force(obj0p,&vforce); phys_apply_rot(obj0p,&vforce2); if ( obj0p->shields >= 0 ) apply_damage_to_player(obj0p, killer, damage ); } break; default: Int3(); // Illegal object type } // end switch } else { ; // mprintf((0, "No badass: robot=%2i, dist=%7.3f, maxdistance=%7.3f .\n", i, f2fl(dist), f2fl(maxdistance))); } // end if (object_to_object_visibility... } // end if (dist < maxdistance) } obj0p++; } // end for } // end if (maxdamage... // mprintf(0, "\n"); return obj; }
void CJumpNode::Render(draw_list* scene, vec3d *pos, vec3d *view_pos) { Assert(pos != NULL); // Assert(view_pos != NULL); - view_pos can be NULL if(m_flags & JN_HIDE) return; if(m_modelnum < 0) return; matrix node_orient = IDENTITY_MATRIX; int mr_flags = MR_NO_LIGHTING | MR_NO_BATCH; if(!(m_flags & JN_SHOW_POLYS)) { mr_flags |= MR_NO_CULL | MR_NO_POLYS | MR_SHOW_OUTLINE | MR_SHOW_OUTLINE_HTL | MR_NO_TEXTURING; } model_render_params render_info; render_info.set_detail_level_lock(0); render_info.set_flags(mr_flags); if ( Fred_running ) { render_info.set_outline_color(m_display_color); model_render_queue(&render_info, scene, m_modelnum, &node_orient, pos); } else { if (m_flags & JN_USE_DISPLAY_COLOR) { //gr_set_color_fast(&m_display_color); render_info.set_outline_color(m_display_color); } else if ( view_pos != NULL) { int alpha_index = HUD_color_alpha; // generate alpha index based on distance to jump this float dist; dist = vm_vec_dist_quick(view_pos, pos); // linearly interpolate alpha. At 1000m or less, full intensity. At 10000m or more 1/2 intensity. if ( dist < 1000 ) { alpha_index = HUD_COLOR_ALPHA_USER_MAX - 2; } else if ( dist > 10000 ) { alpha_index = HUD_COLOR_ALPHA_USER_MIN; } else { alpha_index = fl2i( HUD_COLOR_ALPHA_USER_MAX - 2 + (dist-1000) * (HUD_COLOR_ALPHA_USER_MIN-HUD_COLOR_ALPHA_USER_MAX-2) / (9000) + 0.5f); if ( alpha_index < HUD_COLOR_ALPHA_USER_MIN ) { alpha_index = HUD_COLOR_ALPHA_USER_MIN; } } render_info.set_outline_color(HUD_color_defaults[alpha_index]); } else { render_info.set_outline_color(HUD_color_red, HUD_color_green, HUD_color_blue); } model_render_queue(&render_info, scene, m_modelnum, &node_orient, pos); } }
void warpin_render(object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d) { vec3d center; vec3d vecs[5]; vertex verts[5]; int saved_gr_zbuffering = gr_zbuffer_get(); gr_zbuffer_set(GR_ZBUFF_READ); vm_vec_scale_add( ¢er, pos, &orient->vec.fvec, -(max_radius/2.5f)/3.0f ); if (Warp_glow_bitmap >= 0) { float r = radius; bool render_it = true; #define OUT_PERCENT1 0.80f #define OUT_PERCENT2 0.90f #define IN_PERCENT1 0.10f #define IN_PERCENT2 0.20f if (Cmdline_warp_flash) { if ( (life_percent >= IN_PERCENT1) && (life_percent < IN_PERCENT2) ) { r *= (life_percent - IN_PERCENT1) / (IN_PERCENT2 - IN_PERCENT1); //render_it = true; } else if ( (life_percent >= OUT_PERCENT1) && (life_percent < OUT_PERCENT2) ) { r *= (OUT_PERCENT2 - life_percent) / (OUT_PERCENT2 - OUT_PERCENT1); //render_it = true; } } if (render_it) { // Add in noise int noise_frame = fl2i(Missiontime/15.0f) % NOISE_NUM_FRAMES; r *= (0.40f + Noise[noise_frame] * 0.30f); // Bobboau's warp thingie, toggled by cmdline if (Cmdline_warp_flash) { r += powf((2.0f * life_percent) - 1.0f, 24.0f) * max_radius * 1.5f; } vecs[4] = center; verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f; if (Cmdline_nohtl) { g3_rotate_vertex( &verts[4], &vecs[4] ); } else { g3_transfer_vertex( &verts[4], &vecs[4] ); } float alpha = (The_mission.flags & MISSION_FLAG_FULLNEB) ? (1.0f - neb2_get_fog_intensity(obj)) : 1.0f; gr_set_bitmap( Warp_glow_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, alpha ); g3_draw_bitmap( &verts[4], 0, r, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT ); } } if ( (Warp_model >= 0) && (warp_3d || Cmdline_3dwarp) ) { float scale = radius / 25.0f; model_set_warp_globals(scale, scale, scale, texture_bitmap_num, (radius/max_radius) ); float dist = vm_vec_dist_quick( pos, &Eye_position ); model_set_detail_level((int)(dist / (radius * 10.0f))); model_render( Warp_model, orient, pos, MR_LOCK_DETAIL | MR_NO_LIGHTING | MR_NORMAL | MR_NO_FOGGING | MR_NO_CULL ); model_set_warp_globals(); } else { float Grid_depth = radius/2.5f; gr_set_bitmap( texture_bitmap_num, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 1.0f ); vm_vec_scale_add( &vecs[0], ¢er, &orient->vec.uvec, radius ); vm_vec_scale_add2( &vecs[0], &orient->vec.rvec, -radius ); vm_vec_scale_add2( &vecs[0], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[1], ¢er, &orient->vec.uvec, radius ); vm_vec_scale_add2( &vecs[1], &orient->vec.rvec, radius ); vm_vec_scale_add2( &vecs[1], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[2], ¢er, &orient->vec.uvec, -radius ); vm_vec_scale_add2( &vecs[2], &orient->vec.rvec, radius ); vm_vec_scale_add2( &vecs[2], &orient->vec.fvec, Grid_depth ); vm_vec_scale_add( &vecs[3], ¢er, &orient->vec.uvec, -radius ); vm_vec_scale_add2( &vecs[3], &orient->vec.rvec, -radius ); vm_vec_scale_add2( &vecs[3], &orient->vec.fvec, Grid_depth ); // vm_vec_scale_add( &vecs[4], ¢er, &orient->vec.fvec, -Grid_depth ); vecs[4] = center; verts[0].texture_position.u = 0.01f; verts[0].texture_position.v = 0.01f; verts[1].texture_position.u = 0.99f; verts[1].texture_position.v = 0.01f; verts[2].texture_position.u = 0.99f; verts[2].texture_position.v = 0.99f; verts[3].texture_position.u = 0.01f; verts[3].texture_position.v = 0.99f; verts[4].texture_position.u = 0.5f; verts[4].texture_position.v = 0.5f; if (Cmdline_nohtl) { g3_rotate_vertex( &verts[0], &vecs[0] ); g3_rotate_vertex( &verts[1], &vecs[1] ); g3_rotate_vertex( &verts[2], &vecs[2] ); g3_rotate_vertex( &verts[3], &vecs[3] ); g3_rotate_vertex( &verts[4], &vecs[4] ); } else { g3_transfer_vertex( &verts[0], &vecs[0] ); g3_transfer_vertex( &verts[1], &vecs[1] ); g3_transfer_vertex( &verts[2], &vecs[2] ); g3_transfer_vertex( &verts[3], &vecs[3] ); g3_transfer_vertex( &verts[4], &vecs[4] ); } int cull = gr_set_cull(0); // fixes rendering problem in D3D - taylor draw_face( &verts[0], &verts[4], &verts[1] ); draw_face( &verts[1], &verts[4], &verts[2] ); draw_face( &verts[4], &verts[3], &verts[2] ); draw_face( &verts[0], &verts[3], &verts[4] ); gr_set_cull(cull); } if (Warp_ball_bitmap > -1 && Cmdline_warp_flash == 1) { flash_ball warp_ball(20, .1f,.25f, &vmd_z_vector, &vmd_zero_vector, 4.0f, 0.5f); float adg = (2.0f * life_percent) - 1.0f; float pct = (powf(adg, 4.0f) - powf(adg, 128.0f)) * 4.0f; if (pct > 0.00001f) { g3_start_instance_matrix(pos, orient, true); gr_set_bitmap(Warp_ball_bitmap, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, 0.9999f); warp_ball.render(max_radius * pct * 0.5f, adg * adg, adg * adg * 6.0f); g3_done_instance(true); } } gr_zbuffer_set( saved_gr_zbuffering ); }
/** * Checks weapon-weapon collisions. * @param pair obj_pair pointer to the two objects. pair->a and pair->b are weapons. * @return 1 if all future collisions between these can be ignored */ int collide_weapon_weapon( obj_pair * pair ) { float A_radius, B_radius; object *A = pair->a; object *B = pair->b; Assert( A->type == OBJ_WEAPON ); Assert( B->type == OBJ_WEAPON ); // Don't allow ship to shoot down its own missile. if (A->parent_sig == B->parent_sig) return 1; // Only shoot down teammate's missile if not traveling in nearly same direction. if (Weapons[A->instance].team == Weapons[B->instance].team) if (vm_vec_dot(&A->orient.vec.fvec, &B->orient.vec.fvec) > 0.7f) return 1; // Ignore collisions involving a bomb if the bomb is not yet armed. weapon *wpA, *wpB; weapon_info *wipA, *wipB; wpA = &Weapons[A->instance]; wpB = &Weapons[B->instance]; wipA = &Weapon_info[wpA->weapon_info_index]; wipB = &Weapon_info[wpB->weapon_info_index]; A_radius = A->radius; B_radius = B->radius; if (wipA->weapon_hitpoints > 0) { if (!(wipA->wi_flags2 & WIF2_HARD_TARGET_BOMB)) { A_radius *= 2; // Makes bombs easier to hit } if (wipA->wi_flags & WIF_LOCKED_HOMING) { if ( (wipA->max_lifetime - wpA->lifeleft) < The_mission.ai_profile->delay_bomb_arm_timer[Game_skill_level] ) return 0; } else if ( (wipA->lifetime - wpA->lifeleft) < The_mission.ai_profile->delay_bomb_arm_timer[Game_skill_level] ) return 0; } if (wipB->weapon_hitpoints > 0) { if (!(wipB->wi_flags2 & WIF2_HARD_TARGET_BOMB)) { B_radius *= 2; // Makes bombs easier to hit } if (wipB->wi_flags & WIF_LOCKED_HOMING) { if ( (wipB->max_lifetime - wpB->lifeleft) < The_mission.ai_profile->delay_bomb_arm_timer[Game_skill_level] ) return 0; } else if ( (wipB->lifetime - wpB->lifeleft) < The_mission.ai_profile->delay_bomb_arm_timer[Game_skill_level] ) return 0; } // Rats, do collision detection. if (collide_subdivide(&A->last_pos, &A->pos, A_radius, &B->last_pos, &B->pos, B_radius)) { Script_system.SetHookObjects(4, "Weapon", A, "WeaponB", B, "Self",A, "Object", B); bool a_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, A); //Should be reversed Script_system.SetHookObjects(4, "Weapon", B, "WeaponB", A, "Self",B, "Object", A); bool b_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, B); if(!a_override && !b_override) { float aDamage = wipA->damage; if (wipB->armor_type_idx >= 0) aDamage = Armor_types[wipB->armor_type_idx].GetDamage(aDamage, wipA->damage_type_idx, 1.0f); float bDamage = wipB->damage; if (wipA->armor_type_idx >= 0) bDamage = Armor_types[wipA->armor_type_idx].GetDamage(bDamage, wipB->damage_type_idx, 1.0f); if (wipA->weapon_hitpoints > 0) { if (wipB->weapon_hitpoints > 0) { // Two bombs collide, detonate both. if ((wipA->wi_flags & WIF_BOMB) && (wipB->wi_flags & WIF_BOMB)) { Weapons[A->instance].lifeleft = 0.01f; Weapons[B->instance].lifeleft = 0.01f; Weapons[A->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; Weapons[B->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } else { A->hull_strength -= bDamage; B->hull_strength -= aDamage; // safety to make sure either of the weapons die - allow 'bulkier' to keep going if ((A->hull_strength > 0.0f) && (B->hull_strength > 0.0f)) { if (wipA->weapon_hitpoints > wipB->weapon_hitpoints) { B->hull_strength = -1.0f; } else { A->hull_strength = -1.0f; } } if (A->hull_strength < 0.0f) { Weapons[A->instance].lifeleft = 0.01f; Weapons[A->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } if (B->hull_strength < 0.0f) { Weapons[B->instance].lifeleft = 0.01f; Weapons[B->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } } } else { A->hull_strength -= bDamage; Weapons[B->instance].lifeleft = 0.01f; Weapons[B->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; if (A->hull_strength < 0.0f) { Weapons[A->instance].lifeleft = 0.01f; Weapons[A->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } } } else if (wipB->weapon_hitpoints > 0) { B->hull_strength -= aDamage; Weapons[A->instance].lifeleft = 0.01f; Weapons[A->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; if (B->hull_strength < 0.0f) { Weapons[B->instance].lifeleft = 0.01f; Weapons[B->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } } // single player and multiplayer masters evaluate the scoring and kill stuff if (!MULTIPLAYER_CLIENT) { //Save damage for bomb so we can do scoring once it's destroyed. -Halleck if (wipA->wi_flags & WIF_BOMB) { scoring_add_damage_to_weapon(A, B, wipB->damage); //Update stats. -Halleck scoring_eval_hit(A, B, 0); } if (wipB->wi_flags & WIF_BOMB) { scoring_add_damage_to_weapon(B, A, wipA->damage); //Update stats. -Halleck scoring_eval_hit(B, A, 0); } } #ifndef NDEBUG float dist = 0.0f; if (Weapons[A->instance].lifeleft == 0.01f) { dist = vm_vec_dist_quick(&A->pos, &wpA->homing_pos); } if (Weapons[B->instance].lifeleft == 0.01f) { dist = vm_vec_dist_quick(&B->pos, &wpB->homing_pos); } #endif } if(!(b_override && !a_override)) { Script_system.SetHookObjects(4, "Weapon", A, "WeaponB", B, "Self",A, "Object", B); Script_system.RunCondition(CHA_COLLIDEWEAPON, '\0', NULL, A, wpA->weapon_info_index); } if((b_override && !a_override) || (!b_override && !a_override)) { //Should be reversed Script_system.SetHookObjects(4, "Weapon", B, "WeaponB", A, "Self",B, "Object", A); Script_system.RunCondition(CHA_COLLIDEWEAPON, '\0', NULL, B, wpB->weapon_info_index); } Script_system.RemHookVars(4, "Weapon", "WeaponB", "Self","ObjectB"); return 1; } return 0; }
// ---------------------------------------------------------------------------------------------------------- void robotmaker_proc( FuelCenter * robotcen ) { fix dist_to_player; vms_vector cur_object_loc; //, direction; int matcen_num, segnum, objnum; object *obj; fix top_time; vms_vector direction; if (robotcen->Enabled == 0) return; if (robotcen->Disable_time > 0) { robotcen->Disable_time -= FrameTime; if (robotcen->Disable_time <= 0) { robotcen->Enabled = 0; } } // No robot making in multiplayer mode. #ifdef NETWORK #ifndef SHAREWARE if ((Game_mode & GM_MULTI) && (!(Game_mode & GM_MULTI_ROBOTS) || !multi_i_am_master())) return; #else if (Game_mode & GM_MULTI) return; #endif #endif // Wait until transmorgafier has capacity to make a robot... if ( robotcen->Capacity <= 0 ) { return; } matcen_num = Segment2s[robotcen->segnum].matcen_num; if ( matcen_num == -1 ) { return; } if (RobotCenters[matcen_num].robot_flags[0]==0 && RobotCenters[matcen_num].robot_flags[1]==0) { return; } // Wait until we have a free slot for this puppy... // <<<<<<<<<<<<<<<< Num robots in mine >>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<< Max robots in mine >>>>>>>>>>>>>>> if ( (Players[Player_num].num_robots_level - Players[Player_num].num_kills_level) >= (Gamesave_num_org_robots + Num_extry_robots ) ) { return; } robotcen->Timer += FrameTime; switch( robotcen->Flag ) { case 0: // Wait until next robot can generate if (Game_mode & GM_MULTI) { top_time = ROBOT_GEN_TIME; } else { dist_to_player = vm_vec_dist_quick( &ConsoleObject->pos, &robotcen->Center ); top_time = dist_to_player/64 + d_rand() * 2 + F1_0*2; if ( top_time > ROBOT_GEN_TIME ) top_time = ROBOT_GEN_TIME + d_rand(); if ( top_time < F1_0*2 ) top_time = F1_0*3/2 + d_rand()*2; } if (robotcen->Timer > top_time ) { int count=0; int i, my_station_num = robotcen-Station; object *obj; // Make sure this robotmaker hasn't put out its max without having any of them killed. for (i=0; i<=Highest_object_index; i++) if (Objects[i].type == OBJ_ROBOT) if ((Objects[i].matcen_creator^0x80) == my_station_num) count++; if (count > Difficulty_level + 3) { robotcen->Timer /= 2; return; } // Whack on any robot or player in the matcen segment. count=0; segnum = robotcen->segnum; for (objnum=Segments[segnum].objects;objnum!=-1;objnum=Objects[objnum].next) { count++; if ( count > MAX_OBJECTS ) { Int3(); return; } if (Objects[objnum].type==OBJ_ROBOT) { collide_robot_and_materialization_center(&Objects[objnum]); robotcen->Timer = top_time/2; return; } else if (Objects[objnum].type==OBJ_PLAYER ) { collide_player_and_materialization_center(&Objects[objnum]); robotcen->Timer = top_time/2; return; } } compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]); // HACK!!! The 10 under here should be something equal to the 1/2 the size of the segment. obj = object_create_explosion(robotcen->segnum, &cur_object_loc, i2f(10), VCLIP_MORPHING_ROBOT ); if (obj) extract_orient_from_segment(&obj->orient,&Segments[robotcen->segnum]); if ( Vclip[VCLIP_MORPHING_ROBOT].sound_num > -1 ) { digi_link_sound_to_pos( Vclip[VCLIP_MORPHING_ROBOT].sound_num, robotcen->segnum, 0, &cur_object_loc, 0, F1_0 ); } robotcen->Flag = 1; robotcen->Timer = 0; } break; case 1: // Wait until 1/2 second after VCLIP started. if (robotcen->Timer > (Vclip[VCLIP_MORPHING_ROBOT].play_time/2) ) { robotcen->Capacity -= EnergyToCreateOneRobot; robotcen->Flag = 0; robotcen->Timer = 0; compute_segment_center(&cur_object_loc, &Segments[robotcen->segnum]); // If this is the first materialization, set to valid robot. if (RobotCenters[matcen_num].robot_flags[0] != 0 || RobotCenters[matcen_num].robot_flags[1] != 0) { int type; uint flags; sbyte legal_types[64]; // 64 bits, the width of robot_flags[]. int num_types, robot_index, i; num_types = 0; for (i=0;i<2;i++) { robot_index = i*32; flags = RobotCenters[matcen_num].robot_flags[i]; while (flags) { if (flags & 1) legal_types[num_types++] = robot_index; flags >>= 1; robot_index++; } } if (num_types == 1) type = legal_types[0]; else type = legal_types[(d_rand() * num_types) / 32768]; obj = create_morph_robot(&Segments[robotcen->segnum], &cur_object_loc, type ); if (obj != NULL) { #ifndef SHAREWARE #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_create_robot(robotcen-Station, obj-Objects, type); #endif #endif obj->matcen_creator = (robotcen-Station) | 0x80; // Make object faces player... vm_vec_sub( &direction, &ConsoleObject->pos,&obj->pos ); vm_vector_2_matrix( &obj->orient, &direction, &obj->orient.uvec, NULL); morph_start( obj ); //robotcen->last_created_obj = obj; //robotcen->last_created_sig = robotcen->last_created_obj->signature; } } }
int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float time_limit = 0.0f, int *next_hit = NULL) { mc_info mc, mc_shield, mc_hull; ship *shipp; ship_info *sip; weapon *wp; weapon_info *wip; Assert( ship_objp != NULL ); Assert( ship_objp->type == OBJ_SHIP ); Assert( ship_objp->instance >= 0 ); shipp = &Ships[ship_objp->instance]; sip = &Ship_info[shipp->ship_info_index]; Assert( weapon_objp != NULL ); Assert( weapon_objp->type == OBJ_WEAPON ); Assert( weapon_objp->instance >= 0 ); wp = &Weapons[weapon_objp->instance]; wip = &Weapon_info[wp->weapon_info_index]; Assert( shipp->objnum == OBJ_INDEX(ship_objp)); // Make ships that are warping in not get collision detection done if ( shipp->is_arriving() ) return 0; // Return information for AI to detect incoming fire. // Could perhaps be done elsewhere at lower cost --MK, 11/7/97 float dist = vm_vec_dist_quick(&ship_objp->pos, &weapon_objp->pos); if (dist < weapon_objp->phys_info.speed) { update_danger_weapon(ship_objp, weapon_objp); } int valid_hit_occurred = 0; // If this is set, then hitpos is set int quadrant_num = -1; polymodel *pm = model_get(sip->model_num); // total time is flFrametime + time_limit (time_limit used to predict collisions into the future) vec3d weapon_end_pos; vm_vec_scale_add( &weapon_end_pos, &weapon_objp->pos, &weapon_objp->phys_info.vel, time_limit ); // Goober5000 - I tried to make collision code here much saner... here begin the (major) changes mc_info_init(&mc); // set up collision structs mc.model_instance_num = shipp->model_instance_num; mc.model_num = sip->model_num; mc.submodel_num = -1; mc.orient = &ship_objp->orient; mc.pos = &ship_objp->pos; mc.p0 = &weapon_objp->last_pos; mc.p1 = &weapon_end_pos; mc.lod = sip->collision_lod; memcpy(&mc_shield, &mc, sizeof(mc_info)); memcpy(&mc_hull, &mc, sizeof(mc_info)); // (btw, these are leftover comments from below...) // // Note: This code is obviously stupid. We want to add the shield point if there is shield to hit, but: // 1. We want the size/color of the hit effect to indicate shield damage done. (i.e., for already-weak shield, smaller effect) // 2. Currently (8/9/97), apply_damage_to_shield() passes lefer damage to hull, which might not make sense. If // wouldn't have collided with hull, shouldn't do damage. Once this is fixed, the code below needs to cast the // vector through to the hull if there is leftover damage. // // WIF2_PIERCE_SHIELDS pierces shields // AL 1-14-97: "Puncture" doesn't mean penetrate shield anymore, it means that it punctures // hull to inflict maximum subsystem damage // // _argv[-1], 16 Jan 2005: Surface shields. // Surface shields allow for shields on a ship without a shield mesh. Good for putting real shields // on the Lucifer. This also fixes the strange bug where shots will occasionally go through the // shield mesh when they shouldn't. I don't know what causes this, but this fixes that -- shields // will absorb it when it hits the hull instead. This has no fancy graphical effect, though. // Someone should make one. // check both kinds of collisions int shield_collision = 0; int hull_collision = 0; // check shields for impact if (!(ship_objp->flags[Object::Object_Flags::No_shields])) { if (sip->flags[Ship::Info_Flags::Auto_spread_shields]) { // The weapon is not allowed to impact the shield before it reaches this point vec3d shield_ignored_until = weapon_objp->last_pos; float weapon_flown_for = vm_vec_dist(&wp->start_pos, &weapon_objp->last_pos); float min_weapon_span; if (sip->auto_shield_spread_min_span >= 0.0f) { min_weapon_span = sip->auto_shield_spread_min_span; } else { min_weapon_span = sip->auto_shield_spread; } // If weapon hasn't yet flown a distance greater than the maximum ignore // range, then some part of the currently checked range needs to be // ignored if (weapon_flown_for < min_weapon_span) { vm_vec_sub(&shield_ignored_until, &weapon_end_pos, &wp->start_pos); vm_vec_normalize(&shield_ignored_until); vm_vec_scale(&shield_ignored_until, min_weapon_span); vm_vec_add2(&shield_ignored_until, &wp->start_pos); } float this_range = vm_vec_dist(&weapon_objp->last_pos, &weapon_end_pos); // The range during which the weapon is not allowed to collide with the // shield, except if it actually hits the hull float ignored_range; // If the weapon has not yet surpassed the ignore range, calculate the // remaining ignore range if (vm_vec_dist(&wp->start_pos, &shield_ignored_until) > weapon_flown_for) ignored_range = vm_vec_dist(&weapon_objp->last_pos, &shield_ignored_until); else ignored_range = 0.0f; // The range during which the weapon may impact the shield float active_range = this_range - ignored_range; // During the ignored range, we only check for a ray collision with // the model if (ignored_range > 0.0f) { mc_shield.flags = MC_CHECK_MODEL; mc_shield.p1 = &shield_ignored_until; shield_collision = model_collide(&mc_shield); mc_shield.p1 = &weapon_end_pos; mc_shield.hit_dist = mc_shield.hit_dist * (ignored_range / this_range); } // If no collision with the model found in the ignore range, only // then do we check for sphereline collisions with the model during the // non-ignored range if (!shield_collision && weapon_flown_for + this_range > min_weapon_span) { mc_shield.p0 = &shield_ignored_until; mc_shield.p1 = &weapon_end_pos; mc_shield.radius = sip->auto_shield_spread; if (sip->auto_shield_spread_from_lod > -1) { mc_shield.lod = sip->auto_shield_spread_from_lod; } mc_shield.flags = MC_CHECK_MODEL | MC_CHECK_SPHERELINE; shield_collision = model_collide(&mc_shield); mc_shield.lod = sip->collision_lod; mc_shield.submodel_num = -1; // Because we manipulated p0 and p1 above, hit_dist will be // relative to the values we used, not the values the rest of // the code expects; this fixes that mc_shield.p0 = &weapon_objp->last_pos; mc_shield.p1 = &weapon_end_pos; mc_shield.hit_dist = (ignored_range + (active_range * mc_shield.hit_dist)) / this_range; } if (shield_collision) { // If we used a sphereline check, then the collision point will lie // somewhere on the ship's hull; this re-positions it to lie on the // correct point along the weapon's path if (mc_shield.flags & MC_CHECK_SPHERELINE) { vec3d tempv; vm_vec_sub(&tempv, mc_shield.p1, mc_shield.p0); vm_vec_scale(&tempv, mc_shield.hit_dist); vm_vec_add2(&tempv, mc_shield.p0); mc_shield.hit_point_world = tempv; } // Re-calculate hit_point because it's likely pointing to the wrong // place vec3d tempv; vm_vec_sub(&tempv, &mc_shield.hit_point_world, &ship_objp->pos); vm_vec_rotate(&mc_shield.hit_point, &tempv, &ship_objp->orient); } } else if (sip->flags[Ship::Info_Flags::Surface_shields]) { if (pm->shield.ntris > 0) { // If there is a shield mesh, we need to check that first mc_shield.flags = MC_CHECK_SHIELD; shield_collision = model_collide(&mc_shield); } if (!shield_collision) { // But if no shield mesh or it was missed, check for a hull collision mc_shield.flags = MC_CHECK_MODEL; shield_collision = model_collide(&mc_shield); // Because we used MC_CHECK_MODEL, the returned hit position might be // in a submodel's frame of reference, so we need to ensure we end up // in the ship's frame of reference vec3d local_pos; vm_vec_sub(&local_pos, &mc_shield.hit_point_world, &ship_objp->pos); vm_vec_rotate(&mc_shield.hit_point, &local_pos, &ship_objp->orient); } } else { // Normal collision check against a shield mesh mc_shield.flags = MC_CHECK_SHIELD; shield_collision = (pm->shield.ntris > 0) ? model_collide(&mc_shield) : 0; } } // If we found a shield collision but were only checking for a simple model // collision, we can re-use the same collision info for the hull as well if (shield_collision && mc_shield.flags == MC_CHECK_MODEL) { memcpy(&mc_hull, &mc_shield, sizeof(mc_info)); hull_collision = shield_collision; // The weapon has impacted on the hull, so if it should therefore bypass // the shields altogether, we do it here if (sip->auto_shield_spread_bypass) { shield_collision = 0; } } else { mc_hull.flags = MC_CHECK_MODEL; hull_collision = model_collide(&mc_hull); } if (shield_collision) { // pick out the shield quadrant quadrant_num = get_quadrant(&mc_shield.hit_point, ship_objp); // make sure that the shield is active in that quadrant if (shipp->flags[Ship::Ship_Flags::Dying] || !ship_is_shield_up(ship_objp, quadrant_num)) quadrant_num = -1; // see if we hit the shield if (quadrant_num >= 0) { // do the hit effect if ( mc_shield.shield_hit_tri != -1 && (mc_shield.hit_dist*(flFrametime + time_limit) - flFrametime) < 0.0f ) { add_shield_point(OBJ_INDEX(ship_objp), mc_shield.shield_hit_tri, &mc_shield.hit_point); } // if this weapon pierces the shield, then do the hit effect, but act like a shield collision never occurred; // otherwise, we have a valid hit on this shield if (wip->wi_flags[Weapon::Info_Flags::Pierce_shields]) quadrant_num = -1; else valid_hit_occurred = 1; } } // see which impact we use if (shield_collision && valid_hit_occurred) { memcpy(&mc, &mc_shield, sizeof(mc_info)); Assert(quadrant_num >= 0); } else if (hull_collision) { memcpy(&mc, &mc_hull, sizeof(mc_info)); valid_hit_occurred = 1; } // check if the hit point is beyond the clip plane when warping out. if ((shipp->flags[Ship::Ship_Flags::Depart_warp]) && (shipp->warpout_effect) && (valid_hit_occurred)) { vec3d warp_pnt, hit_direction; matrix warp_orient; shipp->warpout_effect->getWarpPosition(&warp_pnt); shipp->warpout_effect->getWarpOrientation(&warp_orient); vm_vec_sub(&hit_direction, &mc.hit_point_world, &warp_pnt); if (vm_vec_dot(&hit_direction, &warp_orient.vec.fvec) < 0.0f) { valid_hit_occurred = 0; } } // deal with predictive collisions. Find their actual hit time and see if they occured in current frame if (next_hit && valid_hit_occurred) { // find hit time *next_hit = (int) (1000.0f * (mc.hit_dist*(flFrametime + time_limit) - flFrametime) ); if (*next_hit > 0) // if hit occurs outside of this frame, do not do damage return 1; } if ( valid_hit_occurred ) { wp->collisionInfo = new mc_info; // The weapon will free this memory later memcpy(wp->collisionInfo, &mc, sizeof(mc_info)); Script_system.SetHookObjects(4, "Ship", ship_objp, "Weapon", weapon_objp, "Self",ship_objp, "Object", weapon_objp); bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, ship_objp); Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp); bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, weapon_objp); if(!ship_override && !weapon_override) { if (shield_collision && quadrant_num >= 0) { if ((sip->shield_impact_explosion_anim > -1) && (wip->shield_impact_explosion_radius > 0)) { shield_impact_explosion(&mc.hit_point, ship_objp, wip->shield_impact_explosion_radius, sip->shield_impact_explosion_anim); } } ship_weapon_do_hit_stuff(ship_objp, weapon_objp, &mc.hit_point_world, &mc.hit_point, quadrant_num, mc.hit_submodel, mc.hit_normal); } Script_system.SetHookObjects(2, "Self",ship_objp, "Object", weapon_objp); if(!(weapon_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDEWEAPON, '\0', NULL, ship_objp, wp->weapon_info_index); Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp); if((weapon_override && !ship_override) || (!weapon_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, weapon_objp); Script_system.RemHookVars(4, "Ship", "Weapon", "Self","Object"); } else if ((Missiontime - wp->creation_time > F1_0/2) && (wip->is_homing()) && (wp->homing_object == ship_objp)) { if (dist < wip->shockwave.inner_rad) { vec3d vec_to_ship; vm_vec_normalized_dir(&vec_to_ship, &ship_objp->pos, &weapon_objp->pos); if (vm_vec_dot(&vec_to_ship, &weapon_objp->orient.vec.fvec) < 0.0f) { // check if we're colliding against "invisible" ship if (!(shipp->flags[Ship::Ship_Flags::Dont_collide_invis])) { wp->lifeleft = 0.001f; if (ship_objp == Player_obj) nprintf(("Jim", "Frame %i: Weapon %d set to detonate, dist = %7.3f.\n", Framecount, OBJ_INDEX(weapon_objp), dist)); valid_hit_occurred = 1; } } } } return valid_hit_occurred; }
int automap_process_input(window *wind, d_event *event, automap *am) { vms_matrix tempm; Controls = am->controls; kconfig_read_controls(event, 1); am->controls = Controls; memset(&Controls, 0, sizeof(control_info)); if ( !am->controls.automap_state && (am->leave_mode==1) ) { window_close(wind); return 1; } if ( am->controls.automap_count > 0) { am->controls.automap_count = 0; if (am->leave_mode==0) { window_close(wind); return 1; } } if (PlayerCfg.AutomapFreeFlight) { if ( am->controls.fire_primary_count > 0) { // Reset orientation am->viewMatrix = Objects[Players[Player_num].objnum].orient; vm_vec_scale_add(&am->view_position, &Objects[Players[Player_num].objnum].pos, &am->viewMatrix.fvec, -ZOOM_DEFAULT ); am->controls.fire_primary_count = 0; } if (am->controls.pitch_time || am->controls.heading_time || am->controls.bank_time) { vms_angvec tangles; vms_matrix new_m; tangles.p = fixdiv( am->controls.pitch_time, ROT_SPEED_DIVISOR ); tangles.h = fixdiv( am->controls.heading_time, ROT_SPEED_DIVISOR ); tangles.b = fixdiv( am->controls.bank_time, ROT_SPEED_DIVISOR*2 ); vm_angles_2_matrix(&tempm, &tangles); vm_matrix_x_matrix(&new_m,&am->viewMatrix,&tempm); am->viewMatrix = new_m; check_and_fix_matrix(&am->viewMatrix); } if ( am->controls.forward_thrust_time || am->controls.vertical_thrust_time || am->controls.sideways_thrust_time ) { vm_vec_scale_add2( &am->view_position, &am->viewMatrix.fvec, am->controls.forward_thrust_time*ZOOM_SPEED_FACTOR ); vm_vec_scale_add2( &am->view_position, &am->viewMatrix.uvec, am->controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &am->view_position, &am->viewMatrix.rvec, am->controls.sideways_thrust_time*SLIDE_SPEED ); // Crude wrapping check if (am->view_position.x > F1_0*32000) am->view_position.x = F1_0*32000; if (am->view_position.x < -F1_0*32000) am->view_position.x = -F1_0*32000; if (am->view_position.y > F1_0*32000) am->view_position.y = F1_0*32000; if (am->view_position.y < -F1_0*32000) am->view_position.y = -F1_0*32000; if (am->view_position.z > F1_0*32000) am->view_position.z = F1_0*32000; if (am->view_position.z < -F1_0*32000) am->view_position.z = -F1_0*32000; } } else { if ( am->controls.fire_primary_count > 0) { // Reset orientation am->viewDist = ZOOM_DEFAULT; am->tangles.p = PITCH_DEFAULT; am->tangles.h = 0; am->tangles.b = 0; am->view_target = Objects[Players[Player_num].objnum].pos; am->controls.fire_primary_count = 0; } am->viewDist -= am->controls.forward_thrust_time*ZOOM_SPEED_FACTOR; am->tangles.p += fixdiv( am->controls.pitch_time, ROT_SPEED_DIVISOR ); am->tangles.h += fixdiv( am->controls.heading_time, ROT_SPEED_DIVISOR ); am->tangles.b += fixdiv( am->controls.bank_time, ROT_SPEED_DIVISOR*2 ); if ( am->controls.vertical_thrust_time || am->controls.sideways_thrust_time ) { vms_angvec tangles1; vms_vector old_vt; old_vt = am->view_target; tangles1 = am->tangles; vm_angles_2_matrix(&tempm,&tangles1); vm_matrix_x_matrix(&am->viewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); vm_vec_scale_add2( &am->view_target, &am->viewMatrix.uvec, am->controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &am->view_target, &am->viewMatrix.rvec, am->controls.sideways_thrust_time*SLIDE_SPEED ); if ( vm_vec_dist_quick( &am->view_target, &Objects[Players[Player_num].objnum].pos) > i2f(1000) ) am->view_target = old_vt; } vm_angles_2_matrix(&tempm,&am->tangles); vm_matrix_x_matrix(&am->viewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); if ( am->viewDist < ZOOM_MIN_VALUE ) am->viewDist = ZOOM_MIN_VALUE; if ( am->viewDist > ZOOM_MAX_VALUE ) am->viewDist = ZOOM_MAX_VALUE; } return 0; }
void do_automap( int key_code ) { int done=0; vms_matrix tempm; vms_angvec tangles; int leave_mode=0; int first_time=1; int pcx_error; int i; int c; char filename[] = "MAP.PCX"; fix entry_time; int pause_game=1; // Set to 1 if everything is paused during automap...No pause during net. fix t1, t2; control_info saved_control_info; int Max_segments_away = 0; int SegmentLimit = 1; key_code = key_code; // disable warning... if ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME) && (!Endlevel_sequence)) pause_game = 0; if (pause_game) stop_time(); create_name_canv(); Max_edges = min(MAX_EDGES_FROM_VERTS(Num_vertices),MAX_EDGES); //make maybe smaller than max //Edges = malloc( sizeof(Edge_info)*Max_edges); //if ( Edges == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(Edge_info)*Max_edges/1024)); // return; //} //DrawingListBright = malloc( sizeof(short)*Max_edges); //if ( DrawingListBright == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(short)*Max_edges/1024)); // return; //} mprintf( (0, "Num_vertices=%d, Max_edges=%d, (MAX:%d)\n", Num_vertices, Max_edges, MAX_EDGES )); mprintf( (0, "Allocated %d K for automap edge list\n", (sizeof(Edge_info)+sizeof(short))*Max_edges/1024 )); gr_palette_clear(); gr_init_sub_canvas(&Page,&VR_render_buffer[0],0, 0, 640, 480); gr_init_sub_canvas(&DrawingPage,&Page,38,77,564,381); #if 0 gr_init_sub_canvas(&Pages[0],grd_curcanv,0,0,320,400); gr_init_sub_canvas(&Pages[1],grd_curcanv,0,401,320,400); gr_init_sub_canvas(&DrawingPages[0],&Pages[0],16,69,288,272); gr_init_sub_canvas(&DrawingPages[1],&Pages[1],16,69,288,272); #endif gr_set_current_canvas(&Page); pcx_error = pcx_read_bitmap(filename,&(grd_curcanv->cv_bitmap),BM_LINEAR,NULL); if ( pcx_error != PCX_ERROR_NONE ) { printf("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); Error("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); return; } gr_set_curfont(Gamefonts[GFONT_BIG_1]); gr_set_fontcolor(BM_XRGB(20, 20, 20), -1); gr_printf( 80, 36,TXT_AUTOMAP,GFONT_BIG_1); gr_set_curfont(Gamefonts[GFONT_SMALL]); gr_set_fontcolor(BM_XRGB(20, 20, 20), -1); gr_printf( 265, 27,TXT_TURN_SHIP); gr_printf( 265, 44,TXT_SLIDE_UPDOWN); gr_printf( 265, 61,TXT_VIEWING_DISTANCE); gr_set_current_canvas(&DrawingPage); automap_build_edge_list(); if ( ViewDist==0 ) ViewDist = ZOOM_DEFAULT; ViewMatrix = Objects[Players[Player_num].objnum].orient; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; done = 0; view_target = Objects[Players[Player_num].objnum].pos; t1 = entry_time = timer_get_fixed_seconds(); t2 = t1; //Fill in Automap_visited from Objects[Players[Player_num].objnum].segnum Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); while(!done) { #ifndef MAC_SHAREWARE redbook_restart_track(); #endif if ( leave_mode==0 && Controls.automap_state && (timer_get_fixed_seconds()-entry_time)>LEAVE_TIME) leave_mode = 1; if ( !Controls.automap_state && (leave_mode==1) ) done=1; if (!pause_game) { ushort old_wiggle; saved_control_info = Controls; // Save controls so we can zero them memset(&Controls,0,sizeof(control_info)); // Clear everything... old_wiggle = ConsoleObject->mtype.phys_info.flags & PF_WIGGLE; // Save old wiggle ConsoleObject->mtype.phys_info.flags &= ~PF_WIGGLE; // Turn off wiggle #ifdef NETWORK if (multi_menu_poll()) done = 1; #endif // GameLoop( 0, 0 ); // Do game loop with no rendering and no reading controls. ConsoleObject->mtype.phys_info.flags |= old_wiggle; // Restore wiggle Controls = saved_control_info; } controls_read_all(); if ( Controls.automap_down_count ) { if (leave_mode==0) done = 1; c = 0; } while( (c=key_inkey()) ) { switch( c ) { #ifndef NDEBUG case KEY_BACKSP: Int3(); break; #endif case KEY_PRINT_SCREEN: save_screen_shot(1); break; case KEY_ESC: if (leave_mode==0) done = 1; break; case KEY_ALTED+KEY_F: // Alt+F shows full map, if cheats enabled if (Cheats_enabled) { uint t; t = Players[Player_num].flags; Players[Player_num].flags |= PLAYER_FLAGS_MAP_ALL_CHEAT; automap_build_edge_list(); Players[Player_num].flags=t; } break; #ifndef NDEBUG case KEY_DEBUGGED+KEY_F: { for (i=0; i<=Highest_segment_index; i++ ) Automap_visited[i] = 1; automap_build_edge_list(); Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); } break; #endif case KEY_MINUS: if (SegmentLimit > 1) { SegmentLimit--; adjust_segment_limit(SegmentLimit); } break; case KEY_EQUAL: if (SegmentLimit < Max_segments_away) { SegmentLimit++; adjust_segment_limit(SegmentLimit); } break; } } if ( Controls.fire_primary_down_count ) { // Reset orientation ViewDist = ZOOM_DEFAULT; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; view_target = Objects[Players[Player_num].objnum].pos; } ViewDist -= Controls.forward_thrust_time*ZOOM_SPEED_FACTOR; tangles.p += fixdiv( Controls.pitch_time, ROT_SPEED_DIVISOR ); tangles.h += fixdiv( Controls.heading_time, ROT_SPEED_DIVISOR ); tangles.b += fixdiv( Controls.bank_time, ROT_SPEED_DIVISOR*2 ); if ( Controls.vertical_thrust_time || Controls.sideways_thrust_time ) { vms_angvec tangles1; vms_vector old_vt; old_vt = view_target; tangles1 = tangles; vm_angles_2_matrix(&tempm,&tangles1); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); vm_vec_scale_add2( &view_target, &ViewMatrix.uvec, Controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &view_target, &ViewMatrix.rvec, Controls.sideways_thrust_time*SLIDE_SPEED ); if ( vm_vec_dist_quick( &view_target, &Objects[Players[Player_num].objnum].pos) > i2f(1000) ) { view_target = old_vt; } } vm_angles_2_matrix(&tempm,&tangles); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); if ( ViewDist < ZOOM_MIN_VALUE ) ViewDist = ZOOM_MIN_VALUE; if ( ViewDist > ZOOM_MAX_VALUE ) ViewDist = ZOOM_MAX_VALUE; draw_automap(); if ( first_time ) { first_time = 0; gr_palette_load( gr_palette ); } t2 = timer_get_fixed_seconds(); if (pause_game) FrameTime=t2-t1; t1 = t2; } //free(Edges); //free(DrawingListBright); gr_free_canvas(name_canv); name_canv=NULL; mprintf( (0, "Automap memory freed\n" )); game_flush_inputs(); if (pause_game) start_time(); }
// Call this once/frame to process all super mines in the level. void process_super_mines_frame(void) { objnum_t start; object_step_interval_t add; // If we don't know of there being any super mines in the level, just // check every 8th object each frame. if (Super_mines_yes == 0) { start = objnum_t(FrameCount & 7); add = 8; } else { start = object_first; add = 1; } Super_mines_yes = 0; for (objnum_t i=start; i<=Highest_object_index; i+=add) { if ((Objects[i].type == OBJ_WEAPON) && (Objects[i].id == SUPERPROX_ID)) { objnum_t parent_num; parent_num = Objects[i].ctype.laser_info.parent_num; Super_mines_yes = 1; if (Objects[i].lifeleft + F1_0*2 < Weapon_info[SUPERPROX_ID].lifetime) { vms_vector *bombpos; bombpos = &Objects[i].pos; for (objnum_t j=object_first; j<=Highest_object_index; j++) { if ((Objects[j].type == OBJ_PLAYER) || (Objects[j].type == OBJ_ROBOT)) { fix dist; dist = vm_vec_dist_quick(bombpos, &Objects[j].pos); if (j != parent_num) if (dist - Objects[j].size < F1_0*20) { if (Objects[i].segnum == Objects[j].segnum) Objects[i].lifeleft = 1; else { // Object which is close enough to detonate smart mine is not in same segment as smart mine. // Need to do a more expensive check to make sure there isn't an obstruction. if (((FrameCount ^ (i+j)) % 4) == 0) { fvi_query fq; fvi_info hit_data; int fate; fq.startseg = Objects[i].segnum; fq.p0 = &Objects[i].pos; fq.p1 = &Objects[j].pos; fq.rad = 0; fq.thisobjnum = i; fq.ignore_obj_list = NULL; fq.flags = 0; fate = find_vector_intersection(&fq, &hit_data); if (fate != HIT_WALL) Objects[i].lifeleft = 1; } } } } } } } } }
// Checks weapon-weapon collisions. pair->a and pair->b are weapons. // Returns 1 if all future collisions between these can be ignored int collide_weapon_weapon( obj_pair * pair ) { float A_radius, B_radius; object *A = pair->a; object *B = pair->b; Assert( A->type == OBJ_WEAPON ); Assert( B->type == OBJ_WEAPON ); // Don't allow ship to shoot down its own missile. if (A->parent_sig == B->parent_sig) return 1; // Only shoot down teammate's missile if not traveling in nearly same direction. if (Weapons[A->instance].team == Weapons[B->instance].team) if (vm_vec_dot(&A->orient.vec.fvec, &B->orient.vec.fvec) > 0.7f) return 1; // Ignore collisions involving a bomb if the bomb is not yet armed. weapon *wpA, *wpB; weapon_info *wipA, *wipB; wpA = &Weapons[A->instance]; wpB = &Weapons[B->instance]; wipA = &Weapon_info[wpA->weapon_info_index]; wipB = &Weapon_info[wpB->weapon_info_index]; A_radius = A->radius; B_radius = B->radius; // UnknownPlayer : Should we even be bothering with collision detection is neither one of these is a bomb? if (wipA->wi_flags & WIF_BOMB) { A_radius *= 2; // Makes bombs easier to hit if (wipA->lifetime - wpA->lifeleft < BOMB_ARM_TIME) return 0; } if (wipB->wi_flags & WIF_BOMB) { B_radius *= 2; // Makes bombs easier to hit if (wipB->lifetime - wpB->lifeleft < BOMB_ARM_TIME) return 0; } // Rats, do collision detection. if (collide_subdivide(&A->last_pos, &A->pos, A_radius, &B->last_pos, &B->pos, B_radius)) { ship *sap, *sbp; sap = &Ships[Objects[A->parent].instance]; sbp = &Ships[Objects[B->parent].instance]; // MWA -- commented out next line because it was too long for output window on occation. // Yes -- I should fix the output window, but I don't have time to do it now. //nprintf(("AI", "[%s] %s's missile %i shot down by [%s] %s's laser %i\n", lTeamNames[sbp->team], sbp->ship_name, B->instance, lTeamNames[sap->team], sap->ship_name, A->instance)); if (wipA->wi_flags & WIF_BOMB) { if (wipB->wi_flags & WIF_BOMB) { // Two bombs collide, detonate both. Weapons[A->instance].lifeleft = 0.01f; Weapons[B->instance].lifeleft = 0.01f; Weapons[A->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; Weapons[B->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } else { A->hull_strength -= wipB->damage; if (A->hull_strength < 0.0f) { Weapons[A->instance].lifeleft = 0.01f; Weapons[A->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } } } else if (wipB->wi_flags & WIF_BOMB) { B->hull_strength -= wipA->damage; if (B->hull_strength < 0.0f) { Weapons[B->instance].lifeleft = 0.01f; Weapons[B->instance].weapon_flags |= WF_DESTROYED_BY_WEAPON; } } float dist = 0.0f; if (Weapons[A->instance].lifeleft == 0.01f) { dist = vm_vec_dist_quick(&A->pos, &wpA->homing_pos); nprintf(("AI", "Frame %i: Weapon %s shot down. Dist: %.1f, inner: %.0f, outer: %.0f\n", Framecount, wipA->name, dist, wipA->inner_radius, wipA->outer_radius)); } if (Weapons[B->instance].lifeleft == 0.01f) { dist = vm_vec_dist_quick(&A->pos, &wpB->homing_pos); nprintf(("AI", "Frame %i: Weapon %s shot down. Dist: %.1f, inner: %.0f, outer: %.0f\n", Framecount, wipB->name, dist, wipB->inner_radius, wipB->outer_radius)); } return 1; } return 0; }
void modex_print_message(int x, int y, char *str) { #ifndef AUTOMAP_DIRECT_RENDER #ifndef AUTOMAP_NO_PAGING int i; for (i=0; i<2; i++ ) { gr_set_current_canvas(&Pages[i]); #else { gr_set_current_canvas(OffscreenPage); #endif #endif modex_printf(x, y, str, GFONT_MEDIUM_1); #ifndef AUTOMAP_DIRECT_RENDER } gr_set_current_canvas(&DrawingPages[current_page]); #endif } extern void GameLoop(int, int ); extern int set_segment_depths(int start_seg, ubyte *segbuf); u_int32_t automap_mode = SM(640,480); int automap_width = 640; int automap_height = 480; int automap_use_game_res=0; int nice_automap=0; void do_automap( int key_code ) { int done=0; vms_matrix tempm; vms_angvec tangles; int leave_mode=0; int first_time=1; // int pcx_error; int c; // char filename[] = "MAP.PCX"; fix entry_time; int pause_game=1; // Set to 1 if everything is paused during automap...No pause during net. fix t1, t2; control_info saved_control_info; grs_bitmap Automap_background; int Max_segments_away = 0; int SegmentLimit = 1; //added on 10/28/98 by adb to fix compile versions #if !defined (NDEBUG) || (!defined(AUTOMAP_NO_PAGING) && !defined(AUTOMAP_DIRECT_RENDER)) int i; #endif key_code = key_code; // disable warning... if ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME) && (!Endlevel_sequence)) pause_game = 0; if (pause_game) stop_time(); create_name_canv(); Max_edges = min(MAX_EDGES_FROM_VERTS(Num_vertices),MAX_EDGES); //make maybe smaller than max //Edges = malloc( sizeof(Edge_info)*Max_edges); //if ( Edges == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(Edge_info)*Max_edges/1024)); // return; //} //DrawingListBright = malloc( sizeof(short)*Max_edges); //if ( DrawingListBright == NULL ) { // mprintf((0, "Couldn't get %dK for automap!", sizeof(short)*Max_edges/1024)); // return; //} mprintf( (0, "Num_vertices=%d, Max_edges=%d, (MAX:%d)\n", Num_vertices, Max_edges, MAX_EDGES )); mprintf( (0, "Allocated %d K for automap edge list\n", (sizeof(Edge_info)+sizeof(short))*Max_edges/1024 )); //edit 4/23/99 Matt Mueller - don't switch res unless we need to if (grd_curscreen->sc_mode != AUTOMAP_MODE) gr_set_mode( AUTOMAP_MODE ); else gr_set_current_canvas(NULL); //end edit -MM automap_width=grd_curscreen->sc_canvas.cv_bitmap.bm_w; automap_height=grd_curscreen->sc_canvas.cv_bitmap.bm_h; gr_palette_clear(); #ifndef AUTOMAP_DIRECT_RENDER gr_init_sub_canvas(&Pages[0],grd_curcanv,0,0,automap_width,automap_height); #ifndef AUTOMAP_NO_PAGING // NOTICE: should be 0,401! FIXME! gr_init_sub_canvas(&Pages[1],grd_curcanv,0,0,automap_width,automap_height); gr_init_sub_canvas(&DrawingPages[0],&Pages[0],0,0,automap_width,automap_height); gr_init_sub_canvas(&DrawingPages[1],&Pages[1],0,0,automap_width,automap_height); #else OffscreenPage = gr_create_canvas( automap_width,automap_height ); if (!OffscreenPage) { nm_messagebox("No memory for automap", 1, "Ok"); return; } gr_init_sub_canvas(&DrawingPages[0],OffscreenPage,0,0,automap_width,automap_height); #endif #endif gr_init_bitmap_data (&Automap_background); // pcx_error = pcx_read_bitmap(filename,&Automap_background,BM_LINEAR,NULL); // if ( pcx_error != PCX_ERROR_NONE ) { // printf("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); // Error("File %s - PCX error: %s",filename,pcx_errormsg(pcx_error)); // return; // } #ifndef AUTOMAP_DIRECT_RENDER #ifndef AUTOMAP_NO_PAGING for (i=0; i<2; i++ ) { gr_set_current_canvas(&Pages[i]); #else { gr_set_current_canvas(OffscreenPage); #endif // gr_bitmap( 0, 0, &Automap_background ); // modex_printf( 40, 22,TXT_AUTOMAP,GFONT_BIG_1); // modex_printf( 70,353,TXT_TURN_SHIP,GFONT_SMALL); // modex_printf( 70,369,TXT_SLIDE_UPDOWN,GFONT_SMALL); // modex_printf( 70,385,TXT_VIEWING_DISTANCE,GFONT_SMALL); } #ifdef AUTOMAP_NO_PAGING //killed 05/17/99 Matt Mueller - this seems to merely copy undefined bytes around.. not needed //--killed-- gr_bm_ubitblt(automap_width,automap_height, 0, 0, 0, 0, &OffscreenPage->cv_bitmap,&Pages[0].cv_bitmap); //end kill -MM #endif gr_free_bitmap_data (&Automap_background); gr_set_current_canvas(&DrawingPages[current_page]); #endif automap_build_edge_list(); if ( ViewDist==0 ) ViewDist = ZOOM_DEFAULT; ViewMatrix = Objects[Players[Player_num].objnum].orient; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; done = 0; view_target = Objects[Players[Player_num].objnum].pos; t1 = entry_time = timer_get_fixed_seconds(); t2 = t1; //Fill in Automap_visited from Objects[Players[Player_num].objnum].segnum Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); while(!done) { if ( leave_mode==0 && Controls.automap_state && (timer_get_fixed_seconds()-entry_time)>LEAVE_TIME) leave_mode = 1; if ( !Controls.automap_state && (leave_mode==1) ) done=1; if (!pause_game) { ushort old_wiggle; saved_control_info = Controls; // Save controls so we can zero them memset(&Controls,0,sizeof(control_info)); // Clear everything... old_wiggle = ConsoleObject->mtype.phys_info.flags & PF_WIGGLE; // Save old wiggle ConsoleObject->mtype.phys_info.flags &= ~PF_WIGGLE; // Turn off wiggle #ifdef NETWORK if (multi_menu_poll()) done = 1; #endif // GameLoop( 0, 0 ); // Do game loop with no rendering and no reading controls. ConsoleObject->mtype.phys_info.flags |= old_wiggle; // Restore wiggle Controls = saved_control_info; } controls_read_all(); if ( Controls.automap_down_count ) { if (leave_mode==0) done = 1; c = 0; } while( (c=key_inkey()) ) { switch( c ) { #ifndef NDEBUG case KEY_BACKSP: Int3(); break; #endif case KEY_PRINT_SCREEN: save_screen_shot(1); break; case KEY_ESC: if (leave_mode==0) done = 1; break; case KEY_ALTED+KEY_F: // Alt+F shows full map, if cheats enabled if (Cheats_enabled) { uint t; t = Players[Player_num].flags; Players[Player_num].flags |= PLAYER_FLAGS_MAP_ALL_CHEAT; automap_build_edge_list(); Players[Player_num].flags=t; } break; #ifndef NDEBUG case KEY_DEBUGGED+KEY_F: { for (i=0; i<=Highest_segment_index; i++ ) Automap_visited[i] = 1; automap_build_edge_list(); Max_segments_away = set_segment_depths(Objects[Players[Player_num].objnum].segnum, Automap_visited); SegmentLimit = Max_segments_away; adjust_segment_limit(SegmentLimit); } break; #endif case KEY_MINUS: if (SegmentLimit > 1) { SegmentLimit--; adjust_segment_limit(SegmentLimit); } break; case KEY_EQUAL: if (SegmentLimit < Max_segments_away) { SegmentLimit++; adjust_segment_limit(SegmentLimit); } break; } } if ( Controls.fire_primary_down_count ) { // Reset orientation ViewDist = ZOOM_DEFAULT; tangles.p = PITCH_DEFAULT; tangles.h = 0; tangles.b = 0; view_target = Objects[Players[Player_num].objnum].pos; } ViewDist -= Controls.forward_thrust_time*ZOOM_SPEED_FACTOR; tangles.p += fixdiv( Controls.pitch_time, ROT_SPEED_DIVISOR ); tangles.h += fixdiv( Controls.heading_time, ROT_SPEED_DIVISOR ); tangles.b += fixdiv( Controls.bank_time, ROT_SPEED_DIVISOR*2 ); if ( Controls.vertical_thrust_time || Controls.sideways_thrust_time ) { vms_angvec tangles1; vms_vector old_vt; old_vt = view_target; tangles1 = tangles; vm_angles_2_matrix(&tempm,&tangles1); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); vm_vec_scale_add2( &view_target, &ViewMatrix.uvec, Controls.vertical_thrust_time*SLIDE_SPEED ); vm_vec_scale_add2( &view_target, &ViewMatrix.rvec, Controls.sideways_thrust_time*SLIDE_SPEED ); if ( vm_vec_dist_quick( &view_target, &Objects[Players[Player_num].objnum].pos) > i2f(1000) ) { view_target = old_vt; } } vm_angles_2_matrix(&tempm,&tangles); vm_matrix_x_matrix(&ViewMatrix,&Objects[Players[Player_num].objnum].orient,&tempm); if ( ViewDist < ZOOM_MIN_VALUE ) ViewDist = ZOOM_MIN_VALUE; if ( ViewDist > ZOOM_MAX_VALUE ) ViewDist = ZOOM_MAX_VALUE; draw_automap(); if ( first_time ) { first_time = 0; gr_palette_load( gr_palette ); } t2 = timer_get_fixed_seconds(); while (t2-t1<F1_0/100){//ogl is fast enough that the automap can read the input too fast and you start to turn really slow. So delay a bit (and free up some cpu :) if (nice_automap) d_delay(1); t2 = timer_get_fixed_seconds(); } if (pause_game) FrameTime=t2-t1; t1 = t2; } //free(Edges); //free(DrawingListBright); gr_free_canvas(name_canv); name_canv=NULL; #ifdef AUTOMAP_NO_PAGING gr_free_canvas(OffscreenPage); OffscreenPage = NULL; #endif mprintf( (0, "Automap memory freed\n" )); game_flush_inputs(); if (pause_game) start_time(); } void adjust_segment_limit(int SegmentLimit) { int i,e1; Edge_info * e; mprintf(( 0, "Seglimit: %d\n", SegmentLimit )); for (i=0; i<=Highest_edge_index; i++ ) { e = &Edges[i]; e->flags |= EF_TOO_FAR; for (e1=0; e1<e->num_faces; e1++ ) { if ( Automap_visited[e->segnum[e1]] <= SegmentLimit ) { e->flags &= (~EF_TOO_FAR); break; } } } }