naev 0.11.5
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 double friendly_at;
81 nlua_env lua_env;
82 int lua_hit;
87 /* Safe lanes. */
91 /* Presence stuff. */
94 /* Equipping. */
95 nlua_env equip_env;
97 /* Flags. */
98 unsigned int flags;
99 unsigned int oflags;
101 /* Tags. */
102 char **tags;
103} Faction;
104
105static Faction* faction_stack = NULL;
106static int* faction_grid = NULL;
107static size_t faction_mgrid = 0;
109/*
110 * Prototypes
111 */
112/* static */
113static int faction_getRaw( const char *name );
114static void faction_freeOne( Faction *f );
115static void faction_sanitizePlayer( Faction* faction );
116static void faction_modPlayerLua( int f, double mod, const char *source, int secondary );
117static int faction_parse( Faction* temp, const char *file );
118static int faction_parseSocial( const char *file );
119static void faction_addStandingScript( Faction* temp, const char* scriptname );
120static void faction_computeGrid (void);
121/* externed */
122int pfaction_save( xmlTextWriterPtr writer );
123int pfaction_load( xmlNodePtr parent );
124
125static int faction_cmp( const void *p1, const void *p2 )
126{
127 const Faction *f1, *f2;
128 f1 = (const Faction*) p1;
129 f2 = (const Faction*) p2;
130 return strcmp(f1->name,f2->name);
131}
132
139static int faction_getRaw( const char* name )
140{
141 if (name==NULL)
142 return -1;
143
144 /* Escorts are part of the "player" faction. */
145 if (strcmp(name, "Escort") == 0)
146 return FACTION_PLAYER;
147
148 if (name != NULL) {
149 int i;
150 for (i=0; i<array_size(faction_stack); i++)
151 if (strcmp(faction_stack[i].name, name)==0)
152 break;
153
154 if (i != array_size(faction_stack))
155 return i;
156
157 /* Dynamic factions are why we can't have nice things.
158 const Faction f = { .name = (char*)name };
159 Faction *found = bsearch( &f, faction_stack, array_size(faction_stack), sizeof(Faction), faction_cmp );
160 if (found != NULL)
161 return found - faction_stack;
162 */
163 }
164 return -1;
165}
166
173int faction_exists( const char* name )
174{
175 return faction_getRaw(name)!=-1;
176}
177
184int faction_get( const char* name )
185{
186 int id = faction_getRaw(name);
187 if (id<0)
188 WARN(_("Faction '%s' not found in stack."), name);
189 return id;
190}
191
195int* faction_getAll (void)
196{
198 for (int i=0; i<array_size(faction_stack); i++)
199 array_push_back( &f, i );
200
201 return f;
202}
203
208{
210 for (int i=0; i<array_size(faction_stack); i++)
211 if (!faction_isFlag( &faction_stack[i], FACTION_INVISIBLE ))
212 array_push_back( &f, i );
213 return f;
214}
215
220{
222 /* Get IDs. */
223 for (int i=0; i<array_size(faction_stack); i++)
224 if (!faction_isFlag( &faction_stack[i], FACTION_INVISIBLE ) && faction_isKnown_( &faction_stack[i] ))
225 array_push_back( &f, i );
226 return f;
227}
228
233{
234 for (int i=0; i<array_size(faction_stack); i++)
235 if (faction_isKnown_( &faction_stack[i] ))
236 faction_rmFlag( &faction_stack[i], FACTION_KNOWN );
237}
238
242int faction_isStatic( int id )
243{
244 return faction_isFlag( &faction_stack[id], FACTION_STATIC );
245}
246
251{
252 return faction_isFlag( &faction_stack[id], FACTION_INVISIBLE );
253}
254
258int faction_setInvisible( int id, int state )
259{
260 if (!faction_isFaction(id)) {
261 WARN(_("Faction id '%d' is invalid."),id);
262 return -1;
263 }
264 if (state)
265 faction_setFlag( &faction_stack[id], FACTION_INVISIBLE );
266 else
267 faction_rmFlag( &faction_stack[id], FACTION_INVISIBLE );
268
269 return 0;
270}
271
275int faction_isKnown( int id )
276{
277 return faction_isKnown_( &faction_stack[id] );
278}
279
283int faction_isDynamic( int id )
284{
285 return faction_isFlag( &faction_stack[id], FACTION_DYNAMIC );
286}
287
291int faction_setKnown( int id, int state )
292{
293 if (state)
294 faction_setFlag( &faction_stack[id], FACTION_KNOWN );
295 else
296 faction_rmFlag( &faction_stack[id], FACTION_KNOWN );
297 return 0;
298}
299
306const char* faction_name( int f )
307{
308 if (!faction_isFaction(f)) {
309 WARN(_("Faction id '%d' is invalid."),f);
310 return NULL;
311 }
312 /* Don't want player to see their escorts as "Player" faction. */
313 if (f == FACTION_PLAYER)
314 return "Escort";
315
316 return faction_stack[f].name;
317}
318
325const char* faction_shortname( int f )
326{
327 if (!faction_isFaction(f)) {
328 WARN(_("Faction id '%d' is invalid."),f);
329 return NULL;
330 }
331 /* Don't want player to see their escorts as "Player" faction. */
332 if (f == FACTION_PLAYER)
333 return _("Escort");
334
335 /* Possibly get display name. */
336 if (faction_stack[f].displayname != NULL)
337 return _(faction_stack[f].displayname);
338
339 return _(faction_stack[f].name);
340}
341
348const char* faction_longname( int f )
349{
350 if (!faction_isFaction(f)) {
351 WARN(_("Faction id '%d' is invalid."),f);
352 return NULL;
353 }
354 if (faction_stack[f].longname != NULL)
355 return _(faction_stack[f].longname);
356 return _(faction_stack[f].name);
357}
358
365const char* faction_mapname( int f )
366{
367 if (!faction_isFaction(f)) {
368 WARN(_("Faction id '%d' is invalid."),f);
369 return NULL;
370 }
371 if (faction_stack[f].mapname != NULL)
372 return _(faction_stack[f].mapname);
373 return _(faction_stack[f].name);
374}
375
382const char* faction_description( int f )
383{
384 if (!faction_isFaction(f)) {
385 WARN(_("Faction id '%d' is invalid."),f);
386 return NULL;
387 }
388 if (faction_stack[f].description != NULL)
389 return _(faction_stack[f].description);
390 return NULL;
391}
392
399const char* faction_default_ai( int f )
400{
401 if (!faction_isFaction(f)) {
402 WARN(_("Faction id '%d' is invalid."), f);
403 return NULL;
404 }
405 return faction_stack[f].ai;
406}
407
414const char** faction_tags( int f )
415{
416 if (!faction_isFaction(f)) {
417 WARN(_("Faction id '%d' is invalid."), f);
418 return NULL;
419 }
420 return (const char**) faction_stack[f].tags;
421}
422
427{
428 if (!faction_isFaction(f)) {
429 WARN(_("Faction id '%d' is invalid."), f);
430 return 0.;
431 }
433}
434
439{
440 if (!faction_isFaction(f)) {
441 WARN(_("Faction id '%d' is invalid."), f);
442 return 0.;
443 }
445}
446
453const glTexture* faction_logo( int f )
454{
455 if (!faction_isFaction(f)) {
456 WARN(_("Faction id '%d' is invalid."),f);
457 return NULL;
458 }
459
460 return faction_stack[f].logo;
461}
462
469const glColour* faction_colour( int f )
470{
471 if (!faction_isFaction(f)) {
472 WARN(_("Faction id '%d' is invalid."),f);
473 return NULL;
474 }
475
476 return &faction_stack[f].colour;
477}
478
485const int* faction_getEnemies( int f )
486{
487 if (!faction_isFaction(f)) {
488 WARN(_("Faction id '%d' is invalid."),f);
489 return NULL;
490 }
491
492 /* Player's faction ratings can change, so regenerate each call. */
493 if (f == FACTION_PLAYER) {
494 int *enemies = array_create( int );
495
496 for (int i=0; i<array_size(faction_stack); i++)
497 if (faction_isPlayerEnemy(i)) {
498 int *tmp = &array_grow( &enemies );
499 *tmp = i;
500 }
501
502 array_free( faction_stack[f].enemies );
503 faction_stack[f].enemies = enemies;
504 }
505
506 return faction_stack[f].enemies;
507}
508
515const int* faction_getAllies( int f )
516{
517 if (!faction_isFaction(f)) {
518 WARN(_("Faction id '%d' is invalid."),f);
519 return NULL;
520 }
521
522 /* Player's faction ratings can change, so regenerate each call. */
523 if (f == FACTION_PLAYER) {
524 int *allies = array_create( int );
525
526 for (int i=0; i<array_size(faction_stack); i++)
527 if (faction_isPlayerFriend(i)) {
528 int *tmp = &array_grow( &allies );
529 *tmp = i;
530 }
531
532 array_free( faction_stack[ f ].allies );
533 faction_stack[f].allies = allies;
534 }
535
536 return faction_stack[f].allies;
537}
538
545{
546 Faction *ff;
547 /* Get faction. */
548 if (faction_isFaction(f))
549 ff = &faction_stack[f];
550 else { /* f is invalid */
551 WARN(_("Faction id '%d' is invalid."), f);
552 return;
553 }
556}
557
564void faction_addEnemy( int f, int o )
565{
566 Faction *ff;
567 int *tmp;
568
569 if (f==o) return;
570
571 if (faction_isFaction(f))
572 ff = &faction_stack[f];
573 else { /* f is invalid */
574 WARN(_("Faction id '%d' is invalid."), f);
575 return;
576 }
577
578 if (!faction_isFaction(o)) { /* o is invalid */
579 WARN(_("Faction id '%d' is invalid."), o);
580 return;
581 }
582
583 /* player cannot be made an enemy this way */
584 if (f==FACTION_PLAYER) {
585 WARN(_("%d is the player faction"), f);
586 return;
587 }
588 if (o==FACTION_PLAYER) {
589 WARN(_("%d is the player faction"), o);
590 return;
591 }
592
593 for (int i=0;i<array_size(ff->enemies);i++) {
594 if (ff->enemies[i] == o)
595 return;
596 }
597
598 tmp = &array_grow( &ff->enemies );
599 *tmp = o;
600
602}
603
610void faction_rmEnemy( int f, int o )
611{
612 Faction *ff;
613
614 if (f==o) return;
615
616 if (faction_isFaction(f))
617 ff = &faction_stack[f];
618 else { /* f is invalid */
619 WARN(_("Faction id '%d' is invalid."), f);
620 return;
621 }
622
623 for (int i=0;i<array_size(ff->enemies);i++) {
624 if (ff->enemies[i] == o) {
625 array_erase( &ff->enemies, &ff->enemies[i], &ff->enemies[i+1] );
627 return;
628 }
629 }
630}
631
637void faction_clearAlly( int f )
638{
639 Faction *ff;
640 /* Get faction. */
641 if (faction_isFaction(f))
642 ff = &faction_stack[f];
643 else { /* f is invalid */
644 WARN(_("Faction id '%d' is invalid."), f);
645 return;
646 }
649}
650
657void faction_addAlly( int f, int o )
658{
659 Faction *ff;
660 int *tmp;
661
662 if (f==o) return;
663
664 if (faction_isFaction(f))
665 ff = &faction_stack[f];
666 else { /* f is invalid */
667 WARN(_("Faction id '%d' is invalid."), f);
668 return;
669 }
670
671 if (!faction_isFaction(o)) { /* o is invalid */
672 WARN(_("Faction id '%d' is invalid."), o);
673 return;
674 }
675
676 /* player cannot be made an ally this way */
677 if (f==FACTION_PLAYER) {
678 WARN(_("%d is the player faction"), f);
679 return;
680 }
681 if (o==FACTION_PLAYER) {
682 WARN(_("%d is the player faction"), o);
683 return;
684 }
685
686 for (int i=0;i<array_size(ff->allies);i++) {
687 if (ff->allies[i] == o)
688 return;
689 }
690
691 tmp = &array_grow( &ff->allies );
692 *tmp = o;
693
695}
696
703void faction_rmAlly( int f, int o )
704{
705 Faction *ff;
706
707 if (f==o) return;
708
709 if (faction_isFaction(f))
710 ff = &faction_stack[f];
711 else { /* f is invalid */
712 WARN(_("Faction id '%d' is invalid."), f);
713 return;
714 }
715
716 for (int i=0;i<array_size(ff->allies);i++) {
717 if (ff->allies[i] == o) {
718 array_erase( &ff->allies, &ff->allies[i], &ff->allies[i+1] );
720 return;
721 }
722 }
723}
724
728nlua_env faction_getScheduler( int f )
729{
730 if (!faction_isFaction(f)) {
731 WARN(_("Faction id '%d' is invalid."),f);
732 return LUA_NOREF;
733 }
734 return faction_stack[f].sched_env;
735}
736
740nlua_env faction_getEquipper( int f )
741{
742 if (!faction_isFaction(f)) {
743 WARN(_("Faction id '%d' is invalid."),f);
744 return LUA_NOREF;
745 }
746 return faction_stack[f].equip_env;
747}
748
754static void faction_sanitizePlayer( Faction* faction )
755{
756 faction->player = CLAMP( -100., 100., faction->player );
757}
758
762static void faction_modPlayerLua( int f, double mod, const char *source, int secondary )
763{
764 Faction *faction;
765 double old, delta;
766
767 /* Ignore it if player is dead. */
768 if (player.p==NULL)
769 return;
770
771 faction = &faction_stack[f];
772
773 /* Make sure it's not static. */
774 if (faction_isFlag(faction, FACTION_STATIC))
775 return;
776
777 /* Player is dead or cleared. */
778 if (player.p == NULL)
779 return;
780
781 old = faction->player;
782
783 if (faction->lua_env == LUA_NOREF)
784 faction->player += mod;
785 else {
786
787 /* Set up the function:
788 * standing:hit( current, amount, source, secondary ) */
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 );
794
795 /* Call function. */
796 if (nlua_pcall( faction->lua_env, 4, 1 )) { /* An error occurred. */
797 WARN(_("Faction '%s': %s"), faction->name, lua_tostring(naevL,-1));
798 lua_pop( naevL, 1 );
799 return;
800 }
801
802 /* Parse return. */
803 if (!lua_isnumber( naevL, -1 ))
804 WARN(_("Lua script for faction '%s' did not return a %s from '%s'."), faction->name, _("number"), "hit" );
805 else
806 faction->player = lua_tonumber( naevL, -1 );
807 lua_pop( naevL, 1 );
808 }
809
810 /* Sanitize just in case. */
811 faction_sanitizePlayer( faction );
812
813 /* Run hook if necessary. */
814 delta = faction->player - old;
815 if (FABS(delta) > 1e-10) {
816 HookParam hparam[3];
817 hparam[0].type = HOOK_PARAM_FACTION;
818 hparam[0].u.lf = f;
819 hparam[1].type = HOOK_PARAM_NUMBER;
820 hparam[1].u.num = delta;
821 hparam[2].type = HOOK_PARAM_SENTINEL;
822 hooks_runParam( "standing", hparam );
823
824 /* Tell space the faction changed. */
826 }
827}
828
843void faction_modPlayer( int f, double mod, const char *source )
844{
845 Faction *faction;
846
847 if (!faction_isFaction(f)) {
848 WARN(_("Faction id '%d' is invalid."), f);
849 return;
850 }
851 faction = &faction_stack[f];
852
853 /* Modify faction standing with parent faction. */
854 faction_modPlayerLua( f, mod, source, 0 );
855
856 /* Now mod allies to a lesser degree */
857 for (int i=0; i<array_size(faction->allies); i++)
858 /* Modify faction standing */
859 faction_modPlayerLua( faction->allies[i], mod, source, 1 );
860
861 /* Now mod enemies */
862 for (int i=0; i<array_size(faction->enemies); i++)
863 /* Modify faction standing. */
864 faction_modPlayerLua( faction->enemies[i], -mod, source, 1 );
865}
866
883void faction_modPlayerSingle( int f, double mod, const char *source )
884{
885 if (!faction_isFaction(f)) {
886 WARN(_("Faction id '%d' is invalid."), f);
887 return;
888 }
889
890 faction_modPlayerLua( f, mod, source, 0 );
891}
892
903void faction_modPlayerRaw( int f, double mod )
904{
905 Faction *faction;
906 HookParam hparam[3];
907
908 /* Ignore it if player is dead. */
909 if (player.p==NULL)
910 return;
911
912 if (!faction_isFaction(f)) {
913 WARN(_("Faction id '%d' is invalid."), f);
914 return;
915 }
916
917 faction = &faction_stack[f];
918 faction->player += mod;
919 /* Run hook if necessary. */
920 hparam[0].type = HOOK_PARAM_FACTION;
921 hparam[0].u.lf = f;
922 hparam[1].type = HOOK_PARAM_NUMBER;
923 hparam[1].u.num = mod;
924 hparam[2].type = HOOK_PARAM_SENTINEL;
925 hooks_runParam( "standing", hparam );
926
927 /* Sanitize just in case. */
928 faction_sanitizePlayer( faction );
929
930 /* Tell space the faction changed. */
932}
933
940void faction_setPlayer( int f, double value )
941{
942 Faction *faction;
943 double mod;
944
945 /* Ignore it if player is dead. */
946 if (player.p==NULL)
947 return;
948
949 if (!faction_isFaction(f)) {
950 WARN(_("Faction id '%d' is invalid."), f);
951 return;
952 }
953
954 faction = &faction_stack[f];
955 mod = value - faction->player;
956 faction->player = value;
957 /* Run hook if necessary. */
958 if (!faction_isFlag(faction, FACTION_DYNAMIC)) {
959 HookParam hparam[3];
960 hparam[0].type = HOOK_PARAM_FACTION;
961 hparam[0].u.lf = f;
962 hparam[1].type = HOOK_PARAM_NUMBER;
963 hparam[1].u.num = mod;
964 hparam[2].type = HOOK_PARAM_SENTINEL;
965 hooks_runParam( "standing", hparam );
966
967 /* Sanitize just in case. */
968 faction_sanitizePlayer( faction );
969
970 /* Tell space the faction changed. */
972 }
973}
974
981double faction_getPlayer( int f )
982{
983 if (faction_isFaction(f))
984 return faction_stack[f].player;
985 WARN(_("Faction id '%d' is invalid."), f);
986 return -1000.;
987}
988
995double faction_getPlayerDef( int f )
996{
997 if (faction_isFaction(f))
998 return faction_stack[f].player_def;
999 WARN(_("Faction id '%d' is invalid."), f);
1000 return -1000.;
1001}
1002
1010{
1011 const Faction *faction = &faction_stack[f];
1012 return (faction->player >= faction->friendly_at);
1013}
1014
1022{
1023 const Faction *faction = &faction_stack[f];
1024 return (faction->player < 0);
1025}
1026
1035const glColour* faction_getColour( int f )
1036{
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;
1041}
1042
1053{
1054 if (f<0) return 'I';
1055 else if (areEnemies(FACTION_PLAYER,f)) return 'H';
1056 else if (areAllies(FACTION_PLAYER,f)) return 'F';
1057 else return 'N';
1058}
1059
1066const char *faction_getStandingText( int f )
1067{
1069}
1070
1078const char *faction_getStandingTextAtValue( int f, double value )
1079{
1080 Faction *faction;
1081
1082 /* Ignore it if player is dead. */
1083 if (player.p==NULL)
1084 return _("???");
1085
1086 /* Escorts always have the same standing. */
1087 if (f == FACTION_PLAYER)
1088 return _("Escort");
1089
1090 faction = &faction_stack[f];
1091
1092 if (faction->lua_env == LUA_NOREF)
1093 return _("???");
1094 else {
1095 const char *r;
1096 /* Set up the method:
1097 * standing:text_rank( standing ) */
1098 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_text_rank );
1099 lua_pushnumber( naevL, value );
1100
1101 /* Call function. */
1102 if (nlua_pcall( faction->lua_env, 1, 1 )) {
1103 /* An error occurred. */
1104 WARN( _("Faction '%s': %s"), faction->name, lua_tostring( naevL, -1 ) );
1105 lua_pop( naevL, 1 );
1106 return _("???");
1107 }
1108
1109 /* Parse return. */
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" );
1112 r = _("???");
1113 }
1114 else
1115 r = lua_tostring( naevL, -1 ); /* Should be translated already. */
1116 lua_pop( naevL, 1 );
1117 return r;
1118 }
1119}
1120
1129const char *faction_getStandingBroad( int f, int bribed, int override )
1130{
1131 Faction *faction;
1132 const char *r;
1133
1134 /* Ignore it if player is dead. */
1135 if (player.p==NULL)
1136 return _("???");
1137
1138 /* Escorts always have the same standing. */
1139 if (f == FACTION_PLAYER)
1140 return _("Escort");
1141
1142 faction = &faction_stack[f];
1143
1144 if (faction->lua_env == LUA_NOREF)
1145 return _("???");
1146
1147 /* Set up the method:
1148 * standing:text_broad( standing, bribed, override ) */
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 );
1153
1154 /* Call function. */
1155 if (nlua_pcall( faction->lua_env, 3, 1 )) {
1156 /* An error occurred. */
1157 WARN( _("Faction '%s': %s"), faction->name, lua_tostring( naevL, -1 ) );
1158 lua_pop( naevL, 1 );
1159 return _("???");
1160 }
1161
1162 /* Parse return. */
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" );
1165 r = _("???");
1166 }
1167 else
1168 r = lua_tostring( naevL, -1 );
1169 lua_pop( naevL, 1 );
1170 return r;
1171}
1172
1180{
1181 Faction *faction;
1182 double r;
1183
1184 /* Ignore it if player is dead. */
1185 if (player.p==NULL)
1186 return 0.;
1187
1188 /* Escorts always have the same standing. */
1189 if (f == FACTION_PLAYER)
1190 return 100.;
1191
1192 faction = &faction_stack[f];
1193
1194 if (faction->lua_env == LUA_NOREF)
1195 return 0.;
1196
1197 /* Set up the method:
1198 * standing:reputation_max( standing ) */
1199 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_reputation_max );
1200
1201 /* Call function. */
1202 if (nlua_pcall( faction->lua_env, 0, 1 )) {
1203 /* An error occurred. */
1204 WARN( _("Faction '%s': %s"), faction->name, lua_tostring( naevL, -1 ) );
1205 lua_pop( naevL, 1 );
1206 return 0.;
1207 }
1208
1209 /* Parse return. */
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" );
1212 r = 0.;
1213 }
1214 else
1215 r = lua_tonumber( naevL, -1 );
1216 lua_pop( naevL, 1 );
1217 return r;
1218}
1219
1227int areEnemies( int a, int b )
1228{
1229 /* luckily our factions aren't masochistic */
1230 if (a==b)
1231 return 0;
1232
1233 /* Make sure they're valid. */
1234 if (!faction_isFaction(a) || !faction_isFaction(b))
1235 return 0;
1236
1237 /* player handled separately */
1238 if (a==FACTION_PLAYER)
1239 return faction_isPlayerEnemy(b);
1240 else if (b==FACTION_PLAYER)
1241 return faction_isPlayerEnemy(a);
1242
1243 return faction_grid[ a * faction_mgrid + b ] < 0;
1244}
1245
1253int areAllies( int a, int b )
1254{
1255 /* If they are the same they must be allies. */
1256 if (a==b) return 1;
1257
1258 /* Make sure they're valid. */
1259 if (!faction_isFaction(a) || !faction_isFaction(b))
1260 return 0;
1261
1262 /* we assume player becomes allies with high rating */
1263 if (a==FACTION_PLAYER)
1264 return faction_isPlayerFriend(b);
1265 else if (b==FACTION_PLAYER)
1266 return faction_isPlayerFriend(a);
1267
1268 return faction_grid[ a * faction_mgrid + b ] > 0;
1269}
1270
1278{
1279 if ((f<0) || (f>=array_size(faction_stack)))
1280 return 0;
1281 return 1;
1282}
1283
1291static int faction_parse( Faction* temp, const char *file )
1292{
1293 xmlNodePtr node, parent;
1294 int saw_player;
1295
1296 xmlDocPtr doc = xml_parsePhysFS( file );
1297 if (doc == NULL)
1298 return -1;
1299
1300 parent = doc->xmlChildrenNode; /* first faction node */
1301 if (parent == NULL) {
1302 ERR( _("Malformed '%s' file: does not contain elements"), file);
1303 return -1;
1304 }
1305
1306 /* Clear memory. */
1307 memset( temp, 0, sizeof(Faction) );
1308 temp->equip_env = LUA_NOREF;
1309 temp->sched_env = LUA_NOREF;
1310 temp->lua_env = LUA_NOREF;
1311 temp->lua_hit = LUA_NOREF;
1312 temp->lua_text_rank = LUA_NOREF;
1313 temp->lua_text_broad = LUA_NOREF;
1314 temp->lua_reputation_max = LUA_NOREF;
1315
1316 xmlr_attr_strd(parent,"name",temp->name);
1317 if (temp->name == NULL)
1318 WARN(_("Faction from file '%s' has no name!"), file);
1319
1320 saw_player = 0;
1321 node = parent->xmlChildrenNode;
1322 do {
1323 /* Only care about nodes. */
1324 xml_onlyNodes(node);
1325
1326 /* Can be 0 or negative, so we have to take that into account. */
1327 if (xml_isNode(node,"player")) {
1328 temp->player_def = xml_getFloat(node);
1329 saw_player = 1;
1330 continue;
1331 }
1332
1333 xmlr_strd(node,"longname",temp->longname);
1334 xmlr_strd(node,"display",temp->displayname);
1335 xmlr_strd(node,"mapname",temp->mapname);
1336 xmlr_strd(node,"description",temp->description);
1337 xmlr_strd(node,"ai",temp->ai);
1338 xmlr_float(node,"lane_length_per_presence",temp->lane_length_per_presence);
1339 xmlr_float(node,"lane_base_cost",temp->lane_base_cost);
1340 if (xml_isNode(node, "colour")) {
1341 const char *ctmp = xml_get(node);
1342 if (ctmp != NULL)
1343 temp->colour = *col_fromName(xml_raw(node));
1344 /* If no named colour is present, RGB attributes are used. */
1345 else {
1346 /* Initialize in case a colour channel is absent. */
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);
1350 temp->colour.a = 1.;
1351 col_gammaToLinear( &temp->colour );
1352 }
1353 continue;
1354 }
1355
1356 if (xml_isNode(node, "known")) {
1357 faction_setFlag(temp, FACTION_KNOWN);
1358 continue;
1359 }
1360
1361 if (xml_isNode(node,"logo")) {
1362 char buf[PATH_MAX];
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) );
1366 temp->logo = gl_newImage(buf, 0);
1367 continue;
1368 }
1369
1370 if (xml_isNode(node,"static")) {
1371 faction_setFlag(temp, FACTION_STATIC);
1372 continue;
1373 }
1374
1375 if (xml_isNode(node,"invisible")) {
1376 faction_setFlag(temp, FACTION_INVISIBLE);
1377 continue;
1378 }
1379
1380 if (xml_isNode(node,"useshiddenjumps")) {
1381 faction_setFlag(temp, FACTION_USESHIDDENJUMPS);
1382 continue;
1383 }
1384
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");
1389 else
1390 temp->tags = array_create( char* );
1391 do {
1392 xml_onlyNodes(cur);
1393 if (xml_isNode(cur, "tag")) {
1394 const char *tmp = xml_get(cur);
1395 if (tmp != NULL)
1396 array_push_back( &temp->tags, strdup(tmp) );
1397 continue;
1398 }
1399 WARN(_("Faction '%s' has unknown node in tags '%s'."), temp->name, cur->name );
1400 } while (xml_nextNode(cur));
1401 continue;
1402 }
1403
1404#if DEBUGGING
1405 /* Avoid warnings. */
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"))
1409 continue;
1410 WARN(_("Unknown node '%s' in faction '%s'"),node->name,temp->name);
1411#endif /* DEBUGGING */
1412
1413 } while (xml_nextNode(node));
1414
1415 if (!saw_player)
1416 WARN(_("Faction '%s' missing 'player' tag."), temp->name);
1417 if (faction_isKnown_(temp) && !faction_isFlag(temp, FACTION_INVISIBLE) && temp->description==NULL)
1418 WARN(_("Faction '%s' is known but missing 'description' tag."), temp->name);
1419
1420 xmlFreeDoc(doc);
1421
1422 return 0;
1423}
1424
1431static void faction_addStandingScript( Faction* temp, const char* scriptname )
1432{
1433 char buf[PATH_MAX], *dat;
1434 size_t ndat;
1435
1436 snprintf( buf, sizeof(buf), FACTIONS_PATH"standing/%s.lua", scriptname );
1437 temp->lua_env = nlua_newEnv();
1438
1439 nlua_loadStandard( temp->lua_env );
1440 dat = ndata_read( buf, &ndat );
1441 if (nlua_dobufenv(temp->lua_env, dat, ndat, buf) != 0) {
1442 WARN(_("Failed to run standing script: %s\n"
1443 "%s\n"
1444 "Most likely Lua file has improper syntax, please check"),
1445 buf, lua_tostring(naevL,-1));
1446 nlua_freeEnv( temp->lua_env );
1447 temp->lua_env = LUA_NOREF;
1448 }
1449 free(dat);
1450
1451 /* Set up the references. */
1452 temp->lua_hit = nlua_refenvtype( temp->lua_env, "hit", LUA_TFUNCTION );
1453 temp->lua_text_broad = nlua_refenvtype( temp->lua_env, "text_broad", LUA_TFUNCTION );
1454 temp->lua_text_rank = nlua_refenvtype( temp->lua_env, "text_rank", LUA_TFUNCTION );
1455 temp->lua_reputation_max= nlua_refenvtype( temp->lua_env, "reputation_max", LUA_TFUNCTION );
1456
1457 nlua_getenv( naevL, temp->lua_env, "friendly_at" );
1458 temp->friendly_at = lua_tonumber( naevL, -1 );
1459 lua_pop( naevL, 1 );
1460}
1461
1468static int faction_parseSocial( const char *file )
1469{
1470 char buf[PATH_MAX], *name, *dat;
1471 size_t ndat;
1472 xmlNodePtr node, parent;
1473 Faction *base;
1474
1475 xmlDocPtr doc = xml_parsePhysFS( file );
1476 if (doc == NULL)
1477 return -1;
1478
1479 parent = doc->xmlChildrenNode; /* first faction node */
1480 if (parent == NULL) {
1481 ERR( _("Malformed '%s' file: does not contain elements"), file);
1482 return -1;
1483 }
1484
1485 /* Get name. */
1486 base = NULL;
1487 xmlr_attr_strd(parent, "name", name);
1488 if (name != NULL)
1489 base = &faction_stack[ faction_get( name ) ];
1490 free( name );
1491 name = NULL;
1492
1493 assert( base != NULL );
1494
1495 /* Create arrays, not much memory so it doesn't really matter. */
1496 base->allies = array_create( int );
1497 base->enemies = array_create( int );
1498
1499 /* Parse social stuff. */
1500 node = parent->xmlChildrenNode;
1501 do {
1502 if (xml_isNode(node, "generator")) {
1503 FactionGenerator *fg;
1504 if (base->generators==NULL)
1506 fg = &array_grow( &base->generators );
1507 xmlr_attr_float(node,"weight",fg->weight);
1508 fg->id = faction_get( xml_get(node) );
1509 continue;
1510 }
1511
1512 /* Standing scripts. */
1513 if (xml_isNode(node, "standing")) {
1514 if (base->lua_env != LUA_NOREF)
1515 WARN(_("Faction '%s' has duplicate 'standing' tag."), base->name);
1516 faction_addStandingScript( base, xml_raw(node) );
1517 continue;
1518 }
1519
1520 /* Spawning scripts. */
1521 if (xml_isNode(node, "spawn")) {
1522 if (base->sched_env != LUA_NOREF)
1523 WARN(_("Faction '%s' has duplicate 'spawn' tag."), base->name);
1524 snprintf( buf, sizeof(buf), FACTIONS_PATH"spawn/%s.lua", xml_raw(node) );
1525 base->sched_env = nlua_newEnv();
1527 dat = ndata_read( buf, &ndat );
1528 if (nlua_dobufenv(base->sched_env, dat, ndat, buf) != 0) {
1529 WARN(_("Failed to run spawn script: %s\n"
1530 "%s\n"
1531 "Most likely Lua file has improper syntax, please check"),
1532 buf, lua_tostring(naevL,-1));
1533 nlua_freeEnv( base->sched_env );
1534 base->sched_env = LUA_NOREF;
1535 }
1536 free(dat);
1537 continue;
1538 }
1539
1540 /* Equipment scripts. */
1541 if (xml_isNode(node, "equip")) {
1542 if (base->equip_env != LUA_NOREF)
1543 WARN(_("Faction '%s' has duplicate 'equip' tag."), base->name);
1544 snprintf( buf, sizeof(buf), FACTIONS_PATH"equip/%s.lua", xml_raw(node) );
1545 base->equip_env = nlua_newEnv();
1547 dat = ndata_read( buf, &ndat );
1548 if (nlua_dobufenv(base->equip_env, dat, ndat, buf) != 0) {
1549 WARN(_("Failed to run equip script: %s\n"
1550 "%s\n"
1551 "Most likely Lua file has improper syntax, please check"),
1552 buf, lua_tostring(naevL, -1));
1553 nlua_freeEnv( base->equip_env );
1554 base->equip_env = LUA_NOREF;
1555 }
1556 free(dat);
1557 continue;
1558 }
1559
1560 /* Grab the allies */
1561 if (xml_isNode(node,"allies")) {
1562 xmlNodePtr cur = node->xmlChildrenNode;
1563 do {
1564 xml_onlyNodes(cur);
1565 if (xml_isNode(cur,"ally")) {
1566 int *tmp = &array_grow( &base->allies );
1567 *tmp = faction_get(xml_get(cur));
1568 }
1569 } while (xml_nextNode(cur));
1570 continue;
1571 }
1572
1573 /* Grab the enemies */
1574 if (xml_isNode(node,"enemies")) {
1575 xmlNodePtr cur = node->xmlChildrenNode;
1576 do {
1577 xml_onlyNodes(cur);
1578 if (xml_isNode(cur,"enemy")) {
1579 int *tmp = &array_grow( &base->enemies );
1580 *tmp = faction_get(xml_get(cur));
1581 }
1582 } while (xml_nextNode(cur));
1583 continue;
1584 }
1585 } while (xml_nextNode(node));
1586
1587 if ((base->lua_env==LUA_NOREF) && !faction_isFlag( base, FACTION_STATIC ))
1588 WARN(_("Faction '%s' has no Lua and isn't static!"), base->name);
1589
1590 xmlFreeDoc(doc);
1591 return 0;
1592}
1593
1598{
1599 for (int i=0; i<array_size(faction_stack); i++) {
1602 }
1603}
1604
1611{
1612#if DEBUGGING
1613 Uint32 time = SDL_GetTicks();
1614#endif /* DEBUGGING */
1615 Faction *f;
1616 char **faction_files = ndata_listRecursive( FACTION_DATA_PATH );
1617
1618 /* player faction is hard-coded */
1620 f = &array_grow( &faction_stack );
1621 memset( f, 0, sizeof(Faction) );
1622 f->name = strdup("Player");
1623 f->flags = FACTION_STATIC | FACTION_INVISIBLE;
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;
1631 f->allies = array_create( int );
1632 f->enemies = array_create( int );
1633
1634 /* Add the base factions. */
1635 for (int i=0; i<array_size(faction_files); i++) {
1636 if (ndata_matchExt( faction_files[i], "xml" )) {
1637 Faction nf;
1638 int ret = faction_parse( &nf, faction_files[i] );
1639 if (ret == 0) {
1640 nf.oflags = nf.flags;
1642 }
1643
1644 /* Render if necessary. */
1646 }
1647 }
1648
1649 /* Sort by name. */
1650 qsort( faction_stack, array_size(faction_stack), sizeof(Faction), faction_cmp );
1651 faction_player = faction_get("Player");
1652
1653 /* Second pass - sets allies and enemies */
1654 for (int i=0; i<array_size(faction_files); i++) {
1655 if (ndata_matchExt( faction_files[i], "xml" )) {
1656 faction_parseSocial( faction_files[i] );
1657 }
1658 }
1659
1660 /* Third pass, Make allies/enemies symmetric. */
1661 for (int i=0; i<array_size(faction_stack); i++) {
1662 f = &faction_stack[i];
1663
1664 /* First run over allies and make sure it's mutual. */
1665 for (int j=0; j < array_size(f->allies); j++) {
1666 const Faction *sf = &faction_stack[ f->allies[j] ];
1667 int r = 0;
1668 for (int k=0; k < array_size(sf->allies); k++)
1669 if (sf->allies[k] == i) {
1670 r = 1;
1671 break;
1672 }
1673
1674 /* Add ally if necessary. */
1675 if (r == 0)
1676 faction_addAlly( f->allies[j], i );
1677 }
1678
1679 /* Now run over enemies. */
1680 for (int j=0; j < array_size(f->enemies); j++) {
1681 const Faction *sf = &faction_stack[ f->enemies[j] ];
1682 int r = 0;
1683 for (int k=0; k < array_size(sf->enemies); k++)
1684 if (sf->enemies[k] == i) {
1685 r = 1;
1686 break;
1687 }
1688
1689 if (r == 0)
1690 faction_addEnemy( f->enemies[j], i );
1691 }
1692 }
1693
1694 /* Clean up stuff. */
1695 for (int i=0; i<array_size(faction_files); i++)
1696 free( faction_files[i] );
1697 array_free( faction_files );
1698
1699 /* Compute grid and finalize. */
1701#if DEBUGGING
1702 if (conf.devmode) {
1703 time = SDL_GetTicks() - time;
1704 DEBUG( n_( "Loaded %d Faction in %.3f s", "Loaded %d Factions in %.3f s", array_size(faction_stack) ), array_size(faction_stack), time/1000. );
1705 }
1706 else
1707 DEBUG( n_( "Loaded %d Faction", "Loaded %d Factions", array_size(faction_stack) ), array_size(faction_stack) );
1708#endif /* DEBUGGING */
1709
1710 return 0;
1711}
1712
1716static void faction_freeOne( Faction *f )
1717{
1718 free(f->name);
1719 free(f->longname);
1720 free(f->displayname);
1721 free(f->mapname);
1722 free(f->description);
1723 free(f->ai);
1724 array_free(f->generators);
1725 gl_freeTexture(f->logo);
1726 array_free(f->allies);
1727 array_free(f->enemies);
1728 nlua_freeEnv( f->sched_env );
1729 nlua_freeEnv( f->lua_env );
1730 if (!faction_isFlag(f, FACTION_DYNAMIC))
1731 nlua_freeEnv( f->equip_env );
1732 for (int i=0; i<array_size(f->tags); i++)
1733 free(f->tags[i]);
1734 array_free(f->tags);
1735}
1736
1740void factions_free (void)
1741{
1742 /* Free factions. */
1743 for (int i=0; i<array_size(faction_stack); i++)
1746 faction_stack = NULL;
1747
1748 /* Clean up faction grid. */
1749 free( faction_grid );
1750 faction_grid = NULL;
1751 faction_mgrid = 0;
1752}
1753
1760int pfaction_save( xmlTextWriterPtr writer )
1761{
1762 xmlw_startElem(writer,"factions");
1763
1764 for (int i=0; i<array_size(faction_stack); i++) { /* player is faction 0 */
1765 /* Must not be static. */
1766 if (faction_isFlag( &faction_stack[i], FACTION_STATIC ))
1767 continue;
1768
1769 xmlw_startElem(writer,"faction");
1770
1771 xmlw_attr(writer,"name","%s",faction_stack[i].name);
1772 xmlw_elem(writer,"standing","%f",faction_stack[i].player);
1773
1774 if (faction_isKnown_(&faction_stack[i]))
1775 xmlw_elemEmpty(writer, "known");
1776
1777 xmlw_endElem(writer); /* "faction" */
1778 }
1779
1780 xmlw_endElem(writer); /* "factions" */
1781
1782 return 0;
1783}
1784
1791int pfaction_load( xmlNodePtr parent )
1792{
1793 xmlNodePtr node = parent->xmlChildrenNode;
1794
1795 do {
1796 if (xml_isNode(node,"factions")) {
1797 xmlNodePtr cur = node->xmlChildrenNode;
1798 do {
1799 if (xml_isNode(cur,"faction")) {
1800 int faction;
1801 char *str;
1802 xmlr_attr_strd(cur, "name", str);
1803 faction = faction_get(str);
1804
1805 if (faction != -1) { /* Faction is valid. */
1806 xmlNodePtr sub = cur->xmlChildrenNode;
1807 do {
1808 if (xml_isNode(sub,"standing")) {
1809
1810 /* Must not be static. */
1811 if (!faction_isFlag( &faction_stack[faction], FACTION_STATIC ))
1812 faction_stack[faction].player = xml_getFloat(sub);
1813 continue;
1814 }
1815 if (xml_isNode(sub,"known")) {
1816 faction_setFlag(&faction_stack[faction], FACTION_KNOWN);
1817 continue;
1818 }
1819 } while (xml_nextNode(sub));
1820 }
1821 free(str);
1822 }
1823 } while (xml_nextNode(cur));
1824 }
1825 } while (xml_nextNode(node));
1826
1827 return 0;
1828}
1829
1836int *faction_getGroup( int which )
1837{
1838 int *group;
1839
1840 switch (which) {
1841 case 0: /* 'all' */
1842 return array_copy( int, faction_stack );
1843
1844 case 1: /* 'friendly' */
1845 group = array_create( int );
1846 for (int i=0; i < array_size(faction_stack); i++)
1847 if (areAllies( FACTION_PLAYER, i ))
1848 array_push_back( &group, i );
1849 return group;
1850
1851 case 2: /* 'neutral' */
1852 group = array_create( int );
1853 for (int i=0; i < array_size(faction_stack); i++)
1854 if (!areAllies( FACTION_PLAYER, i ) && !areEnemies( FACTION_PLAYER, i ))
1855 array_push_back( &group, i );
1856 return group;
1857
1858 case 3: /* 'hostile' */
1859 group = array_create( int );
1860 for (int i=0; i < array_size(faction_stack); i++)
1861 if (areEnemies( FACTION_PLAYER, i ))
1862 array_push_back( &group, i );
1863 return group;
1864
1865 default:
1866 return NULL;
1867 }
1868}
1869
1874{
1875 if (faction_isFaction(f))
1876 return faction_isFlag( &faction_stack[f], FACTION_USESHIDDENJUMPS );
1877 return 0;
1878}
1879
1884{
1885 if (faction_isFaction(f))
1886 return faction_stack[f].generators;
1887 return NULL;
1888}
1889
1894{
1895 for (int i=0; i<array_size(faction_stack); i++) {
1896 Faction *f = &faction_stack[i];
1897 if (faction_isFlag(f, FACTION_DYNAMIC)) {
1898 faction_freeOne( f );
1899 array_erase( &faction_stack, f, f+1 );
1900 i--;
1901 }
1902 }
1904}
1905
1915int faction_dynAdd( int base, const char* name, const char* display, const char* ai, const glColour* colour )
1916{
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 );
1922 f->allies = array_create( int );
1923 f->enemies = array_create( int );
1924 f->equip_env = LUA_NOREF;
1925 f->lua_env = LUA_NOREF;
1926 f->sched_env = LUA_NOREF;
1928 faction_addStandingScript( f, "static" );
1929 if (base>=0) {
1930 Faction *bf = &faction_stack[base];
1931
1932 if (bf->ai!=NULL && f->ai==NULL)
1933 f->ai = strdup( bf->ai );
1934 if (bf->logo!=NULL)
1935 f->logo = gl_dupTexture( bf->logo );
1936
1937 for (int i=0; i<array_size(bf->allies); i++) {
1938 int *tmp = &array_grow( &f->allies );
1939 *tmp = bf->allies[i];
1940 }
1941 for (int i=0; i<array_size(bf->enemies); i++) {
1942 int *tmp = &array_grow( &f->enemies );
1943 *tmp = bf->enemies[i];
1944 }
1945
1946 f->player_def = bf->player_def;
1947 f->player = bf->player;
1948 f->colour = bf->colour;
1949
1950 /* Lua stuff. */
1951 f->equip_env = bf->equip_env;
1952 }
1953
1954 /* Copy colour over if applicable. */
1955 if (colour != NULL)
1956 f->colour = *colour;
1957
1958 /* TODO make this incremental. */
1960
1961 return f-faction_stack;
1962}
1963
1967static void faction_computeGrid (void)
1968{
1969 size_t n = array_size(faction_stack);
1970 if (faction_mgrid < n) {
1971 free( faction_grid );
1972 faction_grid = malloc( n * n * sizeof(int) );
1973 faction_mgrid = n;
1974 }
1975 n = faction_mgrid;
1976 memset( faction_grid, 0, n*n*sizeof(int) );
1977 for (int i=0; i<array_size(faction_stack); i++) {
1978 Faction *fa = &faction_stack[i];
1979 for (int k=0; k<array_size(fa->allies); k++) {
1980 int j = fa->allies[k];
1981#if DEBUGGING
1982 if ((faction_grid[i*n+j] < 0) || (faction_grid[j*n+i]) < 0)
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 );
1984#endif /* DEBUGGING */
1985 faction_grid[i*n+j] = 1;
1986 faction_grid[j*n+i] = 1;
1987 }
1988 for (int k=0; k<array_size(fa->enemies); k++) {
1989 int j = fa->enemies[k];
1990#if DEBUGGING
1991 if ((faction_grid[i*n+j] > 0) || (faction_grid[j*n+i] > 0))
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 );
1993#endif /* DEBUGGING */
1994 faction_grid[i*n+j] = -1;
1995 faction_grid[j*n+i] = -1;
1996 }
1997 }
1998}
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:1129
const char * faction_longname(int f)
Gets the faction's long name (formal, human-readable).
Definition faction.c:348
static void faction_freeOne(Faction *f)
Frees a single faction.
Definition faction.c:1716
const glColour * faction_getColour(int f)
Gets the colour of the faction based on it's standing with the player.
Definition faction.c:1035
int faction_isPlayerEnemy(int f)
Gets whether or not the player is an enemy of the faction.
Definition faction.c:1021
int faction_exists(const char *name)
Checks to see if a faction exists by name.
Definition faction.c:173
const char * faction_default_ai(int f)
Gets the name of the default AI profile for the faction's pilots.
Definition faction.c:399
const int * faction_getEnemies(int f)
Gets the list of enemies of a faction.
Definition faction.c:485
int faction_dynAdd(int base, const char *name, const char *display, const char *ai, const glColour *colour)
Dynamically add a faction.
Definition faction.c:1915
int faction_player
Definition faction.c:47
static int faction_getRaw(const char *name)
Gets a faction ID by name.
Definition faction.c:139
void faction_rmAlly(int f, int o)
Removes an ally from the faction's allies list.
Definition faction.c:703
int faction_isKnown(int id)
Is the faction known?
Definition faction.c:275
char faction_getColourChar(int f)
Gets the faction character associated to its standing with the player.
Definition faction.c:1052
static void faction_modPlayerLua(int f, double mod, const char *source, int secondary)
Mods player using the power of Lua.
Definition faction.c:762
#define FACTION_INVISIBLE
Definition faction.c:37
int faction_isFaction(int f)
Checks whether or not a faction is valid.
Definition faction.c:1277
static size_t faction_mgrid
Definition faction.c:107
static Faction * faction_stack
Definition faction.c:105
const glTexture * faction_logo(int f)
Gets the faction's logo (ideally 256x256).
Definition faction.c:453
nlua_env faction_getEquipper(int f)
Gets the equipper state associated to the faction scheduler.
Definition faction.c:740
#define FACTION_KNOWN
Definition faction.c:38
int factions_load(void)
Loads up all the factions from the data file.
Definition faction.c:1610
void faction_clearEnemy(int f)
Clears all the enemies of a dynamic faction.
Definition faction.c:544
void factions_reset(void)
Resets player standing and flags of factions to default.
Definition faction.c:1597
void faction_rmEnemy(int f, int o)
Removes an enemy from the faction's enemies list.
Definition faction.c:610
int faction_isPlayerFriend(int f)
Gets whether or not the player is a friend of the faction.
Definition faction.c:1009
void faction_setPlayer(int f, double value)
Sets the player's standing with a faction.
Definition faction.c:940
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1227
void factions_clearDynamic(void)
Clears dynamic factions.
Definition faction.c:1893
int * faction_getGroup(int which)
Returns an array of faction ids.
Definition faction.c:1836
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:306
const char * faction_shortname(int f)
Gets a factions short name (human-readable).
Definition faction.c:325
const char * faction_getStandingText(int f)
Gets the player's standing in human readable form.
Definition faction.c:1066
double faction_getPlayer(int f)
Gets the player's standing with a faction.
Definition faction.c:981
int faction_isDynamic(int id)
Is faction dynamic.
Definition faction.c:283
void factions_free(void)
Frees the factions.
Definition faction.c:1740
const int * faction_getAllies(int f)
Gets the list of allies of a faction.
Definition faction.c:515
void faction_modPlayerRaw(int f, double mod)
Modifies the player's standing without affecting others.
Definition faction.c:903
const FactionGenerator * faction_generators(int f)
Gets the faction's generators.
Definition faction.c:1883
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
Definition faction.c:1873
int * faction_getKnown()
Gets all the known factions in an array (array.h).
Definition faction.c:219
int faction_isInvisible(int id)
Is the faction invisible?
Definition faction.c:250
int pfaction_save(xmlTextWriterPtr writer)
Saves player's standings with the factions.
Definition faction.c:1760
const glColour * faction_colour(int f)
Gets the colour of the faction.
Definition faction.c:469
static void faction_sanitizePlayer(Faction *faction)
Sanitizes player faction standing.
Definition faction.c:754
const char * faction_getStandingTextAtValue(int f, double value)
Gets the player's standing in human readable form.
Definition faction.c:1078
void faction_clearAlly(int f)
Clears all the ally of a dynamic faction.
Definition faction.c:637
int pfaction_load(xmlNodePtr parent)
Loads the player's faction standings.
Definition faction.c:1791
#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:438
void faction_modPlayer(int f, double mod, const char *source)
Modifies the player's standing with a faction.
Definition faction.c:843
const char ** faction_tags(int f)
Gets the tags the faction has.
Definition faction.c:414
static int * faction_grid
Definition faction.c:106
static int faction_parseSocial(const char *file)
Parses the social tidbits of a faction: allies and enemies.
Definition faction.c:1468
#define FACTION_USESHIDDENJUMPS
Definition faction.c:40
double faction_getPlayerDef(int f)
Gets the player's default standing with a faction.
Definition faction.c:995
int * faction_getAll(void)
Returns all faction IDs in an array (array.h).
Definition faction.c:195
void faction_modPlayerSingle(int f, double mod, const char *source)
Modifies the player's standing without affecting others.
Definition faction.c:883
static void faction_addStandingScript(Faction *temp, const char *scriptname)
Sets up a standing script for a faction.
Definition faction.c:1431
static int faction_parse(Faction *temp, const char *file)
Parses a single faction, but doesn't set the allies/enemies bit.
Definition faction.c:1291
#define FACTION_DYNAMIC
Definition faction.c:39
int faction_setInvisible(int id, int state)
Sets the faction's invisible state.
Definition faction.c:258
int faction_setKnown(int id, int state)
Sets the factions known state.
Definition faction.c:291
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:426
int * faction_getAllVisible(void)
Returns all non-invisible faction IDs in an array (array.h).
Definition faction.c:207
const char * faction_mapname(int f)
Gets the faction's map name (translated).
Definition faction.c:365
double faction_reputationMax(int f)
Gets the maximum reputation of a faction.
Definition faction.c:1179
void faction_addAlly(int f, int o)
Adds an ally to the faction's allies list.
Definition faction.c:657
nlua_env faction_getScheduler(int f)
Gets the state associated to the faction scheduler.
Definition faction.c:728
static void faction_computeGrid(void)
Computes the faction relationship grid.
Definition faction.c:1967
const char * faction_description(int f)
Gets the faction's description (translated).
Definition faction.c:382
void faction_clearKnown()
Clears the known factions.
Definition faction.c:232
int faction_isStatic(int id)
Is the faction static?
Definition faction.c:242
void faction_addEnemy(int f, int o)
Adds an enemy to the faction's enemies list.
Definition faction.c:564
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:184
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1253
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition hook.c:979
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition naev.c:597
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:365
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:231
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:798
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:920
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:917
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:675
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
Player_t player
Definition player.c:74
void space_factionChange(void)
Mark when a faction changes.
Definition space.c:1392
double weight
Definition faction.h:17
Description of a lane-building faction.
Definition faction.c:54
unsigned int oflags
Definition faction.c:99
unsigned int flags
Definition faction.c:98
glTexture * logo
Definition faction.c:63
glColour colour
Definition faction.c:64
nlua_env equip_env
Definition faction.c:95
double player
Definition faction.c:74
double lane_base_cost
Definition faction.c:89
char * description
Definition faction.c:60
double friendly_at
Definition faction.c:80
FactionGenerator * generators
Definition faction.c:92
double lane_length_per_presence
Definition faction.c:88
nlua_env lua_env
Definition faction.c:81
char * mapname
Definition faction.c:58
char ** tags
Definition faction.c:102
char * longname
Definition faction.c:56
char * ai
Definition faction.c:59
int lua_text_rank
Definition faction.c:83
char * displayname
Definition faction.c:57
int lua_hit
Definition faction.c:82
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:84
char * name
Definition faction.c:55
int lua_reputation_max
Definition faction.c:85
The actual hook parameter.
Definition hook.h:38
HookParamType type
Definition hook.h:39
union HookParam::@25 u
double num
Definition hook.h:41
LuaFaction lf
Definition hook.h:48
int devmode
Definition conf.h:157
Pilot * p
Definition player.h:101
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36