naev 0.12.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>
12
13#include "npc.h"
14
15#include "array.h"
16#include "land.h"
17#include "log.h"
18#include "ndata.h"
19#include "nlua_evt.h"
20#include "nlua_tex.h"
21#include "ntracing.h"
22
32
36typedef struct NPCevtData_ {
37 unsigned int id;
38 char *func;
40
43typedef struct NPCmisnData_ {
44 unsigned int id;
45 char *func;
47
50typedef struct NPC_s {
51 unsigned int id;
54 char *name;
57 char *desc;
58 union {
61 } u;
62} NPC_t;
63
64static unsigned int npc_array_idgen = 0;
65static NPC_t *npc_array = NULL;
66
67/* We have to store the missions temporarily here. */
68static Mission *npc_missions = NULL;
69
70/*
71 * Prototypes.
72 */
73/* NPCs. */
74static unsigned int npc_add( NPC_t *npc );
75static int npc_rm( NPC_t *npc );
76static NPC_t *npc_arrayGet( unsigned int id );
77static void npc_free( NPC_t *npc );
78/* Missions. */
79static Mission *npc_getMisn( const NPC_t *npc );
80
84static Mission *npc_getMisn( const NPC_t *npc )
85{
86 /* First check active missions. */
87 for ( int i = 0; i < array_size( player_missions ); i++ )
88 if ( player_missions[i]->id == npc->u.m.id )
89 return player_missions[i];
90
91 /* Now check npc missions. */
92 for ( int i = 0; i < array_size( npc_missions ); i++ )
93 if ( npc_missions[i].id == npc->u.m.id )
94 return &npc_missions[i];
95
96 return NULL;
97}
98
102static unsigned int npc_add( NPC_t *npc )
103{
104 NPC_t *new_npc;
105
106 /* Must be landed. */
107 if ( !landed ) {
108 npc_free( npc );
109 return 0;
110 }
111
112 /* Create if needed. */
113 if ( npc_array == NULL )
115
116 /* Grow. */
117 new_npc = &array_grow( &npc_array );
118
119 /* Copy over. */
120 *new_npc = *npc;
121
122 /* Set ID. */
123 new_npc->id = ++npc_array_idgen;
124 return new_npc->id;
125}
126
130static unsigned int npc_add_giver( Mission *misn )
131{
132 NPC_t npc;
133
134 /* Sanity check. */
135 if ( misn->npc == NULL ) {
136 WARN( _( "Mission '%s' trying to create NPC with no name!" ),
137 misn->data->name );
138 return 0;
139 }
140 if ( misn->portrait == NULL ) {
141 WARN( _( "Mission '%s' trying to create NPC with no portrait!" ),
142 misn->data->name );
143 return 0;
144 }
145 if ( misn->npc_desc == NULL ) {
146 WARN( _( "Mission '%s' trying to create NPC with no description!" ),
147 misn->data->name );
148 return 0;
149 }
150
151 /* Set up the data. */
152 npc.type = NPC_TYPE_GIVER;
153 npc.name = strdup( misn->npc );
154 npc.priority = misn->data->avail.priority;
155 npc.portrait = gl_dupTexture( misn->portrait );
156 npc.background = NULL;
157 npc.desc = strdup( misn->npc_desc );
158 npc.u.m.id = misn->id;
159 npc.u.m.func = strdup( "accept" );
160
161 return npc_add( &npc );
162}
163
167unsigned int npc_add_mission( unsigned int mid, const char *func,
168 const char *name, int priority,
169 glTexture *portrait, const char *desc,
170 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,
191 const char *name, int priority, glTexture *portrait,
192 const char *desc, glTexture *background )
193{
194 NPC_t npc;
195
196 /* The data. */
197 npc.type = NPC_TYPE_EVENT;
198 npc.name = strdup( name );
199 npc.priority = priority;
200 npc.portrait = portrait;
201 npc.background = background;
202 npc.desc = strdup( desc );
203 npc.u.e.id = evt;
204 npc.u.e.func = strdup( func );
205
206 return npc_add( &npc );
207}
208
212static int npc_rm( NPC_t *npc )
213{
214 if ( npc == NULL )
215 return 0;
216 npc_free( npc );
217 array_erase( &npc_array, &npc[0], &npc[1] );
218 return 0;
219}
220
224static NPC_t *npc_arrayGet( unsigned int id )
225{
226 for ( int i = 0; i < array_size( npc_array ); i++ )
227 if ( npc_array[i].id == id )
228 return &npc_array[i];
229 return NULL;
230}
231
235int npc_rm_event( unsigned int id, unsigned int evt )
236{
237 /* Get the NPC. */
238 NPC_t *npc = npc_arrayGet( id );
239 if ( npc == NULL )
240 return -1;
241
242 /* Doesn't match type. */
243 if ( npc->type != NPC_TYPE_EVENT )
244 return -1;
245
246 /* Doesn't belong to the event.. */
247 if ( npc->u.e.id != evt )
248 return -1;
249
250 /* Remove the NPC. */
251 return npc_rm( npc );
252}
253
257int npc_rm_mission( unsigned int id, unsigned int mid )
258{
259 /* Get the NPC. */
260 NPC_t *npc = npc_arrayGet( id );
261 if ( npc == NULL )
262 return -1;
263
264 /* Doesn't match type. */
265 if ( npc->type != NPC_TYPE_MISSION )
266 return -1;
267
268 /* Doesn't belong to the mission. */
269 if ( mid != npc->u.m.id )
270 return -1;
271
272 /* Remove the NPC. */
273 return npc_rm( npc );
274}
275
279int npc_rm_parentEvent( unsigned int id )
280{
281 int n = 0;
282 for ( int i = 0; i < array_size( npc_array ); i++ ) {
283 NPC_t *npc = &npc_array[i];
284 if ( npc->type != NPC_TYPE_EVENT )
285 continue;
286 if ( npc->u.e.id != id )
287 continue;
288
289 /* Invalidates iterators. */
290 npc_rm( npc );
291 i--;
292 n++;
293 }
294
295 bar_regen();
296
297 return n;
298}
299
303int npc_rm_parentMission( unsigned int mid )
304{
305 int n = 0;
306 for ( int i = 0; i < array_size( npc_array ); i++ ) {
307 NPC_t *npc = &npc_array[i];
308 if ( npc->type != NPC_TYPE_MISSION )
309 continue;
310 if ( npc->u.m.id != mid )
311 continue;
312
313 /* Invalidates iterators. */
314 npc_rm( npc );
315 i--;
316 n++;
317 }
318
319 bar_regen();
320
321 return n;
322}
323
327static int npc_compare( const void *arg1, const void *arg2 )
328{
329 const NPC_t *npc1, *npc2;
330 int ret;
331
332 npc1 = (NPC_t *)arg1;
333 npc2 = (NPC_t *)arg2;
334
335 /* Compare priority. */
336 if ( npc1->priority > npc2->priority )
337 return +1;
338 else if ( npc1->priority < npc2->priority )
339 return -1;
340
341 /* Compare name. */
342 ret = strcmp( npc1->name, npc2->name );
343 if ( ret != 0 )
344 return ret;
345
346 /* Compare ID. */
347 if ( npc1->id > npc2->id )
348 return +1;
349 else if ( npc1->id < npc2->id )
350 return -1;
351 return 0;
352}
353
357void npc_sort( void )
358{
359 if ( npc_array != NULL )
360 qsort( npc_array, array_size( npc_array ), sizeof( NPC_t ), npc_compare );
361}
362
367{
368 Mission *missions;
369
370 NTracingZone( _ctx, 1 );
371
372 if ( npc_missions == NULL )
373 npc_missions = array_create( Mission );
374
375 /* Get the missions. */
376 missions = missions_genList( land_spob->presence.faction, land_spob,
377 cur_system, MIS_AVAIL_BAR );
378 /* Mission sshould already be generated and have had their 'create' function
379 * run, so NPCs should be running wild (except givers). */
380
381 /* Add to the bar NPC stack and add npc. */
382 for ( int i = 0; i < array_size( missions ); i++ ) {
383 Mission *m = &missions[i];
384 array_push_back( &npc_missions, *m );
385
386 /* See if need to add NPC. */
387 if ( m->npc )
388 npc_add_giver( m );
389
390#if DEBUGGING
391 /* Make sure the mission has created an NPC or it won't be able to do
392 * anything. */
393 int found = 0;
394 NPC_t *npc;
395 for ( int j = 0; j < array_size( npc_array ); j++ ) {
396 npc = &npc_array[j];
397 if ( ( npc->type == NPC_TYPE_MISSION ||
398 npc->type == NPC_TYPE_GIVER ) &&
399 npc->u.m.id == m->id ) {
400 found = 1;
401 break;
402 }
403 }
404 if ( !found )
405 WARN( _( "Mission '%s' was created at the spaceport bar but didn't "
406 "create any NPC!" ),
407 m->data->name );
408#endif /* DEBUGGING */
409 }
410
411 /* Clean up. */
412 array_free( missions );
413
414 /* Sort NPC. */
415 npc_sort();
416
417 NTracingZoneEnd( _ctx );
418}
419
428{
429 if ( npc_missions == NULL )
430 npc_missions = array_create( Mission );
431
432 /* Add to array. */
433 array_push_back( &npc_missions, *misn );
434
435 /* Add mission giver if necessary. */
436 if ( misn->npc )
437 npc_add_giver( misn );
438
439 /* Sort NPC. */
440 npc_sort();
441}
442
446static void npc_free( NPC_t *npc )
447{
448 /* Common free stuff. */
449 if ( npc == NULL )
450 return;
451 free( npc->name );
452 gl_freeTexture( npc->portrait );
453 if ( npc->background != NULL )
455 free( npc->desc );
456
457 /* Type-specific free stuff. */
458 switch ( npc->type ) {
459 case NPC_TYPE_GIVER:
460 case NPC_TYPE_MISSION:
461 free( npc->u.m.func );
462 break;
463
464 case NPC_TYPE_EVENT:
465 free( npc->u.e.func );
466 break;
467
468 default:
469 WARN( _( "Freeing NPC of invalid type." ) );
470 return;
471 }
472}
473
477void npc_clear( void )
478{
479 /* Clear the npcs. */
480 for ( int i = 0; i < array_size( npc_array ); i++ )
481 npc_free( &npc_array[i] );
483 npc_array = NULL;
484
485 /* Clear all the missions. */
486 for ( int i = 0; i < array_size( npc_missions ); i++ ) {
487 int j;
488 /* TODO this is horrible and should be removed */
489 /* Clean up all missions that haven't been moved to the active missions.
490 */
491 for ( j = 0; j < array_size( player_missions ); j++ )
492 if ( player_missions[j]->id == npc_missions[i].id )
493 break;
494 if ( j >= array_size( player_missions ) )
495 mission_cleanup( &npc_missions[i] );
496 }
497 array_free( npc_missions );
498 npc_missions = NULL;
499}
500
505{
506 return array_size( npc_array );
507}
508
512const char *npc_getName( int i )
513{
514 /* Make sure in bounds. */
515 if ( i < 0 || npc_array == NULL || i >= array_size( npc_array ) )
516 return NULL;
517
518 return npc_array[i].name;
519}
520
525{
526 NPC_t *npc;
527
528 /* Make sure in bounds. */
529 if ( i < 0 || npc_array == NULL || i >= array_size( npc_array ) )
530 return NULL;
531 npc = &npc_array[i];
532
533 /* TODO choose the background based on the spob or something. */
534 if ( npc->background == NULL ) {
535 if ( land_spob->lua_barbg != LUA_NOREF ) {
537 lua_rawgeti( naevL, LUA_REGISTRYINDEX, land_spob->lua_barbg ); /* f */
538 if ( nlua_pcall( land_spob->lua_env, 0, 1 ) ) {
539 WARN( _( "Spob '%s' failed to run '%s':\n%s" ), land_spob->name,
540 "barbg", lua_tostring( naevL, -1 ) );
541 lua_pop( naevL, 1 );
542 }
543
544 if ( lua_istex( naevL, -1 ) )
545 npc->background = gl_dupTexture( lua_totex( naevL, -1 ) );
546 else
547 WARN( _( "Spob '%s''s '%s' did not return a texture!" ),
548 land_spob->name, "barbg" );
549 lua_pop( naevL, 1 );
550 }
551 if ( npc->background == NULL )
552 npc->background =
553 gl_newImage( GFX_PATH "portraits/background.png", 0 );
554 }
555
556 return npc->background;
557}
558
563{
564 /* Make sure in bounds. */
565 if ( i < 0 || npc_array == NULL || i >= array_size( npc_array ) )
566 return NULL;
567
568 return npc_array[i].portrait;
569}
570
574const char *npc_getDesc( int i )
575{
576 /* Make sure in bounds. */
577 if ( i < 0 || npc_array == NULL || i >= array_size( npc_array ) )
578 return NULL;
579
580 return npc_array[i].desc;
581}
582
586int npc_isImportant( int i )
587{
588 /* Make sure in bounds. */
589 if ( i < 0 || npc_array == NULL || i >= array_size( npc_array ) )
590 return 0;
591
592 if ( npc_array[i].priority <= 5 )
593 return 1;
594 return 0;
595}
596
602static int npc_approach_giver( NPC_t *npc )
603{
604 int ret;
605 Mission *misn;
606 unsigned int id;
607
608 /* Get mission. */
609 misn = npc_getMisn( npc );
610 if ( misn == NULL ) {
611 WARN(
612 _( "Unable to find mission '%d' in npc_missions for giver npc '%s'!" ),
613 npc->u.m.id, npc->name );
614 return -1;
615 }
616 id = npc->id;
617 ret = mission_accept( misn );
618 if ( ( ret == 3 ) || ( ret == 2 ) ||
619 ( ret == -1 ) ) { /* success in accepting the mission */
620 if ( ret == -1 )
621 mission_cleanup( misn );
622 npc_rm( npc_arrayGet( id ) );
623 ret = 1;
624 } else
625 ret = 0;
626
627 return ret;
628}
629
635int npc_approach( int i )
636{
637 NPC_t *npc;
638 Mission *misn;
639
640 /* Make sure in bounds. */
641 if ( i < 0 || i >= array_size( npc_array ) )
642 return -1;
643
644 /* Comfortability. */
645 npc = &npc_array[i];
646
647 /* Handle type. */
648 switch ( npc->type ) {
649 case NPC_TYPE_GIVER:
650 return npc_approach_giver( npc );
651
652 case NPC_TYPE_MISSION:
653 misn = npc_getMisn( npc );
654 if ( misn == NULL ) {
655 WARN( _( "Unable to find mission '%d' in npc_missions for mission npc "
656 "'%s'!" ),
657 npc->u.m.id, npc->name );
658 return -1;
659 }
660 misn_runStart( misn, npc->u.m.func );
661 lua_pushnumber( naevL, npc->id );
662 misn_runFunc( misn, npc->u.m.func, 1 );
663 break;
664
665 case NPC_TYPE_EVENT:
666 event_runStart( npc->u.e.id, npc->u.e.func );
667 lua_pushnumber( naevL, npc->id );
668 event_runFunc( npc->u.e.id, npc->u.e.func, 1 );
669 break;
670
671 default:
672 WARN( _( "Unknown NPC type!" ) );
673 return -1;
674 }
675
676 return 0;
677}
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_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_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:432
int landed
Definition land.c:78
Spob * land_spob
Definition land.c:87
int mission_accept(Mission *mission)
Small wrapper for misn_run.
Definition mission.c:210
Mission ** player_missions
Definition mission.c:45
void mission_cleanup(Mission *misn)
Cleans up a mission.
Definition mission.c:779
Mission * missions_genList(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:954
lua_State * naevL
Definition nlua.c:54
void event_runStart(unsigned int eventid, const char *func)
Starts running a function, allows programmer to set up arguments.
Definition nlua_evt.c:67
int event_runFunc(unsigned int eventid, const char *func, int nargs)
Runs a function previously set up with event_runStart.
Definition nlua_evt.c:120
glTexture * lua_totex(lua_State *L, int ind)
Lua bindings to interact with OpenGL textures.
Definition nlua_tex.c:86
int lua_istex(lua_State *L, int ind)
Checks to see if ind is a texture.
Definition nlua_tex.c:144
const char * npc_getDesc(int i)
Gets the NPC description.
Definition npc.c:574
static NPC_t * npc_array
Definition npc.c:65
static int npc_rm(NPC_t *npc)
Removes an npc from the spaceport bar.
Definition npc.c:212
void npc_patchMission(Mission *misn)
Patches a new mission bar npc into the bar system.
Definition npc.c:427
void npc_generateMissions(void)
Generates the bar missions.
Definition npc.c:366
glTexture * npc_getTexture(int i)
Get the texture of an NPC.
Definition npc.c:562
static void npc_free(NPC_t *npc)
Frees a single npc.
Definition npc.c:446
static unsigned int npc_add(NPC_t *npc)
Adds an NPC to the spaceport bar.
Definition npc.c:102
int npc_approach(int i)
Approaches the NPC.
Definition npc.c:635
int npc_rm_parentMission(unsigned int mid)
Removes all the npc belonging to a mission.
Definition npc.c:303
NPCtype
NPC types.
Definition npc.c:26
@ NPC_TYPE_MISSION
Definition npc.c:29
@ NPC_TYPE_GIVER
Definition npc.c:28
@ NPC_TYPE_EVENT
Definition npc.c:30
@ NPC_TYPE_NULL
Definition npc.c:27
void npc_clear(void)
Cleans up the spaceport bar NPC.
Definition npc.c:477
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:130
int npc_getArraySize(void)
Get the size of the npc array.
Definition npc.c:504
int npc_rm_parentEvent(unsigned int id)
Removes all the npc belonging to an event.
Definition npc.c:279
glTexture * npc_getBackground(int i)
Get the background of an NPC.
Definition npc.c:524
static unsigned int npc_array_idgen
Definition npc.c:64
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:167
int npc_isImportant(int i)
Checks to see if the NPC is important or not.
Definition npc.c:586
int npc_rm_mission(unsigned int id, unsigned int mid)
removes a mission NPC.
Definition npc.c:257
static int npc_compare(const void *arg1, const void *arg2)
NPC compare function.
Definition npc.c:327
int npc_rm_event(unsigned int id, unsigned int evt)
removes an event NPC.
Definition npc.c:235
const char * npc_getName(int i)
Get the name of an NPC.
Definition npc.c:512
static int npc_approach_giver(NPC_t *npc)
Approaches a mission giver guy.
Definition npc.c:602
static Mission * npc_getMisn(const NPC_t *npc)
Definition npc.c:84
static NPC_t * npc_arrayGet(unsigned int id)
Gets an NPC by ID.
Definition npc.c:224
void npc_sort(void)
Sorts the NPCs.
Definition npc.c:357
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
StarSystem * cur_system
Definition space.c:110
void spob_luaInitMem(const Spob *spob)
Initializes the memory fo a spob.
Definition space.c:2109
char * name
Definition mission.h:65
MissionAvail_t avail
Definition mission.h:67
Represents an active mission.
Definition mission.h:83
char * npc_desc
Definition mission.h:97
unsigned int id
Definition mission.h:86
glTexture * portrait
Definition mission.h:93
const MissionData * data
Definition mission.h:84
char * npc
Definition mission.h:96
The bar NPC.
Definition npc.c:50
NPCmisnData m
Definition npc.c:59
char * name
Definition npc.c:54
NPCevtData e
Definition npc.c:60
unsigned int id
Definition npc.c:51
union NPC_t::@375332274224061363170363060137023356135267020276 u
NPCtype type
Definition npc.c:52
char * desc
Definition npc.c:57
glTexture * portrait
Definition npc.c:55
glTexture * background
Definition npc.c:56
int priority
Definition npc.c:53
Minimum needed NPC data for event.
Definition npc.c:36
unsigned int id
Definition npc.c:37
char * func
Definition npc.c:38
Minimum needed NPC data for mission.
Definition npc.c:43
unsigned int id
Definition npc.c:44
char * func
Definition npc.c:45
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:43