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