1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "common/lua/lua.h"
24 #include "common/lua/lauxlib.h"
25 #include "common/lua/lualib.h"
26 
27 #include "ultima/nuvie/core/nuvie_defs.h"
28 #include "ultima/nuvie/conf/configuration.h"
29 #include "ultima/nuvie/misc/u6_misc.h"
30 #include "ultima/nuvie/core/u6_objects.h"
31 #include "ultima/nuvie/core/game.h"
32 #include "ultima/nuvie/core/game_clock.h"
33 #include "ultima/nuvie/core/effect.h"
34 #include "ultima/nuvie/gui/widgets/msg_scroll.h"
35 #include "ultima/nuvie/core/player.h"
36 #include "ultima/nuvie/core/party.h"
37 #include "ultima/nuvie/actors/actor_manager.h"
38 #include "ultima/nuvie/core/tile_manager.h"
39 #include "ultima/nuvie/views/view_manager.h"
40 #include "ultima/nuvie/views/inventory_view.h"
41 #include "ultima/nuvie/actors/actor.h"
42 #include "ultima/nuvie/core/weather.h"
43 #include "ultima/nuvie/usecode/usecode.h"
44 #include "ultima/nuvie/sound/sound_manager.h"
45 #include "ultima/nuvie/gui/widgets/console.h"
46 #include "ultima/nuvie/core/cursor.h"
47 #include "ultima/nuvie/script/script.h"
48 #include "ultima/nuvie/script/script_actor.h"
49 #include "ultima/nuvie/script/script_cutscene.h"
50 #include "ultima/nuvie/core/magic.h"
51 #include "ultima/nuvie/files/tmx_map.h"
52 #include "ultima/nuvie/files/u6_lib_n.h"
53 
54 namespace Ultima {
55 namespace Nuvie {
56 
57 ///
58 // @module script
59 //
60 
61 /***
62 An in-game object
63 @table Obj
64 @string[readonly] luatype This returns "obj"
65 @int x x position
66 @int y y position
67 @int z z position
68 @tparam[readonly] MapCoord| xyz The object's Location in a MapCoord table.
69 @int obj_n object number
70 @int frame_n frame number
71 @int quality
72 @int qty quantity
73 @string[readonly] name The object name from the 'look' table.
74 @string[readonly] look_string A printable look description
75 	 a book
76 	 an elephant
77 	 5 torches
78 @bool[readonly] on_map Is the object on the map?
79 @bool[readonly] in_container Is the object in a container?
80 @field parent (Obj|Actor) The parent of this object. Either an object if this object is in a container. Or an Actor if this object is in an inventory.
81 @bool[readonly] readied Is this object readied in someone's inventory?
82 @bool[readonly] stackable Is this object able to be stacked together?
83 @number[readonly] weight The object's weight
84 @int[readonly] tile_num The tile number corresponding to the obj_n + frame_num values
85 @bool[readonly] getable Is this object getable by the player?
86 @bool ok_to_take Is it considered stealing if the player gets this object?
87 @int status Object status
88 @bool invisible Toggle object visibility
89 @bool[writeonly] temporary Toggle temporary status *writeonly*
90 
91  */
92 
93 /***
94 A map coordinate
95 @table MapCoord
96 @int x
97 @int y
98 @int z 0 for the 1024x1024 surface level, 1..5 for the dungeon levels
99  */
100 
101 /***
102 An actor schedule entry
103 @table Schedule
104 @int day_of_week
105 @int worktype
106 @int x
107 @int y
108 @int z
109  */
110 
111 extern bool nscript_new_actor_var(lua_State *L, uint16 actor_num);
112 
113 struct ScriptObjRef {
114 	uint16 refcount;
115 	iAVLKey key;
116 
ScriptObjRefUltima::Nuvie::ScriptObjRef117 	ScriptObjRef() {
118 		refcount = 0;
119 		key._int = -1;
120 	};
121 };
122 
123 static iAVLTree *script_obj_list;
124 
get_iAVLKey(const void * item)125 static iAVLKey get_iAVLKey(const void *item) {
126 	return ((const ScriptObjRef *)item)->key;
127 }
128 
129 static NuvieIO *g_objlist_file = NULL;
130 
131 // used for garbage collection.
132 //returns current object reference count. Or -1 on error.
133 static sint32 nscript_inc_obj_ref_count(Obj *obj);
134 static sint32 nscript_dec_obj_ref_count(Obj *obj);
135 
136 bool nscript_get_location_from_args(lua_State *L, uint16 *x, uint16 *y, uint8 *z, int lua_stack_offset = 1);
137 Obj *nscript_get_obj_from_args(lua_State *L, int lua_stack_offset);
138 extern Actor *nscript_get_actor_from_args(lua_State *L, int lua_stack_offset = 1);
139 
140 void nscript_new_obj_var(lua_State *L, Obj *obj);
141 
142 inline bool nscript_obj_init_from_obj(lua_State *L, Obj *dst_obj);
143 inline bool nscript_obj_init_from_args(lua_State *L, int nargs, Obj *s_obj);
144 static int nscript_obj_newobj(lua_State *L);
145 int nscript_obj_new(lua_State *L, Obj *obj);
146 static int nscript_obj_gc(lua_State *L);
147 static int nscript_obj_get(lua_State *L);
148 static int nscript_obj_set(lua_State *L);
149 static int nscript_obj_movetomap(lua_State *L);
150 static int nscript_obj_movetoinv(lua_State *L);
151 static int nscript_obj_movetocont(lua_State *L);
152 static int nscript_obj_use(lua_State *L);
153 static int nscript_obj_removefromengine(lua_State *L);
154 
155 static int nscript_container_remove_obj(lua_State *L);
156 
157 static const luaL_Reg nscript_objlib_f[] = {
158 	{ "new", nscript_obj_newobj },
159 	{ "moveToMap", nscript_obj_movetomap },
160 	{ "moveToInv", nscript_obj_movetoinv },
161 	{ "moveToCont", nscript_obj_movetocont },
162 	{ "removeFromCont", nscript_container_remove_obj },
163 	{ "removeFromEngine", nscript_obj_removefromengine },
164 	{ "use", nscript_obj_use },
165 
166 	{ NULL, NULL }
167 };
168 static const luaL_Reg nscript_objlib_m[] = {
169 	{ "__index", nscript_obj_get },
170 	{ "__newindex", nscript_obj_set },
171 	{ "__gc", nscript_obj_gc },
172 	{ NULL, NULL }
173 };
174 
175 static int nscript_u6link_gc(lua_State *L);
176 
177 static const struct luaL_Reg nscript_u6linklib_m[] = {
178 	{ "__gc", nscript_u6link_gc },
179 	{ NULL, NULL }
180 };
181 
182 static int nscript_u6link_recursive_gc(lua_State *L);
183 
184 static const struct luaL_Reg nscript_u6linkrecursivelib_m[] = {
185 	{ "__gc", nscript_u6link_recursive_gc },
186 	{ NULL, NULL }
187 };
188 
189 static int nscript_print(lua_State *L);
190 static int nscript_clear_scroll(lua_State *L);
191 static int nscript_display_prompt(lua_State *L);
192 //no longer used -- static int nscript_get_target(lua_State *L);
193 static int nscript_load(lua_State *L);
194 
195 static int nscript_config_get_boolean_value(lua_State *L);
196 static int nscript_config_get_game_type(lua_State *L);
197 static int nscript_config_get_language(lua_State *L);
198 
199 static int nscript_objlist_seek(lua_State *L);
200 static int nscript_objlist_read1(lua_State *L);
201 static int nscript_objlist_write1(lua_State *L);
202 static int nscript_objlist_read2(lua_State *L);
203 static int nscript_objlist_write2(lua_State *L);
204 
205 static int nscript_game_get_ui_style(lua_State *L);
206 static int nscript_player_get_name(lua_State *L);
207 static int nscript_player_get_gender(lua_State *L);
208 static int nscript_player_get_location(lua_State *L);
209 static int nscript_player_get_karma(lua_State *L);
210 static int nscript_player_set_karma(lua_State *L);
211 static int nscript_player_dec_alcohol(lua_State *L);
212 static int nscript_player_move(lua_State *L);
213 static int nscript_player_set_actor(lua_State *L);
214 static int nscript_player_is_in_solo_mode(lua_State *L);
215 
216 static int nscript_party_is_in_combat_mode(lua_State *L);
217 static int nscript_party_set_combat_mode(lua_State *L);
218 static int nscript_party_set_party_mode(lua_State *L);
219 static int nscript_party_move(lua_State *L);
220 static int nscript_party_use_entrance(lua_State *L);
221 static int nscript_party_get_size(lua_State *L);
222 static int nscript_party_get_member(lua_State *L);
223 static int nscript_party_update_leader(lua_State *L);
224 static int nscript_party_resurrect_dead_members(lua_State *L);
225 static int nscript_party_exit_vehicle(lua_State *L);
226 static int nscript_party_set_in_vehicle(lua_State *L);
227 static int nscript_party_dismount_from_horses(lua_State *L);
228 static int nscript_party_show_all(lua_State *L);
229 static int nscript_party_hide_all(lua_State *L);
230 
231 static int nscript_timer_set(lua_State *L);
232 static int nscript_timer_get(lua_State *L);
233 static int nscript_timer_update_all(lua_State *L);
234 
235 static int nscript_clock_get_year(lua_State *L);
236 static int nscript_clock_get_month(lua_State *L);
237 static int nscript_clock_get_day(lua_State *L);
238 static int nscript_clock_get_minute(lua_State *L);
239 static int nscript_clock_get_hour(lua_State *L);
240 static int nscript_clock_inc(lua_State *L);
241 
242 static int nscript_wind_set(lua_State *L);
243 static int nscript_wind_get(lua_State *L);
244 
245 static int nscript_input_select(lua_State *L);
246 static int nscript_input_select_integer(lua_State *L);
247 
248 //obj manager
249 static int nscript_objs_at_loc(lua_State *L);
250 static int nscript_find_volcano_obj_near_player(lua_State *L);
251 static int nscript_map_get_obj(lua_State *L);
252 static int nscript_map_remove_obj(lua_State *L);
253 static int nscript_map_is_water(lua_State *L);
254 static int nscript_map_is_on_screen(lua_State *L);
255 static int nscript_map_get_impedence(lua_State *L);
256 static int nscript_map_get_tile_num(lua_State *L);
257 static int nscript_map_get_dmg_tile_num(lua_State *L);
258 static int nscript_map_line_test(lua_State *L);
259 static int nscript_map_line_hit_check(lua_State *L);
260 
261 static int nscript_map_can_put_actor(lua_State *L);
262 static int nscript_map_can_put_obj(lua_State *L);
263 static int nscript_map_enable_temp_actor_cleaning(lua_State *L);
264 
265 static int nscript_map_export_tmx_files(lua_State *L);
266 
267 static int nscript_tileset_export(lua_State *L);
268 
269 static int nscript_tile_get_flag(lua_State *L);
270 static int nscript_tile_get_description(lua_State *L);
271 
272 static int nscript_anim_get_number_of_entries(lua_State *L);
273 static int nscript_anim_get_tile(lua_State *L);
274 static int nscript_anim_get_first_frame(lua_State *L);
275 static int nscript_anim_set_first_frame(lua_State *L);
276 static int nscript_anim_play(lua_State *L);
277 static int nscript_anim_stop(lua_State *L);
278 
279 //Misc
280 static int nscript_new_hit_entities_tbl_var(lua_State *L, ProjectileEffect *effect);
281 static int nscript_quake_start(lua_State *L);
282 static int nscript_explosion_start(lua_State *L);
283 static int nscript_projectile_anim(lua_State *L);
284 static int nscript_projectile_anim_multi(lua_State *L);
285 static int nscript_hit_anim(lua_State *L);
286 static int nscript_usecode_look(lua_State *L);
287 
288 static int nscript_fade_out(lua_State *L);
289 static int nscript_fade_in(lua_State *L);
290 static int nscript_fade_tile(lua_State *L);
291 static int nscript_black_fade_obj(lua_State *L);
292 
293 static int nscript_xor_effect(lua_State *L);
294 static int nscript_xray_effect(lua_State *L);
295 
296 static int nscript_peer_effect(lua_State *L);
297 static int nscript_wing_strike_effect(lua_State *L);
298 static int nscript_hail_storm_effect(lua_State *L);
299 static int nscript_wizard_eye_effect(lua_State *L);
300 
301 
302 static int nscript_play_end_sequence(lua_State *L);
303 
304 static int nscript_play_sfx(lua_State *L);
305 static int nscript_is_god_mode_enabled(lua_State *L);
306 static int nscript_set_armageddon(lua_State *L);
307 
308 static int nscript_mouse_cursor_show(lua_State *L);
309 static int nscript_mouse_cursor_set_pointer(lua_State *L);
310 
311 static int nscript_wait(lua_State *L);
312 
313 static int nscript_mapwindow_center_at_loc(lua_State *L);
314 static int nscript_mapwindow_get_loc(lua_State *L);
315 static int nscript_mapwindow_set_loc(lua_State *L);
316 static int nscript_mapwindow_set_enable_blacking(lua_State *L);
317 
318 static int nscript_load_text_from_lzc(lua_State *L);
319 
320 static int nscript_display_text_in_scroll_gump(lua_State *L);
321 
322 static int nscript_lock_inventory_view(lua_State *L);
323 static int nscript_unlock_inventory_view(lua_State *L);
324 
325 //Iterators
326 int nscript_u6llist_iter(lua_State *L);
327 int nscript_u6llist_iter_recursive(lua_State *L);
328 int nscript_party_iter(lua_State *L);
329 
330 static int nscript_party(lua_State *L);
331 static int nscript_container(lua_State *L);
332 int nscript_init_u6link_iter(lua_State *L, U6LList *list, bool is_recursive);
333 
334 static int nscript_find_obj(lua_State *L);
335 static int nscript_find_obj_from_area(lua_State *L);
336 
337 Script *Script::script = NULL;
338 
lua_error_handler(lua_State * L)339 static int lua_error_handler(lua_State *L) {
340 	//lua_getfield(L, LUA_GLOBALSINDEX, "debug");
341 	lua_getglobal(L, "debug");
342 	if (!lua_istable(L, -1)) {
343 		lua_pop(L, 1);
344 		return 1;
345 	}
346 	lua_getfield(L, -1, "traceback");
347 	if (!lua_isfunction(L, -1)) {
348 		lua_pop(L, 2);
349 		return 1;
350 	}
351 	lua_pushvalue(L, 1);
352 	lua_pushinteger(L, 2);
353 	lua_call(L, 2, 1);
354 	return 1;
355 }
356 
get_tbl_field_sint16(lua_State * L,const char * index,sint16 * field,int table_stack_offset=-2)357 static bool get_tbl_field_sint16(lua_State *L, const char *index, sint16 *field, int table_stack_offset = -2) {
358 	lua_pushstring(L, index);
359 	lua_gettable(L, table_stack_offset);
360 
361 	if (!lua_isnumber(L, -1))
362 		return false;
363 
364 	*field = (sint16)lua_tonumber(L, -1);
365 	lua_pop(L, 1);
366 	return true;
367 }
368 
get_tbl_field_as_wrapped_coord(lua_State * L,const char * index,uint16 * field,uint8 map_level,int table_stack_offset=-2)369 static bool get_tbl_field_as_wrapped_coord(lua_State *L, const char *index, uint16 *field, uint8 map_level, int table_stack_offset = -2) {
370 	sint16 coord;
371 	if (get_tbl_field_sint16(L, index, &coord, table_stack_offset) == false) {
372 		return false;
373 	}
374 
375 	*field = wrap_signed_coord(coord, map_level);
376 
377 	return true;
378 }
379 
get_tbl_field_uint16(lua_State * L,const char * index,uint16 * field,int table_stack_offset=-2)380 static bool get_tbl_field_uint16(lua_State *L, const char *index, uint16 *field, int table_stack_offset = -2) {
381 	lua_pushstring(L, index);
382 	lua_gettable(L, table_stack_offset);
383 
384 	if (!lua_isnumber(L, -1))
385 		return false;
386 
387 	*field = (uint16)lua_tonumber(L, -1);
388 	lua_pop(L, 1);
389 	return true;
390 }
391 
get_tbl_field_uint8(lua_State * L,const char * index,uint8 * field,int table_stack_offset=-2)392 static bool get_tbl_field_uint8(lua_State *L, const char *index, uint8 *field, int table_stack_offset = -2) {
393 	lua_pushstring(L, index);
394 	lua_gettable(L, table_stack_offset);
395 
396 	if (!lua_isnumber(L, -1))
397 		return false;
398 
399 	*field = (uint8)lua_tonumber(L, -1);
400 	lua_pop(L, 1);
401 	return true;
402 }
403 
get_tbl_field_string(lua_State * L,const char * index,char * field,uint16 max_len)404 static bool get_tbl_field_string(lua_State *L, const char *index, char *field, uint16 max_len) {
405 	lua_pushstring(L, index);
406 	lua_gettable(L, -2);
407 
408 	if (!lua_isstring(L, -1))
409 		return false;
410 
411 	size_t size;
412 	const char *string = lua_tolstring(L, -1, &size);
413 	if (size > max_len)
414 		size = max_len;
415 
416 	memcpy(field, string, size);
417 	field[size] = '\0';
418 
419 	lua_pop(L, 1);
420 	return true;
421 }
422 
resume_with_location(MapCoord loc)423 uint8 ScriptThread::resume_with_location(MapCoord loc) {
424 	lua_newtable(L);
425 	lua_pushstring(L, "x");
426 	lua_pushinteger(L, loc.x);
427 	lua_settable(L, -3);
428 
429 	lua_pushstring(L, "y");
430 	lua_pushinteger(L, loc.y);
431 	lua_settable(L, -3);
432 
433 	lua_pushstring(L, "z");
434 	lua_pushinteger(L, loc.z);
435 	lua_settable(L, -3);
436 
437 	return resume(1);
438 }
439 
resume_with_direction(uint8 dir)440 uint8 ScriptThread::resume_with_direction(uint8 dir) {
441 	lua_pushinteger(L, dir);
442 
443 	return resume(1);
444 }
445 
resume_with_spell_num(uint8 spell_num)446 uint8 ScriptThread::resume_with_spell_num(uint8 spell_num) {
447 	lua_pushinteger(L, spell_num);
448 
449 	return resume(1);
450 }
451 
resume_with_obj(Obj * obj)452 uint8 ScriptThread::resume_with_obj(Obj *obj) {
453 	if (obj) {
454 		nscript_new_obj_var(L, obj);
455 		return resume(1);
456 	}
457 
458 	return resume(0);
459 }
460 
resume_with_nil()461 uint8 ScriptThread::resume_with_nil() {
462 	return resume(0);
463 }
464 
resume(int narg)465 uint8 ScriptThread::resume(int narg) {
466 	const char *s;
467 	int ret = lua_resume(L, /*NULL,*/ narg);
468 
469 	state = NUVIE_SCRIPT_ERROR;
470 
471 	if (ret == 0) {
472 		lua_gc(L, LUA_GCCOLLECT, 0); //FIXME! How often should we collect the garbage?
473 		state = NUVIE_SCRIPT_FINISHED;
474 	} else if (ret == LUA_YIELD) {
475 		if (lua_gettop(L) >= 1) {
476 			s = lua_tostring(L, 1);
477 			if (s) {
478 				if (!strcmp(s, "target")) {
479 					state = NUVIE_SCRIPT_GET_TARGET;
480 				} else if (!strcmp(s, "dir")) {
481 					state = NUVIE_SCRIPT_GET_DIRECTION;
482 				} else if (!strcmp(s, "need_dir")) { // input_really_needs_directon()
483 					Game::get_game()->get_event()->do_not_show_target_cursor = true;
484 					state = NUVIE_SCRIPT_GET_DIRECTION;
485 				} else if (!strcmp(s, "spell")) {
486 					state = NUVIE_SCRIPT_GET_SPELL;
487 				} else if (!strcmp(s, "inv_obj")) {
488 					Actor *actor = nscript_get_actor_from_args(L, 2);
489 					data = actor->get_actor_num();
490 					state = NUVIE_SCRIPT_GET_INV_OBJ;
491 				} else if (!strcmp(s, "obj")) {
492 					state = NUVIE_SCRIPT_GET_OBJ;
493 				} else if (!strcmp(s, "player_obj")) {
494 					state = NUVIE_SCRIPT_GET_PLAYER_OBJ;
495 				} else if (!strcmp(s, "talk")) {
496 					Actor *actor = nscript_get_actor_from_args(L, 2);
497 					data = actor->get_actor_num();
498 					return NUVIE_SCRIPT_TALK_TO_ACTOR;
499 				} else if (!strcmp(s, "adv_game_time")) {
500 					if (lua_gettop(L) < 2)
501 						data = 0;
502 					data = lua_tointeger(L, 2);
503 					state = NUVIE_SCRIPT_ADVANCE_GAME_TIME;
504 				}
505 			}
506 		}
507 	}
508 
509 	if (state == NUVIE_SCRIPT_ERROR) {
510 		DEBUG(0, LEVEL_ERROR, "%s\n", lua_tostring(L, lua_gettop(L)));
511 	}
512 
513 	return state;
514 }
515 
516 
Script(Configuration * cfg,GUI * gui,SoundManager * sm,nuvie_game_t type)517 Script::Script(Configuration *cfg, GUI *gui, SoundManager *sm, nuvie_game_t type) {
518 	const char *path;
519 	size_t len;
520 	config = cfg;
521 	gametype = type;
522 	script = this;
523 	soundManager = sm;
524 
525 	script_obj_list = iAVLAllocTree(get_iAVLKey);
526 
527 	L = luaL_newstate();
528 	luaL_openlibs(L);
529 
530 	luaL_newmetatable(L, "nuvie.U6Link");
531 	luaL_register(L, NULL, nscript_u6linklib_m);
532 
533 	luaL_newmetatable(L, "nuvie.U6LinkRecursive");
534 	luaL_register(L, NULL, nscript_u6linkrecursivelib_m);
535 
536 	luaL_newmetatable(L, "nuvie.Obj");
537 	//lua_pushvalue(L, -1); //duplicate metatable
538 	//lua_setfield(L, -2, "__index"); // add __index to metatable
539 	luaL_register(L, NULL, nscript_objlib_m);
540 
541 	luaL_register(L, "Obj", nscript_objlib_f);
542 
543 	lua_pushcfunction(L, nscript_load);
544 	lua_setglobal(L, "nuvie_load");
545 
546 	lua_pushcfunction(L, nscript_config_get_boolean_value);
547 	lua_setglobal(L, "config_get_boolean_value");
548 
549 	lua_pushcfunction(L, nscript_config_get_game_type);
550 	lua_setglobal(L, "config_get_game_type");
551 
552 	lua_pushcfunction(L, nscript_config_get_language);
553 	lua_setglobal(L, "config_get_language");
554 
555 	nscript_init_actor(L);
556 	nscript_init_cutscene(L, cfg, gui, sm);
557 
558 	lua_pushcfunction(L, nscript_objlist_seek);
559 	lua_setglobal(L, "objlist_seek");
560 
561 	lua_pushcfunction(L, nscript_objlist_read1);
562 	lua_setglobal(L, "objlist_read1");
563 
564 	lua_pushcfunction(L, nscript_objlist_write1);
565 	lua_setglobal(L, "objlist_write1");
566 
567 	lua_pushcfunction(L, nscript_objlist_read2);
568 	lua_setglobal(L, "objlist_read2");
569 
570 	lua_pushcfunction(L, nscript_objlist_write2);
571 	lua_setglobal(L, "objlist_write2");
572 
573 	lua_pushcfunction(L, nscript_clear_scroll);
574 	lua_setglobal(L, "clear_scroll");
575 
576 	lua_pushcfunction(L, nscript_print);
577 	lua_setglobal(L, "print");
578 
579 	lua_pushcfunction(L, nscript_display_prompt);
580 	lua_setglobal(L, "display_prompt");
581 
582 	lua_pushcfunction(L, nscript_input_select);
583 	lua_setglobal(L, "input_select");
584 
585 	lua_pushcfunction(L, nscript_input_select_integer);
586 	lua_setglobal(L, "input_select_integer");
587 
588 	lua_pushcfunction(L, nscript_play_end_sequence);
589 	lua_setglobal(L, "play_end_sequence");
590 
591 	lua_pushcfunction(L, nscript_play_sfx);
592 	lua_setglobal(L, "play_sfx");
593 
594 	lua_pushcfunction(L, nscript_party);
595 	lua_setglobal(L, "party_members");
596 
597 	lua_pushcfunction(L, nscript_container);
598 	lua_setglobal(L, "container_objs");
599 
600 	lua_pushcfunction(L, nscript_find_obj);
601 	lua_setglobal(L, "find_obj");
602 
603 	lua_pushcfunction(L, nscript_find_obj_from_area);
604 	lua_setglobal(L, "find_obj_from_area");
605 
606 	lua_pushcfunction(L, nscript_timer_set);
607 	lua_setglobal(L, "timer_set");
608 
609 	lua_pushcfunction(L, nscript_timer_get);
610 	lua_setglobal(L, "timer_get");
611 
612 	lua_pushcfunction(L, nscript_timer_update_all);
613 	lua_setglobal(L, "timer_update_all");
614 
615 	lua_pushcfunction(L, nscript_clock_get_year);
616 	lua_setglobal(L, "clock_get_year");
617 
618 	lua_pushcfunction(L, nscript_clock_get_month);
619 	lua_setglobal(L, "clock_get_month");
620 
621 	lua_pushcfunction(L, nscript_clock_get_day);
622 	lua_setglobal(L, "clock_get_day");
623 
624 	lua_pushcfunction(L, nscript_clock_get_minute);
625 	lua_setglobal(L, "clock_get_minute");
626 
627 	lua_pushcfunction(L, nscript_clock_get_hour);
628 	lua_setglobal(L, "clock_get_hour");
629 
630 	lua_pushcfunction(L, nscript_clock_inc);
631 	lua_setglobal(L, "clock_inc");
632 
633 	lua_pushcfunction(L, nscript_wind_set);
634 	lua_setglobal(L, "wind_set_dir");
635 
636 	lua_pushcfunction(L, nscript_wind_get);
637 	lua_setglobal(L, "wind_get_dir");
638 
639 	lua_pushcfunction(L, nscript_tile_get_flag);
640 	lua_setglobal(L, "tile_get_flag");
641 
642 	lua_pushcfunction(L, nscript_tile_get_description);
643 	lua_setglobal(L, "tile_get_description");
644 
645 	lua_pushcfunction(L, nscript_anim_get_number_of_entries);
646 	lua_setglobal(L, "anim_get_number_of_entries");
647 
648 	lua_pushcfunction(L, nscript_anim_get_tile);
649 	lua_setglobal(L, "anim_get_tile");
650 
651 	lua_pushcfunction(L, nscript_anim_set_first_frame);
652 	lua_setglobal(L, "anim_set_first_frame");
653 
654 	lua_pushcfunction(L, nscript_anim_get_first_frame);
655 	lua_setglobal(L, "anim_get_first_frame");
656 
657 	lua_pushcfunction(L, nscript_anim_play);
658 	lua_setglobal(L, "anim_play");
659 
660 	lua_pushcfunction(L, nscript_anim_stop);
661 	lua_setglobal(L, "anim_stop");
662 
663 	lua_pushcfunction(L, nscript_objs_at_loc);
664 	lua_setglobal(L, "objs_at_loc");
665 
666 	lua_pushcfunction(L, nscript_find_volcano_obj_near_player);
667 	lua_setglobal(L, "find_volcano_near_player");
668 
669 	lua_pushcfunction(L, nscript_map_get_obj);
670 	lua_setglobal(L, "map_get_obj");
671 
672 	lua_pushcfunction(L, nscript_map_remove_obj);
673 	lua_setglobal(L, "map_remove_obj");
674 
675 	lua_pushcfunction(L, nscript_map_is_water);
676 	lua_setglobal(L, "map_is_water");
677 
678 	lua_pushcfunction(L, nscript_map_is_on_screen);
679 	lua_setglobal(L, "map_is_on_screen");
680 
681 	lua_pushcfunction(L, nscript_map_get_impedence);
682 	lua_setglobal(L, "map_get_impedence");
683 
684 	lua_pushcfunction(L, nscript_map_get_tile_num);
685 	lua_setglobal(L, "map_get_tile_num");
686 
687 	lua_pushcfunction(L, nscript_map_get_dmg_tile_num);
688 	lua_setglobal(L, "map_get_dmg_tile_num");
689 
690 	lua_pushcfunction(L, nscript_map_can_put_actor);
691 	lua_setglobal(L, "map_can_put");
692 
693 	lua_pushcfunction(L, nscript_map_can_put_obj);
694 	lua_setglobal(L, "map_can_put_obj");
695 
696 	lua_pushcfunction(L, nscript_map_enable_temp_actor_cleaning);
697 	lua_setglobal(L, "map_enable_temp_actor_cleaning");
698 
699 	lua_pushcfunction(L, nscript_map_line_test);
700 	lua_setglobal(L, "map_can_reach_point");
701 
702 	lua_pushcfunction(L, nscript_map_line_hit_check);
703 	lua_setglobal(L, "map_line_hit_check");
704 
705 	lua_pushcfunction(L, nscript_map_export_tmx_files);
706 	lua_setglobal(L, "map_export_tmx_files");
707 
708 	lua_pushcfunction(L, nscript_tileset_export);
709 	lua_setglobal(L, "tileset_export");
710 
711 	lua_pushcfunction(L, nscript_game_get_ui_style);
712 	lua_setglobal(L, "game_get_ui_style");
713 
714 	lua_pushcfunction(L, nscript_player_get_name);
715 	lua_setglobal(L, "player_get_name");
716 
717 	lua_pushcfunction(L, nscript_player_get_gender);
718 	lua_setglobal(L, "player_get_gender");
719 
720 	lua_pushcfunction(L, nscript_player_get_location);
721 	lua_setglobal(L, "player_get_location");
722 
723 	lua_pushcfunction(L, nscript_player_get_karma);
724 	lua_setglobal(L, "player_get_karma");
725 
726 	lua_pushcfunction(L, nscript_player_set_karma);
727 	lua_setglobal(L, "player_set_karma");
728 
729 	lua_pushcfunction(L, nscript_player_dec_alcohol);
730 	lua_setglobal(L, "player_dec_alcohol");
731 
732 	lua_pushcfunction(L, nscript_player_move);
733 	lua_setglobal(L, "player_move");
734 
735 	lua_pushcfunction(L, nscript_player_set_actor);
736 	lua_setglobal(L, "player_set_actor");
737 
738 	lua_pushcfunction(L, nscript_player_is_in_solo_mode);
739 	lua_setglobal(L, "player_is_in_solo_mode");
740 
741 	lua_pushcfunction(L, nscript_party_get_size);
742 	lua_setglobal(L, "party_get_size");
743 
744 	lua_pushcfunction(L, nscript_party_get_member);
745 	lua_setglobal(L, "party_get_member");
746 
747 	lua_pushcfunction(L, nscript_party_is_in_combat_mode);
748 	lua_setglobal(L, "party_is_in_combat_mode");
749 
750 	lua_pushcfunction(L, nscript_party_set_combat_mode);
751 	lua_setglobal(L, "party_set_combat_mode");
752 
753 	lua_pushcfunction(L, nscript_party_set_party_mode);
754 	lua_setglobal(L, "party_set_party_mode");
755 
756 	lua_pushcfunction(L, nscript_party_move);
757 	lua_setglobal(L, "party_move");
758 
759 	lua_pushcfunction(L, nscript_party_use_entrance);
760 	lua_setglobal(L, "party_use_entrance");
761 
762 	lua_pushcfunction(L, nscript_party_update_leader);
763 	lua_setglobal(L, "party_update_leader");
764 
765 	lua_pushcfunction(L, nscript_party_resurrect_dead_members);
766 	lua_setglobal(L, "party_resurrect_dead_members");
767 
768 	lua_pushcfunction(L, nscript_party_exit_vehicle);
769 	lua_setglobal(L, "party_exit_vehicle");
770 
771 	lua_pushcfunction(L, nscript_party_set_in_vehicle);
772 	lua_setglobal(L, "party_set_in_vehicle");
773 
774 	lua_pushcfunction(L, nscript_party_dismount_from_horses);
775 	lua_setglobal(L, "party_dismount_from_horses");
776 
777 	lua_pushcfunction(L, nscript_party_show_all);
778 	lua_setglobal(L, "party_show_all");
779 
780 	lua_pushcfunction(L, nscript_party_hide_all);
781 	lua_setglobal(L, "party_hide_all");
782 
783 	lua_pushcfunction(L, nscript_quake_start);
784 	lua_setglobal(L, "quake_start");
785 
786 	lua_pushcfunction(L, nscript_explosion_start);
787 	lua_setglobal(L, "explosion_start");
788 
789 	lua_pushcfunction(L, nscript_projectile_anim);
790 	lua_setglobal(L, "projectile_anim");
791 
792 	lua_pushcfunction(L, nscript_projectile_anim_multi);
793 	lua_setglobal(L, "projectile_anim_multi");
794 
795 	lua_pushcfunction(L, nscript_hit_anim);
796 	lua_setglobal(L, "hit_anim");
797 
798 	lua_pushcfunction(L, nscript_usecode_look);
799 	lua_setglobal(L, "usecode_look");
800 
801 	lua_pushcfunction(L, nscript_fade_out);
802 	lua_setglobal(L, "fade_out");
803 
804 	lua_pushcfunction(L, nscript_fade_in);
805 	lua_setglobal(L, "fade_in");
806 
807 	lua_pushcfunction(L, nscript_fade_tile);
808 	lua_setglobal(L, "fade_tile");
809 
810 	lua_pushcfunction(L, nscript_black_fade_obj);
811 	lua_setglobal(L, "fade_obj");
812 
813 	lua_pushcfunction(L, nscript_xor_effect);
814 	lua_setglobal(L, "xor_effect");
815 
816 	lua_pushcfunction(L, nscript_xray_effect);
817 	lua_setglobal(L, "xray_effect");
818 
819 	lua_pushcfunction(L, nscript_peer_effect);
820 	lua_setglobal(L, "peer_effect");
821 
822 	lua_pushcfunction(L, nscript_wing_strike_effect);
823 	lua_setglobal(L, "wing_strike_effect");
824 
825 	lua_pushcfunction(L, nscript_hail_storm_effect);
826 	lua_setglobal(L, "hail_storm_effect");
827 
828 	lua_pushcfunction(L, nscript_wizard_eye_effect);
829 	lua_setglobal(L, "wizard_eye_effect");
830 
831 	lua_pushcfunction(L, nscript_is_god_mode_enabled);
832 	lua_setglobal(L, "is_god_mode_enabled");
833 
834 	lua_pushcfunction(L, nscript_set_armageddon);
835 	lua_setglobal(L, "set_armageddon");
836 
837 	lua_pushcfunction(L, nscript_mouse_cursor_show);
838 	lua_setglobal(L, "mouse_cursor_visible");
839 
840 	lua_pushcfunction(L, nscript_mouse_cursor_set_pointer);
841 	lua_setglobal(L, "mouse_cursor_set_pointer");
842 
843 	lua_pushcfunction(L, nscript_wait);
844 	lua_setglobal(L, "script_wait");
845 
846 	lua_pushcfunction(L, nscript_mapwindow_center_at_loc);
847 	lua_setglobal(L, "mapwindow_center_at_location");
848 
849 	lua_pushcfunction(L, nscript_mapwindow_get_loc);
850 	lua_setglobal(L, "mapwindow_get_location");
851 
852 	lua_pushcfunction(L, nscript_mapwindow_set_loc);
853 	lua_setglobal(L, "mapwindow_set_location");
854 
855 	lua_pushcfunction(L, nscript_mapwindow_set_enable_blacking);
856 	lua_setglobal(L, "mapwindow_set_enable_blacking");
857 
858 	lua_pushcfunction(L, nscript_load_text_from_lzc);
859 	lua_setglobal(L, "load_text_from_lzc");
860 
861 	lua_pushcfunction(L, nscript_display_text_in_scroll_gump);
862 	lua_setglobal(L, "display_text_in_scroll_gump");
863 
864 	lua_pushcfunction(L, nscript_lock_inventory_view);
865 	lua_setglobal(L, "lock_inventory_view");
866 
867 	lua_pushcfunction(L, nscript_unlock_inventory_view);
868 	lua_setglobal(L, "unlock_inventory_view");
869 
870 	seed_random();
871 
872 	lua_getglobal(L, "package");
873 	lua_pushstring(L, "path");
874 	lua_gettable(L, -2);
875 
876 	path = lua_tolstring(L, -1, &len);
877 	DEBUG(0, LEVEL_INFORMATIONAL, "lua path = %s\n", path);
878 
879 }
880 
~Script()881 Script::~Script() {
882 	if (L)
883 		lua_close(L);
884 }
885 
init()886 bool Script::init() {
887 	Std::string dir, path;
888 	config->value("config/datadir", dir, "");
889 	build_path(dir, "scripts", path);
890 	dir = path;
891 
892 	Std::string game_tag = get_game_tag(gametype);
893 	stringToLower(game_tag);
894 
895 	build_path(dir, game_tag, path);
896 
897 	dir = path;
898 	build_path(dir, "init.lua", path);
899 	ConsoleAddInfo("Loading init.lua");
900 
901 	Std::string init_str = "init = nuvie_load(\"";
902 	init_str.append(game_tag);
903 	init_str.append("/init.lua\"); init()");
904 
905 	if (run_script(init_str.c_str()) == false) {
906 		Std::string errorStr = "Loading ";
907 		errorStr.append(path);
908 		ConsoleAddError(errorStr);
909 		return false;
910 	}
911 
912 	return true;
913 }
914 
seed_random()915 void Script::seed_random() {
916 	//Seed the lua random number generator.
917 	//seed with a random number from NUVIE_RAND()
918 	//this should be seeded at this point.
919 
920 	//lua_getfield(L, LUA_GLOBALSINDEX, "math");
921 	lua_getglobal(L, "math");
922 	lua_getfield(L, -1, "randomseed");
923 	lua_remove(L, -2);
924 	lua_pushnumber(L, NUVIE_RAND());
925 	lua_pcall(L, 1, 0, 0);
926 
927 	return;
928 }
929 
run_script(const char * scriptStr)930 bool Script::run_script(const char *scriptStr) {
931 	if (luaL_dostring(L, scriptStr) != 0) {
932 		DEBUG(0, LEVEL_ERROR, "Script Error: %s\n", luaL_checkstring(L, -1));
933 		return false;
934 	}
935 
936 	return true;
937 }
938 
play_cutscene(const char * script_file)939 bool Script::play_cutscene(const char *script_file) {
940 	string script_file_path = "";
941 	config->value("config/GameID", script_file_path);
942 	script_file_path += script_file;
943 
944 	ConsoleHide();
945 
946 	return run_lua_file(script_file_path.c_str());
947 }
948 
call_player_before_move_action(sint16 * rel_x,sint16 * rel_y)949 MovementStatus Script::call_player_before_move_action(sint16 *rel_x, sint16 *rel_y) {
950 	lua_getglobal(L, "player_before_move_action");
951 	lua_pushinteger(L, *rel_x);
952 	lua_pushinteger(L, *rel_y);
953 
954 	if (call_function("player_before_move_action", 2, 3)) {
955 		if (!lua_isnil(L, -2)) {
956 			*rel_x = (sint16)lua_tointeger(L, -2);
957 		}
958 		if (!lua_isnil(L, -1)) {
959 			*rel_y = (sint16)lua_tointeger(L, -1);
960 		}
961 
962 		switch (lua_tointeger(L, -3)) {
963 		case 0 :
964 			return CAN_MOVE;
965 		case 1 :
966 			return BLOCKED;
967 		case 2 :
968 			return FORCE_MOVE;
969 		default :
970 			break;
971 		}
972 	}
973 	return CAN_MOVE;
974 }
975 
976 
call_player_post_move_action(bool didMove)977 bool Script::call_player_post_move_action(bool didMove) {
978 	lua_getglobal(L, "player_post_move_action");
979 	lua_pushboolean(L, didMove);
980 
981 	return call_function("player_post_move_action", 1, 0);
982 }
983 
call_player_pass()984 bool Script::call_player_pass() {
985 	lua_getglobal(L, "player_pass");
986 
987 	return call_function("player_pass", 0, 0);
988 }
989 
call_actor_update_all()990 bool Script::call_actor_update_all() {
991 	lua_getglobal(L, "actor_update_all");
992 
993 	return call_function("actor_update_all", 0, 0);
994 }
995 
call_actor_init(Actor * actor,uint8 alignment)996 bool Script::call_actor_init(Actor *actor, uint8 alignment) {
997 	lua_getglobal(L, "actor_init");
998 	nscript_new_actor_var(L, actor->get_actor_num());
999 	lua_pushinteger(L, alignment);
1000 
1001 	return call_function("actor_init", 2, 0);
1002 }
1003 
call_actor_attack(Actor * actor,MapCoord location,Obj * weapon,Actor * foe)1004 bool Script::call_actor_attack(Actor *actor, MapCoord location, Obj *weapon, Actor *foe) {
1005 	lua_getglobal(L, "actor_attack");
1006 	nscript_new_actor_var(L, actor->get_actor_num());
1007 	//nscript_new_actor_var(L, foe->get_actor_num());
1008 	uint8 num_arg = 6;
1009 	lua_pushnumber(L, (lua_Number)location.x);
1010 	lua_pushnumber(L, (lua_Number)location.y);
1011 	lua_pushnumber(L, (lua_Number)location.z);
1012 	if (weapon == NULL)
1013 		nscript_new_actor_var(L, actor->get_actor_num());
1014 	else
1015 		nscript_obj_new(L, weapon);
1016 	if (foe == NULL)
1017 		num_arg = 5;
1018 	else
1019 		nscript_new_actor_var(L, foe->get_actor_num());
1020 
1021 	if (call_function("actor_attack", num_arg, 0) == false) {
1022 		return false;
1023 	}
1024 
1025 	Game::get_game()->get_map_window()->updateBlacking(); // the script might have updated the blocking objects. eg broken a door.
1026 	return true;
1027 }
1028 
call_load_game(NuvieIO * objlist)1029 bool Script::call_load_game(NuvieIO *objlist) {
1030 	return call_loadsave_game("load_game", objlist);
1031 }
1032 
call_save_game(NuvieIO * objlist)1033 bool Script::call_save_game(NuvieIO *objlist) {
1034 	return call_loadsave_game("save_game", objlist);
1035 }
1036 
call_loadsave_game(const char * function,NuvieIO * objlist)1037 bool Script::call_loadsave_game(const char *function, NuvieIO *objlist) {
1038 	g_objlist_file = objlist;
1039 	lua_getglobal(L, function);
1040 
1041 	bool result = call_function(function, 0, 0);
1042 
1043 	g_objlist_file = NULL;
1044 	return result;
1045 }
1046 
call_actor_map_dmg(Actor * actor,MapCoord location)1047 bool Script::call_actor_map_dmg(Actor *actor, MapCoord location) {
1048 
1049 	lua_getglobal(L, "actor_map_dmg");
1050 	nscript_new_actor_var(L, actor->get_actor_num());
1051 	//nscript_new_actor_var(L, foe->get_actor_num());
1052 	lua_pushnumber(L, (lua_Number)location.x);
1053 	lua_pushnumber(L, (lua_Number)location.y);
1054 	lua_pushnumber(L, (lua_Number)location.z);
1055 
1056 	return call_function("actor_map_dmg", 4, 0);
1057 }
1058 
call_actor_tile_dmg(Actor * actor,uint16 tile_num)1059 bool Script::call_actor_tile_dmg(Actor *actor, uint16 tile_num) {
1060 
1061 	lua_getglobal(L, "actor_tile_dmg");
1062 	nscript_new_actor_var(L, actor->get_actor_num());
1063 	lua_pushnumber(L, (lua_Number)tile_num);
1064 
1065 
1066 	return call_function("actor_tile_dmg", 2, 0);
1067 }
1068 
call_actor_hit(Actor * actor,uint8 dmg,bool display_hit_msg)1069 bool Script::call_actor_hit(Actor *actor, uint8 dmg, bool display_hit_msg) {
1070 	lua_getglobal(L, "actor_hit");
1071 	nscript_new_actor_var(L, actor->get_actor_num());
1072 	lua_pushnumber(L, (lua_Number)dmg);
1073 
1074 	if (call_function("actor_hit", 2, 0) == false)
1075 		return false;
1076 
1077 	if (display_hit_msg) {
1078 		lua_getglobal(L, "actor_hit_msg");
1079 		nscript_new_actor_var(L, actor->get_actor_num());
1080 
1081 		return call_function("actor_hit_msg", 1, 0);
1082 	}
1083 
1084 	return true;
1085 }
1086 
call_look_obj(Obj * obj)1087 bool Script::call_look_obj(Obj *obj) {
1088 	lua_getglobal(L, "look_obj");
1089 
1090 	nscript_obj_new(L, obj);
1091 
1092 	if (call_function("look_obj", 1, 1) == false)
1093 		return false;
1094 
1095 	return lua_toboolean(L, -1);
1096 }
1097 
call_obj_get_readiable_location(Obj * obj)1098 int Script::call_obj_get_readiable_location(Obj *obj) {
1099 	lua_getglobal(L, "obj_get_readiable_location");
1100 
1101 	nscript_obj_new(L, obj);
1102 
1103 	if (call_function("obj_get_readiable_location", 1, 1) == false)
1104 		return -1;
1105 
1106 	return lua_tointeger(L, -1);
1107 }
1108 
actor_get_max_magic_points(Actor * actor)1109 uint8 Script::actor_get_max_magic_points(Actor *actor) {
1110 	lua_getglobal(L, "actor_get_max_magic_points");
1111 	nscript_new_actor_var(L, actor->get_actor_num());
1112 
1113 	if (call_function("actor_get_max_magic_points", 1, 1) == false)
1114 		return 0;
1115 	return (uint8)lua_tointeger(L, -1);
1116 }
1117 
call_actor_get_obj(Actor * actor,Obj * obj,Obj * container)1118 bool Script::call_actor_get_obj(Actor *actor, Obj *obj, Obj *container) {
1119 	int num_args = 2;
1120 	lua_getglobal(L, "actor_get_obj");
1121 	nscript_new_actor_var(L, actor->get_actor_num());
1122 	nscript_obj_new(L, obj);
1123 
1124 	if (container) {
1125 		nscript_obj_new(L, container);
1126 		num_args++;
1127 	}
1128 	if (call_function("actor_get_obj", num_args, 1) == false)
1129 		return false;
1130 
1131 	return lua_toboolean(L, -1);
1132 }
1133 
call_actor_subtract_movement_points(Actor * actor,uint8 points)1134 bool Script::call_actor_subtract_movement_points(Actor *actor, uint8 points) {
1135 	lua_getglobal(L, "subtract_movement_pts");
1136 	nscript_new_actor_var(L, actor->get_actor_num());
1137 	lua_pushnumber(L, (lua_Number)points);
1138 
1139 	if (call_function("subtract_movement_pts", 2, 0) == false)
1140 		return false;
1141 
1142 	return true;
1143 }
1144 
call_actor_resurrect(Actor * actor)1145 bool Script::call_actor_resurrect(Actor *actor) {
1146 	lua_getglobal(L, "actor_resurrect");
1147 	nscript_new_actor_var(L, actor->get_actor_num());
1148 
1149 	if (call_function("actor_resurrect", 1, 0) == false)
1150 		return false;
1151 
1152 	return true;
1153 }
1154 
call_actor_str_adj(Actor * actor)1155 uint8 Script::call_actor_str_adj(Actor *actor) {
1156 	lua_getglobal(L, "actor_str_adj");
1157 	nscript_new_actor_var(L, actor->get_actor_num());
1158 
1159 	if (call_function("actor_str_adj", 1, 1) == false)
1160 		return 0;
1161 	return (uint8)lua_tointeger(L, -1);
1162 }
1163 
call_actor_dex_adj(Actor * actor)1164 uint8 Script::call_actor_dex_adj(Actor *actor) {
1165 	lua_getglobal(L, "actor_dex_adj");
1166 	nscript_new_actor_var(L, actor->get_actor_num());
1167 
1168 	if (call_function("actor_dex_adj", 1, 1) == false)
1169 		return 0;
1170 	return (uint8)lua_tointeger(L, -1);
1171 }
1172 
call_actor_int_adj(Actor * actor)1173 uint8 Script::call_actor_int_adj(Actor *actor) {
1174 	lua_getglobal(L, "actor_int_adj");
1175 	nscript_new_actor_var(L, actor->get_actor_num());
1176 
1177 	if (call_function("actor_int_adj", 1, 1) == false)
1178 		return 0;
1179 	return (uint8)lua_tointeger(L, -1);
1180 }
1181 
call_use_keg(Obj * obj)1182 bool Script::call_use_keg(Obj *obj) {
1183 	lua_getglobal(L, "use_keg");
1184 
1185 	nscript_obj_new(L, obj);
1186 
1187 	if (call_function("use_keg", 1, 0) == false)
1188 		return false;
1189 
1190 	return true;
1191 }
1192 
call_has_usecode(Obj * obj,UseCodeEvent usecode_type)1193 bool Script::call_has_usecode(Obj *obj, UseCodeEvent usecode_type) {
1194 	lua_getglobal(L, "has_usecode");
1195 
1196 	nscript_obj_new(L, obj);
1197 	lua_pushnumber(L, (lua_Number)usecode_type);
1198 
1199 	if (call_function("has_usecode", 2, 1) == false)
1200 		return false;
1201 
1202 	return lua_toboolean(L, -1);
1203 }
1204 
call_use_obj(Obj * obj,Actor * actor)1205 ScriptThread *Script::call_use_obj(Obj *obj, Actor *actor) {
1206 	ScriptThread *t = NULL;
1207 	lua_State *s;
1208 
1209 	s = lua_newthread(L);
1210 
1211 	lua_getglobal(s, "use_obj");
1212 
1213 	nscript_obj_new(s, obj);
1214 	nscript_new_actor_var(s, actor->get_actor_num());
1215 
1216 	//FIXME wrap stacktrace dumping logic here as per call_function method.
1217 
1218 	t = new ScriptThread(s, 2);
1219 	//if(nscript_call_function(L, "use_obj", 2, 0, true) == false)
1220 	//  return false;
1221 
1222 	return t;
1223 }
1224 
call_ready_obj(Obj * obj,Actor * actor)1225 bool Script::call_ready_obj(Obj *obj, Actor *actor) {
1226 	lua_getglobal(L, "ready_obj");
1227 
1228 	nscript_obj_new(L, obj);
1229 	nscript_new_actor_var(L, actor->get_actor_num());
1230 
1231 	if (call_function("ready_obj", 2, 1) == false)
1232 		return false;
1233 
1234 	return lua_toboolean(L, -1);
1235 }
1236 
call_move_obj(Obj * obj,sint16 rel_x,sint16 rel_y)1237 bool Script::call_move_obj(Obj *obj, sint16 rel_x, sint16 rel_y) {
1238 	lua_getglobal(L, "move_obj");
1239 
1240 	nscript_obj_new(L, obj);
1241 	lua_pushnumber(L, (lua_Number)rel_x);
1242 	lua_pushnumber(L, (lua_Number)rel_y);
1243 
1244 	if (call_function("move_obj", 3, 1) == false)
1245 		return false;
1246 
1247 	return lua_toboolean(L, -1);
1248 }
1249 
call_handle_alt_code(uint16 altcode)1250 bool Script::call_handle_alt_code(uint16 altcode) {
1251 	lua_getglobal(L, "handle_alt_code");
1252 	lua_pushnumber(L, (lua_Number)altcode);
1253 
1254 	if (call_function("handle_alt_code", 1, 0) == false)
1255 		return false;
1256 
1257 	return true;
1258 }
1259 
call_magic_get_spell_list(Spell ** spell_list)1260 bool Script::call_magic_get_spell_list(Spell **spell_list) {
1261 	lua_getglobal(L, "magic_get_spell_list");
1262 
1263 	if (call_function("magic_get_spell_list", 0, 1) == false)
1264 		return false;
1265 
1266 	for (int i = 1;; i++) {
1267 		lua_pushinteger(L, i);
1268 		lua_gettable(L, -2);
1269 
1270 		if (!lua_istable(L, -1)) { //we've hit the end of our targets
1271 			::debug(1, "end = %d", i);
1272 			lua_pop(L, 1);
1273 			break;
1274 		}
1275 
1276 		uint16 num;
1277 		uint8 re;
1278 		char name[13];
1279 		char invocation[5];
1280 
1281 		get_tbl_field_uint16(L, "spell_num", &num);
1282 		get_tbl_field_uint8(L, "reagents", &re);
1283 		get_tbl_field_string(L, "name", name, 12);
1284 		get_tbl_field_string(L, "invocation", invocation, 4);
1285 
1286 		if (num < 256 && spell_list[num] == NULL) {
1287 			spell_list[num] = new Spell((uint8)num, (const char *)name, (const char *)invocation, re);
1288 			::debug(1, "num = %d, reagents = %d, name = %s invocation = %s\n", num, re, name, invocation);
1289 		}
1290 
1291 		lua_pop(L, 1);
1292 	}
1293 
1294 	return true;
1295 }
1296 
call_actor_use_effect(Obj * effect_obj,Actor * actor)1297 bool Script::call_actor_use_effect(Obj *effect_obj, Actor *actor) {
1298 	lua_getglobal(L, "actor_use_effect");
1299 	nscript_new_actor_var(L, actor->get_actor_num());
1300 	nscript_obj_new(L, effect_obj);
1301 
1302 	return call_function("actor_use_effect", 2, 0);
1303 }
1304 
call_can_get_obj_override(Obj * obj)1305 bool Script::call_can_get_obj_override(Obj *obj) {
1306 	lua_getglobal(L, "can_get_obj_override");
1307 	nscript_obj_new(L, obj);
1308 
1309 	if (call_function("can_get_obj_override", 1, 1) == false)
1310 		return false;
1311 
1312 	return lua_toboolean(L, -1);
1313 }
1314 
call_out_of_ammo(Actor * attacker,Obj * weapon,bool print_message)1315 bool Script::call_out_of_ammo(Actor *attacker, Obj *weapon, bool print_message) {
1316 	lua_getglobal(L, "out_of_ammo");
1317 	nscript_new_actor_var(L, attacker->get_actor_num());
1318 	if (weapon == NULL)
1319 		nscript_new_actor_var(L, attacker->get_actor_num());
1320 	else
1321 		nscript_obj_new(L, weapon);
1322 	lua_pushboolean(L, print_message);
1323 
1324 	if (call_function("out_of_ammo", 3, 1) == false)
1325 		return false;
1326 
1327 	return lua_toboolean(L, -1);
1328 }
1329 
call_is_avatar_dead()1330 bool Script::call_is_avatar_dead() {
1331 	lua_getglobal(L, "is_avatar_dead");
1332 	if (call_function("is_avatar_dead", 0, 1) == false)
1333 		return false;
1334 	return lua_toboolean(L, -1);
1335 }
1336 
call_is_ranged_select(UseCodeType operation)1337 bool Script::call_is_ranged_select(UseCodeType operation) {
1338 	lua_getglobal(L, "is_ranged_select");
1339 	lua_pushstring(L, useCodeTypeToString(operation));
1340 
1341 	if (call_function("is_ranged_select", 1, 1) == false)
1342 		return false;
1343 	return lua_toboolean(L, -1);
1344 }
1345 
call_function(const char * func_name,int num_args,int num_return,bool print_stacktrace)1346 bool Script::call_function(const char *func_name, int num_args, int num_return, bool print_stacktrace) {
1347 	int start_idx = lua_gettop(L);
1348 	int error_index = 0;
1349 
1350 	if (print_stacktrace) {
1351 		error_index = lua_gettop(L) - num_args;
1352 		lua_pushcfunction(L, lua_error_handler);
1353 		lua_insert(L, error_index);
1354 	}
1355 
1356 	int result = lua_pcall(L, num_args, num_return, error_index);
1357 	if (result != 0) {
1358 		DEBUG(0, LEVEL_ERROR, "Script Error: %s(), %s\n", func_name, luaL_checkstring(L, -1));
1359 		lua_pop(L, 1);
1360 	}
1361 
1362 	if (print_stacktrace) {
1363 		lua_remove(L, error_index);
1364 	}
1365 
1366 	if (lua_gettop(L) + num_args + 1 != start_idx + num_return)
1367 		DEBUG(0, LEVEL_ERROR, "lua stack error!");
1368 
1369 	return (result != 0) ? false : true;
1370 }
1371 
call_function_in_thread(const char * function_name)1372 ScriptThread *Script::call_function_in_thread(const char *function_name) {
1373 	ScriptThread *t = NULL;
1374 	lua_State *s;
1375 
1376 	s = lua_newthread(L);
1377 
1378 	lua_getglobal(s, function_name);
1379 
1380 	//FIXME wrap stacktrace dumping logic here as per call_function method.
1381 
1382 	t = new ScriptThread(s, 0);
1383 
1384 	return t;
1385 }
1386 
run_lua_file(const char * filename)1387 bool Script::run_lua_file(const char *filename) {
1388 	Std::string dir, path;
1389 	Script::get_script()->get_config()->value("config/datadir", dir, "");
1390 
1391 	build_path(dir, "scripts", path);
1392 	dir = path;
1393 	build_path(dir, filename, path);
1394 
1395 	if (luaL_loadfile(L, path.c_str()) != 0) {
1396 		DEBUG(0, LEVEL_ERROR, "loading script file %s", path.c_str());
1397 		return false;
1398 	}
1399 
1400 	return call_function(path.c_str(), 0, 0);
1401 }
1402 
call_moonstone_set_loc(uint8 phase,MapCoord location)1403 bool Script::call_moonstone_set_loc(uint8 phase, MapCoord location) {
1404 	lua_getglobal(L, "moonstone_set_loc");
1405 
1406 	lua_pushnumber(L, (lua_Number)phase);
1407 	lua_pushnumber(L, (lua_Number)location.x);
1408 	lua_pushnumber(L, (lua_Number)location.y);
1409 	lua_pushnumber(L, (lua_Number)location.z);
1410 
1411 	return call_function("moonstone_set_loc", 4, 0);
1412 }
1413 
call_moonstone_get_loc(uint8 phase)1414 MapCoord Script::call_moonstone_get_loc(uint8 phase) {
1415 	MapCoord loc(0, 0, 0);
1416 
1417 	lua_getglobal(L, "moonstone_get_loc");
1418 
1419 	lua_pushnumber(L, (lua_Number)phase);
1420 
1421 	if (call_function("moonstone_get_loc", 1, 1) == false)
1422 		return loc;
1423 
1424 	get_tbl_field_uint16(L, "x", &loc.x);
1425 	get_tbl_field_uint16(L, "y", &loc.y);
1426 	get_tbl_field_uint8(L, "z", &loc.z);
1427 
1428 	return loc;
1429 }
1430 
call_update_moongates(bool visible)1431 bool Script::call_update_moongates(bool visible) {
1432 	lua_getglobal(L, "update_moongates");
1433 
1434 	lua_pushboolean(L, visible);
1435 
1436 	return call_function("update_moongates", 1, 0);
1437 }
1438 
call_advance_time(uint16 minutes)1439 bool Script::call_advance_time(uint16 minutes) {
1440 	lua_getglobal(L, "advance_time");
1441 
1442 	lua_pushnumber(L, (lua_Number)minutes);
1443 
1444 	return call_function("advance_time", 1, 0);
1445 }
1446 
call_set_g_show_stealing(bool stealing)1447 bool Script::call_set_g_show_stealing(bool stealing) {
1448 	lua_getglobal(L, "set_g_show_stealing");
1449 	lua_pushboolean(L, stealing);
1450 
1451 	if (call_function("set_g_show_stealing", 1, 0) == false)
1452 		return false;
1453 	return true;
1454 }
1455 
call_get_combat_range(uint16 absx,uint16 absy)1456 uint8 Script::call_get_combat_range(uint16 absx, uint16 absy) {
1457 	lua_getglobal(L, "get_combat_range");
1458 	lua_pushnumber(L, (lua_Number)absx);
1459 	lua_pushnumber(L, (lua_Number)absy);
1460 	if (call_function("get_combat_range", 2, 1) == false)
1461 		return 9;
1462 	return (uint8)lua_tointeger(L, -1);
1463 }
1464 
call_get_weapon_range(uint16 obj_n)1465 uint8 Script::call_get_weapon_range(uint16 obj_n) {
1466 	lua_getglobal(L, "get_weapon_range");
1467 	lua_pushnumber(L, (lua_Number)obj_n);
1468 	if (call_function("get_weapon_range", 1, 1) == false)
1469 		return 1;
1470 	return (uint8)lua_tointeger(L, -1);
1471 }
1472 
call_play_midgame_sequence(uint16 seq_num)1473 uint8 Script::call_play_midgame_sequence(uint16 seq_num) {
1474 	lua_getglobal(L, "play_midgame_sequence");
1475 	lua_pushnumber(L, (lua_Number)seq_num);
1476 	if (call_function("play_midgame_sequence", 1, 1) == false)
1477 		return 1;
1478 	return (uint8)lua_tointeger(L, -1);
1479 }
1480 
call_talk_script(uint8 script_number)1481 bool Script::call_talk_script(uint8 script_number) {
1482 	lua_getglobal(L, "talk_script");
1483 	lua_pushnumber(L, (lua_Number)script_number);
1484 	if (call_function("talk_script", 1, 0) == false)
1485 		return false;
1486 	return true;
1487 }
1488 
call_talk_to_obj(Obj * obj)1489 bool Script::call_talk_to_obj(Obj *obj) {
1490 	lua_getglobal(L, "talk_to_obj");
1491 
1492 	nscript_obj_new(L, obj);
1493 
1494 	if (call_function("talk_to_obj", 1, 1) == false)
1495 		return false;
1496 
1497 	return (bool)lua_toboolean(L, -1);
1498 }
1499 
call_talk_to_actor(Actor * actor)1500 bool Script::call_talk_to_actor(Actor *actor) {
1501 	lua_getglobal(L, "talk_to_actor");
1502 
1503 	nscript_new_actor_var(L, actor->get_actor_num());
1504 
1505 	if (call_function("talk_to_actor", 1, 1) == false)
1506 		return false;
1507 
1508 	return (bool)lua_toboolean(L, -1);
1509 }
1510 
call_is_container_obj(uint16 obj_n)1511 bool Script::call_is_container_obj(uint16 obj_n) {
1512 	lua_getglobal(L, "is_container_obj");
1513 	lua_pushnumber(L, (lua_Number)obj_n);
1514 	call_function("is_container_object", 1, 1);
1515 	return (bool)lua_toboolean(L, -1);
1516 }
1517 
call_get_portrait_number(Actor * actor)1518 uint8 Script::call_get_portrait_number(Actor *actor) {
1519 	lua_getglobal(L, "get_portrait_number");
1520 	nscript_new_actor_var(L, actor->get_actor_num());
1521 	if (call_function("get_portrait_number", 1, 1) == false)
1522 		return 1;
1523 	return (uint8)lua_tointeger(L, -1);
1524 }
1525 
call_player_attack()1526 bool Script::call_player_attack() {
1527 	lua_getglobal(L, "player_attack");
1528 
1529 	return call_function("player_attack", 0, 0);
1530 }
1531 
call_get_tile_to_object_mapping(uint16 tile_n)1532 uint16 Script::call_get_tile_to_object_mapping(uint16 tile_n) {
1533 	lua_getglobal(L, "get_tile_to_object_mapping");
1534 	lua_pushnumber(L, (lua_Number)tile_n);
1535 	call_function("get_tile_to_object_mapping", 1, 1);
1536 
1537 	return ((uint)lua_tonumber(L, -1));
1538 }
1539 
call_is_tile_object(uint16 obj_n)1540 bool Script::call_is_tile_object(uint16 obj_n) {
1541 	lua_getglobal(L, "is_tile_object");
1542 	lua_pushnumber(L, (lua_Number)obj_n);
1543 	call_function("is_tile_object", 1, 1);
1544 	return (lua_toboolean(L, -1));
1545 }
1546 
new_thread(const char * scriptfile)1547 ScriptThread *Script::new_thread(const char *scriptfile) {
1548 	ScriptThread *t = NULL;
1549 	lua_State *s;
1550 
1551 	s = lua_newthread(L);
1552 	lua_getglobal(s, "run_script");
1553 	lua_pushstring(s, scriptfile);
1554 
1555 	t = new ScriptThread(s, 1);
1556 
1557 	return t;
1558 }
1559 
new_thread_from_string(const char * scriptStr)1560 ScriptThread *Script::new_thread_from_string(const char *scriptStr) {
1561 	ScriptThread *t = NULL;
1562 	lua_State *s;
1563 
1564 	s = lua_newthread(L);
1565 
1566 	if (luaL_loadbuffer(s, scriptStr, strlen(scriptStr), "nuvie") != 0)
1567 		return NULL;
1568 
1569 	t = new ScriptThread(s, 0);
1570 
1571 	return t;
1572 }
1573 
nscript_get_location_from_args(lua_State * L,uint16 * x,uint16 * y,uint8 * z,int lua_stack_offset)1574 bool nscript_get_location_from_args(lua_State *L, uint16 *x, uint16 *y, uint8 *z, int lua_stack_offset) {
1575 	if (lua_istable(L, lua_stack_offset)) {
1576 		if (!get_tbl_field_uint8(L, "z", z, lua_stack_offset)) return false;
1577 		if (!get_tbl_field_as_wrapped_coord(L, "x", x, *z, lua_stack_offset)) return false;
1578 		if (!get_tbl_field_as_wrapped_coord(L, "y", y, *z, lua_stack_offset)) return false;
1579 	} else {
1580 		if (lua_isnil(L, lua_stack_offset)) return false;
1581 		*z = (uint8)luaL_checkinteger(L,  lua_stack_offset + 2);
1582 		*x = wrap_signed_coord((sint16)luaL_checkinteger(L, lua_stack_offset), *z);
1583 		*y = wrap_signed_coord((sint16)luaL_checkinteger(L, lua_stack_offset + 1), *z);
1584 	}
1585 
1586 	return true;
1587 }
1588 
nscript_get_obj_from_args(lua_State * L,int lua_stack_offset)1589 Obj *nscript_get_obj_from_args(lua_State *L, int lua_stack_offset) {
1590 	Obj **s_obj = (Obj **)luaL_checkudata(L, lua_stack_offset, "nuvie.Obj");
1591 	if (s_obj == NULL)
1592 		return NULL;
1593 
1594 	return *s_obj;
1595 }
1596 
nscript_new_obj_var(lua_State * L,Obj * obj)1597 void nscript_new_obj_var(lua_State *L, Obj *obj) {
1598 	Obj **p_obj;
1599 	p_obj = (Obj **)lua_newuserdata(L, sizeof(Obj *));
1600 
1601 	luaL_getmetatable(L, "nuvie.Obj");
1602 	lua_setmetatable(L, -2);
1603 
1604 	*p_obj = obj;
1605 
1606 	nscript_inc_obj_ref_count(obj);
1607 }
1608 
1609 /***
1610 Create a new Obj.
1611 This function can clone and existing object or create a new object from one or more parameters.
1612 @function Obj.new
1613 @tparam[opt] Obj obj Object to clone
1614 @int[opt] obj_n Object number
1615 @int[opt] frame_n Frame number
1616 @int[opt] quality Quality
1617 @int[opt] qty Quantity
1618 @int[opt] x x map position
1619 @int[opt] y y map position
1620 @int[opt] z z map position
1621 @treturn Obj The newly created object
1622 @within Object
1623  */
nscript_obj_newobj(lua_State * L)1624 static int nscript_obj_newobj(lua_State *L) {
1625 	return nscript_obj_new(L, NULL);
1626 }
1627 
nscript_obj_new(lua_State * L,Obj * obj)1628 int nscript_obj_new(lua_State *L, Obj *obj) {
1629 	Obj **p_obj;
1630 
1631 	p_obj = (Obj **)lua_newuserdata(L, sizeof(Obj *));
1632 
1633 	luaL_getmetatable(L, "nuvie.Obj");
1634 	lua_setmetatable(L, -2);
1635 
1636 	if (obj == NULL) {
1637 		obj = new Obj();
1638 
1639 		if (lua_gettop(L) > 1) { // do we have arguments?
1640 			if (lua_isuserdata(L, 1)) { // do we have an obj
1641 				if (nscript_obj_init_from_obj(L, obj) == false)
1642 					return 0;
1643 			} else { // init object from arguments
1644 				if (nscript_obj_init_from_args(L, lua_gettop(L) - 1, obj) == false)
1645 					return 0;
1646 			}
1647 		}
1648 	}
1649 
1650 	*p_obj = obj;
1651 
1652 	nscript_inc_obj_ref_count(obj);
1653 
1654 	return 1;
1655 }
1656 
nscript_inc_obj_ref_count(Obj * obj)1657 sint32 nscript_inc_obj_ref_count(Obj *obj) {
1658 	ScriptObjRef *obj_ref;
1659 	iAVLKey key;
1660 	key._ptr = obj;
1661 
1662 	obj_ref = (ScriptObjRef *)iAVLSearch(script_obj_list, key);
1663 	if (obj_ref == NULL) {
1664 		obj->set_in_script(true); // mark as being used by script engine.
1665 		obj_ref =  new ScriptObjRef();
1666 		obj_ref->key._ptr = obj;
1667 		iAVLInsert(script_obj_list, obj_ref);
1668 	}
1669 
1670 	obj_ref->refcount++;
1671 
1672 	return (sint32)obj_ref->refcount;
1673 }
1674 
nscript_dec_obj_ref_count(Obj * obj)1675 sint32 nscript_dec_obj_ref_count(Obj *obj) {
1676 	ScriptObjRef *obj_ref;
1677 	iAVLKey key;
1678 	key._ptr = obj;
1679 
1680 	obj_ref = (ScriptObjRef *)iAVLSearch(script_obj_list, key);
1681 	if (obj_ref == NULL)
1682 		return -1;
1683 
1684 
1685 	obj_ref->refcount--;
1686 
1687 	if (obj_ref->refcount == 0) {
1688 		iAVLDelete(script_obj_list, key);
1689 		delete obj_ref;
1690 		obj->set_in_script(false); //nolonger being referenced by the script engine.
1691 		return 0;
1692 	}
1693 
1694 	return obj_ref->refcount;
1695 }
1696 
nscript_obj_init_from_obj(lua_State * L,Obj * s_obj)1697 inline bool nscript_obj_init_from_obj(lua_State *L, Obj *s_obj) {
1698 	Obj **tmp_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
1699 	if (tmp_obj == NULL)
1700 		return false;
1701 
1702 	Obj *ptr = *tmp_obj;
1703 	if (ptr == NULL)
1704 		return false;
1705 
1706 	s_obj->obj_n = ptr->obj_n;
1707 	s_obj->frame_n = ptr->frame_n;
1708 	s_obj->quality = ptr->quality;
1709 	s_obj->qty = ptr->qty;
1710 	s_obj->x = ptr->x;
1711 	s_obj->y = ptr->y;
1712 	s_obj->z = ptr->z;
1713 
1714 	return true;
1715 }
1716 
nscript_obj_init_from_args(lua_State * L,int nargs,Obj * s_obj)1717 inline bool nscript_obj_init_from_args(lua_State *L, int nargs, Obj *s_obj) {
1718 	uint8 i = nargs;
1719 
1720 	if (i) {
1721 		if (!lua_isnil(L, 1))
1722 			s_obj->obj_n = (uint16)lua_tointeger(L, 1);
1723 		i--;
1724 	}
1725 
1726 	if (i) {
1727 		if (!lua_isnil(L, 2))
1728 			s_obj->frame_n = (uint8)lua_tointeger(L, 2);
1729 		i--;
1730 	}
1731 
1732 	if (i) {
1733 		if (!lua_isnil(L, 3))
1734 			s_obj->quality = (uint8)lua_tointeger(L, 3);
1735 		i--;
1736 	}
1737 
1738 	if (i) {
1739 		if (!lua_isnil(L, 4))
1740 			s_obj->qty = (uint16)lua_tointeger(L, 4);
1741 		i--;
1742 	}
1743 
1744 	if (i) {
1745 		if (!lua_isnil(L, 5))
1746 			s_obj->x = (uint16)lua_tointeger(L, 5);
1747 		i--;
1748 	}
1749 
1750 	if (i) {
1751 		if (!lua_isnil(L, 6))
1752 			s_obj->y = (uint16)lua_tointeger(L, 6);
1753 		i--;
1754 	}
1755 
1756 	if (i) {
1757 		if (!lua_isnil(L, 7))
1758 			s_obj->z = (uint8)lua_tointeger(L, 7);
1759 		i--;
1760 	}
1761 
1762 	return true;
1763 }
1764 
nscript_obj_gc(lua_State * L)1765 static int nscript_obj_gc(lua_State *L) {
1766 	//DEBUG(0, LEVEL_INFORMATIONAL, "\nObj garbage Collection!\n");
1767 
1768 	Obj **p_obj = (Obj **)lua_touserdata(L, 1);
1769 	Obj *obj;
1770 
1771 	if (p_obj == NULL)
1772 		return false;
1773 
1774 	obj = *p_obj;
1775 
1776 	if (nscript_dec_obj_ref_count(obj) == 0) { // no longer referenced by the script engine
1777 		// remove object if it is not referenced by the game engine.
1778 		if (obj->get_engine_loc() == OBJ_LOC_NONE)
1779 			delete_obj(obj);
1780 	}
1781 
1782 	return 0;
1783 }
1784 
1785 /*
1786    static inline Obj *nscript_get_obj_ptr(ScriptObj *s_obj)
1787    {
1788    if(s_obj)
1789    {
1790 	if(s_obj->obj_ptr)
1791 	  return s_obj->obj_ptr;
1792 	else
1793 	  return &s_obj->script_obj;
1794    }
1795 
1796    return NULL;
1797    }
1798  */
1799 
nscript_update_obj_location_variables(Obj * obj,uint16 x,uint16 y,uint8 z)1800 static void nscript_update_obj_location_variables(Obj *obj, uint16 x, uint16 y, uint8 z) {
1801 	if (obj->is_on_map()) {
1802 		Game::get_game()->get_obj_manager()->move(obj, x, y, z);
1803 	} else {
1804 		obj->x = x;
1805 		obj->y = y;
1806 		obj->z = z;
1807 	}
1808 }
1809 
nscript_obj_set(lua_State * L)1810 static int nscript_obj_set(lua_State *L) {
1811 	Obj **s_obj;
1812 	Obj *obj;
1813 	//Obj *ptr;
1814 	const char *key;
1815 
1816 	s_obj = (Obj **)lua_touserdata(L, 1);
1817 	if (s_obj == NULL)
1818 		return 0;
1819 
1820 	obj = *s_obj;
1821 	if (obj == NULL)
1822 		return 0;
1823 
1824 	// ptr = nscript_get_obj_ptr(s_obj);
1825 
1826 	key = lua_tostring(L, 2);
1827 
1828 	if (!strcmp(key, "x")) {
1829 		nscript_update_obj_location_variables(obj, (uint16)lua_tointeger(L, 3), obj->y, obj->z);
1830 		return 0;
1831 	}
1832 
1833 	if (!strcmp(key, "y")) {
1834 		nscript_update_obj_location_variables(obj, obj->x, (uint16)lua_tointeger(L, 3), obj->z);
1835 		return 0;
1836 	}
1837 
1838 	if (!strcmp(key, "z")) {
1839 		nscript_update_obj_location_variables(obj, obj->x, obj->y, (uint8)lua_tointeger(L, 3));
1840 		return 0;
1841 	}
1842 
1843 	if (!strcmp(key, "obj_n")) {
1844 		obj->obj_n = (uint16)lua_tointeger(L, 3);
1845 		return 0;
1846 	}
1847 
1848 	if (!strcmp(key, "frame_n")) {
1849 		obj->frame_n = (uint8)lua_tointeger(L, 3);
1850 		return 0;
1851 	}
1852 
1853 	if (!strcmp(key, "quality")) {
1854 		obj->quality = (uint8)lua_tointeger(L, 3);
1855 		return 0;
1856 	}
1857 
1858 	if (!strcmp(key, "qty")) {
1859 		obj->qty = (uint8)lua_tointeger(L, 3);
1860 		return 0;
1861 	}
1862 
1863 	if (!strcmp(key, "status")) {
1864 		obj->status = (uint8)lua_tointeger(L, 3);
1865 		return 0;
1866 	}
1867 
1868 	if (!strcmp(key, "invisible")) {
1869 		obj->set_invisible((bool)lua_toboolean(L, 3));
1870 		return 0;
1871 	}
1872 
1873 	if (!strcmp(key, "ok_to_take")) {
1874 		obj->set_ok_to_take((bool)lua_toboolean(L, 3));
1875 		return 0;
1876 	}
1877 
1878 	if (!strcmp(key, "temporary")) {
1879 		obj->set_temporary((bool)lua_toboolean(L, 3));
1880 		return 0;
1881 	}
1882 
1883 	return 0;
1884 }
1885 
nscript_obj_get(lua_State * L)1886 static int nscript_obj_get(lua_State *L) {
1887 	Obj **s_obj;
1888 	Obj *obj;
1889 	const char *key;
1890 
1891 	s_obj = (Obj **)lua_touserdata(L, 1);
1892 	if (s_obj == NULL)
1893 		return 0;
1894 
1895 	obj = *s_obj;
1896 	if (obj == NULL)
1897 		return 0;
1898 
1899 	//ptr = nscript_get_obj_ptr(s_obj);
1900 
1901 	key = lua_tostring(L, 2);
1902 
1903 	if (!strcmp(key, "luatype")) {
1904 		lua_pushstring(L, "obj");
1905 		return 1;
1906 	}
1907 
1908 	if (!strcmp(key, "x")) {
1909 		lua_pushinteger(L, obj->x);
1910 		return 1;
1911 	}
1912 
1913 	if (!strcmp(key, "y")) {
1914 		lua_pushinteger(L, obj->y);
1915 		return 1;
1916 	}
1917 
1918 	if (!strcmp(key, "z")) {
1919 		lua_pushinteger(L, obj->z);
1920 		return 1;
1921 	}
1922 
1923 	if (!strcmp(key, "obj_n")) {
1924 		lua_pushinteger(L, obj->obj_n);
1925 		return 1;
1926 	}
1927 
1928 	if (!strcmp(key, "frame_n")) {
1929 		lua_pushinteger(L, obj->frame_n);
1930 		return 1;
1931 	}
1932 
1933 	if (!strcmp(key, "quality")) {
1934 		lua_pushinteger(L, obj->quality);
1935 		return 1;
1936 	}
1937 
1938 	if (!strcmp(key, "qty")) {
1939 		lua_pushinteger(L, obj->qty);
1940 		return 1;
1941 	}
1942 
1943 	if (!strcmp(key, "name")) {
1944 		ObjManager *obj_manager = Game::get_game()->get_obj_manager();
1945 		lua_pushstring(L, obj_manager->get_obj_name(obj->obj_n, obj->frame_n));
1946 		return 1;
1947 	}
1948 	/*
1949 	   if(!strcmp(key, "container"))
1950 	   {
1951 	       U6LList *obj_list = obj->container;
1952 	       if(obj_list == NULL)
1953 	          return 0;
1954 
1955 	       U6Link *link = obj_list->start();
1956 
1957 	       lua_pushcfunction(L, nscript_u6llist_iter);
1958 
1959 	       U6Link **p_link = (U6Link **)lua_newuserdata(L, sizeof(U6Link *));
1960 	       *p_link = link;
1961 
1962 	       luaL_getmetatable(L, "nuvie.U6Link");
1963 	       lua_setmetatable(L, -2);
1964 
1965 	       return 2;
1966 	   }
1967 	*/
1968 	if (!strcmp(key, "look_string")) {
1969 		ObjManager *obj_manager = Game::get_game()->get_obj_manager();
1970 		lua_pushstring(L, obj_manager->look_obj(obj, true));
1971 		return 1;
1972 	}
1973 
1974 	if (!strcmp(key, "on_map")) {
1975 		lua_pushboolean(L, (int)obj->is_on_map());
1976 		return 1;
1977 	}
1978 
1979 	if (!strcmp(key, "in_container")) {
1980 		lua_pushboolean(L, (int)obj->is_in_container());
1981 		return 1;
1982 	}
1983 
1984 	if (!strcmp(key, "readied")) {
1985 		lua_pushboolean(L, (int)obj->is_readied());
1986 		return 1;
1987 	}
1988 
1989 	if (!strcmp(key, "stackable")) {
1990 		ObjManager *obj_manager = Game::get_game()->get_obj_manager();
1991 		lua_pushboolean(L, (int)obj_manager->is_stackable(obj));
1992 		return 1;
1993 	}
1994 
1995 	if (!strcmp(key, "status")) {
1996 		lua_pushnumber(L, obj->status);
1997 		return 1;
1998 	}
1999 
2000 	if (!strcmp(key, "weight")) {
2001 		ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2002 		float weight = obj_manager->get_obj_weight(obj, OBJ_WEIGHT_INCLUDE_CONTAINER_ITEMS, OBJ_WEIGHT_DONT_SCALE);
2003 		weight = floorf(weight); //get rid of the tiny fraction
2004 		weight /= 10; //now scale.
2005 		lua_pushnumber(L, (lua_Number)weight);
2006 		return 1;
2007 	}
2008 
2009 	if (!strcmp(key, "tile_num")) {
2010 		ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2011 		Tile *tile = obj_manager->get_obj_tile(obj->obj_n, obj->frame_n);
2012 		lua_pushinteger(L, (int)tile->tile_num);
2013 		return 1;
2014 	}
2015 
2016 	if (!strcmp(key, "tile_num_original")) {
2017 		ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2018 		TileManager *tile_manager = Game::get_game()->get_tile_manager();
2019 		Tile *tile = tile_manager->get_original_tile(obj_manager->get_obj_tile_num(obj->obj_n) + obj->frame_n);
2020 		lua_pushinteger(L, (int)tile->tile_num);
2021 		return 1;
2022 	}
2023 
2024 
2025 	if (!strcmp(key, "getable")) {
2026 		ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2027 		lua_pushboolean(L, (int)obj_manager->can_get_obj(obj));
2028 		return 1;
2029 	}
2030 
2031 	if (!strcmp(key, "ok_to_take")) {
2032 		lua_pushboolean(L, (int)obj->is_ok_to_take());
2033 		return 1;
2034 	}
2035 
2036 	if (!strcmp(key, "parent")) {
2037 		Obj *parent_container = obj->get_container_obj();
2038 		if (parent_container) {
2039 			nscript_new_obj_var(L, parent_container);
2040 			return 1;
2041 		} else if (obj->is_in_inventory()) {
2042 			Actor *parent_actor = obj->get_actor_holding_obj();
2043 			if (parent_actor) {
2044 				nscript_new_actor_var(L, parent_actor->get_actor_num());
2045 				return 1;
2046 			}
2047 		}
2048 	}
2049 
2050 	if (!strcmp(key, "xyz")) {
2051 		lua_newtable(L);
2052 		lua_pushstring(L, "x");
2053 		lua_pushinteger(L, obj->x);
2054 		lua_settable(L, -3);
2055 
2056 		lua_pushstring(L, "y");
2057 		lua_pushinteger(L, obj->y);
2058 		lua_settable(L, -3);
2059 
2060 		lua_pushstring(L, "z");
2061 		lua_pushinteger(L, obj->z);
2062 		lua_settable(L, -3);
2063 
2064 		return 1;
2065 	}
2066 
2067 	if (!strcmp(key, "invisible")) {
2068 		lua_pushboolean(L, (int)obj->is_invisible());
2069 		return 1;
2070 	}
2071 
2072 	return 0;
2073 }
2074 
2075 /***
2076 Move an object to the map.
2077 @function Obj.moveToMap
2078 @tparam Obj obj Object to move
2079 @tparam[opt] MapCoord|x,y,z location Map location. If not supplied the location will be taken from the object's x,y and z variables
2080 @within Object
2081  */
nscript_obj_movetomap(lua_State * L)2082 static int nscript_obj_movetomap(lua_State *L) {
2083 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2084 
2085 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
2086 	Obj *obj;
2087 
2088 	obj = *s_obj;
2089 
2090 	MapCoord loc;
2091 	if (lua_gettop(L) >= 2) {
2092 		if (nscript_get_location_from_args(L, &loc.x, &loc.y, &loc.z, 2) == false)
2093 			return 0;
2094 	} else {
2095 		loc.x = obj->x;
2096 		loc.y = obj->y;
2097 		loc.z = obj->z;
2098 	}
2099 
2100 	if (obj) {
2101 		if (obj_manager->moveto_map(obj, loc) == false) {
2102 			//delete map_obj;
2103 			return luaL_error(L, "moving obj to map!");
2104 		}
2105 
2106 		//s_obj->obj_ptr = map_obj;
2107 	}
2108 
2109 	return 0;
2110 }
2111 
2112 /***
2113 Move an object into an Actor's inventory
2114 @function Obj.moveToInv
2115 @tparam Obj obj Object to move
2116 @int actor_num Actor number
2117 @within Object
2118  */
nscript_obj_movetoinv(lua_State * L)2119 static int nscript_obj_movetoinv(lua_State *L) {
2120 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2121 	ActorManager *actor_manager = Game::get_game()->get_actor_manager();
2122 	Actor *actor;
2123 
2124 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
2125 	Obj *obj;
2126 
2127 	obj = *s_obj;
2128 
2129 	if (lua_gettop(L) < 2)
2130 		return luaL_error(L, "You must supply an Actor # to Obj.moveToInv()");
2131 
2132 	actor = actor_manager->get_actor(lua_tointeger(L, 2));
2133 
2134 	if (actor == NULL)
2135 		return luaL_error(L, "Getting Actor (%d)", lua_tointeger(L, 2));
2136 
2137 	if (obj) {
2138 		if (obj_manager->moveto_inventory(obj, actor) == false) {
2139 			//delete inv_obj;
2140 			return luaL_error(L, "moving obj to actor inventory!");
2141 		}
2142 
2143 		//s_obj->obj_ptr = inv_obj;
2144 	}
2145 
2146 
2147 	return 0;
2148 }
2149 
2150 /***
2151 Move an object into a container
2152 @function Obj.moveToCont
2153 @tparam Obj obj Object to move
2154 @tparam Obj container Container object to move into
2155 @within Object
2156  */
nscript_obj_movetocont(lua_State * L)2157 static int nscript_obj_movetocont(lua_State *L) {
2158 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2159 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
2160 	Obj *obj;
2161 	Obj *container_obj;
2162 
2163 	obj = *s_obj;
2164 
2165 	if (obj == NULL)
2166 		return 0;
2167 
2168 	if (lua_gettop(L) < 2)
2169 		return luaL_error(L, "You must supply an Object to move into in Obj.moveToCont()");
2170 
2171 	s_obj = (Obj **)luaL_checkudata(L, 2, "nuvie.Obj");
2172 	container_obj = *s_obj;
2173 
2174 	if (container_obj) {
2175 		if (obj_manager->moveto_container(obj, container_obj) == false) {
2176 			return luaL_error(L, "moving obj into container!");
2177 		}
2178 	}
2179 
2180 	//pos = lua_tointeger(L, 2);
2181 
2182 	return 0;
2183 }
2184 
2185 /***
2186 Remove an object from its container.
2187 The object will be unlinked from the engine after this operation. It will be freed after it goes out of scope.
2188 @function Obj.removeFromCont
2189 @tparam Obj obj Object to move
2190 @within Object
2191  */
nscript_container_remove_obj(lua_State * L)2192 static int nscript_container_remove_obj(lua_State *L) {
2193 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
2194 	Obj *obj;
2195 	Obj *cont_obj;
2196 
2197 	obj = *s_obj;
2198 
2199 	if (obj == NULL)
2200 		return luaL_error(L, "getting obj!");
2201 
2202 	cont_obj = obj->get_container_obj();
2203 
2204 	if (cont_obj == NULL)
2205 		return luaL_error(L, "obj not in a container!");
2206 
2207 	if (cont_obj->remove(obj) == false)
2208 		return luaL_error(L, "removing obj from container!");
2209 
2210 	return 0;
2211 }
2212 
2213 /***
2214 Call the old C++ usecode logic for a given object. (U6)
2215 @function Obj.use
2216 @tparam Obj obj Object to use
2217 @within Object
2218  */
nscript_obj_use(lua_State * L)2219 static int nscript_obj_use(lua_State *L) {
2220 	UseCode *usecode = Game::get_game()->get_usecode();
2221 	Player *player = Game::get_game()->get_player();
2222 	Actor *actor = player->get_actor();
2223 
2224 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
2225 	Obj *obj;
2226 
2227 	obj = *s_obj;
2228 
2229 	if (obj) {
2230 		usecode->use_obj(obj, actor);
2231 	}
2232 
2233 
2234 	return 0;
2235 }
2236 
2237 /***
2238 Remove an object from the game engine.
2239 The object will be unlinked from the engine after this operation. It will be freed after it goes out of scope.
2240 @function Obj.removeFromEngine
2241 @tparam Obj obj Object to unlink
2242 @within Object
2243  */
nscript_obj_removefromengine(lua_State * L)2244 static int nscript_obj_removefromengine(lua_State *L) {
2245 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2246 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
2247 
2248 	Obj *obj;
2249 
2250 	obj = *s_obj;
2251 
2252 	if (obj) {
2253 		obj_manager->unlink_from_engine(obj);
2254 	}
2255 
2256 	return 0;
2257 }
2258 
2259 /* release last iter U6Link if required. */
nscript_u6link_gc(lua_State * L)2260 static int nscript_u6link_gc(lua_State *L) {
2261 	U6Link **s_link = (U6Link **)luaL_checkudata(L, 1, "nuvie.U6Link");
2262 	U6Link *link = *s_link;
2263 
2264 	if (link == NULL)
2265 		return 0;
2266 
2267 	releaseU6Link(link);
2268 
2269 	::debug(1, "U6Link garbage collector!!");
2270 	return 0;
2271 }
2272 
2273 /* free up resources for a recursive U6Link iterator. */
nscript_u6link_recursive_gc(lua_State * L)2274 static int nscript_u6link_recursive_gc(lua_State *L) {
2275 	Std::stack<U6Link *> **s_stack = (Std::stack<U6Link *> **)luaL_checkudata(L, 1, "nuvie.U6LinkRecursive");
2276 	Std::stack<U6Link *> *s = *s_stack;
2277 
2278 	if (s->empty() == false) {
2279 		for (; !s->empty(); s->pop()) {
2280 			U6Link *link = s->top();
2281 
2282 			if (link != NULL)
2283 				releaseU6Link(link);
2284 		}
2285 	}
2286 
2287 	delete s;
2288 
2289 	//printf("U6LinkResursive garbage collector!!\n");
2290 	return 0;
2291 }
2292 
2293 /***
2294    Clear the message scroll
2295    @function clear_scroll
2296  */
nscript_clear_scroll(lua_State * L)2297 static int nscript_clear_scroll(lua_State *L) {
2298 	MsgScroll *scroll = Game::get_game()->get_scroll();
2299 	if (scroll) {
2300 		scroll->clear_scroll();
2301 	}
2302 
2303 	return 0;
2304 }
2305 
2306 /***
2307    Print a string to the message scroll
2308    @function print
2309    @param string the string to print
2310 */
nscript_print(lua_State * L)2311 static int nscript_print(lua_State *L) {
2312 	MsgScroll *scroll = Game::get_game()->get_scroll();
2313 	const char *string = luaL_checkstring(L, 1);
2314 	if (scroll) {
2315 		scroll->display_string(string);
2316 	} else {
2317 		::debug(1, "%s", string);
2318 	}
2319 	return 0;
2320 }
2321 
2322 /***
2323    Print the prompt string to the message scroll
2324    @function display_prompt
2325    @param string the string to print
2326 */
nscript_display_prompt(lua_State * L)2327 static int nscript_display_prompt(lua_State *L) {
2328 	MsgScroll *scroll = Game::get_game()->get_scroll();
2329 
2330 	if (!scroll->can_display_prompt())
2331 		return 0;
2332 
2333 	bool newline = lua_toboolean(L, 1);
2334 	if (newline)
2335 		scroll->display_string("\n");
2336 	scroll->display_prompt();
2337 	return 0;
2338 }
2339 
2340 /***
2341    Load a lua script from the data/scripts/ directory
2342    @function nuvie_load
2343    @param path lua file relative to data/scripts directory
2344    @return contents of the lua file as a function block on success.
2345 		   A string is returned on compilation failure.
2346 		   nil is returned if the file cannot be opened
2347  */
nscript_load(lua_State * L)2348 static int nscript_load(lua_State *L) {
2349 	const char *file = luaL_checkstring(L, 1);
2350 	string dir;
2351 	string path;
2352 
2353 	Script::get_script()->get_config()->value("config/datadir", dir, "");
2354 
2355 	build_path(dir, "scripts", path);
2356 	dir = path;
2357 	build_path(dir, file, path);
2358 
2359 	if (luaL_loadfile(L, path.c_str()) == LUA_ERRFILE) {
2360 		lua_pop(L, 1);
2361 		return 0;
2362 	}
2363 
2364 	return 1;
2365 }
2366 
2367 /***
2368    Get a boolean value for a given key from the config file
2369    @function config_get_boolean_value
2370    @param config_key config key to be retrieved
2371    @return boolean config value
2372  */
nscript_config_get_boolean_value(lua_State * L)2373 static int nscript_config_get_boolean_value(lua_State *L) {
2374 	bool value;
2375 	const char *config_key = luaL_checkstring(L, 1);
2376 	Script::get_script()->get_config()->value(Std::string(config_key), value);
2377 
2378 	lua_pushboolean(L, value);
2379 	return 1;
2380 }
2381 
2382 /***
2383    Get the currently running game type
2384    @function config_get_game_type
2385    @return a two character string representing the current game type. "U6", "MD" or "SE"
2386  */
nscript_config_get_game_type(lua_State * L)2387 static int nscript_config_get_game_type(lua_State *L) {
2388 	lua_pushstring(L, get_game_tag(Game::get_game()->get_game_type()));
2389 	return 1;
2390 }
2391 
2392 /***
2393    Get the currently selected language
2394    @function config_get_language
2395    @return a two character string representing the currently selected language. "en" is the default if no language has been selected.
2396  */
nscript_config_get_language(lua_State * L)2397 static int nscript_config_get_language(lua_State *L) {
2398 	Std::string value;
2399 	Script::get_script()->get_config()->value(config_get_game_key(Script::get_script()->get_config()) + "/language", value, "en");
2400 	lua_pushstring(L, value.c_str());
2401 	return 1;
2402 }
2403 
2404 /***
2405    Seek to a given position in the objlist data
2406    @function objlist_seek
2407    @param position position to seek to in bytes relative to the start of the file
2408  */
nscript_objlist_seek(lua_State * L)2409 static int nscript_objlist_seek(lua_State *L) {
2410 	uint32 position = (uint32)lua_tointeger(L, 1);
2411 	if (g_objlist_file)
2412 		g_objlist_file->seek(position);
2413 
2414 	return 0;
2415 }
2416 
2417 /***
2418    Read a 1 byte integer number from the current position in the objlist data.
2419    The current position is incremented by 1 after the read.
2420    @function objlist_read1
2421    @return value
2422  */
nscript_objlist_read1(lua_State * L)2423 static int nscript_objlist_read1(lua_State *L) {
2424 	if (g_objlist_file) {
2425 		lua_pushinteger(L, g_objlist_file->read1());
2426 		return 1;
2427 	}
2428 
2429 	return 0;
2430 }
2431 
2432 /***
2433    Overwrite objlist data at the current position with a 1 byte unsigned number.
2434    The current position is incremented by 1 after the write.
2435    @function objlist_write1
2436    @param value number to write. This number will be cast to uint8
2437    @return true on success false on failure
2438 
2439  */
nscript_objlist_write1(lua_State * L)2440 static int nscript_objlist_write1(lua_State *L) {
2441 	bool ret = false;
2442 	uint8 value = (uint8)lua_tointeger(L, 1);
2443 	if (g_objlist_file) {
2444 		ret = g_objlist_file->write1(value);
2445 	}
2446 
2447 	lua_pushboolean(L, ret);
2448 	return 1;
2449 }
2450 
2451 /***
2452    Read a 2 byte integer number from the current position in the objlist data.
2453    The current position is incremented by 2 after the read.
2454    @function objlist_read2
2455    @return value
2456  */
nscript_objlist_read2(lua_State * L)2457 static int nscript_objlist_read2(lua_State *L) {
2458 	if (g_objlist_file) {
2459 		lua_pushinteger(L, g_objlist_file->read2());
2460 		return 1;
2461 	}
2462 
2463 	return 0;
2464 }
2465 
2466 /***
2467    Overwrite objlist data at the current position with a 2 byte unsigned number.
2468    The current position is incremented by 2 after the write.
2469    @function objlist_write2
2470    @param value number to write. This number will be cast to uint16
2471    @return true on success false on failure
2472 
2473  */
nscript_objlist_write2(lua_State * L)2474 static int nscript_objlist_write2(lua_State *L) {
2475 	bool ret = false;
2476 	uint16 value = (uint16)lua_tointeger(L, 1);
2477 	if (g_objlist_file) {
2478 		ret = g_objlist_file->write2(value);
2479 	}
2480 
2481 	lua_pushboolean(L, ret);
2482 	return 1;
2483 }
2484 
2485 /***
2486 Get the currently selected UI style
2487 @function game_get_ui_style
2488 @return The UI style
2489 
2490 -   0 = Original style
2491 -   1 = New style
2492 -   2 = Original+ cutoff map
2493 -   3 = Original+ full map
2494  */
nscript_game_get_ui_style(lua_State * L)2495 static int nscript_game_get_ui_style(lua_State *L) {
2496 	lua_pushinteger(L, Game::get_game()->get_game_style());
2497 	return 1;
2498 }
2499 
2500 /***
2501 Get the player name
2502 @function player_get_name
2503 @return string player name
2504 @within player
2505  */
nscript_player_get_name(lua_State * L)2506 static int nscript_player_get_name(lua_State *L) {
2507 	Player *player = Game::get_game()->get_player();
2508 	if (player) {
2509 		lua_pushstring(L, player->get_name());
2510 		return 1;
2511 	}
2512 
2513 	return 0;
2514 }
2515 
2516 /***
2517 Get the gender of the player
2518 @function player_get_gender
2519 @return
2520 
2521 - 0 = Male
2522 - 1 = Female
2523 @within player
2524  */
nscript_player_get_gender(lua_State * L)2525 static int nscript_player_get_gender(lua_State *L) {
2526 	uint8 gender = 0;
2527 	Player *player = Game::get_game()->get_player();
2528 	if (player) {
2529 		gender = player->get_gender();
2530 	}
2531 
2532 	lua_pushinteger(L, gender);
2533 	return 1;
2534 }
2535 
2536 /***
2537 Get the location of the player
2538 @function player_get_location
2539 @treturn MapCoord
2540 @within player
2541  */
nscript_player_get_location(lua_State * L)2542 static int nscript_player_get_location(lua_State *L) {
2543 	Player *player = Game::get_game()->get_player();
2544 
2545 	uint16 x, y;
2546 	uint8 z;
2547 
2548 	player->get_actor()->get_location(&x, &y, &z);
2549 
2550 	lua_newtable(L);
2551 	lua_pushstring(L, "x");
2552 	lua_pushinteger(L, x);
2553 	lua_settable(L, -3);
2554 
2555 	lua_pushstring(L, "y");
2556 	lua_pushinteger(L, y);
2557 	lua_settable(L, -3);
2558 
2559 	lua_pushstring(L, "z");
2560 	lua_pushinteger(L, z);
2561 	lua_settable(L, -3);
2562 
2563 	return 1;
2564 }
2565 
2566 /***
2567 Get the player's karma value (U6)
2568 @function player_get_karma
2569 @return karma value
2570 @within player
2571  */
nscript_player_get_karma(lua_State * L)2572 static int nscript_player_get_karma(lua_State *L) {
2573 	Player *player = Game::get_game()->get_player();
2574 	lua_pushinteger(L, player->get_karma());
2575 	return 1;
2576 }
2577 
2578 /***
2579 Set the karma value for the player (U6)
2580 @function player_set_karma
2581 @param value new karma value
2582 @within player
2583  */
nscript_player_set_karma(lua_State * L)2584 static int nscript_player_set_karma(lua_State *L) {
2585 	Player *player = Game::get_game()->get_player();
2586 	player->set_karma((uint8)lua_tointeger(L, 1));
2587 	return 0;
2588 }
2589 
2590 /***
2591 Decrement the player's alcohol counter (U6)
2592 
2593 If value is greater than the counter the the counter is left at zero.
2594 @function player_dec_alcohol
2595 @param value number to decrement counter by
2596 @within player
2597  */
nscript_player_dec_alcohol(lua_State * L)2598 static int nscript_player_dec_alcohol(lua_State *L) {
2599 	Player *player = Game::get_game()->get_player();
2600 	player->dec_alcohol((uint8)lua_tointeger(L, 1));
2601 	return 0;
2602 }
2603 
2604 /***
2605 Check to see if the party is currently in combat mode
2606 @function party_is_in_combat_mode
2607 @treturn boolean true if the party is in combat mode otherwise false
2608 @within party
2609  */
nscript_party_is_in_combat_mode(lua_State * L)2610 static int nscript_party_is_in_combat_mode(lua_State *L) {
2611 	Party *party = Game::get_game()->get_party();
2612 	lua_pushboolean(L, party->is_in_combat_mode());
2613 	return 1;
2614 }
2615 
2616 /***
2617 Toggle combat mode
2618 @function party_set_combat_mode
2619 @tparam boolean value
2620 @within party
2621  */
nscript_party_set_combat_mode(lua_State * L)2622 static int nscript_party_set_combat_mode(lua_State *L) {
2623 	Party *party = Game::get_game()->get_party();
2624 	party->set_in_combat_mode(lua_toboolean(L, 1));
2625 	return 0;
2626 }
2627 
2628 /***
2629 Set party mode. The first member in the party becomes the leader.
2630 @function party_set_party_mode
2631 @within party
2632  */
nscript_party_set_party_mode(lua_State * L)2633 static int nscript_party_set_party_mode(lua_State *L) {
2634 	Player *player = Game::get_game()->get_player();
2635 	player->set_party_mode(player->get_party()->get_actor(0));
2636 
2637 	return 0;
2638 }
2639 
2640 /***
2641 Move party to a given map location
2642 @function party_move
2643 @tparam MapCoord|x,y,z location map location to move party to.
2644 @within party
2645  */
nscript_party_move(lua_State * L)2646 static int nscript_party_move(lua_State *L) {
2647 	Party *party = Game::get_game()->get_party();
2648 	uint16 x, y;
2649 	uint8 z;
2650 
2651 	if (nscript_get_location_from_args(L, &x, &y, &z) == false)
2652 		return 0;
2653 
2654 	party->move(x, y, z);
2655 
2656 	return 0;
2657 }
2658 
2659 /***
2660 Walk party members to an entrance and teleport them to the exit on the other side.
2661 
2662 __Warning:__ This function uses an old timer based class. So it will execute synchronously on subsequent calls to the main update loop.
2663 
2664 __FIXME:__ This logic should probably be done in pure script with pathfinder helper functions. ;-)
2665 
2666 @function party_use_entrance
2667 @tparam x,y,z entrance entrance location
2668 @tparam MapCoord|x,y,z exit exit location
2669 @within party
2670  */
nscript_party_use_entrance(lua_State * L)2671 static int nscript_party_use_entrance(lua_State *L) {
2672 	Party *party = Game::get_game()->get_party();
2673 
2674 	MapCoord entrance;
2675 	MapCoord exit;
2676 
2677 	if (nscript_get_location_from_args(L, &entrance.x, &entrance.y, &entrance.z) == false)
2678 		return 0;
2679 	if (nscript_get_location_from_args(L, &exit.x, &exit.y, &exit.z, 4) == false)
2680 		return 0;
2681 
2682 	party->walk(&entrance, &exit);
2683 
2684 	return 0;
2685 }
2686 
2687 /***
2688 Move player to given map location
2689 @function player_move
2690 @tparam MapCoord|x,y,z location map location to move player to.
2691 @bool teleport spawn eggs if true
2692 @within player
2693  */
nscript_player_move(lua_State * L)2694 static int nscript_player_move(lua_State *L) {
2695 	Player *player = Game::get_game()->get_player();
2696 	uint16 x, y;
2697 	uint8 z;
2698 
2699 	if (nscript_get_location_from_args(L, &x, &y, &z) == false)
2700 		return 0;
2701 
2702 	player->move(x, y, z, lua_toboolean(L, 4));
2703 
2704 	return 0;
2705 }
2706 
2707 /***
2708 Make the given actor the player controlled actor.
2709 @function player_set_actor
2710 @tparam Actor actor
2711 @within player
2712  */
nscript_player_set_actor(lua_State * L)2713 static int nscript_player_set_actor(lua_State *L) {
2714 	Player *player = Game::get_game()->get_player();
2715 	Actor *actor = nscript_get_actor_from_args(L, 1);
2716 
2717 	if (actor && actor != player->get_actor())
2718 		player->update_player(actor);
2719 
2720 	return 0;
2721 }
2722 
2723 /***
2724 Check if the player is currently in solo mode
2725 @function player_is_in_solo_mode
2726 @treturn bool true if the player is in solo mode otherwise false
2727 @within player
2728  */
nscript_player_is_in_solo_mode(lua_State * L)2729 static int nscript_player_is_in_solo_mode(lua_State *L) {
2730 	Player *player = Game::get_game()->get_player();
2731 	lua_pushboolean(L, !player->in_party_mode());
2732 
2733 	return 1;
2734 }
2735 
2736 /***
2737 Returns the number of members in the party
2738 @function party_get_size
2739 @treturn int number of party members
2740 @within party
2741  */
nscript_party_get_size(lua_State * L)2742 static int nscript_party_get_size(lua_State *L) {
2743 	Party *party = Game::get_game()->get_party();
2744 	lua_pushinteger(L, party->get_party_size());
2745 	return 1;
2746 }
2747 
2748 /***
2749 Get the Actor object for a given party member
2750 @function party_get_member
2751 @int member_num index of party member to retrieve
2752 @treturn Actor|nil returns nil if actor cannot be found for given index
2753 @within party
2754  */
nscript_party_get_member(lua_State * L)2755 static int nscript_party_get_member(lua_State *L) {
2756 	Party *party = Game::get_game()->get_party();
2757 	uint8 member_num = (uint8)lua_tointeger(L, 1);
2758 
2759 	Actor *actor = party->get_actor(member_num);
2760 
2761 	if (actor == NULL)
2762 		return 0;
2763 
2764 	nscript_new_actor_var(L, actor->get_actor_num());
2765 	return 1;
2766 }
2767 
2768 /***
2769 Get the current party leader and update player
2770 @function party_update_leader
2771 @within party
2772  */
nscript_party_update_leader(lua_State * L)2773 static int nscript_party_update_leader(lua_State *L) {
2774 	Party *party = Game::get_game()->get_party();
2775 	Player *player = Game::get_game()->get_player();
2776 
2777 	Actor *leader = party->get_leader_actor();
2778 
2779 	if (leader) {
2780 		player->update_player(leader);
2781 	}
2782 
2783 	return 0;
2784 }
2785 
2786 /***
2787 Resurrect dead party members
2788 @function party_resurrect_dead_members
2789 @within party
2790  */
nscript_party_resurrect_dead_members(lua_State * L)2791 static int nscript_party_resurrect_dead_members(lua_State *L) {
2792 	Party *party = Game::get_game()->get_party();
2793 	party->resurrect_dead_members();
2794 
2795 	return 0;
2796 }
2797 
2798 /***
2799 Exit party members from vehicle
2800 @function party_exit_vehicle
2801 @tparam MapCoord|x,y,z location map location to move party to once they exit the vehicle
2802 @within party
2803  */
nscript_party_exit_vehicle(lua_State * L)2804 static int nscript_party_exit_vehicle(lua_State *L) {
2805 	Party *party = Game::get_game()->get_party();
2806 
2807 	uint16 x, y;
2808 	uint8 z;
2809 
2810 	if (nscript_get_location_from_args(L, &x, &y, &z) == false)
2811 		return 0;
2812 
2813 	party->exit_vehicle(x, y, z);
2814 
2815 	return 0;
2816 }
2817 
2818 /***
2819 Dismount all party members from their horses (U6)
2820 @function party_dismount_from_horses
2821 @within party
2822  */
nscript_party_dismount_from_horses(lua_State * L)2823 static int nscript_party_dismount_from_horses(lua_State *L) {
2824 	Party *party = Game::get_game()->get_party();
2825 	party->dismount_from_horses();
2826 	return 0;
2827 }
2828 
2829 /***
2830 Toggle party vehicle mode
2831 @function party_set_in_vehicle
2832 @bool value
2833 @within party
2834  */
nscript_party_set_in_vehicle(lua_State * L)2835 static int nscript_party_set_in_vehicle(lua_State *L) {
2836 	Party *party = Game::get_game()->get_party();
2837 	party->set_in_vehicle((bool) lua_toboolean(L, 1));
2838 	return 0;
2839 }
2840 
2841 /***
2842 Show all party members on the map.
2843 @function party_show_all
2844 @within party
2845  */
nscript_party_show_all(lua_State * L)2846 static int nscript_party_show_all(lua_State *L) {
2847 	Party *party = Game::get_game()->get_party();
2848 	party->show();
2849 	return 0;
2850 }
2851 
2852 /***
2853 Hide all party members on the map.
2854 @function party_hide_all
2855 @within party
2856  */
nscript_party_hide_all(lua_State * L)2857 static int nscript_party_hide_all(lua_State *L) {
2858 	Party *party = Game::get_game()->get_party();
2859 	party->hide();
2860 	return 0;
2861 }
2862 
2863 /***
2864 Get an object from the map
2865 @function map_get_obj
2866 @tparam MapCoord|x,y,z location
2867 @param[opt] obj_n object number
2868 @bool[opt=false] inc_multi_tile_objs Should this search also include surrounding multi-tile objects that cover this location?
2869 @treturn Obj|nil
2870 @within map
2871  */
nscript_map_get_obj(lua_State * L)2872 static int nscript_map_get_obj(lua_State *L) {
2873 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2874 	Obj *obj;
2875 
2876 	uint16 x, y;
2877 	uint8 z;
2878 
2879 	if (nscript_get_location_from_args(L, &x, &y, &z) == false)
2880 		return 0;
2881 
2882 	int top = lua_gettop(L);
2883 	bool loc_is_table = lua_istable(L, 1);
2884 	int stack_offset = loc_is_table ? 2 : 4;
2885 
2886 	if ((loc_is_table && top > 1) || top > 3) {
2887 		uint16 obj_n = lua_tointeger(L, stack_offset);
2888 		bool include_multi_tile_objs = false;
2889 		if (lua_gettop(L) > stack_offset) {
2890 			include_multi_tile_objs = lua_toboolean(L, stack_offset + 1);
2891 		}
2892 		if (include_multi_tile_objs) {
2893 			obj = obj_manager->get_obj_of_type_from_location_inc_multi_tile(obj_n, x, y, z);
2894 		} else {
2895 			obj = obj_manager->get_obj_of_type_from_location(obj_n, x, y, z);
2896 		}
2897 	} else {
2898 		obj = obj_manager->get_obj(x, y, z);
2899 	}
2900 
2901 	if (obj) {
2902 		nscript_new_obj_var(L, obj);
2903 		return 1;
2904 	}
2905 
2906 	return 0;
2907 }
2908 
2909 /***
2910 Remove an object from the map.
2911 
2912 Once removed from the map the object has no engine location and will be cleaned up in the next GC
2913 @function map_remove_obj
2914 @tparam MapCoord|x,y,z location
2915 @param[opt] obj_n object number
2916 @treturn boolean success/failure
2917 @within map
2918  */
nscript_map_remove_obj(lua_State * L)2919 static int nscript_map_remove_obj(lua_State *L) {
2920 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
2921 
2922 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
2923 	Obj *obj;
2924 
2925 	obj = *s_obj;
2926 
2927 	if (obj_manager->remove_obj_from_map(obj))
2928 		lua_pushboolean(L, true);
2929 	else
2930 		lua_pushboolean(L, false);
2931 
2932 	return 1;
2933 }
2934 
2935 /***
2936 Can you put an actor at a given map location
2937 @function map_can_put
2938 @tparam MapCoord|x,y,z location
2939 @treturn boolean true if actor an be placed at location otherwise false
2940 @within map
2941  */
nscript_map_can_put_actor(lua_State * L)2942 static int nscript_map_can_put_actor(lua_State *L) {
2943 	ActorManager *actor_manager = Game::get_game()->get_actor_manager();
2944 	uint16 x, y;
2945 	uint8 z;
2946 
2947 	if (nscript_get_location_from_args(L, &x, &y, &z) == false)
2948 		return 0;
2949 
2950 	lua_pushboolean(L, actor_manager->can_put_actor(MapCoord(x, y, z)));
2951 
2952 	return 1;
2953 }
2954 
2955 /***
2956 Can you put an object at a given map location
2957 @function map_can_put_obj
2958 @tparam MapCoord|x,y,z location
2959 @treturn bool true if an object an be placed at location otherwise false
2960 @within map
2961  */
nscript_map_can_put_obj(lua_State * L)2962 static int nscript_map_can_put_obj(lua_State *L) {
2963 	Map *map = Game::get_game()->get_game_map();
2964 	uint16 x, y;
2965 	uint8 z;
2966 
2967 	if (nscript_get_location_from_args(L, &x, &y, &z, 1) == false)
2968 		return 0;
2969 
2970 	lua_pushboolean(L, map->can_put_obj(x, y, z));
2971 
2972 	return 1;
2973 }
2974 
2975 /***
2976 Toggle automatic cleaning of out of area temporary actors.
2977 @function map_enable_temp_actor_cleaning
2978 @tparam bool value
2979 @within map
2980  */
nscript_map_enable_temp_actor_cleaning(lua_State * L)2981 static int nscript_map_enable_temp_actor_cleaning(lua_State *L) {
2982 	ActorManager *actorManager = Game::get_game()->get_actor_manager();
2983 	actorManager->enable_temp_actor_cleaning((bool)lua_toboolean(L, 1));
2984 	return 0;
2985 }
2986 
2987 /***
2988 Check map location for water
2989 @function map_is_water
2990 @tparam MapCoord|x,y,z location
2991 @treturn bool true if the map at location is a water tile otherwise false
2992 @within map
2993  */
nscript_map_is_water(lua_State * L)2994 static int nscript_map_is_water(lua_State *L) {
2995 	Map *map = Game::get_game()->get_game_map();
2996 
2997 	uint16 x, y;
2998 	uint8 z;
2999 	if (nscript_get_location_from_args(L, &x, &y, &z, 1) == false)
3000 		return 0;
3001 
3002 	lua_pushboolean(L, map->is_water(x, y, z));
3003 
3004 	return 1;
3005 }
3006 
3007 /***
3008 Checks if the map location is currently on screen
3009 @function map_is_on_screen
3010 @tparam MapCoord|x,y,z location
3011 @treturn bool true if the map location is currently on screen otherwise false
3012 @within map
3013  */
nscript_map_is_on_screen(lua_State * L)3014 static int nscript_map_is_on_screen(lua_State *L) {
3015 	MapWindow *map_window = Game::get_game()->get_map_window();
3016 
3017 	uint16 x, y;
3018 	uint8 z;
3019 	if (nscript_get_location_from_args(L, &x, &y, &z, 1) == false)
3020 		return 0;
3021 
3022 	lua_pushboolean(L, map_window->is_on_screen(x, y, z));
3023 
3024 	return 1;
3025 }
3026 
3027 /***
3028 Get the impedance of a map location
3029 @function map_get_impedence
3030 @int x
3031 @int y
3032 @int z
3033 @bool[opt=true] ignore_objects Ignore objects while calculating impedance
3034 @treturn int impedance
3035 @fixme Rename this function to map_get_impedance()
3036 @within map
3037  */
nscript_map_get_impedence(lua_State * L)3038 static int nscript_map_get_impedence(lua_State *L) {
3039 	Map *map = Game::get_game()->get_game_map();
3040 
3041 	uint16 x, y;
3042 	uint8 z;
3043 	if (nscript_get_location_from_args(L, &x, &y, &z, 1) == false)
3044 		return 0;
3045 
3046 	bool ignore_objects = true;
3047 
3048 	if (lua_gettop(L) >= 4)
3049 		ignore_objects = (bool) lua_toboolean(L, 4);
3050 
3051 	lua_pushinteger(L, map->get_impedance(x, y, z, ignore_objects));
3052 
3053 	return 1;
3054 }
3055 
3056 /***
3057 get the map tile number for a given map location
3058 @function map_get_tile_num
3059 @tparam MapCoord|x,y,z location
3060 @bool[opt=false] get_original_tile_num return the original tile_num.
3061 @treturn int|nil
3062 @within map
3063  */
nscript_map_get_tile_num(lua_State * L)3064 static int nscript_map_get_tile_num(lua_State *L) {
3065 	bool original_tile = false;
3066 	Map *map = Game::get_game()->get_game_map();
3067 
3068 	uint16 x, y;
3069 	uint8 z;
3070 	if (nscript_get_location_from_args(L, &x, &y, &z, 1) == false)
3071 		return 0;
3072 
3073 	if (lua_istable(L, 1)) {
3074 		if (lua_gettop(L) >= 2)
3075 			original_tile = (bool) lua_toboolean(L, 2);
3076 	} else {
3077 		if (lua_gettop(L) >= 4)
3078 			original_tile = (bool) lua_toboolean(L, 4);
3079 	}
3080 
3081 	Tile *t = map->get_tile(x, y, z, original_tile);
3082 	if (t != NULL) {
3083 		lua_pushinteger(L, t->tile_num);
3084 		return 1;
3085 	}
3086 
3087 	return 0;
3088 }
3089 
3090 /***
3091 get the tile number for given location if the map tile can do damage.
3092 If the base map tile does not do damage then objects at the map location
3093 are also searched and the tile number of the first object that can damage the player
3094 is returned.
3095 @function map_get_dmg_tile_num
3096 @int x
3097 @int y
3098 @int z
3099 @treturn int|nil tile number of the damaging tile or nil if no damaging tiles are found at the location
3100 @within map
3101  */
nscript_map_get_dmg_tile_num(lua_State * L)3102 static int nscript_map_get_dmg_tile_num(lua_State *L) {
3103 	Map *map = Game::get_game()->get_game_map();
3104 
3105 	uint16 x, y;
3106 	uint8 z;
3107 	if (nscript_get_location_from_args(L, &x, &y, &z, 1) == false)
3108 		return 0;
3109 
3110 	Tile *t = map->get_dmg_tile(x, y, z);
3111 	if (t != NULL) {
3112 		lua_pushinteger(L, t->tile_num);
3113 		return 1;
3114 	}
3115 
3116 	return 0;
3117 }
3118 
3119 /***
3120 Returns true if a line between points x,y and x1, y1 does not cross any missile boundary tiles
3121 @function map_can_reach_point
3122 @int x
3123 @int y
3124 @int x1
3125 @int y1
3126 @int z
3127 @treturn bool
3128 @within map
3129  */
nscript_map_line_test(lua_State * L)3130 static int nscript_map_line_test(lua_State *L) {
3131 	Map *map = Game::get_game()->get_game_map();
3132 	LineTestResult result;
3133 	bool ret = false;
3134 
3135 	uint16 x = (uint16) luaL_checkinteger(L, 1);
3136 	uint16 y = (uint16) luaL_checkinteger(L, 2);
3137 
3138 	uint16 x1 = (uint16) luaL_checkinteger(L, 3);
3139 	uint16 y1 = (uint16) luaL_checkinteger(L, 4);
3140 	uint8 level = (uint8) luaL_checkinteger(L, 5);
3141 
3142 	//FIXME world wrapping for MD
3143 	if (map->lineTest(x, y, x1, y1, level, LT_HitMissileBoundary, result) == false)
3144 		ret = true;
3145 
3146 	lua_pushboolean(L, (int)ret);
3147 	return 1;
3148 }
3149 
3150 /***
3151 Returns the first point on a line between x,y and x1, y1 where a missile boundary tile is crossed
3152 If no boundary tiles are crossed on the line then x1, y1 are returned
3153 @function map_line_hit_check
3154 @int x
3155 @int y
3156 @int x1
3157 @int y1
3158 @int z
3159 @treturn int,int an x,y coord
3160 @within map
3161  */
nscript_map_line_hit_check(lua_State * L)3162 static int nscript_map_line_hit_check(lua_State *L) {
3163 	Map *map = Game::get_game()->get_game_map();
3164 	LineTestResult result;
3165 
3166 	uint16 x = (uint16) luaL_checkinteger(L, 1);
3167 	uint16 y = (uint16) luaL_checkinteger(L, 2);
3168 
3169 	uint16 x1 = (uint16) luaL_checkinteger(L, 3);
3170 	uint16 y1 = (uint16) luaL_checkinteger(L, 4);
3171 	uint8 level = (uint8) luaL_checkinteger(L, 5);
3172 
3173 	//FIXME world wrapping for MD
3174 	if (map->lineTest(x, y, x1, y1, level, LT_HitMissileBoundary, result)) {
3175 		lua_pushinteger(L, result.hit_x);
3176 		lua_pushinteger(L, result.hit_y);
3177 	} else {
3178 		lua_pushinteger(L, x1);
3179 		lua_pushinteger(L, y1);
3180 	}
3181 
3182 	return 2;
3183 }
3184 
3185 /***
3186 export map to Tiled TMX files. This creates 1 TMX file per map level. They are saved into the currently active save game directory.
3187 @function map_export_tmx_files
3188 @treturn bool returns true if the tmx files were created successfully. false on error
3189  */
nscript_map_export_tmx_files(lua_State * L)3190 static int nscript_map_export_tmx_files(lua_State *L) {
3191 	Game *game = Game::get_game();
3192 	TMXMap *tmxMap = new TMXMap(game->get_tile_manager(), game->get_game_map(), game->get_obj_manager());
3193 	lua_pushboolean(L, tmxMap->exportTmxMapFiles("data", game->get_game_type()));
3194 
3195 	delete tmxMap;
3196 	return 1;
3197 }
3198 
3199 /***
3200 export tileset to a bmp file 'data/images/tiles/nn/custom_tiles.bmp' in the current savegame directory.
3201 @function tileset_export
3202 @bool[opt=false] overWriteFile specifies if the output file should be overwritten if it already exists.
3203 @treturn bool returns true if the was written to disk. false otherwise
3204  */
nscript_tileset_export(lua_State * L)3205 static int nscript_tileset_export(lua_State *L) {
3206 	Game *game = Game::get_game();
3207 	bool overwriteFile = false;
3208 
3209 	if (lua_gettop(L) >= 1) {
3210 		overwriteFile = (bool)lua_toboolean(L, 1);
3211 	}
3212 
3213 	Std::string path;
3214 	path = "data";
3215 	build_path(path, "images", path);
3216 	build_path(path, "tiles", path);
3217 	build_path(path, get_game_tag(game->get_game_type()), path);
3218 
3219 	if (!directory_exists(path.c_str())) {
3220 		mkdir_recursive(path.c_str(), 0700);
3221 	}
3222 
3223 	build_path(path, "custom_tiles.bmp", path);
3224 
3225 	if (!overwriteFile && file_exists(path.c_str())) {
3226 		lua_pushboolean(L, false);
3227 	} else {
3228 		game->get_tile_manager()->exportTilesetToBmpFile(path, false);
3229 		lua_pushboolean(L, true);
3230 	}
3231 
3232 	return 1;
3233 }
3234 
3235 /***
3236 get a tile flag for a given tile number
3237 @function tile_get_flag
3238 @int tile_number
3239 @int flag_set either 1, 2 or 3
3240 @int bit_number bit number of flag from flag_set 0..7
3241 @treturn bool|nil return flag or nil on error
3242  */
nscript_tile_get_flag(lua_State * L)3243 static int nscript_tile_get_flag(lua_State *L) {
3244 	uint16 tile_num = (uint16) luaL_checkinteger(L, 1);
3245 	uint8 flag_set = (uint8) luaL_checkinteger(L, 2);
3246 	uint8 bit = (uint8) luaL_checkinteger(L, 3);
3247 
3248 	Tile *tile = Game::get_game()->get_tile_manager()->get_original_tile(tile_num);
3249 
3250 	if (tile == NULL || flag_set < 1 || flag_set > 3 || bit > 7)
3251 		return 0;
3252 
3253 	uint8 bit_flags = 0;
3254 
3255 	if (flag_set == 1) {
3256 		bit_flags = tile->flags1;
3257 	} else if (flag_set == 2) {
3258 		bit_flags = tile->flags2;
3259 	} else if (flag_set == 3) {
3260 		bit_flags = tile->flags3;
3261 	}
3262 
3263 	lua_pushboolean(L, (bool)(bit_flags & (1 << bit)));
3264 	return 1;
3265 }
3266 
3267 /***
3268 get the description for a given tile number
3269 @function tile_get_description
3270 @int tile_number
3271 @treturn string the descriptive string for the given tile number.
3272  */
nscript_tile_get_description(lua_State * L)3273 static int nscript_tile_get_description(lua_State *L) {
3274 	uint16 tile_num = (uint16) luaL_checkinteger(L, 1);
3275 	lua_pushstring(L, Game::get_game()->get_tile_manager()->lookAtTile(tile_num, 1, false));
3276 	return 1;
3277 }
3278 
3279 /***
3280 get the number of tile animations
3281 @function anim_get_number_of_entries
3282 @treturn int number of animations
3283 */
nscript_anim_get_number_of_entries(lua_State * L)3284 static int nscript_anim_get_number_of_entries(lua_State *L) {
3285 	lua_pushinteger(L, Game::get_game()->get_tile_manager()->get_number_of_animations());
3286 	return 1;
3287 }
3288 
3289 /***
3290 get the tile number for a given animation number
3291 @function anim_get_tile
3292 @int anim_index index of animation
3293 @treturn int tile number
3294 */
nscript_anim_get_tile(lua_State * L)3295 static int nscript_anim_get_tile(lua_State *L) {
3296 	uint16 anim_index = (uint16) luaL_checkinteger(L, 1);
3297 
3298 	lua_pushinteger(L, Game::get_game()->get_tile_manager()->get_anim_tile(anim_index));
3299 	return 1;
3300 }
3301 
3302 /***
3303 set the starting animation frame for a given animation number
3304 @function anim_set_first_frame
3305 @int anim_index index of animation loop to change
3306 @int anim_start_tile the tile number of the start animation
3307 */
nscript_anim_set_first_frame(lua_State * L)3308 static int nscript_anim_set_first_frame(lua_State *L) {
3309 	uint16 anim_index = (uint16) luaL_checkinteger(L, 1);
3310 	uint16 anim_start_tile = (uint16) luaL_checkinteger(L, 2);
3311 
3312 	Game::get_game()->get_tile_manager()->set_anim_first_frame(anim_index, anim_start_tile);
3313 	return 0;
3314 }
3315 
3316 /***
3317 get the starting animation frame for a given animation number
3318 @function anim_get_first_frame
3319 @int anim_index index of animation
3320 @treturn int tile number of first animation frame
3321 */
nscript_anim_get_first_frame(lua_State * L)3322 static int nscript_anim_get_first_frame(lua_State *L) {
3323 	uint16 anim_index = (uint16) luaL_checkinteger(L, 1);
3324 
3325 	lua_pushinteger(L, Game::get_game()->get_tile_manager()->get_anim_first_frame(anim_index));
3326 	return 1;
3327 }
3328 
3329 /***
3330 start playing animation
3331 @function anim_play
3332 @int anim_index index of animation to play
3333 */
nscript_anim_play(lua_State * L)3334 static int nscript_anim_play(lua_State *L) {
3335 	uint8 anim_index = (uint8) luaL_checkinteger(L, 1);
3336 	Game::get_game()->get_tile_manager()->anim_play_repeated(anim_index);
3337 	return 0;
3338 }
3339 
3340 /***
3341 stop playing animation
3342 @function anim_stop
3343 @int anim_index index of animation
3344 */
nscript_anim_stop(lua_State * L)3345 static int nscript_anim_stop(lua_State *L) {
3346 	uint8 anim_index = (uint8) luaL_checkinteger(L, 1);
3347 	Game::get_game()->get_tile_manager()->anim_stop_playing(anim_index);
3348 	return 0;
3349 }
3350 
3351 /***
3352 start earthquake effect. This shakes the mapwindow and makes a sound.
3353 @function quake_start
3354 @int magnitude quake strength
3355 @int duration duration of effect in milliseconds
3356 @treturn bool always returns true
3357 @within effects
3358  */
nscript_quake_start(lua_State * L)3359 static int nscript_quake_start(lua_State *L) {
3360 	Player *player = Game::get_game()->get_player();
3361 
3362 	uint8 magnitude = (uint8)luaL_checkinteger(L, 1);
3363 	uint32 duration = (uint32)luaL_checkinteger(L, 2);
3364 
3365 	new QuakeEffect(magnitude, duration, player->get_actor());
3366 
3367 	lua_pushboolean(L, true);
3368 	return 1;
3369 }
3370 
nscript_new_hit_entities_tbl_var(lua_State * L,ProjectileEffect * effect)3371 static int nscript_new_hit_entities_tbl_var(lua_State *L, ProjectileEffect *effect) {
3372 	vector<MapEntity> *hit_items = effect->get_hit_entities();
3373 
3374 	lua_newtable(L);
3375 
3376 	for (uint16 i = 0; i < hit_items->size(); i++) {
3377 		lua_pushinteger(L, i);
3378 
3379 		MapEntity m = (*hit_items)[i];
3380 		if (m.entity_type == ENT_OBJ)
3381 			nscript_obj_new(L, m.obj);
3382 		else if (m.entity_type == ENT_ACTOR) {
3383 			nscript_new_actor_var(L, m.actor->get_actor_num());
3384 		}
3385 
3386 		lua_settable(L, -3);
3387 	}
3388 
3389 	return 1;
3390 }
3391 
3392 /***
3393 Create an explosion at x,y on the current level. This function returns an iterator function
3394 to iterate through a list of Actors and Objects that were hit by the explosion.
3395 @function explosion_start
3396 @int tile_number
3397 @int x
3398 @int y
3399 @treturn table A table containing the hit Actor and Obj objects.
3400 @usage
3401 	local hit_items = explosion_start(0x17e, actor.x, actor.y)
3402 
3403 	for k,v in pairs(hit_items) do
3404 	  if v.luatype == "actor" then
3405 		actor_hit(v, random(1, 0x14))
3406 	  end
3407 	end
3408 @within effects
3409  */
nscript_explosion_start(lua_State * L)3410 static int nscript_explosion_start(lua_State *L) {
3411 	uint16 tile_num = (uint16)luaL_checkinteger(L, 1);
3412 	uint16 x = (uint16)luaL_checkinteger(L, 2);
3413 	uint16 y = (uint16)luaL_checkinteger(L, 3);
3414 
3415 	ExpEffect *effect = new ExpEffect(tile_num, MapCoord(x, y));
3416 	AsyncEffect *e = new AsyncEffect(effect);
3417 	e->run();
3418 
3419 	return nscript_new_hit_entities_tbl_var(L, (ProjectileEffect *)effect);
3420 }
3421 
3422 /***
3423 Creates a single tile projectile effect. This travels in a straight line from (startx,starty) to (targetx,targety)
3424 the tile can leave a trail and rotate whilst moving.
3425 @function projectile_anim
3426 @int startx
3427 @int starty
3428 @int targetx
3429 @int targety
3430 @int speed how far the tile travels each update. The tile will move speed * 2 pixels along the line each iteration
3431 @bool trail if true a copy of the tile will be left at intervals along the line
3432 @int initial_tile_rotation in degrees
3433 @int[opt=0] rotation_amount in degrees
3434 @int[opt=0] src_tile_y_offset use by U6 projectile tiles which need to be centred vertically before rotation. eg arrows.
3435 @treturn bool Always returns true
3436 @within effects
3437  */
nscript_projectile_anim(lua_State * L)3438 static int nscript_projectile_anim(lua_State *L) {
3439 	uint16 tile_num = (uint16)luaL_checkinteger(L, 1);
3440 	uint16 startx = (uint16)luaL_checkinteger(L, 2);
3441 	uint16 starty = (uint16)luaL_checkinteger(L, 3);
3442 	uint16 targetx = (uint16)luaL_checkinteger(L, 4);
3443 	uint16 targety = (uint16)luaL_checkinteger(L, 5);
3444 	uint16 speed = (uint16)luaL_checkinteger(L, 6);
3445 	bool trail = (bool)lua_toboolean(L, 7);
3446 	uint8 initial_tile_rotation = (uint8)luaL_checkinteger(L, 8);
3447 	uint16 rotation_amount = 0;
3448 	uint8 src_tile_y_offset = 0;
3449 
3450 	if (lua_gettop(L) >= 9)
3451 		rotation_amount = (uint16)luaL_checkinteger(L, 9);
3452 
3453 	if (lua_gettop(L) >= 10)
3454 		src_tile_y_offset = (uint8)luaL_checkinteger(L, 10);
3455 
3456 	ProjectileEffect *projectile_effect = new ProjectileEffect(tile_num, MapCoord(startx, starty), MapCoord(targetx, targety), speed, trail, initial_tile_rotation, rotation_amount, src_tile_y_offset);
3457 	AsyncEffect *e = new AsyncEffect(projectile_effect);
3458 	e->run();
3459 
3460 	lua_pushboolean(L, true);
3461 	return 1;
3462 }
3463 
3464 /***
3465 Create multiple projectile effects emanating from (startx,starty) going to multiple target locations
3466 @function projectile_anim_multi
3467 @int tile_number
3468 @int startx
3469 @int starty
3470 @tparam {MapCoord,...} targets
3471 @int speed
3472 @int trail
3473 @int initial_tile_rotation
3474 @treturn table|bool A table containing the hit Actor and Obj objects. Or false if argument 4 isn't a table
3475 @within effects
3476  */
nscript_projectile_anim_multi(lua_State * L)3477 static int nscript_projectile_anim_multi(lua_State *L) {
3478 	uint16 tile_num = (uint16)luaL_checkinteger(L, 1);
3479 	uint16 startx = (uint16)luaL_checkinteger(L, 2);
3480 	uint16 starty = (uint16)luaL_checkinteger(L, 3);
3481 
3482 	if (!lua_istable(L, 4)) {
3483 		lua_pushboolean(L, false);
3484 		return 1;
3485 	}
3486 
3487 	lua_pushvalue(L, 4); //push table containing targets to top of stack
3488 
3489 	uint16 x = 0;
3490 	uint16 y = 0;
3491 	uint8 z = 0;
3492 
3493 	vector<MapCoord> t;
3494 
3495 	for (int i = 1;; i++) {
3496 		lua_pushinteger(L, i);
3497 		lua_gettable(L, -2);
3498 
3499 		if (!lua_istable(L, -1)) { //we've hit the end of our targets
3500 			::debug(1, "end = %d", i);
3501 			lua_pop(L, 1);
3502 			break;
3503 		}
3504 		//get target fields here.
3505 
3506 		get_tbl_field_uint16(L, "x", &x);
3507 		get_tbl_field_uint16(L, "y", &y);
3508 		get_tbl_field_uint8(L, "z", &z);
3509 
3510 		t.push_back(MapCoord(x, y, z));
3511 
3512 		lua_pop(L, 1);
3513 	}
3514 
3515 	uint16 speed = (uint16)luaL_checkinteger(L, 5);
3516 	bool trail = (bool)luaL_checkinteger(L, 6);
3517 	uint8 initial_tile_rotation = (uint8)luaL_checkinteger(L, 7);
3518 
3519 	ProjectileEffect *effect = new ProjectileEffect(tile_num, MapCoord(startx, starty), t, speed, trail, initial_tile_rotation);
3520 	AsyncEffect *e = new AsyncEffect(effect);
3521 	e->run();
3522 
3523 	return nscript_new_hit_entities_tbl_var(L, effect);
3524 }
3525 
3526 /***
3527 Hit effect. Displays the hit/damage tile over the map at a given location for a short period of time. The hit sfx is also played.
3528 @function hit_anim
3529 @int x
3530 @int y
3531 @treturn bool Always returns true
3532 @within effects
3533  */
nscript_hit_anim(lua_State * L)3534 static int nscript_hit_anim(lua_State *L) {
3535 	uint16 targetx = (uint16)luaL_checkinteger(L, 1);
3536 	uint16 targety = (uint16)luaL_checkinteger(L, 2);
3537 
3538 
3539 	AsyncEffect *e = new AsyncEffect(new HitEffect(MapCoord(targetx, targety)));
3540 	e->run();
3541 
3542 	lua_pushboolean(L, true);
3543 	return 1;
3544 }
3545 
3546 
3547 /***
3548 Call the C++ usecode look function for a given Obj
3549 @function usecode_look
3550 @tparam Obj object object to look at
3551 @treturn bool returns true if the Obj has a C++ usecode look function
3552 @within Object
3553  */
3554 //FIXME need to move this into lua script.
nscript_usecode_look(lua_State * L)3555 static int nscript_usecode_look(lua_State *L) {
3556 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
3557 	Obj *obj;
3558 
3559 	obj = *s_obj;
3560 
3561 	UseCode *usecode = Game::get_game()->get_usecode();
3562 	Player *player = Game::get_game()->get_player();
3563 
3564 	lua_pushboolean(L, (int)usecode->look_obj(obj, player->get_actor()));
3565 	return 1;
3566 }
3567 
3568 /***
3569 execute the pixelated map window fade out effect
3570 @function fade_out
3571 @within effects
3572  */
nscript_fade_out(lua_State * L)3573 static int nscript_fade_out(lua_State *L) {
3574 	AsyncEffect *e = new AsyncEffect(new FadeEffect(FADE_PIXELATED, FADE_OUT));
3575 	e->run();
3576 
3577 	return 0;
3578 }
3579 
3580 /***
3581 execute the pixelated map window fade in effect
3582 @function fade_in
3583 @within effects
3584  */
nscript_fade_in(lua_State * L)3585 static int nscript_fade_in(lua_State *L) {
3586 	AsyncEffect *e = new AsyncEffect(new FadeEffect(FADE_PIXELATED, FADE_IN));
3587 	e->run();
3588 
3589 	return 0;
3590 }
3591 
3592 /***
3593 pixel fade from one tile to another. If to_tile is not supplied the fade to blank
3594 @function fade_tile
3595 @tparam MapCoord|x,y,z location location for the effect to take place
3596 @int from_tile tile number of the tile to fade from
3597 @int[opt] to_tile tile number of the tile to fade to
3598 @within effects
3599  */
nscript_fade_tile(lua_State * L)3600 static int nscript_fade_tile(lua_State *L) {
3601 	MapCoord loc;
3602 	Tile *tile_from =  NULL;
3603 	Tile *tile_to =  NULL;
3604 	TileManager *tm = Game::get_game()->get_tile_manager();
3605 
3606 	if (nscript_get_location_from_args(L, &loc.x, &loc.y, &loc.z) == false)
3607 		return 0;
3608 
3609 	if (lua_isnumber(L, 4))
3610 		tile_from = tm->get_tile((uint16)luaL_checkinteger(L, 4));
3611 
3612 	if (lua_gettop(L) > 4)
3613 		tile_to = tm->get_tile((uint16)luaL_checkinteger(L, 5));
3614 
3615 
3616 	AsyncEffect *e = new AsyncEffect(new TileFadeEffect(loc, tile_from, tile_to, FADE_PIXELATED, 10));
3617 //	AsyncEffect *e = new AsyncEffect(new TileFadeEffect(loc, tile_from, 0, 4, false, 20));
3618 	e->run();
3619 
3620 
3621 	return 0;
3622 }
3623 
3624 /***
3625 black fade effect on a given object
3626 @function fade_obj
3627 @tparam Obj obj object to fade
3628 @int fade_color the colour (palette index) to fade the black pixels to.
3629 @int fade_speed
3630 @within effects
3631  */
nscript_black_fade_obj(lua_State * L)3632 static int nscript_black_fade_obj(lua_State *L) {
3633 	Obj *obj = nscript_get_obj_from_args(L, 1);
3634 	uint8 fade_color = (uint8)lua_tointeger(L, 2);
3635 	uint16 fade_speed = (uint8)lua_tointeger(L, 3);
3636 
3637 	if (obj != NULL) {
3638 		AsyncEffect *e = new AsyncEffect(new TileBlackFadeEffect(obj, fade_color, fade_speed));
3639 		e->run();
3640 	}
3641 
3642 	return 0;
3643 }
3644 
3645 /***
3646 xor effect. XOR the colours on the mapwindow
3647 @function xor_effect
3648 @int duration in milliseconds
3649 @within effects
3650  */
nscript_xor_effect(lua_State * L)3651 static int nscript_xor_effect(lua_State *L) {
3652 	uint16 duration = (uint16)luaL_checkinteger(L, 1);
3653 
3654 	AsyncEffect *e = new AsyncEffect(new XorEffect(duration));
3655 	e->run();
3656 
3657 	return 0;
3658 }
3659 
3660 /***
3661 xray effect. Disable map blacking. (see through walls)
3662 @function xray_effect
3663 @int duration in milliseconds
3664 @within effects
3665  */
nscript_xray_effect(lua_State * L)3666 static int nscript_xray_effect(lua_State *L) {
3667 	uint16 duration = (uint16)luaL_checkinteger(L, 1);
3668 
3669 	AsyncEffect *e = new AsyncEffect(new XRayEffect(duration));
3670 	e->run();
3671 
3672 	return 0;
3673 }
3674 /***
3675 peer effect.
3676 Display an overview of the current area in the MapWindow. Any new actions
3677 cancel the effect and return to the script.
3678 (area is 48x48 tiles around the player, regardless of MapWindow size)
3679 @function peer_effect
3680 @within effects
3681  */
nscript_peer_effect(lua_State * L)3682 static int nscript_peer_effect(lua_State *L) {
3683 	uint16 x, y;
3684 	uint8 z;
3685 
3686 	Game::get_game()->get_player()->get_location(&x, &y, &z);
3687 
3688 	AsyncEffect *e = new AsyncEffect(new PeerEffect((x - x % 8) - 18, (y - y % 8) - 18, z));
3689 	e->run(EFFECT_PROCESS_GUI_INPUT);
3690 
3691 	return 0;
3692 }
3693 
3694 /***
3695 wing strike effect. A dragon flies across the screen. (U6)
3696 @function wing_strike_effect
3697 @within effects
3698  */
nscript_wing_strike_effect(lua_State * L)3699 static int nscript_wing_strike_effect(lua_State *L) {
3700 	Actor *actor = nscript_get_actor_from_args(L, 1);
3701 
3702 	if (actor != NULL) {
3703 		AsyncEffect *e = new AsyncEffect(new WingStrikeEffect(actor));
3704 		e->run();
3705 	}
3706 
3707 	return 0;
3708 }
3709 
3710 /***
3711 hail storm effect (U6). Hail stones rain down on the mapwindow.
3712 @function hail_storm_effect
3713 @tparam MapCoord|x,y,z location
3714 @within effects
3715  */
nscript_hail_storm_effect(lua_State * L)3716 static int nscript_hail_storm_effect(lua_State *L) {
3717 	MapCoord loc;
3718 	if (nscript_get_location_from_args(L, &loc.x, &loc.y, &loc.z) == false)
3719 		return 0;
3720 
3721 
3722 	AsyncEffect *e = new AsyncEffect(new HailStormEffect(loc));
3723 	e->run();
3724 
3725 
3726 	return 0;
3727 }
3728 
3729 /***
3730 wizard's eye effect (U6).
3731 @function wizard_eye_effect
3732 @tparam MapCoord|x,y,z start_location
3733 @within effects
3734  */
nscript_wizard_eye_effect(lua_State * L)3735 static int nscript_wizard_eye_effect(lua_State *L) {
3736 	MapCoord loc;
3737 	uint16 duration = (uint16)luaL_checkinteger(L, 1);
3738 
3739 	if (nscript_get_location_from_args(L, &loc.x, &loc.y, &loc.z, 2) == false)
3740 		return 0;
3741 
3742 	AsyncEffect *e = new AsyncEffect(new WizardEyeEffect(loc, duration));
3743 	e->run(EFFECT_PROCESS_GUI_INPUT);
3744 
3745 
3746 	return 0;
3747 }
3748 
3749 /***
3750 play the game end sequence then quit.
3751 The file ending.lua is used from the relevant game's script directory.
3752 @function play_end_sequence
3753  */
nscript_play_end_sequence(lua_State * L)3754 static int nscript_play_end_sequence(lua_State *L) {
3755 	get_cutscene()->moveToFront();
3756 
3757 	Script::get_script()->play_cutscene("/ending.lua");
3758 
3759 	Game::get_game()->quit();
3760 
3761 	return 0;
3762 }
3763 
3764 /***
3765 play a sound effect
3766 @function play_sfx
3767 @int sfx_id the sound effect index number.
3768 @bool[opt=false] async_playback if true then the sfx is played back asynchronously.
3769  */
nscript_play_sfx(lua_State * L)3770 static int nscript_play_sfx(lua_State *L) {
3771 	bool play_mode = SFX_PLAY_SYNC;
3772 	uint16 sfx_id = (uint16)luaL_checkinteger(L, 1);
3773 	if (lua_gettop(L) > 1) {
3774 		if (lua_toboolean(L, 2) != 0 /*== true*/)
3775 			play_mode = SFX_PLAY_ASYNC;
3776 	}
3777 
3778 	Script::get_script()->get_sound_manager()->playSfx(sfx_id, play_mode);
3779 
3780 	return 0;
3781 }
3782 
nscript_u6llist_iter(lua_State * L)3783 int nscript_u6llist_iter(lua_State *L) {
3784 	U6Link **s_link = (U6Link **)luaL_checkudata(L, 1, "nuvie.U6Link");
3785 	U6Link *link = *s_link;
3786 
3787 	if (link == NULL || link->data == NULL)
3788 		return 0;
3789 
3790 	Obj *obj = (Obj *)link->data;
3791 	nscript_obj_new(L, obj);
3792 
3793 	retainU6Link(link->next);
3794 	*s_link = link->next;
3795 
3796 	releaseU6Link(link); // release old link object.
3797 
3798 	return 1;
3799 }
3800 
nscript_u6llist_iter_recursive(lua_State * L)3801 int nscript_u6llist_iter_recursive(lua_State *L) {
3802 	Std::stack<U6Link *> **s_stack = (Std::stack<U6Link *> **)luaL_checkudata(L, 1, "nuvie.U6LinkRecursive");
3803 	Std::stack<U6Link *> *s = *s_stack;
3804 
3805 	if (s->empty() || s->top() == NULL)
3806 		return 0;
3807 
3808 	U6Link *link = s->top();
3809 
3810 	Obj *obj = (Obj *)link->data;
3811 	nscript_obj_new(L, obj);
3812 
3813 	s->pop();
3814 	if (link->next != NULL) {
3815 		s->push(link->next);
3816 		retainU6Link(link->next);
3817 	}
3818 
3819 	if (obj->container && obj->container->count() > 0) {
3820 		s->push(obj->container->start());
3821 		retainU6Link(obj->container->start());
3822 	}
3823 
3824 	releaseU6Link(link); // release old link object.
3825 
3826 	return 1;
3827 }
3828 
nscript_party_iter(lua_State * L)3829 int nscript_party_iter(lua_State *L) {
3830 	uint16 party_index = (uint16)lua_tointeger(L, lua_upvalueindex(1));
3831 
3832 	if (party_index == Game::get_game()->get_party()->get_party_size())
3833 		return 0;
3834 
3835 	uint8 actor_num = Game::get_game()->get_party()->get_actor_num(party_index);
3836 
3837 	lua_pushinteger(L, party_index + 1);
3838 	lua_replace(L, lua_upvalueindex(1));
3839 
3840 	nscript_new_actor_var(L, actor_num);
3841 
3842 	return 1;
3843 }
3844 
3845 /***
3846 Iterate through party members.
3847 @function party_members
3848 @usage
3849   local actor
3850   for actor in party_members() do
3851 	actor.poisoned = false
3852   end
3853 @within party
3854  */
nscript_party(lua_State * L)3855 static int nscript_party(lua_State *L) {
3856 	lua_pushinteger(L, 0);
3857 	lua_pushcclosure(L, &nscript_party_iter, 1);
3858 	return 1;
3859 }
3860 
nscript_find_obj_iter(lua_State * L)3861 int nscript_find_obj_iter(lua_State *L) {
3862 	Obj *cur_obj = NULL;
3863 
3864 	if (!lua_isnil(L, lua_upvalueindex(1)))
3865 		cur_obj = nscript_get_obj_from_args(L, lua_upvalueindex(1));
3866 	uint8 level = (uint8)lua_tointeger(L, lua_upvalueindex(2));
3867 	bool match_frame_n = (bool)lua_toboolean(L, lua_upvalueindex(3));
3868 	bool match_quality = (bool)lua_toboolean(L, lua_upvalueindex(4));
3869 
3870 	if (cur_obj == NULL)
3871 		return 0;
3872 
3873 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
3874 	Obj *next_obj = obj_manager->find_next_obj(level, cur_obj, match_frame_n, match_quality);
3875 
3876 	if (next_obj == NULL) {
3877 		lua_pushnil(L);
3878 	} else {
3879 		nscript_new_obj_var(L, next_obj);
3880 	}
3881 	lua_replace(L, lua_upvalueindex(1));
3882 
3883 	lua_pushinteger(L, level);
3884 	lua_replace(L, lua_upvalueindex(2));
3885 
3886 	lua_pushboolean(L, match_frame_n);
3887 	lua_replace(L, lua_upvalueindex(3));
3888 
3889 	lua_pushboolean(L, match_quality);
3890 	lua_replace(L, lua_upvalueindex(4));
3891 
3892 	nscript_new_obj_var(L, cur_obj);
3893 
3894 	return 1;
3895 }
3896 
nscript_get_next_obj_from_area(U6Link ** link,uint16 x,uint16 y,uint8 z,uint16 w,uint16 h,uint16 * xOffset,uint16 * yOffset)3897 Obj *nscript_get_next_obj_from_area(U6Link **link, uint16 x, uint16 y, uint8 z, uint16 w, uint16 h, uint16 *xOffset, uint16 *yOffset) {
3898 	if (*link != NULL) {
3899 		Obj *obj = (Obj *)(*link)->data;
3900 		*link = (*link)->next;
3901 		return obj;
3902 	}
3903 
3904 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
3905 	while (*yOffset < h) {
3906 		U6LList *list = obj_manager->get_obj_list(x + *xOffset, y + *yOffset, z);
3907 
3908 		(*xOffset)++;
3909 		if (*xOffset == w) {
3910 			(*yOffset)++;
3911 			*xOffset = 0;
3912 		}
3913 
3914 		if (list) {
3915 			*link = list->start();
3916 			if (*link) {
3917 				Obj *obj = (Obj *)(*link)->data;
3918 				*link = (*link)->next;
3919 				return obj;
3920 			}
3921 		}
3922 	}
3923 
3924 	return NULL;
3925 }
3926 
nscript_find_obj_from_area_iter(lua_State * L)3927 int nscript_find_obj_from_area_iter(lua_State *L) {
3928 	Obj *cur_obj = NULL;
3929 
3930 	U6Link **s_link = (U6Link **)luaL_checkudata(L, lua_upvalueindex(1), "nuvie.U6Link");
3931 
3932 	uint16 x = (uint16)lua_tointeger(L, lua_upvalueindex(2));
3933 	uint16 y = (uint16)lua_tointeger(L, lua_upvalueindex(3));
3934 	uint8 z = (uint8)lua_tointeger(L, lua_upvalueindex(4));
3935 	uint16 width = (uint16)lua_tointeger(L, lua_upvalueindex(5));
3936 	uint16 height = (uint16)lua_tointeger(L, lua_upvalueindex(6));
3937 	uint16 xOffset = (uint16)lua_tointeger(L, lua_upvalueindex(7));
3938 	uint16 yOffset = (uint16)lua_tointeger(L, lua_upvalueindex(8));
3939 
3940 	releaseU6Link(*s_link); // release old link object.
3941 
3942 	cur_obj = nscript_get_next_obj_from_area(s_link, x, y, z, width, height, &xOffset, &yOffset);
3943 
3944 	retainU6Link(*s_link);
3945 
3946 	if (cur_obj == NULL)
3947 		return 0;
3948 
3949 	lua_pushinteger(L, xOffset);
3950 	lua_replace(L, lua_upvalueindex(7));
3951 
3952 	lua_pushinteger(L, yOffset);
3953 	lua_replace(L, lua_upvalueindex(8));
3954 
3955 	nscript_new_obj_var(L, cur_obj);
3956 
3957 	return 1;
3958 }
3959 /***
3960 Iterate through all objects of a specific type on a given map level.
3961 @function find_obj
3962 @int z map level to search
3963 @int obj_n object number to search for
3964 @int[opt] frame_n filter search based on specific frame number
3965 @int[opt] quality filter search based on specific quality value
3966 @usage
3967   local loc = player_get_location()
3968   for obj in find_obj(loc.z, 223, 1) do
3969 	if obj ~= nil then
3970 	  explode_obj(obj)
3971 	end
3972   end
3973 @within Object
3974  */
nscript_find_obj(lua_State * L)3975 static int nscript_find_obj(lua_State *L) {
3976 	uint8 level = (uint8)luaL_checkinteger(L, 1);
3977 	uint16 obj_n = (uint16)luaL_checkinteger(L, 2);
3978 	uint16 frame_n = 0;
3979 	bool match_frame_n = OBJ_NOMATCH_FRAME_N;
3980 	uint16 quality = 0;
3981 	bool match_quality = OBJ_NOMATCH_QUALITY;
3982 
3983 	if (lua_gettop(L) >= 3 && !lua_isnil(L, 3)) {
3984 		frame_n = (uint16)luaL_checkinteger(L, 3);
3985 		match_frame_n = OBJ_MATCH_FRAME_N;
3986 	}
3987 
3988 	if (lua_gettop(L) >= 4 && !lua_isnil(L, 4)) {
3989 		quality = (uint16)luaL_checkinteger(L, 4);
3990 		match_quality = OBJ_MATCH_QUALITY;
3991 	}
3992 
3993 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
3994 	Obj *obj = obj_manager->find_obj(level, obj_n, quality, match_quality, frame_n, match_frame_n);
3995 	if (obj != NULL) {
3996 		nscript_new_obj_var(L, obj);
3997 	} else {
3998 		lua_pushnil(L);
3999 	}
4000 
4001 	lua_pushinteger(L, level);
4002 	lua_pushboolean(L, match_frame_n);
4003 	lua_pushboolean(L, match_quality);
4004 
4005 	lua_pushcclosure(L, &nscript_find_obj_iter, 4);
4006 
4007 	return 1;
4008 }
4009 
4010 /***
4011 Iterate through all objects within a given area.
4012 @function find_obj_from_area
4013 @tparam MapCoord|x,y,z location location for the effect to take place
4014 @int width width of area to search
4015 @int height height of area to search
4016 @within Object
4017  */
nscript_find_obj_from_area(lua_State * L)4018 static int nscript_find_obj_from_area(lua_State *L) {
4019 	MapCoord loc;
4020 	int stackOffset = 4;
4021 	if (nscript_get_location_from_args(L, &loc.x, &loc.y, &loc.z) == false)
4022 		return 0;
4023 	if (lua_istable(L, 1)) {
4024 		stackOffset = 2;
4025 	}
4026 
4027 	uint16 width = (uint16)luaL_checkinteger(L, stackOffset++);
4028 	uint16 height = (uint16)luaL_checkinteger(L, stackOffset);
4029 
4030 	U6Link **p_link = (U6Link **)lua_newuserdata(L, sizeof(U6Link *));
4031 	*p_link = NULL;
4032 
4033 	luaL_getmetatable(L, "nuvie.U6Link");
4034 	lua_setmetatable(L, -2);
4035 
4036 	lua_pushinteger(L, loc.x);
4037 	lua_pushinteger(L, loc.y);
4038 	lua_pushinteger(L, loc.z);
4039 	lua_pushinteger(L, width);
4040 	lua_pushinteger(L, height);
4041 	lua_pushinteger(L, 0); //cur x offset
4042 	lua_pushinteger(L, 0); //cur y offset
4043 
4044 	lua_pushcclosure(L, &nscript_find_obj_from_area_iter, 8);
4045 
4046 	return 1;
4047 }
4048 
4049 /***
4050 Set specific game timer counter (U6).
4051 These counters are decremented each turn and are used for things like torch duration, eclipse etc.
4052 @function timer_set
4053 @int timer_idx
4054 @int value
4055 @within time
4056  */
nscript_timer_set(lua_State * L)4057 static int nscript_timer_set(lua_State *L) {
4058 	GameClock *clock = Game::get_game()->get_clock();
4059 
4060 	uint8 timer_num = (uint8)luaL_checkinteger(L, 1);
4061 	uint8 value = (uint8)luaL_checkinteger(L, 2);
4062 
4063 	clock->set_timer(timer_num, value);
4064 
4065 	return 0;
4066 }
4067 
4068 /***
4069 Get specific game timer counter (U6).
4070 These counters are decremented each turn and are used for things like torch duration, eclipse etc.
4071 @function timer_get
4072 @int timer_idx
4073 @treturn integer value of the timer
4074 @within time
4075  */
nscript_timer_get(lua_State * L)4076 static int nscript_timer_get(lua_State *L) {
4077 	GameClock *clock = Game::get_game()->get_clock();
4078 
4079 	uint8 timer_num = (uint8)luaL_checkinteger(L, 1);
4080 
4081 	lua_pushinteger(L, clock->get_timer(timer_num));
4082 
4083 	return 1;
4084 }
4085 
4086 /***
4087 Set all timer counters with a given value
4088 @function timer_update_all
4089 @int value
4090 @within time
4091  */
nscript_timer_update_all(lua_State * L)4092 static int nscript_timer_update_all(lua_State *L) {
4093 	GameClock *clock = Game::get_game()->get_clock();
4094 
4095 	uint8 value = (uint8)luaL_checkinteger(L, 1);
4096 
4097 	clock->update_timers(value);
4098 
4099 	return 0;
4100 }
4101 
4102 /***
4103 Get the current year
4104 @function clock_get_year
4105 @treturn integer
4106 @within time
4107  */
nscript_clock_get_year(lua_State * L)4108 static int nscript_clock_get_year(lua_State *L) {
4109 	GameClock *clock = Game::get_game()->get_clock();
4110 
4111 	if (clock == NULL)
4112 		return 0;
4113 
4114 	lua_pushinteger(L, clock->get_year());
4115 
4116 	return 1;
4117 }
4118 
4119 /***
4120 Get the current month
4121 @function clock_get_month
4122 @treturn integer
4123 @within time
4124  */
nscript_clock_get_month(lua_State * L)4125 static int nscript_clock_get_month(lua_State *L) {
4126 	GameClock *clock = Game::get_game()->get_clock();
4127 
4128 	if (clock == NULL)
4129 		return 0;
4130 
4131 	lua_pushinteger(L, clock->get_month());
4132 
4133 	return 1;
4134 }
4135 
4136 /***
4137 Get the current day
4138 @function clock_get_day
4139 @treturn integer
4140 @within time
4141  */
nscript_clock_get_day(lua_State * L)4142 static int nscript_clock_get_day(lua_State *L) {
4143 	GameClock *clock = Game::get_game()->get_clock();
4144 
4145 	if (clock == NULL)
4146 		return 0;
4147 
4148 	lua_pushinteger(L, clock->get_day());
4149 
4150 	return 1;
4151 }
4152 
4153 /***
4154 Get the clock minute value
4155 @function clock_get_minute
4156 @treturn integer
4157 @within time
4158  */
nscript_clock_get_minute(lua_State * L)4159 static int nscript_clock_get_minute(lua_State *L) {
4160 	GameClock *clock = Game::get_game()->get_clock();
4161 
4162 	lua_pushinteger(L, clock->get_minute());
4163 
4164 	return 1;
4165 }
4166 
4167 /***
4168 Get the clock hour value
4169 @function clock_get_hour
4170 @treturn integer the hour in 24 hour format
4171 @within time
4172  */
nscript_clock_get_hour(lua_State * L)4173 static int nscript_clock_get_hour(lua_State *L) {
4174 	GameClock *clock = Game::get_game()->get_clock();
4175 
4176 	lua_pushinteger(L, clock->get_hour());
4177 
4178 	return 1;
4179 }
4180 
4181 /***
4182 Increase the game clock by a number of minutes
4183 @function clock_inc
4184 @int minutes the number of minutes to increment the clock by
4185 @within time
4186  */
nscript_clock_inc(lua_State * L)4187 static int nscript_clock_inc(lua_State *L) {
4188 	GameClock *clock = Game::get_game()->get_clock();
4189 
4190 	uint16 minutes = (uint16)luaL_checkinteger(L, 1);
4191 
4192 	clock->inc_minute(minutes);
4193 
4194 	return 0;
4195 }
4196 
4197 /***
4198 Set the current wind direction (U6).
4199 @function wind_set_dir
4200 @int direction new wind direction
4201  */
nscript_wind_set(lua_State * L)4202 static int nscript_wind_set(lua_State *L) {
4203 	Weather *weather = Game::get_game()->get_weather();
4204 	uint8 wind_dir = (uint8)luaL_checkinteger(L, 1);
4205 
4206 	weather->set_wind_dir(wind_dir);
4207 
4208 	return 0;
4209 }
4210 
4211 /***
4212 Get the current wind direction (U6).
4213 @function wind_get_dir
4214 @treturn integer
4215  */
nscript_wind_get(lua_State * L)4216 static int nscript_wind_get(lua_State *L) {
4217 	Weather *weather = Game::get_game()->get_weather();
4218 	lua_pushinteger(L, weather->get_wind_dir());
4219 	return 1;
4220 }
4221 
4222 /***
4223 Get input from the keyboard
4224 @function input_select
4225 @string allowed_characters set to nil if all characters are permitted
4226 @bool can_escape can the player use escape to skip input
4227 @treturn string characters input by the player
4228 @within io
4229  */
nscript_input_select(lua_State * L)4230 static int nscript_input_select(lua_State *L) {
4231 	const char *allowed_chars = NULL;
4232 
4233 	if (!lua_isnil(L, 1))
4234 		allowed_chars = luaL_checkstring(L, 1);
4235 
4236 	bool can_escape = lua_toboolean(L, 2);
4237 
4238 	TextInputEffect *inputEffect = new TextInputEffect(allowed_chars, can_escape);
4239 	AsyncEffect *e = new AsyncEffect(inputEffect);
4240 	e->run(EFFECT_PROCESS_GUI_INPUT);
4241 
4242 	Std::string input = inputEffect->get_input();
4243 
4244 	lua_pushstring(L, input.c_str());
4245 
4246 	return 1;
4247 }
4248 
4249 /***
4250 Get an integer number as input from the player.
4251 The characters input by the player are converted into an integer using the
4252 C function strtol()
4253 @function input_select_integer
4254 @string allowed_characters set to nil if all characters are permitted
4255 @bool can_escape can the player use escape to skip input
4256 @treturn integer number input by the player
4257 @within io
4258  */
nscript_input_select_integer(lua_State * L)4259 static int nscript_input_select_integer(lua_State *L) {
4260 	const char *allowed_chars = NULL;
4261 
4262 	if (!lua_isnil(L, 1))
4263 		allowed_chars = luaL_checkstring(L, 1);
4264 
4265 	bool can_escape = lua_toboolean(L, 2);
4266 
4267 	TextInputEffect *inputEffect = new TextInputEffect(allowed_chars, can_escape);
4268 	AsyncEffect *e = new AsyncEffect(inputEffect);
4269 	e->run(EFFECT_PROCESS_GUI_INPUT);
4270 
4271 	Std::string input = inputEffect->get_input();
4272 
4273 	int num = (int)strtol(input.c_str(), (char **)NULL, 10);
4274 	lua_pushinteger(L, num);
4275 
4276 	return 1;
4277 }
4278 
4279 /***
4280 Iterate through objects at a given map location
4281 @function objs_at_loc
4282 @tparam MapCoord|x,y,z location
4283 @within Object
4284  */
nscript_objs_at_loc(lua_State * L)4285 static int nscript_objs_at_loc(lua_State *L) {
4286 	U6Link *link = NULL;
4287 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
4288 
4289 	uint16 x, y;
4290 	uint8 z;
4291 
4292 	if (nscript_get_location_from_args(L, &x, &y, &z) == false)
4293 		return 0;
4294 
4295 	if (x < 1024 && y < 1024 && z <= 5) {
4296 		U6LList *obj_list = obj_manager->get_obj_list(x, y, z);
4297 		if (obj_list != NULL)
4298 			link = obj_list->start();
4299 	} else {
4300 		DEBUG(0, LEVEL_ERROR, "objs_at_loc() Invalid coordinates (%d, %d, %d)\n", x, y, z);
4301 	}
4302 
4303 	lua_pushcfunction(L, nscript_u6llist_iter);
4304 
4305 	U6Link **p_link = (U6Link **)lua_newuserdata(L, sizeof(U6Link *));
4306 	*p_link = link;
4307 
4308 	if (link)
4309 		retainU6Link(link);
4310 
4311 	luaL_getmetatable(L, "nuvie.U6Link");
4312 	lua_setmetatable(L, -2);
4313 
4314 	return 2;
4315 }
4316 
4317 /***
4318 Find a volcano object near the player. This function searches an area +/- 5 tiles around the location specified.
4319 The search starts top left and finishes bottom right. The first volcano/fumarole object found is returned.
4320 @function find_volcano_near_player
4321 @tparam MapCoord|x,y,z location centre of the search area
4322 @treturn Obj|nil first volcano/fumarole object found or nil if none found.
4323 @within Object
4324  */
nscript_find_volcano_obj_near_player(lua_State * L)4325 static int nscript_find_volcano_obj_near_player(lua_State *L) {
4326 	uint16 x, y;
4327 	uint8 z;
4328 	const uint8 range = 5;
4329 	ObjManager *obj_manager = Game::get_game()->get_obj_manager();
4330 
4331 	Game::get_game()->get_player()->get_location(&x, &y, &z);
4332 
4333 	for (uint16 i = y - range; i < y + range; i++) {
4334 		for (uint16 j = x - range; j < x + range; j++) {
4335 			U6LList *obj_list = obj_manager->get_obj_list(j, i, z);
4336 			if (obj_list) {
4337 				for (U6Link *link = obj_list->start(); link; link = link->next) {
4338 					Obj *o = (Obj *)link->data;
4339 					if (o->obj_n == OBJ_U6_VOLCANO || o->obj_n == OBJ_U6_FUMAROLE) {
4340 						nscript_new_obj_var(L, o);
4341 						return 1;
4342 					}
4343 				}
4344 			}
4345 		}
4346 	}
4347 	return 0;
4348 }
4349 
4350 /***
4351 Iterate through objects in a container.
4352 @function container_objs
4353 @tparam Obj container container object to search.
4354 @bool[opt=false] is_recursive should we search containers inside the container?
4355 @usage
4356   local child
4357   for child in container_objs(obj) do  -- look through container for effect object.
4358 	if child.obj_n == 337 then --effect
4359 	  found = true
4360 	  print("\nIt's trapped.\n");
4361 	  break
4362 	end
4363   end
4364 @within Object
4365  */
nscript_container(lua_State * L)4366 static int nscript_container(lua_State *L) {
4367 	bool is_recursive = false;
4368 	Obj **s_obj = (Obj **)luaL_checkudata(L, 1, "nuvie.Obj");
4369 	Obj *obj;
4370 
4371 	obj = *s_obj;
4372 
4373 	U6LList *obj_list = obj->container;
4374 
4375 	if (lua_gettop(L) >= 2)
4376 		is_recursive = lua_toboolean(L, 2);
4377 
4378 	return nscript_init_u6link_iter(L, obj_list, is_recursive);
4379 }
4380 
nscript_init_u6link_iter(lua_State * L,U6LList * list,bool is_recursive)4381 int nscript_init_u6link_iter(lua_State *L, U6LList *list, bool is_recursive) {
4382 	U6Link *link = NULL;
4383 
4384 	if (list != NULL)
4385 		link = list->start();
4386 
4387 	retainU6Link(link);
4388 
4389 	if (is_recursive) {
4390 		lua_pushcfunction(L, nscript_u6llist_iter_recursive);
4391 
4392 		Std::stack<U6Link *> **p_stack = (Std::stack<U6Link *> **)lua_newuserdata(L, sizeof(Std::stack<U6Link *> *));
4393 		*p_stack = new Std::stack<U6Link *>();
4394 		(*p_stack)->push(link);
4395 
4396 		luaL_getmetatable(L, "nuvie.U6LinkRecursive");
4397 	} else {
4398 		lua_pushcfunction(L, nscript_u6llist_iter);
4399 
4400 		U6Link **p_link = (U6Link **)lua_newuserdata(L, sizeof(U6Link *));
4401 		*p_link = link;
4402 
4403 		luaL_getmetatable(L, "nuvie.U6Link");
4404 	}
4405 
4406 	lua_setmetatable(L, -2);
4407 
4408 	return 2;
4409 }
4410 
4411 /***
4412 Is the god mode cheat currently active?
4413 @function is_god_mode_enabled
4414 @treturn bool
4415  */
nscript_is_god_mode_enabled(lua_State * L)4416 static int nscript_is_god_mode_enabled(lua_State *L) {
4417 	bool god_mode = Game::get_game()->is_god_mode_enabled();
4418 	lua_pushboolean(L, god_mode);
4419 	return 1;
4420 }
4421 
4422 /***
4423 Set armageddon flag
4424 @function set_armageddon
4425 @bool new_value
4426  */
nscript_set_armageddon(lua_State * L)4427 static int nscript_set_armageddon(lua_State *L) {
4428 	Game::get_game()->set_armageddon((bool)lua_toboolean(L, 1));
4429 	return 0;
4430 }
4431 
4432 /***
4433 Toggle mouse cursor visibility.
4434 @function mouse_cursor_visible
4435 @bool visible
4436 @within io
4437  */
nscript_mouse_cursor_show(lua_State * L)4438 static int nscript_mouse_cursor_show(lua_State *L) {
4439 	bool show_cursor = lua_toboolean(L, 1);
4440 	Cursor *cursor = Game::get_game()->get_cursor();
4441 	if (cursor) {
4442 		if (show_cursor) {
4443 			cursor->show();
4444 		} else {
4445 			cursor->hide();
4446 		}
4447 	}
4448 	return 0;
4449 }
4450 
4451 /***
4452 Select which mouse cursor pointer to use.
4453 @function mouse_cursor_set_pointer
4454 @int pointer_index
4455 @within io
4456  */
nscript_mouse_cursor_set_pointer(lua_State * L)4457 static int nscript_mouse_cursor_set_pointer(lua_State *L) {
4458 	uint8 new_pointer = lua_tointeger(L, 1);
4459 	Cursor *cursor = Game::get_game()->get_cursor();
4460 	if (cursor) {
4461 		cursor->set_pointer(new_pointer);
4462 	}
4463 
4464 	return 0;
4465 }
4466 
4467 /***
4468 Pause the script. Tile animation will continue while the script is paused.
4469 @function script_wait
4470 @int duration in milliseconds
4471 @within io
4472  */
nscript_wait(lua_State * L)4473 static int nscript_wait(lua_State *L) {
4474 	uint32 duration = (uint32)luaL_checkinteger(L, 1);
4475 
4476 	Game::get_game()->get_map_window()->updateAmbience();
4477 	Game::get_game()->get_view_manager()->update();
4478 
4479 	AsyncEffect *e = new AsyncEffect(new TimedEffect(duration));
4480 	e->run(EFFECT_PROCESS_GUI_INPUT);
4481 
4482 
4483 	return 0;
4484 }
4485 
4486 /***
4487 Centre the mapwindow at a given location.
4488 @function mapwindow_center_at_location
4489 @int x
4490 @int y
4491 @int z
4492 @within mapwindow
4493  */
nscript_mapwindow_center_at_loc(lua_State * L)4494 static int nscript_mapwindow_center_at_loc(lua_State *L) {
4495 	MapWindow *map_window = Game::get_game()->get_map_window();
4496 
4497 	uint16 x = (uint16) luaL_checkinteger(L, 1);
4498 	uint16 y = (uint16) luaL_checkinteger(L, 2);
4499 	uint8 z = (uint8) luaL_checkinteger(L, 3);
4500 
4501 	map_window->centerMap(x, y, z);
4502 
4503 	return 0;
4504 }
4505 
4506 /***
4507 Get the current location that the mapwindow is displaying. This is the top left corner
4508 of the mapwindow.
4509 @function mapwindow_get_location
4510 @treturn MapCoord
4511 @within mapwindow
4512  */
nscript_mapwindow_get_loc(lua_State * L)4513 static int nscript_mapwindow_get_loc(lua_State *L) {
4514 	MapWindow *map_window = Game::get_game()->get_map_window();
4515 
4516 	uint16 x = map_window->get_cur_x();
4517 	uint16 y = map_window->get_cur_y();
4518 	uint8 z;
4519 	map_window->get_level(&z);
4520 
4521 	lua_newtable(L);
4522 	lua_pushstring(L, "x");
4523 	lua_pushinteger(L, x);
4524 	lua_settable(L, -3);
4525 
4526 	lua_pushstring(L, "y");
4527 	lua_pushinteger(L, y);
4528 	lua_settable(L, -3);
4529 
4530 	lua_pushstring(L, "z");
4531 	lua_pushinteger(L, z);
4532 	lua_settable(L, -3);
4533 
4534 	return 1;
4535 }
4536 
4537 /***
4538 Set the current location that the mapwindow is displaying. This is the top left corner
4539 @function mapwindow_set_location
4540 @int x
4541 @int y
4542 @int z
4543 @within mapwindow
4544  */
nscript_mapwindow_set_loc(lua_State * L)4545 static int nscript_mapwindow_set_loc(lua_State *L) {
4546 	MapWindow *map_window = Game::get_game()->get_map_window();
4547 
4548 	uint16 x = (uint16) luaL_checkinteger(L, 1);
4549 	uint16 y = (uint16) luaL_checkinteger(L, 2);
4550 	uint8 z = (uint8) luaL_checkinteger(L, 3);
4551 
4552 	map_window->moveMap(x, y, z);
4553 
4554 	map_window->set_enable_blacking(false);
4555 
4556 	return 0;
4557 }
4558 
4559 /***
4560 Toggle mapwindow 'blacking'. Blacking hides tiles that are not visible to the player because they are obscured
4561 by a wall.
4562 @function mapwindow_set_enable_blacking
4563 @bool enable_blacking
4564 @within mapwindow
4565  */
nscript_mapwindow_set_enable_blacking(lua_State * L)4566 static int nscript_mapwindow_set_enable_blacking(lua_State *L) {
4567 	MapWindow *map_window = Game::get_game()->get_map_window();
4568 
4569 	bool enable_blacking = lua_toboolean(L, 1);
4570 
4571 	map_window->set_enable_blacking(enable_blacking);
4572 
4573 	return 0;
4574 }
4575 
4576 /***
4577 Loads text from a given LZC file.
4578 @function load_text_from_lzc
4579 @string filename the lzc file to extract the text from
4580 @int index offset in the lzc file to load the text from
4581 @treturn string the extracted text
4582  */
nscript_load_text_from_lzc(lua_State * L)4583 static int nscript_load_text_from_lzc(lua_State *L) {
4584 	unsigned char *buf = NULL;
4585 	Std::string filename(lua_tostring(L, 1));
4586 	U6Lib_n lib_n;
4587 
4588 	Std::string path;
4589 
4590 	config_get_path(Game::get_game()->get_config(), filename, path);
4591 
4592 	if (!lib_n.open(path, 4, NUVIE_GAME_MD)) {
4593 		return 0;
4594 	}
4595 	int idx = lua_tointeger(L, 2);
4596 	if (idx >= (int)lib_n.get_num_items()) {
4597 		return 0;
4598 	}
4599 
4600 	buf = lib_n.get_item(idx, NULL);
4601 	if (!buf) {
4602 		return 0;
4603 	}
4604 
4605 	int len = lib_n.get_item_size(idx);
4606 	lib_n.close();
4607 
4608 	if (len < 1 || buf[len - 1] != 0) {
4609 		free(buf);
4610 		return 0;
4611 	}
4612 
4613 	if (len >= 2 && buf[len - 2] == 0xff) {
4614 		buf[len - 2] = 0x0;
4615 	}
4616 
4617 	lua_pushstring(L, (const char *)buf);
4618 	free(buf);
4619 
4620 	return 1;
4621 }
4622 
4623 /***
4624 Display string in scroll gump if in new style. Otherwise display on regular message scroll.
4625 @function display_text_in_scroll_gump
4626 @string text the text to display in the scroll
4627 @within UI
4628  */
nscript_display_text_in_scroll_gump(lua_State * L)4629 static int nscript_display_text_in_scroll_gump(lua_State *L) {
4630 	const char *text = lua_tostring(L, 1);
4631 	if (text) {
4632 		if (Game::get_game()->is_new_style())
4633 			Game::get_game()->get_view_manager()->open_scroll_gump(text, strlen(text));
4634 		else
4635 			Game::get_game()->get_scroll()->message(text);
4636 	}
4637 	return 0;
4638 }
4639 
4640 /***
4641 Lock the inventory view to a specific Actor.
4642 @function lock_inventory_view
4643 @tparam Actor actor
4644 @within UI
4645  */
nscript_lock_inventory_view(lua_State * L)4646 static int nscript_lock_inventory_view(lua_State *L) {
4647 	Actor *actor = nscript_get_actor_from_args(L, 1);
4648 	Game::get_game()->get_view_manager()->get_inventory_view()->set_actor(actor, true);
4649 	Game::get_game()->get_view_manager()->get_inventory_view()->lock_to_actor(true);
4650 	Game::get_game()->get_view_manager()->set_inventory_mode();
4651 	return 0;
4652 }
4653 
4654 /***
4655 Unlock the inventory view
4656 @function unlock_inventory_view
4657 @within UI
4658  */
nscript_unlock_inventory_view(lua_State * L)4659 static int nscript_unlock_inventory_view(lua_State *L) {
4660 	Game::get_game()->get_view_manager()->get_inventory_view()->lock_to_actor(false);
4661 	Game::get_game()->get_view_manager()->get_inventory_view()->set_party_member(0);
4662 	Game::get_game()->get_view_manager()->set_inventory_mode();
4663 	return 0;
4664 }
4665 
4666 } // End of namespace Nuvie
4667 } // End of namespace Ultima
4668