// add some jitter to a flak gun's aiming direction, take into account range to target so that we're never _too_ far off // assumes dir is normalized void flak_jitter_aim(vec3d* dir, float dist_to_target, float weapon_subsys_strength) { vec3d rand_twist_pre, rand_twist_post; matrix temp; vec3d final_aim; float error_val; // get the matrix needed to rotate the base direction to the actual direction vm_vector_2_matrix(&temp, dir, NULL, NULL); // error value error_val = Flak_error + (Flak_error * 0.65f * (1.0f - weapon_subsys_strength)); // scale the rvec by some random value and make it the "pre-twist" value float rand_dist = frand_range(0.0f, error_val); // no jitter - so do nothing if (rand_dist <= 0.0f) { return; } vm_vec_copy_scale(&rand_twist_pre, &temp.vec.rvec, rand_dist); // now rotate the twist vector around the x axis (the base aim axis) at a random angle vm_rot_point_around_line(&rand_twist_post, &rand_twist_pre, fl_radian(359.0f * frand_range(0.0f, 1.0f)), &vmd_zero_vector, dir); // add the resulting vector to the base aim vector and normalize final_aim = *dir; vm_vec_scale(&final_aim, dist_to_target); vm_vec_add(dir, &final_aim, &rand_twist_post); vm_vec_normalize(dir); }
// throw some jitter into HUD x and y coords void emp_hud_jitter(int *x, int *y) { // if the emp effect is not active, don't jitter anything if(!emp_active_local()){ return; } // some movement *x += (int)frand_range(-8.0f * Emp_intensity, 8.0f * Emp_intensity); *y += (int)frand_range(-8.0f * Emp_intensity, 8.0f * Emp_intensity); }
// randomize the chars in a string void emp_randomize_chars(char *str) { int idx; int char_index; // shuffle chars around for(idx=0; idx<(int)(strlen(str)-1); idx++){ if(frand_range(0.0f, 1.0f) < Emp_intensity){ char_index = (int)frand_range(0.0f, (float)(NUM_RANDOM_CHARS - 1)); str[idx] = Emp_random_char[char_index]; } } }
bool BeamPiercingEffect::processSource(const ParticleSource* source) { particle_info info; memset(&info, 0, sizeof(info)); source->getOrigin()->applyToParticleInfo(info); if (m_effectBitmap >= 0) { info.type = PARTICLE_BITMAP_PERSISTENT; info.optional_data = m_effectBitmap; } else { info.type = PARTICLE_SMOKE; } info.rad = m_radius * frand_range(0.5f, 2.0f); vec3d fvec = source->getOrientation()->getDirectionVector(); float base_v, back_v; vec3d rnd_vec; vm_vec_rand_vec_quick(&rnd_vec); if (m_velocity != 0.0f) { base_v = m_velocity; } else { base_v = m_radius; } if (m_backVelocity != 0.0f) { back_v = m_backVelocity; } else { back_v = base_v * (-0.2f); } vm_vec_copy_scale(&info.vel, &fvec, base_v * frand_range(1.0f, 2.0f)); vm_vec_scale_add2(&info.vel, &rnd_vec, base_v * m_variance); // Create the primary piercing particle create(&info); vm_vec_copy_scale(&info.vel, &fvec, back_v * frand_range(1.0f, 2.0f)); vm_vec_scale_add2(&info.vel, &rnd_vec, back_v * m_variance); // Create the splash particle create(&info); return false; }
void fishtank_start() { int idx; if(Fish_inited){ return; } // try and load the fish anim Fish_left_anim = anim_load(FISH_LEFT_ANIM_NAME); if(Fish_left_anim == NULL){ return; } Fish_right_anim = anim_load(FISH_RIGHT_ANIM_NAME); if(Fish_right_anim == NULL){ return; } // no anim instances for(idx=0; idx<MAX_FISH; idx++){ Fish[idx].a = NULL; Fish[idx].swimming = 0; } Fish_inited = 1; // generate a random # of fish int count = (int)frand_range(1.0f, (float)(MAX_FISH - 1)); for(idx=0; idx<count; idx++){ fish_generate(); } }
// randomly say yes or no to a gauge, if emp is not active, always say yes int emp_should_blit_gauge() { // if the EMP effect is not active, always blit if(!emp_active_local()){ return 1; } // otherwise, randomly say no return frand_range(0.0f, 1.0f) > Emp_intensity; }
// radar is damaged, so make blips dance around void HudGaugeRadarOrb::blipDrawDistorted(blip *b, vec3d *pos) { float scale; float dist=vm_vec_normalize(pos); vec3d out; float distortion_angle=20; // maybe alter the effect if EMP is active if(emp_active_local()) { scale = emp_current_intensity(); distortion_angle *= frand_range(-3.0f,3.0f)*frand_range(0.0f, scale); dist *= frand_range(MAX(0.75f, 0.75f*scale), MIN(1.25f, 1.25f*scale)); if (dist > 1.25f) dist = 1.25f; if (dist < 0.75f) dist = 0.75f; } vm_vec_random_cone(&out,pos,distortion_angle); vm_vec_scale(&out,dist); drawContactHtl(&out,b->rad); }
// radar is damaged, so make blips dance around void HudGaugeRadarDradis::blipDrawDistorted(blip *b, vec3d *pos, float alpha) { float temp_scale; float dist = vm_vec_normalize(pos); vec3d out; float distortion_angle=20; // maybe alter the effect if EMP is active if (emp_active_local()) { temp_scale = emp_current_intensity(); dist *= frand_range(MAX(0.75f, 0.75f*temp_scale), MIN(1.25f, 1.25f*temp_scale)); distortion_angle *= frand_range(-3.0f,3.0f)*frand_range(0.0f, temp_scale); if (dist > 1.0f) dist = 1.0f; if (dist < 0.1f) dist = 0.1f; } vm_vec_random_cone(&out, pos, distortion_angle); vm_vec_scale(&out, dist); drawContact(&out, -1, unknown_contact_icon, b->dist, alpha, 1.0f); }
// blip is for a target immune to sensors, so cause to flicker in/out with mild distortion void HudGaugeRadarOrb::blipDrawFlicker(blip *b, vec3d *pos) { int flicker_index; float dist=vm_vec_normalize(pos); vec3d out; float distortion_angle=10; if ( (b-Blips) & 1 ) { flicker_index=0; } else { flicker_index=1; } if ( timestamp_elapsed(Radar_flicker_timer[flicker_index]) ) { Radar_flicker_timer[flicker_index] = timestamp_rand(50,1000); Radar_flicker_on[flicker_index] ^= 1; } if ( !Radar_flicker_on[flicker_index] ) { return; } if ( rand() & 1 ) { distortion_angle *= frand_range(0.1f,2.0f); dist *= frand_range(0.75f, 1.25f); if (dist > 1.25f) dist = 1.25f; if (dist < 0.75f) dist = 0.75f; } vm_vec_random_cone(&out,pos,distortion_angle); vm_vec_scale(&out,dist); drawContactHtl(&out,b->rad); }
void ssm_get_random_start_pos(vec3d *out, vec3d *start, matrix *orient, size_t ssm_index) { vec3d temp; ssm_info *s = &Ssm_info[ssm_index]; float radius, offset; if (s->max_radius == -1.0f) radius = s->radius; else radius = frand_range(s->radius, s->max_radius); if (s->max_offset == -1.0f) offset = s->offset; else offset = frand_range(s->offset, s->max_offset); switch (s->shape) { case SSM_SHAPE_SPHERE: // get a random vector in a sphere around the target vm_vec_random_in_sphere(&temp, start, orient, radius, 1); break; case SSM_SHAPE_CIRCLE: // get a random vector in the circle of the firing plane vm_vec_random_in_circle(&temp, start, orient, radius, 1); break; case SSM_SHAPE_POINT: // boooring vm_vec_scale_add(&temp, start, &orient->vec.fvec, radius); break; default: Assertion(false, "Unknown shape '%d' in SSM type #" SIZE_T_ARG " ('%s'). This should not be possible; get a coder!\n", s->shape, ssm_index, s->name); break; } // offset it a bit vm_vec_scale_add(out, &temp, &orient->vec.fvec, offset); }
// blip is for a target immune to sensors, so cause to flicker in/out with mild distortion void HudGaugeRadarDradis::blipDrawFlicker(blip *b, vec3d *pos, float alpha) { int flicker_index; float dist=vm_vec_normalize(pos); vec3d out; float distortion_angle=10; if ((b-Blips) & 1) flicker_index=0; else flicker_index=1; if (timestamp_elapsed(Radar_flicker_timer[flicker_index])) { Radar_flicker_timer[flicker_index] = timestamp_rand(50,1000); Radar_flicker_on[flicker_index] ^= 1; } if (!Radar_flicker_on[flicker_index]) return; if (rand() & 1) { distortion_angle *= frand_range(0.1f,2.0f); dist *= frand_range(0.75f, 1.25f); if (dist > 1.0f) dist = 1.0f; if (dist < 0.1f) dist = 0.1f; } vm_vec_random_cone(&out,pos,distortion_angle); vm_vec_scale(&out,dist); drawContact(&out, -1, unknown_contact_icon, b->dist, alpha, 1.0f); }
// process some stuff every frame (before frame is rendered) void emp_process_local() { if(!emp_active_local()){ return; } // decrement the intensity a bit Emp_intensity -= (flFrametime * Emp_decr); // see if we should choose a random target if((Emp_wacky_target_timestamp == -1) || timestamp_elapsed(Emp_wacky_target_timestamp)){ // choose a target (if not the "first" time) if(Emp_wacky_target_timestamp != -1){ hud_target_random_ship(); } // reset the timestamp Emp_wacky_target_timestamp = timestamp((int)frand_range(100.0f, 750.0f * (1.0f - Emp_intensity))); } }
/** * Checks debris-ship collisions. * @param pair obj_pair pointer to the two objects. pair->a is debris and pair->b is ship. * @return 1 if all future collisions between these can be ignored */ int collide_debris_ship( obj_pair * pair ) { float dist; object *pdebris = pair->a; object *pship = pair->b; // Don't check collisions for warping out player if ( Player->control_mode != PCM_NORMAL ) { if ( pship == Player_obj ) return 0; } Assert( pdebris->type == OBJ_DEBRIS ); Assert( pship->type == OBJ_SHIP ); // don't check collision if it's our own debris and we are dying if ( (pdebris->parent == OBJ_INDEX(pship)) && (Ships[pship->instance].flags[Ship::Ship_Flags::Dying]) ) return 0; dist = vm_vec_dist( &pdebris->pos, &pship->pos ); if ( dist < pdebris->radius + pship->radius ) { int hit; vec3d hitpos; // create and initialize ship_ship_hit_info struct collision_info_struct debris_hit_info; init_collision_info_struct(&debris_hit_info); if ( pdebris->phys_info.mass > pship->phys_info.mass ) { debris_hit_info.heavy = pdebris; debris_hit_info.light = pship; } else { debris_hit_info.heavy = pship; debris_hit_info.light = pdebris; } hit = debris_check_collision(pdebris, pship, &hitpos, &debris_hit_info ); if ( hit ) { Script_system.SetHookObjects(4, "Ship", pship, "Debris", pdebris, "Self", pship, "Object", pdebris); bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEDEBRIS, pship); Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship); bool debris_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, pdebris); if(!ship_override && !debris_override) { float ship_damage; float debris_damage; // do collision physics calculate_ship_ship_collision_physics( &debris_hit_info ); if ( debris_hit_info.impulse < 0.5f ) return 0; // calculate ship damage ship_damage = 0.005f * debris_hit_info.impulse; // Cut collision-based damage in half. // Decrease heavy damage by 2x. if (ship_damage > 5.0f) ship_damage = 5.0f + (ship_damage - 5.0f)/2.0f; // calculate debris damage and set debris damage to greater or debris and ship // debris damage is needed since we can really whack some small debris with afterburner and not do // significant damage to ship but the debris goes off faster than afterburner speed. debris_damage = debris_hit_info.impulse/pdebris->phys_info.mass; // ie, delta velocity of debris debris_damage = (debris_damage > ship_damage) ? debris_damage : ship_damage; // modify ship damage by debris damage multiplier ship_damage *= Debris[pdebris->instance].damage_mult; // supercaps cap damage at 10-20% max hull ship damage if (Ship_info[Ships[pship->instance].ship_info_index].flags[Ship::Info_Flags::Supercap]) { float cap_percent_damage = frand_range(0.1f, 0.2f); ship_damage = MIN(ship_damage, cap_percent_damage * Ships[pship->instance].ship_max_hull_strength); } // apply damage to debris debris_hit( pdebris, pship, &hitpos, debris_damage); // speed => damage int quadrant_num, apply_ship_damage; // apply damage to ship unless 1) debris is from ship apply_ship_damage = !(pship->signature == pdebris->parent_sig); if ( debris_hit_info.heavy == pship ) { quadrant_num = get_ship_quadrant_from_global(&hitpos, pship); if ((pship->flags[Object::Object_Flags::No_shields]) || !ship_is_shield_up(pship, quadrant_num) ) { quadrant_num = -1; } if (apply_ship_damage) { ship_apply_local_damage(debris_hit_info.heavy, debris_hit_info.light, &hitpos, ship_damage, quadrant_num, CREATE_SPARKS, debris_hit_info.submodel_num); } } else { // don't draw sparks using sphere hit position if (apply_ship_damage) { ship_apply_local_damage(debris_hit_info.light, debris_hit_info.heavy, &hitpos, ship_damage, MISS_SHIELDS, NO_SPARKS); } } // maybe print Collision on HUD if ( pship == Player_obj ) { hud_start_text_flash(XSTR("Collision", 1431), 2000); } collide_ship_ship_do_sound(&hitpos, pship, pdebris, pship==Player_obj); } Script_system.SetHookObjects(2, "Self",pship, "Object", pdebris); if(!(debris_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDEDEBRIS, '\0', NULL, pship); Script_system.SetHookObjects(2, "Self",pdebris, "Object", pship); if((debris_override && !ship_override) || (!debris_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, pdebris); Script_system.RemHookVars(4, "Ship", "Debris", "Self", "Object"); return 0; } } else { // Bounding spheres don't intersect, set timestamp for next collision check. float ship_max_speed, debris_speed; float time; ship *shipp; shipp = &Ships[pship->instance]; if (ship_is_beginning_warpout_speedup(pship)) { ship_max_speed = MAX(ship_get_max_speed(shipp), ship_get_warpout_speed(pship)); } else { ship_max_speed = ship_get_max_speed(shipp); } ship_max_speed = MAX(ship_max_speed, 10.0f); ship_max_speed = MAX(ship_max_speed, pship->phys_info.vel.xyz.z); debris_speed = pdebris->phys_info.speed; time = 1000.0f * (dist - pship->radius - pdebris->radius - 10.0f) / (ship_max_speed + debris_speed); // 10.0f is a safety factor time -= 200.0f; // allow one frame slow frame at ~5 fps if (time > 100) { pair->next_check_time = timestamp( fl2i(time) ); } else { pair->next_check_time = timestamp(0); // check next time } } return 0; }
// maybe reformat a string void emp_maybe_reformat_text(char *text, int max_len, int gauge_id) { wacky_text *wt; // if the EMP effect is not active, never reformat it if(!emp_active_local()){ return; } // randomly _don't_ apply text craziness if(frand_range(0.0f, 1.0f) > Emp_intensity){ return; } // if the gauge is EG_NULL, empty the string if(gauge_id == EG_NULL){ strcpy(text, ""); return; } // if this gauge has not been wacked out, or if the timestamp has expired, we // neeed to wack it out again Assert((gauge_id >= EG_NULL) && (gauge_id < NUM_TEXT_STAMPS)); wt = &Emp_wacky_text[gauge_id]; if((wt->stamp == -1) || timestamp_elapsed(wt->stamp)){ // reformat specific gauges differently switch(gauge_id){ // weapons case EG_WEAPON_TITLE: case EG_WEAPON_P1: case EG_WEAPON_P2: case EG_WEAPON_P3: case EG_WEAPON_S1: case EG_WEAPON_S2: int wep_index; wep_index = (int)frand_range(0.0f, (float)(MAX_WEAPON_TYPES - 1)); strcpy_s(wt->str, Weapon_info[ wep_index >= MAX_WEAPON_TYPES ? 0 : wep_index ].name); break; // escort list case EG_ESCORT1: case EG_ESCORT2: case EG_ESCORT3: // choose a random ship int shipnum; shipnum = ship_get_random_targetable_ship(); if(shipnum >= 0){ strcpy_s(wt->str, Ships[shipnum].ship_name); } break; // directives title case EG_OBJ_TITLE: strcpy_s(wt->str, ""); break; // directives themselves case EG_OBJ1: case EG_OBJ2: case EG_OBJ3: case EG_OBJ4: case EG_OBJ5: strcpy_s(wt->str, text); emp_randomize_chars(wt->str); break; // target box info case EG_TBOX_EXTRA1: case EG_TBOX_EXTRA2: case EG_TBOX_EXTRA3: case EG_TBOX_CLASS: case EG_TBOX_DIST: case EG_TBOX_CARGO: case EG_TBOX_HULL: case EG_TBOX_NAME: case EG_TBOX_INTEG: strcpy_s(wt->str, text); emp_randomize_chars(wt->str); break; // squadmsg menu case EG_SQ1: case EG_SQ2: case EG_SQ3: case EG_SQ4: case EG_SQ5: case EG_SQ6: case EG_SQ7: case EG_SQ8: case EG_SQ9: case EG_SQ10: strcpy_s(wt->str, text); emp_randomize_chars(wt->str); break; // default default : return; } // recalculate the timestamp wt->stamp = timestamp((int)frand_range(100.0f, 750.0f * (1.0f - Emp_intensity))); // copy the text strcpy(text, wt->str); } // otherwise, use what we calculated last time else { strcpy(text, wt->str); } // watch out for '#' - Goober5000 end_string_at_first_hash_symbol(text); }
void multi_respawn_place(object *new_obj, int team) { ship_obj *moveup; ship *s_check; ship *pri = NULL; object *pri_obj = NULL; object *hit_check; int collided, idx, lookup; // first determine if there are any appropriate priority ships to use pri = NULL; pri_obj = NULL; for(idx=0; idx<Multi_respawn_priority_count; idx++){ // all relevant ships if((Multi_respawn_priority_ships[idx].team == team) || !(Netgame.type_flags & NG_TYPE_TEAM)){ lookup = ship_name_lookup(Multi_respawn_priority_ships[idx].ship_name); if( (lookup >= 0) && ((pri == NULL) || (Ships[lookup].respawn_priority > pri->respawn_priority)) && (Ships[lookup].objnum >= 0) && (Ships[lookup].objnum < MAX_OBJECTS)){ pri = &Ships[lookup]; pri_obj = &Objects[Ships[lookup].objnum]; } } } // if we have a relevant respawn ship if((pri != NULL) && (pri_obj != NULL)){ // pick a point just outside his bounding box polymodel *pm = model_get(pri->modelnum); // hmm, ugly. Pick a point 2000 meters to the y direction if(pm == NULL){ vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, 2000.0f); } else { // pick a random direction int d = (int)frand_range(0.0f, 5.9f); switch(d){ case 0: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, (pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 1: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, -(pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 2: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, (pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 3: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 4: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.fvec, (pm->maxs.xyz.z - pm->mins.xyz.z)); break; case 5: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.fvec, -(pm->maxs.xyz.z - pm->mins.xyz.z)); break; default: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; } } } // otherwise, resort to plain respawn points else { Assert(Multi_respawn_point_count > 0); // get the next appropriate respawn point by team lookup = 0; int count = 0; while(!lookup && (count < 13)){ if((team == TEAM_TRAITOR) || (team == Multi_respawn_points[Multi_next_respawn_point].team)){ lookup = 1; } // next item if(!lookup){ if(Multi_next_respawn_point >= (Multi_respawn_point_count-1)){ Multi_next_respawn_point = 0; } else { Multi_next_respawn_point++; } } count++; } // set respawn info new_obj->pos = Multi_respawn_points[Multi_next_respawn_point].pos; } // now make sure we're not colliding with anyone do { collided = 0; moveup = GET_FIRST(&Ship_obj_list); while(moveup!=END_OF_LIST(&Ship_obj_list)){ // don't check the new_obj itself!! if(Objects[moveup->objnum].net_signature != new_obj->net_signature){ hit_check = &Objects[moveup->objnum]; Assert(hit_check->type == OBJ_SHIP); Assert(hit_check->instance >= 0); if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){ continue; } s_check = &Ships[hit_check->instance]; // just to make sure we don't get any strange magnitude errors if(vm_vec_same(&hit_check->pos, &new_obj->pos)){ new_obj->pos.xyz.x += 1.0f; } WITHIN_BBOX(); if(collided){ MOVE_AWAY_BBOX(); break; } collided = 0; } moveup = GET_NEXT(moveup); } } while(collided); }
void multi_respawn_place(object *new_obj, int team) { ship *pri = NULL; object *pri_obj = NULL; int idx, lookup; // first determine if there are any appropriate priority ships to use pri = NULL; pri_obj = NULL; for(idx=0; idx<Multi_respawn_priority_count; idx++){ // all relevant ships if((Multi_respawn_priority_ships[idx].team == team) || !(Netgame.type_flags & NG_TYPE_TEAM)){ lookup = ship_name_lookup(Multi_respawn_priority_ships[idx].ship_name); if( (lookup >= 0) && ((pri == NULL) || (Ships[lookup].respawn_priority > pri->respawn_priority)) && (Ships[lookup].objnum >= 0) && (Ships[lookup].objnum < MAX_OBJECTS)){ pri = &Ships[lookup]; pri_obj = &Objects[Ships[lookup].objnum]; } } } // if we have a relevant respawn ship if((pri != NULL) && (pri_obj != NULL)){ // pick a point just outside his bounding box polymodel *pm = model_get(Ship_info[pri->ship_info_index].model_num); // hmm, ugly. Pick a point 2000 meters to the y direction if(pm == NULL){ vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, 2000.0f); } else { // pick a random direction int d = (int)frand_range(0.0f, 5.9f); switch(d){ case 0: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, (pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 1: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, -(pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 2: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, (pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 3: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 4: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.fvec, (pm->maxs.xyz.z - pm->mins.xyz.z)); break; case 5: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.fvec, -(pm->maxs.xyz.z - pm->mins.xyz.z)); break; default: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; } } } // otherwise, resort to plain respawn points else { Assert(Multi_respawn_point_count > 0); // get the next appropriate respawn point by team lookup = 0; int count = 0; while(!lookup && (count < 13)){ if((team == Iff_traitor) || (team == Multi_respawn_points[Multi_next_respawn_point].team)){ lookup = 1; } // next item if(!lookup){ if(Multi_next_respawn_point >= (Multi_respawn_point_count-1)){ Multi_next_respawn_point = 0; } else { Multi_next_respawn_point++; } } count++; } // set respawn info new_obj->pos = Multi_respawn_points[Multi_next_respawn_point].pos; } // now make sure we're not colliding with anyone prevent_spawning_collision(new_obj); }
// given a just fired flak shell, pick a detonating distance for it void flak_pick_range(object* objp, vec3d* firing_pos, vec3d* predicted_target_pos, float weapon_subsys_strength) { float final_range; float det_range; vec3d temp; // make sure this flak object is valid Assert(objp->type == OBJ_WEAPON); Assert(objp->instance >= 0); Assert(Weapons[objp->instance].weapon_info_index >= 0); Assert(Weapon_info[Weapons[objp->instance].weapon_info_index].wi_flags & WIF_FLAK); // if the flak index is invalid, do nothing - if this fails the flak simply becomes a non-rendering bullet /* if(Weapons[objp->instance].flak_index < 0){ return; } */ // get the range to the target vm_vec_sub(&temp, &objp->pos, predicted_target_pos); final_range = vm_vec_mag(&temp); //Is it larger than det_range? det_range = Weapon_info[Weapons[objp->instance].weapon_info_index].det_range; if (det_range != 0.0f && final_range > det_range) { flak_set_range(objp, det_range); return; } // add in some randomness final_range += (Flak_range + (Flak_range * 0.65f * (1.0f - weapon_subsys_strength))) * frand_range(-1.0f, 1.0f); // make sure we're firing at least 10 meters away if (final_range < 10.0f) { final_range = 10.0f; } // set the range flak_set_range(objp, final_range); }
void fish_generate() { fish *f; int idx; if(!Fish_inited){ return; } // bogus anims if((Fish_left_anim == NULL) || (Fish_right_anim == NULL)){ return; } // find a free fish f = NULL; for(idx=0; idx<MAX_FISH; idx++){ if(!Fish[idx].swimming){ f = &Fish[idx]; } } // no fish left if(f == NULL){ return; } // left or right f->left = frand_range(0.0f, 1.0f) < 0.5f ? 0 : 1; // start location if(f->left){ f->x = gr_screen.max_w_unscaled_zoomed + frand_range(0.0f, 50.0f); } else { f->x = frand_range(0.0f, -50.0f) - FISH_ANIM_WIDTH; } f->y = frand_range(-40.0f, (float)gr_screen.max_h_unscaled_zoomed + 40.0f); // speed if(f->left){ f->x_speed = frand_range(-1.0f, -15.0f); } else { f->x_speed = frand_range(1.0f, 15.0f); } f->y_speed = frand_range(0.0f, 1.0f) < 0.5f ? frand_range(1.0f, 4.0f) : frand_range(-1.0f, -4.0f); // all fish start out offscreen f->onscreen = 0; // he's swimming f->swimming = 1; // anim instance anim_play_struct aps; if(f->left){ anim_play_init(&aps, Fish_left_anim, (int)f->x, (int)f->y); f->a = anim_play(&aps); // doh. cancel him if(f->a == NULL){ f->swimming = 0; } else { f->a->screen_id = GS_STATE_MAIN_MENU; f->a->looped = 1; f->a->framerate_independent = 1; } } else { anim_play_init(&aps, Fish_right_anim, (int)f->x, (int)f->y); f->a = anim_play(&aps); // doh. cancel him if(f->a == NULL){ f->swimming = 0; } else { f->a->screen_id = GS_STATE_MAIN_MENU; f->a->looped = 1; f->a->framerate_independent = 1; } } }
// Checks debris-ship collisions. pair->a is debris and pair->b is ship. // Returns 1 if all future collisions between these can be ignored int collide_debris_ship( obj_pair * pair ) { float dist; object *pdebris = pair->a; object *pship = pair->b; // Don't check collisions for warping out player if ( Player->control_mode != PCM_NORMAL ) { if ( pship == Player_obj ) return 0; } Assert( pdebris->type == OBJ_DEBRIS ); Assert( pship->type == OBJ_SHIP ); /* Debris_ship_count++; if (Debris_ship_count % 100 == 0) nprintf(("AI", "Done %i debris:ship checks in %i frames = %.2f checks/frame\n", Debris_ship_count, Framecount, (float) Debris_ship_count/Framecount)); */ dist = vm_vec_dist( &pdebris->pos, &pship->pos ); if ( dist < pdebris->radius + pship->radius ) { int hit; vector hitpos; // create and initialize ship_ship_hit_info struct collision_info_struct debris_hit_info; memset( &debris_hit_info, -1, sizeof(collision_info_struct) ); if ( pdebris->phys_info.mass > pship->phys_info.mass ) { debris_hit_info.heavy = pdebris; debris_hit_info.light = pship; } else { debris_hit_info.heavy = pship; debris_hit_info.light = pdebris; } hit = debris_check_collision(pdebris, pship, &hitpos, &debris_hit_info ); if ( hit ) { float ship_damage; float debris_damage; // do collision physics calculate_ship_ship_collision_physics( &debris_hit_info ); if ( debris_hit_info.impulse < 0.5f ) return 0; // calculate ship damage ship_damage = 0.005f * debris_hit_info.impulse; // Cut collision-based damage in half. // Decrease heavy damage by 2x. if (ship_damage > 5.0f) ship_damage = 5.0f + (ship_damage - 5.0f)/2.0f; // calculate debris damage and set debris damage to greater or debris and ship // debris damage is needed since we can really whack some small debris with afterburner and not do // significant damage to ship but the debris goes off faster than afterburner speed. debris_damage = debris_hit_info.impulse/pdebris->phys_info.mass; // ie, delta velocity of debris debris_damage = (debris_damage > ship_damage) ? debris_damage : ship_damage; // supercaps cap damage at 10-20% max hull ship damage if (Ship_info[Ships[pship->instance].ship_info_index].flags & SIF_SUPERCAP) { float cap_percent_damage = frand_range(0.1f, 0.2f); ship_damage = min(ship_damage, cap_percent_damage * Ship_info[Ships[pship->instance].ship_info_index].initial_hull_strength); } // apply damage to debris debris_hit( pdebris, pship, &hitpos, debris_damage); // speed => damage int quadrant_num, apply_ship_damage; // apply damage to ship unless 1) debris is from ship // apply_ship_damage = !((pship->signature == pdebris->parent_sig) && ship_is_beginning_warpout_speedup(pship)); apply_ship_damage = !(pship->signature == pdebris->parent_sig); if ( debris_hit_info.heavy == pship ) { quadrant_num = get_ship_quadrant_from_global(&hitpos, pship); if ((pship->flags & OF_NO_SHIELDS) || !ship_is_shield_up(pship, quadrant_num) ) { quadrant_num = -1; } if (apply_ship_damage) { ship_apply_local_damage(debris_hit_info.heavy, debris_hit_info.light, &hitpos, ship_damage, quadrant_num, CREATE_SPARKS, debris_hit_info.submodel_num); } } else { // don't draw sparks using sphere hit position if (apply_ship_damage) { ship_apply_local_damage(debris_hit_info.light, debris_hit_info.heavy, &hitpos, ship_damage, MISS_SHIELDS, NO_SPARKS); } } // maybe print Collision on HUD if ( pship == Player_obj ) { hud_start_text_flash(XSTR("Collision", 1431), 2000); } collide_ship_ship_do_sound(&hitpos, pship, pdebris, pship==Player_obj); return 0; } } else { // Bounding spheres don't intersect, set timestamp for next collision check. float ship_max_speed, debris_speed; float time; ship *shipp; shipp = &Ships[pship->instance]; if (ship_is_beginning_warpout_speedup(pship)) { ship_max_speed = max(ship_get_max_speed(shipp), ship_get_warp_speed(pship)); } else { ship_max_speed = ship_get_max_speed(shipp); } ship_max_speed = max(ship_max_speed, 10.0f); ship_max_speed = max(ship_max_speed, pship->phys_info.vel.xyz.z); debris_speed = pdebris->phys_info.speed; time = 1000.0f * (dist - pship->radius - pdebris->radius - 10.0f) / (ship_max_speed + debris_speed); // 10.0f is a safety factor time -= 200.0f; // allow one frame slow frame at ~5 fps if (time > 100) { //nprintf(("AI", "Ship %s debris #%i delay time = %.1f seconds\n", Ships[pship->instance].ship_name, pdebris-Objects, time/1000.0f)); pair->next_check_time = timestamp( fl2i(time) ); } else { pair->next_check_time = timestamp(0); // check next time } } return 0; }