1 /*
2 *
3 * Copyright (c) 2014 Samuel Degrande
4 *
5 * This file is part of Freedroid
6 *
7 * Freedroid is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * Freedroid is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Freedroid; see the file COPYING. If not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 * MA 02111-1307 USA
21 *
22 */
23
24 /**
25 * \file luaFD_npc.c
26 * \brief This file contains the definition of the NPC Lua binding.
27 */
28
29 #include "system.h"
30
31 #include "defs.h"
32 #include "struct.h"
33 #include "global.h"
34 #include "proto.h"
35
36 #include "luaFD.h"
37
38 /*
39 * From a Lua script point of view, a NPC is, currently, composed by the
40 * association of an 'enemy' C struct and a 'npc' C struct (if a dialog exists
41 * for that enemy).
42 * The Lua binding holds a reference to the 2 datastructures defining the
43 * 'NPC'.
44 */
45
46 struct luaFD_npc {
47 struct enemy* enemy_ref;
48 struct npc* npc_ref;
49 };
50
51 /**
52 * Called when Lua garbagecollects the NPC.
53 */
_garbage_collect(lua_State * L)54 static int _garbage_collect(lua_State *L)
55 {
56 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
57 // Nothing to do, currently
58 return 0;
59 }
60
61 /**
62 * Retrieve current chat context, and fail with error if there is no dialog
63 * currently running.
64 */
__get_current_chat_context(const char * funcname)65 static struct chat_context *__get_current_chat_context(const char *funcname)
66 {
67 struct chat_context *current_chat_context = chat_get_current_context();
68 if (!current_chat_context)
69 error_message(funcname, _("No chat context available on the context stack."), PLEASE_INFORM | IS_FATAL);
70 return current_chat_context;
71 }
72
73 #define GET_CURRENT_CHAT_CONTEXT() __get_current_chat_context(__FUNCTION__)
74
75 ///////////////////////////////////////////////////////////////////////////////
76 /// \defgroup FDnpc FDnpc: Lua NPC binding
77 /// \ingroup luaFD_bindings
78 ///
79 /// Some doc on FDnpc - TO BE WRITTEN
80 ///
81 ///@{
82 // start FDnpc submodule
83 // Note: Functions comments are written to reflect their Lua usage.
84
85 /**
86 * \brief Get NPC's name (enemy's short description)
87 *
88 * \param self [\p FDnpc] FDnpc instance
89 *
90 * \return [\p string] Name
91 *
92 * \bindtype cfun
93 */
LUAFD_DOC(string get_name (self))94 LUAFD_DOC(string get_name(self))
95
96 static int _get_name(lua_State *L)
97 {
98 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
99
100 if (self->enemy_ref->short_description_text)
101 lua_pushstring(L, self->enemy_ref->short_description_text);
102 else
103 return luaL_error(L, "This NPC has no name ?");
104
105 return 1;
106 }
107
108 /**
109 * \brief Get translated npc's name (enemy's short description)
110 *
111 * \param self [\p FDnpc] FDnpc instance
112 *
113 * \return [\p string] Translated name
114 *
115 * \bindtype cfun
116 */
LUAFD_DOC(string get_translated_name (self))117 LUAFD_DOC(string get_translated_name(self))
118
119 static int _get_translated_name(lua_State *L)
120 {
121 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
122
123 if (self->enemy_ref->short_description_text)
124 lua_pushstring(L, D_(self->enemy_ref->short_description_text));
125 else
126 return luaL_error(L, "This NPC has no name ?");
127
128 return 1;
129 }
130
131 /**
132 * \brief Set npc's name (enemy's short description)
133 *
134 * \param self [\p FDnpc] FDnpc instance
135 * \param name [\p string] New name
136 *
137 * \bindtype cfun
138 */
LUAFD_DOC(void set_name (self,name))139 LUAFD_DOC(void set_name(self, name))
140
141 static int _set_name(lua_State *L)
142 {
143 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
144
145 const char *npc_name = luaL_checkstring(L, 2);
146 free(self->enemy_ref->short_description_text);
147 self->enemy_ref->short_description_text = strdup(npc_name);
148 return 0;
149 }
150
151 /**
152 * \brief Get npc's type (enemy's type)
153 *
154 * \param self [\p FDnpc] FDnpc instance
155 *
156 * \return [\p string] Type
157 *
158 * \bindtype cfun
159 */
LUAFD_DOC(string get_type (self))160 LUAFD_DOC(string get_type(self))
161
162 static int _get_type(lua_State *L)
163 {
164 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
165
166 lua_pushstring(L, Droidmap[self->enemy_ref->type].droidname);
167 return 1;
168 }
169
170 /**
171 * \brief Get npc's class (enemy's class)
172 *
173 * \param self [\p FDnpc] FDnpc instance
174 *
175 * \return [\p string] Class
176 *
177 * \bindtype cfun
178 */
LUAFD_DOC(string get_class (self))179 LUAFD_DOC(string get_class(self))
180
181 static int _get_class(lua_State *L)
182 {
183 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
184
185 lua_pushinteger(L, (lua_Integer)Droidmap[self->enemy_ref->type].class);
186 return 1;
187 }
188
189 /**
190 * \brief Set npc's state (enemy's state)
191 *
192 * \param self [\p FDnpc] FDnpc instance
193 * \param state [\p string] New state
194 *
195 * \bindtype cfun
196 */
LUAFD_DOC(void set_state (self,state))197 LUAFD_DOC(void set_state(self, state))
198
199 static int _set_state(lua_State *L)
200 {
201 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
202
203 const char *cmd = luaL_checkstring(L, 2);
204 enemy_set_state(self->enemy_ref, cmd);
205 return 0;
206 }
207
208 /**
209 * \brief Set npc's faction
210 *
211 * \param self [\p FDnpc] FDnpc instance
212 * \param faction [\p string] New faction
213 *
214 * \bindtype cfun
215 */
LUAFD_DOC(void set_state (self,faction))216 LUAFD_DOC(void set_state(self, faction))
217
218 static int _set_faction(lua_State *L)
219 {
220 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
221
222 const char *faction = luaL_checkstring(L, 2);
223 self->enemy_ref->faction = get_faction_id(faction);
224 return 0;
225 }
226
227 /**
228 * \brief Set npc's new destination (map label)
229 *
230 * \param self [\p FDnpc] FDnpc instance
231 * \param label [\p string] Map label to set as the new destination
232 *
233 * \bindtype cfun
234 */
LUAFD_DOC(void set_destination (self,label))235 LUAFD_DOC(void set_destination(self, label))
236
237 static int _set_destination(lua_State *L)
238 {
239 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
240
241 const char *label = luaL_checkstring(L, 2);
242 enemy_set_destination(self->enemy_ref, label);
243 return 0;
244 }
245
246 /**
247 * \brief Set npc to rush Tux or not
248 *
249 * \param self [\p FDnpc] FDnpc instance
250 * \param flag [\p boolean] true/false: If 'true', the npc will rush Tux
251 *
252 * \bindtype cfun
253 */
LUAFD_DOC(void set_rush_tux (self,flag))254 LUAFD_DOC(void set_rush_tux(self, flag))
255
256 static int _set_rush_tux(lua_State *L)
257 {
258 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
259
260 if (!lua_isboolean(L, 2)) {
261 return luaL_error(L, "boolean expected, got %s", luaL_typename(L, 2));
262 }
263 const uint8_t flag = (uint8_t)lua_toboolean(L, 2);
264 self->enemy_ref->will_rush_tux = flag;
265 return 0;
266 }
267
268 /**
269 * \brief Return npc's ability to rush Tux or not
270 *
271 * \param self [\p FDnpc] FDnpc instance
272 *
273 * \return [\p boolean] 'true' if the npc's is configured to rush Tux, 'false' otherwise
274 *
275 * \bindtype cfun
276 */
LUAFD_DOC(boolean get_rush_tux (self))277 LUAFD_DOC(boolean get_rush_tux(self))
278
279 static int _get_rush_tux(lua_State * L)
280 {
281 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
282
283 lua_pushboolean(L, self->enemy_ref->will_rush_tux);
284 return 1;
285 }
286
287 /**
288 * \brief Get npc's current HP value
289 *
290 * \param self [\p FDnpc] FDnpc instance
291 *
292 * \return [\p number] NPC's current HP
293 *
294 * \bindtype cfun
295 */
LUAFD_DOC(number get_health (self))296 LUAFD_DOC(number get_health(self))
297
298 static int _get_health(lua_State *L)
299 {
300 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
301
302 lua_pushnumber(L, self->enemy_ref->energy);
303 return 1;
304 }
305
306 /**
307 * \brief Get npc's maximum HP value
308 *
309 * \param self [\p FDnpc] FDnpc instance
310 *
311 * \return [\p number] NPC's maximum HP
312 *
313 * \bindtype cfun
314 */
LUAFD_DOC(number get_max_health (self))315 LUAFD_DOC(number get_max_health(self))
316
317 static int _get_max_health(lua_State *L)
318 {
319 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
320
321 lua_pushnumber(L, Droidmap[self->enemy_ref->type].maxenergy);
322 return 1;
323 }
324
325 /**
326 * \brief Set the item dropped when the npc dies.
327 *
328 * \param self [\p FDnpc] FDnpc instance
329 * \param item [\p string] Item's name (or "NONE")
330 *
331 * \bindtype cfun
332 */
LUAFD_DOC(void set_death_item (self,item))333 LUAFD_DOC(void set_death_item(self, item))
334
335 static int _set_death_item(lua_State * L)
336 {
337 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
338
339 const char *item_id = luaL_checkstring(L, 2);
340 if (!strcmp(item_id, "NONE"))
341 self->enemy_ref->on_death_drop_item_code = -1;
342 else
343 self->enemy_ref->on_death_drop_item_code = get_item_type_by_id(item_id);
344 return 0;
345 }
346
347 /**
348 * \brief Check if the npc is dead or alive.
349 *
350 * \param self [\p FDnpc] FDnpc instance
351 *
352 * \return [\p boolean] 'true' if npc is dead
353 *
354 * \bindtype cfun
355 */
LUAFD_DOC(boolean is_dead (self))356 LUAFD_DOC(boolean is_dead(self))
357
358 static int _is_dead(lua_State *L)
359 {
360 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
361
362 int dead = FALSE;
363 enemy *erot;
364 BROWSE_DEAD_BOTS(erot) {
365 if (!strcmp(erot->dialog_section_name, self->enemy_ref->dialog_section_name)) {
366 dead = TRUE;
367 break;
368 }
369 }
370
371 lua_pushboolean(L, dead);
372 return 1;
373 }
374
375 /**
376 * \brief Get the name of the npc's sensor
377 *
378 * \param self [\p FDnpc] FDnpc instance
379 *
380 * \return [\p string] NPC sensor's name
381 *
382 * \bindtype cfun
383 */
LUAFD_DOC(number get_sensor (self))384 LUAFD_DOC(number get_sensor(self))
385
386 static int _get_sensor(lua_State *L)
387 {
388 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
389
390 lua_pushstring(L, get_sensor_name_by_id(self->enemy_ref->sensor_id));
391 return 1;
392 }
393
394 /**
395 * \brief Teleport the npc to a given map label
396 *
397 * \param self [\p FDnpc] FDnpc instance
398 * \param label [\p string] Map label
399 *
400 * \bindtype cfun
401 */
LUAFD_DOC(void teleport (self,label))402 LUAFD_DOC(void teleport(self, label))
403
404 static int _teleport(lua_State *L)
405 {
406 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
407
408 const char *label = luaL_checkstring(L, 2);
409 gps teleport_pos = get_map_label_center(label);
410 teleport_enemy(self->enemy_ref, teleport_pos.z, teleport_pos.x, teleport_pos.y);
411 return 0;
412 }
413
414 /**
415 * \brief Heal the npc, by restoring its maximum energy
416 *
417 * \param self [\p FDnpc] FDnpc instance
418 *
419 * \bindtype cfun
420 */
LUAFD_DOC(void heal (self))421 LUAFD_DOC(void heal(self))
422
423 static int _heal(lua_State *L)
424 {
425 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
426
427 self->enemy_ref->energy = Droidmap[self->enemy_ref->type].maxenergy;
428 return 0;
429 }
430
431 /**
432 * \brief Freeze the npc, for a given duration
433 *
434 * \param self [\p FDnpc] FDnpc instance
435 * \param duration [\p number] Duration
436 *
437 * \bindtype cfun
438 */
LUAFD_DOC(void freeze (self,duration))439 LUAFD_DOC(void freeze(self, duration))
440
441 static int _freeze(lua_State *L)
442 {
443 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
444
445 float duration = luaL_checknumber(L, 2);
446 self->enemy_ref->paralysation_duration_left = duration;
447 return 0;
448 }
449
450 /**
451 * \brief Hit npc to death
452 *
453 * \param self [\p FDnpc] FDnpc instance
454 *
455 * \bindtype cfun
456 */
LUAFD_DOC(void drop_dead (self))457 LUAFD_DOC(void drop_dead(self))
458
459 static int _drop_dead(lua_State * L)
460 {
461 GET_SELF_INSTANCE_OF(struct luaFD_npc, L, "FDnpc");
462
463 hit_enemy(self->enemy_ref, self->enemy_ref->energy + 1, 0, Droidmap[self->enemy_ref->type].is_human - 2, 0);
464
465 // If hit enemy is the one we are talking with, close the dialog
466 struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
467 if (self->enemy_ref == current_chat_context->partner)
468 current_chat_context->end_dialog = 1;
469
470 return 0;
471 }
472
473 // end FDnpc submodule
474 ///@}
475 ///////////////////////////////////////////////////////////////////////////////
476
477 /**
478 * FDnpc cfuns list
479 */
480 static const luaL_Reg npc_cfuns[] = {
481 { "__gc", _garbage_collect },
482 LUAFD_CFUN(get_name),
483 LUAFD_CFUN(get_translated_name),
484 LUAFD_CFUN(set_name),
485 LUAFD_CFUN(get_type),
486 LUAFD_CFUN(get_class),
487 LUAFD_CFUN(set_state),
488 LUAFD_CFUN(set_faction),
489 LUAFD_CFUN(set_destination),
490 LUAFD_CFUN(set_rush_tux),
491 LUAFD_CFUN(get_rush_tux),
492 LUAFD_CFUN(get_health),
493 LUAFD_CFUN(get_max_health),
494 LUAFD_CFUN(set_death_item),
495 LUAFD_CFUN(is_dead),
496 LUAFD_CFUN(get_sensor),
497 LUAFD_CFUN(teleport),
498 LUAFD_CFUN(heal),
499 LUAFD_CFUN(freeze),
500 LUAFD_CFUN(drop_dead),
501 { NULL, NULL }
502 };
503
504 /**
505 * \brief Create class-type metatable for NPCanic lua binding
506 *
507 * This function creates and stores in the C registry a FDnpc metatable containing
508 * cfuns and lfuns to act on the C structs defining a NPC.\n
509 * cfuns are defined in the npc_cfuns array.\n
510 * lfuns are defined in the FDnpc_lfuns.lua file.
511 *
512 * \param L Pointer to the Lua state to use
513 *
514 * \return TRUE
515 */
luaFD_npc_init(lua_State * L)516 int luaFD_npc_init(lua_State *L)
517 {
518 // Create a metatable that will contain the NPC cfuncs and lfuncs.
519 // The metatable is stored in the C registry.
520
521 luaL_newmetatable(L, "FDnpc"); // stack: (-1) metatable (1)
522 lua_setfield(L, -1, "__index"); // empty stack
523
524 // First load lfuns.
525 // We use a simple trick: The metatable is, temporally, made available as a
526 // global table called 'FDnpc'. We then load a script that will add entries
527 // into that table, using standard table access such as 'FDnpc.key = value'.
528 // Finally, we remove the table from the global name space.
529 //
530 // Note: Loading lfuns first will ensure that a lfun can not override a cfun
531 // (because a cfun will overwrite a lfun with the same name).
532
533 luaL_getmetatable(L, "FDnpc"); // stack: (-1) metatable (1)
534 lua_setglobal(L, "FDnpc"); // empty stack
535
536 char fpath[PATH_MAX];
537 if (find_file("FDnpc_lfuns.lua", LUA_MOD_DIR, fpath, PLEASE_INFORM | IS_FATAL)) {
538 if (luaL_loadfile(L, fpath)) {
539 error_message(__FUNCTION__, "Aborting loading FDnpc lfuns.\nError while loading ’%s’: %s",
540 PLEASE_INFORM, "FDnpc_lfuns.lua", lua_tostring(L, -1));
541 lua_pop(L, 1);
542 return FALSE;
543 }
544
545 if (lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK) {
546 error_message(__FUNCTION__, "Aborting loading FDnpc lfuns.\nError while running ’%s’: %s",
547 PLEASE_INFORM, "FDnpc_lfuns.lua", lua_tostring(L, -1));
548 lua_pop(L, 1);
549 return FALSE;
550 }
551 }
552
553 lua_pushnil(L); // stack: (-1) nil (1)
554 lua_setglobal(L, "FDnpc"); // empty stack
555
556 // Now register the cfuns
557
558 luaL_getmetatable(L, "FDnpc"); // stack: (-1) metatable (1)
559 luaL_setfuncs(L, npc_cfuns, 0); // stack: (-1) metatable (1)
560
561 // When running the dialogs validator, the execution of some methods will
562 // crash because the game engine is not actually running.
563 // The __override_for_validator lfun redefines those methods (cfuns as
564 // well as lfuns) so that they do not call the engine.
565 if (do_benchmark && !strncmp(do_benchmark, "dialog", 6)) {
566 // Run FDnpc.__override_for_validator, if it exists
567 lua_getfield(L, -1, "__override_for_validator"); // stack: (-1) fun < metatable (1)
568 if (!lua_isnil(L, -1)) {
569 lua_pushvalue(L, -2); // stack: (-1) metatable < fun < metatable (1)
570 lua_call(L, 1, 0); // stack: (-1) metatable (1)
571 } else {
572 lua_pop(L, 1); // stack: (-1) metatable (1)
573 }
574 }
575
576 lua_pop(L, 1); // empty stack
577
578 return TRUE;
579 }
580
581 /**
582 * \brief Get a FDnpc instance (singleton)
583 *
584 * On first call, this function creates a Lua userdata which acts as a FDnpc
585 *
586 * blah...
587 *
588 * \param L Pointer to the Lua state to use
589 *
590 * \return 1 (userdata on the Lua stack)
591 */
luaFD_npc_get_instance(lua_State * L)592 int luaFD_npc_get_instance(lua_State *L)
593 {
594 struct enemy *partner = NULL;
595 const char *dialog = luaL_optstring(L, 1, NULL);
596
597 if (!dialog) {
598 struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
599 partner = current_chat_context->partner;
600 if (!partner) {
601 error_message(__FUNCTION__, ("Current chat context has no 'partner'. How is it possible?"), PLEASE_INFORM | IS_FATAL);
602 return 0;
603 }
604 } else {
605 partner = get_enemy_with_dialog(dialog);
606 if (!partner)
607 return luaL_error(L, ("Could not find a droid with name \"%s\""), dialog);
608 }
609
610 // Try to get the userdata from the C registry.
611 // If it does not exist, create it.
612
613 lua_rawgetp(L, LUA_REGISTRYINDEX, (void *)partner); // stack: (-1) userdata (1)
614
615 if (lua_isnil(L, -1)) {
616
617 lua_pop(L, 1); // empty stack
618
619 /* Create a userdata and make it be a FDnpc instance */
620 struct luaFD_npc* userdata = (struct luaFD_npc*)lua_newuserdata(L, sizeof(struct luaFD_npc)); // stack: (-1) userdata (1)
621 userdata->enemy_ref = partner;
622 userdata->npc_ref = npc_get(partner->dialog_section_name);
623 luaL_setmetatable(L, "FDnpc"); // stack: (-1) userdata (1)
624
625 /* Register the userdata, using the value of the pointer to create a lightuserdata key */
626 lua_pushvalue(L, -1); // stack: (-1) userdata < userdata (1)
627 lua_rawsetp(L, LUA_REGISTRYINDEX, (void *)partner); // stack: (-1) userdata (1)
628 }
629
630 // Return the userdata (already on the Lua stack)
631 return 1;
632 }
633