/** * @brief Initializes a new Solid. * * @param dest Solid to initialize. * @param mass Mass to set solid to. * @param dir Solid initial direction. * @param pos Initial solid position. * @param vel Initial solid velocity. */ void solid_init( Solid* dest, const double mass, const double dir, const Vector2d* pos, const Vector2d* vel, int update ) { memset(dest, 0, sizeof(Solid)); dest->mass = mass; /* Set direction velocity. */ dest->dir_vel = 0.; /* Set force. */ dest->thrust = 0.; /* Set direction. */ dest->dir = dir; if ((dest->dir > 2.*M_PI) || (dest->dir < 0.)) dest->dir = fmod(dest->dir, 2.*M_PI); /* Set velocity. */ if (vel == NULL) vectnull( &dest->vel ); else vectcpy( &dest->vel, vel ); /* Set position. */ if (pos == NULL) vectnull( &dest->pos ); else vectcpy( &dest->pos, pos); /* Misc. */ dest->speed_max = -1.; /* Negative is invalid. */ /* Handle update. */ switch (update) { case SOLID_UPDATE_RK4: dest->update = solid_update_rk4; break; case SOLID_UPDATE_EULER: dest->update = solid_update_euler; break; default: WARN("Solid initialization did not specify correct update function!"); dest->update = solid_update_rk4; break; } }
/** * @brief Gets the player's position. * * @usage v = player.pos() * * @luareturn The position of the player (Vec2). * @luafunc pos() */ static int playerL_getPosition( lua_State *L ) { LuaVector v; vectcpy( &v.vec, &player.p->solid->pos ); lua_pushvector(L, v); return 1; }
/** * @brief Gets the position of the jump in the system. * * @usage v = j:pos() * @luaparam j Jump to get the position of. * @luareturn The position of the jump in the system as a vec2. * @luafunc pos( j ) */ static int jumpL_position( lua_State *L ) { JumpPoint *jp; LuaVector v; jp = luaL_validjump(L,1); vectcpy(&v.vec, &jp->pos); lua_pushvector(L, v); return 1; }
/** * @brief Gets the position of the planet in the system. * * @usage v = p:pos() * @luaparam p Planet to get the position of. * @luareturn The position of the planet in the system as a vec2. * @luafunc pos( p ) */ static int planetL_position( lua_State *L ) { LuaPlanet *p; LuaVector v; p = luaL_checkplanet(L,1); vectcpy(&v.vec, &p->p->pos); lua_pushvector(L, v); return 1; }
/** * @brief Gets the pilot's velocity. * * @usage vel = p:vel() * * @luaparam p Pilot to get the velocity of. * @luareturn The pilot's current velocity as a vec2. * @luafunc vel( p ) */ static int pilotL_velocity( lua_State *L ) { LuaPilot *p1; Pilot *p; LuaVector v; /* Parse parameters */ p1 = luaL_checkpilot(L,1); p = pilot_get( p1->pilot ); /* Pilot must exist. */ if (p == NULL) { NLUA_ERROR(L,"Pilot is invalid."); return 0; } /* Push velocity. */ vectcpy( &v.vec, &p->solid->vel ); lua_pushvector(L, v); return 1; }
/** * @brief Sets the pilot's position. * * @usage p:warp( vec2.new( 300, 200 ) ) * * @luaparam p Pilot to set the position of. * @luaparam pos Position to set. * @luafunc warp( p, pos ) */ static int pilotL_warp( lua_State *L ) { LuaPilot *p1; Pilot *p; LuaVector *v; /* Parse parameters */ p1 = luaL_checkpilot(L,1); p = pilot_get( p1->pilot ); v = luaL_checkvector(L,2); /* Pilot must exist. */ if (p == NULL) { NLUA_ERROR(L,"Pilot is invalid."); return 0; } /* Warp pilot to new position. */ vectcpy( &p->solid->pos, &v->vec ); vectnull( &p->solid->vel ); /* Clear velocity otherwise it's a bit weird. */ return 0; }
/** * @brief Gets the position of a jump point from one system to another. * * @usage v = system.cur():jumpPos( neighbour_system ) -- Gets the position of the jump point to neighbour_system * * @luaparam from System jumping from. * @luaparam to System jumping to. * @luareturn A Vector2D containing the jump position or nil if not connected. * @luafunc jumpPos( from, to ) */ static int systemL_jumpPos( lua_State *L ) { LuaVector lv; StarSystem *from, *to; int i; from = luaL_validsystem(L,1); to = luaL_validsystem(L,2); for (i=0; i<from->njumps; i++) { /* Wait until found. */ if (from->jumps[i].target != to) continue; vectcpy( &lv.vec, &from->jumps[i].pos ); lua_pushvector(L,lv); return 1; } lua_pushnil(L); return 1; }
/** * @brief Teleports the player to a new planet or system (only if not landed). * * If the destination is a system, the coordinates of the player will not change. * If the destination is a planet, the player will be placed over that planet. * * @usage player.teleport( system.get("Arcanis") ) -- Teleports the player to Arcanis. * @usage player.teleport( "Arcanis" ) -- Teleports the player to Arcanis. * @usage player.teleport( "Dvaer Prime" ) -- Teleports the player to Dvaer, and relocates him to Dvaer Prime. * * @luaparam dest System or name of a system or planet or name of a planet to teleport the player to. * @luafunc teleport( dest ) */ static int playerL_teleport( lua_State *L ) { Planet *pnt; StarSystem *sys; const char *name, *pntname; /* Must not be landed. */ if (landed) NLUA_ERROR(L,"Can not teleport the player while landed!"); if (comm_isOpen()) NLUA_ERROR(L,"Can not teleport the player while the comm is open!"); if (player_isBoarded()) NLUA_ERROR(L,"Can not teleport the player while he is boarded!"); pnt = NULL; /* Get a system. */ if (lua_issystem(L,1)) { sys = luaL_validsystem(L,1); name = system_getIndex(sys->id)->name; } /* Get a planet. */ else if (lua_isplanet(L,1)) { pnt = luaL_validplanet(L,1); name = planet_getSystem( pnt->name ); if (name == NULL) { NLUA_ERROR( L, "Planet '%s' does not belong to a system..", pnt->name ); return 0; } } /* Get destination from string. */ else if (lua_isstring(L,1)) { name = lua_tostring(L,1); if (!system_exists( name )) { if (!planet_exists( name )) { NLUA_ERROR( L, "'%s' is not a valid teleportation target.", name ); return 0; } /* No system found, assume destination string is the name of a planet. */ pntname = name; name = planet_getSystem( name ); pnt = planet_get( pntname ); if (name == NULL) { NLUA_ERROR( L, "Planet '%s' does not belong to a system..", pntname ); return 0; } } } else NLUA_INVALID_PARAMETER(L); /* Check if system exists. */ if (!system_exists( name )) { NLUA_ERROR( L, "System '%s' does not exist.", name ); return 0; } /* Jump out hook is run first. */ hooks_run( "jumpout" ); /* Just in case remove hyperspace flags. */ pilot_rmFlag( player.p, PILOT_HYPERSPACE ); pilot_rmFlag( player.p, PILOT_HYP_BEGIN ); pilot_rmFlag( player.p, PILOT_HYP_BRAKE ); pilot_rmFlag( player.p, PILOT_HYP_PREP ); /* Free graphics. */ space_gfxUnload( cur_system ); /* Go to the new system. */ space_init( name ); /* Map gets deformed when jumping this way. */ map_clear(); /* Add the escorts. */ player_addEscorts(); /* Run hooks - order is important. */ hooks_run( "jumpin" ); hooks_run( "enter" ); events_trigger( EVENT_TRIGGER_ENTER ); missions_run( MIS_AVAIL_SPACE, -1, NULL, NULL ); /* Reset targets when teleporting */ player_targetPlanetSet( -1 ); player_targetHyperspaceSet( -1 ); gui_setNav(); /* Move to planet. */ if (pnt != NULL) vectcpy( &player.p->solid->pos, &pnt->pos ); return 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; }
/** * @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; }