naev 0.11.5
npc.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <lua.h>
11
12#include "naev.h"
15#include "npc.h"
16
17#include "array.h"
18#include "dialogue.h"
19#include "event.h"
20#include "land.h"
21#include "log.h"
22#include "nlua_evt.h"
23#include "nlua_tex.h"
24#include "nstring.h"
25#include "opengl.h"
26#include "ndata.h"
27
37
41typedef struct NPCevtData_ {
42 unsigned int id;
43 char *func;
48typedef struct NPCmisnData_ {
49 unsigned int id;
50 char *func;
55typedef struct NPC_s {
56 unsigned int id;
59 char *name;
62 char *desc;
63 union {
66 } u;
67} NPC_t;
68
69static unsigned int npc_array_idgen = 0;
70static NPC_t *npc_array = NULL;
72/* We have to store the missions temporarily here. */
73static Mission *npc_missions = NULL;
74
75/*
76 * Prototypes.
77 */
78/* NPCs. */
79static unsigned int npc_add( NPC_t *npc );
80static int npc_rm( NPC_t *npc );
81static NPC_t *npc_arrayGet( unsigned int id );
82static void npc_free( NPC_t *npc );
83/* Missions. */
84static Mission* npc_getMisn( const NPC_t *npc );
85
89static Mission* npc_getMisn( const NPC_t *npc )
90{
91 /* First check active missions. */
92 for (int i=0; i<array_size(player_missions); i++)
93 if (player_missions[i]->id == npc->u.m.id)
94 return player_missions[i];
95
96 /* Now check npc missions. */
97 for (int i=0; i<array_size(npc_missions); i++)
98 if (npc_missions[i].id == npc->u.m.id)
99 return &npc_missions[i];
100
101 return NULL;
102}
103
107static unsigned int npc_add( NPC_t *npc )
108{
109 NPC_t *new_npc;
110
111 /* Must be landed. */
112 if (!landed) {
113 npc_free( npc );
114 return 0;
115 }
116
117 /* Create if needed. */
118 if (npc_array == NULL)
120
121 /* Grow. */
122 new_npc = &array_grow( &npc_array );
123
124 /* Copy over. */
125 *new_npc = *npc;
126
127 /* Set ID. */
128 new_npc->id = ++npc_array_idgen;
129 return new_npc->id;
130}
131
135static unsigned int npc_add_giver( Mission *misn )
136{
137 NPC_t npc;
138
139 /* Sanity check. */
140 if (misn->npc == NULL) {
141 WARN(_("Mission '%s' trying to create NPC with no name!"), misn->data->name);
142 return 0;
143 }
144 if (misn->portrait == NULL) {
145 WARN(_("Mission '%s' trying to create NPC with no portrait!"), misn->data->name);
146 return 0;
147 }
148 if (misn->npc_desc == NULL) {
149 WARN(_("Mission '%s' trying to create NPC with no description!"), misn->data->name);
150 return 0;
151 }
152
153 /* Set up the data. */
154 npc.type = NPC_TYPE_GIVER;
155 npc.name = strdup(misn->npc);
156 npc.priority = misn->data->avail.priority;
157 npc.portrait = gl_dupTexture(misn->portrait);
158 npc.background = NULL;
159 npc.desc = strdup(misn->npc_desc);
160 npc.u.m.id = misn->id;
161 npc.u.m.func = strdup("accept");
162
163 return npc_add( &npc );
164}
165
169unsigned int npc_add_mission( unsigned int mid, const char *func, const char *name,
170 int priority, glTexture *portrait, const char *desc, glTexture *background )
171{
172 NPC_t npc;
173
174 /* The data. */
176 npc.name = strdup( name );
177 npc.priority = priority;
178 npc.portrait = portrait;
179 npc.background = background;
180 npc.desc = strdup( desc );
181 npc.u.m.id = mid;
182 npc.u.m.func = strdup( func );
183
184 return npc_add( &npc );
185}
186
190unsigned int npc_add_event( unsigned int evt, const char *func, const char *name,
191 int priority, glTexture *portrait, const char *desc, glTexture *background )
192{
193 NPC_t npc;
194
195 /* The data. */
196 npc.type = NPC_TYPE_EVENT;
197 npc.name = strdup( name );
198 npc.priority = priority;
199 npc.portrait = portrait;
200 npc.background = background;
201 npc.desc = strdup( desc );
202 npc.u.e.id = evt;
203 npc.u.e.func = strdup( func );
204
205 return npc_add( &npc );
206}
207
211static int npc_rm( NPC_t *npc )
212{
213 if (npc == NULL)
214 return 0;
215 npc_free(npc);
216 array_erase( &npc_array, &npc[0], &npc[1] );
217 return 0;
218}
219
223static NPC_t *npc_arrayGet( unsigned int id )
224{
225 for (int i=0; i<array_size( npc_array ); i++)
226 if (npc_array[i].id == id)
227 return &npc_array[i];
228 return NULL;
229}
230
234int npc_rm_event( unsigned int id, unsigned int evt )
235{
236 /* Get the NPC. */
237 NPC_t *npc = npc_arrayGet( id );
238 if (npc == NULL)
239 return -1;
240
241 /* Doesn't match type. */
242 if (npc->type != NPC_TYPE_EVENT)
243 return -1;
244
245 /* Doesn't belong to the event.. */
246 if (npc->u.e.id != evt)
247 return -1;
248
249 /* Remove the NPC. */
250 return npc_rm( npc );
251}
252
256int npc_rm_mission( unsigned int id, unsigned int mid )
257{
258 /* Get the NPC. */
259 NPC_t *npc = npc_arrayGet( id );
260 if (npc == NULL)
261 return -1;
262
263 /* Doesn't match type. */
264 if (npc->type != NPC_TYPE_MISSION)
265 return -1;
266
267 /* Doesn't belong to the mission. */
268 if (mid != npc->u.m.id)
269 return -1;
270
271 /* Remove the NPC. */
272 return npc_rm( npc );
273}
274
278int npc_rm_parentEvent( unsigned int id )
279{
280 int n = 0;
281 for (int i=0; i<array_size(npc_array); i++) {
282 NPC_t *npc = &npc_array[i];
283 if (npc->type != NPC_TYPE_EVENT)
284 continue;
285 if (npc->u.e.id != id )
286 continue;
287
288 /* Invalidates iterators. */
289 npc_rm( npc );
290 i--;
291 n++;
292 }
293
294 bar_regen();
295
296 return n;
297}
298
302int npc_rm_parentMission( unsigned int mid )
303{
304 int n = 0;
305 for (int i=0; i<array_size(npc_array); i++) {
306 NPC_t *npc = &npc_array[i];
307 if (npc->type != NPC_TYPE_MISSION)
308 continue;
309 if (npc->u.m.id != mid )
310 continue;
311
312 /* Invalidates iterators. */
313 npc_rm( npc );
314 i--;
315 n++;
316 }
317
318 bar_regen();
319
320 return n;
321}
322
326static int npc_compare( const void *arg1, const void *arg2 )
327{
328 const NPC_t *npc1, *npc2;
329 int ret;
330
331 npc1 = (NPC_t*)arg1;
332 npc2 = (NPC_t*)arg2;
333
334 /* Compare priority. */
335 if (npc1->priority > npc2->priority)
336 return +1;
337 else if (npc1->priority < npc2->priority)
338 return -1;
339
340 /* Compare name. */
341 ret = strcmp( npc1->name, npc2->name );
342 if (ret != 0)
343 return ret;
344
345 /* Compare ID. */
346 if (npc1->id > npc2->id)
347 return +1;
348 else if (npc1->id < npc2->id)
349 return -1;
350 return 0;
351}
352
356void npc_sort (void)
357{
358 if (npc_array != NULL)
359 qsort( npc_array, array_size(npc_array), sizeof(NPC_t), npc_compare );
360}
361
366{
367 Mission *missions;
368 int nmissions;
369
370 if (npc_missions == NULL)
371 npc_missions = array_create( Mission );
372
373 /* Get the missions. */
374 missions = missions_genList( &nmissions,
376 MIS_AVAIL_BAR );
377 /* Mission sshould already be generated and have had their 'create' function
378 * run, so NPCs should be running wild (except givers). */
379
380 /* Add to the bar NPC stack and add npc. */
381 for (int i=0; i<nmissions; i++) {
382 Mission *m = &missions[i];
383 array_push_back( &npc_missions, *m );
384
385 /* See if need to add NPC. */
386 if (m->npc)
387 npc_add_giver( m );
388
389#if DEBUGGING
390 /* Make sure the mission has created an NPC or it won't be able to do anything. */
391 int found = 0;
392 NPC_t *npc;
393 for (int j=0; j<array_size(npc_array); j++) {
394 npc = &npc_array[j];
395 if ((npc->type == NPC_TYPE_MISSION || npc->type == NPC_TYPE_GIVER) &&
396 npc->u.m.id == m->id) {
397 found = 1;
398 break;
399 }
400 }
401 if (!found)
402 WARN(_("Mission '%s' was created at the spaceport bar but didn't create any NPC!"), m->data->name);
403#endif /* DEBUGGING */
404 }
405
406 /* Clean up. */
407 free( missions );
408
409 /* Sort NPC. */
410 npc_sort();
411}
412
421{
422 if (npc_missions==NULL)
423 npc_missions = array_create( Mission );
424
425 /* Add to array. */
426 array_push_back( &npc_missions, *misn );
427
428 /* Add mission giver if necessary. */
429 if (misn->npc)
430 npc_add_giver( misn );
431
432 /* Sort NPC. */
433 npc_sort();
434}
435
439static void npc_free( NPC_t *npc )
440{
441 /* Common free stuff. */
442 if (npc == NULL)
443 return;
444 free(npc->name);
446 if (npc->background != NULL)
448 free(npc->desc);
449
450 /* Type-specific free stuff. */
451 switch (npc->type) {
452 case NPC_TYPE_GIVER:
453 case NPC_TYPE_MISSION:
454 free(npc->u.m.func);
455 break;
456
457 case NPC_TYPE_EVENT:
458 free(npc->u.e.func);
459 break;
460
461 default:
462 WARN(_("Freeing NPC of invalid type."));
463 return;
464 }
465}
466
470void npc_clear (void)
471{
472 /* Clear the npcs. */
473 for (int i=0; i<array_size( npc_array ); i++)
474 npc_free( &npc_array[i] );
476 npc_array = NULL;
477
478 /* Clear all the missions. */
479 for (int i=0; i<array_size( npc_missions ); i++) {
480 int j;
481 /* TODO this is horrible and should be removed */
482 /* Clean up all missions that haven't been moved to the active missions. */
483 for (j=0; j<array_size(player_missions); j++)
484 if (player_missions[j]->id == npc_missions[i].id)
485 break;
487 mission_cleanup( &npc_missions[i] );
488 }
489 array_free( npc_missions );
490 npc_missions = NULL;
491}
492
497{
498 return array_size( npc_array );
499}
500
504const char *npc_getName( int i )
505{
506 /* Make sure in bounds. */
507 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
508 return NULL;
509
510 return npc_array[i].name;
511}
512
517{
518 NPC_t *npc;
519
520 /* Make sure in bounds. */
521 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
522 return NULL;
523 npc = &npc_array[i];
524
525 /* TODO choose the background based on the spob or something. */
526 if (npc->background == NULL) {
527 if (land_spob->lua_barbg != LUA_NOREF) {
529 lua_rawgeti(naevL, LUA_REGISTRYINDEX, land_spob->lua_barbg); /* f */
530 if (nlua_pcall( land_spob->lua_env, 0, 1 )) {
531 WARN(_("Spob '%s' failed to run '%s':\n%s"), land_spob->name, "barbg", lua_tostring(naevL,-1));
532 lua_pop(naevL,1);
533 }
534
535 if (lua_istex(naevL,-1))
536 npc->background = gl_dupTexture( lua_totex(naevL,-1) );
537 else
538 WARN(_("Spob '%s''s '%s' did not return a texture!"), land_spob->name, "barbg");
539 lua_pop(naevL,1);
540 }
541 if (npc->background == NULL)
542 npc->background = gl_newImage( GFX_PATH"portraits/background.png", 0 );
543 }
544
545 return npc->background;
546}
547
552{
553 /* Make sure in bounds. */
554 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
555 return NULL;
556
557 return npc_array[i].portrait;
558}
559
563const char *npc_getDesc( int i )
564{
565 /* Make sure in bounds. */
566 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
567 return NULL;
568
569 return npc_array[i].desc;
570}
571
575int npc_isImportant( int i )
576{
577 /* Make sure in bounds. */
578 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
579 return 0;
580
581 if (npc_array[i].priority <= 5)
582 return 1;
583 return 0;
584}
585
591static int npc_approach_giver( NPC_t *npc )
592{
593 int ret;
594 Mission *misn;
595 unsigned int id;
596
597 /* Get mission. */
598 misn = npc_getMisn( npc );
599 if (misn==NULL) {
600 WARN(_("Unable to find mission '%d' in npc_missions for giver npc '%s'!"), npc->u.m.id, npc->name);
601 return -1;
602 }
603 id = npc->id;
604 ret = mission_accept( misn );
605 if ((ret==3) || (ret==2) || (ret==-1)) { /* success in accepting the mission */
606 if (ret==-1)
607 mission_cleanup( misn );
608 npc_rm( npc_arrayGet(id) );
609 ret = 1;
610 }
611 else
612 ret = 0;
613
614 return ret;
615}
616
622int npc_approach( int i )
623{
624 NPC_t *npc;
625 Mission *misn;
626
627 /* Make sure in bounds. */
628 if (i<0 || i>=array_size(npc_array))
629 return -1;
630
631 /* Comfortability. */
632 npc = &npc_array[i];
633
634 /* Handle type. */
635 switch (npc->type) {
636 case NPC_TYPE_GIVER:
637 return npc_approach_giver( npc );
638
639 case NPC_TYPE_MISSION:
640 misn = npc_getMisn( npc );
641 if (misn==NULL) {
642 WARN(_("Unable to find mission '%d' in npc_missions for mission npc '%s'!"), npc->u.m.id, npc->name);
643 return -1;
644 }
645 misn_runStart( misn, npc->u.m.func );
646 lua_pushnumber( naevL, npc->id );
647 misn_runFunc( misn, npc->u.m.func, 1 );
648 break;
649
650 case NPC_TYPE_EVENT:
651 event_runStart( npc->u.e.id, npc->u.e.func );
652 lua_pushnumber( naevL, npc->id );
653 event_runFunc( npc->u.e.id, npc->u.e.func, 1 );
654 break;
655
656 default:
657 WARN(_("Unknown NPC type!"));
658 return -1;
659 }
660
661 return 0;
662}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:140
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:129
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
void bar_regen(void)
Regenerates the bar list.
Definition land.c:382
int landed
Definition land.c:75
Spob * land_spob
Definition land.c:83
int mission_accept(Mission *mission)
Small wrapper for misn_run.
Definition mission.c:206
Mission ** player_missions
Definition mission.c:47
Mission * missions_genList(int *n, int faction, const Spob *pnt, const StarSystem *sys, MissionAvailability loc)
Generates a mission list. This runs create() so won't work with all missions.
Definition mission.c:914
void mission_cleanup(Mission *misn)
Cleans up a mission.
Definition mission.c:739
Header file with generic functions and naev-specifics.
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
glTexture * lua_totex(lua_State *L, int ind)
Lua bindings to interact with OpenGL textures.
Definition nlua_tex.c:89
int lua_istex(lua_State *L, int ind)
Checks to see if ind is a texture.
Definition nlua_tex.c:145
const char * npc_getDesc(int i)
Gets the NPC description.
Definition npc.c:563
static NPC_t * npc_array
Definition npc.c:70
static int npc_rm(NPC_t *npc)
Removes an npc from the spaceport bar.
Definition npc.c:211
void npc_patchMission(Mission *misn)
Patches a new mission bar npc into the bar system.
Definition npc.c:420
void npc_generateMissions(void)
Generates the bar missions.
Definition npc.c:365
glTexture * npc_getTexture(int i)
Get the texture of an NPC.
Definition npc.c:551
static void npc_free(NPC_t *npc)
Frees a single npc.
Definition npc.c:439
static unsigned int npc_add(NPC_t *npc)
Adds an NPC to the spaceport bar.
Definition npc.c:107
int npc_approach(int i)
Approaches the NPC.
Definition npc.c:622
int npc_rm_parentMission(unsigned int mid)
Removes all the npc belonging to a mission.
Definition npc.c:302
NPCtype
NPC types.
Definition npc.c:31
@ NPC_TYPE_MISSION
Definition npc.c:34
@ NPC_TYPE_GIVER
Definition npc.c:33
@ NPC_TYPE_EVENT
Definition npc.c:35
@ NPC_TYPE_NULL
Definition npc.c:32
void npc_clear(void)
Cleans up the spaceport bar NPC.
Definition npc.c:470
unsigned int npc_add_event(unsigned int evt, const char *func, const char *name, int priority, glTexture *portrait, const char *desc, glTexture *background)
Adds a event NPC to the mission computer.
Definition npc.c:190
static unsigned int npc_add_giver(Mission *misn)
Adds a mission giver NPC to the mission computer.
Definition npc.c:135
int npc_getArraySize(void)
Get the size of the npc array.
Definition npc.c:496
int npc_rm_parentEvent(unsigned int id)
Removes all the npc belonging to an event.
Definition npc.c:278
glTexture * npc_getBackground(int i)
Get the background of an NPC.
Definition npc.c:516
static unsigned int npc_array_idgen
Definition npc.c:69
unsigned int npc_add_mission(unsigned int mid, const char *func, const char *name, int priority, glTexture *portrait, const char *desc, glTexture *background)
Adds a mission NPC to the mission computer.
Definition npc.c:169
int npc_isImportant(int i)
Checks to see if the NPC is important or not.
Definition npc.c:575
int npc_rm_mission(unsigned int id, unsigned int mid)
removes a mission NPC.
Definition npc.c:256
static int npc_compare(const void *arg1, const void *arg2)
NPC compare function.
Definition npc.c:326
int npc_rm_event(unsigned int id, unsigned int evt)
removes an event NPC.
Definition npc.c:234
const char * npc_getName(int i)
Get the name of an NPC.
Definition npc.c:504
static int npc_approach_giver(NPC_t *npc)
Approaches a mission giver guy.
Definition npc.c:591
static Mission * npc_getMisn(const NPC_t *npc)
Definition npc.c:89
static NPC_t * npc_arrayGet(unsigned int id)
Gets an NPC by ID.
Definition npc.c:223
void npc_sort(void)
Sorts the NPCs.
Definition npc.c:356
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition opengl_tex.c:917
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:675
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:862
StarSystem * cur_system
Definition space.c:106
void spob_luaInitMem(const Spob *spob)
Initializes the memory fo a spob.
Definition space.c:1986
char * name
Definition mission.h:63
MissionAvail_t avail
Definition mission.h:65
Represents an active mission.
Definition mission.h:81
char * npc_desc
Definition mission.h:92
unsigned int id
Definition mission.h:83
glTexture * portrait
Definition mission.h:90
const MissionData * data
Definition mission.h:82
char * npc
Definition mission.h:91
The bar NPC.
Definition npc.c:55
NPCmisnData m
Definition npc.c:64
char * name
Definition npc.c:59
NPCevtData e
Definition npc.c:65
unsigned int id
Definition npc.c:56
NPCtype type
Definition npc.c:57
char * desc
Definition npc.c:62
glTexture * portrait
Definition npc.c:60
glTexture * background
Definition npc.c:61
int priority
Definition npc.c:58
union NPC_t::@30 u
Minimum needed NPC data for event.
Definition npc.c:41
unsigned int id
Definition npc.c:42
char * func
Definition npc.c:43
Minimum needed NPC data for mission.
Definition npc.c:48
unsigned int id
Definition npc.c:49
char * func
Definition npc.c:50
int faction
Definition space.h:67
int lua_barbg
Definition space.h:149
nlua_env lua_env
Definition space.h:138
char * name
Definition space.h:91
SpobPresence presence
Definition space.h:104
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:36