20#include "damagetype.h"
23#include "gatherable.h"
25#include "nlua_asteroid.h"
37typedef struct Debris_ {
67static int asteroid_creating = 0;
70static int asttype_cmp(
const void *p1,
const void *p2 );
73static int astgroup_cmp(
const void *p1,
const void *p2 );
77static int asteroid_updateSingle(
Asteroid *a );
83static int asteroid_updateSingle(
Asteroid *a )
92 offx = ast->
pos.
x - a->sol.pos.x;
93 offy = ast->
pos.
y - a->sol.pos.y;
97 a->sol.vel.x += ast->
accel * dt * offx /
d;
98 a->sol.vel.y += ast->
accel * dt * offy /
d;
110 ex = a->sol.pos.x - exc->
pos.
x;
111 ey = a->sol.pos.y - exc->
pos.
y;
115 a->sol.vel.x += ast->
accel * dt * ex / ed;
116 a->sol.vel.y += ast->
accel * dt * ey / ed;
124 double speed = MOD( a->sol.vel.x, a->sol.vel.y );
126 a->sol.vel.x *= ast->
maxspeed / speed;
127 a->sol.vel.y *= ast->
maxspeed / speed;
133 a->sol.pre = a->sol.pos;
134 a->sol.pos.x += a->sol.vel.x * dt;
135 a->sol.pos.y += a->sol.vel.y * dt;
138 a->ang += a->spin * dt;
141 forced = a->timer < 0.;
143 if ( a->timer < 0. ) {
144 switch ( a->state ) {
148 if ( !forced && (
player.p != NULL ) &&
149 ( ( vec2_dist2( &
player.p->solid.pos, &a->sol.pos ) <
151 ( (
player.p->nav_anchor == a->parent ) &&
152 (
player.p->nav_asteroid == a->id ) ) ) )
162 case ASTEROID_XX_TO_BG:
163 a->timer_max = a->timer = 1. + 3. * RNGF();
167 case ASTEROID_FG_TO_BG:
168 a->timer_max = a->timer = 10. + 20. * RNGF();
170 case ASTEROID_BG_TO_FG:
171 a->timer_max = a->timer = 90. + 30. * RNGF();
175 case ASTEROID_BG_TO_XX:
177 a->timer_max = a->timer = 10. + 20. * RNGF();
185 a->state = ( a->state + 1 ) % ASTEROID_STATE_MAX;
190 if ( a->state == ASTEROID_FG )
191 a->scan_alpha =
MIN( a->scan_alpha +
SCAN_FADE * dt, 1. );
193 a->scan_alpha =
MAX( a->scan_alpha -
SCAN_FADE * dt, 0. );
205 NTracingZone( _ctx, 1 );
214 if ( vec2_dist2( &ast->
pos, &exc->
pos ) <
227 if ( a->state == ASTEROID_XX ) {
229 if ( a->timer < 0. ) {
230 a->state = ASTEROID_XX_TO_BG;
231 a->timer_max = a->timer = 1. + 3. * RNGF();
235 asteroid_updateSingle( a );
239 qt_clear( &ast->
qt );
243 if ( a->state == ASTEROID_FG ) {
244 int x, y, w2, h2, px, py;
245 x = round( a->sol.pos.x );
246 y = round( a->sol.pos.y );
247 px = round( a->sol.pre.x );
248 py = round( a->sol.pre.y );
249 w2 = ceil( a->gfx->sw * 0.5 );
250 h2 = ceil( a->gfx->sh * 0.5 );
251 qt_insert( &ast->
qt, j,
MIN( x, px ) - w2,
MIN( y, py ) - h2,
252 MAX( x, px ) + w2,
MAX( y, py ) + h2 );
267 d->pos.x +=
d->vel.x * dt - dx;
268 d->pos.y +=
d->vel.y * dt - dy;
286 d->alpha =
MIN( 1.0,
d->alpha + 0.5 * dt );
288 d->alpha =
MAX( 0.0,
d->alpha - 0.5 * dt );
292 NTracingZoneEnd( _ctx );
300 double density_max = 0.;
302 asteroid_creating = 1;
304 NTracingZone( _ctx, 1 );
329 qt_destroy( &ast->
qt );
330 qx = round( ast->
pos.
x );
331 qy = round( ast->
pos.
y );
333 qt_create( &ast->
qt, qx - qr, qy - qr, qx + qr, qy + qr, 2, 5 );
340 for (
int j = 0; j < ast->
nmax; j++ ) {
348 a.state = ASTEROID_FG;
350 a.state = ASTEROID_XB;
352 a.state = ASTEROID_BX;
354 a.state = ASTEROID_XX;
355 a.timer = a.timer_max = 30. * RNGF();
356 a.ang = RNGF() * M_PI * 2.;
361 if ( ast->
label != NULL )
362 WARN( _(
"Asteroid field '%s' in system '%s' has no asteroid types "
366 WARN( _(
"Asteroid field with no label in system '%s' has no "
367 "asteroid types defined!" ),
371 density_max =
MAX( density_max, ast->
density );
380 ndebris = density_max * 100. *
382 ( RESOLUTION_W_MIN * RESOLUTION_H_MIN );
388 asteroid_creating = 0;
390 NTracingZoneEnd( _ctx );
400 double mod, theta, wmax, r;
411 n = sqrt( RNGF() ) * field->
radius;
412 a = RNGF() * 2. * M_PI;
414 vec2_cset( &pos, field->
pos.
x + n * cos( a ),
415 field->
pos.
y + n * sin( a ) );
422 if ( asteroid_creating && outfield ) {
423 ast->
state = ASTEROID_XX;
430 }
while ( outfield && ( attempts++ < 1000 ) );
461 theta = RNGF() * 2. * M_PI;
466 ast->
state = ASTEROID_XX;
468 ast->
ang = RNGF() * M_PI * 2.;
472 vec2_pset( &vel, mod, theta );
474 solid_init( &ast->
sol, 1., theta, &pos, &vel, SOLID_UPDATE_EULER );
491 theta = RNGF() * 2. * M_PI;
493 vec2_pset( &deb->
vel, mod, theta );
500 deb->
height = 0.8 + RNGF() * 0.4;
502 deb->
ang = RNGF() * M_PI * 2.;
511 a->area = M_PI *
pow2( a->radius );
514 a->nmax = floor( a->area / ASTEROID_REF_AREA * a->density );
515 if ( a->asteroids == NULL )
519 a->margin =
pow2( a->maxspeed ) / ( 4. * a->accel ) + 50.;
522 a->groupswtotal = 0.;
523 for (
int i = 0; i <
array_size( a->groupsw ); i++ )
524 a->groupswtotal += a->groupsw[i];
534 char **asteroid_files;
540 asteroid_files = PHYSFS_enumerateFiles( SPOB_GFX_SPACE_PATH
"asteroid/" );
543 for (
size_t i = 0; asteroid_files[i] != NULL; i++ ) {
545 snprintf( file,
sizeof( file ),
"%s%s", SPOB_GFX_SPACE_PATH
"asteroid/",
550 PHYSFS_freeList( asteroid_files );
562 return strcmp( at1->
name, at2->
name );
573 return strcmp( at1->
name, at2->
name );
586 for (
int i = 0; i <
array_size( asteroid_files ); i++ ) {
593 free( asteroid_files[i] );
603 WARN( _(
"Asteroid Types with same name '%s'" ),
609 for (
int i = 0; i <
array_size( asteroid_files ); i++ ) {
616 free( asteroid_files[i] );
637 WARN( _(
"Asteroid Type Groups with same name '%s'" ),
651 xmlNodePtr parent, node;
660 parent = doc->xmlChildrenNode;
661 if ( !xml_isNode( parent,
"asteroid" ) ) {
662 WARN( _(
"Malformed '%s' file: missing root element 'asteroid'" ), file );
676 xmlr_attr_strd( parent,
"name", at->
name );
677 if ( at->
name == NULL )
678 WARN( _(
"Asteroid '%s' has invalid or no name" ), file );
680 node = parent->xmlChildrenNode;
683 xml_onlyNodes( node );
686 xmlr_float( node,
"armour_min", at->
armour_min );
687 xmlr_float( node,
"armour_max", at->
armour_max );
688 xmlr_float( node,
"absorb", at->
absorb );
689 xmlr_float( node,
"damage", at->
damage );
690 xmlr_float( node,
"disable", at->
disable );
691 xmlr_float( node,
"penetration", at->
penetration );
692 xmlr_float( node,
"exp_radius", at->
exp_radius );
693 xmlr_float( node,
"alert_range", at->
alert_range );
695 if ( xml_isNode( node,
"gfx" ) ) {
699 OPENGL_TEX_MAPTRANS | OPENGL_TEX_MIPMAPS ) );
702 }
else if ( xml_isNode( node,
"commodity" ) ) {
706 memset( &material, 0,
sizeof( material ) );
708 xmlNodePtr cur = node->xmlChildrenNode;
710 xml_onlyNodes( cur );
712 xmlr_int( cur,
"quantity", material.
quantity );
713 xmlr_int( cur,
"rarity", material.
rarity );
715 if ( xml_isNode( cur,
"name" ) ) {
716 const char *str = xml_get( cur );
719 WARN( _(
"Asteroid Type '%s' has Commodity '%s' with no "
726 WARN( _(
"Asteroid Type '%s' has unknown node '%s'" ), at->
name,
728 }
while ( xml_nextNode( cur ) );
730 if ( namdef == 0 || material.
quantity == 0 )
731 WARN( _(
"Asteroid Type '%s' has commodity that lacks name or "
738 WARN( _(
"Asteroid Type '%s' has unknown node '%s'" ), at->
name,
740 }
while ( xml_nextNode( node ) );
751 WARN( _(
"Asteroid Type '%s' has armour_max below armour_min" ),
754#define MELEMENT( o, s ) \
756 WARN( _( "Asteroid Type '%s' missing/invalid '%s' element" ), at->name, \
760 MELEMENT( at->
armour_min <= 0.,
"armour_min" );
761 MELEMENT( at->
armour_max <= 0.,
"armour_max" );
779 snprintf( file,
sizeof( file ),
"%s%s.xml", ASTEROID_POLYGON_PATH, buf );
782 if ( !PHYSFS_exists( file ) ) {
783 WARN( _(
"%s xml collision polygon does not exist!\n \
784 Please use the script 'polygon_from_sprite.py'\n \
785 This file can be found in Naev's artwork repo." ),
795 node = doc->xmlChildrenNode;
796 if ( node == NULL ) {
798 WARN( _(
"Malformed %s file: does not contain elements" ), file );
803 if ( xml_isNode( node,
"polygons" ) ) {
808 }
while ( xml_nextNode( node ) );
823 xmlNodePtr parent, node;
832 parent = doc->xmlChildrenNode;
833 if ( !xml_isNode( parent,
"asteroid_group" ) ) {
834 WARN( _(
"Malformed '%s' file: missing root element 'asteroid_group'" ),
844 xmlr_attr_strd( parent,
"name", ag->
name );
845 if ( ag->
name == NULL )
846 WARN( _(
"Asteroid '%s' has invalid or no name" ), file );
848 node = parent->xmlChildrenNode;
851 xml_onlyNodes( node );
853 if ( xml_isNode( node,
"type" ) ) {
855 xmlr_attr_float_def( node,
"weight", w, 1. );
862 WARN( _(
"Asteroid Type Group '%s' has unknown node '%s'" ), ag->
name,
864 }
while ( xml_nextNode( node ) );
882 NTracingZone( _ctx, 1 );
887 if (
d->height > 1. )
891 NTracingZoneEnd( _ctx );
905 NTracingZone( _ctx, 1 );
915 if ( ( x < -r ) || ( x > SCREEN_W + r ) || ( y < -r ) ||
916 ( y > SCREEN_H + r ) )
927 if (
d->height <= 1. )
934 NTracingZoneEnd( _ctx );
946 const glColour darkcol = cGrey20;
949 if ( a->state == ASTEROID_XX )
952 progress = a->timer / a->timer_max;
953 switch ( a->state ) {
954 case ASTEROID_XX_TO_BG:
956 col.a = 1. - progress;
962 case ASTEROID_BG_TO_FG:
963 col_blend( &col, &darkcol, &cWhite, progress );
968 case ASTEROID_FG_TO_BG:
969 col_blend( &col, &cWhite, &darkcol, progress );
971 case ASTEROID_BG_TO_XX:
988 col.a = a->scan_alpha;
1009 const double scale = 0.5;
1010 const glColour col = COL_ALPHA( cInert,
d->alpha );
1013 scale,
d->ang, 0, 0, &col );
1022 ast->
density = ASTEROID_DEFAULT_DENSITY;
1025 ast->
radius = ASTEROID_DEFAULT_RADIUS;
1026 ast->
maxspeed = ASTEROID_DEFAULT_MAXSPEED;
1027 ast->
maxspin = ASTEROID_DEFAULT_MAXSPIN;
1028 ast->
accel = ASTEROID_DEFAULT_ACCEL;
1039 qt_destroy( &ast->
qt );
1121 if ( vec2_dist2( p, &a->pos ) <=
pow2( a->radius ) )
1150 WARN( _(
"Unknown Asteroid Type '%s'" ), name );
1177 WARN( _(
"Unknown Asteroid Type Group '%s'" ), name );
1190 double mining_bonus )
1196 a->armour -= darmour;
1197 if ( a->armour <= 0 )
1224 expl_explode( a->sol.pos.x, a->sol.pos.y, a->sol.vel.x, a->sol.vel.y,
1225 at->
exp_radius, &dmg, NULL, EXPL_MODE_SHIP );
1228 snprintf( buf,
sizeof( buf ),
"explosion%d", RNG( 0, 2 ) );
1234 la.parent = a->parent;
1240 if ( vec2_dist2( &p->solid.pos, &a->sol.pos ) > rad2 )
1245 lua_pop(
naevL, 1 );
1248 if ( max_rarity >= 0 ) {
1252 if ( mat->
rarity > max_rarity )
1258 double prob = 1. / (double)ndrops;
1262 if ( mat->
rarity > max_rarity )
1268 int nb = RNG( 0, round( (
double)mat->
quantity * mining_bonus ) );
1269 for (
int j = 0; j < nb; j++ ) {
1273 pos.
x += ( RNGF() * 30. - 15. );
1274 pos.
y += ( RNGF() * 30. - 15. );
1275 vel.
x += ( RNGF() * 20. - 10. );
1276 vel.
y += ( RNGF() * 20. - 10. );
1290 a->state = ASTEROID_BG_TO_XX;
1291 a->timer_max = a->timer = 0.5;
1297 qt_query( &anc->
qt, il, x1, y1, x2, y2 );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
#define array_resize(ptr_array, new_size)
Resizes the array to accomodate new_size elements.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_shrink(ptr_array)
Shrinks memory to fit only ‘size’ elements.
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
void asteroids_render(void)
Renders the current systems' spobs.
static int astgroup_parse(AsteroidTypeGroup *ag, const char *file)
Parses an asteroid type group from a file.
void asteroids_computeInternals(AsteroidAnchor *a)
Updates internal alues of an asteroid field.
static Debris * debris_stack
static void asteroid_renderSingle(const Asteroid *a)
Renders an asteroid.
static AsteroidTypeGroup * asteroid_groups
static glTexture ** debris_gfx
void asteroids_free(void)
Cleans up the system.
void asteroid_hit(Asteroid *a, const Damage *dmg, int max_rarity, double mining_bonus)
Hits an asteroid.
int asteroids_load(void)
Loads the asteroids.
void asteroid_freeAnchor(AsteroidAnchor *ast)
Frees an asteroid anchor.
static AsteroidType * asteroid_types
static void debris_renderSingle(const Debris *d, double cx, double cy)
Renders a debris.
static glTexture ** asteroid_gfx
AsteroidType * asttype_getName(const char *name)
Gets the ID of an asteroid type by name.
static int astgroup_cmp(const void *p1, const void *p2)
Compares two asteroid type groups.
const AsteroidTypeGroup * astgroup_getAll(void)
Gets all the asteroid type groups.
AsteroidTypeGroup * astgroup_getName(const char *name)
Gets an asteroid type group by name.
static int asttype_cmp(const void *p1, const void *p2)
Compares two asteroid types.
static int asttype_parse(AsteroidType *at, const char *file)
Parses the XML of an asteroid type.
void asteroid_explode(Asteroid *a, int max_rarity, double mining_bonus)
Makes an asteroid explode.
static int asttype_load(void)
Loads the asteroids types.
static const double SCAN_FADE
static double asteroid_dt
static void debris_init(Debris *deb)
Initializes a debris.
void asteroids_init(void)
Initializes the system.
void asteroids_renderOverlay(void)
Renders the system overlay.
static int asteroid_init(Asteroid *ast, const AsteroidAnchor *field)
Initializes an asteroid.
void asteroid_initAnchor(AsteroidAnchor *ast)
Initializes an asteroid anchor.
void asteroid_freeExclude(AsteroidExclusion *exc)
Frees an asteroid exclusion.
const AsteroidType * asttype_getAll(void)
Gets all the asteroid types.
int asteroids_inField(const vec2 *p)
See if the position is in an asteroid field.
void asteroids_update(double dt)
Controls fleet spawning.
static int asteroid_loadPLG(AsteroidType *temp, const char *buf)
Loads the collision polygon for an asteroid type.
void cam_getDPos(double *dx, double *dy)
Gets the camera position differential (change in last frame).
void cam_getPos(double *x, double *y)
Gets the camera position.
double cam_getZoom(void)
Gets the camera zoom.
void poly_load(CollPoly *polygon, xmlNodePtr base, const char *name)
Loads a polygon from an xml node.
void col_blend(glColour *blend, const glColour *fg, const glColour *bg, float alpha)
Blends two colours.
Commodity * commodity_get(const char *name)
Gets a commodity by name.
void dtype_calcDamage(double *dshield, double *darmour, double absorb, double *knockback, const Damage *dmg, const ShipStats *s)
Gives the real shield damage, armour damage and knockback modifier.
int dtype_get(const char *name)
Gets the id of a dtype based on name.
void expl_explode(double x, double y, double vx, double vy, double radius, const Damage *dmg, const Pilot *parent, int mode)
Does explosion in a radius (damage and graphics).
void gl_printRaw(const glFont *ft_font, double x, double y, const glColour *c, double outlineR, const char *text)
Prints text on screen.
void gatherable_free(void)
Frees all the gatherables.
int gatherable_init(const Commodity *com, const vec2 *pos, const vec2 *vel, double lifeleng, int qtt, unsigned int player_only)
Initializes a gatherable object.
void gatherable_render(void)
Renders all the gatherables.
Header file with generic functions and naev-specifics.
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
LuaAsteroid_t * lua_pushasteroid(lua_State *L, LuaAsteroid_t asteroid)
Pushes a asteroid on the stack.
glTexture * xml_parseTexture(xmlNodePtr node, const char *path, int defsx, int defsy, const unsigned int flags)
Parses a texture handling the sx and sy elements.
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
void gl_gameToScreenCoords(double *nx, double *ny, double bx, double by)
Converts in-game coordinates to screen coordinates.
void gl_renderSpriteScaleRotate(const glTexture *sprite, double bx, double by, double scalew, double scaleh, double angle, int sx, int sy, const glColour *c)
Blits a sprite, position is relative to the player with scaling and rotation.
void gl_screenToGameCoords(double *nx, double *ny, int bx, int by)
Converts screen coordinates to in-game coordinates.
void gl_renderSpriteRotate(const glTexture *sprite, double bx, double by, double angle, int sx, int sy, const glColour *c)
Blits a sprite, position is relative to the player with rotation.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
void gl_freeTexture(glTexture *texture)
Frees a texture.
void pilot_msg(const Pilot *p, const Pilot *receiver, const char *type, unsigned int idx)
Sends a message.
static Pilot ** pilot_stack
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
void pilot_untargetAsteroid(int anchor, int asteroid)
Loops over pilot stack to remove an asteroid as target.
int sound_playPos(int sound, double px, double py, double vx, double vy)
Plays a sound based on position.
int sound_get(const char *name)
Gets the buffer to sound of name.
int space_isSimulation(void)
returns whether we're just simulating.
Represents an asteroid field anchor.
AsteroidTypeGroup ** groups
Represents an asteroid exclusion zone.
Represents a potential reward from the asteroid.
Represents a group of asteroids.
Represents a type of asteroid.
AsteroidReward * material
Represents a single asteroid.
const AsteroidType * type
Core damage that an outfit does.
Represents a small asteroid debris rendered in the player frame.
The representation of an in-game pilot.
Abstraction for rendering sprite sheets.