1 /*
2  *
3  *   Copyright (c) 2008-2010 Arthur Huillet
4  *
5  *
6  *  This file is part of Freedroid
7  *
8  *  Freedroid is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  Freedroid is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with Freedroid; see the file COPYING. If not, write to the
20  *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  *  MA  02111-1307  USA
22  *
23  */
24 
25 /**
26  * This file contains functions related to the Lua scripting interface of FreedroidRPG
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 "lvledit/lvledit_actions.h"
37 #include "lvledit/lvledit_map.h"
38 
39 #include "widgets/widgets.h"
40 
41 #include "lua.h"
42 #include "lauxlib.h"
43 #include "lualib.h"
44 
45 /* Lua state for dialog execution */
46 static lua_State *dialog_lua_state;
47 
48 /* Lua state for config execution */
49 lua_State *config_lua_state;
50 
get_lua_state(enum lua_target target)51 lua_State *get_lua_state(enum lua_target target)
52 {
53 	if (target == LUA_CONFIG)
54 		return config_lua_state;
55 
56 	return dialog_lua_state;
57 }
58 
lua_to_int(lua_Integer value)59 int lua_to_int(lua_Integer value)
60 {
61 	if (sizeof(lua_Integer) > sizeof(int)) {
62 		if (value > (lua_Integer)INT_MAX)
63 			return INT_MAX;
64 		if (value < (lua_Integer)INT_MIN)
65 			return INT_MIN;
66 		return (int)value;
67 	}
68 	return (int)value;
69 }
70 
lua_to_short(lua_Integer value)71 short lua_to_short(lua_Integer value)
72 {
73 	if (sizeof(lua_Integer) > sizeof(short)) {
74 		if (value > (lua_Integer)SHRT_MAX)
75 			return SHRT_MAX;
76 		if (value < (lua_Integer)SHRT_MIN)
77 			return SHRT_MIN;
78 		return (short)value;
79 	}
80 	return (short)value;
81 }
82 
83 /**
84  * Retrieve current chat context, and fail with error if there is no dialog
85  * currently running.
86  */
__get_current_chat_context(const char * funcname)87 static struct chat_context *__get_current_chat_context(const char *funcname)
88 {
89 	struct chat_context *current_chat_context = chat_get_current_context();
90 	if (!current_chat_context)
91 		error_message(funcname, _("No chat context available on the context stack."), PLEASE_INFORM | IS_FATAL);
92 	return current_chat_context;
93 }
94 
95 #define GET_CURRENT_CHAT_CONTEXT() __get_current_chat_context(__FUNCTION__)
96 
97 /** Helper to retrieve the enemy a Lua function must act upon.
98   * An optional dialog name can be provided, by default the function will act
99   * upon the current chat droid.
100   */
get_enemy_opt(lua_State * L,int param_number,int optional)101 static enemy *get_enemy_opt(lua_State *L, int param_number, int optional)
102 {
103 	const char *dialog = luaL_optstring(L, param_number, NULL);
104 
105 	if (!dialog) {
106 		struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
107 		return current_chat_context->partner;
108 	}
109 
110 	enemy *en = get_enemy_with_dialog(dialog);
111 	if (!optional && !en)
112 		error_message(__FUNCTION__, "Could not find a droid corresponding to the dialog \"%s\".", PLEASE_INFORM | IS_FATAL, dialog);
113 	return en;
114 }
115 
get_enemy_arg(lua_State * L,int param_number)116 static enemy *get_enemy_arg(lua_State *L, int param_number)
117 {
118 	return get_enemy_opt(L, param_number, FALSE);
119 }
120 
lua_event_teleport(lua_State * L)121 static int lua_event_teleport(lua_State * L)
122 {
123 	gps stop_pos = { -1, -1, -1 };
124 	const char *label = luaL_checkstring(L, 1);
125 	gps teleport_pos = get_map_label_center(label);
126 	reset_visible_levels();
127 	Teleport(teleport_pos.z, teleport_pos.x, teleport_pos.y, TRUE, TRUE);
128 	Me.speed.x = 0.0;
129 	Me.speed.y = 0.0;
130 	clear_out_intermediate_points(&stop_pos, Me.next_intermediate_point, MAX_INTERMEDIATE_WAYPOINTS_FOR_TUX);
131 	clear_active_bullets();
132 	return 0;
133 }
134 
lua_event_teleport_npc(lua_State * L)135 static int lua_event_teleport_npc(lua_State * L)
136 {
137 	const char *label = luaL_checkstring(L, 1);
138 	enemy *en = get_enemy_arg(L, 2);
139 	gps teleport_pos = get_map_label_center(label);
140 	teleport_enemy(en, teleport_pos.z, teleport_pos.x, teleport_pos.y);
141 	return 0;
142 }
143 
lua_event_teleport_home(lua_State * L)144 static int lua_event_teleport_home(lua_State * L)
145 {
146 	TeleportHome();
147 
148 	return 0;
149 }
150 
lua_event_has_teleport_anchor(lua_State * L)151 static int lua_event_has_teleport_anchor(lua_State * L)
152 {
153 	if (Me.teleport_anchor.z != -1)
154 		lua_pushboolean(L, TRUE);
155 	else
156 		lua_pushboolean(L, FALSE);
157 
158 	return 1;
159 }
160 
lua_event_display_big_message(lua_State * L)161 static int lua_event_display_big_message(lua_State * L)
162 {
163 	const char *msg = luaL_checkstring(L, 1);
164 	SetNewBigScreenMessage(msg);
165 	return 0;
166 }
167 
lua_event_display_console_message(lua_State * L)168 static int lua_event_display_console_message(lua_State * L)
169 {
170 	const char *msg = luaL_checkstring(L, 1);
171 	append_new_game_message("%s", msg);
172 	return 0;
173 }
174 
lua_event_change_obstacle(lua_State * L)175 static int lua_event_change_obstacle(lua_State * L)
176 {
177 	const char *obslabel = luaL_checkstring(L, 1);
178 	int type = lua_to_int(luaL_checkinteger(L, 2));
179 	change_obstacle_type(obslabel, type);
180 	return 0;
181 }
182 
lua_event_get_obstacle_type(lua_State * L)183 static int lua_event_get_obstacle_type(lua_State * L)
184 {
185 	const char *obslabel = luaL_checkstring(L, 1);
186 
187 	obstacle *our_obstacle = give_pointer_to_obstacle_with_label(obslabel, NULL);
188 
189 	lua_pushinteger(L, (lua_Integer)our_obstacle->type);
190 	return 1;
191 }
192 
lua_event_delete_obstacle(lua_State * L)193 static int lua_event_delete_obstacle(lua_State * L)
194 {
195 	const char *obslabel = luaL_checkstring(L, 1);
196 	change_obstacle_type(obslabel, -1);
197 	return 0;
198 }
199 
lua_change_obstacle_message(lua_State * L)200 static int lua_change_obstacle_message(lua_State *L)
201 {
202 	const char *obslabel = luaL_checkstring(L, 1);
203 	const char *message = luaL_checkstring(L, 2);
204 	int obstacle_level_num;
205 	obstacle *o = give_pointer_to_obstacle_with_label(obslabel, &obstacle_level_num);
206 	level *l = curShip.AllLevels[obstacle_level_num];
207 
208 	message = strdup(message);
209 
210 	del_obstacle_extension(l, o, OBSTACLE_EXTENSION_SIGNMESSAGE);
211 	add_obstacle_extension(l, o, OBSTACLE_EXTENSION_SIGNMESSAGE, (void *)message);
212 
213 	return 0;
214 }
215 
lua_event_heal_tux(lua_State * L)216 static int lua_event_heal_tux(lua_State * L)
217 {
218 	if (Me.energy > 0) {
219 		Me.energy = Me.maxenergy;
220 		play_sound("effects/new_healing_sound.ogg");
221 	}
222 	return 0;
223 }
224 
lua_event_kill_tux(lua_State * L)225 static int lua_event_kill_tux(lua_State * L)
226 {
227 	Me.energy = -100;
228 	return 0;
229 }
230 
lua_event_hurt_tux(lua_State * L)231 static int lua_event_hurt_tux(lua_State * L)
232 {
233 	int hp = lua_to_int(luaL_checkinteger(L, 1));
234 
235 	if (hp < 0)
236 		play_sound("effects/new_healing_sound.ogg");
237 
238 	hit_tux(hp);
239 	return 0;
240 }
241 
lua_event_get_tux_hp(lua_State * L)242 static int lua_event_get_tux_hp(lua_State * L)
243 {
244 	lua_pushinteger(L, (lua_Integer)Me.energy);
245 	return 1;
246 }
247 
lua_event_get_tux_max_hp(lua_State * L)248 static int lua_event_get_tux_max_hp(lua_State * L)
249 {
250 	lua_pushinteger(L, (lua_Integer)Me.maxenergy);
251 	return 1;
252 }
253 
lua_event_heat_tux(lua_State * L)254 static int lua_event_heat_tux(lua_State * L)
255 {
256 	int temp = lua_to_int(luaL_checkinteger(L, 1));
257 	Me.temperature += temp;
258 	return 0;
259 }
260 
lua_event_get_tux_cool(lua_State * L)261 static int lua_event_get_tux_cool(lua_State * L)
262 {
263 	lua_pushinteger(L, (lua_Integer)(Me.max_temperature - Me.temperature));
264 	return 1;
265 }
266 
lua_event_improve_skill(lua_State * L)267 static int lua_event_improve_skill(lua_State * L)
268 {
269 	const char *skilltype = luaL_checkstring(L, 1);
270 	int *skillptr = NULL;
271 	if (!strcmp(skilltype, "melee")) {
272 		skillptr = &Me.melee_weapon_skill;
273 		SetNewBigScreenMessage(_("Melee fighting ability improved!"));
274 	} else if (!strcmp(skilltype, "ranged")) {
275 		skillptr = &Me.ranged_weapon_skill;
276 		SetNewBigScreenMessage(_("Ranged combat ability improved!"));
277 	} else if (!strcmp(skilltype, "programming")) {
278 		skillptr = &Me.spellcasting_skill;
279 		SetNewBigScreenMessage(_("Programming ability improved!"));
280 	} else {
281 		error_message(__FUNCTION__,
282 			     "Lua script called me with an incorrect parameter. Accepted values are \"melee\", \"ranged\", and \"programming\".",
283 			     PLEASE_INFORM);
284 	}
285 
286 	if (skillptr) {
287 		ImproveSkill(skillptr);
288 	}
289 	return 0;
290 }
291 
lua_event_get_skill(lua_State * L)292 static int lua_event_get_skill(lua_State * L)
293 {
294 	const char *skilltype = luaL_checkstring(L, 1);
295 	int *skillptr = NULL;
296 	if (!strcmp(skilltype, "melee")) {
297 		skillptr = &Me.melee_weapon_skill;
298 	} else if (!strcmp(skilltype, "ranged")) {
299 		skillptr = &Me.ranged_weapon_skill;
300 	} else if (!strcmp(skilltype, "programming")) {
301 		skillptr = &Me.spellcasting_skill;
302 	} else {
303 		error_message(__FUNCTION__,
304 			     "Lua script called me with an incorrect parameter. Accepted values are \"melee\", \"ranged\", and \"programming\".",
305 			     PLEASE_INFORM);
306 	}
307 
308 	if (skillptr) {
309 		lua_pushinteger(L, (lua_Integer)*skillptr);
310 	} else
311 		lua_pushinteger(L, (lua_Integer)0);
312 
313 	return 1;
314 }
315 
lua_event_improve_program(lua_State * L)316 static int lua_event_improve_program(lua_State * L)
317 {
318 	const char *pname = luaL_checkstring(L, 1);
319 	improve_program(get_program_index_with_name(pname));
320 	return 0;
321 }
322 
lua_event_downgrade_program(lua_State * L)323 static int lua_event_downgrade_program(lua_State * L)
324 {
325 	const char *pname = luaL_checkstring(L, 1);
326 	downgrade_program(get_program_index_with_name(pname));
327 	return 0;
328 }
329 
lua_event_get_program_revision(lua_State * L)330 static int lua_event_get_program_revision(lua_State * L)
331 {
332 	const char *pname = luaL_checkstring(L, 1);
333 	lua_pushinteger(L, (lua_Integer)Me.skill_level[get_program_index_with_name(pname)]);
334 	return 1;
335 }
336 
lua_event_delete_item(lua_State * L)337 static int lua_event_delete_item(lua_State * L)
338 {
339 	const char *item_id = luaL_checkstring(L, 1);
340 	int mult = lua_to_int(luaL_optinteger(L, 2, 1));
341 	DeleteInventoryItemsOfType(get_item_type_by_id(item_id), mult);
342 	return 0;
343 }
344 
lua_event_give_item(lua_State * L)345 static int lua_event_give_item(lua_State * L)
346 {
347 	const char *itemname = luaL_checkstring(L, 1);
348 	int mult = lua_to_int(luaL_optinteger(L, 2, 1));
349 
350 	if (!mult) { error_message(__FUNCTION__, "Tried to give %s with multiplicity 0.", PLEASE_INFORM, itemname); return 0; }
351 
352 	item NewItem;
353 	NewItem = create_item_with_id(itemname, TRUE, mult);
354 
355 	// Either we put the new item directly into inventory or we issue a warning
356 	// that there is no room and then drop the item to the floor directly under
357 	// the current Tux position.  That can't fail, right?
358 	char msg[1000];
359 	if (!give_item(&NewItem)) {
360 		sprintf(msg, _("Received item: %s (on floor)"), itemname);
361 	} else {
362 		sprintf(msg, _("Received item: %s"), itemname);
363 	}
364 	SetNewBigScreenMessage(msg);
365 	return 0;
366 }
367 
lua_event_sell_item(lua_State * L)368 static int lua_event_sell_item(lua_State *L)
369 {
370 	struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
371 
372 	const char *itemname = luaL_checkstring(L, 1);
373 	int weight = lua_to_int(luaL_optinteger(L, 2, 1));
374 	const char *charname = luaL_optstring(L, 3, current_chat_context->partner->dialog_section_name);
375 
376 	npc_add_shoplist(charname, itemname, weight);
377 
378 	return 0;
379 }
380 
lua_event_count_item_backpack(lua_State * L)381 static int lua_event_count_item_backpack(lua_State * L)
382 {
383 	const char *item_id = luaL_checkstring(L, 1);
384 
385 	lua_pushinteger(L, (lua_Integer)CountItemtypeInInventory(get_item_type_by_id(item_id)));
386 
387 	return 1;
388 }
389 
lua_event_has_item_equipped(lua_State * L)390 static int lua_event_has_item_equipped(lua_State * L)
391 {
392 	const char *item_id = luaL_checkstring(L, 1);
393 	int item_idx = get_item_type_by_id(item_id);
394 	if ((item_idx != -1) && ((Me.weapon_item.type == item_idx) || (Me.drive_item.type == item_idx)
395 		|| (Me.armour_item.type == item_idx) || (Me.shield_item.type == item_idx)
396 		|| (Me.special_item.type == item_idx))) {
397 		lua_pushboolean(L, TRUE);
398 	} else {
399 		lua_pushboolean(L, FALSE);
400 	}
401 	return 1;
402 }
403 
lua_event_equip_item(lua_State * L)404 static int lua_event_equip_item(lua_State * L)
405 {
406 	const char *item_name = luaL_checkstring(L, 1);
407 
408 	if (!item_name) {
409 		error_message(__FUNCTION__, "Tried to add item without a name", PLEASE_INFORM);
410 		return 0;
411 	}
412 	item new_item = create_item_with_id(item_name, TRUE, 1);
413 	equip_item(&new_item);
414 	SetNewBigScreenMessage(_("1 item received!"));
415 	return 0;
416 }
417 
lua_set_death_item(lua_State * L)418 static int lua_set_death_item(lua_State * L)
419 {
420 	const char *item_id = luaL_checkstring(L, 1);
421 	enemy *en = get_enemy_arg(L, 2);
422 	if (!strcmp(item_id, "NONE"))
423 		en->on_death_drop_item_code = -1;
424 	else
425 		en->on_death_drop_item_code = get_item_type_by_id(item_id);
426 	return 0;
427 }
428 
lua_event_add_diary_entry(lua_State * L)429 static int lua_event_add_diary_entry(lua_State * L)
430 {
431 	const char *mis_name = luaL_checkstring(L, 1);
432 	const char *text = luaL_checkstring(L, 2);
433 
434 	mission_diary_add(mis_name, text);
435 	return 0;
436 }
437 
lua_event_has_met(lua_State * L)438 static int lua_event_has_met(lua_State *L)
439 {
440 	const char *npc_name = luaL_checkstring(L, 1);
441 	struct npc *npc = npc_get(npc_name);
442 	lua_pushboolean(L, npc->chat_character_initialized);
443 	return 1;
444 }
445 
lua_event_assign_mission(lua_State * L)446 static int lua_event_assign_mission(lua_State * L)
447 {
448 	const char *misname = luaL_checkstring(L, 1);
449 	const char *diarytext = luaL_optstring(L, 2, NULL);
450 
451 	AssignMission(misname);
452 	if (diarytext != NULL)
453 		mission_diary_add(misname, diarytext);
454 
455 	return 0;
456 }
457 
lua_event_complete_mission(lua_State * L)458 static int lua_event_complete_mission(lua_State * L)
459 {
460 	const char *misname = luaL_checkstring(L, 1);
461 	const char *diarytext = luaL_optstring(L, 2, NULL);
462 
463 	CompleteMission(misname);
464 	if (diarytext != NULL)
465 		mission_diary_add(misname, diarytext);
466 
467 	return 0;
468 }
469 
lua_event_is_mission_assigned(lua_State * L)470 static int lua_event_is_mission_assigned(lua_State * L)
471 {
472 	const char *misname = luaL_checkstring(L, 1);
473 
474 	lua_pushboolean(L, Me.AllMissions[GetMissionIndexByName(misname)].MissionWasAssigned);
475 
476 	return 1;
477 }
478 
lua_event_is_mission_complete(lua_State * L)479 static int lua_event_is_mission_complete(lua_State * L)
480 {
481 	const char *misname = luaL_checkstring(L, 1);
482 
483 	lua_pushboolean(L, Me.AllMissions[GetMissionIndexByName(misname)].MissionIsComplete);
484 
485 	return 1;
486 }
487 
lua_event_give_xp(lua_State * L)488 static int lua_event_give_xp(lua_State * L)
489 {
490 	int xp = lua_to_int(luaL_checkinteger(L, 1)) * Me.experience_factor;
491 	char tmpstr[150];
492 	Me.Experience += xp;
493 	sprintf(tmpstr, _("+%d experience points"), xp);
494 	SetNewBigScreenMessage(tmpstr);
495 	return 0;
496 }
497 
lua_event_eat_training_points(lua_State * L)498 static int lua_event_eat_training_points(lua_State * L)
499 {
500 	int nb = lua_to_int(luaL_checkinteger(L, 1));
501 	Me.points_to_distribute -= nb;
502 	return 0;
503 }
504 
lua_event_get_training_points(lua_State * L)505 static int lua_event_get_training_points(lua_State * L)
506 {
507 	lua_pushinteger(L, (lua_Integer)Me.points_to_distribute);
508 	return 1;
509 }
510 
lua_event_add_gold(lua_State * L)511 static int lua_event_add_gold(lua_State * L)
512 {
513 	int nb = lua_to_int(luaL_checkinteger(L, 1));
514 	char tmpstr[150];
515 
516 	if (nb < 0 && -nb > Me.Gold) {
517 		error_message(__FUNCTION__, "Tried to remove %d gold from the player that only has %d!", PLEASE_INFORM,
518 			     -nb, Me.Gold);
519 		nb = -Me.Gold;
520 	}
521 
522 	Me.Gold += nb;
523 
524 	if (nb > 0)
525 		sprintf(tmpstr, _("Gained %d valuable circuits!"), nb);
526 	else
527 		sprintf(tmpstr, _("Lost %d valuable circuits!"), -nb);
528 
529 	SetNewBigScreenMessage(tmpstr);
530 	return 0;
531 }
532 
lua_event_get_gold(lua_State * L)533 static int lua_event_get_gold(lua_State * L)
534 {
535 	lua_pushinteger(L, (lua_Integer)Me.Gold);
536 	return 1;
537 }
538 
lua_event_change_stat(lua_State * L)539 static int lua_event_change_stat(lua_State * L)
540 {
541 	const char *characteristic = luaL_checkstring(L, 1);
542 	int nb = lua_to_int(luaL_checkinteger(L, 2));
543 	int *statptr = NULL;
544 
545 	if (!strcmp(characteristic, "strength")) {
546 		statptr = &Me.base_strength;
547 	} else if (!strcmp(characteristic, "dexterity")) {
548 		statptr = &Me.base_dexterity;
549 	} else if (!strcmp(characteristic, "CPU")) {
550 		statptr = &Me.base_cooling;
551 	} else if (!strcmp(characteristic, "vitality")) {
552 		statptr = &Me.base_physique;
553 	} else {
554 		error_message(__FUNCTION__,
555 			     "I was called with characteristic name %s - accepted values are \"strength\", \"dexterity\", \"CPU\", and \"vitality\".",
556 			     PLEASE_INFORM, characteristic);
557 		return 0;
558 	}
559 
560 	*statptr += nb;
561 	return 0;
562 }
563 
lua_event_respawn_level(lua_State * L)564 static int lua_event_respawn_level(lua_State * L)
565 {
566 	int lnb = lua_to_int(luaL_checkinteger(L, 1));
567 
568 	respawn_level(lnb);
569 
570 	return 0;
571 }
572 
lua_event_trade_with(lua_State * L)573 static int lua_event_trade_with(lua_State * L)
574 {
575 	const char *cname = luaL_checkstring(L, 1);
576 
577 	struct npc *n = npc_get(cname);
578 	InitTradeWithCharacter(n);
579 
580 	return 0;
581 }
582 
lua_event_upgrade_items(lua_State * L)583 static int lua_event_upgrade_items(lua_State * L)
584 {
585 	item_upgrade_ui();
586 
587 	return 0;
588 }
589 
lua_event_craft_addons(lua_State * L)590 static int lua_event_craft_addons(lua_State * L)
591 {
592 	addon_crafting_ui();
593 
594 	return 0;
595 }
596 
lua_event_heal_npc(lua_State * L)597 static int lua_event_heal_npc(lua_State * L)
598 {
599 	enemy *en = get_enemy_arg(L, 1);
600 	en->energy = Droidmap[en->type].maxenergy;
601 	return 0;
602 }
603 
lua_get_npc_damage_amount(lua_State * L)604 static int lua_get_npc_damage_amount(lua_State * L)
605 {
606 	enemy *en = get_enemy_arg(L, 1);
607 	lua_pushinteger(L, (lua_Integer)(Droidmap[en->type].maxenergy - en->energy));
608 	return 1;
609 }
610 
lua_get_npc_max_health(lua_State * L)611 static int lua_get_npc_max_health(lua_State * L)
612 {
613 	enemy *en = get_enemy_arg(L, 1);
614 	lua_pushinteger(L, (lua_Integer)(Droidmap[en->type].maxenergy));
615 	return 1;
616 }
617 
lua_event_npc_dead(lua_State * L)618 static int lua_event_npc_dead(lua_State *L)
619 {
620 	const char *cname = luaL_checkstring(L, 1);
621 	enemy *erot;
622 	int dead = 0;
623 
624 	BROWSE_DEAD_BOTS(erot) {
625 		if (!strcmp(erot->dialog_section_name, cname)) {
626 			dead = 1;
627 			break;
628 		}
629 	}
630 
631 	lua_pushboolean(L, dead);
632 	return 1;
633 }
634 
lua_event_freeze_tux_npc(lua_State * L)635 static int lua_event_freeze_tux_npc(lua_State * L)
636 {
637 	float duration = luaL_checknumber(L, 1);
638 	enemy *en = get_enemy_arg(L, 2);
639 	en->paralysation_duration_left = duration;
640 	Me.paralyze_duration = duration;
641 	return 0;
642 }
643 
644 
lua_chat_player_name(lua_State * L)645 static int lua_chat_player_name(lua_State * L)
646 {
647 	if (Me.character_name)
648 		lua_pushstring(L, Me.character_name);
649 	else
650 		lua_pushstring(L, "");
651 	return 1;
652 }
653 
lua_chat_says(lua_State * L)654 static int lua_chat_says(lua_State * L)
655 {
656 	const char *answer = luaL_checkstring(L, 1);
657 	int no_wait = !strcmp(luaL_optstring(L, 2, "WAIT"), "NO_WAIT");
658 
659 	chat_add_response(answer);
660 
661 	if (no_wait)
662 		return 0;
663 
664 	struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
665 	current_chat_context->wait_user_click = TRUE;
666 	// The Lua manual says that:
667 	// "lua_yield() should only be called as the return expression of a C function"
668 	// But the "should" is actually a "must"...
669 	return lua_yield(L, 0);
670 }
671 
lua_start_chat(lua_State * L)672 static int lua_start_chat(lua_State * L)
673 {
674 	int called_from_dialog;
675 	struct enemy *partner;
676 	struct npc *npc;
677 	struct chat_context *chat_context;
678 	char *dialog_name;
679 
680 	// This function can be called from an event lua script or from a dialog
681 	// lua script.
682 	// In the first case, we have to open the chat screen and launch the chat
683 	// engine.
684 	// In the second case, a dialog is already running, so we have to interrupt
685 	// it (yield the lua coroutine) to let the chat engine run the new dialog.
686 
687 	// To know if the function is called from a dialog script, we check if
688 	// there is already something on the chat context stack.
689 	called_from_dialog = (chat_get_current_context() != NULL);
690 
691 	// Create a chat context and push it on the satck
692 	// Get the enemy to chat with from its name, get associated npc and
693 	// dialog, and create a chat context
694 	partner = get_enemy_arg(L, 1);
695 	npc = npc_get(partner->dialog_section_name);
696 	if (!npc)
697 		return 0;
698 	dialog_name = partner->dialog_section_name;
699 
700 	chat_context = chat_create_context(partner, npc, dialog_name);
701 	if (!chat_push_context(chat_context)) {
702 		chat_delete_context(chat_context);
703 		return 0;
704 	}
705 
706 	if (!called_from_dialog) {
707 		// Open the chat screen and run the chat engine.
708 		chat_run();
709 	} else {
710 		// Yield the current dialog script, to let the chat engine run the
711 		// new dialog.
712 		return lua_yield(L, 0); // lua_yield must be called in a return statement
713 	}
714 
715 	return 0;
716 }
717 
lua_chat_end_dialog(lua_State * L)718 static int lua_chat_end_dialog(lua_State * L)
719 {
720 	struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
721 	current_chat_context->end_dialog = 1;
722 	return 0;
723 }
724 
lua_chat_partner_started(lua_State * L)725 static int lua_chat_partner_started(lua_State * L)
726 {
727 	struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
728 	lua_pushboolean(L, current_chat_context->partner_started);
729 	return 1;
730 }
731 
lua_chat_drop_dead(lua_State * L)732 static int lua_chat_drop_dead(lua_State * L)
733 {
734 	enemy *en = get_enemy_arg(L, 1);
735 	hit_enemy(en, en->energy + 1, 0, Droidmap[en->type].is_human - 2, 0);
736 
737 	struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
738 
739 	if (en == current_chat_context->partner)
740 		current_chat_context->end_dialog = 1;
741 	return 0;
742 }
743 
lua_chat_set_bot_state(lua_State * L)744 static int lua_chat_set_bot_state(lua_State * L)
745 {
746 	const char *cmd = luaL_checkstring(L, 1);
747 	enemy *en = get_enemy_arg(L, 2);
748 	enemy_set_state(en, cmd);
749 	return 0;
750 }
751 
lua_chat_broadcast_bot_state(lua_State * L)752 static int lua_chat_broadcast_bot_state(lua_State * L)
753 {
754 	const char *cmd = luaL_checkstring(L, 1);
755 
756 	struct chat_context *current_chat_context = GET_CURRENT_CHAT_CONTEXT();
757 
758 	const char *dialogname = current_chat_context->partner->dialog_section_name;
759 	enemy *en;
760 	BROWSE_LEVEL_BOTS(en, current_chat_context->partner->pos.z) {
761 		if (!strcmp(en->dialog_section_name, dialogname) && (is_friendly(en->faction, FACTION_SELF))) {
762 			enemy_set_state(en, cmd);
763 		}
764 	}
765 	return 0;
766 }
767 
lua_set_bot_destination(lua_State * L)768 static int lua_set_bot_destination(lua_State * L)
769 {
770 	const char *label = luaL_checkstring(L, 1);
771 	enemy *en = get_enemy_arg(L, 2);
772 	enemy_set_destination(en, label);
773 	return 0;
774 }
775 
lua_set_rush_tux(lua_State * L)776 static int lua_set_rush_tux(lua_State * L)
777 {
778 	const uint8_t cmd = (luaL_checkinteger(L, 1) != FALSE);
779 	enemy *en = get_enemy_arg(L, 2);
780 	en->will_rush_tux = cmd;
781 	return 0;
782 }
783 
lua_will_rush_tux(lua_State * L)784 static int lua_will_rush_tux(lua_State * L)
785 {
786 	enemy *en = get_enemy_arg(L, 1);
787 	lua_pushboolean(L, en->will_rush_tux);
788 	return 1;
789 }
790 
lua_chat_takeover(lua_State * L)791 static int lua_chat_takeover(lua_State * L)
792 {
793 	int opponent_capsules = lua_to_int(luaL_checkinteger(L, 1));
794 	int player_capsules = 2 + Me.skill_level[get_program_index_with_name("Hacking")];
795 	int game_length = lua_to_int(luaL_optinteger(L, 2, (lua_Integer)100));
796 
797 	int won = do_takeover(player_capsules, opponent_capsules, game_length, NULL);
798 
799 	lua_pushboolean(L, won);
800 
801 	return 1;
802 }
803 
lua_chat_bot_exists(lua_State * L)804 static int lua_chat_bot_exists(lua_State *L)
805 {
806 	int exists = get_enemy_opt(L, 1, TRUE) != NULL;
807 	lua_pushboolean(L, exists);
808 	return 1;
809 }
810 
lua_chat_get_bot_type(lua_State * L)811 static int lua_chat_get_bot_type(lua_State * L)
812 {
813 	enemy *en = get_enemy_arg(L, 1);
814 	lua_pushstring(L, Droidmap[en->type].droidname);
815 	return 1;
816 }
817 
lua_event_bot_class(lua_State * L)818 static int lua_event_bot_class(lua_State * L)
819 {
820        enemy *en = get_enemy_arg(L, 1);
821        lua_pushinteger(L, (lua_Integer)Droidmap[en->type].class);
822        return 1;
823 }
824 
lua_chat_get_bot_name(lua_State * L)825 static int lua_chat_get_bot_name(lua_State * L)
826 {
827 	enemy *en = get_enemy_arg(L, 1);
828 	lua_pushstring(L, en->short_description_text);
829 	return 1;
830 }
831 
lua_chat_get_bot_translated_name(lua_State * L)832 static int lua_chat_get_bot_translated_name(lua_State * L)
833 {
834 	enemy *en = get_enemy_arg(L, 1);
835 	lua_pushstring(L, D_(en->short_description_text));
836 	return 1;
837 }
838 
lua_chat_set_bot_name(lua_State * L)839 static int lua_chat_set_bot_name(lua_State * L)
840 {
841 	const char *bot_name = luaL_checkstring(L, 1);
842 	enemy *en = get_enemy_arg(L, 2);
843 	free(en->short_description_text);
844 	en->short_description_text = strdup(bot_name);
845 	return 0;
846 }
847 
lua_difficulty_level(lua_State * L)848 static int lua_difficulty_level(lua_State * L)
849 {
850 	lua_pushnumber(L, GameConfig.difficulty_level);
851 	return 1;
852 }
853 
lua_set_npc_faction(lua_State * L)854 static int lua_set_npc_faction(lua_State *L)
855 {
856 	const char *fact = luaL_checkstring(L, 1);
857 	enemy *en = get_enemy_arg(L, 2);
858 	en->faction = get_faction_id(fact);
859 	return 0;
860 }
861 
lua_kill_faction(lua_State * L)862 static int lua_kill_faction(lua_State *L)
863 {
864 	const char *fact = luaL_checkstring(L, 1);
865 	const char *respawn = luaL_optstring(L, 2, "");
866 	enemy *erot, *nerot;
867 	if (strcmp(respawn, "no_respawn") && (strcmp(respawn, "")))
868 		error_message(__FUNCTION__, "\
869 				Received optional second argument \"%s\". Accepted value is \"no_respawn\".\n\
870 				Faction \"%s\" will now be killed and will respawn as usual.", PLEASE_INFORM, respawn, fact);
871 	BROWSE_ALIVE_BOTS_SAFE(erot, nerot) {
872 		if (erot->faction != get_faction_id(fact))
873 			continue;
874 		hit_enemy(erot, erot->energy + 1, 0, -2, 0);
875 		if (!strcmp(respawn, "no_respawn"))
876 			erot->will_respawn = FALSE;
877 	}
878 	return 0;
879 }
880 
lua_user_input_string(lua_State * L)881 static int lua_user_input_string(lua_State *L)
882 {
883 	const char *title = luaL_checkstring(L, 1);
884 	const char *default_str = luaL_optstring(L, 2, "");
885 
886 	const char *str = GetEditableStringInPopupWindow(100, title, default_str);
887 
888 	if (!str)
889 		str = strdup("");
890 
891 	lua_pushstring(L, str);
892 
893 	free((void *)str);
894 	return 1;
895 }
896 
lua_set_faction_state(lua_State * L)897 static int lua_set_faction_state(lua_State *L)
898 {
899 	const char *fact_name = luaL_checkstring(L, 1);
900 	const char *state_str = luaL_checkstring(L, 2);
901 	const char *fact2_name = luaL_optstring(L, 3, "self");
902 
903 	enum faction_state state;
904 	enum faction_id fact_id = get_faction_id(fact_name);
905 	enum faction_id fact2_id = get_faction_id(fact2_name);
906 
907 	if (!strcmp(state_str, "hostile"))
908 		state = HOSTILE;
909 	else if (!strcmp(state_str, "friendly"))
910 		state = FRIENDLY;
911 	else {
912 		error_message(__FUNCTION__, "Unknown faction state %s.", PLEASE_INFORM, state_str);
913 		return 0;
914 	}
915 
916 	set_faction_state(fact_id, fact2_id, state);
917 
918 	return 0;
919 }
920 
lua_create_droid(lua_State * L)921 static int lua_create_droid(lua_State *L)
922 {
923 	const char *label = luaL_checkstring(L, 1);
924 	const char *type_name = luaL_checkstring(L, 2);
925 	const char *fact_name = luaL_optstring(L, 3, "ms");
926 	const char *dialog    = luaL_optstring(L, 4, "AfterTakeover");
927 	const char *Sensor_ID = luaL_optstring(L, 5, NULL);
928 	gps pos = get_map_label_center(label);
929 	int type;
930 
931 	type = get_droid_type(type_name);
932 
933 	enemy *en = enemy_new(type);
934 	enemy_reset(en);
935 	en->pos.x = pos.x;
936 	en->pos.y = pos.y;
937 	en->pos.z = pos.z;
938 	en->faction = get_faction_id(fact_name);
939 	en->dialog_section_name = strdup(dialog);
940 	if (Sensor_ID != NULL)
941 		en->sensor_id = get_sensor_id_by_name(Sensor_ID);
942 	enemy_insert_into_lists(en, TRUE);
943 
944 	return 0;
945 }
946 
lua_get_game_time(lua_State * L)947 static int lua_get_game_time(lua_State *L)
948 {
949 	lua_pushinteger(L, (lua_Integer)(Me.current_game_date));
950 
951 	return 1;
952 }
953 
lua_get_game_date(lua_State * L)954 static int lua_get_game_date(lua_State *L)
955 {
956 	// This function retrieves the ingame date, using C functions defined in hud.c
957 	// It returns in sequence: days, hours and minutes.
958 	lua_pushinteger(L, get_days_of_game_duration(Me.current_game_date));
959 	lua_pushinteger(L, get_hours_of_game_duration(Me.current_game_date));
960 	lua_pushinteger(L, get_minutes_of_game_duration(Me.current_game_date));
961 
962 	return 3;
963 }
964 
lua_win_game(lua_State * L)965 static int lua_win_game(lua_State *L)
966 {
967 	ThouHastWon();
968 
969 	return 0;
970 }
971 
lua_play_sound(lua_State * L)972 static int lua_play_sound(lua_State *L)
973 {
974 	const char *filename = luaL_checkstring(L, 1);
975 
976 	play_sound(filename);
977 	return 0;
978 }
979 
lua_event_freeze_tux(lua_State * L)980 static int lua_event_freeze_tux(lua_State * L)
981 {
982 	float duration = luaL_checknumber(L, 1);
983 	Me.paralyze_duration = duration;
984 	return 0;
985 }
986 
lua_event_freeze_npc(lua_State * L)987 static int lua_event_freeze_npc(lua_State * L)
988 {
989 	float duration = luaL_checknumber(L, 1);
990 	enemy *en = get_enemy_arg(L, 2);
991 	en->paralysation_duration_left = duration;
992 	return 0;
993 }
994 
lua_add_obstacle(lua_State * L)995 static int lua_add_obstacle(lua_State *L)
996 {
997 	int levelnum = lua_to_int(luaL_checkinteger(L, 1));
998 	struct level *level = curShip.AllLevels[levelnum];
999 	float x = luaL_checknumber(L, 2);
1000 	float y = luaL_checknumber(L, 3);
1001 	int type = luaL_checknumber(L, 4);
1002 
1003 	add_obstacle(level, x, y, type);
1004 
1005 	return 0;
1006 }
1007 
lua_add_volatile_obstacle(lua_State * L)1008 static int lua_add_volatile_obstacle(lua_State *L)
1009 {
1010 	int levelnum = lua_to_int(luaL_checkinteger(L, 1));
1011 	struct level *level = curShip.AllLevels[levelnum];
1012 	float x = luaL_checknumber(L, 2);
1013 	float y = luaL_checknumber(L, 3);
1014 	int type = luaL_checknumber(L, 4);
1015 
1016 	struct obstacle_spec *obs_spec = get_obstacle_spec(type);
1017 	add_volatile_obstacle(level, x, y, type, obs_spec->vanish_delay + obs_spec->vanish_duration);
1018 
1019 	return 0;
1020 }
1021 
lua_meters_traveled(lua_State * L)1022 static int lua_meters_traveled(lua_State *L)
1023 {
1024 	lua_pushinteger(L, (lua_Integer)Me.meters_traveled);
1025 	return 1;
1026 }
1027 
lua_run_from_dialog(lua_State * L)1028 static int lua_run_from_dialog(lua_State *L)
1029 {
1030 	lua_pushboolean(L, (chat_get_current_context() != NULL));
1031 	return 1;
1032 }
1033 
lua_running_benchmark(lua_State * L)1034 static int lua_running_benchmark(lua_State *L)
1035 {
1036 	lua_pushboolean(L, (do_benchmark) != NULL);
1037 	return 1;
1038 }
1039 
lua_reprogramm_bots_after_takeover(lua_State * L)1040 static int lua_reprogramm_bots_after_takeover(lua_State *L)
1041 {
1042 	int rvat = lua_to_int(luaL_checkinteger(L, 1));
1043 	GameConfig.talk_to_bots_after_takeover = rvat;
1044 
1045 	return 0;
1046 }
1047 
lua_switch_background_music_to(lua_State * L)1048 static int lua_switch_background_music_to(lua_State *L)
1049 {
1050 	char *filename = (char *)luaL_checkstring(L, 1);
1051 	switch_background_music(filename);
1052 	return 0;
1053 }
1054 
lua_exit_game(lua_State * L)1055 static int lua_exit_game(lua_State *L)
1056 {
1057 	lua_Integer exit_status = luaL_checkinteger(L, 1);
1058 
1059 	if (exit_status == 1) {
1060 		Terminate(EXIT_FAILURE);
1061 		return 0;
1062 	} else {
1063 		Terminate(EXIT_SUCCESS);
1064 		return 0;
1065 	}
1066 }
1067 
lua_find_file(lua_State * L)1068 static int lua_find_file(lua_State *L)
1069 {
1070 	char fpath[PATH_MAX];
1071 	const char *filename = (char *)luaL_checkstring(L, 1);
1072 	int subdir_handle    = lua_to_int(luaL_checkinteger(L, 2));
1073 
1074 	if (subdir_handle >= 0 && subdir_handle < LAST_DATA_DIR) {
1075 		if (find_file(filename, subdir_handle, fpath, PLEASE_INFORM)) {
1076 			lua_pushstring(L, fpath);
1077 			return 1;
1078 		}
1079 	}
1080 
1081 	lua_pushnil(L); /* return nil on error */
1082 	return 1;
1083 }
1084 
lua_term_has_color_cap(lua_State * L)1085 static int lua_term_has_color_cap(lua_State *L)
1086 {
1087 	lua_pushboolean(L, (term_has_color_cap == TRUE));
1088 	return 1;
1089 }
1090 
lua_dir(lua_State * L)1091 static int lua_dir(lua_State *L)
1092 {
1093 	/* Note: Code taken (and adapted) from "Programming in Lua, 2nd edition" */
1094 
1095 	DIR *dir = NULL;
1096 	struct dirent *entry = NULL;
1097 	int i;
1098 	int subdir_handle = lua_to_int(luaL_checkinteger(L, 1));
1099 
1100 	if (subdir_handle < 0 || subdir_handle >= LAST_DATA_DIR) {
1101 		lua_pushnil(L); /* return nil on error */
1102 		return 1;
1103 	}
1104 
1105 	/* open directory */
1106 	dir = opendir(data_dirs[subdir_handle].path);
1107 
1108 	/* create the returned result table */
1109 	lua_newtable(L);
1110 	i = 1;
1111 	while ((entry = readdir(dir)) != NULL) {
1112 		lua_pushnumber(L, i++); /* push key */
1113 		lua_pushstring(L, entry->d_name); /* push value */
1114 		lua_settable(L, -3);
1115 	}
1116 
1117 	closedir(dir);
1118 	return 1;
1119 }
1120 
lua_set_mouse_move_target(lua_State * L)1121 static int lua_set_mouse_move_target(lua_State *L)
1122 {
1123 	/* USE WITH CARE!
1124 	 * I made this function so we could automatizes some tests on level 24
1125 	 * This is not supposed to be used in the "real game"
1126 	 */
1127 	Me.mouse_move_target.x = luaL_checknumber(L, 1);
1128 	Me.mouse_move_target.y = luaL_checknumber(L, 2);
1129 	Me.mouse_move_target.z = luaL_checknumber(L, 3);
1130 
1131 	move_tux();
1132 
1133 	return 1;
1134 }
1135 
lua_src_gettext(lua_State * L)1136 static int lua_src_gettext(lua_State *L)
1137 {
1138 	char *text = (char *)luaL_checkstring(L, 1);
1139 	lua_pushstring(L, _(text));
1140 	return 1;
1141 }
1142 
lua_data_gettext(lua_State * L)1143 static int lua_data_gettext(lua_State *L)
1144 {
1145 	char *text = (char *)luaL_checkstring(L, 1);
1146 	lua_pushstring(L, D_(text));
1147 	return 1;
1148 }
1149 
lua_dialogs_gettext(lua_State * L)1150 static int lua_dialogs_gettext(lua_State *L)
1151 {
1152 	char *text = (char *)luaL_checkstring(L, 1);
1153 	lua_pushstring(L, L_(text));
1154 	return 1;
1155 }
1156 
lua_get_game_version(lua_State * L)1157 static int lua_get_game_version(lua_State *L)
1158 {
1159 	lua_pushstring(L, freedroid_version);
1160 	return 1;
1161 }
1162 
1163 luaL_Reg lfuncs[] = {
1164 	/* teleport(string map_label)
1165 	 * Teleports the player to the given map label.
1166 	 */
1167 	{"teleport", lua_event_teleport} // -> FDtux:teleport
1168 	,
1169 	/* teleport_npc(string map_label, [dialog name])
1170 	 * Teleports the current npc, or named npc to the given map label
1171 	 */
1172 	{"teleport_npc", lua_event_teleport_npc} // -> FDnpc:teleport
1173 	,
1174 	/* teleport_home(string map_label)
1175 	 * Teleports the player to the home.
1176 	 */
1177 	{"teleport_home", lua_event_teleport_home} // -> FDtux:teleport_home
1178 	,
1179 	/* has_teleport_anchor()
1180 	 * Return true if a teleport anchor is active.
1181 	 */
1182 	{"has_teleport_anchor", lua_event_has_teleport_anchor} // -> FDtux:has_teleport_anchor
1183 	,
1184 	/* display_big_message(string msg)
1185 	 * Displays a big vanishing message on screen (seen in game, not in the dialog).
1186 	 */
1187 	{"display_big_message", lua_event_display_big_message}
1188 	,
1189 	/* use display_console_message(string msg), supports [b] and [/b]
1190 	 * Displays a message on the game console.
1191 	 */
1192 	{"event_display_console_message", lua_event_display_console_message}
1193 	,
1194 
1195 	/* change_obstacle_type(string obstacle_label, int obstacle_type)
1196 	 * Changes the obstacle to the given state.
1197 	 */
1198 	{"change_obstacle_type", lua_event_change_obstacle},
1199 	{"get_obstacle_type", lua_event_get_obstacle_type}
1200 	,
1201 	/* del_obstacle(string obstacle_label)
1202 	 * Delete the given obstacle
1203 	 */
1204 	{"del_obstacle", lua_event_delete_obstacle}
1205 	,
1206 
1207 	/* change_obstacle_message(string obstacle_label, string message)
1208 	 * Change the SIGNMESSAGE of the given obstacle.
1209 	 */
1210 	{"change_obstacle_message", lua_change_obstacle_message}
1211 	,
1212 
1213 	/* kill_tux() - kills Tux
1214 	 * heal_tux() - heal_tux completely heals Tux
1215 	 * hurt_tux(int how_many_hp_to_remove) - removes the given number of health points.
1216 	 * 	This number can obviously be negative.
1217 	 * heat_tux(int amount)	- Increases temperature (=removes cooling), number can be negative.
1218 	 */
1219 	{"kill_tux", lua_event_kill_tux} // -> FDtux:kill
1220 	,
1221 	{"heal_tux", lua_event_heal_tux} // -> FDtux:heal
1222 	,
1223 	{"hurt_tux", lua_event_hurt_tux} // -> FDtux:hurt
1224 	,
1225 	{"heat_tux", lua_event_heat_tux} // -> FDtux:heat
1226 	,
1227 	/* get_tux_hp()             - Returns Tux's current health
1228 	 * get_tux_max_hp()         - Returns Tux's current maximum health
1229 	 * see also: tux_hp_ratio() - Returns the ratio of the two
1230 	 */
1231 	{"get_tux_hp", lua_event_get_tux_hp} // -> FDtux:get_hp
1232 	,
1233 	{"get_tux_max_hp", lua_event_get_tux_max_hp} // -> FDtux:get_max_hp
1234 	,
1235 	/* get_tux_cool()		- Returns Tux's current remaining heat absorbing capabilities
1236 	 */
1237 	{"get_tux_cool", lua_event_get_tux_cool} // -> FDtux:get_cool
1238 	,
1239 	/* improve_skill(string skill_name)
1240 	 * get_skill()
1241 	 * improve_skill improves one of the three "melee", "ranged" and "programming" skills
1242 	 * by one level.
1243 	 * get_skill returns the current level (as an integer) of one of the three skills.
1244 	 */
1245 	{"improve_skill", lua_event_improve_skill} // -> FDtux:improve_skill
1246 	,
1247 	{"get_skill", lua_event_get_skill} // -> FDtux:get_skill
1248 	,
1249 
1250 	/* improve_program(string program_name)
1251 	 * Improve the program given by one level.
1252 	 * get_program_revision(string program_name) returns current program revision level
1253 	 */
1254 	{"improve_program", lua_event_improve_program} // -> FDtux:improve_program
1255 	,
1256 	{"downgrade_program", lua_event_downgrade_program} // -> FDtux:downgrade_program
1257 	,
1258 	{"get_program_revision", lua_event_get_program_revision} // -> FDtux:get_program_revision
1259 	,
1260 	/* del_item_backpack(string item_name[, int multiplicity = 1])
1261 	 * add_item(string item_name, int multiplicity)
1262 	 * - Deletes or adds the given number of items from/to the inventory.
1263 	 *
1264 	 * count_item_backpack(string item_name)
1265 	 * - returns the number of items of the given name currently in the inventory.
1266 	 *
1267 	 * has_item_equipped(string item_name)
1268 	 * - returns true when the item is equipped
1269 	 */
1270 	{"del_item_backpack", lua_event_delete_item} // -> FDtux:del_item_backpack
1271 	,
1272 	{"add_item", lua_event_give_item} // -> FDtux:add_item
1273 	,
1274 	{"count_item_backpack", lua_event_count_item_backpack} // -> FDtux:count_item_backpack
1275 	,
1276 	{"has_item_equipped", lua_event_has_item_equipped} // -> FDtux:has_item_equipped
1277 	,
1278 	{"equip_item", lua_event_equip_item} // -> FDtux:equip_item
1279 	,
1280 	{"sell_item", lua_event_sell_item}
1281 	,
1282 	/* set_death_item(string item_name [, string  npc])
1283 	 * changes the item dropped when the droid dies
1284 	*/
1285 	{"set_death_item", lua_set_death_item} // -> FDnpc:set_death_item
1286 	,
1287 	{"add_diary_entry", lua_event_add_diary_entry}
1288 	,
1289 	{"has_met", lua_event_has_met} // -> FDtux:has_met
1290 	,
1291 	{"assign_quest", lua_event_assign_mission} // -> FDtux:assign_quest
1292 	,
1293 	{"has_quest", lua_event_is_mission_assigned} // -> FDtux:has_quest
1294 	,
1295 	{"complete_quest", lua_event_complete_mission} // -> FDtux:complete_quest
1296 	,
1297 	{"done_quest", lua_event_is_mission_complete} // -> FDtux:done_quest
1298 	,
1299 	{"add_xp", lua_event_give_xp} // -> FDtux:add_xp
1300 	,
1301 	{"del_training_points", lua_event_eat_training_points} // -> FDtux:del_training_points
1302 	,
1303 	{"get_training_points", lua_event_get_training_points} // -> FDtux:get_training_points
1304 	,
1305 	{"add_gold", lua_event_add_gold} // -> FDtux:add_gold
1306 	,
1307 	{"get_gold", lua_event_get_gold} // -> FDtux:get_gold
1308 	,
1309 	{"change_stat", lua_event_change_stat} // -> FDtux:change_stat
1310 	,
1311 	{"respawn_level", lua_event_respawn_level}
1312 	,
1313 	{"trade_with", lua_event_trade_with}
1314 	,
1315 	{"upgrade_items", lua_event_upgrade_items}
1316 	,
1317 	{"craft_addons", lua_event_craft_addons}
1318 	,
1319 	{"get_player_name", lua_chat_player_name} // -> FDtux:get_player_name
1320 	,
1321 	{"chat_says", lua_chat_says}
1322 	,
1323 	{"start_chat", lua_start_chat}
1324 	,
1325 	{"end_dialog", lua_chat_end_dialog}
1326 	,
1327 	/* NOTE:  if (partner_started())  will always be true
1328 	 * if rush_tux is 1
1329 	 */
1330 	{"partner_started", lua_chat_partner_started}
1331 	,
1332 	{"drop_dead", lua_chat_drop_dead}  // -> FDnpc:drop_dead
1333 	,
1334 	{"bot_exists", lua_chat_bot_exists} // <Fluzz> Is that really needed ?
1335 	,
1336 	{"set_bot_state", lua_chat_set_bot_state} // -> FDnpc:set_state
1337 	,
1338 	{"set_bot_destination", lua_set_bot_destination} // -> FDnpc:set_destination
1339 	,
1340 	{"broadcast_bot_state", lua_chat_broadcast_bot_state} // <Fluzz> Broadcast only to bots with same dialog. Intended ?
1341 	,
1342 	/* set_rush_tux()   - Sets or unsets if the NPC should rush and talk to Tux
1343 	 * will_rush_tux() - Checks if the NPC is planning on rushing Tux
1344 	 */
1345 	{"set_rush_tux", lua_set_rush_tux} // -> FDnpc:set_rush_tux
1346 	,
1347 	{"will_rush_tux", lua_will_rush_tux} // -> FDnpc:get_rush_tux
1348 	,
1349 	{"takeover", lua_chat_takeover}
1350 	,
1351 	/* heal_npc([dialog])			- Returns the NPC's current health
1352 	 * npc_damage_amount([dialog])		- Returns the current damage for the NPC
1353 	 * npc_max_health([dialog])		- Returns the max possible health for the NPC
1354 	 * see also: npc_damage_ratio([dialog]) - Returns the ratio of the two
1355 	 */
1356 	{"heal_npc", lua_event_heal_npc} // -> FDnpc:heal
1357 	,
1358 	{"npc_damage_amount", lua_get_npc_damage_amount} // -> FDnpc:get_damage
1359 	,
1360 	{"npc_max_health", lua_get_npc_max_health} // -> FDnpc:get_max_health
1361 	,
1362 	{"freeze_tux_npc", lua_event_freeze_tux_npc}
1363 	,
1364 	{"npc_dead", lua_event_npc_dead},  // -> FDnpc:is_dead
1365 	/* bot_type() tells you what model
1366 	   bot_class() tells you the class of a bot
1367 	   bot_name() tells you what name it displays
1368 	   set_bot_name() puts a new name in
1369 	 */
1370 	{"bot_type", lua_chat_get_bot_type}, // -> FDnpc:get_type
1371 
1372 	{"bot_class", lua_event_bot_class}, // -> FDnpc:get_class
1373 
1374 	{"bot_name", lua_chat_get_bot_name}, // -> FDnpc:get_name
1375 	{"bot_translated_name", lua_chat_get_bot_translated_name}, // -> FDnpc:get_translated_name
1376 
1377 	{"set_bot_name", lua_chat_set_bot_name}, // -> FDnpc:set_name
1378 
1379 	{"difficulty_level", lua_difficulty_level},
1380 
1381 	{"set_npc_faction", lua_set_npc_faction}, // -> FDnpc:set_faction
1382 	{"set_faction_state", lua_set_faction_state},
1383 	/*
1384 	  kill_faction() kills all enemies belonging
1385 	  to a specified faction. The second argument is
1386 	  optional, and specifies whether or not the faction
1387 	  will respawn. It can only be the string "no_respawn".
1388 	*/
1389 	{"kill_faction", lua_kill_faction},
1390 
1391 	{"user_input_string", lua_user_input_string},
1392 
1393 	{"create_droid", lua_create_droid},
1394 
1395 	{"win_game", lua_win_game},
1396 	// Finish the game.
1397 
1398 	{"game_time", lua_get_game_time},
1399 	{"game_date", lua_get_game_date},
1400 	/* play_sound("file")
1401 	 * path has to originate from /sound , e.g.
1402 	 * play_sound("effects/No_Ammo_Sound_0.ogg")
1403 	 */
1404 	{"play_sound", lua_play_sound},
1405 	// freeze_tux() freezes tux for the given amount of seconds
1406 	{"freeze_tux", lua_event_freeze_tux}, // -> FDtux:freeze
1407 	// freeze_npc() freezes the npc for the given amount of seconds
1408 	{"freeze_npc", lua_event_freeze_npc}, // -> FDnpc:freeze
1409 	/* add_obstacle(lvl, x, y, obst_ID) add obstacles to maps at given position
1410 	 * add_obstacle(8, 41.4, 51.5, 100)
1411 	 * where 8 is the level number, x and y are the coorinates and 100
1412 	 * is the obstacle ID (see defs.h)
1413 	 */
1414 	{"add_obstacle", lua_add_obstacle},
1415 	{"add_volatile_obstacle", lua_add_volatile_obstacle},
1416 	// meters_traveled() returns ingame meters tux has traveled
1417 	{"meters_traveled", lua_meters_traveled}, // -> FDtux:get_meters_traveled
1418 	// if (run_from_dialog()) then
1419 	// to check if certain code was run from inside a dialog or not
1420 	{"run_from_dialog", lua_run_from_dialog},
1421 	// returns if we are running a benchmark e.g. the dialog validator
1422 	// or not
1423 	// USE WITH CARE
1424 	{"running_benchmark", lua_running_benchmark},
1425 	/* switch_background_music("file")
1426 	 * path has to originate from /sound/music , e.g.
1427 	 * play_sound("menu.ogg")
1428 	 */
1429 	{"switch_background_music", lua_switch_background_music_to},
1430 	// 1 = true,  0 = false
1431 	{"reprogramm_bots_after_takeover", lua_reprogramm_bots_after_takeover},
1432 
1433 	{"exit_game", lua_exit_game},
1434 
1435 	{"find_file", lua_find_file},
1436 	{"dir", lua_dir},
1437 
1438 	{"term_has_color_cap", lua_term_has_color_cap },
1439 	/* USE WITH CARE!
1440 	 * I made this function so we could automatizes some tests on level 24
1441 	 * This is not supposed to be used in the "real game"
1442 	 */
1443 	{"set_mouse_move_target", lua_set_mouse_move_target},
1444 
1445 	{"get_game_version", lua_get_game_version},
1446 	{NULL, NULL}
1447 };
1448 
1449 /*
1450  * Prepare a lua function call by pushing on the Lua stack the name of
1451  * the function to call and the arguments of the call (see comment of call_lua_func()).
1452  */
push_func_and_args(lua_State * L,const char * module,const char * func,const char * sig,va_list * vl)1453 static int push_func_and_args(lua_State *L, const char *module, const char *func, const char *sig, va_list *vl)
1454 {
1455 	 /* push function */
1456 	if (module) {
1457 		lua_getglobal(L, module);
1458 		lua_getfield(L, -1, func);
1459 		lua_remove(L, -2);
1460 	} else {
1461 		lua_getglobal(L, func);
1462 	}
1463 
1464 	while (sig && *sig) { /* repeat for each argument */
1465 		switch (*sig++) {
1466 		case 'f': /* double argument */
1467 			lua_pushnumber(L, va_arg(*vl, double));
1468 			break;
1469 		case 'd': /* int argument */
1470 			lua_pushinteger(L, (lua_Integer)va_arg(*vl, int));
1471 			break;
1472 		case 's': /* string argument */
1473 			lua_pushstring(L, va_arg(*vl, char *));
1474 			break;
1475 		case 'S': /* dynarray of strings : push a table containing the strings */
1476 			{
1477 				int i;
1478 				struct dynarray *array = va_arg(*vl, struct dynarray *);
1479 				lua_createtable(L, array->size, 0);
1480 				for (i=0; i<array->size; i++)
1481 				{
1482 					char *text = ((char **)(array->arr))[i];
1483 					lua_pushstring(L, text);
1484 					lua_rawseti(L, -2, i+1); // table[i+1] = text
1485 				}
1486 			}
1487 			break;
1488 		default:
1489 			DebugPrintf(-1, "call_lua_func: invalid input option (%c).", *(sig - 1));
1490 			return 0;
1491 		}
1492 	}
1493 
1494 	return 1;
1495 }
1496 
1497 /*
1498  * Retrieve the returned values of a lua function call.
1499  * The results are stored in the locations pointed to by the pointer arguments
1500  * that follow the signature string (see comment of call_lua_func()).
1501  */
pop_results(lua_State * L,const char * sig,va_list * vl)1502 static int pop_results(lua_State *L, const char *sig, va_list *vl)
1503 {
1504 	if (!sig)
1505 		return 1;
1506 
1507 	int nres = strlen(sig);
1508 	int index;
1509 	int rc = 0;
1510 
1511 	for (index = -nres; *sig; index++) { /* repeat for each result */
1512 		int ltype = lua_type(L, index);
1513 		switch (*sig++) {
1514 		case 'f': /* double result */
1515 			if (ltype != LUA_TNUMBER) {
1516 				DebugPrintf(-1, "call_lua_func: wrong result type for #%d returned value (number expected)", index);
1517 				goto pop_and_return;
1518 			}
1519 			*va_arg(*vl, double *) = lua_tonumber(L, index);
1520 			break;
1521 		case 'd': /* int result */
1522 			if (ltype != LUA_TNUMBER) {
1523 				DebugPrintf(-1, "call_lua_func: wrong result type for #%d returned value (number expected)", index);
1524 				goto pop_and_return;
1525 			}
1526 			*va_arg(*vl, int *) = lua_to_int(lua_tointeger(L, index));
1527 			break;
1528 		case 's': /* string result */
1529 			if (ltype != LUA_TSTRING) {
1530 				DebugPrintf(-1, "call_lua_func: wrong result type for #%d returned value (string expected)", index);
1531 				goto pop_and_return;
1532 			}
1533 			*va_arg(*vl, const char **) = strdup(lua_tostring(L, index));
1534 			break;
1535 		case 'S': /* dynarray of strings result */
1536 			{
1537 				int i;
1538 				if (ltype != LUA_TTABLE) {
1539 					DebugPrintf(-1, "call_lua_func: wrong result type for #%d returned value (table expected)", index);
1540 					goto pop_and_return;
1541 				}
1542 				struct dynarray *array = va_arg(*vl, struct dynarray *);
1543 				dynarray_init(array, lua_rawlen(L, index), sizeof(char *)); // the dynarray was reseted by the caller
1544 				for (i=1; i<=lua_rawlen(L, index); i++) {
1545 					lua_rawgeti(L, index, i);
1546 					if (!lua_isstring(L, -1)) {
1547 						DebugPrintf(-1, "call_lua_func: wrong result type for #%d:%d returned value (string expected).\nSkeeping that value", index, i);
1548 					} else {
1549 						char *nodename = strdup(lua_tostring(L, -1));
1550 						dynarray_add(array, &nodename, sizeof(string));
1551 					}
1552 					lua_pop(L, 1);
1553 				}
1554 			}
1555 			break;
1556 		default:
1557 			DebugPrintf(-1, "call_lua_func: invalid output option (%c)", *(sig - 1));
1558 			goto pop_and_return;
1559 		}
1560 	}
1561 
1562 	rc = 1;
1563 
1564 pop_and_return:
1565 	lua_pop(L, nres);
1566 	return rc;
1567 }
1568 
1569 /**
1570  * \brief Helper function to call a Lua function.
1571  *
1572  * \details Call a Lua function passing parameters and retrieving results through the
1573  * Lua stack.
1574  * (inspired from a code found in "Programming in Lua, 2ed").
1575  *
1576  * Usage:
1577  *
1578  * To execute a Lua function call such as "var1, var2 = my_module.my_func(param1)",
1579  * use "call_lua_func(lua_target, "my_module", "my_func", insig, outsig, param1, &var1, var2)"
1580  *
1581  * C being a strong typed language, the type of the input parameters and of the
1582  * returned values has to be defined, through 'insig' (for input parameters)
1583  * and 'outsig' (for returned values). A type is defined by a single specific
1584  * character, and 'insig' (resp. 'outsig') is a string containing a list of
1585  * those characters, one character per parameter (resp. returned value).
1586  *
1587  * Known types are:
1588  *   'f' for double type
1589  *   'd' for int type
1590  *   's' for string type (i.e. char*)
1591  *   'S' for dynarray of strings
1592  *
1593  * Following 'insig' and 'outsig' is a list of data to be used as parameters for
1594  * the Lua function (one data per character in 'insig'), followed by a list
1595  * of pointers to store the returned values (one pointer per character in 'outsig').
1596  * Note 1: memory of string returned values is allocated by call_lua_func().
1597  * Note 2: memory of string dynarray slots is allocated by call_lua_func(),
1598  *         and the dynarray has to be freed before the call.
1599  *
1600  * If the Lua function is not inside a module, set 'module' to NULL.
1601  * If the Lua function has no parameters, set 'insig' to NULL.
1602  * If the Lua does not return values, set 'outsig' to NULL.
1603  *
1604  * Exemples (of doubtful utility...):
1605  * double sine;
1606  * call_lua_func(LUA_DIALOG, "math", "sin", "f", "f", 3.14, &sine);
1607  * char *tmpname;
1608  * call_lua_func(LUA_DIALOG, "os", "tmpname", NULL, "s", tmpname);
1609  *
1610  * \param target A lua_target enum value defining the Lua context to use
1611  * \param module Name of the module containing the Lua function, or NULL if none
1612  * \param func   Name of the Lua function to call
1613  * \param insig  Signature string for the input parameters, or NULL
1614  * \param outsig Signature string for the returned values
1615  * \param ...    Input parameters data and pointers to returned value storages
1616  *
1617  * \return TRUE if the function call succeeded, else return FALSE
1618  */
call_lua_func(enum lua_target target,const char * module,const char * func,const char * insig,const char * outsig,...)1619 int call_lua_func(enum lua_target target, const char *module, const char *func, const char *insig, const char *outsig, ...)
1620 {
1621 	int narg = (insig) ? strlen(insig) : 0;   /* number of arguments */
1622 	int nres = (outsig) ? strlen(outsig) : 0; /* number of results */
1623 
1624 	lua_State *L = get_lua_state(target);
1625 
1626 	va_list vl;
1627 	va_start(vl, outsig);
1628 
1629 	/* do the call */
1630 	if (!push_func_and_args(L, module, func, insig, &vl)) {
1631 		error_message(__FUNCTION__, "Aborting lua function call.", NO_REPORT);
1632 		va_end(vl);
1633 		return FALSE;
1634 	}
1635 
1636 	if (lua_pcall(L, narg, nres, 0) != LUA_OK) {
1637 		DebugPrintf(-1, "call_lua_func: Error calling ’%s’: %s", func, lua_tostring(L, -1));
1638 		lua_pop(L, 1);
1639 		error_message(__FUNCTION__, "Aborting lua function call.", NO_REPORT);
1640 		va_end(vl);
1641 		return FALSE;
1642 	}
1643 
1644 	if (!pop_results(L, outsig, &vl)) {
1645 		error_message(__FUNCTION__, "Aborting lua function call.", NO_REPORT);
1646 		va_end(vl);
1647 		return FALSE;
1648 	}
1649 
1650 	va_end(vl);
1651 	return TRUE;
1652 }
1653 
pretty_print_lua_error(lua_State * L,const char * error_msg,const char * code,int cur_line,const char * funcname)1654 static void pretty_print_lua_error(lua_State* L, const char* error_msg, const char *code, int cur_line, const char *funcname)
1655 {
1656 	int err_line = 0;
1657 	struct auto_string *erronous_code;
1658 
1659 	erronous_code = alloc_autostr(16);
1660 
1661 	// Find which line the error is on (if there is a line number in the error message)
1662 	const char *error_ptr = error_msg;
1663 
1664 	while (*error_ptr != 0 && *error_ptr != ':') {
1665 		error_ptr++;
1666 	}
1667 	if (*error_ptr != 0) {
1668 		// Line number found
1669 		error_ptr++;
1670 		err_line = strtol(error_ptr, NULL, 10);
1671 	}
1672 
1673 	// Break up lua code by newlines then insert line numbers & error notification.
1674 	// Note: strtok() can not be used to split display_code, because a sequence
1675 	// of two or more contiguous delimiter bytes ('\n' in our case) in the parsed
1676 	// string is considered to be a single delimiter. So, we would miss all
1677 	// blank lines.
1678 	char *display_code = strdup(code);
1679 	char *ptr = display_code;
1680 
1681 	for (;;) {
1682 		char *line = ptr;
1683 
1684 		if (*line == '\0')
1685 			break;
1686 
1687 		ptr = strchr(line, '\n');
1688 		if (ptr)
1689 			*ptr = '\0';
1690 
1691 		if (err_line != cur_line) {
1692 			autostr_append(erronous_code, "%d  %s\n", cur_line, line);
1693 		} else if (term_has_color_cap) { //color highlighting for Linux/Unix terminals
1694 			autostr_append(erronous_code, "\033[41m>%d %s\033[0m\n", cur_line, line);
1695 		} else {
1696 			autostr_append(erronous_code, ">%d %s\n", cur_line, line);
1697 		}
1698 
1699 		if (!ptr) {
1700 			// We just inserted the last line
1701 			break;
1702 		}
1703 
1704 		// Prepare for next line output
1705 		*ptr = '\n';
1706 		ptr++;
1707 		cur_line++;
1708 	}
1709 
1710 	fflush(stdout);
1711 	error_message(funcname, "Error running Lua code: %s.\nErroneous LuaCode={\n%s}",
1712 			 PLEASE_INFORM, error_msg, erronous_code->value);
1713 
1714 	free(display_code);
1715 	free_autostr(erronous_code);
1716 }
1717 
1718 /**
1719  * \brief Prepare to call a lua function from a module in a coroutine
1720  *
1721  * \details Create a new lua thread, and fill the lua stack with the function to
1722  * call and its argument, in preparation to a call to resume_coroutine, which will
1723  * actually start the coroutine.
1724  * (See call_lua_func() for an explanation of the parameters, given that there are
1725  * no returned values for coroutine)
1726  *
1727  * \param target A lua_target enum value defining the Lua context to use
1728  * \param module Name of the module containing the Lua function, or NULL if none
1729  * \param func   Name of the Lua function to call
1730  * \param insig  Signature string for the input parameters, or NULL
1731  * \param ...    Input parameters data
1732  *
1733  * \return Pointer to a lua_coroutine struct holding the data needed to start (resume) the coroutine
1734  */
prepare_lua_coroutine(enum lua_target target,const char * module,const char * func,const char * insig,...)1735 struct lua_coroutine *prepare_lua_coroutine(enum lua_target target, const char *module, const char *func, const char *insig, ...)
1736 {
1737 	lua_State *L = get_lua_state(target);
1738 	lua_State *co_L = lua_newthread(L);
1739 
1740 	struct lua_coroutine *new_coroutine = (struct lua_coroutine *)MyMalloc(sizeof(struct lua_coroutine));
1741 	new_coroutine->thread = co_L;
1742 	new_coroutine->nargs = (insig) ? strlen(insig) : 0;
1743 
1744 	va_list vl;
1745 	va_start(vl, insig);
1746 
1747 	push_func_and_args(co_L, module, func, insig, &vl);
1748 
1749 	va_end(vl);
1750 
1751 	return new_coroutine;
1752 }
1753 
1754 /**
1755  * \brief Prepare to call a lua function, given in a source code, in a coroutine
1756  *
1757  * \details Create a new lua thread, and fill the lua stack with the function to
1758  * call and its argument, in preparation to a call to resume_coroutine, which will
1759  * actually start the coroutine.
1760  *
1761  * \param target A lua_target enum value defining the Lua context to use
1762  * \param code   The code of the function to execute
1763  *
1764  * \return Pointer to a lua_coroutine struct holding the data needed to start (resume) the coroutine
1765  */
load_lua_coroutine(enum lua_target target,const char * code)1766 struct lua_coroutine *load_lua_coroutine(enum lua_target target, const char *code)
1767 {
1768 	lua_State *L = get_lua_state(target);
1769 	lua_State *co_L = lua_newthread(L);
1770 
1771 	if (luaL_loadstring(co_L, code)) {
1772 		pretty_print_lua_error(co_L, lua_tostring(co_L, -1), code, 2, __FUNCTION__);
1773 		lua_pop(L, -1);
1774 		return NULL;
1775 	}
1776 	struct lua_coroutine *new_coroutine = (struct lua_coroutine *)MyMalloc(sizeof(struct lua_coroutine));
1777 	new_coroutine->thread = co_L;
1778 	new_coroutine->nargs = 0;
1779 
1780 	return new_coroutine;
1781 }
1782 
resume_lua_coroutine(struct lua_coroutine * coroutine)1783 int resume_lua_coroutine(struct lua_coroutine *coroutine)
1784 {
1785 	int rtn = lua_resume(coroutine->thread, NULL, coroutine->nargs);
1786 
1787 	switch (rtn) {
1788 		case 0:
1789 			// The lua script has ended
1790 			return TRUE;
1791 		case LUA_YIELD:
1792 			// The lua script is 'pausing'. Next resume will be without arguments
1793 			coroutine->nargs = 0;
1794 			return FALSE;
1795 		default:
1796 			// Any other return code is an error.
1797 			break;
1798 	}
1799 
1800 	// On error:
1801 	// Use the lua debug API to get informations about the code of the current script
1802 	char *error_msg = strdup(lua_tostring(coroutine->thread, -1));
1803 
1804 	lua_Debug ar;
1805 	lua_getstack(coroutine->thread, 0, &ar);
1806 	lua_getinfo(coroutine->thread, "nS", &ar);
1807 
1808 	if (ar.what[0] == 'C') {
1809 		// Error caught in a C function.
1810 		// Try to get the lua calling code from the call stack.
1811 		if (!lua_getstack(coroutine->thread, 1, &ar)) {
1812 			// Nothing in the call stack. Display an error msg and exit.
1813 			error_message(__FUNCTION__, "Error in a lua API call in function '%s()': %s.",
1814 					PLEASE_INFORM, ar.name, error_msg);
1815 			goto EXIT;
1816 		}
1817 		// Get the info of the lua calling code, and continue to display it
1818 		lua_getinfo(coroutine->thread, "nS", &ar);
1819 	}
1820 
1821 	if (ar.source[0] != '@') {
1822 		// ar.source contains the script code
1823 		pretty_print_lua_error(coroutine->thread, error_msg, ar.source, 2, __FUNCTION__);
1824 	} else {
1825 		// The script code is in an external file
1826 		// Extract the erroneous function's code from the source file
1827 		FILE *src = fopen(&ar.source[1], "r");
1828 		struct auto_string *code = alloc_autostr(256);
1829 		char buffer[256] = "";
1830 		char *ptr = buffer;
1831 		int lc = 1;
1832 		for (;;) {
1833 			if (*ptr == '\0') {
1834 				if (feof(src)) break;
1835 				size_t nbc = fread(buffer, 1, 255, src);
1836 				buffer[nbc] = '\0';
1837 				ptr = buffer;
1838 			}
1839 			if (lc > ar.lastlinedefined) break;
1840 			if (lc >= ar.linedefined) {
1841 				// The use of autostr_append to add a single character is
1842 				// not efficient, but this code is used only in case of a
1843 				// script error, so we do not really care of efficiency
1844 				autostr_append(code, "%c", *ptr);
1845 			}
1846 			if (*ptr == '\n') lc++;
1847 			ptr++;
1848 		}
1849 
1850 		pretty_print_lua_error(coroutine->thread, error_msg, code->value, ar.linedefined, __FUNCTION__);
1851 		free_autostr(code);
1852 	}
1853 
1854 EXIT:
1855 	free(error_msg);
1856 	lua_pop(coroutine->thread, 1);
1857 
1858 	return TRUE; // Pretend the lua script has ended
1859 }
1860 
run_lua(enum lua_target target,const char * code)1861 int run_lua(enum lua_target target, const char *code)
1862 {
1863 	lua_State *L = get_lua_state(target);
1864 
1865 	int rtn = luaL_dostring(L, code);
1866 	if (rtn) {
1867 		pretty_print_lua_error(L, lua_tostring(L, -1), code, 2, __FUNCTION__);
1868 		lua_pop(L, -1);
1869 	}
1870 
1871 	return rtn;
1872 }
1873 
run_lua_file(enum lua_target target,const char * path)1874 void run_lua_file(enum lua_target target, const char *path)
1875 {
1876 	lua_State *L = get_lua_state(target);
1877 
1878 	if (luaL_dofile(L, path)) {
1879 		error_message(__FUNCTION__, "Cannot run script file %s: %s.",
1880 		         PLEASE_INFORM | IS_FATAL, path, lua_tostring(L, -1));
1881 	}
1882 }
1883 
set_lua_ctor_upvalue(enum lua_target target,const char * fn,void * p)1884 void set_lua_ctor_upvalue(enum lua_target target, const char *fn, void *p)
1885 {
1886 	lua_State *L = get_lua_state(target);
1887 
1888 	lua_getglobal(L, fn);
1889 	lua_pushlightuserdata(L, p);
1890 	if (!lua_setupvalue(L, -2, 1)) {
1891 		lua_pop(L, 2);
1892 		error_message(__FUNCTION__, "No upvalue defined for %s closure.",
1893 		             PLEASE_INFORM | IS_FATAL, fn);
1894 	}
1895 	lua_pop(L, 1);
1896 }
1897 
1898 /*
1899  * Load a lua module in a lua context.
1900  * The directory containing the module is added to the package.path lua global
1901  * variable.
1902  * The module is loaded by calling 'require(module)'.
1903  */
load_lua_module(enum lua_target target,int subdir,const char * module)1904 static void load_lua_module(enum lua_target target, int subdir, const char *module)
1905 {
1906 	char *module_file;
1907 	char fpath[PATH_MAX];
1908 	lua_State *L = get_lua_state(target);
1909 
1910 	module_file = (char *)MyMalloc(strlen(module)+strlen(".lua")+1);
1911 	strcpy(module_file, module);
1912 	strcat(module_file, ".lua");
1913 
1914 	/*
1915 	 * Add the module's dir to the Lua package.path
1916 	 */
1917 
1918 	if (find_file(module_file, subdir, fpath, PLEASE_INFORM)) {
1919 
1920 		// Keep the dirname of the file path and add the search pattern
1921 		char *ptr = strstr(fpath, module_file);
1922 		strcpy(ptr, "?.lua");
1923 
1924 		// Get current Lua package.path
1925 		lua_getglobal(L, "package");
1926 		lua_getfield(L, 1, "path");
1927 		const char *package_path = lua_tostring(L, -1);
1928 		lua_pop(L, 2);
1929 
1930 		// Add the search path, if needed
1931 		if (!strstr(package_path, fpath)) {
1932 			lua_getglobal(L, "package"); /* -> stack: package */
1933 			lua_getfield(L, 1, "path");  /* -> stack: package.path < package */
1934 			lua_pushliteral(L, ";");     /* -> stack: ";" < package.path < package */
1935 			lua_pushstring(L, fpath);    /* -> stack: fpath < ";" < package.path < package */
1936 			lua_concat(L, 3);            /* -> stack: package.path;fpath < package */
1937 			lua_setfield(L, 1, "path");  /* package.path = package.path;fpath -> stack: package */
1938 			lua_pop(L, 1);
1939 		}
1940 	}
1941 
1942 	/*
1943 	 * Call "require(module)" to load the module
1944 	 */
1945 
1946 	call_lua_func(target, NULL, "require", "s", NULL, module);
1947 
1948 	free(module_file);
1949 }
1950 
1951 /**
1952  * Initialize the Lua state used to load the config files
1953  */
init_lua()1954 void init_lua()
1955 {
1956 	char fpath[PATH_MAX];
1957 
1958 	dialog_lua_state = NULL;
1959 
1960 	config_lua_state = luaL_newstate();
1961 	luaL_openlibs(config_lua_state);
1962 
1963 	// Add a context specific lua gettext
1964 	luaL_Reg lua_gettexts = { "D_", lua_data_gettext };
1965 	lua_pushcfunction(config_lua_state, lua_gettexts.func);
1966 	lua_setglobal(config_lua_state, lua_gettexts.name);
1967 
1968 	find_file("script_helpers.lua", MAP_DIR, fpath, PLEASE_INFORM | IS_FATAL);
1969 	run_lua_file(LUA_CONFIG, fpath);
1970 }
1971 
1972 /**
1973  * Close all active lua states. To be called when the game quits, to call
1974  * the lua garbage collector, in order to call all Lua object 'destructors'
1975  */
close_lua()1976 void close_lua()
1977 {
1978 	if (dialog_lua_state)
1979 		lua_close(dialog_lua_state);
1980 	if (config_lua_state)
1981 		lua_close(config_lua_state);
1982 }
1983 
1984 /**
1985  * Reset (or create) the Lua state used to load and execute the dialogs
1986  */
reset_lua_state(void)1987 void reset_lua_state(void)
1988 {
1989 	int i;
1990 	char fpath[2048];
1991 
1992 	if (dialog_lua_state)
1993 		lua_close(dialog_lua_state);
1994 	dialog_lua_state = luaL_newstate();
1995 	luaL_openlibs(dialog_lua_state);
1996 
1997 	// Add context specific lua gettexts
1998 	luaL_Reg lua_gettext[] = {
1999 			{ "_",  lua_dialogs_gettext },
2000 			{ "S_", lua_src_gettext     },
2001 			{ "D_", lua_data_gettext    },
2002 			{ NULL, NULL }
2003 	};
2004 	for (i = 0; lua_gettext[i].name != NULL; i++) {
2005 		lua_pushcfunction(dialog_lua_state, lua_gettext[i].func);
2006 		lua_setglobal(dialog_lua_state, lua_gettext[i].name);
2007 	}
2008 
2009 	for (i = 0; lfuncs[i].name != NULL; i++) {
2010 		lua_pushcfunction(dialog_lua_state, lfuncs[i].func);
2011 		lua_setglobal(dialog_lua_state, lfuncs[i].name);
2012 	}
2013 
2014 	// Bindings
2015 	luaFD_init(get_lua_state(LUA_DIALOG));
2016 
2017 	// Load and initialize some Lua modules
2018 	load_lua_module(LUA_DIALOG, LUA_MOD_DIR, "FDutils");
2019 	load_lua_module(LUA_DIALOG, LUA_MOD_DIR, "FDdialog");
2020 	call_lua_func(LUA_DIALOG, "FDdialog", "set_dialog_dir", "d", NULL, DIALOG_DIR);
2021 
2022 	// Finally load the script helpers Lua functions
2023 	find_file("script_helpers.lua", MAP_DIR, fpath, PLEASE_INFORM | IS_FATAL);
2024 	run_lua_file(LUA_DIALOG, fpath);
2025 
2026 }
2027 
2028 /**
2029  * Save Lua variables as lua code.
2030  * Variables prefixed with '_' are omitted because these are Lua predefined variables.
2031  */
write_lua_variables(struct auto_string * savestruct_autostr)2032 void write_lua_variables(struct auto_string *savestruct_autostr)
2033 {
2034 	int boolean;
2035 	const char *value;
2036 	lua_State *L = get_lua_state(LUA_DIALOG);
2037 
2038 	// Push global table on the stack
2039 	lua_pushglobaltable(L);
2040 
2041 	// Loop over the global table content
2042 	lua_pushnil(L);
2043 	while (lua_next(L, -2) != 0) {
2044 		int value_type = lua_type(L, -1);
2045 		int key_type = lua_type(L, -2);
2046 
2047 		if (key_type != LUA_TSTRING) {
2048 			lua_pop(L, 1);
2049 			continue;
2050 		}
2051 
2052 		const char *name = lua_tostring(L, -2);
2053 		if (name[0] == '_') {
2054 			lua_pop(L, 1);
2055 			continue;
2056 		}
2057 
2058 		switch (value_type)
2059 		{
2060 			case LUA_TBOOLEAN:
2061 				boolean = lua_toboolean(L, -1);
2062 				autostr_append(savestruct_autostr, "_G[\"%s\"] = %s\n", name, boolean ? "true" : "false");
2063 				break;
2064 			case LUA_TSTRING:
2065 				value = lua_tostring(L, -1);
2066 				autostr_append(savestruct_autostr, "_G[\"%s\"] = \"%s\"\n", name, value);
2067 				break;
2068 			case LUA_TNUMBER:
2069 				value = lua_tostring(L, -1);
2070 				autostr_append(savestruct_autostr, "_G[\"%s\"] = %s\n", name, value);
2071 				break;
2072 			default:
2073 				break;
2074 		}
2075 
2076 		lua_pop(L, 1);
2077 	}
2078 
2079 	autostr_append(savestruct_autostr, "\n");
2080 
2081 	// Pop global table from the stack
2082 	lua_pop(L, 1);
2083 }
2084