naev 0.10.4
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 "nstring.h"
24#include "opengl.h"
25#include "ndata.h"
26
30typedef enum NPCtype_ {
36
40typedef struct NPCevtData_ {
41 unsigned int id;
42 char *func;
47typedef struct NPCmisnData_ {
48 unsigned int id;
49 char *func;
54typedef struct NPC_s {
55 unsigned int id;
58 char *name;
61 char *desc;
62 union {
65 } u;
66} NPC_t;
67
68static unsigned int npc_array_idgen = 0;
69static NPC_t *npc_array = NULL;
71/* We have to store the missions temporarily here. */
72static Mission *npc_missions = NULL;
73
74/*
75 * Prototypes.
76 */
77/* NPCs. */
78static unsigned int npc_add( NPC_t *npc );
79static int npc_rm( NPC_t *npc );
80static NPC_t *npc_arrayGet( unsigned int id );
81static void npc_free( NPC_t *npc );
82/* Missions. */
83static Mission* npc_getMisn( const NPC_t *npc );
84
88static Mission* npc_getMisn( const NPC_t *npc )
89{
90 /* First check active missions. */
91 for (int i=0; i<array_size(player_missions); i++)
92 if (player_missions[i]->id == npc->u.m.id)
93 return player_missions[i];
94
95 /* Now check npc missions. */
96 for (int i=0; i<array_size(npc_missions); i++)
97 if (npc_missions[i].id == npc->u.m.id)
98 return &npc_missions[i];
99
100 return NULL;
101}
102
106static unsigned int npc_add( NPC_t *npc )
107{
108 NPC_t *new_npc;
109
110 /* Must be landed. */
111 if (!landed) {
112 npc_free( npc );
113 return 0;
114 }
115
116 /* Create if needed. */
117 if (npc_array == NULL)
119
120 /* Grow. */
121 new_npc = &array_grow( &npc_array );
122
123 /* Copy over. */
124 *new_npc = *npc;
125
126 /* Set ID. */
127 new_npc->id = ++npc_array_idgen;
128 return new_npc->id;
129}
130
134static unsigned int npc_add_giver( Mission *misn )
135{
136 NPC_t npc;
137
138 /* Sanity check. */
139 if (misn->npc == NULL) {
140 WARN(_("Mission '%s' trying to create NPC with no name!"), misn->data->name);
141 return 0;
142 }
143 if (misn->portrait == NULL) {
144 WARN(_("Mission '%s' trying to create NPC with no portrait!"), misn->data->name);
145 return 0;
146 }
147 if (misn->npc_desc == NULL) {
148 WARN(_("Mission '%s' trying to create NPC with no description!"), misn->data->name);
149 return 0;
150 }
151
152 /* Set up the data. */
153 npc.type = NPC_TYPE_GIVER;
154 npc.name = strdup(misn->npc);
155 npc.priority = misn->data->avail.priority;
156 npc.portrait = gl_dupTexture(misn->portrait);
157 npc.background = NULL;
158 npc.desc = strdup(misn->npc_desc);
159 npc.u.m.id = misn->id;
160 npc.u.m.func = strdup("accept");
161
162 return npc_add( &npc );
163}
164
168unsigned int npc_add_mission( unsigned int mid, const char *func, const char *name,
169 int priority, glTexture *portrait, const char *desc, glTexture *background )
170{
171 NPC_t npc;
172
173 /* The data. */
175 npc.name = strdup( name );
176 npc.priority = priority;
177 npc.portrait = portrait;
178 npc.background = background;
179 npc.desc = strdup( desc );
180 npc.u.m.id = mid;
181 npc.u.m.func = strdup( func );
182
183 return npc_add( &npc );
184}
185
189unsigned int npc_add_event( unsigned int evt, const char *func, const char *name,
190 int priority, glTexture *portrait, const char *desc, glTexture *background )
191{
192 NPC_t npc;
193
194 /* The data. */
195 npc.type = NPC_TYPE_EVENT;
196 npc.name = strdup( name );
197 npc.priority = priority;
198 npc.portrait = portrait;
199 npc.background = background;
200 npc.desc = strdup( desc );
201 npc.u.e.id = evt;
202 npc.u.e.func = strdup( func );
203
204 return npc_add( &npc );
205}
206
210static int npc_rm( NPC_t *npc )
211{
212 if (npc == NULL)
213 return 0;
214 npc_free(npc);
215 array_erase( &npc_array, &npc[0], &npc[1] );
216 return 0;
217}
218
222static NPC_t *npc_arrayGet( unsigned int id )
223{
224 for (int i=0; i<array_size( npc_array ); i++)
225 if (npc_array[i].id == id)
226 return &npc_array[i];
227 return NULL;
228}
229
233int npc_rm_event( unsigned int id, unsigned int evt )
234{
235 /* Get the NPC. */
236 NPC_t *npc = npc_arrayGet( id );
237 if (npc == NULL)
238 return -1;
239
240 /* Doesn't match type. */
241 if (npc->type != NPC_TYPE_EVENT)
242 return -1;
243
244 /* Doesn't belong to the event.. */
245 if (npc->u.e.id != evt)
246 return -1;
247
248 /* Remove the NPC. */
249 return npc_rm( npc );
250}
251
255int npc_rm_mission( unsigned int id, unsigned int mid )
256{
257 /* Get the NPC. */
258 NPC_t *npc = npc_arrayGet( id );
259 if (npc == NULL)
260 return -1;
261
262 /* Doesn't match type. */
263 if (npc->type != NPC_TYPE_MISSION)
264 return -1;
265
266 /* Doesn't belong to the mission. */
267 if (mid != npc->u.m.id)
268 return -1;
269
270 /* Remove the NPC. */
271 return npc_rm( npc );
272}
273
277int npc_rm_parentEvent( unsigned int id )
278{
279 int n = 0;
280 for (int i=0; i<array_size(npc_array); i++) {
281 NPC_t *npc = &npc_array[i];
282 if (npc->type != NPC_TYPE_EVENT)
283 continue;
284 if (npc->u.e.id != id )
285 continue;
286
287 /* Invalidates iterators. */
288 npc_rm( npc );
289 i--;
290 n++;
291 }
292
293 bar_regen();
294
295 return n;
296}
297
301int npc_rm_parentMission( unsigned int mid )
302{
303 int n = 0;
304 for (int i=0; i<array_size(npc_array); i++) {
305 NPC_t *npc = &npc_array[i];
306 if (npc->type != NPC_TYPE_MISSION)
307 continue;
308 if (npc->u.m.id != mid )
309 continue;
310
311 /* Invalidates iterators. */
312 npc_rm( npc );
313 i--;
314 n++;
315 }
316
317 bar_regen();
318
319 return n;
320}
321
325static int npc_compare( const void *arg1, const void *arg2 )
326{
327 const NPC_t *npc1, *npc2;
328 int ret;
329
330 npc1 = (NPC_t*)arg1;
331 npc2 = (NPC_t*)arg2;
332
333 /* Compare priority. */
334 if (npc1->priority > npc2->priority)
335 return +1;
336 else if (npc1->priority < npc2->priority)
337 return -1;
338
339 /* Compare name. */
340 ret = strcmp( npc1->name, npc2->name );
341 if (ret != 0)
342 return ret;
343
344 /* Compare ID. */
345 if (npc1->id > npc2->id)
346 return +1;
347 else if (npc1->id < npc2->id)
348 return -1;
349 return 0;
350}
351
355void npc_sort (void)
356{
357 if (npc_array != NULL)
358 qsort( npc_array, array_size(npc_array), sizeof(NPC_t), npc_compare );
359}
360
365{
366 Mission *missions;
367 int nmissions;
368
369 if (npc_missions == NULL)
370 npc_missions = array_create( Mission );
371
372 /* Get the missions. */
373 missions = missions_genList( &nmissions,
375 MIS_AVAIL_BAR );
376 /* Mission sshould already be generated and have had their 'create' function
377 * run, so NPCs should be running wild (except givers). */
378
379 /* Add to the bar NPC stack and add npc. */
380 for (int i=0; i<nmissions; i++) {
381 Mission *m = &missions[i];
382 array_push_back( &npc_missions, *m );
383
384 /* See if need to add NPC. */
385 if (m->npc)
386 npc_add_giver( m );
387
388#if DEBUGGING
389 /* Make sure the mission has created an NPC or it won't be able to do anything. */
390 int found = 0;
391 NPC_t *npc;
392 for (int j=0; j<array_size(npc_array); j++) {
393 npc = &npc_array[j];
394 if ((npc->type == NPC_TYPE_MISSION || npc->type == NPC_TYPE_GIVER) &&
395 npc->u.m.id == m->id) {
396 found = 1;
397 break;
398 }
399 }
400 if (!found)
401 WARN(_("Mission '%s' was created at the spaceport bar but didn't create any NPC!"), m->data->name);
402#endif /* DEBUGGING */
403 }
404
405 /* Clean up. */
406 free( missions );
407
408 /* Sort NPC. */
409 npc_sort();
410}
411
420{
421 if (npc_missions==NULL)
422 npc_missions = array_create( Mission );
423
424 /* Add to array. */
425 array_push_back( &npc_missions, *misn );
426
427 /* Add mission giver if necessary. */
428 if (misn->npc)
429 npc_add_giver( misn );
430
431 /* Sort NPC. */
432 npc_sort();
433}
434
438static void npc_free( NPC_t *npc )
439{
440 /* Common free stuff. */
441 if (npc == NULL)
442 return;
443 free(npc->name);
445 if (npc->background != NULL)
447 free(npc->desc);
448
449 /* Type-specific free stuff. */
450 switch (npc->type) {
451 case NPC_TYPE_GIVER:
452 case NPC_TYPE_MISSION:
453 free(npc->u.m.func);
454 break;
455
456 case NPC_TYPE_EVENT:
457 free(npc->u.e.func);
458 break;
459
460 default:
461 WARN(_("Freeing NPC of invalid type."));
462 return;
463 }
464}
465
469void npc_clear (void)
470{
471 /* Clear the npcs. */
472 for (int i=0; i<array_size( npc_array ); i++)
473 npc_free( &npc_array[i] );
475 npc_array = NULL;
476
477 /* Clear all the missions. */
478 for (int i=0; i<array_size( npc_missions ); i++) {
479 int j;
480 /* TODO this is horrible and should be removed */
481 /* Clean up all missions that haven't been moved to the active missions. */
482 for (j=0; j<array_size(player_missions); j++)
483 if (player_missions[j]->id == npc_missions[i].id)
484 break;
486 mission_cleanup( &npc_missions[i] );
487 }
488 array_free( npc_missions );
489 npc_missions = NULL;
490}
491
496{
497 return array_size( npc_array );
498}
499
503const char *npc_getName( int i )
504{
505 /* Make sure in bounds. */
506 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
507 return NULL;
508
509 return npc_array[i].name;
510}
511
516{
517 /* Make sure in bounds. */
518 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
519 return NULL;
520
521 /* TODO choose the background based on the spob or something. */
522 if (npc_array[i].background == NULL)
523 npc_array[i].background = gl_newImage( GFX_PATH"portraits/background.png", 0 );
524 return npc_array[i].background;
525}
526
531{
532 /* Make sure in bounds. */
533 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
534 return NULL;
535
536 return npc_array[i].portrait;
537}
538
542const char *npc_getDesc( int i )
543{
544 /* Make sure in bounds. */
545 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
546 return NULL;
547
548 return npc_array[i].desc;
549}
550
554int npc_isImportant( int i )
555{
556 /* Make sure in bounds. */
557 if (i<0 || npc_array == NULL || i>=array_size(npc_array))
558 return 0;
559
560 if (npc_array[i].priority <= 5)
561 return 1;
562 return 0;
563}
564
570static int npc_approach_giver( NPC_t *npc )
571{
572 int ret;
573 Mission *misn;
574 unsigned int id;
575
576 /* Get mission. */
577 misn = npc_getMisn( npc );
578 if (misn==NULL) {
579 WARN(_("Unable to find mission '%d' in npc_missions for giver npc '%s'!"), npc->u.m.id, npc->name);
580 return -1;
581 }
582 id = npc->id;
583 ret = mission_accept( misn );
584 if ((ret==3) || (ret==2) || (ret==-1)) { /* success in accepting the mission */
585 if (ret==-1)
586 mission_cleanup( misn );
587 npc_rm( npc_arrayGet(id) );
588 ret = 1;
589 }
590 else
591 ret = 0;
592
593 return ret;
594}
595
601int npc_approach( int i )
602{
603 NPC_t *npc;
604 Mission *misn;
605
606 /* Make sure in bounds. */
607 if (i<0 || i>=array_size(npc_array))
608 return -1;
609
610 /* Comfortability. */
611 npc = &npc_array[i];
612
613 /* Handle type. */
614 switch (npc->type) {
615 case NPC_TYPE_GIVER:
616 return npc_approach_giver( npc );
617
618 case NPC_TYPE_MISSION:
619 misn = npc_getMisn( npc );
620 if (misn==NULL) {
621 WARN(_("Unable to find mission '%d' in npc_missions for mission npc '%s'!"), npc->u.m.id, npc->name);
622 return -1;
623 }
624 misn_runStart( misn, npc->u.m.func );
625 lua_pushnumber( naevL, npc->id );
626 misn_runFunc( misn, npc->u.m.func, 1 );
627 break;
628
629 case NPC_TYPE_EVENT:
630 event_runStart( npc->u.e.id, npc->u.e.func );
631 lua_pushnumber( naevL, npc->id );
632 event_runFunc( npc->u.e.id, npc->u.e.func, 1 );
633 break;
634
635 default:
636 WARN(_("Unknown NPC type!"));
637 return -1;
638 }
639
640 return 0;
641}
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:452
int landed
Definition: land.c:74
Spob * land_spob
Definition: land.c:82
int mission_accept(Mission *mission)
Small wrapper for misn_run.
Definition: mission.c:199
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:846
void mission_cleanup(Mission *misn)
Cleans up a mission.
Definition: mission.c:677
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
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
const char * npc_getDesc(int i)
Gets the NPC description.
Definition: npc.c:542
static NPC_t * npc_array
Definition: npc.c:69
static int npc_rm(NPC_t *npc)
Removes an npc from the spaceport bar.
Definition: npc.c:210
void npc_patchMission(Mission *misn)
Patches a new mission bar npc into the bar system.
Definition: npc.c:419
void npc_generateMissions(void)
Generates the bar missions.
Definition: npc.c:364
glTexture * npc_getTexture(int i)
Get the texture of an NPC.
Definition: npc.c:530
static void npc_free(NPC_t *npc)
Frees a single npc.
Definition: npc.c:438
static unsigned int npc_add(NPC_t *npc)
Adds an NPC to the spaceport bar.
Definition: npc.c:106
int npc_approach(int i)
Approaches the NPC.
Definition: npc.c:601
int npc_rm_parentMission(unsigned int mid)
Removes all the npc belonging to a mission.
Definition: npc.c:301
NPCtype
NPC types.
Definition: npc.c:30
@ NPC_TYPE_MISSION
Definition: npc.c:33
@ NPC_TYPE_GIVER
Definition: npc.c:32
@ NPC_TYPE_EVENT
Definition: npc.c:34
@ NPC_TYPE_NULL
Definition: npc.c:31
void npc_clear(void)
Cleans up the spaceport bar NPC.
Definition: npc.c:469
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:189
static unsigned int npc_add_giver(Mission *misn)
Adds a mission giver NPC to the mission computer.
Definition: npc.c:134
int npc_getArraySize(void)
Get the size of the npc array.
Definition: npc.c:495
int npc_rm_parentEvent(unsigned int id)
Removes all the npc belonging to an event.
Definition: npc.c:277
glTexture * npc_getBackground(int i)
Get the background of an NPC.
Definition: npc.c:515
static unsigned int npc_array_idgen
Definition: npc.c:68
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:168
int npc_isImportant(int i)
Checks to see if the NPC is important or not.
Definition: npc.c:554
int npc_rm_mission(unsigned int id, unsigned int mid)
removes a mission NPC.
Definition: npc.c:255
static int npc_compare(const void *arg1, const void *arg2)
NPC compare function.
Definition: npc.c:325
int npc_rm_event(unsigned int id, unsigned int evt)
removes an event NPC.
Definition: npc.c:233
const char * npc_getName(int i)
Get the name of an NPC.
Definition: npc.c:503
static int npc_approach_giver(NPC_t *npc)
Approaches a mission giver guy.
Definition: npc.c:570
static Mission * npc_getMisn(const NPC_t *npc)
Definition: npc.c:88
static NPC_t * npc_arrayGet(unsigned int id)
Gets an NPC by ID.
Definition: npc.c:222
void npc_sort(void)
Sorts the NPCs.
Definition: npc.c:355
glTexture * gl_dupTexture(const glTexture *texture)
Duplicates a texture.
Definition: opengl_tex.c:809
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition: opengl_tex.c:570
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition: opengl_tex.c:755
StarSystem * cur_system
Definition: space.c:105
int priority
Definition: mission.h:53
char * name
Definition: mission.h:62
MissionAvail_t avail
Definition: mission.h:64
Represents an active mission.
Definition: mission.h:79
char * npc_desc
Definition: mission.h:90
unsigned int id
Definition: mission.h:81
glTexture * portrait
Definition: mission.h:88
const MissionData * data
Definition: mission.h:80
char * npc
Definition: mission.h:89
The bar NPC.
Definition: npc.c:54
NPCmisnData m
Definition: npc.c:63
char * name
Definition: npc.c:58
union NPC_t::@18 u
NPCevtData e
Definition: npc.c:64
unsigned int id
Definition: npc.c:55
NPCtype type
Definition: npc.c:56
char * desc
Definition: npc.c:61
glTexture * portrait
Definition: npc.c:59
glTexture * background
Definition: npc.c:60
int priority
Definition: npc.c:57
Minimum needed NPC data for event.
Definition: npc.c:40
unsigned int id
Definition: npc.c:41
char * func
Definition: npc.c:42
Minimum needed NPC data for mission.
Definition: npc.c:47
unsigned int id
Definition: npc.c:48
char * func
Definition: npc.c:49
int faction
Definition: space.h:66
SpobPresence presence
Definition: space.h:102
Abstraction for rendering sprite sheets.
Definition: opengl_tex.h:34