naev 0.10.4
faction.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <assert.h>
11#include <stdlib.h>
12
13#include "naev.h"
16#include "faction.h"
17
18#include "conf.h"
19#include "array.h"
20#include "colour.h"
21#include "hook.h"
22#include "log.h"
23#include "ndata.h"
24#include "nlua.h"
25#include "nluadef.h"
26#include "nxml.h"
27#include "nstring.h"
28#include "player.h"
29#include "opengl.h"
30#include "rng.h"
31#include "space.h"
32
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))
46
54typedef struct Faction_ {
55 char *name;
56 char *longname;
58 char *mapname;
59 char *ai;
62 /* Graphics. */
64 glColour colour;
66 /* Enemies */
67 int *enemies;
69 /* Allies */
70 int *allies;
72 /* Player information. */
73 double player_def;
74 double player;
76 /* Scheduler. */
77 nlua_env sched_env;
79 /* Behaviour. */
80 nlua_env env;
81 double friendly_at;
83 int lua_hit;
88 /* Safe lanes. */
92 /* Presence stuff. */
95 /* Equipping. */
96 nlua_env equip_env;
98 /* Flags. */
99 unsigned int flags;
100 unsigned int oflags;
102 /* Tags. */
103 char **tags;
104} Faction;
105
106static Faction* faction_stack = NULL;
107static int* faction_grid = NULL;
108static size_t faction_mgrid = 0;
110/*
111 * Prototypes
112 */
113/* static */
114static int faction_getRaw( const char *name );
115static void faction_freeOne( Faction *f );
116static void faction_sanitizePlayer( Faction* faction );
117static void faction_modPlayerLua( int f, double mod, const char *source, int secondary );
118static int faction_parse( Faction* temp, const char *file );
119static int faction_parseSocial( const char *file );
120static void faction_addStandingScript( Faction* temp, const char* scriptname );
121static void faction_computeGrid (void);
122/* externed */
123int pfaction_save( xmlTextWriterPtr writer );
124int pfaction_load( xmlNodePtr parent );
125
126static int faction_cmp( const void *p1, const void *p2 )
127{
128 const Faction *f1, *f2;
129 f1 = (const Faction*) p1;
130 f2 = (const Faction*) p2;
131 return strcmp(f1->name,f2->name);
132}
133
140static int faction_getRaw( const char* name )
141{
142 /* Escorts are part of the "player" faction. */
143 if (strcmp(name, "Escort") == 0)
144 return FACTION_PLAYER;
145
146 if (name != NULL) {
147 int i;
148 for (i=0; i<array_size(faction_stack); i++)
149 if (strcmp(faction_stack[i].name, name)==0)
150 break;
151
152 if (i != array_size(faction_stack))
153 return i;
154
155 /* Dynamic factions are why we can't have nice things.
156 const Faction f = { .name = (char*)name };
157 Faction *found = bsearch( &f, faction_stack, array_size(faction_stack), sizeof(Faction), faction_cmp );
158 if (found != NULL)
159 return found - faction_stack;
160 */
161 }
162 return -1;
163}
164
171int faction_exists( const char* name )
172{
173 return faction_getRaw(name)!=-1;
174}
175
182int faction_get( const char* name )
183{
184 int id = faction_getRaw(name);
185 if (id<0)
186 WARN(_("Faction '%s' not found in stack."), name);
187 return id;
188}
189
193int* faction_getAll (void)
194{
196 for (int i=0; i<array_size(faction_stack); i++)
197 array_push_back( &f, i );
198
199 return f;
200}
201
206{
208 for (int i=0; i<array_size(faction_stack); i++)
209 if (!faction_isFlag( &faction_stack[i], FACTION_INVISIBLE ))
210 array_push_back( &f, i );
211 return f;
212}
213
218{
220 /* Get IDs. */
221 for (int i=0; i<array_size(faction_stack); i++)
222 if (!faction_isFlag( &faction_stack[i], FACTION_INVISIBLE ) && faction_isKnown_( &faction_stack[i] ))
223 array_push_back( &f, i );
224 return f;
225}
226
231{
232 for (int i=0; i<array_size(faction_stack); i++)
233 if (faction_isKnown_( &faction_stack[i] ))
234 faction_rmFlag( &faction_stack[i], FACTION_KNOWN );
235}
236
240int faction_isStatic( int id )
241{
242 return faction_isFlag( &faction_stack[id], FACTION_STATIC );
243}
244
249{
250 return faction_isFlag( &faction_stack[id], FACTION_INVISIBLE );
251}
252
256int faction_setInvisible( int id, int state )
257{
258 if (!faction_isFaction(id)) {
259 WARN(_("Faction id '%d' is invalid."),id);
260 return -1;
261 }
262 if (state)
263 faction_setFlag( &faction_stack[id], FACTION_INVISIBLE );
264 else
265 faction_rmFlag( &faction_stack[id], FACTION_INVISIBLE );
266
267 return 0;
268}
269
273int faction_isKnown( int id )
274{
275 return faction_isKnown_( &faction_stack[id] );
276}
277
281int faction_isDynamic( int id )
282{
283 return faction_isFlag( &faction_stack[id], FACTION_DYNAMIC );
284}
285
289int faction_setKnown( int id, int state )
290{
291 if (state)
292 faction_setFlag( &faction_stack[id], FACTION_KNOWN );
293 else
294 faction_rmFlag( &faction_stack[id], FACTION_KNOWN );
295 return 0;
296}
297
304const char* faction_name( int f )
305{
306 if (!faction_isFaction(f)) {
307 WARN(_("Faction id '%d' is invalid."),f);
308 return NULL;
309 }
310 /* Don't want player to see their escorts as "Player" faction. */
311 if (f == FACTION_PLAYER)
312 return "Escort";
313
314 return faction_stack[f].name;
315}
316
323const char* faction_shortname( int f )
324{
325 if (!faction_isFaction(f)) {
326 WARN(_("Faction id '%d' is invalid."),f);
327 return NULL;
328 }
329 /* Don't want player to see their escorts as "Player" faction. */
330 if (f == FACTION_PLAYER)
331 return _("Escort");
332
333 /* Possibly get display name. */
334 if (faction_stack[f].displayname != NULL)
335 return _(faction_stack[f].displayname);
336
337 return _(faction_stack[f].name);
338}
339
346const char* faction_longname( int f )
347{
348 if (!faction_isFaction(f)) {
349 WARN(_("Faction id '%d' is invalid."),f);
350 return NULL;
351 }
352 if (faction_stack[f].longname != NULL)
353 return _(faction_stack[f].longname);
354 return _(faction_stack[f].name);
355}
356
363const char* faction_mapname( int f )
364{
365 if (!faction_isFaction(f)) {
366 WARN(_("Faction id '%d' is invalid."),f);
367 return NULL;
368 }
369 if (faction_stack[f].mapname != NULL)
370 return _(faction_stack[f].mapname);
371 return _(faction_stack[f].name);
372}
373
380const char* faction_description( int f )
381{
382 if (!faction_isFaction(f)) {
383 WARN(_("Faction id '%d' is invalid."),f);
384 return NULL;
385 }
386 if (faction_stack[f].description != NULL)
387 return _(faction_stack[f].description);
388 return NULL;
389}
390
397const char* faction_default_ai( int f )
398{
399 if (!faction_isFaction(f)) {
400 WARN(_("Faction id '%d' is invalid."), f);
401 return NULL;
402 }
403 return faction_stack[f].ai;
404}
405
412const char** faction_tags( int f )
413{
414 if (!faction_isFaction(f)) {
415 WARN(_("Faction id '%d' is invalid."), f);
416 return NULL;
417 }
418 return (const char**) faction_stack[f].tags;
419}
420
425{
426 if (!faction_isFaction(f)) {
427 WARN(_("Faction id '%d' is invalid."), f);
428 return 0.;
429 }
431}
432
437{
438 if (!faction_isFaction(f)) {
439 WARN(_("Faction id '%d' is invalid."), f);
440 return 0.;
441 }
443}
444
451const glTexture* faction_logo( int f )
452{
453 if (!faction_isFaction(f)) {
454 WARN(_("Faction id '%d' is invalid."),f);
455 return NULL;
456 }
457
458 return faction_stack[f].logo;
459}
460
467const glColour* faction_colour( int f )
468{
469 if (!faction_isFaction(f)) {
470 WARN(_("Faction id '%d' is invalid."),f);
471 return NULL;
472 }
473
474 return &faction_stack[f].colour;
475}
476
483const int* faction_getEnemies( int f )
484{
485 if (!faction_isFaction(f)) {
486 WARN(_("Faction id '%d' is invalid."),f);
487 return NULL;
488 }
489
490 /* Player's faction ratings can change, so regenerate each call. */
491 if (f == FACTION_PLAYER) {
492 int *enemies = array_create( int );
493
494 for (int i=0; i<array_size(faction_stack); i++)
495 if (faction_isPlayerEnemy(i)) {
496 int *tmp = &array_grow( &enemies );
497 *tmp = i;
498 }
499
500 array_free( faction_stack[f].enemies );
501 faction_stack[f].enemies = enemies;
502 }
503
504 return faction_stack[f].enemies;
505}
506
513const int* faction_getAllies( int f )
514{
515 if (!faction_isFaction(f)) {
516 WARN(_("Faction id '%d' is invalid."),f);
517 return NULL;
518 }
519
520 /* Player's faction ratings can change, so regenerate each call. */
521 if (f == FACTION_PLAYER) {
522 int *allies = array_create( int );
523
524 for (int i=0; i<array_size(faction_stack); i++)
525 if (faction_isPlayerFriend(i)) {
526 int *tmp = &array_grow( &allies );
527 *tmp = i;
528 }
529
530 array_free( faction_stack[ f ].allies );
531 faction_stack[f].allies = allies;
532 }
533
534 return faction_stack[f].allies;
535}
536
543{
544 Faction *ff;
545 /* Get faction. */
546 if (faction_isFaction(f))
547 ff = &faction_stack[f];
548 else { /* f is invalid */
549 WARN(_("Faction id '%d' is invalid."), f);
550 return;
551 }
554}
555
562void faction_addEnemy( int f, int o )
563{
564 Faction *ff;
565 int *tmp;
566
567 if (f==o) return;
568
569 if (faction_isFaction(f))
570 ff = &faction_stack[f];
571 else { /* f is invalid */
572 WARN(_("Faction id '%d' is invalid."), f);
573 return;
574 }
575
576 if (!faction_isFaction(o)) { /* o is invalid */
577 WARN(_("Faction id '%d' is invalid."), o);
578 return;
579 }
580
581 /* player cannot be made an enemy this way */
582 if (f==FACTION_PLAYER) {
583 WARN(_("%d is the player faction"), f);
584 return;
585 }
586 if (o==FACTION_PLAYER) {
587 WARN(_("%d is the player faction"), o);
588 return;
589 }
590
591 for (int i=0;i<array_size(ff->enemies);i++) {
592 if (ff->enemies[i] == o)
593 return;
594 }
595
596 tmp = &array_grow( &ff->enemies );
597 *tmp = o;
598
600}
601
608void faction_rmEnemy( int f, int o )
609{
610 Faction *ff;
611
612 if (f==o) return;
613
614 if (faction_isFaction(f))
615 ff = &faction_stack[f];
616 else { /* f is invalid */
617 WARN(_("Faction id '%d' is invalid."), f);
618 return;
619 }
620
621 for (int i=0;i<array_size(ff->enemies);i++) {
622 if (ff->enemies[i] == o) {
623 array_erase( &ff->enemies, &ff->enemies[i], &ff->enemies[i+1] );
625 return;
626 }
627 }
628}
629
635void faction_clearAlly( int f )
636{
637 Faction *ff;
638 /* Get faction. */
639 if (faction_isFaction(f))
640 ff = &faction_stack[f];
641 else { /* f is invalid */
642 WARN(_("Faction id '%d' is invalid."), f);
643 return;
644 }
647}
648
655void faction_addAlly( int f, int o )
656{
657 Faction *ff;
658 int *tmp;
659
660 if (f==o) return;
661
662 if (faction_isFaction(f))
663 ff = &faction_stack[f];
664 else { /* f is invalid */
665 WARN(_("Faction id '%d' is invalid."), f);
666 return;
667 }
668
669 if (!faction_isFaction(o)) { /* o is invalid */
670 WARN(_("Faction id '%d' is invalid."), o);
671 return;
672 }
673
674 /* player cannot be made an ally this way */
675 if (f==FACTION_PLAYER) {
676 WARN(_("%d is the player faction"), f);
677 return;
678 }
679 if (o==FACTION_PLAYER) {
680 WARN(_("%d is the player faction"), o);
681 return;
682 }
683
684 for (int i=0;i<array_size(ff->allies);i++) {
685 if (ff->allies[i] == o)
686 return;
687 }
688
689 tmp = &array_grow( &ff->allies );
690 *tmp = o;
691
693}
694
701void faction_rmAlly( int f, int o )
702{
703 Faction *ff;
704
705 if (f==o) return;
706
707 if (faction_isFaction(f))
708 ff = &faction_stack[f];
709 else { /* f is invalid */
710 WARN(_("Faction id '%d' is invalid."), f);
711 return;
712 }
713
714 for (int i=0;i<array_size(ff->allies);i++) {
715 if (ff->allies[i] == o) {
716 array_erase( &ff->allies, &ff->allies[i], &ff->allies[i+1] );
718 return;
719 }
720 }
721}
722
726nlua_env faction_getScheduler( int f )
727{
728 if (!faction_isFaction(f)) {
729 WARN(_("Faction id '%d' is invalid."),f);
730 return LUA_NOREF;
731 }
732 return faction_stack[f].sched_env;
733}
734
738nlua_env faction_getEquipper( int f )
739{
740 if (!faction_isFaction(f)) {
741 WARN(_("Faction id '%d' is invalid."),f);
742 return LUA_NOREF;
743 }
744 return faction_stack[f].equip_env;
745}
746
752static void faction_sanitizePlayer( Faction* faction )
753{
754 faction->player = CLAMP( -100., 100., faction->player );
755}
756
760static void faction_modPlayerLua( int f, double mod, const char *source, int secondary )
761{
762 Faction *faction;
763 double old, delta;
764
765 faction = &faction_stack[f];
766
767 /* Make sure it's not static. */
768 if (faction_isFlag(faction, FACTION_STATIC))
769 return;
770
771 /* Player is dead or cleared. */
772 if (player.p == NULL)
773 return;
774
775 old = faction->player;
776
777 if (faction->env == LUA_NOREF)
778 faction->player += mod;
779 else {
780
781 /* Set up the function:
782 * standing:hit( current, amount, source, secondary ) */
783 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_hit );
784 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_standing );
785 lua_pushnumber( naevL, faction->player );
786 lua_pushnumber( naevL, mod );
787 lua_pushstring( naevL, source );
788 lua_pushboolean( naevL, secondary );
789
790 /* Call function. */
791 if (nlua_pcall( faction->env, 5, 1 )) { /* An error occurred. */
792 WARN(_("Faction '%s': %s"), faction->name, lua_tostring(naevL,-1));
793 lua_pop( naevL, 1 );
794 return;
795 }
796
797 /* Parse return. */
798 if (!lua_isnumber( naevL, -1 ))
799 WARN( _("Lua script for faction '%s' did not return a number from 'standing:hit(...)'."), faction->name );
800 else
801 faction->player = lua_tonumber( naevL, -1 );
802 lua_pop( naevL, 1 );
803 }
804
805 /* Sanitize just in case. */
806 faction_sanitizePlayer( faction );
807
808 /* Run hook if necessary. */
809 delta = faction->player - old;
810 if (FABS(delta) > 1e-10) {
811 HookParam hparam[3];
812 hparam[0].type = HOOK_PARAM_FACTION;
813 hparam[0].u.lf = f;
814 hparam[1].type = HOOK_PARAM_NUMBER;
815 hparam[1].u.num = delta;
816 hparam[2].type = HOOK_PARAM_SENTINEL;
817 hooks_runParam( "standing", hparam );
818
819 /* Tell space the faction changed. */
821 }
822}
823
839void faction_modPlayer( int f, double mod, const char *source )
840{
841 Faction *faction;
842
843 if (!faction_isFaction(f)) {
844 WARN(_("Faction id '%d' is invalid."), f);
845 return;
846 }
847 faction = &faction_stack[f];
848
849 /* Modify faction standing with parent faction. */
850 faction_modPlayerLua( f, mod, source, 0 );
851
852 /* Now mod allies to a lesser degree */
853 for (int i=0; i<array_size(faction->allies); i++)
854 /* Modify faction standing */
855 faction_modPlayerLua( faction->allies[i], mod, source, 1 );
856
857 /* Now mod enemies */
858 for (int i=0; i<array_size(faction->enemies); i++)
859 /* Modify faction standing. */
860 faction_modPlayerLua( faction->enemies[i], -mod, source, 1 );
861}
862
879void faction_modPlayerSingle( int f, double mod, const char *source )
880{
881 if (!faction_isFaction(f)) {
882 WARN(_("Faction id '%d' is invalid."), f);
883 return;
884 }
885
886 faction_modPlayerLua( f, mod, source, 0 );
887}
888
899void faction_modPlayerRaw( int f, double mod )
900{
901 Faction *faction;
902 HookParam hparam[3];
903
904 if (!faction_isFaction(f)) {
905 WARN(_("Faction id '%d' is invalid."), f);
906 return;
907 }
908
909 faction = &faction_stack[f];
910 faction->player += mod;
911 /* Run hook if necessary. */
912 hparam[0].type = HOOK_PARAM_FACTION;
913 hparam[0].u.lf = f;
914 hparam[1].type = HOOK_PARAM_NUMBER;
915 hparam[1].u.num = mod;
916 hparam[2].type = HOOK_PARAM_SENTINEL;
917 hooks_runParam( "standing", hparam );
918
919 /* Sanitize just in case. */
920 faction_sanitizePlayer( faction );
921
922 /* Tell space the faction changed. */
924}
925
932void faction_setPlayer( int f, double value )
933{
934 Faction *faction;
935 HookParam hparam[3];
936 double mod;
937
938 if (!faction_isFaction(f)) {
939 WARN(_("Faction id '%d' is invalid."), f);
940 return;
941 }
942
943 faction = &faction_stack[f];
944 mod = value - faction->player;
945 faction->player = value;
946 /* Run hook if necessary. */
947 if (!faction_isFlag(faction, FACTION_DYNAMIC)) {
948 hparam[0].type = HOOK_PARAM_FACTION;
949 hparam[0].u.lf = f;
950 hparam[1].type = HOOK_PARAM_NUMBER;
951 hparam[1].u.num = mod;
952 hparam[2].type = HOOK_PARAM_SENTINEL;
953 hooks_runParam( "standing", hparam );
954
955 /* Sanitize just in case. */
956 faction_sanitizePlayer( faction );
957
958 /* Tell space the faction changed. */
960 }
961}
962
969double faction_getPlayer( int f )
970{
971 if (faction_isFaction(f))
972 return faction_stack[f].player;
973 WARN(_("Faction id '%d' is invalid."), f);
974 return -1000.;
975}
976
983double faction_getPlayerDef( int f )
984{
985 if (faction_isFaction(f))
986 return faction_stack[f].player_def;
987 WARN(_("Faction id '%d' is invalid."), f);
988 return -1000.;
989}
990
998{
999 Faction *faction = &faction_stack[f];
1000 return faction->player >= faction->friendly_at;
1001}
1002
1010{
1011 Faction *faction = &faction_stack[f];
1012 return faction->player < 0;
1013}
1014
1023const glColour* faction_getColour( int f )
1024{
1025 if (f<0) return &cInert;
1026 else if (areAllies(FACTION_PLAYER,f)) return &cFriend;
1027 else if (areEnemies(FACTION_PLAYER,f)) return &cHostile;
1028 else return &cNeutral;
1029}
1030
1041{
1042 if (f<0) return 'I';
1043 else if (areEnemies(FACTION_PLAYER,f)) return 'H';
1044 else if (areAllies(FACTION_PLAYER,f)) return 'F';
1045 else return 'N';
1046}
1047
1054const char *faction_getStandingText( int f )
1055{
1056 Faction *faction;
1057
1058 /* Escorts always have the same standing. */
1059 if (f == FACTION_PLAYER)
1060 return _("Escort");
1061
1062 faction = &faction_stack[f];
1063
1064 if (faction->env == LUA_NOREF)
1065 return _("???");
1066 else {
1067 const char *r;
1068 /* Set up the method:
1069 * standing:text_rank( standing ) */
1070 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_text_rank );
1071 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_standing );
1072 lua_pushnumber( naevL, faction->player );
1073
1074 /* Call function. */
1075 if (nlua_pcall( faction->env, 2, 1 )) {
1076 /* An error occurred. */
1077 WARN( _("Faction '%s': %s"), faction->name, lua_tostring( naevL, -1 ) );
1078 lua_pop( naevL, 1 );
1079 return _("???");
1080 }
1081
1082 /* Parse return. */
1083 if (!lua_isstring( naevL, -1 )) {
1084 WARN( _("Lua script for faction '%s' did not return a string from 'standing:text_rank(...)'."), faction->name );
1085 r = _("???");
1086 }
1087 else
1088 r = lua_tostring( naevL, -1 ); /* Should be translated already. */
1089 lua_pop( naevL, 1 );
1090
1091 return r;
1092 }
1093}
1094
1103const char *faction_getStandingBroad( int f, int bribed, int override )
1104{
1105 Faction *faction;
1106 const char *r;
1107
1108 /* Escorts always have the same standing. */
1109 if (f == FACTION_PLAYER)
1110 return _("Escort");
1111
1112 faction = &faction_stack[f];
1113
1114 if (faction->env == LUA_NOREF)
1115 return _("???");
1116
1117 /* Set up the method:
1118 * standing:text_broad( standing, bribed, override ) */
1119 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_text_broad );
1120 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_standing );
1121 lua_pushnumber( naevL, faction->player );
1122 lua_pushboolean( naevL, bribed );
1123 lua_pushnumber( naevL, override );
1124
1125 /* Call function. */
1126 if (nlua_pcall( faction->env, 4, 1 )) {
1127 /* An error occurred. */
1128 WARN( _("Faction '%s': %s"), faction->name, lua_tostring( naevL, -1 ) );
1129 lua_pop( naevL, 1 );
1130 return "???";
1131 }
1132
1133 /* Parse return. */
1134 if (!lua_isstring( naevL, -1 )) {
1135 WARN( _("Lua script for faction '%s' did not return a string from 'standing:text_broad(...)'."), faction->name );
1136 r = "???";
1137 }
1138 else
1139 r = lua_tostring( naevL, -1 );
1140 lua_pop( naevL, 1 );
1141
1142 return r;
1143}
1144
1152{
1153 Faction *faction;
1154 double r;
1155
1156 /* Escorts always have the same standing. */
1157 if (f == FACTION_PLAYER)
1158 return 100.;
1159
1160 faction = &faction_stack[f];
1161
1162 if (faction->env == LUA_NOREF)
1163 return 0.;
1164
1165 /* Set up the method:
1166 * standing:reputation_max( standing ) */
1167 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_reputation_max );
1168 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_standing );
1169
1170 /* Call function. */
1171 if (nlua_pcall( faction->env, 1, 1 )) {
1172 /* An error occurred. */
1173 WARN( _("Faction '%s': %s"), faction->name, lua_tostring( naevL, -1 ) );
1174 lua_pop( naevL, 1 );
1175 return 0.;
1176 }
1177
1178 /* Parse return. */
1179 if (!lua_isnumber( naevL, -1 )) {
1180 WARN( _("Lua script for faction '%s' did not return a string from 'standing:reputation_max(...)'."), faction->name );
1181 r = 0.;
1182 }
1183 else
1184 r = lua_tonumber( naevL, -1 );
1185 lua_pop( naevL, 1 );
1186
1187 return r;
1188}
1189
1197int areEnemies( int a, int b )
1198{
1199 /* luckily our factions aren't masochistic */
1200 if (a==b) return 0;
1201
1202 /* Make sure they're valid. */
1203 if (!faction_isFaction(a) || !faction_isFaction(b))
1204 return 0;
1205
1206 /* player handled separately */
1207 if (a==FACTION_PLAYER)
1208 return faction_isPlayerEnemy(b);
1209 else if (b==FACTION_PLAYER)
1210 return faction_isPlayerEnemy(a);
1211
1212 return faction_grid[ a * faction_mgrid + b ] < 0;
1213}
1214
1222int areAllies( int a, int b )
1223{
1224 /* If they are the same they must be allies. */
1225 if (a==b) return 1;
1226
1227 /* Make sure they're valid. */
1228 if (!faction_isFaction(a) || !faction_isFaction(b))
1229 return 0;
1230
1231 /* we assume player becomes allies with high rating */
1232 if (a==FACTION_PLAYER)
1233 return faction_isPlayerFriend(b);
1234 else if (b==FACTION_PLAYER)
1235 return faction_isPlayerFriend(a);
1236
1237 return faction_grid[ a * faction_mgrid + b ] > 0;
1238}
1239
1247{
1248 if ((f<0) || (f>=array_size(faction_stack)))
1249 return 0;
1250 return 1;
1251}
1252
1260static int faction_parse( Faction* temp, const char *file )
1261{
1262 xmlNodePtr node, parent;
1263 int saw_player;
1264
1265 xmlDocPtr doc = xml_parsePhysFS( file );
1266 if (doc == NULL)
1267 return -1;
1268
1269 parent = doc->xmlChildrenNode; /* first faction node */
1270 if (parent == NULL) {
1271 ERR( _("Malformed '%s' file: does not contain elements"), file);
1272 return -1;
1273 }
1274
1275 /* Clear memory. */
1276 memset( temp, 0, sizeof(Faction) );
1277 temp->equip_env = LUA_NOREF;
1278 temp->env = LUA_NOREF;
1279 temp->sched_env = LUA_NOREF;
1280
1281 xmlr_attr_strd(parent,"name",temp->name);
1282 if (temp->name == NULL)
1283 WARN(_("Faction from file '%s' has no name!"), file);
1284
1285 saw_player = 0;
1286 node = parent->xmlChildrenNode;
1287 do {
1288 /* Only care about nodes. */
1289 xml_onlyNodes(node);
1290
1291 /* Can be 0 or negative, so we have to take that into account. */
1292 if (xml_isNode(node,"player")) {
1293 temp->player_def = xml_getFloat(node);
1294 saw_player = 1;
1295 continue;
1296 }
1297
1298 xmlr_strd(node,"longname",temp->longname);
1299 xmlr_strd(node,"display",temp->displayname);
1300 xmlr_strd(node,"mapname",temp->mapname);
1301 xmlr_strd(node,"description",temp->description);
1302 xmlr_strd(node,"ai",temp->ai);
1303 xmlr_float(node,"lane_length_per_presence",temp->lane_length_per_presence);
1304 xmlr_float(node,"lane_base_cost",temp->lane_base_cost);
1305 if (xml_isNode(node, "colour")) {
1306 char *ctmp = xml_get(node);
1307 if (ctmp != NULL)
1308 temp->colour = *col_fromName(xml_raw(node));
1309 /* If no named colour is present, RGB attributes are used. */
1310 else {
1311 /* Initialize in case a colour channel is absent. */
1312 xmlr_attr_float(node,"r",temp->colour.r);
1313 xmlr_attr_float(node,"g",temp->colour.g);
1314 xmlr_attr_float(node,"b",temp->colour.b);
1315 temp->colour.a = 1.;
1316 col_gammaToLinear( &temp->colour );
1317 }
1318 continue;
1319 }
1320
1321 if (xml_isNode(node, "known")) {
1322 faction_setFlag(temp, FACTION_KNOWN);
1323 continue;
1324 }
1325
1326 if (xml_isNode(node,"logo")) {
1327 char buf[PATH_MAX];
1328 if (temp->logo != NULL)
1329 WARN(_("Faction '%s' has duplicate 'logo' tag."), temp->name);
1330 snprintf( buf, sizeof(buf), FACTION_LOGO_PATH"%s.webp", xml_get(node) );
1331 temp->logo = gl_newImage(buf, 0);
1332 continue;
1333 }
1334
1335 if (xml_isNode(node,"static")) {
1336 faction_setFlag(temp, FACTION_STATIC);
1337 continue;
1338 }
1339
1340 if (xml_isNode(node,"invisible")) {
1341 faction_setFlag(temp, FACTION_INVISIBLE);
1342 continue;
1343 }
1344
1345 if (xml_isNode(node,"useshiddenjumps")) {
1346 faction_setFlag(temp, FACTION_USESHIDDENJUMPS);
1347 continue;
1348 }
1349
1350 if (xml_isNode(node, "tags")) {
1351 xmlNodePtr cur = node->children;
1352 if (temp->tags != NULL)
1353 WARN(_("Faction '%s' has duplicate '%s' node!"), temp->name, "tags");
1354 else
1355 temp->tags = array_create( char* );
1356 do {
1357 xml_onlyNodes(cur);
1358 if (xml_isNode(cur, "tag")) {
1359 char *tmp = xml_get(cur);
1360 if (tmp != NULL)
1361 array_push_back( &temp->tags, strdup(tmp) );
1362 continue;
1363 }
1364 WARN(_("Faction '%s' has unknown node in tags '%s'."), temp->name, cur->name );
1365 } while (xml_nextNode(cur));
1366 continue;
1367 }
1368
1369#if DEBUGGING
1370 /* Avoid warnings. */
1371 if (xml_isNode(node,"allies") || xml_isNode(node,"enemies") ||
1372 xml_isNode(node,"generator") || xml_isNode(node,"standing") ||
1373 xml_isNode(node,"spawn") || xml_isNode(node,"equip"))
1374 continue;
1375 WARN(_("Unknown node '%s' in faction '%s'"),node->name,temp->name);
1376#endif /* DEBUGGING */
1377
1378 } while (xml_nextNode(node));
1379
1380 if (!saw_player)
1381 WARN(_("Faction '%s' missing 'player' tag."), temp->name);
1382 if (faction_isKnown_(temp) && !faction_isFlag(temp, FACTION_INVISIBLE) && temp->description==NULL)
1383 WARN(_("Faction '%s' is known but missing 'description' tag."), temp->name);
1384
1385 xmlFreeDoc(doc);
1386
1387 return 0;
1388}
1389
1396static void faction_addStandingScript( Faction* temp, const char* scriptname )
1397{
1398 char buf[PATH_MAX], *dat;
1399 size_t ndat;
1400
1401 snprintf( buf, sizeof(buf), FACTIONS_PATH"standing/%s.lua", scriptname );
1402 temp->env = nlua_newEnv();
1403
1404 nlua_loadStandard( temp->env );
1405 dat = ndata_read( buf, &ndat );
1406 if (nlua_dobufenv(temp->env, dat, ndat, buf) != 0) {
1407 WARN(_("Failed to run standing script: %s\n"
1408 "%s\n"
1409 "Most likely Lua file has improper syntax, please check"),
1410 buf, lua_tostring(naevL,-1));
1411 nlua_freeEnv( temp->env );
1412 temp->env = LUA_NOREF;
1413 }
1414 free(dat);
1415
1416 /* Set up the references. */
1417 temp->lua_standing = nlua_refenvtype( temp->env, "standing", LUA_TTABLE );
1418 temp->lua_hit = nlua_reffield( temp->lua_standing, "hit" );
1419 temp->lua_text_broad = nlua_reffield( temp->lua_standing, "text_broad" );
1420 temp->lua_text_rank = nlua_reffield( temp->lua_standing, "text_rank" );
1421 temp->lua_reputation_max= nlua_reffield( temp->lua_standing, "reputation_max" );
1422
1423 if (temp->lua_standing != LUA_NOREF) {
1424 lua_rawgeti( naevL, LUA_REGISTRYINDEX, temp->lua_standing );
1425 lua_getfield( naevL, -1, "friendly_at" );
1426 temp->friendly_at = lua_tonumber( naevL, -1 );
1427 lua_pop( naevL, 2 );
1428 }
1429 else {
1430 WARN(_("Standing script did not set the \"standing\" variable: %s"), buf);
1431 temp->friendly_at = 0.;
1432 }
1433}
1434
1441static int faction_parseSocial( const char *file )
1442{
1443 char buf[PATH_MAX], *name, *dat;
1444 size_t ndat;
1445 xmlNodePtr node, parent;
1446 Faction *base;
1447
1448 xmlDocPtr doc = xml_parsePhysFS( file );
1449 if (doc == NULL)
1450 return -1;
1451
1452 parent = doc->xmlChildrenNode; /* first faction node */
1453 if (parent == NULL) {
1454 ERR( _("Malformed '%s' file: does not contain elements"), file);
1455 return -1;
1456 }
1457
1458 /* Get name. */
1459 base = NULL;
1460 xmlr_attr_strd(parent, "name", name);
1461 if (name != NULL)
1462 base = &faction_stack[ faction_get( name ) ];
1463 free( name );
1464 name = NULL;
1465
1466 assert( base != NULL );
1467
1468 /* Create arrays, not much memory so it doesn't really matter. */
1469 base->allies = array_create( int );
1470 base->enemies = array_create( int );
1471
1472 /* Parse social stuff. */
1473 node = parent->xmlChildrenNode;
1474 do {
1475 if (xml_isNode(node, "generator")) {
1476 FactionGenerator *fg;
1477 if (base->generators==NULL)
1479 fg = &array_grow( &base->generators );
1480 xmlr_attr_float(node,"weight",fg->weight);
1481 fg->id = faction_get( xml_get(node) );
1482 continue;
1483 }
1484
1485 /* Standing scripts. */
1486 if (xml_isNode(node, "standing")) {
1487 if (base->env != LUA_NOREF)
1488 WARN(_("Faction '%s' has duplicate 'standing' tag."), base->name);
1489 faction_addStandingScript( base, xml_raw(node) );
1490 continue;
1491 }
1492
1493 /* Spawning scripts. */
1494 if (xml_isNode(node, "spawn")) {
1495 if (base->sched_env != LUA_NOREF)
1496 WARN(_("Faction '%s' has duplicate 'spawn' tag."), base->name);
1497 snprintf( buf, sizeof(buf), FACTIONS_PATH"spawn/%s.lua", xml_raw(node) );
1498 base->sched_env = nlua_newEnv();
1500 dat = ndata_read( buf, &ndat );
1501 if (nlua_dobufenv(base->sched_env, dat, ndat, buf) != 0) {
1502 WARN(_("Failed to run spawn script: %s\n"
1503 "%s\n"
1504 "Most likely Lua file has improper syntax, please check"),
1505 buf, lua_tostring(naevL,-1));
1506 nlua_freeEnv( base->sched_env );
1507 base->sched_env = LUA_NOREF;
1508 }
1509 free(dat);
1510 continue;
1511 }
1512
1513 /* Equipment scripts. */
1514 if (xml_isNode(node, "equip")) {
1515 if (base->equip_env != LUA_NOREF)
1516 WARN(_("Faction '%s' has duplicate 'equip' tag."), base->name);
1517 snprintf( buf, sizeof(buf), FACTIONS_PATH"equip/%s.lua", xml_raw(node) );
1518 base->equip_env = nlua_newEnv();
1520 dat = ndata_read( buf, &ndat );
1521 if (nlua_dobufenv(base->equip_env, dat, ndat, buf) != 0) {
1522 WARN(_("Failed to run equip script: %s\n"
1523 "%s\n"
1524 "Most likely Lua file has improper syntax, please check"),
1525 buf, lua_tostring(naevL, -1));
1526 nlua_freeEnv( base->equip_env );
1527 base->equip_env = LUA_NOREF;
1528 }
1529 free(dat);
1530 continue;
1531 }
1532
1533 /* Grab the allies */
1534 if (xml_isNode(node,"allies")) {
1535 xmlNodePtr cur = node->xmlChildrenNode;
1536 do {
1537 xml_onlyNodes(cur);
1538 if (xml_isNode(cur,"ally")) {
1539 int *tmp = &array_grow( &base->allies );
1540 *tmp = faction_get(xml_get(cur));
1541 }
1542 } while (xml_nextNode(cur));
1543 continue;
1544 }
1545
1546 /* Grab the enemies */
1547 if (xml_isNode(node,"enemies")) {
1548 xmlNodePtr cur = node->xmlChildrenNode;
1549 do {
1550 xml_onlyNodes(cur);
1551 if (xml_isNode(cur,"enemy")) {
1552 int *tmp = &array_grow( &base->enemies );
1553 *tmp = faction_get(xml_get(cur));
1554 }
1555 } while (xml_nextNode(cur));
1556 continue;
1557 }
1558 } while (xml_nextNode(node));
1559
1560 if ((base->env==LUA_NOREF) && !faction_isFlag( base, FACTION_STATIC ))
1561 WARN(_("Faction '%s' has no Lua and isn't static!"), base->name);
1562
1563 xmlFreeDoc(doc);
1564 return 0;
1565}
1566
1571{
1572 for (int i=0; i<array_size(faction_stack); i++) {
1575 }
1576}
1577
1584{
1585 Faction *f;
1586 Uint32 time = SDL_GetTicks();
1587 char **faction_files = ndata_listRecursive( FACTION_DATA_PATH );
1588
1589 /* player faction is hard-coded */
1591 f = &array_grow( &faction_stack );
1592 memset( f, 0, sizeof(Faction) );
1593 f->name = strdup("Player");
1594 f->flags = FACTION_STATIC | FACTION_INVISIBLE;
1595 f->equip_env = LUA_NOREF;
1596 f->env = LUA_NOREF;
1597 f->sched_env = LUA_NOREF;
1598 f->allies = array_create( int );
1599 f->enemies = array_create( int );
1600
1601 /* Add the base factions. */
1602 for (int i=0; i<array_size(faction_files); i++) {
1603 if (ndata_matchExt( faction_files[i], "xml" )) {
1604 Faction nf;
1605 int ret = faction_parse( &nf, faction_files[i] );
1606 if (ret == 0) {
1607 nf.oflags = nf.flags;
1609 }
1610
1611 /* Render if necessary. */
1613 }
1614 }
1615
1616 /* Sort by name. */
1617 qsort( faction_stack, array_size(faction_stack), sizeof(Faction), faction_cmp );
1618 faction_player = faction_get("Player");
1619
1620 /* Second pass - sets allies and enemies */
1621 for (int i=0; i<array_size(faction_files); i++) {
1622 if (ndata_matchExt( faction_files[i], "xml" )) {
1623 faction_parseSocial( faction_files[i] );
1624 }
1625 }
1626
1627 /* Third pass, Make allies/enemies symmetric. */
1628 for (int i=0; i<array_size(faction_stack); i++) {
1629 f = &faction_stack[i];
1630
1631 /* First run over allies and make sure it's mutual. */
1632 for (int j=0; j < array_size(f->allies); j++) {
1633 Faction *sf = &faction_stack[ f->allies[j] ];
1634 int r = 0;
1635 for (int k=0; k < array_size(sf->allies); k++)
1636 if (sf->allies[k] == i) {
1637 r = 1;
1638 break;
1639 }
1640
1641 /* Add ally if necessary. */
1642 if (r == 0)
1643 faction_addAlly( f->allies[j], i );
1644 }
1645
1646 /* Now run over enemies. */
1647 for (int j=0; j < array_size(f->enemies); j++) {
1648 Faction *sf = &faction_stack[ f->enemies[j] ];
1649 int r = 0;
1650 for (int k=0; k < array_size(sf->enemies); k++)
1651 if (sf->enemies[k] == i) {
1652 r = 1;
1653 break;
1654 }
1655
1656 if (r == 0)
1657 faction_addEnemy( f->enemies[j], i );
1658 }
1659 }
1660
1661 /* Clean up stuff. */
1662 for (int i=0; i<array_size(faction_files); i++)
1663 free( faction_files[i] );
1664 array_free( faction_files );
1665
1666 /* Compute grid and finalize. */
1668 if (conf.devmode) {
1669 time = SDL_GetTicks() - time;
1670 DEBUG( n_( "Loaded %d Faction in %.3f s", "Loaded %d Factions in %.3f s", array_size(faction_stack) ), array_size(faction_stack), time/1000. );
1671 }
1672 else
1673 DEBUG( n_( "Loaded %d Faction", "Loaded %d Factions", array_size(faction_stack) ), array_size(faction_stack) );
1674
1675 return 0;
1676}
1677
1681static void faction_freeOne( Faction *f )
1682{
1683 free(f->name);
1684 free(f->longname);
1685 free(f->displayname);
1686 free(f->mapname);
1687 free(f->description);
1688 free(f->ai);
1689 array_free(f->generators);
1690 gl_freeTexture(f->logo);
1691 array_free(f->allies);
1692 array_free(f->enemies);
1693 nlua_freeEnv( f->sched_env );
1694 nlua_freeEnv( f->env );
1695 if (!faction_isFlag(f, FACTION_DYNAMIC))
1696 nlua_freeEnv( f->equip_env );
1697 for (int i=0; i<array_size(f->tags); i++)
1698 free(f->tags[i]);
1699 array_free(f->tags);
1700}
1701
1705void factions_free (void)
1706{
1707 /* Free factions. */
1708 for (int i=0; i<array_size(faction_stack); i++)
1711 faction_stack = NULL;
1712
1713 /* Clean up faction grid. */
1714 free( faction_grid );
1715 faction_grid = NULL;
1716 faction_mgrid = 0;
1717}
1718
1725int pfaction_save( xmlTextWriterPtr writer )
1726{
1727 xmlw_startElem(writer,"factions");
1728
1729 for (int i=0; i<array_size(faction_stack); i++) { /* player is faction 0 */
1730 /* Must not be static. */
1731 if (faction_isFlag( &faction_stack[i], FACTION_STATIC ))
1732 continue;
1733
1734 xmlw_startElem(writer,"faction");
1735
1736 xmlw_attr(writer,"name","%s",faction_stack[i].name);
1737 xmlw_elem(writer,"standing","%f",faction_stack[i].player);
1738
1739 if (faction_isKnown_(&faction_stack[i]))
1740 xmlw_elemEmpty(writer, "known");
1741
1742 xmlw_endElem(writer); /* "faction" */
1743 }
1744
1745 xmlw_endElem(writer); /* "factions" */
1746
1747 return 0;
1748}
1749
1756int pfaction_load( xmlNodePtr parent )
1757{
1758 xmlNodePtr node = parent->xmlChildrenNode;
1759
1760 do {
1761 if (xml_isNode(node,"factions")) {
1762 xmlNodePtr cur = node->xmlChildrenNode;
1763 do {
1764 if (xml_isNode(cur,"faction")) {
1765 int faction;
1766 char *str;
1767 xmlr_attr_strd(cur, "name", str);
1768 faction = faction_get(str);
1769
1770 if (faction != -1) { /* Faction is valid. */
1771 xmlNodePtr sub = cur->xmlChildrenNode;
1772 do {
1773 if (xml_isNode(sub,"standing")) {
1774
1775 /* Must not be static. */
1776 if (!faction_isFlag( &faction_stack[faction], FACTION_STATIC ))
1777 faction_stack[faction].player = xml_getFloat(sub);
1778 continue;
1779 }
1780 if (xml_isNode(sub,"known")) {
1781 faction_setFlag(&faction_stack[faction], FACTION_KNOWN);
1782 continue;
1783 }
1784 } while (xml_nextNode(sub));
1785 }
1786 free(str);
1787 }
1788 } while (xml_nextNode(cur));
1789 }
1790 } while (xml_nextNode(node));
1791
1792 return 0;
1793}
1794
1801int *faction_getGroup( int which )
1802{
1803 int *group;
1804
1805 switch (which) {
1806 case 0: /* 'all' */
1807 return array_copy( int, faction_stack );
1808
1809 case 1: /* 'friendly' */
1810 group = array_create( int );
1811 for (int i=0; i < array_size(faction_stack); i++)
1812 if (areAllies( FACTION_PLAYER, i ))
1813 array_push_back( &group, i );
1814 return group;
1815
1816 case 2: /* 'neutral' */
1817 group = array_create( int );
1818 for (int i=0; i < array_size(faction_stack); i++)
1819 if (!areAllies( FACTION_PLAYER, i ) && !areEnemies( FACTION_PLAYER, i ))
1820 array_push_back( &group, i );
1821 return group;
1822
1823 case 3: /* 'hostile' */
1824 group = array_create( int );
1825 for (int i=0; i < array_size(faction_stack); i++)
1826 if (areEnemies( FACTION_PLAYER, i ))
1827 array_push_back( &group, i );
1828 return group;
1829
1830 default:
1831 return NULL;
1832 }
1833}
1834
1839{
1840 if (faction_isFaction(f))
1841 return faction_isFlag( &faction_stack[f], FACTION_USESHIDDENJUMPS );
1842 return 0;
1843}
1844
1849{
1850 if (faction_isFaction(f))
1851 return faction_stack[f].generators;
1852 return NULL;
1853}
1854
1859{
1860 for (int i=0; i<array_size(faction_stack); i++) {
1861 Faction *f = &faction_stack[i];
1862 if (faction_isFlag(f, FACTION_DYNAMIC)) {
1863 faction_freeOne( f );
1864 array_erase( &faction_stack, f, f+1 );
1865 i--;
1866 }
1867 }
1869}
1870
1880int faction_dynAdd( int base, const char* name, const char* display, const char* ai, const glColour* colour )
1881{
1883 memset( f, 0, sizeof(Faction) );
1884 f->name = strdup( name );
1885 f->displayname = (display==NULL) ? NULL : strdup( display );
1886 f->ai = (ai==NULL) ? NULL : strdup( ai );
1887 f->allies = array_create( int );
1888 f->enemies = array_create( int );
1889 f->equip_env = LUA_NOREF;
1890 f->env = LUA_NOREF;
1891 f->sched_env = LUA_NOREF;
1893 faction_addStandingScript( f, "static" );
1894 if (base>=0) {
1895 Faction *bf = &faction_stack[base];
1896
1897 if (bf->ai!=NULL && f->ai==NULL)
1898 f->ai = strdup( bf->ai );
1899 if (bf->logo!=NULL)
1900 f->logo = gl_dupTexture( bf->logo );
1901
1902 for (int i=0; i<array_size(bf->allies); i++) {
1903 int *tmp = &array_grow( &f->allies );
1904 *tmp = bf->allies[i];
1905 }
1906 for (int i=0; i<array_size(bf->enemies); i++) {
1907 int *tmp = &array_grow( &f->enemies );
1908 *tmp = bf->enemies[i];
1909 }
1910
1911 f->player_def = bf->player_def;
1912 f->player = bf->player;
1913 f->colour = bf->colour;
1914
1915 /* Lua stuff. */
1916 f->equip_env = bf->equip_env;
1917 }
1918
1919 /* Copy colour over if applicable. */
1920 if (colour != NULL)
1921 f->colour = *colour;
1922
1923 /* TODO make this incremental. */
1925
1926 return f-faction_stack;
1927}
1928
1932static void faction_computeGrid (void)
1933{
1934 size_t n = array_size(faction_stack);
1935 if (faction_mgrid < n) {
1936 free( faction_grid );
1937 faction_grid = malloc( n * n * sizeof(int) );
1938 faction_mgrid = n;
1939 }
1940 n = faction_mgrid;
1941 memset( faction_grid, 0, n*n*sizeof(int) );
1942 for (int i=0; i<array_size(faction_stack); i++) {
1943 Faction *fa = &faction_stack[i];
1944 for (int k=0; k<array_size(fa->allies); k++) {
1945 int j = fa->allies[k];
1946#if DEBUGGING
1947 if ((faction_grid[i*n+j] < 0) || (faction_grid[j*n+i]) < 0)
1948 WARN("Incoherent faction grid! '%s' and '%s' are already enemies, but trying to set to allies!", faction_stack[i].name, faction_stack[j].name );
1949#endif /* DEBUGGING */
1950 faction_grid[i*n+j] = 1;
1951 faction_grid[j*n+i] = 1;
1952 }
1953 for (int k=0; k<array_size(fa->enemies); k++) {
1954 int j = fa->enemies[k];
1955#if DEBUGGING
1956 if ((faction_grid[i*n+j] > 0) || (faction_grid[j*n+i] > 0))
1957 WARN("Incoherent faction grid! '%s' and '%s' are already allies, but trying to set to enemies!", faction_stack[i].name, faction_stack[j].name );
1958#endif /* DEBUGGING */
1959 faction_grid[i*n+j] = -1;
1960 faction_grid[j*n+i] = -1;
1961 }
1962 }
1963}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition: array.h:158
#define array_copy(basic_type, ptr_array)
Returns a shallow copy of the input array.
Definition: array.h:218
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
Definition: array.h:202
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition: array.h:102
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition: array.h:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition: array.h:119
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition: array.h:129
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition: array.h:194
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition: array.h:93
const char * faction_getStandingBroad(int f, int bribed, int override)
Gets the broad faction standing.
Definition: faction.c:1103
const char * faction_longname(int f)
Gets the faction's long name (formal, human-readable).
Definition: faction.c:346
static void faction_freeOne(Faction *f)
Frees a single faction.
Definition: faction.c:1681
const glColour * faction_getColour(int f)
Gets the colour of the faction based on it's standing with the player.
Definition: faction.c:1023
int faction_isPlayerEnemy(int f)
Gets whether or not the player is an enemy of the faction.
Definition: faction.c:1009
int faction_exists(const char *name)
Checks to see if a faction exists by name.
Definition: faction.c:171
const char * faction_default_ai(int f)
Gets the name of the default AI profile for the faction's pilots.
Definition: faction.c:397
const int * faction_getEnemies(int f)
Gets the list of enemies of a faction.
Definition: faction.c:483
int faction_dynAdd(int base, const char *name, const char *display, const char *ai, const glColour *colour)
Dynamically add a faction.
Definition: faction.c:1880
int faction_player
Definition: faction.c:47
static int faction_getRaw(const char *name)
Gets a faction ID by name.
Definition: faction.c:140
void faction_rmAlly(int f, int o)
Removes an ally from the faction's allies list.
Definition: faction.c:701
int faction_isKnown(int id)
Is the faction known?
Definition: faction.c:273
char faction_getColourChar(int f)
Gets the faction character associated to its standing with the player.
Definition: faction.c:1040
static void faction_modPlayerLua(int f, double mod, const char *source, int secondary)
Mods player using the power of Lua.
Definition: faction.c:760
#define FACTION_INVISIBLE
Definition: faction.c:37
int faction_isFaction(int f)
Checks whether or not a faction is valid.
Definition: faction.c:1246
static size_t faction_mgrid
Definition: faction.c:108
static Faction * faction_stack
Definition: faction.c:106
const glTexture * faction_logo(int f)
Gets the faction's logo (ideally 256x256).
Definition: faction.c:451
nlua_env faction_getEquipper(int f)
Gets the equipper state associated to the faction scheduler.
Definition: faction.c:738
#define FACTION_KNOWN
Definition: faction.c:38
int factions_load(void)
Loads up all the factions from the data file.
Definition: faction.c:1583
void faction_clearEnemy(int f)
Clears all the enemies of a dynamic faction.
Definition: faction.c:542
void factions_reset(void)
Resets player standing and flags of factions to default.
Definition: faction.c:1570
void faction_rmEnemy(int f, int o)
Removes an enemy from the faction's enemies list.
Definition: faction.c:608
int faction_isPlayerFriend(int f)
Gets whether or not the player is a friend of the faction.
Definition: faction.c:997
void faction_setPlayer(int f, double value)
Sets the player's standing with a faction.
Definition: faction.c:932
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition: faction.c:1197
void factions_clearDynamic(void)
Clears dynamic factions.
Definition: faction.c:1858
int * faction_getGroup(int which)
Returns an array of faction ids.
Definition: faction.c:1801
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition: faction.c:304
const char * faction_shortname(int f)
Gets a factions short name (human-readable).
Definition: faction.c:323
const char * faction_getStandingText(int f)
Gets the player's standing in human readable form.
Definition: faction.c:1054
double faction_getPlayer(int f)
Gets the player's standing with a faction.
Definition: faction.c:969
int faction_isDynamic(int id)
Is faction dynamic.
Definition: faction.c:281
void factions_free(void)
Frees the factions.
Definition: faction.c:1705
const int * faction_getAllies(int f)
Gets the list of allies of a faction.
Definition: faction.c:513
void faction_modPlayerRaw(int f, double mod)
Modifies the player's standing without affecting others.
Definition: faction.c:899
const FactionGenerator * faction_generators(int f)
Gets the faction's generators.
Definition: faction.c:1848
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
Definition: faction.c:1838
int * faction_getKnown()
Gets all the known factions in an array (array.h).
Definition: faction.c:217
int faction_isInvisible(int id)
Is the faction invisible?
Definition: faction.c:248
int pfaction_save(xmlTextWriterPtr writer)
Saves player's standings with the factions.
Definition: faction.c:1725
const glColour * faction_colour(int f)
Gets the colour of the faction.
Definition: faction.c:467
static void faction_sanitizePlayer(Faction *faction)
Sanitizes player faction standing.
Definition: faction.c:752
void faction_clearAlly(int f)
Clears all the ally of a dynamic faction.
Definition: faction.c:635
int pfaction_load(xmlNodePtr parent)
Loads the player's faction standings.
Definition: faction.c:1756
#define FACTION_STATIC
Definition: faction.c:36
double faction_lane_base_cost(int f)
Gets the faction's weight for patrolled safe-lane construction;.
Definition: faction.c:436
void faction_modPlayer(int f, double mod, const char *source)
Modifies the player's standing with a faction.
Definition: faction.c:839
const char ** faction_tags(int f)
Gets the tags the faction has.
Definition: faction.c:412
static int * faction_grid
Definition: faction.c:107
static int faction_parseSocial(const char *file)
Parses the social tidbits of a faction: allies and enemies.
Definition: faction.c:1441
#define FACTION_USESHIDDENJUMPS
Definition: faction.c:40
double faction_getPlayerDef(int f)
Gets the player's default standing with a faction.
Definition: faction.c:983
int * faction_getAll(void)
Returns all faction IDs in an array (array.h).
Definition: faction.c:193
void faction_modPlayerSingle(int f, double mod, const char *source)
Modifies the player's standing without affecting others.
Definition: faction.c:879
static void faction_addStandingScript(Faction *temp, const char *scriptname)
Sets up a standing script for a faction.
Definition: faction.c:1396
static int faction_parse(Faction *temp, const char *file)
Parses a single faction, but doesn't set the allies/enemies bit.
Definition: faction.c:1260
#define FACTION_DYNAMIC
Definition: faction.c:39
int faction_setInvisible(int id, int state)
Sets the faction's invisible state.
Definition: faction.c:256
int faction_setKnown(int id, int state)
Sets the factions known state.
Definition: faction.c:289
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).
Definition: faction.c:424
int * faction_getAllVisible(void)
Returns all non-invisible faction IDs in an array (array.h).
Definition: faction.c:205
const char * faction_mapname(int f)
Gets the faction's map name (translated).
Definition: faction.c:363
double faction_reputationMax(int f)
Gets the maximum reputation of a faction.
Definition: faction.c:1151
void faction_addAlly(int f, int o)
Adds an ally to the faction's allies list.
Definition: faction.c:655
nlua_env faction_getScheduler(int f)
Gets the state associated to the faction scheduler.
Definition: faction.c:726
static void faction_computeGrid(void)
Computes the faction relationship grid.
Definition: faction.c:1932
const char * faction_description(int f)
Gets the faction's description (translated).
Definition: faction.c:380
void faction_clearKnown()
Clears the known factions.
Definition: faction.c:230
int faction_isStatic(int id)
Is the faction static?
Definition: faction.c:240
void faction_addEnemy(int f, int o)
Adds an enemy to the faction's enemies list.
Definition: faction.c:562
int faction_get(const char *name)
Gets a faction ID by name.
Definition: faction.c:182
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition: faction.c:1222
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition: hook.c:967
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition: naev.c:549
Header file with generic functions and naev-specifics.
#define CLAMP(a, b, x)
Definition: naev.h:41
#define FABS(x)
Definition: naev.h:37
#define PATH_MAX
Definition: naev.h:50
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition: ndata.c:154
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
Definition: ndata.c:366
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition: ndata.c:232
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition: nlua.c:760
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.
Definition: nlua.c:873
int nlua_reffield(int objref, const char *name)
Gets the reference to the specified field from an object reference.
Definition: nlua.c:889
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition: nxml.c:75
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition: opengl_tex.c:809
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition: opengl_tex.c:570
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition: opengl_tex.c:755
Player_t player
Definition: player.c:73
static const double b[]
Definition: rng.c:256
void space_factionChange(void)
Mark when a faction changes.
Definition: space.c:1344
double weight
Definition: faction.h:17
Description of a lane-building faction.
Definition: faction.c:54
unsigned int oflags
Definition: faction.c:100
unsigned int flags
Definition: faction.c:99
glTexture * logo
Definition: faction.c:63
glColour colour
Definition: faction.c:64
nlua_env equip_env
Definition: faction.c:96
double player
Definition: faction.c:74
double lane_base_cost
Definition: faction.c:90
char * description
Definition: faction.c:60
double friendly_at
Definition: faction.c:81
FactionGenerator * generators
Definition: faction.c:93
nlua_env env
Definition: faction.c:80
double lane_length_per_presence
Definition: faction.c:89
char * mapname
Definition: faction.c:58
char ** tags
Definition: faction.c:103
char * longname
Definition: faction.c:56
char * ai
Definition: faction.c:59
int lua_text_rank
Definition: faction.c:84
char * displayname
Definition: faction.c:57
int lua_hit
Definition: faction.c:83
int * allies
Definition: faction.c:70
int * enemies
Definition: faction.c:67
nlua_env sched_env
Definition: faction.c:77
double player_def
Definition: faction.c:73
int lua_text_broad
Definition: faction.c:85
char * name
Definition: faction.c:55
int lua_reputation_max
Definition: faction.c:86
int lua_standing
Definition: faction.c:82
The actual hook parameter.
Definition: hook.h:35
union HookParam::@4 u
HookParamType type
Definition: hook.h:36
double num
Definition: hook.h:38
LuaFaction lf
Definition: hook.h:42
int devmode
Definition: conf.h:158
Pilot * p
Definition: player.h:101
Abstraction for rendering sprite sheets.
Definition: opengl_tex.h:34