/** * @brief Throws cargo out in space graphically. * * @param pilot ID of the pilot throwing the stuff out * @param com Commodity to throw out. * @param quantity Quantity thrown out. */ void commodity_Jettison( int pilot, Commodity* com, int quantity ) { (void)com; int i; Pilot* p; int n, effect; double px,py, bvx, bvy, r,a, vx,vy; p = pilot_get( pilot ); n = MAX( 1, RNG(quantity/10, quantity/5) ); px = p->solid->pos.x; py = p->solid->pos.y; bvx = p->solid->vel.x; bvy = p->solid->vel.y; for (i=0; i<n; i++) { effect = spfx_get("cargo"); /* Radial distribution gives much nicer results */ r = RNGF()*25 - 12.5; a = 2. * M_PI * RNGF(); vx = bvx + r*cos(a); vy = bvy + r*sin(a); /* Add the cargo effect */ spfx_add( effect, px, py, vx, vy, SPFX_LAYER_BACK ); } }
/** * @brief Checks to see if the pilot can steal from it's target. * * @param p Pilot stealing from it's target. * @return 0 if successful, 1 if fails, -1 if fails and kills target. */ static int board_trySteal( Pilot *p ) { Pilot *target; /* Get the target. */ target = pilot_get(p->target); if (target == NULL) return 1; /* See if was successful. */ if (RNGF() > (0.5 * (10. + (double)target->ship->crew)/(10. + (double)p->ship->crew))) return 0; /* Triggered self destruct. */ if (RNGF() < 0.4) { /* Don't actually kill. */ target->armour = 1.; /* This will make the boarding ship take the possible faction hit. */ pilot_hit( target, NULL, p->id, DAMAGE_TYPE_KINETIC, 100. ); /* Return ship dead. */ return -1; } return 1; }
/** * @brief Runs all the events matching a trigger. * * @param trigger Trigger to match. */ void events_trigger( EventTrigger_t trigger ) { int i, c; for (i=0; i<event_ndata; i++) { /* Make sure trigger matches. */ if (event_data[i].trigger != trigger) continue; /* Make sure chance is succeeded. */ if (RNGF() > event_data[i].chance) continue; /* Test uniqueness. */ if ((event_data[i].flags & EVENT_FLAG_UNIQUE) && (player_eventAlreadyDone( i ) || event_alreadyRunning(i))) continue; /* Test conditional. */ if (event_data[i].cond != NULL) { c = cond_check(event_data[i].cond); if (c<0) { WARN("Conditional for event '%s' failed to run.", event_data[i].name); continue; } else if (!c) continue; } /* Create the event. */ event_create( i ); } }
/** * @brief Runs missions matching location, all Lua side and one-shot. * * @param loc Location to match. * @param faction Faction of the planet. * @param planet Name of the current planet. * @param sysname Name of the current system. */ void missions_run( int loc, int faction, const char* planet, const char* sysname ) { MissionData* misn; Mission mission; int i; double chance; for (i=0; i<mission_nstack; i++) { misn = &mission_stack[i]; if (misn->avail.loc != loc) continue; if (!mission_meetReq(i, faction, planet, sysname)) continue; chance = (double)(misn->avail.chance % 100)/100.; if (chance == 0.) /* We want to consider 100 -> 100% not 0% */ chance = 1.; if (RNGF() < chance) { mission_init( &mission, misn, 1, 1, NULL ); mission_cleanup(&mission); /* it better clean up for itself or we do it */ } } }
/** * @brief Prepares the nebualae to be rendered. * * @param density Density of the nebula (0-1000). * @param volatility Volatility of the nebula (0-1000). */ void nebu_prep( double density, double volatility ) { (void)volatility; int i; nebu_view = 1000. - density; /* At density 1000 you're blind */ nebu_dt = 2000. / (density + 100.); /* Faster at higher density */ nebu_timer = nebu_dt; nebu_npuffs = density/4.; nebu_puffs = realloc(nebu_puffs, sizeof(NebulaPuff)*nebu_npuffs); for (i=0; i<nebu_npuffs; i++) { /* Position */ nebu_puffs[i].x = (double)RNG(-NEBULA_PUFF_BUFFER, SCREEN_W + NEBULA_PUFF_BUFFER); nebu_puffs[i].y = (double)RNG(-NEBULA_PUFF_BUFFER, SCREEN_H + NEBULA_PUFF_BUFFER); /* Maybe make size related? */ nebu_puffs[i].tex = RNG(0,NEBULA_PUFFS-1); nebu_puffs[i].height = RNGF() + 0.2; } /* Generate the overlay. */ nebu_genOverlay(); }
/** * @brief Grabs a (for now) random fleet out of the stack for the faction. * * @param faction Which faction to get a fleet for. * @return a pointer to a fleet, or NULL if not found. */ Fleet* fleet_grab( const int faction ) { Fleet* fleet; int inf = 0; int rnd; /* Check for a legal faction. */ if(!faction_isFaction(faction)) { WARN("%i is not a faction.", faction); return NULL; } /* Try to find a fleet of the faction. */ while(1) { /* Check for infinite loop. */ if(inf > 100 * nfleets) { WARN("Could not find a fleet for faction %s.", faction_name(faction)); return NULL; } inf++; /* Get a fleet and check its faction. */ rnd = RNGF() * (nfleets - 0.01); fleet = &fleet_stack[rnd]; } return fleet; }
/** * @brief Generates a mission list. This runs create() so won't work with all * missions. * * @param[out] n Missions created. * @param faction Faction of the planet. * @param planet Name of the planet. * @param sysname Name of the current system. * @param loc Location * @return The stack of Missions created with n members. */ Mission* missions_genList( int *n, int faction, const char* planet, const char* sysname, int loc ) { int i,j, m, alloced; double chance; int rep; Mission* tmp; MissionData* misn; /* Missions can't be generated by tutorial. */ if (player_isTut()) { *n = 0; return NULL; } /* Find available missions. */ tmp = NULL; m = 0; alloced = 0; for (i=0; i<mission_nstack; i++) { misn = &mission_stack[i]; if (misn->avail.loc == loc) { /* Must meet requirements. */ if (!mission_meetReq(i, faction, planet, sysname)) continue; /* Must hit chance. */ chance = (double)(misn->avail.chance % 100)/100.; if (chance == 0.) /* We want to consider 100 -> 100% not 0% */ chance = 1.; rep = MAX(1, misn->avail.chance / 100); for (j=0; j<rep; j++) /* random chance of rep appearances */ if (RNGF() < chance) { m++; /* Extra allocation. */ if (m > alloced) { alloced += 32; tmp = realloc( tmp, sizeof(Mission) * alloced ); } /* Initialize the mission. */ if (mission_init( &tmp[m-1], misn, 1, 1, NULL )) m--; } } } /* Sort. */ if (tmp != NULL) { qsort( tmp, m, sizeof(Mission), mission_compare ); (*n) = m; } else { (*n) = 0; } return tmp; }
/** * @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 Does explosion in a radius (damage and graphics). * * @param x X position of explosion center. * @param y Y position of explosion center. * @param vx X velocity of explosion center. * @param vy Y velocity of explosion center. * @param radius Radius of the explosion. * @param dtype Damage type. * @param damage Damage amount. * @param parent Parent of the explosion, NULL is none. * @param mode Defines the explosion behaviour. */ void expl_explode( double x, double y, double vx, double vy, double radius, const Damage *dmg, const Pilot *parent, int mode ) { int i, n; double a, d; double area; double ex, ey; int layer; int efx; /* Standard stuff - lazy allocation. */ if (exp_s == -1) { exp_s = spfx_get("ExpS"); exp_m = spfx_get("ExpM"); exp_l = spfx_get("ExpL"); } layer = SPFX_LAYER_FRONT; /* Number of explosions. */ area = M_PI * pow2(radius); n = (int)(area / 100.); /* Create explosions. */ for (i=0; i<n; i++) { /* Get position. */ a = RNGF()*360.; d = RNGF()*(radius-5.) + 5.; ex = d*cos(a); ey = d*sin(a); /* Create explosion. */ efx = (RNG(0,2)==0) ? exp_m : exp_s; spfx_add( efx, x+ex, y+ey, vx, vy, layer ); } /* Final explosion. */ spfx_add( exp_l, x, y, vx, vy, layer ); /* Run the damage. */ if (dmg != NULL) expl_explodeDamage( x, y, radius, dmg, parent, mode ); }
/** * @brief Creates a new special effect. * * @param effect Base effect identifier to use. * @param px X position of the effect. * @param py Y position of the effect. * @param vx X velocity of the effect. * @param vy Y velocity of the effect. * @param layer Layer to put the effect on. */ void spfx_add( int effect, const double px, const double py, const double vx, const double vy, const int layer ) { SPFX *cur_spfx; double ttl, anim; if ((effect < 0) || (effect > spfx_neffects)) { WARN("Trying to add spfx with invalid effect!"); return; } /* * Select the Layer */ if (layer == SPFX_LAYER_FRONT) { /* front layer */ if (spfx_mstack_front < spfx_nstack_front+1) { /* need more memory */ if (spfx_mstack_front == 0) spfx_mstack_front = SPFX_CHUNK_MIN; else spfx_mstack_front += MIN( spfx_mstack_front, SPFX_CHUNK_MAX ); spfx_stack_front = realloc( spfx_stack_front, spfx_mstack_front*sizeof(SPFX) ); } cur_spfx = &spfx_stack_front[spfx_nstack_front]; spfx_nstack_front++; } else if (layer == SPFX_LAYER_BACK) { /* back layer */ if (spfx_mstack_back < spfx_nstack_back+1) { /* need more memory */ if (spfx_mstack_back == 0) spfx_mstack_back = SPFX_CHUNK_MIN; else spfx_mstack_back += MIN( spfx_mstack_back, SPFX_CHUNK_MAX ); spfx_stack_back = realloc( spfx_stack_back, spfx_mstack_back*sizeof(SPFX) ); } cur_spfx = &spfx_stack_back[spfx_nstack_back]; spfx_nstack_back++; } else { WARN("Invalid SPFX layer."); return; } /* The actual adding of the spfx */ cur_spfx->effect = effect; vect_csetmin( &cur_spfx->pos, px, py ); vect_csetmin( &cur_spfx->vel, vx, vy ); /* Timer magic if ttl != anim */ ttl = spfx_effects[effect].ttl; anim = spfx_effects[effect].anim; if (ttl != anim) cur_spfx->timer = ttl + RNGF()*anim; else cur_spfx->timer = ttl; }
/** * @brief Increases the current rumble level. * * Rumble will decay over time. * * @param mod Modifier to increase level by. */ void spfx_shake( double mod ) { /* Add the modifier. */ shake_rad += mod; if (shake_rad > SHAKE_MAX) shake_rad = SHAKE_MAX; vect_pset( &shake_vel, SHAKE_VEL_MOD*shake_rad, RNGF() * 2. * M_PI ); /* Rumble if it wasn't rumbling before. */ spfx_hapticRumble(mod); /* Notify that rumble is active. */ shake_off = 0; }
/** * @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 Runs all the events matching a trigger. * * @param trigger Trigger to match. */ void events_trigger( EventTrigger_t trigger ) { int i, c; int created; /* Events can't be triggered by tutorial. */ if (player_isTut()) return; created = 0; for (i=0; i<event_ndata; i++) { /* Make sure trigger matches. */ if (event_data[i].trigger != trigger) continue; /* Make sure chance is succeeded. */ if (RNGF() > event_data[i].chance) continue; /* Test uniqueness. */ if ((event_data[i].flags & EVENT_FLAG_UNIQUE) && (player_eventAlreadyDone( i ) || event_alreadyRunning(i))) continue; /* Test conditional. */ if (event_data[i].cond != NULL) { c = cond_check(event_data[i].cond); if (c<0) { WARN("Conditional for event '%s' failed to run.", event_data[i].name); continue; } else if (!c) continue; } /* Create the event. */ event_create( i, NULL ); created++; } /* Run claims if necessary. */ if (created) claim_activateAll(); }
/** * @brief Gets a random number. With no parameters it returns a random float between * 0 and 1. * * With one parameter it returns a whole number between 0 and that number * (both included). With two parameters it returns a whole number between * both parameters (both included). * * @usage n = rnd() -- Number in range [0:1]. * @usage n = rnd(5) -- Number in range [0:5]. * @usage n = rnd(3,5) -- Number in range [3,5]. * * @luaparam x First parameter, read description for details. * @luaparam y Second parameter, read description for details. * @luareturn A randomly generated number, read description for details. * @luafunc rnd( x, y ) */ static int rnd_int( lua_State *L ) { int o; int l,h; o = lua_gettop(L); if (o==0) lua_pushnumber(L, RNGF() ); /* random double 0 <= x <= 1 */ else if (o==1) { /* random int 0 <= x <= parameter */ l = luaL_checkint(L,1); lua_pushnumber(L, RNG(0, l)); } else if (o>=2) { /* random int parameter 1 <= x <= parameter 2 */ l = luaL_checkint(L,1); h = luaL_checkint(L,2); lua_pushnumber(L, RNG(l,h)); } else NLUA_INVALID_PARAMETER(L); return 1; /* unless it's returned 0 already it'll always return a parameter */ }
/** * @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 Initilaizes background stars. * * @param n Number of stars to add (stars per 800x640 screen). */ void background_initStars( int n ) { unsigned int i; GLfloat w, h, hw, hh; double size; /* Calculate size. */ size = SCREEN_W*SCREEN_H+STAR_BUF*STAR_BUF; size /= pow2(conf.zoom_far); /* Calculate star buffer. */ 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.; /* Calculate stars. */ size *= n; nstars = (unsigned int)(size/(800.*600.)); if (mstars < nstars) { /* Create data. */ star_vertex = realloc( star_vertex, nstars * sizeof(GLfloat) * 4 ); star_colour = realloc( star_colour, nstars * sizeof(GLfloat) * 8 ); mstars = nstars; } for (i=0; i < nstars; i++) { /* Set the position. */ star_vertex[4*i+0] = RNGF()*w - hw; star_vertex[4*i+1] = RNGF()*h - hh; star_vertex[4*i+2] = 0.; star_vertex[4*i+3] = 0.; /* Set the colour. */ star_colour[8*i+0] = 1.; star_colour[8*i+1] = 1.; star_colour[8*i+2] = 1.; star_colour[8*i+3] = RNGF()*0.6 + 0.2; star_colour[8*i+4] = 1.; star_colour[8*i+5] = 1.; star_colour[8*i+6] = 1.; star_colour[8*i+7] = 0.; } /* Destroy old VBO. */ if (star_vertexVBO != NULL) { gl_vboDestroy( star_vertexVBO ); star_vertexVBO = NULL; } if (star_colourVBO != NULL) { gl_vboDestroy( star_colourVBO ); star_colourVBO = NULL; } /* Create now VBO. */ star_vertexVBO = gl_vboCreateStream( nstars * sizeof(GLfloat) * 4, star_vertex ); star_colourVBO = gl_vboCreateStatic( nstars * sizeof(GLfloat) * 8, star_colour ); }
/** * @brief Makes the player take off if landed. * * @param delay Whether or not to have time pass as if the player landed normally. */ void takeoff( int delay ) { int h; char *nt; double a, r; if (!landed) return; /* Clear queued takeoff. */ land_takeoff = 0; /* Refuel if needed. */ land_checkAddRefuel(); /* In case we had paused messy sounds. */ sound_stopAll(); /* ze music */ music_choose("takeoff"); /* to randomize the takeoff a bit */ a = RNGF() * 2. * M_PI; r = RNGF() * land_planet->radius; /* no longer authorized to land */ player_rmFlag(PLAYER_LANDACK); pilot_rmFlag(player.p,PILOT_LANDING); /* No longer landing. */ /* set player to another position with random facing direction and no vel */ player_warp( land_planet->pos.x + r * cos(a), land_planet->pos.y + r * sin(a) ); vect_pset( &player.p->solid->vel, 0., 0. ); player.p->solid->dir = RNGF() * 2. * M_PI; cam_setTargetPilot( player.p->id, 0 ); /* heal the player */ player.p->armour = player.p->armour_max; player.p->shield = player.p->shield_max; player.p->energy = player.p->energy_max; player.p->stimer = 0.; /* initialize the new space */ h = player.p->nav_hyperspace; space_init(NULL); player.p->nav_hyperspace = h; /* cleanup */ if (save_all() < 0) { /* must be before cleaning up planet */ dialogue_alert( "Failed to save game! You should exit and check the log to see what happened and then file a bug report!" ); } /* time goes by, triggers hook before takeoff */ if (delay) ntime_inc( ntime_create( 0, 1, 0 ) ); /* 1 STP */ nt = ntime_pretty( 0, 2 ); player_message("\epTaking off from %s on %s.", land_planet->name, nt); free(nt); /* Hooks and stuff. */ land_cleanup(); /* Cleanup stuff */ hooks_run("takeoff"); /* Must be run after cleanup since we don't want the missions to think we are landed. */ if (menu_isOpen(MENU_MAIN)) return; player_addEscorts(); hooks_run("enter"); if (menu_isOpen(MENU_MAIN)) return; events_trigger( EVENT_TRIGGER_ENTER ); if (menu_isOpen(MENU_MAIN)) return; player.p->ptimer = PILOT_TAKEOFF_DELAY; pilot_setFlag( player.p, PILOT_TAKEOFF ); pilot_setThrust( player.p, 0. ); pilot_setTurn( player.p, 0. ); }
/** * @brief Makes the player take off if landed. * * @param delay Whether or not to have time pass as if the player landed normally. */ void takeoff( int delay ) { int h; char *nt; double a, r; if (!landed) return; /* Player's ship is not able to fly. */ if (!player_canTakeoff()) { char message[512]; pilot_reportSpaceworthy( player.p, message, sizeof(message) ); dialogue_msg( "Ship not fit for flight", message ); /* Check whether the player needs rescuing. */ land_stranded(); return; } /* Clear queued takeoff. */ land_takeoff = 0; /* Refuel if needed. */ land_refuel(); /* In case we had paused messy sounds. */ sound_stopAll(); /* ze music */ music_choose("takeoff"); /* to randomize the takeoff a bit */ a = RNGF() * 2. * M_PI; r = RNGF() * land_planet->radius; /* no longer authorized to land */ player_rmFlag(PLAYER_LANDACK); pilot_rmFlag(player.p,PILOT_LANDING); /* No longer landing. */ /* set player to another position with random facing direction and no vel */ player_warp( land_planet->pos.x + r * cos(a), land_planet->pos.y + r * sin(a) ); vect_pset( &player.p->solid->vel, 0., 0. ); player.p->solid->dir = RNGF() * 2. * M_PI; cam_setTargetPilot( player.p->id, 0 ); /* heal the player */ pilot_healLanded( player.p ); /* Clear planet target. Allows for easier autonav out of the system. */ player_targetPlanetSet( -1 ); /* initialize the new space */ h = player.p->nav_hyperspace; space_init(NULL); player.p->nav_hyperspace = h; /* cleanup */ if (save_all() < 0) /* must be before cleaning up planet */ dialogue_alert( "Failed to save game! You should exit and check the log to see what happened and then file a bug report!" ); /* time goes by, triggers hook before takeoff */ if (delay) ntime_inc( ntime_create( 0, 1, 0 ) ); /* 1 STP */ nt = ntime_pretty( 0, 2 ); player_message("\epTaking off from %s on %s.", land_planet->name, nt); free(nt); /* Hooks and stuff. */ land_cleanup(); /* Cleanup stuff */ hooks_run("takeoff"); /* Must be run after cleanup since we don't want the missions to think we are landed. */ if (menu_isOpen(MENU_MAIN)) return; player_addEscorts(); hooks_run("enter"); if (menu_isOpen(MENU_MAIN)) return; events_trigger( EVENT_TRIGGER_ENTER ); missions_run( MIS_AVAIL_SPACE, -1, NULL, NULL ); if (menu_isOpen(MENU_MAIN)) return; player.p->ptimer = PILOT_TAKEOFF_DELAY; pilot_setFlag( player.p, PILOT_TAKEOFF ); pilot_setThrust( player.p, 0. ); pilot_setTurn( player.p, 0. ); }
/** * @brief Adds a fleet to the system. * * You can then iterate over the pilots to change parameters like so: * @code * p = pilot.add( "Sml Trader Convoy" ) * for k,v in pairs(p) do * v:setHostile() * end * @endcode * * @usage p = pilot.add( "Pirate Hyena" ) -- Just adds the pilot (will jump in). * @usage p = pilot.add( "Trader Llama", "dummy" ) -- Overrides AI with dummy ai. * @usage p = pilot.add( "Sml Trader Convoy", "def", vec2.new( 1000, 200 ) ) -- Pilot won't jump in, will just appear. * @usage p = pilot.add( "Empire Pacifier", "def", vec2.new( 1000, 1000 ), true ) -- Have the pilot jump in. * * @luaparam fleetname Name of the fleet to add. * @luaparam ai If set will override the standard fleet AI. "def" means use default. * @luaparam pos Position to create pilots around instead of choosing randomly. * @luaparam jump true if pilots should jump in, false by default if pos is defined. * @luareturn Table populated with all the pilots created. The keys are ordered numbers. * @luafunc add( fleetname, ai, pos, jump ) */ static int pilot_addFleet( lua_State *L ) { NLUA_MIN_ARGS(1); Fleet *flt; const char *fltname, *fltai; int i, j; unsigned int p; double a; double d; Vector2d vv,vp, vn; FleetPilot *plt; LuaPilot lp; LuaVector *lv; int jump; /* Parse first argument - Fleet Name */ fltname = luaL_checkstring(L,1); /* Parse second argument - Fleet AI Override */ if (lua_gettop(L) > 1) { fltai = luaL_checkstring(L,2); if (strcmp(fltai, "def")==0) /* Check if set to default */ fltai = NULL; } else fltai = NULL; /* Parse third argument - Position */ if (lua_gettop(L) > 2) { lv = luaL_checkvector(L,3); } else lv = NULL; if (lua_gettop(L) > 3) { jump = lua_toboolean(L,4); } else { /* Only jump by default if not position was passed. */ if (lv==NULL) jump = 1; else jump = 0; } /* Needed to determine angle. */ vectnull(&vn); /* pull the fleet */ flt = fleet_get( fltname ); if (flt == NULL) { NLUA_ERROR(L,"Fleet '%s' doesn't exist.", fltname); return 0; } /* Use position passed if possible. */ if (lv != NULL) { if (!jump) vectcpy( &vp, &lv->vec ); else { /* Pilot is jumping in, we'll only use the vector angle. */ d = RNGF()*(HYPERSPACE_ENTER_MAX-HYPERSPACE_ENTER_MIN) + HYPERSPACE_ENTER_MIN; vect_pset( &vp, d, VANGLE(lv->vec) ); } } else { d = RNGF()*(HYPERSPACE_ENTER_MAX-HYPERSPACE_ENTER_MIN) + HYPERSPACE_ENTER_MIN; vect_pset( &vp, d, RNGF() * 2.*M_PI); } /* now we start adding pilots and toss ids into the table we return */ j = 0; lua_newtable(L); for (i=0; i<flt->npilots; i++) { plt = &flt->pilots[i]; if (RNG(0,100) <= plt->chance) { /* fleet displacement */ vect_cadd(&vp, RNG(75,150) * (RNG(0,1) ? 1 : -1), RNG(75,150) * (RNG(0,1) ? 1 : -1)); /* Set velocity only if no position is set.. */ if (lv != NULL) { if (jump) { a = vect_angle(&vp,&vn); vect_pset( &vv, HYPERSPACE_VEL, a ); } else { a = RNGF() * 2.*M_PI; vectnull( &vv ); } } else { /* Entering via hyperspace. */ a = vect_angle(&vp,&vn); vect_pset( &vv, HYPERSPACE_VEL, a ); } /* Make sure angle is sane. */ if (a < 0.) a += 2.*M_PI; /* Create the pilot. */ p = fleet_createPilot( flt, plt, a, &vp, &vv, fltai, 0 ); /* we push each pilot created into a table and return it */ lua_pushnumber(L,++j); /* index, starts with 1 */ lp.pilot = p; lua_pushpilot(L,lp); /* value = LuaPilot */ lua_rawset(L,-3); /* store the value in the table */ } } return 1; }