/** * @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 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 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 Does UV decomposition of the reference vector. * * @param[out] u Parallel component of the reference vector. * @param[out] v Perpendicular component of the reference vector. * @param reference_vector The reference vector to decompose. */ void vect_uv_decomp( Vector2d* u, Vector2d* v, Vector2d* reference_vector ) { vect_pset(u, 1, VANGLE(*reference_vector)); vect_pset(v, 1, VANGLE(*reference_vector)+M_PI_2); }
/** * @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; }
/** * @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 );*/ }