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