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