/** * @brief Computes an estimation of ammo flying time * * @param w the weapon that shoot * @param parent Parent of the weapon * @param target Target of the weapon */ double pilot_weapFlyTime( Outfit *o, Pilot *parent, Vector2d *pos, Vector2d *vel) { Vector2d approach_vector, relative_location, orthoradial_vector; double speed, radial_speed, orthoradial_speed, dist, t; dist = vect_dist( &parent->solid->pos, pos ); /* Beam weapons */ if (outfit_isBeam(o)) { if (dist > o->u.bem.range) return INFINITY; return 0.; } /* A bay doesn't have range issues */ if (outfit_isFighterBay(o)) return 0.; /* Rockets use absolute velocity while bolt use relative vel */ if (outfit_isLauncher(o)) vect_cset( &approach_vector, - vel->x, - vel->y ); else vect_cset( &approach_vector, VX(parent->solid->vel) - vel->x, VY(parent->solid->vel) - vel->y ); speed = outfit_speed(o); /* Get the vector : shooter -> target */ vect_cset( &relative_location, pos->x - VX(parent->solid->pos), pos->y - VY(parent->solid->pos) ); /* Get the orthogonal vector */ vect_cset(&orthoradial_vector, VY(parent->solid->pos) - pos->y, pos->x - VX(parent->solid->pos) ); radial_speed = vect_dot( &approach_vector, &relative_location ); radial_speed = radial_speed / VMOD(relative_location); orthoradial_speed = vect_dot(&approach_vector, &orthoradial_vector); orthoradial_speed = orthoradial_speed / VMOD(relative_location); if( ((speed*speed - VMOD(approach_vector)*VMOD(approach_vector)) != 0) && (speed*speed - orthoradial_speed*orthoradial_speed) > 0) t = dist * (sqrt( speed*speed - orthoradial_speed*orthoradial_speed ) - radial_speed) / (speed*speed - VMOD(approach_vector)*VMOD(approach_vector)); else return INFINITY; /* if t < 0, try the other solution */ if (t < 0) t = - dist * (sqrt( speed*speed - orthoradial_speed*orthoradial_speed ) + radial_speed) / (speed*speed - VMOD(approach_vector)*VMOD(approach_vector)); /* if t still < 0, no solution */ if (t < 0) return INFINITY; return t; }
/** * @brief Updates the shake position. */ static void spfx_updateShake( double dt ) { double mod, vmod, angle; double force_x, force_y; int forced; /* Must still be on. */ if (shake_off) return; /* The shake decays over time */ forced = 0; if (shake_force_mod > 0.) { shake_force_mod -= SHAKE_DECAY*dt; if (shake_force_mod < 0.) shake_force_mod = 0.; else forced = 1; } /* See if it's settled down. */ mod = VMOD( shake_pos ); vmod = VMOD( shake_vel ); if (!forced && (mod < 0.01) && (vmod < 0.01)) { shake_off = 1; if (shake_force_ang > 1e3) shake_force_ang = RNGF(); return; } /* Calculate force. */ force_x = -SHAKE_K*shake_pos.x + -SHAKE_B*shake_vel.x; force_y = -SHAKE_K*shake_pos.y + -SHAKE_B*shake_vel.y; /* Apply force if necessary. */ if (forced) { shake_force_ang += dt; angle = noise_simplex1( shake_noise, &shake_force_ang ) * 5.*M_PI; force_x += shake_force_mod * cos(angle); force_y += shake_force_mod * sin(angle); } /* Update velocity. */ vect_cadd( &shake_vel, (1./SHAKE_MASS) * force_x * dt, (1./SHAKE_MASS) * force_y * dt ); /* Update position. */ vect_cadd( &shake_pos, shake_vel.x * dt, shake_vel.y * dt ); }
/** * @brief Updates the camera zoom. */ static void cam_updatePilotZoom( Pilot *follow, Pilot *target, double dt ) { double d, x,y, z,tz, dx, dy; double zfar, znear; double c; /* Must have auto zoom enabled. */ if (conf.zoom_manual) return; /* Minimum depends on velocity normally. * * w*h = A, cte area constant * w/h = K, cte proportion constant * d^2 = A, cte geometric longitud * * A_v = A*(1+v/d) area of view is based on speed * A_v / A = (1 + v/d) * * z = A / A_v = 1. / (1 + v/d) */ d = sqrt(SCREEN_W*SCREEN_H); znear = MIN( conf.zoom_near, 1. / (0.8 + VMOD(follow->solid->vel)/d) ); /* Maximum is limited by nebulae. */ if (cur_system->nebu_density > 0.) { c = MIN( SCREEN_W, SCREEN_H ) / 2; zfar = CLAMP( conf.zoom_far, conf.zoom_near, c / nebu_getSightRadius() ); } else zfar = conf.zoom_far; znear = MAX( znear, zfar ); /* * Set Zoom to pilot target. */ z = cam_getZoom(); if (target != NULL) { /* Get current relative target position. */ gui_getOffset( &x, &y ); x += target->solid->pos.x - follow->solid->pos.x; y += target->solid->pos.y - follow->solid->pos.y; /* Get distance ratio. */ dx = (SCREEN_W/2.) / (FABS(x) + 2*target->ship->gfx_space->sw); dy = (SCREEN_H/2.) / (FABS(y) + 2*target->ship->gfx_space->sh); /* Get zoom. */ tz = MIN( dx, dy ); } else tz = znear; /* Aim at in. */ /* Gradually zoom in/out. */ d = CLAMP(-conf.zoom_speed, conf.zoom_speed, tz - z); d *= dt / dt_mod; /* Remove dt dependence. */ if (d < 0) /** Speed up if needed. */ d *= 2.; camera_Z = CLAMP( zfar, znear, z + d); }
/** * @brief Gets the modulus of the vector. * @luaparam v Vector to get modulus of. * @luareturn The modulus of the vector. * @luafunc mod(v) */ static int vectorL_mod( lua_State *L ) { LuaVector *v; v = luaL_checkvector(L,1); lua_pushnumber(L, VMOD(v->vec)); return 1; }
/** * @brief Gets the modulus of the vector. * @luaparam v Vector to get modulus of. * @luareturn The modulus of the vector. * @luafunc mod(v) */ static int vectorL_mod( lua_State *L ) { Vector2d *v; v = luaL_checkvector(L,1); lua_pushnumber(L, VMOD(*v)); return 1; }
/** * @brief Prepares the rendering for the special effects. * * Should be called at the beginning of the rendering loop. * * @param dt Current delta tick. */ void spfx_begin( const double dt ) { GLdouble bx, by, x, y; double inc; /* Save cycles. */ if (shake_off == 1) return; #if SDL_VERSION_ATLEAST(1,3,0) /* Decrement the haptic timer. */ if (haptic_lastUpdate > 0.) haptic_lastUpdate -= dt; #endif /* SDL_VERSION_ATLEAST(1,3,0) */ /* set defaults */ bx = SCREEN_W/2; by = SCREEN_H/2; if (!paused) { inc = dt*100000.; /* calculate new position */ if (shake_rad > 0.01) { vect_cadd( &shake_pos, shake_vel.x * inc, shake_vel.y * inc ); if (VMOD(shake_pos) > shake_rad) { /* change direction */ vect_pset( &shake_pos, shake_rad, VANGLE(shake_pos) ); vect_pset( &shake_vel, SHAKE_VEL_MOD*shake_rad, -VANGLE(shake_pos) + (RNGF()-0.5) * M_PI ); } /* the shake decays over time */ shake_rad -= SHAKE_DECAY*dt; if (shake_rad < 0.) shake_rad = 0.; x = shake_pos.x; y = shake_pos.y; } else { shake_rad = 0.; shake_off = 1; x = 0.; y = 0.; } } else { x = 0.; y = 0.; } /* set the new viewport */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho( -bx+x, bx+x, -by+y, by+y, -1., 1. ); }
/** * @brief Updates the pilot's dynamic electronic warfare properties. * * @param p Pilot to update. */ void pilot_ewUpdateDynamic( Pilot *p ) { /* Update hide. */ p->ew_heat = pilot_ewHeat( p->heat_T ); p->ew_hide = p->ew_base_hide * p->ew_mass * p->ew_heat; /* Update evasion. */ p->ew_movement = pilot_ewMovement( VMOD(p->solid->vel) ); p->ew_evasion = p->ew_hide * EVASION_SCALE; }
/** * @brief Gets polar coordinates of a vector. * * The angle is in degrees, not radians. * * @usage modulus, angle = my_vec:polar() * * @luaparam v Vector to get polar coordinates of. * @luareturn The modulus and angle of the vector. * @luafunc polar(v) */ static int vectorL_polar( lua_State *L ) { LuaVector *v1; /* Get self. */ v1 = luaL_checkvector(L,1); lua_pushnumber(L, VMOD(v1->vec)); lua_pushnumber(L, VANGLE(v1->vec)*180./M_PI); return 2; }
/** * @brief Gets polar coordinates of a vector. * * The angle is in degrees, not radians. * * @usage modulus, angle = my_vec:polar() * * @luaparam v Vector to get polar coordinates of. * @luareturn The modulus and angle of the vector. * @luafunc polar(v) */ static int vectorL_polar( lua_State *L ) { Vector2d *v1; /* Get self. */ v1 = luaL_checkvector(L,1); lua_pushnumber(L, VMOD(*v1)); lua_pushnumber(L, VANGLE(*v1)*180./M_PI); return 2; }
/** * @brief Handles approaching a position with autonav. * * @param[in] pos Position to go to. * @param[out] dist2 Square distance left to target. * @param count_target If 1 it subtracts the braking distance from dist2. Otherwise it returns the full distance. * @return 1 on completion. */ static int player_autonavApproach( const Vector2d *pos, double *dist2, int count_target ) { double d, t, vel, dist; /* Only accelerate if facing move dir. */ d = pilot_face( player.p, vect_angle( &player.p->solid->pos, pos ) ); if (FABS(d) < MIN_DIR_ERR) { if (player_acc < 1.) player_accel( 1. ); } else if (player_acc > 0.) player_accelOver(); /* Get current time to reach target. */ t = MIN( 1.5*player.p->speed, VMOD(player.p->solid->vel) ) / (player.p->thrust / player.p->solid->mass); /* Get velocity. */ vel = MIN( player.p->speed, VMOD(player.p->solid->vel) ); /* Get distance. */ dist = vel*(t+1.1*M_PI/player.p->turn) - 0.5*(player.p->thrust/player.p->solid->mass)*t*t; /* Output distance^2 */ d = vect_dist( pos, &player.p->solid->pos ); dist = d - dist; if (count_target) *dist2 = dist; else *dist2 = d; /* See if should start braking. */ if (dist < 0.) { player_accelOver(); return 1; } return 0; }
/** * @brief Handles common time accel ramp-down for autonav to positions and planets. */ static void player_autonavRampdown( double d ) { double t, tint; double vel; vel = MIN( 1.5*player.p->speed, VMOD(player.p->solid->vel) ); t = d / vel * (1. - 0.075 * tc_base); tint = 3. + 0.5*(3.*(tc_mod-tc_base)); if (t < tint) { tc_rampdown = 1; tc_down = (tc_mod-tc_base) / 3.; } }
/** * @brief Renders the starry background. * * @param dt Current delta tick. */ void background_renderStars( const double dt ) { (void) dt; unsigned int i; GLfloat hh, hw, h, w; GLfloat x, y, m, b; GLfloat brightness; double z; double sx, sy; int shade_mode; int j, n; /* * gprof claims it's the slowest thing in the game! */ /* Do some scaling for now. */ z = cam_getZoom(); z = 1. * (1. - conf.zoom_stars) + z * conf.zoom_stars; gl_matrixPush(); gl_matrixTranslate( SCREEN_W/2., SCREEN_H/2. ); gl_matrixScale( z, z ); if (!paused && (player.p != NULL) && !player_isFlag(PLAYER_DESTROYED) && !player_isFlag(PLAYER_CREATING)) { /* update position */ /* Calculate some dimensions. */ w = (SCREEN_W + 2.*STAR_BUF); w += conf.zoom_stars * (w / conf.zoom_far - 1.); h = (SCREEN_H + 2.*STAR_BUF); h += conf.zoom_stars * (h / conf.zoom_far - 1.); hw = w/2.; hh = h/2.; if ((star_x > SCREEN_W) || (star_y > SCREEN_H)) { sx = ceil( star_x / SCREEN_W ); sy = ceil( star_y / SCREEN_H ); n = MAX( sx, sy ); star_x /= (double)n; star_y /= (double)n; } else n = 1; /* Calculate new star positions. */ for (j=0; j < n; j++) { for (i=0; i < nstars; i++) { /* calculate new position */ b = 1./(9. - 10.*star_colour[8*i+3]); star_vertex[4*i+0] = star_vertex[4*i+0] + star_x*b; star_vertex[4*i+1] = star_vertex[4*i+1] + star_y*b; /* check boundaries */ if (star_vertex[4*i+0] > hw) star_vertex[4*i+0] -= w; else if (star_vertex[4*i+0] < -hw) star_vertex[4*i+0] += w; if (star_vertex[4*i+1] > hh) star_vertex[4*i+1] -= h; else if (star_vertex[4*i+1] < -hh) star_vertex[4*i+1] += h; } } /* Upload the data. */ gl_vboSubData( star_vertexVBO, 0, nstars * 4 * sizeof(GLfloat), star_vertex ); } /* Decide on shade mode. */ shade_mode = 0; if ((player.p != NULL) && !player_isFlag(PLAYER_DESTROYED) && !player_isFlag(PLAYER_CREATING)) { if (pilot_isFlag(player.p,PILOT_HYPERSPACE) && /* hyperspace fancy effects */ (player.p->ptimer < HYPERSPACE_STARS_BLUR)) { glShadeModel(GL_SMOOTH); shade_mode = 1; /* lines will be based on velocity */ m = HYPERSPACE_STARS_BLUR-player.p->ptimer; m /= HYPERSPACE_STARS_BLUR; m *= HYPERSPACE_STARS_LENGTH; x = m*cos(VANGLE(player.p->solid->vel)); y = m*sin(VANGLE(player.p->solid->vel)); } else if (dt_mod > 3.) { glShadeModel(GL_SMOOTH); shade_mode = 1; /* lines will be based on velocity */ m = (dt_mod-3.)*VMOD(player.p->solid->vel)/10.; x = m*cos(VANGLE(player.p->solid->vel)); y = m*sin(VANGLE(player.p->solid->vel)); } if (shade_mode) { /* Generate lines. */ for (i=0; i < nstars; i++) { brightness = star_colour[8*i+3]; star_vertex[4*i+2] = star_vertex[4*i+0] + x*brightness; star_vertex[4*i+3] = star_vertex[4*i+1] + y*brightness; } /* Upload new data. */ gl_vboSubData( star_vertexVBO, 0, nstars * 4 * sizeof(GLfloat), star_vertex ); } } /* Render. */ gl_vboActivate( star_vertexVBO, GL_VERTEX_ARRAY, 2, GL_FLOAT, 2 * sizeof(GLfloat) ); gl_vboActivate( star_colourVBO, GL_COLOR_ARRAY, 4, GL_FLOAT, 4 * sizeof(GLfloat) ); if (shade_mode) { glDrawArrays( GL_LINES, 0, nstars ); glDrawArrays( GL_POINTS, 0, nstars ); /* This second pass is when the lines are very short that they "lose" intensity. */ glShadeModel(GL_FLAT); } else { glDrawArrays( GL_POINTS, 0, nstars ); } /* Clear star movement. */ star_x = 0.; star_y = 0.; /* Disable vertex array. */ gl_vboDeactivate(); /* Pop matrix. */ gl_matrixPop(); /* Check for errors. */ gl_checkErr(); }
/** * @brief The AI of seeker missiles. * * @param w Weapon to do the thinking. * @param dt Current delta tick. */ static void think_seeker( Weapon* w, const double dt ) { double diff; double vel; Pilot *p; int effect; Vector2d v; double t; if (w->target == w->parent) return; /* no self shooting */ p = pilot_get(w->target); /* no null pilot_nstack */ if (p==NULL) { weapon_setThrust( w, 0. ); weapon_setTurn( w, 0. ); return; } /* Handle by status. */ switch (w->status) { case WEAPON_STATUS_OK: if (w->lockon < 0.) w->status = WEAPON_STATUS_LOCKEDON; break; case WEAPON_STATUS_LOCKEDON: /* Check to see if can get jammed */ if ((p->jam_range != 0.) && /* Target has jammer and weapon is in range */ (vect_dist(&w->solid->pos,&p->solid->pos) < p->jam_range)) { /* Check to see if weapon gets jammed */ if (RNGF() < p->jam_chance - w->outfit->u.amm.resist) { w->status = WEAPON_STATUS_JAMMED; /* Give it a nice random effect */ effect = RNG(0,3); switch (effect) { case 0: /* Stuck in left loop */ weapon_setTurn( w, w->outfit->u.amm.turn ); break; case 1: /* Stuck in right loop */ weapon_setTurn( w, -w->outfit->u.amm.turn ); break; default: /* Blow up. */ w->timer = -1.; break; } } else /* Can't get jammed anymore */ w->status = WEAPON_STATUS_UNJAMMED; } /* Purpose fallthrough */ case WEAPON_STATUS_UNJAMMED: /* Work as expected */ /* Smart seekers take into account ship velocity. */ if (w->outfit->u.amm.ai == 2) { /* Calculate time to reach target. */ vect_cset( &v, p->solid->pos.x - w->solid->pos.x, p->solid->pos.y - w->solid->pos.y ); t = vect_odist( &v ) / w->outfit->u.amm.speed; /* Calculate target's movement. */ vect_cset( &v, v.x + t*(p->solid->vel.x - w->solid->vel.x), v.y + t*(p->solid->vel.y - w->solid->vel.y) ); /* Get the angle now. */ diff = angle_diff(w->solid->dir, VANGLE(v) ); } /* Other seekers are stupid. */ else { diff = angle_diff(w->solid->dir, /* Get angle to target pos */ vect_angle(&w->solid->pos, &p->solid->pos)); } /* Set turn. */ weapon_setTurn( w, CLAMP( -w->outfit->u.amm.turn, w->outfit->u.amm.turn, 10 * diff * w->outfit->u.amm.turn )); break; case WEAPON_STATUS_JAMMED: /* Continue doing whatever */ /* Do nothing, dir_vel should be set already if needed */ break; default: WARN("Unknown weapon status for '%s'", w->outfit->name); break; } /* Limit speed here */ vel = MIN(w->outfit->u.amm.speed, VMOD(w->solid->vel) + w->outfit->u.amm.thrust*dt); vect_pset( &w->solid->vel, vel, w->solid->dir ); /*limit_speed( &w->solid->vel, w->outfit->u.amm.speed, dt );*/ }
/** * @brief Creates a new weapon. * * @param outfit Outfit which spawned the weapon. * @param dir Direction the shooter is facing. * @param pos Position of the shooter. * @param vel Velocity of the shooter. * @param parent Shooter ID. * @param target Target ID of the shooter. * @return A pointer to the newly created weapon. */ static Weapon* weapon_create( const Outfit* outfit, const double dir, const Vector2d* pos, const Vector2d* vel, const unsigned int parent, const unsigned int target ) { Vector2d v; double mass, rdir; Pilot *pilot_target; double x,y, t, dist; Weapon* w; /* Create basic features */ w = malloc(sizeof(Weapon)); memset(w, 0, sizeof(Weapon)); w->faction = pilot_get(parent)->faction; /* non-changeable */ w->parent = parent; /* non-changeable */ w->target = target; /* non-changeable */ w->outfit = outfit; /* non-changeable */ w->update = weapon_update; w->status = WEAPON_STATUS_OK; w->strength = 1.; switch (outfit->type) { /* Bolts treated together */ case OUTFIT_TYPE_BOLT: case OUTFIT_TYPE_TURRET_BOLT: /* Only difference is the direction of fire */ if ((outfit->type == OUTFIT_TYPE_TURRET_BOLT) && (w->parent!=w->target) && (w->target != 0)) { /* Must have valid target */ pilot_target = pilot_get(w->target); if (pilot_target == NULL) rdir = dir; else { /* Get the distance */ dist = vect_dist( pos, &pilot_target->solid->pos ); /* Aim. */ if (dist > outfit->u.blt.range*1.2) { x = pilot_target->solid->pos.x - pos->x; y = pilot_target->solid->pos.y - pos->y; } else { /* Try to predict where the enemy will be. */ /* Time for shots to reach that distance */ t = dist / (w->outfit->u.blt.speed + VMOD(*vel)); /* Position is calculated on where it should be */ x = (pilot_target->solid->pos.x + pilot_target->solid->vel.x*t) - (pos->x + vel->x*t); y = (pilot_target->solid->pos.y + pilot_target->solid->vel.y*t) - (pos->y + vel->y*t); } /* Set angle to face. */ rdir = ANGLE(x, y); } } else /* fire straight */ rdir = dir; rdir += RNG_2SIGMA() * outfit->u.blt.accuracy/2. * 1./180.*M_PI; if (rdir < 0.) rdir += 2.*M_PI; else if (rdir >= 2.*M_PI) rdir -= 2.*M_PI; mass = 1; /* Lasers are presumed to have unitary mass */ vectcpy( &v, vel ); vect_cadd( &v, outfit->u.blt.speed*cos(rdir), outfit->u.blt.speed*sin(rdir)); w->timer = outfit->u.blt.range / outfit->u.blt.speed; w->falloff = w->timer - outfit->u.blt.falloff / outfit->u.blt.speed; w->solid = solid_create( mass, rdir, pos, &v ); w->voice = sound_playPos( w->outfit->u.blt.sound, w->solid->pos.x, w->solid->pos.y, w->solid->vel.x, w->solid->vel.y); break; /* Beam weapons are treated together. */ case OUTFIT_TYPE_BEAM: case OUTFIT_TYPE_TURRET_BEAM: if ((outfit->type == OUTFIT_TYPE_TURRET_BEAM) && (w->parent!=w->target)) { pilot_target = pilot_get(target); rdir = (pilot_target == NULL) ? dir : vect_angle(pos, &pilot_target->solid->pos); } else rdir = dir; if (rdir < 0.) rdir += 2.*M_PI; else if (rdir >= 2.*M_PI) rdir -= 2.*M_PI; mass = 1.; /**< Needs a mass. */ w->solid = solid_create( mass, rdir, pos, NULL ); w->think = think_beam; w->timer = outfit->u.bem.duration; w->voice = sound_playPos( w->outfit->u.bem.sound, w->solid->pos.x, w->solid->pos.y, w->solid->vel.x, w->solid->vel.y); break; /* Treat seekers together. */ case OUTFIT_TYPE_AMMO: case OUTFIT_TYPE_TURRET_AMMO: if (w->outfit->type == OUTFIT_TYPE_TURRET_AMMO) { pilot_target = pilot_get(w->target); if (pilot_target == NULL) rdir = dir; else { /* Get the distance */ dist = vect_dist( pos, &pilot_target->solid->pos ); /* Aim. */ /* Try to predict where the enemy will be. */ /* Time for shots to reach that distance */ if (outfit->u.amm.thrust == 0.) t = dist / (w->outfit->u.amm.speed + VMOD(*vel)); else t = dist / w->outfit->u.amm.speed; /* Position is calculated on where it should be */ x = (pilot_target->solid->pos.x + pilot_target->solid->vel.x*t) - (pos->x + vel->x*t); y = (pilot_target->solid->pos.y + pilot_target->solid->vel.y*t) - (pos->y + vel->y*t); /* Set angle to face. */ rdir = ANGLE(x, y); } } else { rdir = dir; } if (outfit->u.amm.accuracy != 0.) { rdir += RNG_2SIGMA() * outfit->u.amm.accuracy/2. * 1./180.*M_PI; if ((rdir > 2.*M_PI) || (rdir < 0.)) rdir = fmod(rdir, 2.*M_PI); } if (rdir < 0.) rdir += 2.*M_PI; else if (rdir >= 2.*M_PI) rdir -= 2.*M_PI; /* If thrust is 0. we assume it starts out at speed. */ vectcpy( &v, vel ); if (outfit->u.amm.thrust == 0.) vect_cadd( &v, cos(rdir) * w->outfit->u.amm.speed, sin(rdir) * w->outfit->u.amm.speed ); /* Set up ammo details. */ mass = w->outfit->mass; w->lockon = outfit->u.amm.lockon; w->timer = outfit->u.amm.duration; w->solid = solid_create( mass, rdir, pos, &v ); if (w->outfit->u.amm.thrust != 0.) weapon_setThrust( w, w->outfit->u.amm.thrust * mass ); /* Handle seekers. */ if (w->outfit->u.amm.ai > 0) { w->think = think_seeker; /* AI is the same atm. */ /* If they are seeking a pilot, increment lockon counter. */ pilot_target = pilot_get(target); if (pilot_target != NULL) pilot_target->lockons++; } /* Play sound. */ w->voice = sound_playPos(w->outfit->u.amm.sound, w->solid->pos.x, w->solid->pos.y, w->solid->vel.x, w->solid->vel.y); break; /* just dump it where the player is */ default: WARN("Weapon of type '%s' has no create implemented yet!", w->outfit->name); w->solid = solid_create( 1., dir, pos, vel ); break; } /* Set life to timer. */ w->life = w->timer; return w; }
/** * @brief Handles the autonavigation process for the player. */ static void player_autonav (void) { JumpPoint *jp; int ret; double d, t, tint; double vel; switch (player.autonav) { case AUTONAV_JUMP_APPROACH: /* Target jump. */ jp = &cur_system->jumps[ player.p->nav_hyperspace ]; ret = player_autonavApproach( &jp->pos, &d, 0 ); if (ret) player.autonav = AUTONAV_JUMP_BRAKE; else if (!tc_rampdown && (map_npath<=1)) { vel = MIN( 1.5*player.p->speed, VMOD(player.p->solid->vel) ); t = d / vel * (1.2 - .1 * tc_base); /* tint is the integral of the time in per time units. * * tc_mod * ^ * | * |\ * | \ * | \___ * | * +------> time * 0 3 * * We decompose integral in a rectangle (3*1) and a triangle (3*(tc_mod-1.))/2. * This is the "elapsed time" when linearly decreasing the tc_mod. Which we can * use to calculate the actual "game time" that'll pass when decreasing the * tc_mod to 1 during 3 seconds. This can be used then to compare when we want to * start decrementing. */ tint = 3. + 0.5*(3.*(tc_mod-tc_base)); if (t < tint) { tc_rampdown = 1; tc_down = (tc_mod-tc_base) / 3.; } } break; case AUTONAV_JUMP_BRAKE: /* Target jump. */ jp = &cur_system->jumps[ player.p->nav_hyperspace ]; if (player.p->stats.misc_instant_jump) { ret = pilot_interceptPos( player.p, jp->pos.x, jp->pos.y ); if (!ret && space_canHyperspace(player.p)) ret = 1; player_acc = player.p->solid->thrust / player.p->thrust; } else ret = player_autonavBrake(); /* Try to jump or see if braked. */ if (ret) { if (space_canHyperspace(player.p)) player_jump(); player.autonav = AUTONAV_JUMP_APPROACH; } /* See if should ramp down. */ if (!tc_rampdown && (map_npath<=1)) { tc_rampdown = 1; tc_down = (tc_mod-tc_base) / 3.; } break; case AUTONAV_POS_APPROACH: ret = player_autonavApproach( &player.autonav_pos, &d, 1 ); if (ret) { player_message( _("\apAutonav arrived at position.") ); player_autonavEnd(); } else if (!tc_rampdown) player_autonavRampdown(d); break; case AUTONAV_PNT_APPROACH: ret = player_autonavApproach( &player.autonav_pos, &d, 1 ); if (ret) { player_message( _("\apAutonav arrived at \a%c%s\a\0."), planet_getColourChar( planet_get(player.autonavmsg) ), player.autonavmsg ); player_autonavEnd(); } else if (!tc_rampdown) player_autonavRampdown(d); break; } }