naev 0.10.4
hook.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
23#include <assert.h>
24#include <stdlib.h>
25
26#include "naev.h"
29#include "hook.h"
30
31#include "array.h"
32#include "claim.h"
33#include "event.h"
34#include "gatherable.h"
35#include "log.h"
36#include "menu.h"
37#include "mission.h"
38#include "nlua_evt.h"
39#include "nlua_hook.h"
40#include "nlua_pilot.h"
41#include "nstring.h"
42#include "nxml.h"
43#include "player.h"
44#include "space.h"
45
49typedef struct HookQueue_s {
50 struct HookQueue_s *next;
51 char *stack;
52 unsigned int id;
53 HookParam hparam[ HOOK_MAX_PARAM ];
55static HookQueue_t *hook_queue = NULL;
56static int hook_atomic = 0;
57static ntime_t hook_time_accum = 0;
62typedef enum HookType_e {
68
74typedef struct Hook_ {
75 struct Hook_ *next;
77 unsigned int id;
78 char *stack;
79 int created;
80 int delete;
82 int once;
84 /* Timer information. */
86 double ms;
88 /* Date information. */
89 int is_date;
90 ntime_t res;
91 ntime_t acc;
94 union {
95 struct {
96 unsigned int parent;
97 char *func;
98 } misn;
99 struct {
100 unsigned int parent;
101 char *func;
102 } event;
103 struct {
104 int (*func)( void* );
105 void *data;
106 } func;
107 } u;
108} Hook;
109
110/*
111 * the stack
112 */
113static unsigned int hook_id = 0;
114static Hook* hook_list = NULL;
115static int hook_runningstack = 0;
116static int hook_loadingstack = 0;
118/*
119 * prototypes
120 */
121/* Execution. */
122static int hooks_executeParam( const char* stack, const HookParam *param );
123static void hooks_updateDateExecute( ntime_t change );
124/* intern */
125static void hook_rmRaw( Hook *h );
126static void hooks_purgeList (void);
127static Hook* hook_get( unsigned int id );
128static unsigned int hook_genID (void);
129static Hook* hook_new( HookType_t type, const char *stack );
130static int hook_parseParam( const HookParam *param );
131static int hook_runMisn( Hook *hook, const HookParam *param, int claims );
132static int hook_runEvent( Hook *hook, const HookParam *param, int claims );
133static int hook_run( Hook *hook, const HookParam *param, int claims );
134static void hook_free( Hook *h );
135static int hook_needSave( Hook *h );
136static int hook_parse( xmlNodePtr base );
137/* externed */
138int hook_save( xmlTextWriterPtr writer );
139int hook_load( xmlNodePtr parent );
140/* Misc. */
141static Mission *hook_getMission( Hook *hook );
142
146static int hq_add( HookQueue_t *hq )
147{
148 HookQueue_t *c;
149
150 /* Set as head. */
151 if (hook_queue == NULL) {
152 hook_queue = hq;
153 return 0;
154 }
155
156 /* Find tail. */
157 for (c=hook_queue; c->next != NULL; c=c->next);
158 c->next = hq;
159 return 0;
160}
161
165static void hq_free( HookQueue_t *hq )
166{
167 free(hq->stack);
168 free(hq);
169}
170
174static void hq_clear (void)
175{
176 HookQueue_t *hq;
177 while (hook_queue != NULL) {
178 hq = hook_queue;
179 hook_queue = hq->next;
180 hq_free( hq );
181 }
182}
183
188{
189 hook_atomic = 1;
190}
191
195void hook_exclusionEnd( double dt )
196{
197 HookQueue_t *hq;
198 ntime_t temp;
199 hook_atomic = 0;
200
201 /* Handle hook queue. */
202 while (hook_queue != NULL) {
203 /* Move hook down. */
204 hq = hook_queue;
205 hook_queue = hq->next;
206
207 /* Execute. */
208 hooks_executeParam( hq->stack, hq->hparam );
209
210 /* Clean up. */
211 hq_free( hq );
212 }
213
214 /* Update timer hooks. */
215 hooks_update( dt );
216
217 /* Run assorted hooks. */
218 if (player.p != NULL) /* All these hooks rely on player actually existing. */
220
221 /* Time hooks. */
222 temp = hook_time_accum;
223 hook_time_accum = 0;
225
226 /* Purge the dead. */
228}
229
236static int hook_parseParam( const HookParam *param )
237{
238 int n;
239
240 if (param == NULL)
241 return 0;
242
243 n = 0;
244 while (param[n].type != HOOK_PARAM_SENTINEL) {
245 switch (param[n].type) {
246 case HOOK_PARAM_NIL:
247 lua_pushnil( naevL );
248 break;
249 case HOOK_PARAM_NUMBER:
250 lua_pushnumber( naevL, param[n].u.num );
251 break;
252 case HOOK_PARAM_STRING:
253 lua_pushstring( naevL, param[n].u.str );
254 break;
255 case HOOK_PARAM_BOOL:
256 lua_pushboolean( naevL, param[n].u.b );
257 break;
258 case HOOK_PARAM_PILOT:
259 lua_pushpilot( naevL, param[n].u.lp );
260 break;
261 case HOOK_PARAM_FACTION:
262 lua_pushfaction( naevL, param[n].u.lf );
263 break;
264 case HOOK_PARAM_SPOB:
265 lua_pushspob( naevL, param[n].u.la );
266 break;
267 case HOOK_PARAM_JUMP:
268 lua_pushjump( naevL, param[n].u.lj );
269 break;
270 case HOOK_PARAM_REF:
271 lua_rawgeti( naevL, LUA_REGISTRYINDEX, param[n].u.ref );
272 break;
273
274 default:
275 WARN( _("Unknown Lua parameter type.") );
276 lua_pushnil( naevL );
277 break;
278 }
279 n++;
280 }
281
282 return n;
283}
284
293static int hook_runMisn( Hook *hook, const HookParam *param, int claims )
294{
295 unsigned int id;
296 Mission* misn;
297 int n;
298
299 /* Simplicity. */
300 id = hook->id;
301
302 /* Make sure it's valid. */
303 if (hook->u.misn.parent == 0) {
304 WARN(_("Trying to run hook with nonexistent parent: deleting"));
305 hook->delete = 1; /* so we delete it */
306 return -1;
307 }
308
309 /* Locate the mission */
310 misn = hook_getMission( hook );
311 if (misn == NULL) {
312 WARN(_("Trying to run hook with parent not in player mission stack: deleting"));
313 hook->delete = 1; /* so we delete it. */
314 return -1;
315 }
316
317 /* Make sure it's claimed. */
318 if ((claims > 0) && (claim_testSys(misn->claims, cur_system->id) != claims))
319 return 1;
320
321 /* Delete if only supposed to run once. */
322 if (hook->once)
323 hook_rmRaw( hook );
324
325 /* Set up hook parameters. */
326 misn_runStart( misn, hook->u.misn.func );
327 n = hook_parseParam( param );
328
329 /* Add hook parameters. */
330 n += hookL_getarg( id );
331
332 /* Run mission code. */
333 hook->ran_once = 1;
334 if (misn_runFunc( misn, hook->u.misn.func, n ) < 0) { /* error has occurred */
335 WARN(_("Hook [%s] '%d' -> '%s' failed"), hook->stack,
336 hook->id, hook->u.misn.func);
337 hook_rmRaw( hook );
338 return -1;
339 }
340 return 0;
341}
342
351static int hook_runEvent( Hook *hook, const HookParam *param, int claims )
352{
353 int ret, n, id;
354
355 /* Simplicity. */
356 id = hook->id;
357
358 /* Must match claims. */
359 if ((claims > 0) && (event_testClaims( hook->u.event.parent, cur_system->id ) != claims))
360 return 1;
361
362 /* Delete if only supposed to run once. */
363 if (hook->once)
364 hook_rmRaw( hook );
365
366 /* Set up hook parameters. */
367 if (event_get(hook->u.event.parent) == NULL) {
368 WARN(_("Hook [%s] '%d' -> '%s' failed, event does not exist. Deleting hook."), hook->stack,
369 id, hook->u.event.func);
370 hook->delete = 1; /* Set for deletion. */
371 return -1;
372 }
373
374 event_runStart( hook->u.event.parent, hook->u.event.func );
375 n = hook_parseParam( param );
376
377 /* Add hook parameters. */
378 n += hookL_getarg( id );
379
380 /* Run the hook. */
381 ret = event_runFunc( hook->u.event.parent, hook->u.event.func, n );
382 hook->ran_once = 1;
383 if (ret < 0) {
384 WARN(_("Hook [%s] '%d' -> '%s' failed"), hook->stack,
385 hook->id, hook->u.event.func);
386 hook_rmRaw( hook );
387 return -1;
388 }
389 return 0;
390}
391
400static int hook_run( Hook *hook, const HookParam *param, int claims )
401{
402 int ret;
403
404 /* Do not run if pending deletion. */
405 if (hook->delete)
406 return 0;
407
408 /* Don't run anything when main menu is open. */
410 return 0;
411
412 switch (hook->type) {
413 case HOOK_TYPE_MISN:
414 ret = hook_runMisn(hook, param, claims);
415 break;
416
417 case HOOK_TYPE_EVENT:
418 ret = hook_runEvent(hook, param, claims);
419 break;
420
421 case HOOK_TYPE_FUNC:
422 /* We have to remove the hook first, so it doesn't get run again.
423 * Note that the function will not do any checks nor has arguments, since it is C-side. */
424 if (hook->once)
425 hook->delete = 1;
426 ret = hook->u.func.func( hook->u.func.data );
427 break;
428
429 default:
430 WARN(_("Invalid hook type '%d', deleting."), hook->type);
431 hook->delete = 1;
432 return -1;
433 }
434
435 return ret;
436}
437
443static unsigned int hook_genID (void)
444{
445 unsigned int id = ++hook_id; /* default id, not safe if loading */
446
447 /* If not loading we can just return. */
449 return id;
450
451 /* Must check ids for collisions. */
452 for (Hook *h=hook_list; h!=NULL; h=h->next)
453 if (id == h->id) /* Check for collision. */
454 return hook_genID(); /* recursively try again */
455
456 return id;
457}
458
466static Hook* hook_new( HookType_t type, const char *stack )
467{
468 /* Get and create new hook. */
469 Hook *new_hook = calloc( 1, sizeof(Hook) );
470 if (hook_list == NULL)
471 hook_list = new_hook;
472 else {
473 /* Put at front, O(1). */
474 new_hook->next = hook_list;
475 hook_list = new_hook;
476 }
477
478 /* Fill out generic details. */
479 new_hook->type = type;
480 new_hook->id = hook_genID();
481 new_hook->stack = strdup(stack);
482 new_hook->created = 1;
483
485 if (strcmp(stack,"safe")==0)
486 new_hook->once = 1;
487
488 return new_hook;
489}
490
499unsigned int hook_addMisn( unsigned int parent, const char *func, const char *stack )
500{
501 /* Create the new hook. */
502 Hook *new_hook = hook_new( HOOK_TYPE_MISN, stack );
503
504 /* Put mission specific details. */
505 new_hook->u.misn.parent = parent;
506 new_hook->u.misn.func = strdup(func);
507
508 return new_hook->id;
509}
510
519unsigned int hook_addEvent( unsigned int parent, const char *func, const char *stack )
520{
521 /* Create the new hook. */
522 Hook *new_hook = hook_new( HOOK_TYPE_EVENT, stack );
523
524 /* Put event specific details. */
525 new_hook->u.event.parent = parent;
526 new_hook->u.event.func = strdup(func);
527
528 return new_hook->id;
529}
530
539unsigned int hook_addTimerMisn( unsigned int parent, const char *func, double ms )
540{
541 /* Create the new hook. */
542 Hook *new_hook = hook_new( HOOK_TYPE_MISN, "timer" );
543
544 /* Put mission specific details. */
545 new_hook->u.misn.parent = parent;
546 new_hook->u.misn.func = strdup(func);
547
548 /* Timer information. */
549 new_hook->is_timer = 1;
550 new_hook->ms = ms;
551
552 return new_hook->id;
553}
554
563unsigned int hook_addTimerEvt( unsigned int parent, const char *func, double ms )
564{
565 /* Create the new hook. */
566 Hook *new_hook = hook_new( HOOK_TYPE_EVENT, "timer" );
567
568 /* Put event specific details. */
569 new_hook->u.event.parent = parent;
570 new_hook->u.event.func = strdup(func);
571
572 /* Timer information. */
573 new_hook->is_timer = 1;
574 new_hook->ms = ms;
575
576 return new_hook->id;
577}
578
582unsigned int hook_addFunc( int (*func)(void*), void *data, const char *stack )
583{
584 Hook *new_hook = hook_new( HOOK_TYPE_FUNC, stack );
585
586 /* Function special stuff. */
587 new_hook->u.func.func = func;
588 new_hook->u.func.data = data;
589
590 return new_hook->id;
591}
592
596static void hooks_purgeList (void)
597{
598 Hook *h, *hl;
599
600 /* Do not run while stack is being run. */
602 return;
603
604 /* Second pass to delete. */
605 hl = NULL;
606 h = hook_list;
607 while (h != NULL) {
608 /* Find valid timer hooks. */
609 if (h->delete) {
610
611 if (hl == NULL)
612 hook_list = h->next;
613 else
614 hl->next = h->next;
615
616 /* Free. */
617 h->next = NULL;
618 hook_free( h );
619
620 /* Last. */
621 h = hl;
622 }
623
624 hl = h;
625 if (h == NULL)
626 h = hook_list;
627 else
628 h = h->next;
629 }
630}
631
635void hooks_updateDate( ntime_t change )
636{
637 if (change > 0)
638 hook_time_accum += change;
639}
640
644static void hooks_updateDateExecute( ntime_t change )
645{
646 /* Don't update without player. */
647 if ((player.p == NULL) || player_isFlag(PLAYER_CREATING))
648 return;
649
650 /* Clear creation flags. */
651 for (Hook *h=hook_list; h!=NULL; h=h->next)
652 h->created = 0;
653
654 /* On j=0 we increment all timers and try to run, then on j=1 we update the timers. */
655 hook_runningstack++; /* running hooks */
656 for (int j=1; j>=0; j--) {
657 for (Hook *h=hook_list; h!=NULL; h=h->next) {
658 /* Not be deleting. */
659 if (h->delete)
660 continue;
661 /* Find valid date hooks. */
662 if (h->is_date == 0)
663 continue;
664 /* Don't update newly created hooks. */
665 if (h->created != 0)
666 continue;
667
668 /* Decrement timer and check to see if should run. */
669 if (j==1)
670 h->acc += change;
671 if (h->acc < h->res)
672 continue;
673
674 /* Run the timer hook. */
675 hook_run( h, NULL, j );
676 /* Date hooks are not deleted. */
677
678 /* Time is modified at the end. */
679 if (j==0)
680 h->acc %= h->res; /* We'll skip all buggers. */
681 }
682 }
683 hook_runningstack--; /* not running hooks anymore */
684
685 /* Second pass to delete. */
687}
688
689unsigned int hook_addDateMisn( unsigned int parent, const char *func, ntime_t resolution )
690{
691 /* Create the new hook. */
692 Hook *new_hook = hook_new( HOOK_TYPE_MISN, "date" );
693
694 /* Put mission specific details. */
695 new_hook->u.misn.parent = parent;
696 new_hook->u.misn.func = strdup(func);
697
698 /* Timer information. */
699 new_hook->is_date = 1;
700 new_hook->res = resolution;
701 new_hook->acc = 0;
702
703 return new_hook->id;
704}
705
706unsigned int hook_addDateEvt( unsigned int parent, const char *func, ntime_t resolution )
707{
708 /* Create the new hook. */
709 Hook *new_hook = hook_new( HOOK_TYPE_EVENT, "date" );
710
711 /* Put event specific details. */
712 new_hook->u.event.parent = parent;
713 new_hook->u.event.func = strdup(func);
714
715 /* Timer information. */
716 new_hook->is_date = 1;
717 new_hook->res = resolution;
718 new_hook->acc = 0;
719
720 return new_hook->id;
721}
722
726void hooks_update( double dt )
727{
728 Hook *h;
729
730 /* Don't update without player. */
731 if ((player.p == NULL) || player_isFlag(PLAYER_CREATING) || player_isFlag(PLAYER_DESTROYED))
732 return;
733
734 /* Clear creation flags. */
735 for (h=hook_list; h!=NULL; h=h->next)
736 h->created = 0;
737
738 hook_runningstack++; /* running hooks */
739 for (int j=1; j>=0; j--) {
740 for (h=hook_list; h!=NULL; h=h->next) {
741 /* Not be deleting. */
742 if (h->delete)
743 continue;
744 /* Find valid timer hooks. */
745 if (h->is_timer == 0)
746 continue;
747 /* Don't update newly created hooks. */
748 if (h->created != 0)
749 continue;
750
751 /* Decrement timer and check to see if should run. */
752 if (j==1)
753 h->ms -= dt;
754 if (h->ms > 0.)
755 continue;
756
757 /* Run the timer hook. */
758 hook_run( h, NULL, j );
759 if (h->ran_once) /* Remove when run. */
760 hook_rmRaw( h );
761 }
762 }
763 hook_runningstack--; /* not running hooks anymore */
764
765 /* Second pass to delete. */
767}
768
773{
774 for (int i=0; i<array_size(player_missions); i++)
775 if (player_missions[i]->id == hook->u.misn.parent)
776 return player_missions[i];
777
778 return NULL;
779}
780
786void hook_rm( unsigned int id )
787{
788 Hook *h = hook_get( id );
789 if (h==NULL)
790 return;
791
792 hook_rmRaw( h );
793}
794
798static void hook_rmRaw( Hook *h )
799{
800 h->delete = 1;
801 hookL_unsetarg( h->id );
802}
803
809void hook_rmMisnParent( unsigned int parent )
810{
811 for (Hook *h=hook_list; h!=NULL; h=h->next)
812 if ((h->type==HOOK_TYPE_MISN) && (parent == h->u.misn.parent))
813 h->delete = 1;
814}
815
821void hook_rmEventParent( unsigned int parent )
822{
823 for (Hook *h=hook_list; h!=NULL; h=h->next)
824 if ((h->type==HOOK_TYPE_EVENT) && (parent == h->u.event.parent))
825 h->delete = 1;
826}
827
834int hook_hasMisnParent( unsigned int parent )
835{
836 int num = 0;
837 for (Hook *h=hook_list; h!=NULL; h=h->next)
838 if ((h->type==HOOK_TYPE_MISN) && (parent == h->u.misn.parent))
839 num++;
840
841 return num;
842}
843
850int hook_hasEventParent( unsigned int parent )
851{
852 int num = 0;
853 for (Hook *h=hook_list; h!=NULL; h=h->next)
854 if ((h->type==HOOK_TYPE_EVENT) && (parent == h->u.event.parent))
855 num++;
856
857 return num;
858}
859
860static int hooks_executeParam( const char* stack, const HookParam *param )
861{
862 int run;
863
864 /* Don't update if player is dead. */
865 if ((player.p == NULL) || player_isFlag(PLAYER_DESTROYED))
866 return 0;
867
868 /* Reset the current stack's ran and creation flags. */
869 for (Hook *h=hook_list; h!=NULL; h=h->next)
870 if (strcmp(stack, h->stack)==0) {
871 h->ran_once = 0;
872 h->created = 0;
873 }
874
875 run = 0;
876 hook_runningstack++; /* running hooks */
877 for (int j=1; j>=0; j--) {
878 for (Hook *h=hook_list; h!=NULL; h=h->next) {
879 /* Should be deleted. */
880 if (h->delete)
881 continue;
882 /* Don't run again. */
883 if (h->ran_once)
884 continue;
885 /* Don't update newly created hooks. */
886 if (h->created != 0)
887 continue;
888 /* Doesn't match stack. */
889 if (strcmp(stack, h->stack) != 0)
890 continue;
891
892 /* Run hook. */
893 hook_run( h, param, j );
894 run++;
895
896 /* If hook_cleanup was run, hook_list will be NULL */
897 if (hook_list==NULL)
898 break;
899 }
900 if (hook_list==NULL)
901 break;
902 }
903 hook_runningstack--; /* not running hooks anymore */
904
905 /* Free reference parameters. */
906 if (param != NULL) {
907 int n = 0;
908 while (param[n].type != HOOK_PARAM_SENTINEL) {
909 switch (param[n].type) {
910 case HOOK_PARAM_REF:
911 luaL_unref( naevL, LUA_REGISTRYINDEX, param[n].u.ref );
912 break;
913
914 default:
915 break;
916 }
917 n++;
918 }
919 }
920
921 /* Check claims. */
922 if (run)
924
925 return run;
926}
927
935int hooks_runParamDeferred( const char* stack, const HookParam *param )
936{
937 int i;
938 HookQueue_t *hq;
939
940 /* Don't update if player is dead. */
941 if ((player.p == NULL) || player_isFlag(PLAYER_DESTROYED))
942 return 0;
943
944 hq = calloc( 1, sizeof(HookQueue_t) );
945 hq->stack = strdup(stack);
946 i = 0;
947 if (param != NULL) {
948 for (; param[i].type != HOOK_PARAM_SENTINEL; i++)
949 hq->hparam[i] = param[i];
950 }
951#ifdef DEBUGGING
952 if (i >= HOOK_MAX_PARAM)
953 WARN( _("HOOK_MAX_PARAM is set too low (%d), need at least %d!"), HOOK_MAX_PARAM, i );
954#endif /* DEBUGGING */
955 hq->hparam[i].type = HOOK_PARAM_SENTINEL;
956 hq_add( hq );
957 return 0;
958}
959
967int hooks_runParam( const char* stack, const HookParam *param )
968{
969 /* Don't update if player is dead. */
970 if ((player.p == NULL) || player_isFlag(PLAYER_DESTROYED))
971 return 0;
972
973 /* Not time to run hooks, so queue them. */
974 if (hook_atomic)
975 return hooks_runParamDeferred( stack, param );
976
977 /* Execute. */
978 return hooks_executeParam( stack, param );
979}
980
987int hooks_run( const char* stack )
988{
989 return hooks_runParam( stack, NULL );
990}
991
995static Hook* hook_get( unsigned int id )
996{
997 for (Hook *h=hook_list; h!=NULL; h=h->next)
998 if (h->id == id)
999 return h;
1000
1001 return NULL;
1002}
1003
1007nlua_env hook_env( unsigned int hook )
1008{
1009 Mission *misn;
1010 Event_t *evt;
1011
1012 Hook *h = hook_get(hook);
1013 if (h == NULL)
1014 return LUA_NOREF;
1015
1016 switch (h->type) {
1017 case HOOK_TYPE_MISN:
1018 misn = hook_getMission( h );
1019 if (misn != NULL)
1020 return misn->env;
1021 break;
1022 case HOOK_TYPE_EVENT:
1023 evt = event_get( h->u.event.parent );
1024 if (evt != NULL)
1025 return evt->env;
1026 break;
1027 default:
1028 break;
1029 }
1030
1031 return LUA_NOREF;
1032}
1033
1041int hook_runIDparam( unsigned int id, const HookParam *param )
1042{
1043 Hook *h;
1044
1045 /* Don't update if player is dead. */
1046 if ((player.p == NULL) || player_isFlag(PLAYER_DESTROYED))
1047 return 0;
1048
1049 /* Try to find the hook and run it. */
1050 h = hook_get( id );
1051 if (h == NULL) {
1052 WARN(_("Attempting to run hook of id '%d' which is not in the stack"), id);
1053 return -1;
1054 }
1055 hook_run( h, param, -1 );
1056
1057 return 0;
1058}
1059
1066int hook_runID( unsigned int id )
1067{
1068 return hook_runIDparam( id, 0 );
1069}
1070
1076static void hook_free( Hook *h )
1077{
1078 /* Remove from all the pilots. */
1079 pilots_rmHook( h->id );
1080
1081 /* Generic freeing. */
1082 free( h->stack );
1083
1084 /* Free type specific. */
1085 switch (h->type) {
1086 case HOOK_TYPE_MISN:
1087 free( h->u.misn.func );
1088 break;
1089
1090 case HOOK_TYPE_EVENT:
1091 free( h->u.event.func );
1092 break;
1093
1094 default:
1095 break;
1096 }
1097
1098 free( h );
1099}
1100
1104void hook_cleanup (void)
1105{
1106 Hook *h;
1107
1108 /* Clear queued hooks. */
1109 hq_clear();
1110
1111 h = hook_list;
1112 while (h != NULL) {
1113 Hook *hn = h->next;
1114 hook_free( h );
1115 h = hn;
1116 }
1117 /* safe defaults just in case */
1118 hook_list = NULL;
1119}
1120
1127static int hook_needSave( Hook *h )
1128{
1129 const char *nosave[] = {
1130 "p_death", "p_board", "p_disable", "p_jump", "p_attacked", "p_idle", /* pilot hooks */
1131 "timer", /* timers */
1132 "end" };
1133
1134 /* Impossible to save functions. */
1135 if (h->type == HOOK_TYPE_FUNC)
1136 return 0;
1137
1138 /* Events must need saving. */
1139 if ((h->type == HOOK_TYPE_EVENT) && !event_save(h->u.event.parent))
1140 return 0;
1141
1142 /* Must not be pending deletion. */
1143 if (h->delete)
1144 return 0;
1145
1146 /* Make sure it's in the proper stack. */
1147 for (int i=0; strcmp(nosave[i],"end") != 0; i++)
1148 if (strcmp(nosave[i],h->stack)==0) return 0;
1149
1150 return 1;
1151}
1152
1159int hook_save( xmlTextWriterPtr writer )
1160{
1161 xmlw_startElem(writer,"hooks");
1162 for (Hook *h=hook_list; h!=NULL; h=h->next) {
1163
1164 if (!hook_needSave(h))
1165 continue; /* no need to save it */
1166
1167 xmlw_startElem(writer,"hook");
1168
1169 switch (h->type) {
1170 case HOOK_TYPE_MISN:
1171 xmlw_attr(writer,"type","misn"); /* Save attribute. */
1172 xmlw_elem(writer,"parent","%u",h->u.misn.parent);
1173 xmlw_elem(writer,"func","%s",h->u.misn.func);
1174 break;
1175
1176 case HOOK_TYPE_EVENT:
1177 xmlw_attr(writer,"type","event"); /* Save attribute. */
1178 xmlw_elem(writer,"parent","%u",h->u.event.parent);
1179 xmlw_elem(writer,"func","%s",h->u.event.func);
1180 break;
1181
1182 default:
1183 WARN(_("Something has gone screwy here..."));
1184 break;
1185 }
1186
1187 /* Generic information. */
1188 xmlw_elem(writer,"id","%u",h->id);
1189 xmlw_elem(writer,"stack","%s",h->stack);
1190
1191 /* Store additional date information. */
1192 if (h->is_date)
1193 xmlw_elem(writer,"resolution","%"PRId64,h->res);
1194
1195 xmlw_endElem(writer); /* "hook" */
1196 }
1197 xmlw_endElem(writer); /* "hooks" */
1198
1199 return 0;
1200}
1201
1208int hook_load( xmlNodePtr parent )
1209{
1210 xmlNodePtr node;
1211
1212 /* We're loading. */
1214
1215 node = parent->xmlChildrenNode;
1216 do {
1217 if (xml_isNode(node,"hooks"))
1218 hook_parse(node);
1219 } while (xml_nextNode(node));
1220
1221 /* Done loading. */
1223
1224 /* Set ID gen to highest hook. */
1225 for (Hook *h=hook_list; h!=NULL; h=h->next)
1226 hook_id = MAX( h->id, hook_id );
1227
1228 return 0;
1229}
1230
1237static int hook_parse( xmlNodePtr base )
1238{
1239 xmlNodePtr node, cur;
1240 char *func, *stack, *stype;
1241 unsigned int parent, id, new_id;
1242 HookType_t type;
1243 Hook *h;
1244 int is_date;
1245 ntime_t res = 0;
1246
1247 /* Defaults. */
1248
1249 node = base->xmlChildrenNode;
1250 do {
1251 if (xml_isNode(node, "hook")) {
1252 id = 0;
1253 parent = 0;
1254 func = NULL;
1255 stack = NULL;
1256 is_date = 0;
1257
1258 /* Handle the type. */
1259 xmlr_attr_strd(node, "type", stype);
1260 /* Default to mission for old saves. */
1261 if (stype == NULL)
1262 type = HOOK_TYPE_MISN;
1263 /* Mission type. */
1264 else if (strcmp(stype, "misn") == 0) {
1265 type = HOOK_TYPE_MISN;
1266 free(stype);
1267 }
1268 /* Event type. */
1269 else if (strcmp(stype, "event") == 0) {
1270 type = HOOK_TYPE_EVENT;
1271 free(stype);
1272 }
1273 /* Unknown. */
1274 else {
1275 WARN(_("Hook of unknown type '%s' found, skipping."), stype);
1276 free(stype);
1277 continue;
1278 }
1279
1280 /* Handle the data. */
1281 cur = node->xmlChildrenNode;
1282 do {
1283 xml_onlyNodes(cur);
1284
1285 /* ID. */
1286 xmlr_long(cur, "id", id);
1287
1288 /* Generic. */
1289 xmlr_str(cur, "stack", stack);
1290
1291 /* Type specific. */
1292 if ((type == HOOK_TYPE_MISN) || (type == HOOK_TYPE_EVENT)) {
1293 xmlr_uint(cur, "parent", parent);
1294 xmlr_str(cur, "func", func);
1295 }
1296
1297 /* Check for date hook. */
1298 if (xml_isNode( cur, "resolution" )) {
1299 is_date = 1;
1300 res = xml_getLong( cur );
1301 continue;
1302 }
1303
1304 WARN(_("Save has unknown hook node '%s'."), cur->name);
1305 } while (xml_nextNode(cur));
1306
1307 /* Check for validity. */
1308 if ((parent == 0) || (func == NULL) || (stack == NULL)) {
1309 WARN(_("Invalid hook."));
1310 continue;
1311 }
1312
1313 /* Create the hook. */
1314 switch (type) {
1315 case HOOK_TYPE_MISN:
1316 new_id = hook_addMisn( parent, func, stack );
1317 break;
1318 case HOOK_TYPE_EVENT:
1319 new_id = hook_addEvent( parent, func, stack );
1320 break;
1321 default:
1322 WARN(_("Save has unsupported hook type."));
1323 continue;
1324 }
1325
1326 /* Set the id. */
1327 if (id != 0) {
1328 h = hook_get( new_id );
1329 h->id = id;
1330
1331 /* Additional info. */
1332 if (is_date) {
1333 h->is_date = 1;
1334 h->res = res;
1335 }
1336 }
1337 }
1338 } while (xml_nextNode(node));
1339
1340 return 0;
1341}
Provides macros to work with dynamic arrays.
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition: array.h:168
int claim_testSys(const Claim_t *claim, int sys)
Tests to see if a system is claimed by a system claim.
Definition: claim.c:170
void claim_activateAll(void)
Activates all the claims.
Definition: claim.c:239
Event_t * event_get(unsigned int eventid)
Gets an event.
Definition: event.c:100
int event_save(unsigned int eventid)
Checks to see if an event should be saved.
Definition: event.c:284
int event_testClaims(unsigned int eventid, int sys)
Tests to see if an event has claimed a system.
Definition: event.c:729
static unsigned int hook_id
Definition: hook.c:113
static int hook_runningstack
Definition: hook.c:115
static ntime_t hook_time_accum
Definition: hook.c:57
unsigned int hook_addTimerEvt(unsigned int parent, const char *func, double ms)
Adds a new event type hook timer.
Definition: hook.c:563
int hook_runIDparam(unsigned int id, const HookParam *param)
Runs a single hook by id.
Definition: hook.c:1041
static int hook_parseParam(const HookParam *param)
Parses hook parameters.
Definition: hook.c:236
static Hook * hook_new(HookType_t type, const char *stack)
Generates and allocates a new hook.
Definition: hook.c:466
int hooks_runParam(const char *stack, const HookParam *param)
Runs all the hooks of stack.
Definition: hook.c:967
static int hook_runMisn(Hook *hook, const HookParam *param, int claims)
Runs a mission hook.
Definition: hook.c:293
void hook_rmMisnParent(unsigned int parent)
Removes all hooks belonging to parent mission.
Definition: hook.c:809
static void hq_free(HookQueue_t *hq)
Frees a queued hook.
Definition: hook.c:165
static int hook_loadingstack
Definition: hook.c:116
static void hq_clear(void)
Clears the queued hooks.
Definition: hook.c:174
int hook_load(xmlNodePtr parent)
Loads hooks for a player.
Definition: hook.c:1208
static Hook * hook_get(unsigned int id)
Gets a hook by ID.
Definition: hook.c:995
void hooks_update(double dt)
Updates all the hook timer related stuff.
Definition: hook.c:726
int hook_runID(unsigned int id)
Runs a single hook by id.
Definition: hook.c:1066
HookType_t
Types of hook.
Definition: hook.c:62
@ HOOK_TYPE_EVENT
Definition: hook.c:65
@ HOOK_TYPE_NULL
Definition: hook.c:63
@ HOOK_TYPE_MISN
Definition: hook.c:64
@ HOOK_TYPE_FUNC
Definition: hook.c:66
int hook_hasEventParent(unsigned int parent)
Checks to see how many hooks there are with the same event parent.
Definition: hook.c:850
static void hooks_updateDateExecute(ntime_t change)
Updates date hooks and runs them if necessary.
Definition: hook.c:644
static void hooks_purgeList(void)
Purges the list of deletable hooks.
Definition: hook.c:596
static int hq_add(HookQueue_t *hq)
Definition: hook.c:146
static HookQueue_t * hook_queue
Definition: hook.c:55
void hook_cleanup(void)
Gets rid of all current hooks.
Definition: hook.c:1104
int hooks_runParamDeferred(const char *stack, const HookParam *param)
Runs all the hooks of stack in the next frame. Does not trigger right away.
Definition: hook.c:935
static int hook_runEvent(Hook *hook, const HookParam *param, int claims)
Runs a Event function hook.
Definition: hook.c:351
static int hook_atomic
Definition: hook.c:56
nlua_env hook_env(unsigned int hook)
Gets the lua env for a hook.
Definition: hook.c:1007
void hooks_updateDate(ntime_t change)
Updates the time to see if it should be updated.
Definition: hook.c:635
static int hook_run(Hook *hook, const HookParam *param, int claims)
Runs a hook.
Definition: hook.c:400
static Mission * hook_getMission(Hook *hook)
Gets the mission of a hook.
Definition: hook.c:772
unsigned int hook_addEvent(unsigned int parent, const char *func, const char *stack)
Adds a new event type hook.
Definition: hook.c:519
static void hook_free(Hook *h)
Frees a hook.
Definition: hook.c:1076
void hook_rm(unsigned int id)
Removes a hook.
Definition: hook.c:786
static Hook * hook_list
Definition: hook.c:114
static int hook_needSave(Hook *h)
Checks if a hook needs to be saved.
Definition: hook.c:1127
void hook_exclusionEnd(double dt)
Ends exclusion zone and runs all the queued hooks.
Definition: hook.c:195
int hooks_run(const char *stack)
Runs all the hooks of stack.
Definition: hook.c:987
void hook_rmEventParent(unsigned int parent)
Removes all hooks belonging to parent event.
Definition: hook.c:821
unsigned int hook_addFunc(int(*func)(void *), void *data, const char *stack)
Adds a function hook to be run.
Definition: hook.c:582
static unsigned int hook_genID(void)
Generates a new hook id.
Definition: hook.c:443
int hook_hasMisnParent(unsigned int parent)
Checks to see how many hooks there are with the same mission parent.
Definition: hook.c:834
void hook_exclusionStart(void)
Starts the hook exclusion zone, this makes hooks queue until exclusion is done.
Definition: hook.c:187
unsigned int hook_addTimerMisn(unsigned int parent, const char *func, double ms)
Adds a new mission type hook timer hook.
Definition: hook.c:539
static int hook_parse(xmlNodePtr base)
Parses an individual hook.
Definition: hook.c:1237
unsigned int hook_addMisn(unsigned int parent, const char *func, const char *stack)
Adds a new mission type hook.
Definition: hook.c:499
static void hook_rmRaw(Hook *h)
Removes a hook.
Definition: hook.c:798
int hook_save(xmlTextWriterPtr writer)
Saves all the hooks.
Definition: hook.c:1159
Handles the important game menus.
#define MENU_MAIN
Definition: menu.h:9
#define menu_isOpen(f)
Definition: menu.h:16
Mission ** player_missions
Definition: mission.c:47
Header file with generic functions and naev-specifics.
#define MAX(x, y)
Definition: naev.h:39
void event_runStart(unsigned int eventid, const char *func)
Starts running a function, allows programmer to set up arguments.
Definition: nlua_evt.c:78
int event_runFunc(unsigned int eventid, const char *func, int nargs)
Runs a function previously set up with event_runStart.
Definition: nlua_evt.c:131
LuaFaction * lua_pushfaction(lua_State *L, LuaFaction faction)
Pushes a faction on the stack.
Definition: nlua_faction.c:192
void hookL_unsetarg(unsigned int hook)
Unsets a Lua argument.
Definition: nlua_hook.c:197
int hookL_getarg(unsigned int hook)
Gets a Lua argument for a hook.
Definition: nlua_hook.c:220
LuaJump * lua_pushjump(lua_State *L, LuaJump jump)
Pushes a jump on the stack.
Definition: nlua_jump.c:182
void misn_runStart(Mission *misn, const char *func)
Sets up the mission to run misn_runFunc.
Definition: nlua_misn.c:195
int misn_runFunc(Mission *misn, const char *func, int nargs)
Runs a mission set up with misn_runStart.
Definition: nlua_misn.c:215
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Definition: nlua_pilot.c:495
LuaSpob * lua_pushspob(lua_State *L, LuaSpob spob)
Pushes a spob on the stack.
Definition: nlua_spob.c:192
void pilots_rmHook(unsigned int hook)
Removes a hook from all the pilots.
Definition: pilot_hook.c:175
void player_runHooks(void)
Runs hooks for the player.
Definition: player.c:3034
Player_t player
Definition: player.c:73
static const double c[]
Definition: rng.c:264
StarSystem * cur_system
Definition: space.c:105
Activated event structure.
Definition: event.h:12
nlua_env env
Definition: event.h:15
The actual hook parameter.
Definition: hook.h:35
HookParamType type
Definition: hook.h:36
Hook queue to delay execution.
Definition: hook.c:49
struct HookQueue_s * next
Definition: hook.c:50
HookParam hparam[HOOK_MAX_PARAM]
Definition: hook.c:53
unsigned int id
Definition: hook.c:52
char * stack
Definition: hook.c:51
Internal representation of a hook.
Definition: hook.c:74
int delete
Definition: hook.c:80
struct Hook_ * next
Definition: hook.c:75
unsigned int id
Definition: hook.c:77
char * func
Definition: hook.c:97
int once
Definition: hook.c:82
ntime_t acc
Definition: hook.c:91
struct Hook::@9::@10 misn
int ran_once
Definition: hook.c:81
struct Hook::@9::@11 event
int is_timer
Definition: hook.c:85
int created
Definition: hook.c:79
ntime_t res
Definition: hook.c:90
unsigned int parent
Definition: hook.c:96
char * stack
Definition: hook.c:78
HookType_t type
Definition: hook.c:93
double ms
Definition: hook.c:86
int is_date
Definition: hook.c:89
union Hook::@9 u
Represents an active mission.
Definition: mission.h:79
Claim_t * claims
Definition: mission.h:103
nlua_env env
Definition: mission.h:105
Pilot * p
Definition: player.h:101