naev 0.10.4
effect.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "naev.h"
13#include "effect.h"
14
15#include "array.h"
16#include "conf.h"
17#include "log.h"
18#include "nxml.h"
19#include "ndata.h"
20#include "gui.h"
21#include "nlua_pilot.h"
22
23static EffectData *effect_list = NULL; /* List of all available effects. */
24
28static int effect_cmp( const void *p1, const void *p2 )
29{
30 const EffectData *e1 = p1;
31 const EffectData *e2 = p2;
32 return strcmp( e1->name, e2->name );
33}
34
38static int effect_cmpTimer( const void *p1, const void *p2 )
39{
40 const Effect *e1 = p1;
41 const Effect *e2 = p2;
42 return e1->timer - e2->timer;
43}
44
48static int effect_parse( EffectData *efx, const char *file )
49{
50 xmlNodePtr node, parent;
51 xmlDocPtr doc = xml_parsePhysFS( file );
52 if (doc == NULL)
53 return -1;
54
55 parent = doc->xmlChildrenNode; /* first system node */
56 if (parent == NULL) {
57 ERR( _("Malformed '%s' file: does not contain elements"), file );
58 return -1;
59 }
60
61 /* Clear data. */
62 memset( efx, 0, sizeof(EffectData) );
63 efx->duration = -1.;
64 efx->priority = 5;
65 efx->lua_env = LUA_NOREF;
66 efx->lua_add = LUA_NOREF;
67 efx->lua_extend= LUA_NOREF;
68 efx->lua_remove= LUA_NOREF;
69
70 xmlr_attr_strd(parent,"name",efx->name);
71 if (efx->name == NULL)
72 WARN(_("Effect '%s' has invalid or no name"), file);
73
74 node = parent->xmlChildrenNode;
75 do { /* load all the data */
76 /* Only handle nodes. */
77 xml_onlyNodes(node);
78
79 xmlr_strd(node, "description", efx->desc);
80 xmlr_strd(node, "overwrite", efx->overwrite);
81 xmlr_int(node, "priority", efx->priority);
82 xmlr_float(node, "duration", efx->duration);
83 if (xml_isNode(node,"icon")) {
84 efx->icon = xml_parseTexture( node, "%s", 1, 1, OPENGL_TEX_MIPMAPS );
85 continue;
86 }
87 if (xml_isNode(node,"shader")) {
88 char *vertex;
89 xmlr_attr_strd(node,"vertex",vertex);
90 if (vertex == NULL)
91 vertex = strdup("effect.vert");
92 efx->program = gl_program_vert_frag( vertex, xml_get(node) );
93 free( vertex );
94 efx->vertex = glGetAttribLocation( efx->program, "vertex" );
95 efx->projection= glGetUniformLocation( efx->program, "projection" );
96 efx->tex_mat = glGetUniformLocation( efx->program, "tex_mat" );
97 efx->dimensions= glGetUniformLocation( efx->program, "dimensions" );
98 efx->u_r = glGetUniformLocation( efx->program, "u_r" );
99 efx->u_tex = glGetUniformLocation( efx->program, "u_tex" );
100 efx->u_timer = glGetUniformLocation( efx->program, "u_timer" );
101 efx->u_elapsed = glGetUniformLocation( efx->program, "u_elapsed" );
102 continue;
103 }
104 if (xml_isNode(node,"lua")) {
105 nlua_env env;
106 size_t sz;
107 const char *filename = xml_get(node);
108 char *dat = ndata_read( filename, &sz );
109 if (dat==NULL) {
110 WARN(_("Effect '%s' failed to read Lua '%s'!"), efx->name, filename );
111 continue;
112 }
113
114 env = nlua_newEnv();
115 nlua_loadStandard( env );
116 if (nlua_dobufenv( env, dat, sz, filename ) != 0) {
117 WARN(_("Effect '%s' Lua error:\n%s"), efx->name, lua_tostring(naevL,-1));
118 lua_pop(naevL,1);
119 nlua_freeEnv( env );
120 free( dat );
121 continue;
122 }
123 efx->lua_env = env;
124 efx->lua_add = nlua_refenvtype( env, "add", LUA_TFUNCTION );
125 efx->lua_extend= nlua_refenvtype( env, "extend",LUA_TFUNCTION );
126 efx->lua_remove= nlua_refenvtype( env, "remove",LUA_TFUNCTION );
127 free( dat );
128 continue;
129 }
130
131 if (xml_isNode(node,"stats")) {
132 xmlNodePtr cur = node->children;
133 do {
134 ShipStatList *ll;
135 xml_onlyNodes(cur);
136 /* Stats. */
137 ll = ss_listFromXML( cur );
138 if (ll != NULL) {
139 ll->next = efx->stats;
140 efx->stats = ll;
141 continue;
142 }
143 WARN(_("Effect '%s' has unknown node '%s'"), efx->name, cur->name);
144 } while (xml_nextNode(cur));
145 continue;
146 }
147 WARN(_("Effect '%s' has unknown node '%s'"),efx->name, node->name);
148 } while (xml_nextNode(node));
149
150#define MELEMENT(o,s) \
151if (o) WARN( _("Effect '%s' missing/invalid '%s' element"), efx->name, s)
152 MELEMENT(efx->name==NULL,"name");
153 MELEMENT(efx->desc==NULL,"description");
154 MELEMENT(efx->duration<0.,"duration");
155 MELEMENT(efx->icon==NULL,"icon");
156#undef MELEMENT
157
158 xmlFreeDoc(doc);
159
160 return 0;
161}
162
168int effect_load (void)
169{
170 int ne;
171 Uint32 time = SDL_GetTicks();
172 char **effect_files = ndata_listRecursive( EFFECT_DATA_PATH );
173 effect_list = array_create( EffectData );
174
175 for (int i=0; i<array_size(effect_files); i++) {
176 if (ndata_matchExt( effect_files[i], "xml" )) {
177 EffectData ed;
178 int ret = effect_parse( &ed, effect_files[i] );
179 if (ret == 0)
180 array_push_back( &effect_list, ed );
181 }
182 free( effect_files[i] );
183 }
184 array_free( effect_files );
185
186 ne = array_size(effect_list);
187 qsort( effect_list, ne, sizeof(EffectData), effect_cmp );
188
189 if (conf.devmode) {
190 time = SDL_GetTicks() - time;
191 DEBUG( n_( "Loaded %d Effect in %.3f s", "Loaded %d Effects in %.3f s", ne ), ne, time/1000. );
192 }
193 else
194 DEBUG( n_( "Loaded %d Effect", "Loaded %d Effects", ne ), ne );
195
196 return 0;
197}
198
202void effect_exit (void)
203{
204 for (int i=0; i<array_size(effect_list); i++) {
205 EffectData *e = &effect_list[i];
206 nlua_freeEnv( e->lua_env );
207 free( e->name );
208 free( e->desc );
209 free( e->overwrite );
210 gl_freeTexture( e->icon );
211 ss_free( e->stats );
212 }
213 array_free( effect_list );
214}
215
222const EffectData *effect_get( const char *name )
223{
224 const EffectData k = { .name = (char*)name };
225 EffectData *e = bsearch( &k, effect_list, array_size(effect_list), sizeof(EffectData), effect_cmp );
226 if (e==NULL)
227 WARN(_("Trying to get unknown effect data '%s'!"), name);
228 return e;
229}
230
238int effect_update( Effect **efxlist, double dt )
239{
240 int n = 0;
241 for (int i=array_size(*efxlist)-1; i>=0; i--) {
242 Effect *e = &(*efxlist)[i];
243 e->timer -= dt;
244 e->elapsed += dt;
245 if (e->timer > 0.)
246 continue;
247
248 /* Run Lua if necessary. */
249 if (e->data->lua_remove != LUA_NOREF) {
250 lua_rawgeti(naevL, LUA_REGISTRYINDEX, e->data->lua_remove); /* f */
251 lua_pushpilot(naevL, e->parent);
252 if (nlua_pcall( e->data->lua_env, 1, 0 )) {
253 WARN(_("Effect '%s' failed to run '%s':\n%s"), e->data->name, "remove", lua_tostring(naevL,-1));
254 lua_pop(naevL,1);
255 }
256 }
257
258 /* Get rid of it. */
259 array_erase( efxlist, e, e+1 );
260 n++;
261 }
262 if (n>0)
263 gui_updateEffects();
264 return n;
265}
266
277int effect_add( Effect **efxlist, const EffectData *efx, double duration, double scale, unsigned int parent )
278{
279 Effect *e = NULL;
280 int overwrite = 0;
281
282 if (*efxlist == NULL)
283 *efxlist = array_create( Effect );
284
285 /* See if we should overwrite. */
286 if (efx->overwrite != NULL) {
287 for (int i=0; i<array_size(*efxlist); i++) {
288 Effect *el = &(*efxlist)[i];
289 if ((el->data->overwrite!=NULL) &&
290 (efx->priority <= el->data->priority) &&
291 (strcmp(efx->overwrite, el->data->overwrite)==0)) {
292 e = el;
293 if (e->data == efx)
294 overwrite = 1;
295 else {
296 if (e->data->lua_remove != LUA_NOREF) {
297 lua_rawgeti(naevL, LUA_REGISTRYINDEX, e->data->lua_remove); /* f */
298 lua_pushpilot(naevL, e->parent);
299 if (nlua_pcall( e->data->lua_env, 1, 0 )) {
300 WARN(_("Effect '%s' failed to run '%s':\n%s"), e->data->name, "remove", lua_tostring(naevL,-1));
301 lua_pop(naevL,1);
302 }
303 }
304 }
305 break;
306 }
307 }
308 }
309
310 /* Add new effect if necessary. */
311 if (e==NULL) {
312 e = &array_grow( efxlist );
313 e->elapsed = 0.; /* Don't 0. when overwriting. */
314 e->r = RNGF();
315 }
316 e->data = efx;
317 e->duration = (duration > 0.) ? duration : efx->duration;
318 e->timer = e->duration;
319 e->scale = scale;
320 e->parent = parent;
321
322 /* Run Lua if necessary. */
323 if (overwrite) {
324 if (efx->lua_extend != LUA_NOREF) {
325 lua_rawgeti(naevL, LUA_REGISTRYINDEX, e->data->lua_extend); /* f */
326 lua_pushpilot(naevL, e->parent);
327 if (nlua_pcall( e->data->lua_env, 1, 0 )) {
328 WARN(_("Effect '%s' failed to run '%s':\n%s"), e->data->name, "extend", lua_tostring(naevL,-1));
329 lua_pop(naevL,1);
330 }
331 }
332 }
333 else {
334 if (efx->lua_add != LUA_NOREF) {
335 lua_rawgeti(naevL, LUA_REGISTRYINDEX, e->data->lua_add); /* f */
336 lua_pushpilot(naevL, e->parent);
337 if (nlua_pcall( e->data->lua_env, 1, 0 )) {
338 WARN(_("Effect '%s' failed to run '%s':\n%s"), e->data->name, "add", lua_tostring(naevL,-1));
339 lua_pop(naevL,1);
340 }
341 }
342 }
343
344 /* Sort and update. */
345 qsort( *efxlist, array_size(*efxlist), sizeof(Effect), effect_cmpTimer );
346 gui_updateEffects();
347 return 0;
348}
349
358int effect_rm( Effect **efxlist, const EffectData *efx, int all )
359{
360 int ret = 0;
361 for (int i=array_size(*efxlist)-1; i>=0; i++) {
362 const Effect *e = &(*efxlist)[i];
363 if (e->data != efx)
364 continue;
365 /* Run Lua if necessary. */
366 if (e->data->lua_remove != LUA_NOREF) {
367 lua_rawgeti(naevL, LUA_REGISTRYINDEX, e->data->lua_remove); /* f */
368 lua_pushpilot(naevL, e->parent);
369 if (nlua_pcall( e->data->lua_env, 1, 0 )) {
370 WARN(_("Effect '%s' failed to run '%s':\n%s"), e->data->name, "remove", lua_tostring(naevL,-1));
371 lua_pop(naevL,1);
372 }
373 }
374 array_erase( efxlist, &e[0], &e[1] );
375 if (!all)
376 return 1;
377 ret++;
378 }
379 return ret;
380}
381
387void effect_clear( Effect **efxlist )
388{
389 for (int i=0; i<array_size(*efxlist); i++) {
390 const Effect *e = &(*efxlist)[i];
391 /* Run Lua if necessary. */
392 if (e->data->lua_remove != LUA_NOREF) {
393 lua_rawgeti(naevL, LUA_REGISTRYINDEX, e->data->lua_remove); /* f */
394 lua_pushpilot(naevL, e->parent);
395 if (nlua_pcall( e->data->lua_env, 1, 0 )) {
396 WARN(_("Effect '%s' failed to run '%s':\n%s"), e->data->name, "remove", lua_tostring(naevL,-1));
397 lua_pop(naevL,1);
398 }
399 }
400 }
401 array_erase( efxlist, array_begin(*efxlist), array_end(*efxlist) );
402}
403
410void effect_compute( ShipStats *s, const Effect *efxlist )
411{
412 for (int i=0; i<array_size(efxlist); i++) {
413 const Effect *e = &efxlist[i];
415 }
416}
417
423void effect_cleanup( Effect *efxlist )
424{
425 array_free( efxlist );
426}
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_end(array)
Returns a pointer to the end of the reserved memory space.
Definition: array.h:202
#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_begin(array)
Returns a pointer to the beginning of the reserved memory space.
Definition: array.h:194
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition: array.h:93
static int effect_cmp(const void *p1, const void *p2)
Compares effects based on name.
Definition: effect.c:28
int effect_rm(Effect **efxlist, const EffectData *efx, int all)
Removes an effect from an effect list.
Definition: effect.c:358
static int effect_parse(EffectData *efx, const char *file)
Parsess an effect.
Definition: effect.c:48
const EffectData * effect_get(const char *name)
Gets an effect by name.
Definition: effect.c:222
void effect_cleanup(Effect *efxlist)
Cleans up an effect list freeing it.
Definition: effect.c:423
void effect_clear(Effect **efxlist)
Clears an effect list, removing all active effects.
Definition: effect.c:387
int effect_add(Effect **efxlist, const EffectData *efx, double duration, double scale, unsigned int parent)
Adds an effect to an effect list.
Definition: effect.c:277
static int effect_cmpTimer(const void *p1, const void *p2)
Compares effects based on timer.
Definition: effect.c:38
void effect_compute(ShipStats *s, const Effect *efxlist)
Updates shipstats from effect list.
Definition: effect.c:410
int effect_load(void)
Loads all the effects.
Definition: effect.c:168
void effect_exit(void)
Gets rid of all the effects.
Definition: effect.c:202
int effect_update(Effect **efxlist, double dt)
Updates an effect list.
Definition: effect.c:238
Header file with generic functions and naev-specifics.
void * ndata_read(const char *path, size_t *filesize)
Reads a file from the ndata (will be NUL terminated).
Definition: ndata.c:154
int ndata_matchExt(const char *path, const char *ext)
Sees if a file matches an extension.
Definition: ndata.c:366
char ** ndata_listRecursive(const char *path)
Lists all the visible files in a directory, at any depth.
Definition: ndata.c:232
int nlua_loadStandard(nlua_env env)
Loads the standard Naev Lua API.
Definition: nlua.c:760
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:873
LuaPilot * lua_pushpilot(lua_State *L, LuaPilot pilot)
Pushes a pilot on the stack.
Definition: nlua_pilot.c:495
glTexture * xml_parseTexture(xmlNodePtr node, const char *path, int defsx, int defsy, const unsigned int flags)
Parses a texture handling the sx and sy elements.
Definition: nxml.c:29
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition: nxml.c:75
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition: opengl_tex.c:755
void ss_free(ShipStatList *ll)
Frees a list of ship stats.
Definition: shipstats.c:807
int ss_statsModFromListScale(ShipStats *stats, const ShipStatList *list, double scale)
Updates a stat structure from a stat list.
Definition: shipstats.c:558
ShipStatList * ss_listFromXML(xmlNodePtr node)
Creates a shipstat list element from an xml node.
Definition: shipstats.c:209
Pilot ship effect data.
Definition: effect.h:13
int lua_extend
Definition: effect.h:34
nlua_env lua_env
Definition: effect.h:32
char * desc
Definition: effect.h:15
int lua_remove
Definition: effect.h:35
int priority
Definition: effect.h:17
int lua_add
Definition: effect.h:33
double duration
Definition: effect.h:18
ShipStatList * stats
Definition: effect.h:19
char * name
Definition: effect.h:14
glTexture * icon
Definition: effect.h:21
char * overwrite
Definition: effect.h:16
Pilot ship effect.
Definition: effect.h:41
double r
Definition: effect.h:47
double scale
Definition: effect.h:46
const EffectData * data
Definition: effect.h:42
double elapsed
Definition: effect.h:48
unsigned int parent
Definition: effect.h:43
double timer
Definition: effect.h:44
double duration
Definition: effect.h:45
int devmode
Definition: conf.h:158
Represents relative ship statistics as a linked list.
Definition: shipstats.h:167
struct ShipStatList_ * next
Definition: shipstats.h:168
Represents ship statistics, properties ship can use.
Definition: shipstats.h:198