naev 0.12.6
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 "SDL_timer.h"
14
15#include "naev.h"
17
18#include "faction.h"
19
20#include "array.h"
21#include "colour.h"
22#include "hook.h"
23#include "log.h"
24#include "ndata.h"
25#include "nlua.h"
26#include "nlua_system.h"
27#include "nxml.h"
28#include "opengl_tex.h"
29#include "player.h"
30#include "space.h"
31
32#define XML_FACTION_ID "Factions"
33#define XML_FACTION_TAG "faction"
34
35#define FACTION_STATIC \
36 ( 1 << 0 )
37#define FACTION_INVISIBLE \
38 ( 1 << 1 )
39#define FACTION_KNOWN ( 1 << 2 )
40#define FACTION_DYNAMIC ( 1 << 3 )
41#define FACTION_USESHIDDENJUMPS \
42 ( 1 << 4 )
43#define FACTION_REPOVERRIDE ( 1 << 5 ) /* Reputation is being overidden. */
44
45#define faction_setFlag( fa, f ) ( ( fa )->flags |= ( f ) )
46#define faction_rmFlag( fa, f ) ( ( fa )->flags &= ~( f ) )
47#define faction_isFlag( fa, f ) ( ( fa )->flags & ( f ) )
48#define faction_isKnown_( fa ) ( ( fa )->flags & ( FACTION_KNOWN ) )
49
50typedef enum FactionGrid {
51 GRID_NONE = 0,
52 GRID_ENEMIES,
53 GRID_ALLIES,
54 GRID_NEUTRAL,
55} FactionGrid;
56
58
64typedef struct Faction_ {
65 char *name;
66 char *longname;
68 char *mapname;
69 char *ai;
71 double local_th;
72
73 /* Scripts. */
74 char *script_standing;
75 char *script_spawn;
76 char *script_equip;
77
78 /* Graphics. */
80 glColour colour;
81
82 /* Enemies */
83 int *enemies;
84
85 /* Allies */
86 int *allies;
87
88 /* True neutrals. */
89 int *neutrals;
90
91 /* Player information. */
92 double player_def;
93 double player;
94 double override;
95
96 /* Scheduler. */
97 nlua_env sched_env;
98
99 /* Behaviour. */
100 double friendly_at;
101 nlua_env lua_env;
107
108 /* Safe lanes. */
109 double
113
114 /* Presence stuff. */
117
118 /* Equipping. */
119 nlua_env equip_env;
120
121 /* Flags. */
122 unsigned int flags;
123 unsigned int oflags;
124
125 /* Tags. */
126 char **tags;
127} Faction;
128
129static Faction *faction_stack = NULL;
130static int *faction_grid = NULL;
131static size_t faction_mgrid = 0;
132
133/*
134 * Prototypes
135 */
136/* static */
137static int faction_getRaw( const char *name );
138static void faction_freeOne( Faction *f );
139static void faction_sanitizePlayer( Faction *faction );
140static double faction_hitLua( int f, const StarSystem *sys, double mod,
141 const char *source, int secondary,
142 int primary_faction );
143static int faction_parse( Faction *temp, const char *file );
144static int faction_parseSocial( const char *file );
145static void faction_addStandingScript( Faction *temp, const char *scriptname );
146static void faction_computeGrid( void );
147/* externed */
148int pfaction_save( xmlTextWriterPtr writer );
149int pfaction_load( xmlNodePtr parent );
150
151static int faction_cmp( const void *p1, const void *p2 )
152{
153 const Faction *f1 = p1;
154 const Faction *f2 = p2;
155 return strcmp( f1->name, f2->name );
156}
157
164static int faction_getRaw( const char *name )
165{
166 if ( name == NULL )
167 return -1;
168
169 /* Escorts are part of the "player" faction. */
170 if ( strcmp( name, "Escort" ) == 0 )
171 return FACTION_PLAYER;
172
173 if ( name != NULL ) {
174 int i;
175 for ( i = 0; i < array_size( faction_stack ); i++ )
176 if ( strcmp( faction_stack[i].name, name ) == 0 )
177 break;
178
179 if ( i != array_size( faction_stack ) )
180 return i;
181
182 /* Dynamic factions are why we can't have nice things.
183 const Faction f = { .name = (char*)name };
184 Faction *found = bsearch( &f, faction_stack, array_size(faction_stack),
185 sizeof(Faction), faction_cmp ); if (found != NULL) return found -
186 faction_stack;
187 */
188 }
189 return -1;
190}
191
198int faction_exists( const char *name )
199{
200 return faction_getRaw( name ) != -1;
201}
202
209int faction_get( const char *name )
210{
211 int id = faction_getRaw( name );
212 if ( id < 0 )
213 WARN( _( "Faction '%s' not found in stack." ), name );
214 return id;
215}
216
220int *faction_getAll( void )
221{
222 int *f = array_create_size( int, array_size( faction_stack ) );
223 for ( int i = 0; i < array_size( faction_stack ); i++ )
224 array_push_back( &f, i );
225 return f;
226}
227
232{
233 int *f = array_create_size( int, array_size( faction_stack ) );
234 for ( int i = 0; i < array_size( faction_stack ); i++ )
235 if ( !faction_isFlag( &faction_stack[i], FACTION_INVISIBLE ) )
236 array_push_back( &f, i );
237 return f;
238}
239
244{
245 int *f = array_create_size( int, array_size( faction_stack ) );
246 /* Get IDs. */
247 for ( int i = 0; i < array_size( faction_stack ); i++ )
248 if ( !faction_isFlag( &faction_stack[i], FACTION_INVISIBLE ) &&
249 faction_isKnown_( &faction_stack[i] ) )
250 array_push_back( &f, i );
251 return f;
252}
253
258{
259 for ( int i = 0; i < array_size( faction_stack ); i++ )
260 if ( faction_isKnown_( &faction_stack[i] ) )
261 faction_rmFlag( &faction_stack[i], FACTION_KNOWN );
262}
263
267int faction_isStatic( int id )
268{
269 return faction_isFlag( &faction_stack[id], FACTION_STATIC );
270}
271
276{
277 return faction_isFlag( &faction_stack[id], FACTION_INVISIBLE );
278}
279
283int faction_setInvisible( int id, int state )
284{
285 if ( !faction_isFaction( id ) ) {
286 WARN( _( "Faction id '%d' is invalid." ), id );
287 return -1;
288 }
289 if ( state )
290 faction_setFlag( &faction_stack[id], FACTION_INVISIBLE );
291 else
292 faction_rmFlag( &faction_stack[id], FACTION_INVISIBLE );
293
294 return 0;
295}
296
300int faction_isKnown( int id )
301{
302 return faction_isKnown_( &faction_stack[id] );
303}
304
308int faction_isDynamic( int id )
309{
310 return faction_isFlag( &faction_stack[id], FACTION_DYNAMIC );
311}
312
316int faction_setKnown( int id, int state )
317{
318 if ( state )
319 faction_setFlag( &faction_stack[id], FACTION_KNOWN );
320 else
321 faction_rmFlag( &faction_stack[id], FACTION_KNOWN );
322 return 0;
323}
324
331const char *faction_name( int f )
332{
333 if ( !faction_isFaction( f ) ) {
334 WARN( _( "Faction id '%d' is invalid." ), f );
335 return NULL;
336 }
337 /* Don't want player to see their escorts as "Player" faction. */
338 if ( f == FACTION_PLAYER )
339 return "Escort";
340
341 return faction_stack[f].name;
342}
343
350const char *faction_shortname( int f )
351{
352 if ( !faction_isFaction( f ) ) {
353 WARN( _( "Faction id '%d' is invalid." ), f );
354 return NULL;
355 }
356 /* Don't want player to see their escorts as "Player" faction. */
357 if ( f == FACTION_PLAYER )
358 return _( "Escort" );
359
360 /* Possibly get display name. */
361 if ( faction_stack[f].displayname != NULL )
362 return _( faction_stack[f].displayname );
363
364 return _( faction_stack[f].name );
365}
366
373const char *faction_longname( int f )
374{
375 if ( !faction_isFaction( f ) ) {
376 WARN( _( "Faction id '%d' is invalid." ), f );
377 return NULL;
378 }
379 if ( faction_stack[f].longname != NULL )
380 return _( faction_stack[f].longname );
381 return _( faction_stack[f].name );
382}
383
390const char *faction_mapname( int f )
391{
392 if ( !faction_isFaction( f ) ) {
393 WARN( _( "Faction id '%d' is invalid." ), f );
394 return NULL;
395 }
396 if ( faction_stack[f].mapname != NULL )
397 return _( faction_stack[f].mapname );
398 return _( faction_stack[f].name );
399}
400
407const char *faction_description( int f )
408{
409 if ( !faction_isFaction( f ) ) {
410 WARN( _( "Faction id '%d' is invalid." ), f );
411 return NULL;
412 }
413 if ( faction_stack[f].description != NULL )
414 return _( faction_stack[f].description );
415 return NULL;
416}
417
424const char *faction_default_ai( int f )
425{
426 if ( !faction_isFaction( f ) ) {
427 WARN( _( "Faction id '%d' is invalid." ), f );
428 return NULL;
429 }
430 return faction_stack[f].ai;
431}
432
439const char *const *faction_tags( int f )
440{
441 if ( !faction_isFaction( f ) ) {
442 WARN( _( "Faction id '%d' is invalid." ), f );
443 return NULL;
444 }
445 return (const char **)faction_stack[f].tags;
446}
447
453{
454 if ( !faction_isFaction( f ) ) {
455 WARN( _( "Faction id '%d' is invalid." ), f );
456 return 0.;
457 }
458 return faction_stack[f].lane_length_per_presence;
459}
460
465{
466 if ( !faction_isFaction( f ) ) {
467 WARN( _( "Faction id '%d' is invalid." ), f );
468 return 0.;
469 }
470 return faction_stack[f].lane_base_cost;
471}
472
479const glTexture *faction_logo( int f )
480{
481 if ( !faction_isFaction( f ) ) {
482 WARN( _( "Faction id '%d' is invalid." ), f );
483 return NULL;
484 }
485 return faction_stack[f].logo;
486}
487
494const glColour *faction_colour( int f )
495{
496 if ( !faction_isFaction( f ) ) {
497 WARN( _( "Faction id '%d' is invalid." ), f );
498 return NULL;
499 }
500 return &faction_stack[f].colour;
501}
502
509const int *faction_getEnemies( int f )
510{
511 if ( !faction_isFaction( f ) ) {
512 WARN( _( "Faction id '%d' is invalid." ), f );
513 return NULL;
514 }
515
516 /* Player's faction ratings can change, so regenerate each call. */
517 if ( f == FACTION_PLAYER ) {
518 int *enemies = array_create( int );
519
520 for ( int i = 0; i < array_size( faction_stack ); i++ )
521 if ( faction_isPlayerEnemy( i ) ) {
522 int *tmp = &array_grow( &enemies );
523 *tmp = i;
524 }
525
526 array_free( faction_stack[f].enemies );
527 faction_stack[f].enemies = enemies;
528 }
529
530 return faction_stack[f].enemies;
531}
532
539const int *faction_getAllies( int f )
540{
541 if ( !faction_isFaction( f ) ) {
542 WARN( _( "Faction id '%d' is invalid." ), f );
543 return NULL;
544 }
545
546 /* Player's faction ratings can change, so regenerate each call. */
547 if ( f == FACTION_PLAYER ) {
548 int *allies = array_create( int );
549
550 for ( int i = 0; i < array_size( faction_stack ); i++ )
551 if ( faction_isPlayerFriend( i ) ) {
552 int *tmp = &array_grow( &allies );
553 *tmp = i;
554 }
555
556 array_free( faction_stack[f].allies );
557 faction_stack[f].allies = allies;
558 }
559
560 return faction_stack[f].allies;
561}
562
569{
570 Faction *ff;
571 /* Get faction. */
572 if ( faction_isFaction( f ) )
573 ff = &faction_stack[f];
574 else { /* f is invalid */
575 WARN( _( "Faction id '%d' is invalid." ), f );
576 return;
577 }
579 array_end( ff->enemies ) );
581}
582
589void faction_addEnemy( int f, int o )
590{
591 Faction *ff;
592 int *tmp;
593
594 if ( f == o )
595 return;
596
597 if ( faction_isFaction( f ) )
598 ff = &faction_stack[f];
599 else { /* f is invalid */
600 WARN( _( "Faction id '%d' is invalid." ), f );
601 return;
602 }
603
604 if ( !faction_isFaction( o ) ) { /* o is invalid */
605 WARN( _( "Faction id '%d' is invalid." ), o );
606 return;
607 }
608
609 /* player cannot be made an enemy this way */
610 if ( f == FACTION_PLAYER ) {
611 WARN( _( "%d is the player faction" ), f );
612 return;
613 }
614 if ( o == FACTION_PLAYER ) {
615 WARN( _( "%d is the player faction" ), o );
616 return;
617 }
618
619 for ( int i = 0; i < array_size( ff->enemies ); i++ ) {
620 if ( ff->enemies[i] == o )
621 return;
622 }
623
624 tmp = &array_grow( &ff->enemies );
625 *tmp = o;
626
628}
629
636void faction_rmEnemy( int f, int o )
637{
638 Faction *ff;
639
640 if ( f == o )
641 return;
642
643 if ( faction_isFaction( f ) )
644 ff = &faction_stack[f];
645 else { /* f is invalid */
646 WARN( _( "Faction id '%d' is invalid." ), f );
647 return;
648 }
649
650 for ( int i = 0; i < array_size( ff->enemies ); i++ ) {
651 if ( ff->enemies[i] == o ) {
652 array_erase( &ff->enemies, &ff->enemies[i], &ff->enemies[i + 1] );
654 return;
655 }
656 }
657}
658
664void faction_clearAlly( int f )
665{
666 Faction *ff;
667 /* Get faction. */
668 if ( faction_isFaction( f ) )
669 ff = &faction_stack[f];
670 else { /* f is invalid */
671 WARN( _( "Faction id '%d' is invalid." ), f );
672 return;
673 }
674 array_erase( &ff->allies, array_begin( ff->allies ),
675 array_end( ff->allies ) );
677}
678
685void faction_addAlly( int f, int o )
686{
687 Faction *ff;
688 int *tmp;
689
690 if ( f == o )
691 return;
692
693 if ( faction_isFaction( f ) )
694 ff = &faction_stack[f];
695 else { /* f is invalid */
696 WARN( _( "Faction id '%d' is invalid." ), f );
697 return;
698 }
699
700 if ( !faction_isFaction( o ) ) { /* o is invalid */
701 WARN( _( "Faction id '%d' is invalid." ), o );
702 return;
703 }
704
705 /* player cannot be made an ally this way */
706 if ( f == FACTION_PLAYER ) {
707 WARN( _( "%d is the player faction" ), f );
708 return;
709 }
710 if ( o == FACTION_PLAYER ) {
711 WARN( _( "%d is the player faction" ), o );
712 return;
713 }
714
715 for ( int i = 0; i < array_size( ff->allies ); i++ ) {
716 if ( ff->allies[i] == o )
717 return;
718 }
719
720 tmp = &array_grow( &ff->allies );
721 *tmp = o;
722
724}
725
732void faction_rmAlly( int f, int o )
733{
734 Faction *ff;
735
736 if ( f == o )
737 return;
738
739 if ( faction_isFaction( f ) )
740 ff = &faction_stack[f];
741 else { /* f is invalid */
742 WARN( _( "Faction id '%d' is invalid." ), f );
743 return;
744 }
745
746 for ( int i = 0; i < array_size( ff->allies ); i++ ) {
747 if ( ff->allies[i] == o ) {
748 array_erase( &ff->allies, &ff->allies[i], &ff->allies[i + 1] );
750 return;
751 }
752 }
753}
754
758nlua_env faction_getScheduler( int f )
759{
760 if ( !faction_isFaction( f ) ) {
761 WARN( _( "Faction id '%d' is invalid." ), f );
762 return LUA_NOREF;
763 }
764 return faction_stack[f].sched_env;
765}
766
770nlua_env faction_getEquipper( int f )
771{
772 if ( !faction_isFaction( f ) ) {
773 WARN( _( "Faction id '%d' is invalid." ), f );
774 return LUA_NOREF;
775 }
776 return faction_stack[f].equip_env;
777}
778
784static void faction_sanitizePlayer( Faction *faction )
785{
786 faction->player = CLAMP( -100., 100., faction->player );
787}
788
792static double faction_hitLua( int f, const StarSystem *sys, double mod,
793 const char *source, int secondary,
794 int primary_faction )
795{
796 /* Ignore it if player is dead. */
797 if ( player.p == NULL )
798 return 0.;
799
800 Faction *faction = &faction_stack[f];
801
802 /* Make sure it's not static. */
803 if ( faction_isFlag( faction, FACTION_STATIC ) )
804 return 0.;
805
806 /* Overriden, so doesn't budge. */
807 if ( faction_isFlag( faction, FACTION_REPOVERRIDE ) )
808 return 0.;
809
810 /* Set up the function:
811 * standing:hit( sys, amount, source, secondary ) */
812 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_hit );
813 if ( sys != NULL )
814 lua_pushsystem( naevL, sys->id );
815 else
816 lua_pushnil( naevL );
817 lua_pushnumber( naevL, mod );
818 lua_pushstring( naevL, source );
819 lua_pushinteger( naevL, secondary );
820 if ( faction_isFaction( primary_faction ) )
821 lua_pushfaction( naevL, primary_faction );
822 else
823 lua_pushnil( naevL );
824
825 /* Call function. */
826 if ( nlua_pcall( faction->lua_env, 5, 1 ) ) { /* An error occurred. */
827 WARN( _( "Faction '%s': %s" ), faction->name, lua_tostring( naevL, -1 ) );
828 lua_pop( naevL, 1 );
829 return 0.;
830 }
831
832 /* Sanitize just in case. */
833 faction_sanitizePlayer( faction );
834
835 /* Run hook if necessary. */
836 double delta = lua_tonumber( naevL, -1 );
837 lua_pop( naevL, 1 );
838 if ( FABS( delta ) > DOUBLE_TOL ) {
839 HookParam hparam[7];
840 hparam[0].type = HOOK_PARAM_FACTION;
841 hparam[0].u.lf = f;
842 if ( sys != NULL ) {
843 hparam[1].type = HOOK_PARAM_SSYS;
844 hparam[1].u.ls = sys->id;
845 } else
846 hparam[1].type = HOOK_PARAM_NIL;
847 hparam[2].type = HOOK_PARAM_NUMBER;
848 hparam[2].u.num = delta;
849 hparam[3].type = HOOK_PARAM_STRING;
850 hparam[3].u.str = source;
851 hparam[4].type = HOOK_PARAM_NUMBER;
852 hparam[4].u.num = secondary;
853 if ( faction_isFaction( primary_faction ) ) {
854 hparam[5].type = HOOK_PARAM_FACTION;
855 hparam[5].u.lf = primary_faction;
856 } else
857 hparam[5].type = HOOK_PARAM_NIL;
858 hparam[6].type = HOOK_PARAM_SENTINEL;
859 hooks_runParam( "standing", hparam );
860
861 /* Tell space the faction changed. */
863 }
864
865 return delta;
866}
867
871double faction_hit( int f, const StarSystem *sys, double mod,
872 const char *source, int single )
873{
874 double ret;
875 if ( !faction_isFaction( f ) ) {
876 WARN( _( "Faction id '%d' is invalid." ), f );
877 return 0;
878 }
879 const Faction *faction = &faction_stack[f];
880
881 /* Modify faction standing with parent faction. */
882 ret = faction_hitLua( f, sys, mod, source, 0, -1 );
883
884 /* Don't apply secondary hits. */
885 if ( !single ) {
886 /* Now mod allies to a lesser degree */
887 for ( int i = 0; i < array_size( faction->allies ); i++ )
888 /* Modify faction standing */
889 faction_hitLua( faction->allies[i], sys, mod, source, 1, f );
890 /* Now mod enemies */
891 for ( int i = 0; i < array_size( faction->enemies ); i++ )
892 /* Modify faction standing. */
893 faction_hitLua( faction->enemies[i], sys, -mod, source, -1, f );
894 }
895
896 return ret;
897}
898
903double faction_hitTest( int f, const StarSystem *sys, double mod,
904 const char *source )
905{
906 if ( !faction_isFaction( f ) ) {
907 WARN( _( "Faction id '%d' is invalid." ), f );
908 return 0;
909 }
910
911 /* Ignore it if player is dead. */
912 if ( player.p == NULL )
913 return 0.;
914
915 Faction *faction = &faction_stack[f];
916
917 /* Make sure it's not static. */
918 if ( faction_isFlag( faction, FACTION_STATIC ) )
919 return 0.;
920
921 /* Overriden, so doesn't budge. */
922 if ( faction_isFlag( faction, FACTION_REPOVERRIDE ) )
923 return 0.;
924
925 /* Set up the function:
926 * standing:hit( sys, amount, source, secondary ) */
927 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_hit );
928 if ( sys != NULL )
929 lua_pushsystem( naevL, sys->id );
930 else
931 lua_pushnil( naevL );
932 lua_pushnumber( naevL, mod );
933 lua_pushstring( naevL, source );
934 lua_pushinteger( naevL, 0 );
935 lua_pushnil( naevL );
936
937 /* Call function. */
938 if ( nlua_pcall( faction->lua_env, 5, 1 ) ) { /* An error occurred. */
939 WARN( _( "Faction '%s': %s" ), faction->name, lua_tostring( naevL, -1 ) );
940 lua_pop( naevL, 1 );
941 return 0.;
942 }
943
944 /* Sanitize just in case. */
945 faction_sanitizePlayer( faction );
946
947 /* Run hook if necessary. */
948 double delta = lua_tonumber( naevL, -1 );
949 lua_pop( naevL, 1 );
950 return delta;
951}
952
967void faction_modPlayer( int f, double mod, const char *source )
968{
969 Faction *faction;
970
971 if ( !faction_isFaction( f ) ) {
972 WARN( _( "Faction id '%d' is invalid." ), f );
973 return;
974 }
975 faction = &faction_stack[f];
976
977 /* Modify faction standing with parent faction. */
978 faction_hitLua( f, NULL, mod, source, 0, -1 );
979
980 /* Now mod allies to a lesser degree */
981 for ( int i = 0; i < array_size( faction->allies ); i++ )
982 /* Modify faction standing */
983 faction_hitLua( faction->allies[i], NULL, mod, source, 1, f );
984
985 /* Now mod enemies */
986 for ( int i = 0; i < array_size( faction->enemies ); i++ )
987 /* Modify faction standing. */
988 faction_hitLua( faction->enemies[i], NULL, -mod, source, 1, f );
989}
990
1007void faction_modPlayerSingle( int f, double mod, const char *source )
1008{
1009 if ( !faction_isFaction( f ) ) {
1010 WARN( _( "Faction id '%d' is invalid." ), f );
1011 return;
1012 }
1013 faction_hitLua( f, NULL, mod, source, 0, -1 );
1014}
1015
1026void faction_modPlayerRaw( int f, double mod )
1027{
1028 Faction *faction;
1029
1030 /* Ignore it if player is dead. */
1031 if ( player.p == NULL )
1032 return;
1033
1034 if ( !faction_isFaction( f ) ) {
1035 WARN( _( "Faction id '%d' is invalid." ), f );
1036 return;
1037 }
1038
1039 faction = &faction_stack[f];
1040 faction->player += mod;
1041
1042 /* Deprecated so no hook now. */
1043
1044 /* Sanitize just in case. */
1045 faction_sanitizePlayer( faction );
1046
1047 /* Tell space the faction changed. */
1049}
1050
1057void faction_setReputation( int f, double value )
1058{
1059 Faction *faction;
1060 double mod;
1061
1062 /* Ignore it if player is dead. */
1063 if ( player.p == NULL )
1064 return;
1065
1066 if ( !faction_isFaction( f ) ) {
1067 WARN( _( "Faction id '%d' is invalid." ), f );
1068 return;
1069 }
1070 faction = &faction_stack[f];
1071 value = CLAMP( -100., 100.,
1072 value ); /* Gets reset by applying threshold otherwise. */
1073
1074 /* In case of a dynamic faction, we just overwrite. */
1075 if ( faction_isFlag( faction, FACTION_DYNAMIC ) ) {
1076 faction->player = value;
1077 return;
1078 }
1079
1080 /* Make sure it's not static. */
1081 if ( faction_isFlag( faction, FACTION_STATIC ) )
1082 return;
1083
1084 /* Overriden, so doesn't budge. */
1085 if ( faction_isFlag( faction, FACTION_REPOVERRIDE ) )
1086 return;
1087
1088 /* Global and hit. */
1089 mod = value - faction->player;
1090 faction->player = value;
1091
1092 /* Reset local. */
1093 StarSystem *sys_stack = system_getAll();
1094 for ( int j = 0; j < array_size( sys_stack ); j++ ) {
1095 StarSystem *sys = &sys_stack[j];
1096 for ( int k = 0; k < array_size( sys->presence ); k++ ) {
1097 SystemPresence *sp = &sys->presence[k];
1098 if ( sp->faction != f )
1099 continue;
1100 sp->local = value;
1101 }
1102 }
1103
1104 /* Run hook if necessary. */
1105 HookParam hparam[7];
1106 hparam[0].type = HOOK_PARAM_FACTION;
1107 hparam[0].u.lf = f;
1108 hparam[1].type = HOOK_PARAM_NIL;
1109 hparam[2].type = HOOK_PARAM_NUMBER;
1110 hparam[2].u.num = mod;
1111 hparam[3].type = HOOK_PARAM_STRING;
1112 hparam[3].u.str = "script";
1113 hparam[4].type = HOOK_PARAM_NUMBER;
1114 hparam[4].u.num = 0;
1115 hparam[5].type = HOOK_PARAM_NIL;
1116 hparam[6].type = HOOK_PARAM_SENTINEL;
1117 hooks_runParam( "standing", hparam );
1118
1119 /* Tell space the faction changed. */
1121}
1122
1129double faction_reputation( int f )
1130{
1131 if ( faction_isFaction( f ) ) {
1132 const Faction *fac = &faction_stack[f];
1133 if ( faction_isFlag( fac, FACTION_REPOVERRIDE ) )
1134 return fac->override;
1135 else
1136 return round( fac->player );
1137 }
1138 WARN( _( "Faction id '%d' is invalid." ), f );
1139 return -1000.;
1140}
1141
1149{
1150 if ( faction_isFaction( f ) )
1151 return faction_stack[f].player_def;
1152 WARN( _( "Faction id '%d' is invalid." ), f );
1153 return -1000.;
1154}
1155
1163{
1164 const Faction *faction = &faction_stack[f];
1165 return ( faction_reputation( f ) >= faction->friendly_at );
1166}
1167int faction_isPlayerFriendSystem( int f, const StarSystem *sys )
1168{
1169 const Faction *faction = &faction_stack[f];
1170 return ( system_getReputationOrGlobal( sys, f ) >= faction->friendly_at );
1171}
1172
1180{
1181 return ( faction_reputation( f ) < 0. );
1182}
1183int faction_isPlayerEnemySystem( int f, const StarSystem *sys )
1184{
1185 return ( system_getReputationOrGlobal( sys, f ) < 0 );
1186}
1187
1196const glColour *faction_reputationColour( int f )
1197{
1198 if ( f < 0 )
1199 return &cInert;
1200 else if ( areAllies( FACTION_PLAYER, f ) )
1201 return &cFriend;
1202 else if ( areEnemies( FACTION_PLAYER, f ) )
1203 return &cHostile;
1204 else
1205 return &cNeutral;
1206}
1207const glColour *faction_reputationColourSystem( int f, const StarSystem *sys )
1208{
1209 if ( f < 0 )
1210 return &cInert;
1211 else if ( areAlliesSystem( FACTION_PLAYER, f, sys ) )
1212 return &cFriend;
1213 else if ( areEnemiesSystem( FACTION_PLAYER, f, sys ) )
1214 return &cHostile;
1215 else
1216 return &cNeutral;
1217}
1218
1229{
1230 if ( f < 0 )
1231 return 'I';
1232 else if ( areEnemies( FACTION_PLAYER, f ) )
1233 return 'H';
1234 else if ( areAllies( FACTION_PLAYER, f ) )
1235 return 'F';
1236 else
1237 return 'N';
1238}
1239char faction_reputationColourCharSystem( int f, const StarSystem *sys )
1240{
1241 if ( f < 0 )
1242 return 'I';
1243 else if ( areEnemiesSystem( FACTION_PLAYER, f, sys ) )
1244 return 'H';
1245 else if ( areAlliesSystem( FACTION_PLAYER, f, sys ) )
1246 return 'F';
1247 else
1248 return 'N';
1249}
1250
1257const char *faction_getStandingText( int f )
1258{
1260}
1261
1269const char *faction_getStandingTextAtValue( int f, double value )
1270{
1271 Faction *faction;
1272
1273 /* Ignore it if player is dead. */
1274 if ( player.p == NULL )
1275 return _( "???" );
1276
1277 /* Escorts always have the same standing. */
1278 if ( f == FACTION_PLAYER )
1279 return _( "Escort" );
1280
1281 faction = &faction_stack[f];
1282
1283 if ( faction->lua_env == LUA_NOREF )
1284 return _( "???" );
1285 else {
1286 const char *r;
1287 /* Set up the method:
1288 * standing:text_rank( standing ) */
1289 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_text_rank );
1290 lua_pushnumber( naevL, round( value ) );
1291
1292 /* Call function. */
1293 if ( nlua_pcall( faction->lua_env, 1, 1 ) ) {
1294 /* An error occurred. */
1295 WARN( _( "Faction '%s': %s" ), faction->name,
1296 lua_tostring( naevL, -1 ) );
1297 lua_pop( naevL, 1 );
1298 return _( "???" );
1299 }
1300
1301 /* Parse return. */
1302 if ( !lua_isstring( naevL, -1 ) ) {
1303 WARN(
1304 _( "Lua script for faction '%s' did not return a %s from '%s'." ),
1305 faction->name, _( "string" ), "text_rank" );
1306 r = _( "???" );
1307 } else
1308 r = lua_tostring( naevL, -1 ); /* Should be translated already. */
1309 lua_pop( naevL, 1 );
1310 return r;
1311 }
1312}
1313
1322const char *faction_getStandingBroad( int f, int bribed, int override )
1323{
1324 Faction *faction;
1325 const char *r;
1326
1327 /* Ignore it if player is dead. */
1328 if ( player.p == NULL )
1329 return _( "???" );
1330
1331 /* Escorts always have the same standing. */
1332 if ( f == FACTION_PLAYER )
1333 return _( "Escort" );
1334
1335 faction = &faction_stack[f];
1336
1337 if ( faction->lua_env == LUA_NOREF )
1338 return _( "???" );
1339
1340 /* Set up the method:
1341 * standing:text_broad( standing, bribed, override ) */
1342 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_text_broad );
1343 lua_pushnumber( naevL, ( faction_isFlag( faction, FACTION_REPOVERRIDE )
1344 ? faction->override
1345 : faction->player ) );
1346 lua_pushboolean( naevL, bribed );
1347 lua_pushinteger( naevL, override );
1348
1349 /* Call function. */
1350 if ( nlua_pcall( faction->lua_env, 3, 1 ) ) {
1351 /* An error occurred. */
1352 WARN( _( "Faction '%s': %s" ), faction->name, lua_tostring( naevL, -1 ) );
1353 lua_pop( naevL, 1 );
1354 return _( "???" );
1355 }
1356
1357 /* Parse return. */
1358 if ( !lua_isstring( naevL, -1 ) ) {
1359 WARN( _( "Lua script for faction '%s' did not return a %s from '%s'." ),
1360 faction->name, _( "string" ), "text_broad" );
1361 r = _( "???" );
1362 } else
1363 r = lua_tostring( naevL, -1 );
1364 lua_pop( naevL, 1 );
1365 return r;
1366}
1367
1375{
1376 Faction *faction;
1377 double r;
1378
1379 /* Ignore it if player is dead. */
1380 if ( player.p == NULL )
1381 return 0.;
1382
1383 /* Escorts always have the same standing. */
1384 if ( f == FACTION_PLAYER )
1385 return 100.;
1386
1387 faction = &faction_stack[f];
1388
1389 if ( faction->lua_env == LUA_NOREF )
1390 return 0.;
1391
1392 /* Set up the method:
1393 * standing:reputation_max( standing ) */
1394 lua_rawgeti( naevL, LUA_REGISTRYINDEX, faction->lua_reputation_max );
1395
1396 /* Call function. */
1397 if ( nlua_pcall( faction->lua_env, 0, 1 ) ) {
1398 /* An error occurred. */
1399 WARN( _( "Faction '%s': %s" ), faction->name, lua_tostring( naevL, -1 ) );
1400 lua_pop( naevL, 1 );
1401 return 0.;
1402 }
1403
1404 /* Parse return. */
1405 if ( !lua_isnumber( naevL, -1 ) ) {
1406 WARN( _( "Lua script for faction '%s' did not return a %s from '%s'." ),
1407 faction->name, _( "number" ), "reputation_max" );
1408 r = 0.;
1409 } else
1410 r = lua_tonumber( naevL, -1 );
1411 lua_pop( naevL, 1 );
1412 return r;
1413}
1414
1424int areNeutral( int a, int b )
1425{
1426 /* luckily our factions aren't masochistic */
1427 if ( a == b )
1428 return 0;
1429
1430 /* Make sure they're valid. */
1431 if ( !faction_isFaction( a ) || !faction_isFaction( b ) )
1432 return 0;
1433
1434 /* player handled separately */
1435 if ( a == FACTION_PLAYER )
1436 return 0;
1437 else if ( b == FACTION_PLAYER )
1438 return 0;
1439
1440 return faction_grid[a * faction_mgrid + b] == GRID_NEUTRAL;
1441}
1442
1450int areEnemies( int a, int b )
1451{
1452 /* luckily our factions aren't masochistic */
1453 if ( a == b )
1454 return 0;
1455
1456 /* Make sure they're valid. */
1457 if ( !faction_isFaction( a ) || !faction_isFaction( b ) )
1458 return 0;
1459
1460 /* player handled separately */
1461 if ( a == FACTION_PLAYER )
1462 return faction_isPlayerEnemy( b );
1463 else if ( b == FACTION_PLAYER )
1464 return faction_isPlayerEnemy( a );
1465
1466 return faction_grid[a * faction_mgrid + b] == GRID_ENEMIES;
1467}
1468
1476int areAllies( int a, int b )
1477{
1478 /* If they are the same they must be allies. */
1479 if ( a == b )
1480 return 1;
1481
1482 /* Make sure they're valid. */
1483 if ( !faction_isFaction( a ) || !faction_isFaction( b ) )
1484 return 0;
1485
1486 /* we assume player becomes allies with high rating */
1487 if ( a == FACTION_PLAYER )
1488 return faction_isPlayerFriend( b );
1489 else if ( b == FACTION_PLAYER )
1490 return faction_isPlayerFriend( a );
1491
1492 return faction_grid[a * faction_mgrid + b] == GRID_ALLIES;
1493}
1494
1495int areEnemiesSystem( int a, int b, const StarSystem *sys )
1496{
1497 /* luckily our factions aren't masochistic */
1498 if ( a == b )
1499 return 0;
1500
1501 /* Make sure they're valid. */
1502 if ( !faction_isFaction( a ) || !faction_isFaction( b ) )
1503 return 0;
1504
1505 /* player handled separately */
1506 if ( a == FACTION_PLAYER )
1507 return faction_isPlayerEnemySystem( b, sys );
1508 else if ( b == FACTION_PLAYER )
1509 return faction_isPlayerEnemySystem( a, sys );
1510
1511 return faction_grid[a * faction_mgrid + b] == GRID_ENEMIES;
1512}
1513
1514int areAlliesSystem( int a, int b, const StarSystem *sys )
1515{
1516 /* If they are the same they must be allies. */
1517 if ( a == b )
1518 return 1;
1519
1520 /* Make sure they're valid. */
1521 if ( !faction_isFaction( a ) || !faction_isFaction( b ) )
1522 return 0;
1523
1524 /* we assume player becomes allies with high rating */
1525 if ( a == FACTION_PLAYER )
1526 return faction_isPlayerFriendSystem( b, sys );
1527 else if ( b == FACTION_PLAYER )
1528 return faction_isPlayerFriendSystem( a, sys );
1529
1530 return faction_grid[a * faction_mgrid + b] == GRID_ALLIES;
1531}
1532
1540{
1541 if ( ( f < 0 ) || ( f >= array_size( faction_stack ) ) )
1542 return 0;
1543 return 1;
1544}
1545
1553static int faction_parse( Faction *temp, const char *file )
1554{
1555 xmlNodePtr node, parent;
1556 int saw_player;
1557
1558 xmlDocPtr doc = xml_parsePhysFS( file );
1559 if ( doc == NULL )
1560 return -1;
1561
1562 parent = doc->xmlChildrenNode; /* first faction node */
1563 if ( parent == NULL ) {
1564 WARN( _( "Malformed '%s' file: does not contain elements" ), file );
1565 return -1;
1566 }
1567
1568 /* Clear memory. */
1569 memset( temp, 0, sizeof( Faction ) );
1570 temp->local_th = 10.;
1571 temp->equip_env = LUA_NOREF;
1572 temp->sched_env = LUA_NOREF;
1573 temp->lua_env = LUA_NOREF;
1574 temp->lua_hit = LUA_NOREF;
1575 temp->lua_hit_test = LUA_NOREF;
1576 temp->lua_text_rank = LUA_NOREF;
1577 temp->lua_text_broad = LUA_NOREF;
1578 temp->lua_reputation_max = LUA_NOREF;
1579
1580 xmlr_attr_strd( parent, "name", temp->name );
1581 if ( temp->name == NULL )
1582 WARN( _( "Faction from file '%s' has no name!" ), file );
1583
1584 saw_player = 0;
1585 node = parent->xmlChildrenNode;
1586 do {
1587 /* Only care about nodes. */
1588 xml_onlyNodes( node );
1589
1590 /* Can be 0 or negative, so we have to take that into account. */
1591 if ( xml_isNode( node, "player" ) ) {
1592 temp->player_def = xml_getFloat( node );
1593 saw_player = 1;
1594 continue;
1595 }
1596
1597 xmlr_strd( node, "longname", temp->longname );
1598 xmlr_strd( node, "display", temp->displayname );
1599 xmlr_strd( node, "mapname", temp->mapname );
1600 xmlr_strd( node, "description", temp->description );
1601 xmlr_strd( node, "ai", temp->ai );
1602 xmlr_float( node, "local_th", temp->local_th );
1603 xmlr_float( node, "lane_length_per_presence",
1605 xmlr_float( node, "lane_base_cost", temp->lane_base_cost );
1606 if ( xml_isNode( node, "colour" ) ) {
1607 const char *ctmp = xml_get( node );
1608 if ( ctmp != NULL ) {
1609 const glColour *c = col_fromName( xml_raw( node ) );
1610 if ( c != NULL )
1611 temp->colour = *c;
1612 else
1613 WARN( _( "Faction '%s' has invalid colour '%s'!" ), temp->name,
1614 ctmp );
1615 }
1616 /* If no named colour is present, RGB attributes are used. */
1617 else {
1618 /* Initialize in case a colour channel is absent. */
1619 xmlr_attr_float( node, "r", temp->colour.r );
1620 xmlr_attr_float( node, "g", temp->colour.g );
1621 xmlr_attr_float( node, "b", temp->colour.b );
1622 temp->colour.a = 1.;
1623 col_gammaToLinear( &temp->colour );
1624 }
1625 continue;
1626 }
1627
1628 if ( xml_isNode( node, "known" ) ) {
1629 faction_setFlag( temp, FACTION_KNOWN );
1630 continue;
1631 }
1632
1633 if ( xml_isNode( node, "logo" ) ) {
1634 char buf[PATH_MAX];
1635 if ( temp->logo != NULL ) {
1636 WARN( _( "Faction '%s' has duplicate 'logo' tag." ), temp->name );
1637 continue;
1638 }
1639 snprintf( buf, sizeof( buf ), FACTION_LOGO_PATH "%s.webp",
1640 xml_get( node ) );
1641 temp->logo = gl_newImage( buf, 0 );
1642 continue;
1643 }
1644
1645 if ( xml_isNode( node, "static" ) ) {
1646 faction_setFlag( temp, FACTION_STATIC );
1647 continue;
1648 }
1649
1650 if ( xml_isNode( node, "invisible" ) ) {
1651 faction_setFlag( temp, FACTION_INVISIBLE );
1652 continue;
1653 }
1654
1655 if ( xml_isNode( node, "useshiddenjumps" ) ) {
1656 faction_setFlag( temp, FACTION_USESHIDDENJUMPS );
1657 continue;
1658 }
1659
1660 if ( xml_isNode( node, "tags" ) ) {
1661 xmlNodePtr cur = node->children;
1662 if ( temp->tags != NULL )
1663 WARN( _( "Faction '%s' has duplicate '%s' node!" ), temp->name,
1664 "tags" );
1665 else
1666 temp->tags = array_create( char * );
1667 do {
1668 xml_onlyNodes( cur );
1669 if ( xml_isNode( cur, "tag" ) ) {
1670 const char *tmp = xml_get( cur );
1671 if ( tmp != NULL )
1672 array_push_back( &temp->tags, strdup( tmp ) );
1673 continue;
1674 }
1675 WARN( _( "Faction '%s' has unknown node in tags '%s'." ),
1676 temp->name, cur->name );
1677 } while ( xml_nextNode( cur ) );
1678 continue;
1679 }
1680
1681#if DEBUGGING
1682 /* Avoid warnings. */
1683 if ( xml_isNode( node, "allies" ) || xml_isNode( node, "enemies" ) ||
1684 xml_isNode( node, "neutrals" ) || xml_isNode( node, "generator" ) ||
1685 xml_isNode( node, "standing" ) || xml_isNode( node, "spawn" ) ||
1686 xml_isNode( node, "equip" ) )
1687 continue;
1688 WARN( _( "Unknown node '%s' in faction '%s'" ), node->name, temp->name );
1689#endif /* DEBUGGING */
1690
1691 } while ( xml_nextNode( node ) );
1692
1693 if ( !saw_player )
1694 WARN( _( "Faction '%s' missing 'player' tag." ), temp->name );
1695 if ( faction_isKnown_( temp ) &&
1696 !faction_isFlag( temp, FACTION_INVISIBLE ) &&
1697 temp->description == NULL )
1698 WARN( _( "Faction '%s' is known but missing 'description' tag." ),
1699 temp->name );
1700
1701 xmlFreeDoc( doc );
1702
1703 return 0;
1704}
1705
1712static void faction_addStandingScript( Faction *temp, const char *scriptname )
1713{
1714 char buf[PATH_MAX], *dat;
1715 size_t ndat;
1716
1717 snprintf( buf, sizeof( buf ), FACTIONS_PATH "standing/%s.lua", scriptname );
1718 temp->lua_env = nlua_newEnv( temp->name );
1719
1720 nlua_loadStandard( temp->lua_env );
1721 dat = ndata_read( buf, &ndat );
1722 if ( nlua_dobufenv( temp->lua_env, dat, ndat, buf ) != 0 ) {
1723 WARN( _( "Failed to run standing script: %s\n"
1724 "%s\n"
1725 "Most likely Lua file has improper syntax, please check" ),
1726 buf, lua_tostring( naevL, -1 ) );
1727 nlua_freeEnv( temp->lua_env );
1728 temp->lua_env = LUA_NOREF;
1729 free( dat );
1730 lua_pop( naevL, 1 );
1731 return;
1732 }
1733 free( dat );
1734
1735 /* Set up the references. */
1736 temp->lua_hit = nlua_refenvtype( temp->lua_env, "hit", LUA_TFUNCTION );
1737 temp->lua_hit_test =
1738 nlua_refenvtype( temp->lua_env, "hit_test", LUA_TFUNCTION );
1739 temp->lua_text_broad =
1740 nlua_refenvtype( temp->lua_env, "text_broad", LUA_TFUNCTION );
1741 temp->lua_text_rank =
1742 nlua_refenvtype( temp->lua_env, "text_rank", LUA_TFUNCTION );
1743 temp->lua_reputation_max =
1744 nlua_refenvtype( temp->lua_env, "reputation_max", LUA_TFUNCTION );
1745
1746 nlua_getenv( naevL, temp->lua_env, "friendly_at" );
1747 temp->friendly_at = lua_tonumber( naevL, -1 );
1748 lua_pop( naevL, 1 );
1749}
1750
1757static int faction_parseSocial( const char *file )
1758{
1759 char *name;
1760 xmlNodePtr node, parent;
1761 Faction *base;
1762
1763 xmlDocPtr doc = xml_parsePhysFS( file );
1764 if ( doc == NULL )
1765 return -1;
1766
1767 parent = doc->xmlChildrenNode; /* first faction node */
1768 if ( parent == NULL ) {
1769 WARN( _( "Malformed '%s' file: does not contain elements" ), file );
1770 return -1;
1771 }
1772
1773 /* Get name. */
1774 base = NULL;
1775 xmlr_attr_strd( parent, "name", name );
1776 if ( name != NULL )
1777 base = &faction_stack[faction_get( name )];
1778 free( name );
1779 name = NULL;
1780
1781 assert( base != NULL );
1782
1783 /* Create arrays, not much memory so it doesn't really matter. */
1784 base->allies = array_create( int );
1785 base->enemies = array_create( int );
1786 base->neutrals = array_create( int );
1787
1788 /* Parse social stuff. */
1789 node = parent->xmlChildrenNode;
1790 do {
1791 xml_onlyNodes( node );
1792
1793 if ( xml_isNode( node, "generator" ) ) {
1794 FactionGenerator *fg;
1795 if ( base->generators == NULL )
1797 fg = &array_grow( &base->generators );
1798 xmlr_attr_float( node, "weight", fg->weight );
1799 fg->id = faction_get( xml_get( node ) );
1800 continue;
1801 }
1802
1803 /* Load script paths. */
1804 xmlr_strd( node, "standing", base->script_standing );
1805 xmlr_strd( node, "spawn", base->script_spawn );
1806 xmlr_strd( node, "equip", base->script_equip );
1807
1808 /* Grab the allies */
1809 if ( xml_isNode( node, "allies" ) ) {
1810 xmlNodePtr cur = node->xmlChildrenNode;
1811 do {
1812 xml_onlyNodes( cur );
1813 if ( xml_isNode( cur, "ally" ) ) {
1814 int fct = faction_get( xml_get( cur ) );
1815 if ( faction_isFaction( fct ) )
1816 array_push_back( &base->allies, fct );
1817 }
1818 } while ( xml_nextNode( cur ) );
1819 continue;
1820 }
1821
1822 /* Grab the enemies. */
1823 if ( xml_isNode( node, "enemies" ) ) {
1824 xmlNodePtr cur = node->xmlChildrenNode;
1825 do {
1826 xml_onlyNodes( cur );
1827 if ( xml_isNode( cur, "enemy" ) ) {
1828 int fct = faction_get( xml_get( cur ) );
1829 if ( faction_isFaction( fct ) )
1830 array_push_back( &base->enemies, fct );
1831 }
1832 } while ( xml_nextNode( cur ) );
1833 continue;
1834 }
1835
1836 /* Grab the true neutral. */
1837 if ( xml_isNode( node, "neutrals" ) ) {
1838 xmlNodePtr cur = node->xmlChildrenNode;
1839 do {
1840 xml_onlyNodes( cur );
1841 if ( xml_isNode( cur, "neutral" ) ) {
1842 int fct = faction_get( xml_get( cur ) );
1843 if ( faction_isFaction( fct ) )
1844 array_push_back( &base->neutrals, fct );
1845 }
1846 } while ( xml_nextNode( cur ) );
1847 continue;
1848 }
1849 } while ( xml_nextNode( node ) );
1850
1851 xmlFreeDoc( doc );
1852 return 0;
1853}
1854
1858void factions_reset( void )
1859{
1861
1862 /* Reset global standing. */
1863 for ( int i = 0; i < array_size( faction_stack ); i++ ) {
1864 faction_stack[i].player = faction_stack[i].player_def;
1865 faction_stack[i].flags = faction_stack[i].oflags;
1866 }
1868}
1869
1874{
1875 StarSystem *sys_stack = system_getAll();
1876 for ( int i = 0; i < array_size( sys_stack ); i++ ) {
1877 StarSystem *sys = &sys_stack[i];
1878 for ( int j = 0; j < array_size( sys->presence ); j++ ) {
1879 SystemPresence *sp = &sys->presence[j];
1880 sp->local = faction_reputation( sp->faction );
1881 }
1882 }
1883 // faction_updateGlobal();
1884}
1885
1886void faction_updateSingle( int f )
1887{
1888 int n = 0;
1889 double v = 0.;
1890 StarSystem *sys_stack = system_getAll();
1891 for ( int j = 0; j < array_size( sys_stack ); j++ ) {
1892 StarSystem *sys = &sys_stack[j];
1893 for ( int k = 0; k < array_size( sys->presence ); k++ ) {
1894 SystemPresence *sp = &sys->presence[k];
1895 if ( sp->faction != f )
1896 continue;
1897 v += sp->local;
1898 n++;
1899 }
1900 }
1901 faction_stack[f].player = v / (double)n;
1902}
1903
1908{
1909 for ( int i = 0; i < array_size( faction_stack ); i++ )
1910 faction_updateSingle( i );
1911}
1912
1913void faction_applyLocalThreshold( int f, StarSystem *sys )
1914{
1915 SystemPresence *srep =
1916 system_getFactionPresence( sys, f ); /* Starting reputation. */
1917 if ( srep == NULL )
1918 return;
1919
1920#if DEBUGGING
1921 if ( srep->value <= 0. ) {
1922 WARN( "Trying to apply local faction threshold from system with no "
1923 "presence." );
1924 return;
1925 }
1926#endif /* DEBUGGING */
1927
1928 double n = 0;
1929 double rep = srep->local;
1930 StarSystem *sys_stack = system_getAll();
1931 double th = faction_stack[f].local_th;
1932 /* TODO avoid a memory allocation every call. */
1933 int *done = array_create( int );
1934 int *queuea = array_create( int );
1935 int *queueb = array_create( int );
1936
1937 array_push_back( &queuea, sys->id );
1938 array_push_back( &done, sys->id );
1939 while ( array_size( queuea ) > 0 ) {
1940 /* Go backwards through queue. */
1941 for ( int i = 0; i < array_size( queuea ); i++ ) {
1942 StarSystem *qsys = &sys_stack[queuea[i]];
1943
1944 /* Update local presence. */
1945 srep = system_getFactionPresence( qsys, f );
1946 if ( srep != NULL )
1947 srep->local = CLAMP( MAX( rep - n * th, -100 ),
1948 MIN( rep + n * th, 100 ), srep->local );
1949
1950 /* Propagate to next systems. */
1951 for ( int j = 0; j < array_size( qsys->jumps ); j++ ) {
1952 StarSystem *nsys = qsys->jumps[j].target;
1953 int found = 0;
1954 /* Ignore systems already looked at. */
1955 for ( int k = 0; k < array_size( done ); k++ ) {
1956 if ( nsys->id == done[k] ) {
1957 found = 1;
1958 break;
1959 }
1960 }
1961 if ( found )
1962 continue;
1963 /* We only process systems that have presence. No presence systems
1964 * will act as a buffer. */
1965 if ( system_getPresence( nsys, f ) > 0. )
1966 array_push_back( &queueb, nsys->id );
1967 array_push_back( &done, nsys->id );
1968 }
1969 }
1970 array_erase( &queuea, array_begin( queuea ), array_end( queuea ) );
1971
1972 /* Increment distance. */
1973 n++;
1974
1975 /* Flip buffers. */
1976 int *queue = queuea;
1977 queuea = queueb;
1978 queueb = queue;
1979 }
1980
1981 array_free( done );
1982 array_free( queuea );
1983 array_free( queueb );
1984
1985 /* Update global standing. */
1986 faction_updateSingle( f );
1987}
1988
1994int factions_load( void )
1995{
1996#if DEBUGGING
1997 Uint32 time = SDL_GetTicks();
1998#endif /* DEBUGGING */
1999 Faction *f;
2000 char **faction_files = ndata_listRecursive( FACTION_DATA_PATH );
2001
2002 /* player faction is hard-coded */
2004 f = &array_grow( &faction_stack );
2005 memset( f, 0, sizeof( Faction ) );
2006 f->name = strdup( "Player" );
2007 f->flags = FACTION_STATIC | FACTION_INVISIBLE;
2008 f->equip_env = LUA_NOREF;
2009 f->sched_env = LUA_NOREF;
2010 f->lua_env = LUA_NOREF;
2011 f->lua_hit = LUA_NOREF;
2012 f->lua_hit_test = LUA_NOREF;
2013 f->lua_text_rank = LUA_NOREF;
2014 f->lua_text_broad = LUA_NOREF;
2015 f->lua_reputation_max = LUA_NOREF;
2016 f->allies = array_create( int );
2017 f->enemies = array_create( int );
2018
2019 /* Add the base factions. */
2020 for ( int i = 0; i < array_size( faction_files ); i++ ) {
2021 if ( ndata_matchExt( faction_files[i], "xml" ) ) {
2022 Faction nf;
2023 int ret = faction_parse( &nf, faction_files[i] );
2024 if ( ret == 0 ) {
2025 nf.oflags = nf.flags;
2027 }
2028
2029 /* Render if necessary. */
2031 }
2032 }
2033
2034 /* Sort by name. */
2035 qsort( faction_stack, array_size( faction_stack ), sizeof( Faction ),
2036 faction_cmp );
2037 faction_player = faction_get( "Player" );
2038
2039 /* Second pass - sets allies and enemies */
2040 for ( int i = 0; i < array_size( faction_files ); i++ ) {
2041 if ( ndata_matchExt( faction_files[i], "xml" ) ) {
2042 faction_parseSocial( faction_files[i] );
2043 }
2044 }
2045
2046 /* Third pass, Make allies/enemies symmetric. */
2047 for ( int i = 0; i < array_size( faction_stack ); i++ ) {
2048 f = &faction_stack[i];
2049
2050 /* First run over allies and make sure it's mutual. */
2051 for ( int j = 0; j < array_size( f->allies ); j++ ) {
2052 const Faction *sf = &faction_stack[f->allies[j]];
2053 int r = 0;
2054 for ( int k = 0; k < array_size( sf->allies ); k++ )
2055 if ( sf->allies[k] == i ) {
2056 r = 1;
2057 break;
2058 }
2059
2060 /* Add ally if necessary. */
2061 if ( r == 0 )
2062 faction_addAlly( f->allies[j], i );
2063 }
2064
2065 /* Now run over enemies. */
2066 for ( int j = 0; j < array_size( f->enemies ); j++ ) {
2067 const Faction *sf = &faction_stack[f->enemies[j]];
2068 int r = 0;
2069 for ( int k = 0; k < array_size( sf->enemies ); k++ )
2070 if ( sf->enemies[k] == i ) {
2071 r = 1;
2072 break;
2073 }
2074
2075 if ( r == 0 )
2076 faction_addEnemy( f->enemies[j], i );
2077 }
2078 }
2079
2080 /* Clean up stuff. */
2081 for ( int i = 0; i < array_size( faction_files ); i++ )
2082 free( faction_files[i] );
2083 array_free( faction_files );
2084
2085 /* Compute grid and finalize. */
2087#if DEBUGGING
2088 if ( conf.devmode ) {
2089 time = SDL_GetTicks() - time;
2090 DEBUG( n_( "Loaded %d Faction in %.3f s", "Loaded %d Factions in %.3f s",
2092 array_size( faction_stack ), time / 1000. );
2093 } else
2094 DEBUG( n_( "Loaded %d Faction", "Loaded %d Factions",
2097#endif /* DEBUGGING */
2098
2099 return 0;
2100}
2101
2102void factions_loadPost( void )
2103{
2104 for ( int i = 0; i < array_size( faction_stack ); i++ ) {
2105 Faction *f = &faction_stack[i];
2106
2107 /* Standing scripts. */
2108 if ( f->script_standing != NULL )
2109 faction_addStandingScript( f, f->script_standing );
2110
2111 if ( f->script_spawn != NULL ) {
2112 char buf[PATH_MAX], *dat;
2113 size_t ndat;
2114
2115 snprintf( buf, sizeof( buf ), FACTIONS_PATH "spawn/%s.lua",
2116 f->script_spawn );
2117 f->sched_env = nlua_newEnv( buf );
2118 nlua_loadStandard( f->sched_env );
2119 dat = ndata_read( buf, &ndat );
2120 if ( nlua_dobufenv( f->sched_env, dat, ndat, buf ) != 0 ) {
2121 WARN( _( "Failed to run spawn script: %s\n"
2122 "%s\n"
2123 "Most likely Lua file has improper syntax, please check" ),
2124 buf, lua_tostring( naevL, -1 ) );
2125 nlua_freeEnv( f->sched_env );
2126 f->sched_env = LUA_NOREF;
2127 }
2128 free( dat );
2129 }
2130
2131 if ( f->script_equip != NULL ) {
2132 char buf[PATH_MAX], *dat;
2133 size_t ndat;
2134
2135 snprintf( buf, sizeof( buf ), FACTIONS_PATH "equip/%s.lua",
2136 f->script_equip );
2137 f->equip_env = nlua_newEnv( buf );
2138 nlua_loadStandard( f->equip_env );
2139 dat = ndata_read( buf, &ndat );
2140 if ( nlua_dobufenv( f->equip_env, dat, ndat, buf ) != 0 ) {
2141 WARN( _( "Failed to run equip script: %s\n"
2142 "%s\n"
2143 "Most likely Lua file has improper syntax, please check" ),
2144 buf, lua_tostring( naevL, -1 ) );
2145 nlua_freeEnv( f->equip_env );
2146 f->equip_env = LUA_NOREF;
2147 }
2148 free( dat );
2149 }
2150
2151 /* Make sure functions that need Lua have it. */
2152 if ( ( f->lua_env == LUA_NOREF ) && !faction_isFlag( f, FACTION_STATIC ) )
2153 WARN( _( "Faction '%s' has no Lua and isn't static!" ), f->name );
2154 }
2155}
2156
2160static void faction_freeOne( Faction *f )
2161{
2162 free( f->name );
2163 free( f->longname );
2164 free( f->displayname );
2165 free( f->mapname );
2166 free( f->description );
2167 free( f->ai );
2168 free( f->script_standing );
2169 free( f->script_spawn );
2170 free( f->script_equip );
2171 array_free( f->generators );
2172 gl_freeTexture( f->logo );
2173 array_free( f->allies );
2174 array_free( f->enemies );
2175 array_free( f->neutrals );
2176 nlua_freeEnv( f->sched_env );
2177 nlua_freeEnv( f->lua_env );
2178 if ( !faction_isFlag( f, FACTION_DYNAMIC ) )
2179 nlua_freeEnv( f->equip_env );
2180 for ( int i = 0; i < array_size( f->tags ); i++ )
2181 free( f->tags[i] );
2182 array_free( f->tags );
2183}
2184
2188void factions_free( void )
2189{
2190 /* Free factions. */
2191 for ( int i = 0; i < array_size( faction_stack ); i++ )
2194 faction_stack = NULL;
2195
2196 /* Clean up faction grid. */
2197 free( faction_grid );
2198 faction_grid = NULL;
2199 faction_mgrid = 0;
2200}
2201
2208int pfaction_save( xmlTextWriterPtr writer )
2209{
2210 xmlw_startElem( writer, "factions" );
2211
2212 for ( int i = 0; i < array_size( faction_stack ); i++ ) {
2213 const Faction *f = &faction_stack[i];
2214
2215 /* Must not be static. */
2216 if ( faction_isFlag( f, FACTION_STATIC ) )
2217 continue;
2218
2219 xmlw_startElem( writer, "faction" );
2220
2221 xmlw_attr( writer, "name", "%s", f->name );
2222 xmlw_elem( writer, "standing", "%f", f->player );
2223 if ( faction_isFlag( f, FACTION_REPOVERRIDE ) )
2224 xmlw_elem( writer, "override", "%f", f->override );
2225
2226 if ( faction_isKnown_( f ) )
2227 xmlw_elemEmpty( writer, "known" );
2228
2229 xmlw_endElem( writer ); /* "faction" */
2230 }
2231
2232 xmlw_endElem( writer ); /* "factions" */
2233 return 0;
2234}
2235
2242int pfaction_load( xmlNodePtr parent )
2243{
2244 xmlNodePtr node = parent->xmlChildrenNode;
2245
2246 do {
2247 if ( xml_isNode( node, "factions" ) ) {
2248 xmlNodePtr cur = node->xmlChildrenNode;
2249 do {
2250 if ( xml_isNode( cur, "faction" ) ) {
2251 int faction;
2252 char *str;
2253 xmlr_attr_strd( cur, "name", str );
2254 faction = faction_get( str );
2255 free( str );
2256 if ( faction < 0 )
2257 continue;
2258
2259 xmlNodePtr sub = cur->xmlChildrenNode;
2260 Faction *fct = &faction_stack[faction];
2261 do {
2262 if ( xml_isNode( sub, "standing" ) ) {
2263
2264 /* Must not be static. */
2265 if ( !faction_isFlag( fct, FACTION_STATIC ) )
2266 fct->player = xml_getFloat( sub );
2267 continue;
2268 }
2269 if ( xml_isNode( sub, "known" ) ) {
2270 faction_setFlag( fct, FACTION_KNOWN );
2271 continue;
2272 }
2273 if ( xml_isNode( sub, "override" ) ) {
2274 fct->override = xml_getFloat( sub );
2275 faction_setFlag( fct, FACTION_REPOVERRIDE );
2276 continue;
2277 }
2278 } while ( xml_nextNode( sub ) );
2279 }
2280 } while ( xml_nextNode( cur ) );
2281 }
2282 } while ( xml_nextNode( node ) );
2283
2284 return 0;
2285}
2286
2294int *faction_getGroup( int which )
2295{
2296 int *group;
2297
2298 switch ( which ) {
2299 case 0: /* 'all' */
2300 return array_copy( int, faction_stack );
2301
2302 case 1: /* 'friendly' */
2303 group = array_create( int );
2304 for ( int i = 0; i < array_size( faction_stack ); i++ )
2305 if ( areAllies( FACTION_PLAYER, i ) )
2306 array_push_back( &group, i );
2307 return group;
2308
2309 case 2: /* 'neutral' */
2310 group = array_create( int );
2311 for ( int i = 0; i < array_size( faction_stack ); i++ )
2312 if ( !areAllies( FACTION_PLAYER, i ) &&
2313 !areEnemies( FACTION_PLAYER, i ) )
2314 array_push_back( &group, i );
2315 return group;
2316
2317 case 3: /* 'hostile' */
2318 group = array_create( int );
2319 for ( int i = 0; i < array_size( faction_stack ); i++ )
2320 if ( areEnemies( FACTION_PLAYER, i ) )
2321 array_push_back( &group, i );
2322 return group;
2323
2324 default:
2325 return NULL;
2326 }
2327}
2328
2329double faction_reputationOverride( int f, int *set )
2330{
2331 if ( !faction_isFaction( f ) ) {
2332 *set = -1;
2333 return 0.;
2334 }
2335 Faction *fct = &faction_stack[f];
2336 *set = faction_isFlag( fct, FACTION_REPOVERRIDE );
2337 return fct->override;
2338}
2339
2340void faction_setReputationOverride( int f, int set, double value )
2341{
2342 if ( !faction_isFaction( f ) )
2343 return;
2344 Faction *fct = &faction_stack[f];
2345 if ( !set ) {
2346 faction_rmFlag( fct, FACTION_REPOVERRIDE );
2347 return;
2348 }
2349 faction_setFlag( fct, FACTION_REPOVERRIDE );
2350 fct->override = value;
2351}
2352
2357{
2358 if ( faction_isFaction( f ) )
2359 return faction_isFlag( &faction_stack[f], FACTION_USESHIDDENJUMPS );
2360 return 0;
2361}
2362
2367{
2368 if ( faction_isFaction( f ) )
2369 return faction_stack[f].generators;
2370 return NULL;
2371}
2372
2377{
2378 for ( int i = array_size( faction_stack ) - 1; i >= 0; i-- ) {
2379 Faction *f = &faction_stack[i];
2380 if ( !faction_isFlag( f, FACTION_DYNAMIC ) )
2381 continue;
2382 faction_freeOne( f );
2383 array_erase( &faction_stack, f, f + 1 );
2384 }
2386}
2387
2397int faction_dynAdd( int base, const char *name, const char *display,
2398 const char *ai, const glColour *colour )
2399{
2401 memset( f, 0, sizeof( Faction ) );
2402 f->name = strdup( name );
2403 f->displayname = ( display == NULL ) ? NULL : strdup( display );
2404 f->ai = ( ai == NULL ) ? NULL : strdup( ai );
2405 f->allies = array_create( int );
2406 f->enemies = array_create( int );
2407 f->equip_env = LUA_NOREF;
2408 f->lua_env = LUA_NOREF;
2409 f->sched_env = LUA_NOREF;
2410 f->flags =
2412 faction_addStandingScript( f, "static" );
2413 if ( base >= 0 ) {
2414 Faction *bf = &faction_stack[base];
2415
2416 if ( bf->ai != NULL && f->ai == NULL )
2417 f->ai = strdup( bf->ai );
2418 if ( bf->logo != NULL )
2419 f->logo = gl_dupTexture( bf->logo );
2420
2421 for ( int i = 0; i < array_size( bf->allies ); i++ ) {
2422 int *tmp = &array_grow( &f->allies );
2423 *tmp = bf->allies[i];
2424 }
2425 for ( int i = 0; i < array_size( bf->enemies ); i++ ) {
2426 int *tmp = &array_grow( &f->enemies );
2427 *tmp = bf->enemies[i];
2428 }
2429
2430 f->player_def = bf->player_def;
2431 f->player = bf->player;
2432 f->colour = bf->colour;
2433
2434 /* Lua stuff. */
2435 f->equip_env = bf->equip_env;
2436 }
2437
2438 /* Copy colour over if applicable. */
2439 if ( colour != NULL )
2440 f->colour = *colour;
2441
2442 /* TODO make this incremental. */
2444
2445 return f - faction_stack;
2446}
2447
2451static void faction_computeGrid( void )
2452{
2453 size_t n = array_size( faction_stack );
2454 if ( faction_mgrid < n ) {
2455 free( faction_grid );
2456 faction_grid = malloc( n * n * sizeof( int ) );
2457 faction_mgrid = n;
2458 }
2459 n = faction_mgrid;
2460 memset( faction_grid, 0, n * n * sizeof( int ) );
2461 for ( int i = 0; i < array_size( faction_stack ); i++ ) {
2462 Faction *fa = &faction_stack[i];
2463 for ( int k = 0; k < array_size( fa->allies ); k++ ) {
2464 int j = fa->allies[k];
2465#if DEBUGGING
2466 int fij = faction_grid[i * n + j];
2467 int fji = faction_grid[j * n + i];
2468 if ( ( fij != GRID_ALLIES && fij != GRID_NONE ) ||
2469 ( fji != GRID_ALLIES && fji != GRID_NONE ) )
2470 WARN( "Incoherent faction grid! '%s' and '%s' already have a "
2471 "relationship, "
2472 "but trying to set to allies!",
2473 faction_stack[i].name, faction_stack[j].name );
2474#endif /* DEBUGGING */
2475 faction_grid[i * n + j] = GRID_ALLIES;
2476 faction_grid[j * n + i] = GRID_ALLIES;
2477 }
2478 for ( int k = 0; k < array_size( fa->enemies ); k++ ) {
2479 int j = fa->enemies[k];
2480#if DEBUGGING
2481 int fij = faction_grid[i * n + j];
2482 int fji = faction_grid[j * n + i];
2483 if ( ( fij != GRID_ENEMIES && fij != GRID_NONE ) ||
2484 ( fji != GRID_ENEMIES && fji != GRID_NONE ) )
2485 WARN( "Incoherent faction grid! '%s' and '%s' already have a "
2486 "relationship, "
2487 "but trying to set to enemies!",
2488 faction_stack[i].name, faction_stack[j].name );
2489#endif /* DEBUGGING */
2490 faction_grid[i * n + j] = GRID_ENEMIES;
2491 faction_grid[j * n + i] = GRID_ENEMIES;
2492 }
2493 for ( int k = 0; k < array_size( fa->neutrals ); k++ ) {
2494 int j = fa->neutrals[k];
2495#if DEBUGGING
2496 int fij = faction_grid[i * n + j];
2497 int fji = faction_grid[j * n + i];
2498 if ( ( fij != GRID_NEUTRAL && fij != GRID_NONE ) ||
2499 ( fji != GRID_NEUTRAL && fji != GRID_NONE ) )
2500 WARN( "Incoherent faction grid! '%s' and '%s' already have a "
2501 "relationship, "
2502 "but trying to set to neutrals!",
2503 faction_stack[i].name, faction_stack[j].name );
2504#endif /* DEBUGGING */
2505 faction_grid[i * n + j] = GRID_NEUTRAL;
2506 faction_grid[j * n + i] = GRID_NEUTRAL;
2507 }
2508 }
2509}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_copy(basic_type, ptr_array)
Returns a shallow copy of the input array.
Definition array.h:230
#define array_end(array)
Returns a pointer to the end of the reserved memory space.
Definition array.h:214
#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:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition array.h:206
#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:1322
const char * faction_longname(int f)
Gets the faction's long name (formal, human-readable).
Definition faction.c:373
static void faction_freeOne(Faction *f)
Frees a single faction.
Definition faction.c:2160
const glColour * faction_reputationColour(int f)
Gets the colour of the faction based on it's standing with the player.
Definition faction.c:1196
int faction_isPlayerEnemy(int f)
Gets whether or not the player is an enemy of the faction.
Definition faction.c:1179
int faction_exists(const char *name)
Checks to see if a faction exists by name.
Definition faction.c:198
const char * faction_default_ai(int f)
Gets the name of the default AI profile for the faction's pilots.
Definition faction.c:424
const int * faction_getEnemies(int f)
Gets the list of enemies of a faction.
Definition faction.c:509
int faction_dynAdd(int base, const char *name, const char *display, const char *ai, const glColour *colour)
Dynamically add a faction.
Definition faction.c:2397
int faction_player
Definition faction.c:57
static int faction_getRaw(const char *name)
Gets a faction ID by name.
Definition faction.c:164
void faction_rmAlly(int f, int o)
Removes an ally from the faction's allies list.
Definition faction.c:732
int faction_isKnown(int id)
Is the faction known?
Definition faction.c:300
#define FACTION_INVISIBLE
Definition faction.c:37
int faction_isFaction(int f)
Checks whether or not a faction is valid.
Definition faction.c:1539
static size_t faction_mgrid
Definition faction.c:131
static Faction * faction_stack
Definition faction.c:129
double faction_reputationDefault(int f)
Gets the player's default standing with a faction.
Definition faction.c:1148
void faction_updateGlobal(void)
Computes the global faction standing for each of the factions.
Definition faction.c:1907
const glTexture * faction_logo(int f)
Gets the faction's logo (ideally 256x256).
Definition faction.c:479
nlua_env faction_getEquipper(int f)
Gets the equipper state associated to the faction scheduler.
Definition faction.c:770
#define FACTION_KNOWN
Definition faction.c:39
int factions_load(void)
Loads up all the factions from the data file.
Definition faction.c:1994
void faction_clearEnemy(int f)
Clears all the enemies of a dynamic faction.
Definition faction.c:568
void factions_reset(void)
Resets player standing and flags of factions to default.
Definition faction.c:1858
void faction_rmEnemy(int f, int o)
Removes an enemy from the faction's enemies list.
Definition faction.c:636
int faction_isPlayerFriend(int f)
Gets whether or not the player is a friend of the faction.
Definition faction.c:1162
int areEnemies(int a, int b)
Checks whether two factions are enemies.
Definition faction.c:1450
void factions_clearDynamic(void)
Clears dynamic factions.
Definition faction.c:2376
int * faction_getGroup(int which)
Returns an array of faction ids.
Definition faction.c:2294
const char *const * faction_tags(int f)
Gets the tags the faction has.
Definition faction.c:439
double faction_hit(int f, const StarSystem *sys, double mod, const char *source, int single)
Handles a faction hit against a faction and how to apply it.
Definition faction.c:871
double faction_hitTest(int f, const StarSystem *sys, double mod, const char *source)
Tests a faction hit to see how much it would apply. Does not actually modify standing.
Definition faction.c:903
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:331
const char * faction_shortname(int f)
Gets a factions short name (human-readable).
Definition faction.c:350
const char * faction_getStandingText(int f)
Gets the player's standing in human readable form.
Definition faction.c:1257
int faction_isDynamic(int id)
Is faction dynamic.
Definition faction.c:308
void factions_free(void)
Frees the factions.
Definition faction.c:2188
int areNeutral(int a, int b)
Checks whether two factions are true neutral.
Definition faction.c:1424
void factions_resetLocal(void)
Reset local standing.
Definition faction.c:1873
const int * faction_getAllies(int f)
Gets the list of allies of a faction.
Definition faction.c:539
void faction_modPlayerRaw(int f, double mod)
Modifies the player's standing without affecting others.
Definition faction.c:1026
const FactionGenerator * faction_generators(int f)
Gets the faction's generators.
Definition faction.c:2366
int faction_usesHiddenJumps(int f)
Checks to see if a faction uses hidden jumps.
Definition faction.c:2356
int * faction_getKnown()
Gets all the known factions in an array (array.h).
Definition faction.c:243
int faction_isInvisible(int id)
Is the faction invisible?
Definition faction.c:275
int pfaction_save(xmlTextWriterPtr writer)
Saves player's standings with the factions.
Definition faction.c:2208
const glColour * faction_colour(int f)
Gets the colour of the faction.
Definition faction.c:494
static void faction_sanitizePlayer(Faction *faction)
Sanitizes player faction standing.
Definition faction.c:784
const char * faction_getStandingTextAtValue(int f, double value)
Gets the player's standing in human readable form.
Definition faction.c:1269
void faction_clearAlly(int f)
Clears all the ally of a dynamic faction.
Definition faction.c:664
int pfaction_load(xmlNodePtr parent)
Loads the player's faction standings.
Definition faction.c:2242
#define FACTION_STATIC
Definition faction.c:35
double faction_lane_base_cost(int f)
Gets the faction's weight for patrolled safe-lane construction;.
Definition faction.c:464
void faction_modPlayer(int f, double mod, const char *source)
Modifies the player's standing with a faction.
Definition faction.c:967
void faction_setReputation(int f, double value)
Sets the player's standing with a faction.
Definition faction.c:1057
static int * faction_grid
Definition faction.c:130
static int faction_parseSocial(const char *file)
Parses the social tidbits of a faction: allies and enemies.
Definition faction.c:1757
char faction_reputationColourChar(int f)
Gets the faction character associated to its standing with the player.
Definition faction.c:1228
static double faction_hitLua(int f, const StarSystem *sys, double mod, const char *source, int secondary, int primary_faction)
Mods player using the power of Lua.
Definition faction.c:792
#define FACTION_USESHIDDENJUMPS
Definition faction.c:41
int * faction_getAll(void)
Returns all faction IDs in an array (array.h).
Definition faction.c:220
void faction_modPlayerSingle(int f, double mod, const char *source)
Modifies the player's standing without affecting others.
Definition faction.c:1007
static void faction_addStandingScript(Faction *temp, const char *scriptname)
Sets up a standing script for a faction.
Definition faction.c:1712
static int faction_parse(Faction *temp, const char *file)
Parses a single faction, but doesn't set the allies/enemies bit.
Definition faction.c:1553
#define FACTION_DYNAMIC
Definition faction.c:40
int faction_setInvisible(int id, int state)
Sets the faction's invisible state.
Definition faction.c:283
int faction_setKnown(int id, int state)
Sets the factions known state.
Definition faction.c:316
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:452
int * faction_getAllVisible(void)
Returns all non-invisible faction IDs in an array (array.h).
Definition faction.c:231
const char * faction_mapname(int f)
Gets the faction's map name (translated).
Definition faction.c:390
double faction_reputationMax(int f)
Gets the maximum reputation of a faction.
Definition faction.c:1374
void faction_addAlly(int f, int o)
Adds an ally to the faction's allies list.
Definition faction.c:685
nlua_env faction_getScheduler(int f)
Gets the state associated to the faction scheduler.
Definition faction.c:758
static void faction_computeGrid(void)
Computes the faction relationship grid.
Definition faction.c:2451
double faction_reputation(int f)
Gets the player's standing with a faction.
Definition faction.c:1129
const char * faction_description(int f)
Gets the faction's description (translated).
Definition faction.c:407
void faction_clearKnown()
Clears the known factions.
Definition faction.c:257
int faction_isStatic(int id)
Is the faction static?
Definition faction.c:267
void faction_addEnemy(int f, int o)
Adds an enemy to the faction's enemies list.
Definition faction.c:589
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:209
int areAllies(int a, int b)
Checks whether two factions are allies or not.
Definition faction.c:1476
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition hook.c:1029
void naev_renderLoadscreen(void)
Renders the loadscreen if necessary.
Definition naev.c:640
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define CLAMP(a, b, x)
Definition naev.h:41
#define FABS(x)
Definition naev.h:34
#define MAX(x, y)
Definition naev.h:37
#define PATH_MAX
Definition naev.h:57
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition ndata.c:207
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
Definition ndata.c:420
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition ndata.c:286
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition nlua.c:914
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:1047
lua_State * naevL
Definition nlua.c:54
LuaFaction * lua_pushfaction(lua_State *L, LuaFaction faction)
Pushes a faction on the stack.
LuaSystem * lua_pushsystem(lua_State *L, LuaSystem sys)
Pushes a system on the stack.
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:70
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:891
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:587
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:835
Player_t player
Definition player.c:77
static const double c[]
Definition rng.c:256
void space_factionChange(void)
Mark when a faction changes.
Definition space.c:1460
double system_getReputationOrGlobal(const StarSystem *sys, int faction)
Gets the local reputation of the player in a system or returns the global standing.
Definition space.c:4518
StarSystem * system_getAll(void)
Gets an array (array.h) of all star systems.
Definition space.c:925
double system_getPresence(const StarSystem *sys, int faction)
Get the presence of a faction in a system.
Definition space.c:4537
double weight
Definition faction.h:19
Description of a lane-building faction.
Definition faction.c:64
unsigned int oflags
Definition faction.c:123
unsigned int flags
Definition faction.c:122
glTexture * logo
Definition faction.c:79
glColour colour
Definition faction.c:80
nlua_env equip_env
Definition faction.c:119
int lua_hit_test
Definition faction.c:103
double player
Definition faction.c:93
double lane_base_cost
Definition faction.c:112
double override
Definition faction.c:94
char * description
Definition faction.c:70
double friendly_at
Definition faction.c:100
FactionGenerator * generators
Definition faction.c:116
int * neutrals
Definition faction.c:89
double lane_length_per_presence
Definition faction.c:110
nlua_env lua_env
Definition faction.c:101
char * mapname
Definition faction.c:68
char ** tags
Definition faction.c:126
char * longname
Definition faction.c:66
char * ai
Definition faction.c:69
int lua_text_rank
Definition faction.c:104
char * displayname
Definition faction.c:67
int lua_hit
Definition faction.c:102
double local_th
Definition faction.c:71
int * allies
Definition faction.c:86
int * enemies
Definition faction.c:83
nlua_env sched_env
Definition faction.c:97
double player_def
Definition faction.c:92
int lua_text_broad
Definition faction.c:105
char * name
Definition faction.c:65
int lua_reputation_max
Definition faction.c:106
The actual hook parameter.
Definition hook.h:40
const char * str
Definition hook.h:44
LuaSystem ls
Definition hook.h:51
union HookParam::@114305201244257020071001257133270030317263020235 u
HookParamType type
Definition hook.h:41
double num
Definition hook.h:43
LuaFaction lf
Definition hook.h:50
Represents presence in a system.
Definition space.h:228
double value
Definition space.h:232
double local
Definition space.h:236
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:43