15#include "SDL_thread.h"
25#include "damagetype.h"
32#include "nlua_pilotoutfit.h"
33#include "nlua_outfit.h"
34#include "nlua_camera.h"
36#include "nlua_munition.h"
41#include "pilot_heat.h"
42#include "pilot_outfit.h"
47#include "threadpool.h"
50#define outfit_setProp(o,p) ((o)->properties |= p)
52#define XML_OUTFIT_TAG "outfit"
54#define OUTFIT_SHORTDESC_MAX STRMAX_SHORT
59typedef struct OutfitThreadData_ {
74#define SDESC_ADD( l, temp, txt, ... ) \
75(l) += scnprintf( &(temp)->summary_raw[l], OUTFIT_SHORTDESC_MAX - (l), (txt), ## __VA_ARGS__ )
85static int outfit_parseThread(
void *ptr );
102typedef struct s_Outfitstat {
106 int colour_threshold;
113static int os_printD(
char *buf,
int len,
double value,
const os_opts *opts );
118static os_opts darmour_opts = { N_(
"Armour Damage"), _UNIT_PERCENT, 1, 100, 0, 0 };
119static os_opts dshield_opts = { N_(
"Shield Damage"), _UNIT_PERCENT, 1, 100, 0, 0 };
120static os_opts dknockback_opts = { N_(
"Knockback"), _UNIT_PERCENT, 0, 0, 1, 0 };
121static os_opts cpu_opts = { N_(
"CPU"), _UNIT_CPU, 1, 0, 1, 0 };
122static os_opts mass_opts = { N_(
"Mass"), _UNIT_MASS, 0, 0, 1, 0 };
123static os_opts penetration_opts = { N_(
"Penetration"), _UNIT_PERCENT, 0, 0, 1, 0 };
124static os_opts damage_opts = {N_(
"Damage"), _UNIT_ENERGY, 0, 1, 1, 1 };
125static os_opts dps_opts = {N_(
"Damage Rate"), _UNIT_POWER, 0, 0, 1, 1 };
126static os_opts disable_opts = {N_(
"Disable"), _UNIT_ENERGY, 0, 1, 1, 1 };
127static os_opts disable_rate_opts = {N_(
"Disable Rate"), _UNIT_POWER, 0, 0, 1, 1 };
128static os_opts fire_rate_opts = {N_(
"Fire Rate"), _UNIT_PER_TIME, 0, 0, 0, 1 };
129static os_opts energy_opts = { N_(
"Energy"), _UNIT_ENERGY, 0, 1, 1, 1 };
130static os_opts power_opts = { N_(
"Power"), _UNIT_POWER, 0, 0, 1, 1 };
131static os_opts range_opts = { N_(
"Range"), _UNIT_DISTANCE, 0, 0, 1, 0 };
132static os_opts speed_opts = { N_(
"Speed"), _UNIT_SPEED, 0, 0, 1, 0 };
133static os_opts heatup_opts = { N_(
"Overheat"), _UNIT_TIME, 0, 0, 1, 1 };
134static os_opts dispersion_opts = { N_(
"Dispersion"), _UNIT_ANGLE, 0, 0, 1, 0 };
135static os_opts swivel_opts = { N_(
"Swivel"), _UNIT_ANGLE, 0, 0, 1, 0 };
136static os_opts tracking_opts = { N_(
"Tracking"), _UNIT_DISTANCE, 0, 0, 1, 0 };
137static os_opts duration_opts = { N_(
"Duration"), _UNIT_TIME, 0, 0, 1, 1 };
138static os_opts cooldown_opts = { N_(
"Cooldown"), _UNIT_TIME, 0, 0, 1, 1 };
139static os_opts lockon_opts = { N_(
"Lock On"), _UNIT_TIME, 0, 0, 1, 0 };
140static os_opts inflight_calib_opts = { N_(
"Inflight Calibration"), _UNIT_TIME, 0, 0, 1, 1 };
141static os_opts initial_speed_opts = { N_(
"Launch Speed"), _UNIT_SPEED, 0, 0, 1, 0 };
142static os_opts accel_opts = { N_(
"Accel"), _UNIT_ACCEL, 0, 0, 1, 0 };
143static os_opts max_speed_opts = { N_(
"Max Speed"), _UNIT_SPEED, 0, 0, 1, 0 };
144static os_opts reload_opts = { N_(
"Reload Time"), _UNIT_TIME, 0, 0, 1, 1 };
145static os_opts armour_opts = { N_(
"Armour"), _UNIT_ENERGY, 0, 0, 1, 1 };
146static os_opts absorp_opts = { N_(
"Absorption"), _UNIT_PERCENT, 0, 0, 1, 1 };
147static os_opts jam_res_opts = { N_(
"Jam Resistance"), _UNIT_PERCENT, 0, 0, 1, 0 };
148static os_opts max_mass_opts = { N_(
"Max Effective Mass"), _UNIT_MASS, 0, 0, 1, 0 };
149static os_opts rumble_opts = { N_(
"Rumble"), NULL, 0, 0, 1, 1 };
150static os_opts shots_delay_opts = { N_(
"Shots Delay"), _UNIT_TIME, 0, 0, 1, 1 };
152static int outfit_cmp(
const void *p1,
const void *p2 )
157 return strcmp( o1->
name, o2->
name );
170 WARN(_(
"Outfit '%s' not found in stack."), name);
182 const Outfit s = {.name = (
char*)name };
215 names = malloc(
sizeof(
char*) * nstack );
219 for (
int i=0; i<nstack; i++) {
220 if (SDL_strcasestr( _(
outfit_stack[i].name), name ) != NULL) {
249 o1 = * (
const Outfit**) outfit1;
250 o2 = * (
const Outfit**) outfit2;
300 return strcmp( o1->
name, o2->
name );
303int outfit_filterWeapon(
const Outfit *o )
306int outfit_filterUtility(
const Outfit *o )
309int outfit_filterStructure(
const Outfit *o )
312int outfit_filterCore(
const Outfit *o )
315int outfit_filterOther(
const Outfit *o )
318 || (o->
slot.
type == OUTFIT_SLOT_NA)));
338 case OUTFIT_SLOT_NULL:
341 return gettext_noop(
"N/A");
342 case OUTFIT_SLOT_INTRINSIC:
343 return gettext_noop(
"Intrinsic");
344 case OUTFIT_SLOT_STRUCTURE:
345 return gettext_noop(
"Structure");
346 case OUTFIT_SLOT_UTILITY:
347 return gettext_noop(
"Utility");
348 case OUTFIT_SLOT_WEAPON:
349 return gettext_noop(
"Weapon");
351 return gettext_noop(
"Unknown");
361 case OUTFIT_SLOT_SIZE_NA:
362 return gettext_noop(
"N/A");
363 case OUTFIT_SLOT_SIZE_LIGHT:
364 return gettext_noop(
"Small");
365 case OUTFIT_SLOT_SIZE_MEDIUM:
366 return gettext_noop(
"Medium");
367 case OUTFIT_SLOT_SIZE_HEAVY:
368 return gettext_noop(
"Large");
370 return gettext_noop(
"Unknown");
393 if (os->
size == OUTFIT_SLOT_SIZE_HEAVY)
394 return &cOutfitHeavy;
395 else if (os->
size == OUTFIT_SLOT_SIZE_MEDIUM)
396 return &cOutfitMedium;
397 else if (os->
size == OUTFIT_SLOT_SIZE_LIGHT)
398 return &cOutfitLight;
410 if (os->
size == OUTFIT_SLOT_SIZE_HEAVY)
412 else if (os->
size == OUTFIT_SLOT_SIZE_MEDIUM)
414 else if (os->
size == OUTFIT_SLOT_SIZE_LIGHT)
427 if (os->
type == OUTFIT_SLOT_WEAPON)
429 else if (os->
type == OUTFIT_SLOT_UTILITY)
431 else if (os->
type == OUTFIT_SLOT_STRUCTURE)
446 size_t p =
scnprintf( &buf[0], size,
"%s", _(outfit->
name) );
447 if (outfit->
slot.
type != OUTFIT_SLOT_NA) {
448 p +=
scnprintf( &buf[p], size-p, _(
"\n#%c%s #%c%s #0slot"),
465 return OUTFIT_SLOT_SIZE_NA;
468 if (strcasecmp(s,
"Large")==0)
469 return OUTFIT_SLOT_SIZE_HEAVY;
470 else if (strcasecmp(s,
"Medium")==0)
471 return OUTFIT_SLOT_SIZE_MEDIUM;
472 else if (strcasecmp(s,
"Small")==0)
473 return OUTFIT_SLOT_SIZE_LIGHT;
475 WARN(_(
"'%s' does not match any outfit slot sizes."), s);
476 return OUTFIT_SLOT_SIZE_NA;
520 return ( (o->
type==OUTFIT_TYPE_BOLT) ||
521 (o->
type==OUTFIT_TYPE_BEAM) ||
522 (o->
type==OUTFIT_TYPE_TURRET_BOLT) ||
523 (o->
type==OUTFIT_TYPE_TURRET_BEAM) ||
524 (o->
type==OUTFIT_TYPE_LAUNCHER) ||
525 (o->
type==OUTFIT_TYPE_TURRET_LAUNCHER) ||
526 (o->
type==OUTFIT_TYPE_FIGHTER_BAY));
536 return ( (o->
type==OUTFIT_TYPE_BOLT) ||
537 (o->
type==OUTFIT_TYPE_BEAM) );
546 return ( (o->
type==OUTFIT_TYPE_BOLT) ||
547 (o->
type==OUTFIT_TYPE_TURRET_BOLT) );
556 return ( (o->
type==OUTFIT_TYPE_BEAM) ||
557 (o->
type==OUTFIT_TYPE_TURRET_BEAM) );
566 return ( (o->
type==OUTFIT_TYPE_LAUNCHER) ||
567 (o->
type==OUTFIT_TYPE_TURRET_LAUNCHER) );
576 if (((o->
type==OUTFIT_TYPE_TURRET_LAUNCHER) ||
577 (o->
type==OUTFIT_TYPE_LAUNCHER)) &&
589 return ((o->
type==OUTFIT_TYPE_TURRET_BOLT) ||
590 (o->
type==OUTFIT_TYPE_TURRET_BEAM) ||
591 (o->
type==OUTFIT_TYPE_TURRET_LAUNCHER));
600 return (o->
type==OUTFIT_TYPE_MODIFICATION);
609 return (o->
type==OUTFIT_TYPE_AFTERBURNER);
618 return (o->
type==OUTFIT_TYPE_FIGHTER_BAY);
627 return (o->
type==OUTFIT_TYPE_MAP);
636 return (o->
type==OUTFIT_TYPE_LOCALMAP);
645 return (o->
type==OUTFIT_TYPE_LICENSE);
654 return (o->
type==OUTFIT_TYPE_GUI);
664 return (o->
properties & OUTFIT_PROP_WEAP_SECONDARY) != 0;
789 return pilot_outfitRange( NULL, o );
811 if (t < o->u.lau.duration)
947 const char* outfit_typename[] = {
954 N_(
"Turret Launcher"),
955 N_(
"Ship Modification"),
967 return outfit_typename[o->
type];
989 else return N_(
"Unknown");
999 const char *ai_type[] = {
1006 WARN(_(
"Outfit '%s' is not a launcher outfit"), o->
name);
1010 return ai_type[o->
u.
lau.
ai];
1052 if ((os->
type == OUTFIT_SLOT_NULL) ||
1053 (os->
type == OUTFIT_SLOT_NA) ||
1054 (os->
type == OUTFIT_SLOT_INTRINSIC))
1097 if ((os->
type == OUTFIT_SLOT_NULL) ||
1098 (os->
type == OUTFIT_SLOT_NA) ||
1099 (os->
type == OUTFIT_SLOT_INTRINSIC))
1121if (strcasecmp(buf,(s))==0) return t
1130 O_CMP(
"bolt", OUTFIT_TYPE_BOLT);
1131 O_CMP(
"beam", OUTFIT_TYPE_BEAM);
1132 O_CMP(
"turret bolt", OUTFIT_TYPE_TURRET_BOLT);
1133 O_CMP(
"turret beam", OUTFIT_TYPE_TURRET_BEAM);
1134 O_CMP(
"launcher", OUTFIT_TYPE_LAUNCHER);
1135 O_CMP(
"turret launcher",OUTFIT_TYPE_TURRET_LAUNCHER);
1136 O_CMP(
"modification", OUTFIT_TYPE_MODIFICATION);
1137 O_CMP(
"afterburner", OUTFIT_TYPE_AFTERBURNER);
1138 O_CMP(
"fighter bay", OUTFIT_TYPE_FIGHTER_BAY);
1139 O_CMP(
"map", OUTFIT_TYPE_MAP);
1140 O_CMP(
"localmap", OUTFIT_TYPE_LOCALMAP);
1141 O_CMP(
"license", OUTFIT_TYPE_LICENSE);
1142 O_CMP(
"gui", OUTFIT_TYPE_GUI);
1144 WARN(_(
"Invalid outfit type: '%s'"),buf);
1145 return OUTFIT_TYPE_NULL;
1157 SDESC_ADD( *l, temp,
"\n#g%s#0", _(
"Can mine uncommon and rare minerals") );
1159 SDESC_ADD( *l, temp,
"\n#g%s#0", _(
"Can mine uncommon minerals") );
1184 cur = node->xmlChildrenNode;
1186 xml_onlyNodes( cur );
1190 xmlr_float( cur,
"physical", dmg->
damage );
1191 xmlr_float( cur,
"disable", dmg->
disable );
1194 if (xml_isNode(cur,
"type")) {
1195 char *buf = xml_get( cur );
1197 if (dmg->
type < 0) {
1199 WARN(_(
"Unknown damage type '%s'"), buf);
1202 else WARN(_(
"Damage has unknown node '%s'"), cur->name);
1204 }
while (xml_nextNode(cur));
1230 WARN(_(
"Trying to load polygon for non-compatible outfit '%s'!"),temp->
name);
1234 SDL_asprintf( &file,
"%s%s.xml", OUTFIT_POLYGON_PATH, buf );
1237 if (!PHYSFS_exists(file)) {
1238 WARN(_(
"%s xml collision polygon does not exist!\n \
1239 Please use the script 'polygon_from_sprite.py' \
1240that can be found in Naev's artwork repo."), file);
1253 node = doc->xmlChildrenNode;
1256 WARN(_(
"Malformed %s file: does not contain elements"), file);
1264 if (xml_isNode(node,
"polygons")) {
1265 xmlNodePtr cur = node->children;
1268 if (xml_isNode(cur,
"polygon")) {
1272 }
while (xml_nextNode(cur));
1274 }
while (xml_nextNode(node));
1294 WARN(_(
"Trying to load graphics for non-compatible outfit '%s'!"),temp->
name);
1299 xmlr_attr_float(node,
"spin", gfx->
spin);
1300 if (gfx->
spin != 0.)
1304 xmlr_attr_strd(node,
"type",type);
1305 if ((type != NULL) && (strcmp(type,
"shader")==0)) {
1308 xmlr_attr_strd(node,
"vertex",vertex);
1310 vertex = strdup(
"project_pos.vert");
1312 gfx->
program = gl_program_vert_frag( vertex, xml_get(node), NULL );
1314 gfx->
vertex = glGetAttribLocation( gfx->
program,
"vertex" );
1317 gfx->
u_r = glGetUniformLocation( gfx->
program,
"u_r" );
1318 gfx->
u_time = glGetUniformLocation( gfx->
program,
"u_time" );
1319 gfx->
u_fade = glGetUniformLocation( gfx->
program,
"u_fade" );
1322 xmlr_attr_float_def(node,
"size",gfx->
size,-1.);
1324 WARN(_(
"Outfit '%s' has GFX shader but no 'size' set!"),temp->
name);
1326 xmlr_attr_float_def(node,
"col_size",gfx->
col_size,gfx->
size*0.8);
1331 else if (type != NULL) {
1332 WARN(_(
"Outfit '%s' has unknown gfx type '%s'!"), temp->
name, type);
1338 char *buf = xml_get(node);
1342 flags = OPENGL_TEX_MIPMAPS;
1344 flags |= OPENGL_TEX_MAPTRANS;
1350 WARN(_(
"Outfit '%s': the number of collision polygons is wrong.\n \
1351 npolygon = %i and sx*sy = %i"),
1369 double dshield, darmour, dknockback;
1382 node = parent->xmlChildrenNode;
1384 xml_onlyNodes(node);
1385 xmlr_float(node,
"speed",temp->
u.
blt.
speed);
1386 xmlr_float(node,
"delay",temp->
u.
blt.
delay);
1387 xmlr_float(node,
"energy",temp->
u.
blt.
energy);
1388 xmlr_float(node,
"heatup",temp->
u.
blt.
heatup);
1391 xmlr_float(node,
"swivel",temp->
u.
blt.
swivel);
1394 xmlr_int(node,
"shots",temp->
u.
blt.
shots);
1396 xmlr_strd(node,
"lua",temp->
lua_file);
1397 if (xml_isNode(node,
"radius")) {
1400 xmlr_attr_strd(node,
"friendlyfire",buf);
1407 if (xml_isNode(node,
"pointdefense")) {
1411 if (xml_isNode(node,
"miss_ships")) {
1415 if (xml_isNode(node,
"miss_asteroids")) {
1419 if (xml_isNode(node,
"miss_explode")) {
1423 if (xml_isNode(node,
"onlyhittarget")) {
1427 if (xml_isNode(node,
"range")) {
1429 xmlr_attr_strd(node,
"blowup",buf);
1431 if (strcmp(buf,
"armour")==0)
1433 else if (strcmp(buf,
"shield")==0)
1436 WARN(_(
"Outfit '%s' has invalid blowup property: '%s'"),
1446 if (xml_isNode(node,
"gfx")) {
1450 if (xml_isNode(node,
"gfx_end")) {
1452 OUTFIT_GFX_PATH
"space/%s", 6, 6, OPENGL_TEX_MIPMAPS );
1457 if (xml_isNode(node,
"spfx_shield")) {
1460 WARN(_(
"Outfit '%s' has unknown spfx_shield '%s'!"),temp->
name,xml_get(node));
1463 if (xml_isNode(node,
"spfx_armour")) {
1466 WARN(_(
"Outfit '%s' has unknown spfx_armour '%s'!"),temp->
name,xml_get(node));
1471 if (xml_isNode(node,
"sound")) {
1475 if (xml_isNode(node,
"sound_hit")) {
1479 if (xml_isNode(node,
"damage")) {
1491 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
1492 }
while (xml_nextNode(node));
1510 temp->
u.
blt.
heat = ((800.-CONST_SPACE_STAR_TEMP)*
C +
1511 STEEL_HEAT_CONDUCTIVITY * ((800.-CONST_SPACE_STAR_TEMP) * area)) /
1517 SDESC_ADD( l, temp, p_(
"outfitstats",
"%s [%s]"), _(
outfit_getType(temp)),
1540 char radius[STRMAX_SHORT];
1541 snprintf(radius,
sizeof(radius), outfit_isProp(temp, OUTFIT_PROP_WEAP_FRIENDLYFIRE) ? p_(
"friendlyfire",
"#r!! %s !!#0") :
"%s", _(
"Hit radius"));
1544 .unit = _UNIT_DISTANCE,
1546 .colour_threshold = 0,
1561#define MELEMENT(o,s) \
1562if (o) WARN(_("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
1567 MELEMENT(temp->
mass==0.,
"mass");
1593 double dshield, darmour, dknockback;
1603 node = parent->xmlChildrenNode;
1605 xml_onlyNodes(node);
1606 xmlr_float(node,
"range",temp->
u.
bem.
range);
1607 xmlr_float(node,
"turn",temp->
u.
bem.
turn);
1608 xmlr_float(node,
"energy",temp->
u.
bem.
energy);
1609 xmlr_float(node,
"delay",temp->
u.
bem.
delay);
1610 xmlr_float(node,
"warmup",temp->
u.
bem.
warmup);
1611 xmlr_float(node,
"heatup",temp->
u.
bem.
heatup);
1612 xmlr_float(node,
"swivel",temp->
u.
bem.
swivel);
1614 xmlr_strd(node,
"lua",temp->
lua_file);
1615 if (xml_isNode(node,
"pointdefense")) {
1619 if (xml_isNode(node,
"miss_ships")) {
1623 if (xml_isNode(node,
"miss_asteroids")) {
1628 if (xml_isNode(node,
"duration")) {
1634 if (xml_isNode(node,
"damage")) {
1640 if (xml_isNode(node,
"shader")) {
1641 xmlr_attr_float(node,
"r", temp->
u.
bem.
colour.r);
1642 xmlr_attr_float(node,
"g", temp->
u.
bem.
colour.g);
1643 xmlr_attr_float(node,
"b", temp->
u.
bem.
colour.b);
1644 xmlr_attr_float(node,
"a", temp->
u.
bem.
colour.a);
1645 xmlr_attr_float(node,
"width", temp->
u.
bem.
width);
1647 shader = xml_get(node);
1648 if (gl_has( OPENGL_SUBROUTINES )) {
1650 temp->
u.
bem.
shader = glGetSubroutineIndex( shaders.beam.program, GL_FRAGMENT_SHADER, shader );
1652 WARN(
"Beam outfit '%s' has unknown shader function '%s'", temp->
name, shader);
1657 if (xml_isNode(node,
"spfx_armour")) {
1661 if (xml_isNode(node,
"spfx_shield")) {
1667 if (xml_isNode(node,
"sound_warmup")) {
1671 if (xml_isNode(node,
"sound")) {
1675 if (xml_isNode(node,
"sound_off")) {
1687 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
1688 }
while (xml_nextNode(node));
1695 temp->
u.
bem.
heat = ((800.-CONST_SPACE_STAR_TEMP)*
C +
1696 STEEL_HEAT_CONDUCTIVITY * ((800.-CONST_SPACE_STAR_TEMP) * area)) /
1726#define MELEMENT(o,s) \
1727if (o) WARN( _("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
1728 MELEMENT(temp->
u.
bem.
width==0.,
"shader width");
1738 MELEMENT((temp->
type!=OUTFIT_TYPE_BEAM) && (temp->
u.
bem.
turn==0),
"turn");
1740 MELEMENT(temp->
cpu==0.,
"cpu");
1756 double dshield, darmour, dknockback;
1770 node = parent->xmlChildrenNode;
1772 xml_onlyNodes(node);
1773 xmlr_float(node,
"delay",temp->
u.
lau.
delay);
1778 xmlr_float(node,
"lockon",temp->
u.
lau.
lockon);
1780 xmlr_float(node,
"swivel",temp->
u.
lau.
swivel);
1783 xmlr_float(node,
"armour",temp->
u.
lau.
armour);
1785 xmlr_int(node,
"shots",temp->
u.
lau.
shots);
1787 xmlr_strd(node,
"lua",temp->
lua_file);
1788 if (xml_isNode(node,
"radius")) {
1791 xmlr_attr_strd(node,
"friendlyfire",buf);
1798 if (xml_isNode(node,
"pointdefense")) {
1802 if (xml_isNode(node,
"miss_ships")) {
1806 if (xml_isNode(node,
"miss_asteroids")) {
1810 if (xml_isNode(node,
"miss_explode")) {
1814 if (xml_isNode(node,
"onlyhittarget")) {
1820 xmlr_float(node,
"arc",temp->
u.
lau.
arc);
1824 if (xml_isNode(node,
"duration")) {
1826 xmlr_attr_strd(node,
"blowup",buf);
1828 if (strcmp(buf,
"armour")==0)
1830 else if (strcmp(buf,
"shield")==0)
1833 WARN(_(
"Outfit '%s' has invalid blowup property: '%s'"),
1840 xmlr_float(node,
"resist",temp->
u.
lau.
resist);
1842 xmlr_float(node,
"accel",temp->
u.
lau.
accel);
1843 xmlr_float(node,
"turn",temp->
u.
lau.
turn);
1844 xmlr_float(node,
"speed",temp->
u.
lau.
speed);
1846 xmlr_float(node,
"energy",temp->
u.
lau.
energy);
1848 if (xml_isNode(node,
"gfx")) {
1852 if (xml_isNode(node,
"spfx_armour")) {
1856 if (xml_isNode(node,
"spfx_shield")) {
1860 if (xml_isNode(node,
"sound")) {
1864 if (xml_isNode(node,
"sound_hit")) {
1868 if (xml_isNode(node,
"damage")) {
1872 if (xml_isNode(node,
"trail_generator")) {
1874 char *buf = xml_get(node);
1880 if (xml_isNode(node,
"ai")) {
1881 char *buf = xml_get(node);
1883 if (strcmp(buf,
"unguided")==0)
1884 temp->
u.
lau.
ai = AMMO_AI_UNGUIDED;
1885 else if (strcmp(buf,
"seek")==0)
1886 temp->
u.
lau.
ai = AMMO_AI_SEEK;
1887 else if (strcmp(buf,
"smart")==0)
1888 temp->
u.
lau.
ai = AMMO_AI_SMART;
1890 WARN(_(
"Ammo '%s' has unknown ai type '%s'."), temp->
name, buf);
1902 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
1903 }
while (xml_nextNode(node));
1906 if (!outfit_isProp(temp,OUTFIT_PROP_TEMPLATE)) {
1908 if (temp->
mass < 0.)
1909 WARN(_(
"Launcher outfit '%s' has negative mass when subtracting ammo mass!"), temp->
name);
1922 WARN(_(
"Max speed of ammo '%s' will be ignored."), temp->
name);
1954 SDESC_ADD( l, temp,
"\n%s", _(
"No Seeking") );
1961 SDESC_ADD( l, temp, _(
"\n Holds %d ammo"), temp->
u.
lau.
amount );
1963 char radius[STRMAX_SHORT];
1964 snprintf(radius,
sizeof(radius), outfit_isProp(temp, OUTFIT_PROP_WEAP_FRIENDLYFIRE) ? p_(
"friendlyfire",
"#r!! %s !!#0") :
"%s", _(
"Hit radius"));
1967 .unit = _UNIT_DISTANCE,
1969 .colour_threshold = 0,
1994#define MELEMENT(o,s) \
1995if (o) WARN(_("Outfit '%s' missing '%s' element"), temp->name, s)
1996 MELEMENT(temp->
u.
lau.
delay==0.,
"delay");
2002 MELEMENT(!outfit_isProp(temp,OUTFIT_PROP_SHOOT_DRY)&&temp->
u.
lau.
spfx_shield==-1,
"spfx_shield");
2003 MELEMENT(!outfit_isProp(temp,OUTFIT_PROP_SHOOT_DRY)&&temp->
u.
lau.
spfx_armour==-1,
"spfx_armour");
2008 MELEMENT(temp->
u.
lau.
turn==0,
"turn");
2014 MELEMENT(!outfit_isProp(temp,OUTFIT_PROP_SHOOT_DRY)&&temp->
u.
lau.
speed_max==0,
"speed_max");
2015 MELEMENT(!outfit_isProp(temp,OUTFIT_PROP_SHOOT_DRY)&&temp->
u.
lau.
duration==0,
"duration");
2019 if (!outfit_isProp(temp,OUTFIT_PROP_SHOOT_DRY)&&temp->
u.
lau.
speed==0. && temp->
u.
lau.
accel==0.)
2020 WARN(_(
"Outfit '%s' has no speed nor accel set!"), temp->
name);
2022 WARN(_(
"Outfit '%s' has longer 'iflockon' than ammo 'duration'"), temp->
name);
2033 xmlNodePtr node = parent->children;
2038 xml_onlyNodes(node);
2039 xmlr_strd(node,
"lua",temp->
lua_file);
2041 if (xml_isNode(node,
"active")) {
2042 xmlr_attr_float(node,
"cooldown", temp->
u.
mod.
cooldown);
2061 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2062 }
while (xml_nextNode(node));
2079 xmlNodePtr node = parent->children;
2093 xml_onlyNodes(node);
2094 xmlr_float(node,
"rumble",temp->
u.
afb.
rumble);
2095 xmlr_strd(node,
"lua",temp->
lua_file);
2096 if (xml_isNode(node,
"sound_on")) {
2100 if (xml_isNode(node,
"sound")) {
2104 if (xml_isNode(node,
"sound_off")) {
2108 xmlr_float(node,
"accel",temp->
u.
afb.
accel);
2109 xmlr_float(node,
"speed",temp->
u.
afb.
speed);
2110 xmlr_float(node,
"energy",temp->
u.
afb.
energy);
2112 xmlr_float(node,
"heatup",temp->
u.
afb.
heatup);
2123 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2124 }
while (xml_nextNode(node));
2130 SDESC_ADD( l, temp,
"\n#o%s#0", _(
"Activated Outfit") );
2135 SDESC_ADD( l, temp,
"\n%s", _(
"Only one can be equipped") );
2146 temp->
u.
afb.
heat = ((800.-CONST_SPACE_STAR_TEMP)*
C +
2147 STEEL_HEAT_CONDUCTIVITY * ((800.-CONST_SPACE_STAR_TEMP) * area)) /
2150#define MELEMENT(o,s) \
2151if (o) WARN(_("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
2152 MELEMENT(temp->
u.
afb.
accel==0.,
"accel");
2153 MELEMENT(temp->
u.
afb.
speed==0.,
"speed");
2170 xmlNodePtr node = parent->children;
2175 xml_onlyNodes(node);
2176 xmlr_float(node,
"delay",temp->
u.
bay.
delay);
2181 xmlr_strd(node,
"lua",temp->
lua_file);
2190 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2191 }
while (xml_nextNode(node));
2195 if (temp->
mass < 0.)
2196 WARN(_(
"Fighter bay outfit '%s' has negative mass when subtracting ship mass!"), temp->
name);
2204 SDESC_ADD( l, temp, _(
"\n Holds %d ships"), temp->
u.
bay.
amount );
2208#define MELEMENT(o,s) \
2209if (o) WARN(_("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
2214 MELEMENT(temp->
cpu==0.,
"cpu");
2230 node = parent->children;
2233 temp->
slot.
size = OUTFIT_SLOT_SIZE_NA;
2240 xml_onlyNodes(node);
2242 if (xml_isNode(node,
"sys")) {
2243 xmlr_attr_strd(node,
"name",buf);
2246 WARN(_(
"Map '%s' has invalid system '%s'"), temp->
name, buf);
2254 xmlNodePtr cur = node->children;
2258 if (xml_isNode(cur,
"spob")) {
2261 if ((buf != NULL) && (spob != NULL))
2264 WARN(_(
"Map '%s' has invalid spob '%s'"), temp->
name, buf);
2266 else if (xml_isNode(cur,
"jump")) {
2269 if ((buf != NULL) && ((jump =
jump_get(xml_get(cur),
2273 WARN(_(
"Map '%s' has invalid jump point '%s'"), temp->
name, buf);
2276 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, cur->name);
2277 }
while (xml_nextNode(cur));
2279 else if (xml_isNode(node,
"short_desc")) {
2283 else if (xml_isNode(node,
"all")) {
2285 for (
int i=0;i<
array_size(system_stack);i++) {
2286 StarSystem *ss = &system_stack[i];
2288 for (
int j=0;j<
array_size(system_stack[i].spobs);j++)
2290 for (
int j=0;j<
array_size(system_stack[i].jumps);j++)
2295 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2296 }
while (xml_nextNode(node));
2309#define MELEMENT(o,s) \
2310if (o) WARN(_("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
2312 MELEMENT(temp->
mass!=0.,
"cpu");
2313 MELEMENT(temp->
cpu!=0.,
"cpu");
2325 xmlNodePtr node = parent->children;
2328 temp->
slot.
size = OUTFIT_SLOT_SIZE_NA;
2331 xml_onlyNodes(node);
2334 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2335 }
while (xml_nextNode(node));
2346#define MELEMENT(o,s) \
2347if (o) WARN(_("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
2349 MELEMENT(temp->
mass!=0.,
"cpu");
2350 MELEMENT(temp->
cpu!=0.,
"cpu");
2362 xmlNodePtr node = parent->children;
2365 temp->
slot.
size = OUTFIT_SLOT_SIZE_NA;
2368 xml_onlyNodes(node);
2369 xmlr_strd(node,
"gui",temp->
u.
gui.
gui);
2370 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2371 }
while (xml_nextNode(node));
2376 _(
"GUI (Graphical User Interface)") );
2378#define MELEMENT(o,s) \
2379if (o) WARN(_("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
2381 MELEMENT(temp->
u.
gui.
gui==NULL,
"gui");
2382 MELEMENT(temp->
mass!=0.,
"cpu");
2383 MELEMENT(temp->
cpu!=0.,
"cpu");
2395 xmlNodePtr node = parent->children;
2398 temp->
slot.
size = OUTFIT_SLOT_SIZE_NA;
2401 xml_onlyNodes(node);
2403 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2404 }
while (xml_nextNode(node));
2415#define MELEMENT(o,s) \
2416if (o) WARN(_("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
2418 MELEMENT(temp->
mass!=0.,
"cpu");
2419 MELEMENT(temp->
cpu!=0.,
"cpu");
2432 xmlNodePtr node, parent;
2441 parent = doc->xmlChildrenNode;
2442 if (parent == NULL) {
2443 ERR( _(
"Malformed '%s' file: does not contain elements"), file);
2448 memset( temp, 0,
sizeof(
Outfit) );
2482 xmlr_attr_strd(parent,
"name",temp->
name);
2483 if (temp->
name == NULL)
2484 WARN(_(
"Outfit '%s' has invalid or no name"), file);
2486 node = parent->xmlChildrenNode;
2491 xml_onlyNodes(node);
2493 if (xml_isNode(node,
"general")) {
2494 xmlNodePtr cur = node->children;
2497 xmlr_int(cur,
"rarity",temp->
rarity);
2498 xmlr_strd(cur,
"shortname",temp->
shortname);
2499 xmlr_strd(cur,
"license",temp->
license);
2500 xmlr_strd(cur,
"cond",temp->
cond);
2501 xmlr_strd(cur,
"condstr",temp->
condstr);
2502 xmlr_float(cur,
"mass",temp->
mass);
2503 xmlr_float(cur,
"cpu",temp->
cpu);
2504 xmlr_long(cur,
"price",temp->
price);
2505 xmlr_strd(cur,
"limit",temp->
limit);
2506 xmlr_strd(cur,
"description",temp->
desc_raw);
2507 xmlr_strd(cur,
"desc_extra",temp->
desc_extra);
2508 xmlr_strd(cur,
"typename",temp->
typename);
2509 xmlr_int(cur,
"priority",temp->
priority);
2512 if (xml_isNode(cur,
"unique")) {
2516 if (xml_isNode(cur,
"shoot_dry")) {
2520 if (xml_isNode(cur,
"template")) {
2524 else if (xml_isNode(cur,
"gfx_store")) {
2526 OUTFIT_GFX_PATH
"store/%s", 1, 1, OPENGL_TEX_MIPMAPS );
2529 else if (xml_isNode(cur,
"gfx_overlays")) {
2530 xmlNodePtr ccur = cur->children;
2533 xml_onlyNodes(ccur);
2534 if (xml_isNode(ccur,
"gfx_overlay"))
2536 xml_parseTexture( ccur, OVERLAY_GFX_PATH
"%s", 1, 1, OPENGL_TEX_MIPMAPS ) );
2537 }
while (xml_nextNode(ccur));
2540 else if (xml_isNode(cur,
"slot")) {
2541 cprop = xml_get(cur);
2543 WARN(_(
"Outfit '%s' has an slot type invalid."), temp->
name);
2544 else if (strcmp(cprop,
"structure") == 0)
2545 temp->
slot.
type = OUTFIT_SLOT_STRUCTURE;
2546 else if (strcmp(cprop,
"utility") == 0)
2547 temp->
slot.
type = OUTFIT_SLOT_UTILITY;
2548 else if (strcmp(cprop,
"weapon") == 0)
2549 temp->
slot.
type = OUTFIT_SLOT_WEAPON;
2550 else if (strcmp(cprop,
"intrinsic") == 0)
2551 temp->
slot.
type = OUTFIT_SLOT_INTRINSIC;
2552 else if (strcmp(cprop,
"none") == 0)
2555 WARN(_(
"Outfit '%s' has unknown slot type '%s'."), temp->
name, cprop);
2558 xmlr_attr_strd( cur,
"prop", prop );
2564 else if (xml_isNode(cur,
"size")) {
2568 else if (xml_isNode(cur,
"illegalto")) {
2569 xmlNodePtr ccur = cur->xmlChildrenNode;
2572 xml_onlyNodes(ccur);
2573 if (xml_isNode(ccur,
"faction")) {
2574 const char *s = xml_get(ccur);
2576 WARN(_(
"Empty faction string for outfit '%s' legality!"), temp->
name);
2580 }
while (xml_nextNode(ccur));
2582 WARN(_(
"Outfit '%s' has no factions defined in <illegalto> block!"), temp->
name);
2585 WARN(_(
"Outfit '%s' has unknown general node '%s'"),temp->
name, cur->name);
2586 }
while (xml_nextNode(cur));
2590 if (xml_isNode(node,
"stats")) {
2591 xmlNodePtr cur = node->children;
2602 WARN(_(
"Outfit '%s' has unknown node '%s'"), temp->
name, cur->name);
2603 }
while (xml_nextNode(cur));
2608 if (xml_isNode(node,
"tags")) {
2609 xmlNodePtr cur = node->children;
2613 if (xml_isNode(cur,
"tag")) {
2614 const char *tmp = xml_get(cur);
2619 WARN(_(
"Outfit '%s' has unknown node in tags '%s'."), temp->
name, cur->name );
2620 }
while (xml_nextNode(cur));
2624 if (xml_isNode(node,
"specific")) {
2626 xmlr_attr_strd(node,
"type", prop);
2628 ERR(_(
"Outfit '%s' element 'specific' missing property 'type'"),temp->
name);
2633 xmlr_attr_strd(node,
"secondary", prop);
2635 if ((
int)atoi(prop))
2641 xmlr_attr_int_def(node,
"group", group, -1);
2643 if (group > PILOT_WEAPON_SETS || group < 1) {
2644 WARN(_(
"Outfit '%s' has group '%d', should be in the 1-%d range"),
2645 temp->
name, group, PILOT_WEAPON_SETS);
2654 if (temp->
type==OUTFIT_TYPE_NULL)
2655 WARN(_(
"Outfit '%s' is of type NONE"), temp->
name);
2669 temp->
u.
map = malloc(
sizeof(OutfitMapData_t) );
2671 temp->
slot.
size = OUTFIT_SLOT_SIZE_NA;
2685 WARN(_(
"Outfit '%s' has unknown node '%s'"),temp->
name, node->name);
2686 }
while (xml_nextNode(node));
2688#define MELEMENT(o,s) \
2689if (o) WARN( _("Outfit '%s' missing/invalid '%s' element"), temp->name, s)
2690 MELEMENT(temp->
name==NULL,
"name");
2691 if (!outfit_isProp(temp,OUTFIT_PROP_TEMPLATE)) {
2692 MELEMENT(temp->
slot.
type==OUTFIT_SLOT_NULL,
"slot");
2693 MELEMENT((temp->
slot.
type!=OUTFIT_SLOT_NA) && (temp->
slot.
type!=OUTFIT_SLOT_INTRINSIC) && (temp->
slot.
size==OUTFIT_SLOT_SIZE_NA),
"size");
2694 MELEMENT(temp->
gfx_store==NULL,
"gfx_store");
2695 MELEMENT(temp->
desc_raw==NULL,
"description");
2698 MELEMENT(temp->
type==0,
"type");
2700 MELEMENT((temp->
cond!=NULL) && (temp->
condstr==NULL),
"condstr");
2701 MELEMENT((temp->
cond==NULL) && (temp->
condstr!=NULL),
"cond");
2709static int outfit_parseThread(
void *ptr )
2712 data->ret =
outfit_parse( &data->outfit, data->filename );
2731 ThreadQueue *tq = vpool_create();
2734 for (
int i=0; i <
array_size( outfit_files ); i++) {
2737 od->filename = outfit_files[i];
2740 free( outfit_files[i] );
2746 vpool_enqueue( tq, outfit_parseThread, &odata[i] );
2761 free( od->filename );
2776 Uint32 time = SDL_GetTicks();
2791 for (
int i=1; i<noutfits; i++)
2793 WARN(_(
"Duplicated outfit name '%s' detected!"),
outfit_stack[i].name);
2797 for (
int i=0; i<noutfits; i++) {
2806 WARN(_(
"Outfit '%s' failed to read Lua '%s'!"), o->
name, o->
lua_file );
2810 env = nlua_newEnv();
2820 if (nlua_dobufenv( env, dat, sz, o->
lua_file ) != 0) {
2821 WARN(_(
"Outfit '%s' Lua error:\n%s"), o->
name, lua_tostring(naevL,-1));
2859 nlua_getenv( naevL, env,
"notactive" );
2861 if (lua_toboolean(naevL,-1)) {
2864 WARN(_(
"Outfit '%s' has 'ontoggle' Lua function defined, but is set as 'notactive'!"),o->
name);
2872 SDESC_ADD( l, o,
"\n#o%s#0", _(
"Activated Outfit") );
2881 for (
int i=0; i<noutfits; i++) {
2888 SDESC_ADD( l, temp,
"\n#o%s#0", _(
"Activated Outfit") );
2905 char **outfit_names = malloc( noutfits *
sizeof(
char*) );
2908 for (
int i=0; i<noutfits; i++)
2911 qsort( outfit_names, noutfits,
sizeof(
char*),
strsort );
2912 for (
int i=0; i<(noutfits - 1); i++) {
2914 while (strcmp(outfit_names[i], outfit_names[i+1]) == 0)
2920 WARN( n_(
"Name collision! %d outfit is named '%s'",
"Name collision! %d outfits are named '%s'",
2922 i + 1 - start, outfit_names[ start ] );
2929 time = SDL_GetTicks() - time;
2930 DEBUG( n_(
"Loaded %d Outfit in %.3f s",
"Loaded %d Outfits in %.3f s", noutfits ), noutfits, time/1000. );
2933 DEBUG( n_(
"Loaded %d Outfit",
"Loaded %d Outfits", noutfits ), noutfits );
2963 SDESC_ADD( l, o,
"\n#r%s#0", _(
"Illegal to:") );
2969 if (o->
lua_env != LUA_NOREF) {
2970 nlua_getenv( naevL, o->
lua_env,
"onload" );
2971 if (lua_isnil(naevL,-1))
2975 if (nlua_pcall( o->
lua_env, 1, 0 )) {
2976 WARN(_(
"Outfit '%s' lua load error -> 'load':\n%s"), o->
name, lua_tostring(naevL,-1));
2984 WARN(_(
"Outfit '%s' has inexistent license requirement '%s'!"), o->
name, o->
license);
2998 xmlNodePtr node, cur;
3008 node = doc->xmlChildrenNode;
3010 WARN( _(
"Malformed '%s' file: does not contain elements"), o->
filename );
3015 cur = node->xmlChildrenNode;
3020 if (xml_isNode(cur,
"specific"))
3023 }
while (xml_nextNode(cur));
3038 snprintf( s,
sizeof(s), OVERLAY_GFX_PATH
"rarity_%d.webp", rarity );
3081 FreePolygon( &gfx->
polygon[j] );
3083 glDeleteProgram(gfx->
program);
3152 char buf[NUM2STRLEN];
3154 if (opts->hide_zero && fabs(value) < 1e-2)
3158 precision = opts->precision;
3160 precision =
MAX( opts->precision, 2 );
3162 i +=
scnprintf(buffer + i, MAXLEN,
"\n");
3165 value > opts->colour_threshold ?
"#g" :
3166 value < opts->colour_threshold ?
"#r" :
"");
3168 num2str( buf, value, precision );
3169 i +=
scnprintf(buffer + i, MAXLEN, p_(
"outfitstats",
"%s: %s %s"), _(opts->name), buf, opts->unit ? _(opts->unit) :
"" );
3171 i +=
scnprintf(buffer + i, MAXLEN,
"#0");
3188 char buf1[NUM2STRLEN], buf2[NUM2STRLEN];
3190 if (opts->hide_zero && fabs(maxValue) < 1e-2)
3193 num2str( buf1, minValue, opts->precision );
3194 num2str( buf2, maxValue, opts->precision );
3196 i +=
scnprintf(buffer + i, MAXLEN,
"\n");
3199 maxValue > opts->colour_threshold ?
"#g" :
3200 maxValue < opts->colour_threshold ?
"#r" :
"");
3201 i +=
scnprintf(buffer + i, MAXLEN, p_(
"outfitstats",
"%s: %s %s - %s %s"), _(opts->name),
3202 buf1, _(opts->unit), buf2, _(opts->unit) );
3204 i +=
scnprintf(buffer + i, MAXLEN,
"#0");
3224 char buf1[NUM2STRLEN], buf2[NUM2STRLEN];
3226 if (val_opts->hide_zero && fabs(val) < 1e-2)
3229 i +=
scnprintf(buffer + i, MAXLEN,
"\n");
3230 if (val_opts->colour)
3232 val > val_opts->colour_threshold ?
"#g" :
3233 val < val_opts->colour_threshold ?
"#r" :
"");
3236 snprintf( mult,
sizeof(mult), p_(
"multiplier",
" x %d"), multiplier );
3240 num2str( buf1, val, val_opts->precision );
3241 num2str( buf2, rate, rate_opts->precision );
3243 i +=
scnprintf(buffer + i, MAXLEN, p_(
"outfitstats",
"%s: %s%s %s [%s %s]"), _(val_opts->name),
3244 buf1, mult, _(val_opts->unit), buf2, _(rate_opts->unit) );
3245 if (val_opts->colour)
3246 i +=
scnprintf(buffer + i, MAXLEN,
"#0");
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#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_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
void LoadPolygon(CollPoly *polygon, xmlNodePtr node)
Loads a polygon from an xml node.
int dtype_raw(int type, double *shield, double *armour, double *knockback)
Gets the raw modulation stats of a damage type.
int dtype_get(const char *name)
Gets the id of a dtype based on name.
const char * dtype_damageTypeToStr(int type)
Gets the human readable string from damage type.
const char * faction_name(int f)
Gets a factions "real" (internal) name.
int faction_get(const char *name)
Gets a faction ID by name.
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
int naev_shouldRenderLoadscreen(void)
Whether or not we want to render the loadscreen.
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
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.
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
int nlua_refenvtype(nlua_env env, const char *name, int type)
Gets the reference of a global in a lua environment if it matches a type.
int nlua_loadCamera(nlua_env env)
Loads the camera library.
int nlua_loadGFX(nlua_env env)
Loads the graphics library.
int nlua_loadMunition(nlua_env env)
Loads the munition library.
const Outfit ** lua_pushoutfit(lua_State *L, const Outfit *outfit)
Pushes a outfit on the stack.
int nlua_loadPilotOutfit(nlua_env env)
Loads the pilot outfit library.
int num2str(char dest[NUM2STRLEN], double n, int decimals)
Converts a numeric value to a string.
int strsort(const void *p1, const void *p2)
Sort function for sorting strings with qsort().
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
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.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
void gl_freeTexture(glTexture *texture)
Frees a texture.
int outfit_isSecondary(const Outfit *o)
Checks if outfit has the secondary flag set.
const char * outfit_description(const Outfit *o)
Gets the description of an outfit.
static int outfit_loadGFX(Outfit *temp, const xmlNodePtr node)
Loads the graphics for an outfit.
static void outfit_parseSMap(Outfit *temp, const xmlNodePtr parent)
Parses the map tidbits of the outfit.
double outfit_speed(const Outfit *o)
Gets the outfit's speed.
static Outfit * outfit_stack
double outfit_trackmin(const Outfit *o)
Gets the outfit's minimal tracking.
static void outfit_parseSLauncher(Outfit *temp, const xmlNodePtr parent)
Parses the specific area for a launcher and loads it into Outfit.
static int outfit_parseDamage(Damage *dmg, xmlNodePtr node)
Parses a damage node.
int outfit_isBeam(const Outfit *o)
Checks if outfit is a beam type weapon.
const char * outfit_summary(const Outfit *o, int withname)
Gets the summary of an outfit.
const Outfit * outfit_getAll(void)
Gets the array (array.h) of all outfits.
double outfit_cpu(const Outfit *o)
Gets the outfit's cpu usage.
static void outfit_parseSAfterburner(Outfit *temp, const xmlNodePtr parent)
Parses the afterburner tidbits of the outfit.
int outfit_isActive(const Outfit *o)
Checks if outfit is an active outfit.
int outfit_soundHit(const Outfit *o)
Gets the outfit's hit sound.
static int outfit_parse(Outfit *temp, const char *file)
Parses and returns Outfit from parent node.
const Outfit * outfit_get(const char *name)
Gets an outfit by name.
int outfit_isLauncher(const Outfit *o)
Checks if outfit is a weapon launcher.
int outfit_isSeeker(const Outfit *o)
Checks if outfit is a seeking weapon.
static OutfitType outfit_strToOutfitType(char *buf)
Gets the outfit type from a human readable string.
OutfitSlotSize outfit_toSlotSize(const char *s)
Gets the outfit slot size from a human readable string.
int outfit_miningRarity(const Outfit *o)
Gets the maximum rarity the outfit can mine up to.
static int outfit_loadDir(const char *dir)
Loads all the files in a directory.
static void outfit_parseSLicense(Outfit *temp, const xmlNodePtr parent)
Parses the license tidbits of the outfit.
int outfit_isLocalMap(const Outfit *o)
Checks if outfit is a local space map.
int outfit_isWeapon(const Outfit *o)
Checks to see if an outfit is a weapon.
static void outfit_parseSFighterBay(Outfit *temp, const xmlNodePtr parent)
Parses the fighter bay tidbits of the outfit.
char outfit_slotTypeColourFont(const OutfitSlot *os)
Gets a font colour character that roughly matches an outfit slot type colour.
int outfit_isToggleable(const Outfit *o)
Checks if outfit can be toggled.
static void outfit_parseSBolt(Outfit *temp, const xmlNodePtr parent)
Parses the specific area for a bolt weapon and loads it into Outfit.
int outfit_compareTech(const void *outfit1, const void *outfit2)
Function meant for use with C89, C99 algorithm qsort().
size_t outfit_getNameWithClass(const Outfit *outfit, char *buf, size_t size)
Gets a brief name/class description suitable for the title section of an outfitter screen.
const Outfit * outfit_getW(const char *name)
Gets an outfit by name without warning on no-find.
const char * outfit_getTypeBroad(const Outfit *o)
Gets the outfit's broad type.
static void outfit_parseSMod(Outfit *temp, const xmlNodePtr parent)
Parses the modification tidbits of the outfit.
int outfit_fitsSlot(const Outfit *o, const OutfitSlot *s)
Checks to see if an outfit fits a slot.
int outfit_checkIllegal(const Outfit *o, int fct)
Checks illegality of an outfit to a faction.
int outfit_isFighterBay(const Outfit *o)
Checks if outfit is a fighter bay.
int outfit_isAfterburner(const Outfit *o)
Checks if outfit is an afterburner.
double outfit_range(const Outfit *o)
Gets the outfit's range.
int outfit_isMap(const Outfit *o)
Checks if outfit is a space map.
double outfit_radius(const Outfit *o)
Gets the outfit's explosion radius.
int outfit_spfxShield(const Outfit *o)
Gets the outfit's sound effect.
int outfit_isTurret(const Outfit *o)
Checks if outfit is a turret class weapon.
double outfit_ammoMass(const Outfit *o)
Gets the outfit's ammunition mass.
int outfit_isForward(const Outfit *o)
Checks if outfit is a fixed mounted weapon.
const CollPoly * outfit_plg(const Outfit *o)
Gets the outfit's collision polygon.
static void sdesc_miningRarity(int *l, Outfit *temp, int rarity)
Adds a small blurb about rarity mining.
int outfit_isLicense(const Outfit *o)
Checks if outfit is a license.
static void outfit_parseSGUI(Outfit *temp, const xmlNodePtr parent)
Parses the GUI tidbits of the outfit.
char outfit_slotSizeColourFont(const OutfitSlot *os)
Gets a font colour character that roughly matches an outfit slot size colour.
const OutfitGFX * outfit_gfx(const Outfit *o)
Gets the outfit's graphic effect.
int outfit_amount(const Outfit *o)
Gets the amount an outfit can hold.
int outfit_load(void)
Loads all the outfits.
const char * slotName(const OutfitSlotType type)
double outfit_spin(const Outfit *o)
Gets the outfit's animation spin.
int outfit_mapParse(void)
Parses all the maps.
const char * outfit_getType(const Outfit *o)
Gets the outfit's specific type.
double outfit_heat(const Outfit *o)
Gets the outfit's heat generation.
double outfit_trackmax(const Outfit *o)
Gets the outfit's minimal tracking.
static void outfit_parseSBeam(Outfit *temp, const xmlNodePtr parent)
Parses the beam weapon specifics of an outfit.
static char ** license_stack
int outfit_isMod(const Outfit *o)
Checks if outfit is a ship modification.
static int os_printD_range(char *buffer, int i, double minValue, double maxValue, const t_os_stat *opts)
Writes an outfit statistic representing a range between two values to a buffer.
int outfit_isGUI(const Outfit *o)
Checks if outfit is a GUI.
int outfit_sound(const Outfit *o)
Gets the outfit's sound.
int outfit_spfxArmour(const Outfit *o)
Gets the outfit's sound effect.
#define OUTFIT_SHORTDESC_MAX
static int outfit_loadPLG(Outfit *temp, const char *buf)
Loads the collision polygon for a bolt outfit.
const char * slotSize(const OutfitSlotSize o)
Gets the slot size as a string.
const Damage * outfit_damage(const Outfit *o)
Gets the outfit's damage.
char ** outfit_searchFuzzyCase(const char *name, int *n)
Does a fuzzy search of all the outfits. Searches translated names but returns internal names.
double outfit_swivel(const Outfit *o)
Gets the swivel of an outfit.
static void outfit_parseSLocalMap(Outfit *temp, const xmlNodePtr parent)
Parses the map tidbits of the outfit.
double outfit_duration(const Outfit *o)
Gets the outfit's duration.
double outfit_cooldown(const Outfit *o)
Gets the outfit's cooldown.
const char * outfit_slotName(const Outfit *o)
Gets the name of the slot type of an outfit.
int outfit_isBolt(const Outfit *o)
Checks if outfit is bolt type weapon.
const char * outfit_slotSize(const Outfit *o)
Gets the name of the slot size of an outfit.
void outfit_free(void)
Frees the outfit stack.
#define outfit_setProp(o, p)
const char * outfit_existsCase(const char *name)
Checks to see if an outfit exists matching name (case insensitive).
double outfit_energy(const Outfit *o)
Gets the outfit's energy usage.
int outfit_licenseExists(const char *name)
Checks to see if a license exists.
void outfit_freeSlot(OutfitSlot *s)
Frees an outfit slot.
static int os_printD(char *buf, int len, double value, const os_opts *opts)
Writes an outfit statistic to a buffer.
const char * outfit_getAmmoAI(const Outfit *o)
Gets a human-readable string describing an ammo outfit's AI.
glTexture * rarity_texture(int rarity)
const glColour * outfit_slotSizeColour(const OutfitSlot *os)
Gets the slot size colour for an outfit slot.
static int os_printD_rate(char *buffer, int i, double val, const t_os_stat *val_opts, int multiplier, double rate, const t_os_stat *rate_opts)
Writes an outfit statistic representing a "per unit" value and rate of change value.
double outfit_delay(const Outfit *o)
Gets the outfit's delay.
int outfit_fitsSlotType(const Outfit *o, const OutfitSlot *s)
Checks to see if an outfit fits a slot type (ignoring size).
int outfit_loadPost(void)
Loads all the outfits legality.
double pilot_heatCalcOutfitC(const Outfit *o)
Calculates the thermal mass of an outfit.
double pilot_heatCalcOutfitArea(const Outfit *o)
Calculates the effective transfer area of an outfit.
const char * pilot_outfitDescription(const Pilot *p, const Outfit *o)
Gets the description of an outfit for a given pilot.
const char * pilot_outfitSummary(const Pilot *p, const Outfit *o, int withname)
Gets the summary of an outfit for a give pilot.
const Ship * ship_get(const char *name)
Gets a ship based on its name.
int ss_statsListDesc(const ShipStatList *ll, char *buf, int len, int newline)
Writes the ship statistics description.
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
int ss_sort(ShipStatList **ll)
Sorts the ship stats, useful if doing saving stuff.
unsigned int sp_get(const char *name)
Gets the id of a slot property.
int sp_required(unsigned int spid)
Gets whether or not a slot property is required.
int sound_get(const char *name)
Gets the buffer to sound of name.
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
StarSystem * system_getAll(void)
Gets an array (array.h) of all star systems.
StarSystem * system_get(const char *sysname)
Get the system from its name.
JumpPoint * jump_get(const char *jumpname, const StarSystem *sys)
Gets a jump point based on its target and system.
const TrailSpec * trailSpec_get(const char *name)
Gets a trail spec by name.
int spfx_get(const char *name)
Gets the id of an spfx based on name.
const char * start_dtype_default(void)
Gets the default damage type.
Represents a polygon used for collision detection.
Core damage that an outfit does.
const struct Ship_ * ship
const TrailSpec * trail_spec
Pilot slot that can contain outfits.
For threaded loading of outfits.
A ship outfit, depends radically on the type.
OutfitModificationData mod
OutfitAfterburnerData afb
glTexture ** gfx_overlays
Represents relative ship statistics as a linked list.
struct ShipStatList_ * next
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Abstraction for rendering sprite sheets.