33#define XML_FACTION_ID "Factions"
34#define XML_FACTION_TAG "faction"
36#define FACTION_STATIC (1<<0)
37#define FACTION_INVISIBLE (1<<1)
38#define FACTION_KNOWN (1<<2)
39#define FACTION_DYNAMIC (1<<3)
40#define FACTION_USESHIDDENJUMPS (1<<4)
42#define faction_setFlag(fa,f) ((fa)->flags |= (f))
43#define faction_rmFlag(fa,f) ((fa)->flags &= ~(f))
44#define faction_isFlag(fa,f) ((fa)->flags & (f))
45#define faction_isKnown_(fa) ((fa)->flags & (FACTION_KNOWN))
54typedef struct Faction_ {
125static int faction_cmp(
const void *p1,
const void *p2 )
145 if (strcmp(name,
"Escort") == 0)
146 return FACTION_PLAYER;
188 WARN(_(
"Faction '%s' not found in stack."), name);
261 WARN(_(
"Faction id '%d' is invalid."),
id);
309 WARN(_(
"Faction id '%d' is invalid."),f);
313 if (f == FACTION_PLAYER)
328 WARN(_(
"Faction id '%d' is invalid."),f);
332 if (f == FACTION_PLAYER)
351 WARN(_(
"Faction id '%d' is invalid."),f);
368 WARN(_(
"Faction id '%d' is invalid."),f);
385 WARN(_(
"Faction id '%d' is invalid."),f);
402 WARN(_(
"Faction id '%d' is invalid."), f);
417 WARN(_(
"Faction id '%d' is invalid."), f);
429 WARN(_(
"Faction id '%d' is invalid."), f);
441 WARN(_(
"Faction id '%d' is invalid."), f);
456 WARN(_(
"Faction id '%d' is invalid."),f);
472 WARN(_(
"Faction id '%d' is invalid."),f);
488 WARN(_(
"Faction id '%d' is invalid."),f);
493 if (f == FACTION_PLAYER) {
518 WARN(_(
"Faction id '%d' is invalid."),f);
523 if (f == FACTION_PLAYER) {
551 WARN(_(
"Faction id '%d' is invalid."), f);
574 WARN(_(
"Faction id '%d' is invalid."), f);
579 WARN(_(
"Faction id '%d' is invalid."), o);
584 if (f==FACTION_PLAYER) {
585 WARN(_(
"%d is the player faction"), f);
588 if (o==FACTION_PLAYER) {
589 WARN(_(
"%d is the player faction"), o);
619 WARN(_(
"Faction id '%d' is invalid."), f);
644 WARN(_(
"Faction id '%d' is invalid."), f);
667 WARN(_(
"Faction id '%d' is invalid."), f);
672 WARN(_(
"Faction id '%d' is invalid."), o);
677 if (f==FACTION_PLAYER) {
678 WARN(_(
"%d is the player faction"), f);
681 if (o==FACTION_PLAYER) {
682 WARN(_(
"%d is the player faction"), o);
712 WARN(_(
"Faction id '%d' is invalid."), f);
731 WARN(_(
"Faction id '%d' is invalid."),f);
743 WARN(_(
"Faction id '%d' is invalid."),f);
783 if (faction->
lua_env == LUA_NOREF)
789 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->
lua_hit );
790 lua_pushnumber( naevL, faction->
player );
791 lua_pushnumber( naevL, mod );
792 lua_pushstring( naevL, source );
793 lua_pushboolean( naevL, secondary );
796 if (nlua_pcall( faction->
lua_env, 4, 1 )) {
797 WARN(_(
"Faction '%s': %s"), faction->
name, lua_tostring(naevL,-1));
803 if (!lua_isnumber( naevL, -1 ))
804 WARN(_(
"Lua script for faction '%s' did not return a %s from '%s'."), faction->
name, _(
"number"),
"hit" );
806 faction->
player = lua_tonumber( naevL, -1 );
814 delta = faction->
player - old;
815 if (
FABS(delta) > 1e-10) {
817 hparam[0].
type = HOOK_PARAM_FACTION;
819 hparam[1].
type = HOOK_PARAM_NUMBER;
820 hparam[1].
u.
num = delta;
821 hparam[2].
type = HOOK_PARAM_SENTINEL;
848 WARN(_(
"Faction id '%d' is invalid."), f);
886 WARN(_(
"Faction id '%d' is invalid."), f);
913 WARN(_(
"Faction id '%d' is invalid."), f);
920 hparam[0].
type = HOOK_PARAM_FACTION;
922 hparam[1].
type = HOOK_PARAM_NUMBER;
923 hparam[1].
u.
num = mod;
924 hparam[2].
type = HOOK_PARAM_SENTINEL;
950 WARN(_(
"Faction id '%d' is invalid."), f);
955 mod = value - faction->
player;
960 hparam[0].
type = HOOK_PARAM_FACTION;
962 hparam[1].
type = HOOK_PARAM_NUMBER;
963 hparam[1].
u.
num = mod;
964 hparam[2].
type = HOOK_PARAM_SENTINEL;
985 WARN(_(
"Faction id '%d' is invalid."), f);
999 WARN(_(
"Faction id '%d' is invalid."), f);
1024 return (faction->
player < 0);
1037 if (f<0)
return &cInert;
1038 else if (
areAllies(FACTION_PLAYER,f))
return &cFriend;
1039 else if (
areEnemies(FACTION_PLAYER,f))
return &cHostile;
1040 else return &cNeutral;
1054 if (f<0)
return 'I';
1055 else if (
areEnemies(FACTION_PLAYER,f))
return 'H';
1056 else if (
areAllies(FACTION_PLAYER,f))
return 'F';
1087 if (f == FACTION_PLAYER)
1092 if (faction->
lua_env == LUA_NOREF)
1098 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->
lua_text_rank );
1099 lua_pushnumber( naevL, value );
1102 if (nlua_pcall( faction->
lua_env, 1, 1 )) {
1104 WARN( _(
"Faction '%s': %s"), faction->
name, lua_tostring( naevL, -1 ) );
1105 lua_pop( naevL, 1 );
1110 if (!lua_isstring( naevL, -1 )) {
1111 WARN(_(
"Lua script for faction '%s' did not return a %s from '%s'."), faction->
name, _(
"string"),
"text_rank" );
1115 r = lua_tostring( naevL, -1 );
1116 lua_pop( naevL, 1 );
1139 if (f == FACTION_PLAYER)
1144 if (faction->
lua_env == LUA_NOREF)
1149 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->
lua_text_broad );
1150 lua_pushnumber( naevL, faction->
player );
1151 lua_pushboolean( naevL, bribed );
1152 lua_pushinteger( naevL,
override );
1155 if (nlua_pcall( faction->
lua_env, 3, 1 )) {
1157 WARN( _(
"Faction '%s': %s"), faction->
name, lua_tostring( naevL, -1 ) );
1158 lua_pop( naevL, 1 );
1163 if (!lua_isstring( naevL, -1 )) {
1164 WARN(_(
"Lua script for faction '%s' did not return a %s from '%s'."), faction->
name, _(
"string"),
"text_broad" );
1168 r = lua_tostring( naevL, -1 );
1169 lua_pop( naevL, 1 );
1189 if (f == FACTION_PLAYER)
1194 if (faction->
lua_env == LUA_NOREF)
1202 if (nlua_pcall( faction->
lua_env, 0, 1 )) {
1204 WARN( _(
"Faction '%s': %s"), faction->
name, lua_tostring( naevL, -1 ) );
1205 lua_pop( naevL, 1 );
1210 if (!lua_isnumber( naevL, -1 )) {
1211 WARN(_(
"Lua script for faction '%s' did not return a %s from '%s'."), faction->
name, _(
"number"),
"reputation_max" );
1215 r = lua_tonumber( naevL, -1 );
1216 lua_pop( naevL, 1 );
1238 if (a==FACTION_PLAYER)
1240 else if (b==FACTION_PLAYER)
1263 if (a==FACTION_PLAYER)
1265 else if (b==FACTION_PLAYER)
1293 xmlNodePtr node, parent;
1300 parent = doc->xmlChildrenNode;
1301 if (parent == NULL) {
1302 ERR( _(
"Malformed '%s' file: does not contain elements"), file);
1307 memset( temp, 0,
sizeof(
Faction) );
1316 xmlr_attr_strd(parent,
"name",temp->
name);
1317 if (temp->
name == NULL)
1318 WARN(_(
"Faction from file '%s' has no name!"), file);
1321 node = parent->xmlChildrenNode;
1324 xml_onlyNodes(node);
1327 if (xml_isNode(node,
"player")) {
1333 xmlr_strd(node,
"longname",temp->
longname);
1335 xmlr_strd(node,
"mapname",temp->
mapname);
1337 xmlr_strd(node,
"ai",temp->
ai);
1340 if (xml_isNode(node,
"colour")) {
1341 const char *ctmp = xml_get(node);
1343 temp->
colour = *col_fromName(xml_raw(node));
1347 xmlr_attr_float(node,
"r",temp->
colour.r);
1348 xmlr_attr_float(node,
"g",temp->
colour.g);
1349 xmlr_attr_float(node,
"b",temp->
colour.b);
1351 col_gammaToLinear( &temp->
colour );
1356 if (xml_isNode(node,
"known")) {
1361 if (xml_isNode(node,
"logo")) {
1363 if (temp->
logo != NULL)
1364 WARN(_(
"Faction '%s' has duplicate 'logo' tag."), temp->
name);
1365 snprintf( buf,
sizeof(buf), FACTION_LOGO_PATH
"%s.webp", xml_get(node) );
1370 if (xml_isNode(node,
"static")) {
1375 if (xml_isNode(node,
"invisible")) {
1380 if (xml_isNode(node,
"useshiddenjumps")) {
1385 if (xml_isNode(node,
"tags")) {
1386 xmlNodePtr cur = node->children;
1387 if (temp->
tags != NULL)
1388 WARN(_(
"Faction '%s' has duplicate '%s' node!"), temp->
name,
"tags");
1393 if (xml_isNode(cur,
"tag")) {
1394 const char *tmp = xml_get(cur);
1399 WARN(_(
"Faction '%s' has unknown node in tags '%s'."), temp->
name, cur->name );
1400 }
while (xml_nextNode(cur));
1406 if (xml_isNode(node,
"allies") || xml_isNode(node,
"enemies") ||
1407 xml_isNode(node,
"generator") || xml_isNode(node,
"standing") ||
1408 xml_isNode(node,
"spawn") || xml_isNode(node,
"equip"))
1410 WARN(_(
"Unknown node '%s' in faction '%s'"),node->name,temp->
name);
1413 }
while (xml_nextNode(node));
1416 WARN(_(
"Faction '%s' missing 'player' tag."), temp->
name);
1418 WARN(_(
"Faction '%s' is known but missing 'description' tag."), temp->
name);
1436 snprintf( buf,
sizeof(buf), FACTIONS_PATH
"standing/%s.lua", scriptname );
1437 temp->
lua_env = nlua_newEnv();
1441 if (nlua_dobufenv(temp->
lua_env, dat, ndat, buf) != 0) {
1442 WARN(_(
"Failed to run standing script: %s\n"
1444 "Most likely Lua file has improper syntax, please check"),
1445 buf, lua_tostring(naevL,-1));
1446 nlua_freeEnv( temp->
lua_env );
1457 nlua_getenv( naevL, temp->
lua_env,
"friendly_at" );
1459 lua_pop( naevL, 1 );
1472 xmlNodePtr node, parent;
1479 parent = doc->xmlChildrenNode;
1480 if (parent == NULL) {
1481 ERR( _(
"Malformed '%s' file: does not contain elements"), file);
1487 xmlr_attr_strd(parent,
"name", name);
1493 assert( base != NULL );
1500 node = parent->xmlChildrenNode;
1502 if (xml_isNode(node,
"generator")) {
1507 xmlr_attr_float(node,
"weight",fg->
weight);
1513 if (xml_isNode(node,
"standing")) {
1514 if (base->
lua_env != LUA_NOREF)
1515 WARN(_(
"Faction '%s' has duplicate 'standing' tag."), base->
name);
1521 if (xml_isNode(node,
"spawn")) {
1523 WARN(_(
"Faction '%s' has duplicate 'spawn' tag."), base->
name);
1524 snprintf( buf,
sizeof(buf), FACTIONS_PATH
"spawn/%s.lua", xml_raw(node) );
1528 if (nlua_dobufenv(base->
sched_env, dat, ndat, buf) != 0) {
1529 WARN(_(
"Failed to run spawn script: %s\n"
1531 "Most likely Lua file has improper syntax, please check"),
1532 buf, lua_tostring(naevL,-1));
1541 if (xml_isNode(node,
"equip")) {
1543 WARN(_(
"Faction '%s' has duplicate 'equip' tag."), base->
name);
1544 snprintf( buf,
sizeof(buf), FACTIONS_PATH
"equip/%s.lua", xml_raw(node) );
1548 if (nlua_dobufenv(base->
equip_env, dat, ndat, buf) != 0) {
1549 WARN(_(
"Failed to run equip script: %s\n"
1551 "Most likely Lua file has improper syntax, please check"),
1552 buf, lua_tostring(naevL, -1));
1561 if (xml_isNode(node,
"allies")) {
1562 xmlNodePtr cur = node->xmlChildrenNode;
1565 if (xml_isNode(cur,
"ally")) {
1569 }
while (xml_nextNode(cur));
1574 if (xml_isNode(node,
"enemies")) {
1575 xmlNodePtr cur = node->xmlChildrenNode;
1578 if (xml_isNode(cur,
"enemy")) {
1582 }
while (xml_nextNode(cur));
1585 }
while (xml_nextNode(node));
1588 WARN(_(
"Faction '%s' has no Lua and isn't static!"), base->
name);
1613 Uint32 time = SDL_GetTicks();
1621 memset( f, 0,
sizeof(
Faction) );
1622 f->name = strdup(
"Player");
1624 f->equip_env = LUA_NOREF;
1625 f->sched_env = LUA_NOREF;
1626 f->lua_env = LUA_NOREF;
1627 f->lua_hit = LUA_NOREF;
1628 f->lua_text_rank = LUA_NOREF;
1629 f->lua_text_broad = LUA_NOREF;
1630 f->lua_reputation_max = LUA_NOREF;
1635 for (
int i=0; i<
array_size(faction_files); i++) {
1654 for (
int i=0; i<
array_size(faction_files); i++) {
1665 for (
int j=0; j <
array_size(f->allies); j++) {
1669 if (sf->
allies[k] == i) {
1680 for (
int j=0; j <
array_size(f->enemies); j++) {
1695 for (
int i=0; i<
array_size(faction_files); i++)
1696 free( faction_files[i] );
1703 time = SDL_GetTicks() - time;
1720 free(f->displayname);
1722 free(f->description);
1728 nlua_freeEnv( f->sched_env );
1729 nlua_freeEnv( f->lua_env );
1731 nlua_freeEnv( f->equip_env );
1762 xmlw_startElem(writer,
"factions");
1769 xmlw_startElem(writer,
"faction");
1775 xmlw_elemEmpty(writer,
"known");
1777 xmlw_endElem(writer);
1780 xmlw_endElem(writer);
1793 xmlNodePtr node = parent->xmlChildrenNode;
1796 if (xml_isNode(node,
"factions")) {
1797 xmlNodePtr cur = node->xmlChildrenNode;
1799 if (xml_isNode(cur,
"faction")) {
1802 xmlr_attr_strd(cur,
"name", str);
1805 if (faction != -1) {
1806 xmlNodePtr sub = cur->xmlChildrenNode;
1808 if (xml_isNode(sub,
"standing")) {
1815 if (xml_isNode(sub,
"known")) {
1819 }
while (xml_nextNode(sub));
1823 }
while (xml_nextNode(cur));
1825 }
while (xml_nextNode(node));
1915int faction_dynAdd(
int base,
const char* name,
const char* display,
const char* ai,
const glColour* colour )
1918 memset( f, 0,
sizeof(
Faction) );
1919 f->name = strdup( name );
1920 f->displayname = (display==NULL) ? NULL : strdup( display );
1921 f->ai = (ai==NULL) ? NULL : strdup( ai );
1924 f->equip_env = LUA_NOREF;
1925 f->lua_env = LUA_NOREF;
1926 f->sched_env = LUA_NOREF;
1932 if (bf->
ai!=NULL && f->ai==NULL)
1933 f->
ai = strdup( bf->
ai );
1956 f->colour = *colour;
1983 WARN(
"Incoherent faction grid! '%s' and '%s' are already enemies, but trying to set to allies!",
faction_stack[i].name,
faction_stack[j].name );
1992 WARN(
"Incoherent faction grid! '%s' and '%s' are already allies, but trying to set to enemies!",
faction_stack[i].name,
faction_stack[j].name );
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
#define array_copy(basic_type, ptr_array)
Returns a shallow copy of the input array.
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
#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_grow(ptr_array)
Increases the number of elements by one and returns the last element.
#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’.
const char * faction_getStandingBroad(int f, int bribed, int override)
Gets the broad faction standing.
const char * faction_longname(int f)
Gets the faction's long name (formal, human-readable).
static void faction_freeOne(Faction *f)
Frees a single faction.
const glColour * faction_getColour(int f)
Gets the colour of the faction based on it's standing with the player.
int faction_isPlayerEnemy(int f)
Gets whether or not the player is an enemy of the faction.
int faction_exists(const char *name)
Checks to see if a faction exists by name.
const char * faction_default_ai(int f)
Gets the name of the default AI profile for the faction's pilots.
const int * faction_getEnemies(int f)
Gets the list of enemies of a faction.
int faction_dynAdd(int base, const char *name, const char *display, const char *ai, const glColour *colour)
Dynamically add a faction.
static int faction_getRaw(const char *name)
Gets a faction ID by name.
void faction_rmAlly(int f, int o)
Removes an ally from the faction's allies list.
int faction_isKnown(int id)
Is the faction known?
char faction_getColourChar(int f)
Gets the faction character associated to its standing with the player.
static void faction_modPlayerLua(int f, double mod, const char *source, int secondary)
Mods player using the power of Lua.
#define FACTION_INVISIBLE
int faction_isFaction(int f)
Checks whether or not a faction is valid.
static size_t faction_mgrid
static Faction * faction_stack
const glTexture * faction_logo(int f)
Gets the faction's logo (ideally 256x256).
nlua_env faction_getEquipper(int f)
Gets the equipper state associated to the faction scheduler.
int factions_load(void)
Loads up all the factions from the data file.
void faction_clearEnemy(int f)
Clears all the enemies of a dynamic faction.
void factions_reset(void)
Resets player standing and flags of factions to default.
void faction_rmEnemy(int f, int o)
Removes an enemy from the faction's enemies list.
int faction_isPlayerFriend(int f)
Gets whether or not the player is a friend of the faction.
void faction_setPlayer(int f, double value)
Sets the player's standing with a faction.
int areEnemies(int a, int b)
Checks whether two factions are enemies.
void factions_clearDynamic(void)
Clears dynamic factions.
int * faction_getGroup(int which)
Returns an array of faction ids.
const char * faction_name(int f)
Gets a factions "real" (internal) name.
const char * faction_shortname(int f)
Gets a factions short name (human-readable).
const char * faction_getStandingText(int f)
Gets the player's standing in human readable form.
double faction_getPlayer(int f)
Gets the player's standing with a faction.
int faction_isDynamic(int id)
Is faction dynamic.
void factions_free(void)
Frees the factions.
const int * faction_getAllies(int f)
Gets the list of allies of a faction.
void faction_modPlayerRaw(int f, double mod)
Modifies the player's standing without affecting others.
const FactionGenerator * faction_generators(int f)
Gets the faction's generators.
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
int * faction_getKnown()
Gets all the known factions in an array (array.h).
int faction_isInvisible(int id)
Is the faction invisible?
int pfaction_save(xmlTextWriterPtr writer)
Saves player's standings with the factions.
const glColour * faction_colour(int f)
Gets the colour of the faction.
static void faction_sanitizePlayer(Faction *faction)
Sanitizes player faction standing.
const char * faction_getStandingTextAtValue(int f, double value)
Gets the player's standing in human readable form.
void faction_clearAlly(int f)
Clears all the ally of a dynamic faction.
int pfaction_load(xmlNodePtr parent)
Loads the player's faction standings.
double faction_lane_base_cost(int f)
Gets the faction's weight for patrolled safe-lane construction;.
void faction_modPlayer(int f, double mod, const char *source)
Modifies the player's standing with a faction.
const char ** faction_tags(int f)
Gets the tags the faction has.
static int * faction_grid
static int faction_parseSocial(const char *file)
Parses the social tidbits of a faction: allies and enemies.
#define FACTION_USESHIDDENJUMPS
double faction_getPlayerDef(int f)
Gets the player's default standing with a faction.
int * faction_getAll(void)
Returns all faction IDs in an array (array.h).
void faction_modPlayerSingle(int f, double mod, const char *source)
Modifies the player's standing without affecting others.
static void faction_addStandingScript(Faction *temp, const char *scriptname)
Sets up a standing script for a faction.
static int faction_parse(Faction *temp, const char *file)
Parses a single faction, but doesn't set the allies/enemies bit.
int faction_setInvisible(int id, int state)
Sets the faction's invisible state.
int faction_setKnown(int id, int state)
Sets the factions known state.
double faction_lane_length_per_presence(int f)
Gets the faction's weight for patrolled safe-lane construction (0 means they don't build lanes).
int * faction_getAllVisible(void)
Returns all non-invisible faction IDs in an array (array.h).
const char * faction_mapname(int f)
Gets the faction's map name (translated).
double faction_reputationMax(int f)
Gets the maximum reputation of a faction.
void faction_addAlly(int f, int o)
Adds an ally to the faction's allies list.
nlua_env faction_getScheduler(int f)
Gets the state associated to the faction scheduler.
static void faction_computeGrid(void)
Computes the faction relationship grid.
const char * faction_description(int f)
Gets the faction's description (translated).
void faction_clearKnown()
Clears the known factions.
int faction_isStatic(int id)
Is the faction static?
void faction_addEnemy(int f, int o)
Adds an enemy to the faction's enemies list.
int faction_get(const char *name)
Gets a faction ID by name.
int areAllies(int a, int b)
Checks whether two factions are allies or not.
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
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.
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
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 space_factionChange(void)
Mark when a faction changes.
Description of a lane-building faction.
FactionGenerator * generators
double lane_length_per_presence
The actual hook parameter.
Abstraction for rendering sprite sheets.