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/lauxlib.h"
24 
25 #include "ultima/nuvie/core/nuvie_defs.h"
26 #include "ultima/nuvie/misc/u6_misc.h"
27 #include "ultima/nuvie/files/u6_lib_n.h"
28 #include "ultima/nuvie/files/nuvie_io.h"
29 #include "ultima/nuvie/files/nuvie_io_file.h"
30 #include "ultima/nuvie/files/u6_lzw.h"
31 #include "ultima/nuvie/misc/u6_line_walker.h"
32 #include "ultima/nuvie/screen/game_palette.h"
33 #include "ultima/nuvie/sound/sound_manager.h"
34 #include "ultima/nuvie/fonts/font.h"
35 #include "ultima/nuvie/fonts/wou_font.h"
36 #include "ultima/nuvie/core/cursor.h"
37 #include "ultima/nuvie/keybinding/keys.h"
38 #include "ultima/nuvie/script/script_cutscene.h"
39 #include "common/system.h"
40 
41 namespace Ultima {
42 namespace Nuvie {
43 
44 #define DELUXE_PAINT_MAGIC 0x4d524f46 // "FORM"
45 
46 #define INPUT_KEY_RIGHT 79 | (1<<30)
47 #define INPUT_KEY_LEFT 80 | (1<<30)
48 #define INPUT_KEY_DOWN  81 | (1<<30)
49 #define INPUT_KEY_UP  82 | (1<<30)
50 
51 static ScriptCutscene *cutScene = NULL;
get_cutscene()52 ScriptCutscene *get_cutscene() {
53 	return cutScene;
54 }
55 
56 static int nscript_image_set(lua_State *L);
57 static int nscript_image_get(lua_State *L);
58 
59 bool nscript_new_image_var(lua_State *L, CSImage *image);
60 static int nscript_image_gc(lua_State *L);
61 
62 static sint32 nscript_dec_image_ref_count(CSImage *image);
63 
64 static int nscript_image_new(lua_State *L);
65 static int nscript_image_new_starfield(lua_State *L);
66 static int nscript_image_copy(lua_State *L);
67 static int nscript_image_load(lua_State *L);
68 static int nscript_image_load_all(lua_State *L);
69 static int nscript_image_print(lua_State *L);
70 static int nscript_image_draw_line(lua_State *L);
71 static int nscript_image_blit(lua_State *L);
72 static int nscript_image_update_effect(lua_State *L);
73 static int nscript_image_static(lua_State *L);
74 static int nscript_image_set_transparency_colour(lua_State *L);
75 static int nscript_image_bubble_effect_add_color(lua_State *L);
76 static int nscript_image_bubble_effect(lua_State *L);
77 
78 static const struct luaL_Reg nscript_imagelib_m[] = {
79 	{ "__index", nscript_image_get },
80 	{ "__newindex", nscript_image_set },
81 	{ "__gc", nscript_image_gc },
82 	{ NULL, NULL }
83 };
84 
85 static int nscript_sprite_set(lua_State *L);
86 static int nscript_sprite_get(lua_State *L);
87 
88 bool nscript_new_sprite_var(lua_State *L, CSSprite *image);
89 static int nscript_sprite_gc(lua_State *L);
90 
91 static const struct luaL_Reg nscript_spritelib_m[] = {
92 	{ "__index", nscript_sprite_get },
93 	{ "__newindex", nscript_sprite_set },
94 	{ "__gc", nscript_sprite_gc },
95 	{ NULL, NULL }
96 };
97 
98 static int nscript_sprite_new(lua_State *L);
99 static int nscript_sprite_move_to_front(lua_State *L);
100 
101 static int nscript_text_load(lua_State *L);
102 static int nscript_midgame_load(lua_State *L);
103 
104 static int nscript_canvas_set_bg_color(lua_State *L);
105 static int nscript_canvas_set_palette(lua_State *L);
106 static int nscript_canvas_set_palette_entry(lua_State *L);
107 static int nscript_canvas_rotate_palette(lua_State *L);
108 static int nscript_canvas_set_update_interval(lua_State *L);
109 static int nscript_canvas_set_opacity(lua_State *L);
110 static int nscript_canvas_set_solid_bg(lua_State *L);
111 static int nscript_canvas_update(lua_State *L);
112 static int nscript_canvas_show(lua_State *L);
113 static int nscript_canvas_hide(lua_State *L);
114 static int nscript_canvas_hide_all_sprites(lua_State *L);
115 static int nscript_canvas_string_length(lua_State *L);
116 static int nscript_canvas_rotate_game_palette(lua_State *L);
117 
118 static int nscript_music_play(lua_State *L);
119 static int nscript_music_stop(lua_State *L);
120 static int nscript_get_mouse_x(lua_State *L);
121 static int nscript_get_mouse_y(lua_State *L);
122 static int nscript_input_poll(lua_State *L);
123 
124 static int nscript_config_set(lua_State *L);
125 
126 static int nscript_engine_should_quit(lua_State *L);
127 
nscript_init_cutscene(lua_State * L,Configuration * cfg,GUI * gui,SoundManager * sm)128 void nscript_init_cutscene(lua_State *L, Configuration *cfg, GUI *gui, SoundManager *sm) {
129 	cutScene = new ScriptCutscene(gui, cfg, sm);
130 
131 	luaL_newmetatable(L, "nuvie.Image");
132 	luaL_register(L, NULL, nscript_imagelib_m);
133 
134 	luaL_newmetatable(L, "nuvie.Sprite");
135 	luaL_register(L, NULL, nscript_spritelib_m);
136 
137 	lua_pushcfunction(L, nscript_image_new);
138 	lua_setglobal(L, "image_new");
139 
140 	lua_pushcfunction(L, nscript_image_new_starfield);
141 	lua_setglobal(L, "image_new_starfield");
142 
143 	lua_pushcfunction(L, nscript_image_copy);
144 	lua_setglobal(L, "image_copy");
145 
146 	lua_pushcfunction(L, nscript_image_load);
147 	lua_setglobal(L, "image_load");
148 
149 	lua_pushcfunction(L, nscript_image_load_all);
150 	lua_setglobal(L, "image_load_all");
151 
152 	lua_pushcfunction(L, nscript_image_print);
153 	lua_setglobal(L, "image_print");
154 
155 	lua_pushcfunction(L, nscript_image_static);
156 	lua_setglobal(L, "image_static");
157 
158 	lua_pushcfunction(L, nscript_image_set_transparency_colour);
159 	lua_setglobal(L, "image_set_transparency_colour");
160 
161 	lua_pushcfunction(L, nscript_image_update_effect);
162 	lua_setglobal(L, "image_update_effect");
163 
164 	lua_pushcfunction(L, nscript_sprite_new);
165 	lua_setglobal(L, "sprite_new");
166 
167 	lua_pushcfunction(L, nscript_sprite_move_to_front);
168 	lua_setglobal(L, "sprite_move_to_front");
169 
170 	lua_pushcfunction(L, nscript_image_bubble_effect_add_color);
171 	lua_setglobal(L, "image_bubble_effect_add_color");
172 
173 	lua_pushcfunction(L, nscript_image_bubble_effect);
174 	lua_setglobal(L, "image_bubble_effect");
175 
176 	lua_pushcfunction(L, nscript_image_draw_line);
177 	lua_setglobal(L, "image_draw_line");
178 
179 	lua_pushcfunction(L, nscript_image_blit);
180 	lua_setglobal(L, "image_blit");
181 
182 	lua_pushcfunction(L, nscript_text_load);
183 	lua_setglobal(L, "text_load");
184 
185 	lua_pushcfunction(L, nscript_midgame_load);
186 	lua_setglobal(L, "midgame_load");
187 
188 	lua_pushcfunction(L, nscript_canvas_set_bg_color);
189 	lua_setglobal(L, "canvas_set_bg_color");
190 
191 	lua_pushcfunction(L, nscript_canvas_set_palette);
192 	lua_setglobal(L, "canvas_set_palette");
193 
194 	lua_pushcfunction(L, nscript_canvas_set_palette_entry);
195 	lua_setglobal(L, "canvas_set_palette_entry");
196 
197 	lua_pushcfunction(L, nscript_canvas_rotate_palette);
198 	lua_setglobal(L, "canvas_rotate_palette");
199 
200 	lua_pushcfunction(L, nscript_canvas_set_update_interval);
201 	lua_setglobal(L, "canvas_set_update_interval");
202 
203 	lua_pushcfunction(L, nscript_canvas_set_solid_bg);
204 	lua_setglobal(L, "canvas_set_solid_bg");
205 
206 	lua_pushcfunction(L, nscript_canvas_set_opacity);
207 	lua_setglobal(L, "canvas_set_opacity");
208 
209 	lua_pushcfunction(L, nscript_canvas_update);
210 	lua_setglobal(L, "canvas_update");
211 
212 	lua_pushcfunction(L, nscript_canvas_show);
213 	lua_setglobal(L, "canvas_show");
214 
215 	lua_pushcfunction(L, nscript_canvas_hide);
216 	lua_setglobal(L, "canvas_hide");
217 
218 	lua_pushcfunction(L, nscript_canvas_hide_all_sprites);
219 	lua_setglobal(L, "canvas_hide_all_sprites");
220 
221 	lua_pushcfunction(L, nscript_canvas_string_length);
222 	lua_setglobal(L, "canvas_string_length");
223 
224 	lua_pushcfunction(L, nscript_canvas_rotate_game_palette);
225 	lua_setglobal(L, "canvas_rotate_game_palette");
226 
227 	lua_pushcfunction(L, nscript_music_play);
228 	lua_setglobal(L, "music_play");
229 
230 	lua_pushcfunction(L, nscript_music_stop);
231 	lua_setglobal(L, "music_stop");
232 
233 	lua_pushcfunction(L, nscript_get_mouse_x);
234 	lua_setglobal(L, "get_mouse_x");
235 
236 	lua_pushcfunction(L, nscript_get_mouse_y);
237 	lua_setglobal(L, "get_mouse_y");
238 
239 	lua_pushcfunction(L, nscript_input_poll);
240 	lua_setglobal(L, "input_poll");
241 
242 	lua_pushcfunction(L, nscript_config_set);
243 	lua_setglobal(L, "config_set");
244 
245 	lua_pushcfunction(L, nscript_engine_should_quit);
246 	lua_setglobal(L, "engine_should_quit");
247 }
248 
nscript_new_image_var(lua_State * L,CSImage * image)249 bool nscript_new_image_var(lua_State *L, CSImage *image) {
250 	CSImage **userdata;
251 
252 	userdata = (CSImage **)lua_newuserdata(L, sizeof(CSImage *));
253 
254 	luaL_getmetatable(L, "nuvie.Image");
255 	lua_setmetatable(L, -2);
256 
257 	*userdata = image;
258 
259 	if (image)
260 		image->refcount++;
261 
262 	return true;
263 }
264 
nscript_get_image_from_args(lua_State * L,int lua_stack_offset)265 CSImage *nscript_get_image_from_args(lua_State *L, int lua_stack_offset) {
266 	CSImage **s_image = (CSImage **)luaL_checkudata(L, lua_stack_offset, "nuvie.Image");
267 	if (s_image == NULL)
268 		return NULL;
269 
270 	return *s_image;
271 }
272 
nscript_image_set(lua_State * L)273 static int nscript_image_set(lua_State *L) {
274 	CSImage **s_image;
275 	CSImage *image;
276 	const char *key;
277 
278 	s_image = (CSImage **)lua_touserdata(L, 1);
279 	if (s_image == NULL)
280 		return 0;
281 
282 	image = *s_image;
283 	if (image == NULL)
284 		return 0;
285 
286 	key = lua_tostring(L, 2);
287 
288 	if (!strcmp(key, "scale")) {
289 		image->setScale((uint16)lua_tointeger(L, 3));
290 		return 0;
291 	}
292 
293 	return 0;
294 }
295 
296 
nscript_image_get(lua_State * L)297 static int nscript_image_get(lua_State *L) {
298 	CSImage **s_image;
299 	CSImage *image;
300 	const char *key;
301 
302 	s_image = (CSImage **)lua_touserdata(L, 1);
303 	if (s_image == NULL)
304 		return 0;
305 
306 	image = *s_image;
307 	if (image == NULL)
308 		return 0;
309 
310 	key = lua_tostring(L, 2);
311 
312 	if (!strcmp(key, "w")) {
313 		uint16 w, h;
314 		image->shp->get_size(&w, &h);
315 		lua_pushinteger(L, w);
316 		return 1;
317 	}
318 
319 	if (!strcmp(key, "h")) {
320 		uint16 w, h;
321 		image->shp->get_size(&w, &h);
322 		lua_pushinteger(L, h);
323 		return 1;
324 	}
325 
326 	if (!strcmp(key, "scale")) {
327 		lua_pushinteger(L, image->getScale());
328 		return 1;
329 	}
330 
331 	return 0;
332 }
333 
nscript_dec_image_ref_count(CSImage * image)334 static sint32 nscript_dec_image_ref_count(CSImage *image) {
335 	if (image == NULL)
336 		return -1;
337 
338 	image->refcount--;
339 
340 	return image->refcount;
341 }
342 
nscript_image_gc(lua_State * L)343 static int nscript_image_gc(lua_State *L) {
344 	//DEBUG(0, LEVEL_INFORMATIONAL, "\nImage garbage Collection!\n");
345 
346 	CSImage **p_image = (CSImage **)lua_touserdata(L, 1);
347 	CSImage *image;
348 
349 	if (p_image == NULL)
350 		return false;
351 
352 	image = *p_image;
353 
354 	if (nscript_dec_image_ref_count(image) == 0) {
355 		if (image->shp)
356 			delete image->shp;
357 		delete image;
358 	}
359 
360 	return 0;
361 }
362 
nscript_image_new(lua_State * L)363 static int nscript_image_new(lua_State *L) {
364 	uint16 width = lua_tointeger(L, 1);
365 	uint16 height = lua_tointeger(L, 2);
366 
367 	U6Shape *shp = new U6Shape();
368 	if (shp->init(width, height) == false)
369 		return 0;
370 
371 	if (lua_gettop(L) >= 3)
372 		shp->fill((uint8)lua_tointeger(L, 3));
373 
374 	CSImage *image = new CSImage(shp);
375 
376 	nscript_new_image_var(L, image);
377 	return 1;
378 }
379 
nscript_image_new_starfield(lua_State * L)380 static int nscript_image_new_starfield(lua_State *L) {
381 	uint16 width = lua_tointeger(L, 1);
382 	uint16 height = lua_tointeger(L, 2);
383 
384 	U6Shape *shp = new U6Shape();
385 	if (shp->init(width, height) == false)
386 		return 0;
387 
388 	CSStarFieldImage *image = new CSStarFieldImage(shp);
389 
390 	nscript_new_image_var(L, image);
391 	return 1;
392 }
393 
nscript_image_copy(lua_State * L)394 static int nscript_image_copy(lua_State *L) {
395 	CSImage *img = nscript_get_image_from_args(L, 1);
396 	uint16 w, h;
397 
398 	U6Shape *shp = new U6Shape();
399 	img->shp->get_size(&w, &h);
400 	if (shp->init(w, h) == false) {
401 		return 0;
402 	}
403 	shp->blit(img->shp, 0, 0);
404 
405 	CSImage *image = new CSImage(shp);
406 
407 	nscript_new_image_var(L, image);
408 	return 1;
409 }
410 
nscript_image_load(lua_State * L)411 static int nscript_image_load(lua_State *L) {
412 	const char *filename = lua_tostring(L, 1);
413 	int idx = -1;
414 	int sub_idx = 0;
415 
416 	if (lua_gettop(L) >= 2)
417 		idx = lua_tointeger(L, 2);
418 
419 	if (lua_gettop(L) >= 3)
420 		sub_idx = lua_tointeger(L, 3);
421 
422 	CSImage *image = cutScene->load_image(filename, idx, sub_idx);
423 
424 	if (image) {
425 		nscript_new_image_var(L, image);
426 		return 1;
427 	}
428 
429 	return 0;
430 }
431 
nscript_image_load_all(lua_State * L)432 static int nscript_image_load_all(lua_State *L) {
433 	const char *filename = lua_tostring(L, 1);
434 	Std::vector<Std::vector<CSImage *> > images = cutScene->load_all_images(filename);
435 
436 	if (images.empty()) {
437 		return 0;
438 	}
439 
440 	lua_newtable(L);
441 
442 	for (uint16 i = 0; i < images.size(); i++) {
443 		lua_pushinteger(L, i);
444 		if (images[i].size() > 1) {
445 			lua_newtable(L);
446 			for (uint16 j = 0; j < images[i].size(); j++) {
447 				lua_pushinteger(L, j);
448 				nscript_new_image_var(L, images[i][j]);
449 				lua_settable(L, -3);
450 			}
451 		} else {
452 			nscript_new_image_var(L, images[i][0]);
453 		}
454 		lua_settable(L, -3);
455 	}
456 
457 	return 1;
458 }
459 
nscript_image_print(lua_State * L)460 static int nscript_image_print(lua_State *L) {
461 	CSImage *img = nscript_get_image_from_args(L, 1);
462 	const char *text = lua_tostring(L, 2);
463 	uint16 startx = lua_tointeger(L, 3);
464 	uint16 width = lua_tointeger(L, 4);
465 	uint16 x = lua_tointeger(L, 5);
466 	uint16 y = lua_tointeger(L, 6);
467 	uint8 color = lua_tointeger(L, 7);
468 
469 	cutScene->print_text(img, text, &x, &y, startx, width, color);
470 
471 	lua_pushinteger(L, x);
472 	lua_pushinteger(L, y);
473 
474 	return 2;
475 }
476 
nscript_image_draw_line(lua_State * L)477 static int nscript_image_draw_line(lua_State *L) {
478 	CSImage *img = nscript_get_image_from_args(L, 1);
479 	uint16 sx = lua_tointeger(L, 2);
480 	uint16 sy = lua_tointeger(L, 3);
481 	uint16 ex = lua_tointeger(L, 4);
482 	uint16 ey = lua_tointeger(L, 5);
483 	uint8 color = lua_tointeger(L, 6);
484 
485 	if (img) {
486 		img->shp->draw_line(sx, sy, ex, ey, color);
487 	}
488 
489 	return 0;
490 }
491 
nscript_image_blit(lua_State * L)492 static int nscript_image_blit(lua_State *L) {
493 	CSImage *dest_img = nscript_get_image_from_args(L, 1);
494 	CSImage *src_img = nscript_get_image_from_args(L, 2);
495 	uint16 x = lua_tointeger(L, 3);
496 	uint16 y = lua_tointeger(L, 4);
497 
498 	if (dest_img && src_img) {
499 		dest_img->shp->blit(src_img->shp, x, y);
500 	}
501 
502 	return 0;
503 }
nscript_image_update_effect(lua_State * L)504 static int nscript_image_update_effect(lua_State *L) {
505 	CSImage *img = nscript_get_image_from_args(L, 1);
506 	if (img) {
507 		img->updateEffect();
508 	}
509 
510 	return 0;
511 }
512 
513 static uint8 u6_flask_num_colors = 0;
514 static uint8 u6_flask_liquid_colors[8];
515 
nscript_image_bubble_effect_add_color(lua_State * L)516 static int nscript_image_bubble_effect_add_color(lua_State *L) {
517 	if (u6_flask_num_colors != 8) {
518 		u6_flask_liquid_colors[u6_flask_num_colors++] = lua_tointeger(L, 1);
519 	}
520 
521 	return 0;
522 }
523 
nscript_image_bubble_effect(lua_State * L)524 static int nscript_image_bubble_effect(lua_State *L) {
525 	CSImage *img = nscript_get_image_from_args(L, 1);
526 
527 	if (img && u6_flask_num_colors > 0) {
528 		unsigned char *data = img->shp->get_data();
529 		uint16 w, h;
530 		img->shp->get_size(&w, &h);
531 
532 		for (int i = 0; i < w * h; i++) {
533 			if (*data != 0xff) {
534 				*data = u6_flask_liquid_colors[NUVIE_RAND() % u6_flask_num_colors];
535 			}
536 
537 			data++;
538 		}
539 
540 	}
541 	return 0;
542 }
543 
nscript_image_set_transparency_colour(lua_State * L)544 static int nscript_image_set_transparency_colour(lua_State *L) {
545 	CSImage *img = nscript_get_image_from_args(L, 1);
546 	uint8 pal_index = lua_tointeger(L, 2);
547 	if (img) {
548 		unsigned char *data = img->shp->get_data();
549 		uint16 w, h;
550 		img->shp->get_size(&w, &h);
551 		for (int i = 0; i < w * h; i++) {
552 			if (data[i] == pal_index)
553 				data[i] = 0xff;
554 		}
555 	}
556 	return 0;
557 }
558 
nscript_image_static(lua_State * L)559 static int nscript_image_static(lua_State *L) {
560 	CSImage *img = nscript_get_image_from_args(L, 1);
561 
562 	if (img) {
563 		unsigned char *data = img->shp->get_data();
564 		uint16 w, h;
565 		img->shp->get_size(&w, &h);
566 		memset(data, 16, w * h);
567 		for (int i = 0; i < 1000; i++) {
568 			data[NUVIE_RAND() % (w * h)] = 0;
569 		}
570 	}
571 	return 0;
572 }
573 
nscript_get_sprite_from_args(lua_State * L,int lua_stack_offset)574 CSSprite *nscript_get_sprite_from_args(lua_State *L, int lua_stack_offset) {
575 	CSSprite **s_sprite;
576 	CSSprite *sprite;
577 
578 	s_sprite = (CSSprite **)lua_touserdata(L, 1);
579 	if (s_sprite == NULL)
580 		return NULL;
581 
582 	sprite = *s_sprite;
583 	return sprite;
584 }
585 
nscript_new_sprite_var(lua_State * L,CSSprite * sprite)586 bool nscript_new_sprite_var(lua_State *L, CSSprite *sprite) {
587 	CSSprite **userdata;
588 
589 	userdata = (CSSprite **)lua_newuserdata(L, sizeof(CSSprite *));
590 
591 	luaL_getmetatable(L, "nuvie.Sprite");
592 	lua_setmetatable(L, -2);
593 
594 	*userdata = sprite;
595 
596 	return true;
597 }
598 
nscript_sprite_set(lua_State * L)599 static int nscript_sprite_set(lua_State *L) {
600 	CSSprite **s_sprite;
601 	CSSprite *sprite;
602 	const char *key;
603 
604 	s_sprite = (CSSprite **)lua_touserdata(L, 1);
605 	if (s_sprite == NULL)
606 		return 0;
607 
608 	sprite = *s_sprite;
609 	if (sprite == NULL)
610 		return 0;
611 
612 	key = lua_tostring(L, 2);
613 
614 	if (!strcmp(key, "x")) {
615 		sprite->x = lua_tointeger(L, 3);
616 		return 0;
617 	}
618 
619 	if (!strcmp(key, "y")) {
620 		sprite->y = lua_tointeger(L, 3);
621 		return 0;
622 	}
623 
624 	if (!strcmp(key, "opacity")) {
625 		int opacity = lua_tointeger(L, 3);
626 		sprite->opacity = (uint8)clamp(opacity, 0, 255);
627 		return 0;
628 	}
629 
630 	if (!strcmp(key, "visible")) {
631 		sprite->visible = lua_toboolean(L, 3);
632 		return 0;
633 	}
634 
635 	if (!strcmp(key, "image")) {
636 		if (sprite->image) {
637 			sprite->image->refcount--;
638 			if (sprite->image->refcount == 0)
639 				delete sprite->image;
640 		}
641 
642 		sprite->image = nscript_get_image_from_args(L, 3);
643 		if (sprite->image)
644 			sprite->image->refcount++;
645 
646 		return 0;
647 	}
648 
649 	if (!strcmp(key, "clip_x")) {
650 		sprite->clip_rect.left = lua_tointeger(L, 3) + cutScene->get_x_off();
651 		return 0;
652 	}
653 
654 	if (!strcmp(key, "clip_y")) {
655 		sprite->clip_rect.top = lua_tointeger(L, 3) + cutScene->get_y_off();
656 		return 0;
657 	}
658 
659 	if (!strcmp(key, "clip_w")) {
660 		sprite->clip_rect.setWidth(lua_tointeger(L, 3));
661 		return 0;
662 	}
663 
664 	if (!strcmp(key, "clip_h")) {
665 		sprite->clip_rect.setHeight(lua_tointeger(L, 3));
666 		return 0;
667 	}
668 	if (!strcmp(key, "text")) {
669 		const char *text = lua_tostring(L, 3);
670 		sprite->text = Std::string(text);
671 	}
672 	if (!strcmp(key, "text_color")) {
673 		sprite->text_color = lua_tointeger(L, 3);
674 		return 0;
675 	}
676 	if (!strcmp(key, "text_align")) {
677 		int align_val = lua_tointeger(L, 3);
678 		sprite->text_align = (uint8) align_val;
679 		return 0;
680 	}
681 	return 0;
682 }
683 
684 
nscript_sprite_get(lua_State * L)685 static int nscript_sprite_get(lua_State *L) {
686 	CSSprite **s_sprite;
687 	CSSprite *sprite;
688 	const char *key;
689 
690 	s_sprite = (CSSprite **)lua_touserdata(L, 1);
691 	if (s_sprite == NULL)
692 		return 0;
693 
694 	sprite = *s_sprite;
695 	if (sprite == NULL)
696 		return 0;
697 
698 	key = lua_tostring(L, 2);
699 
700 	if (!strcmp(key, "x")) {
701 		lua_pushinteger(L, sprite->x);
702 		return 1;
703 	}
704 
705 	if (!strcmp(key, "y")) {
706 		lua_pushinteger(L, sprite->y);
707 		return 1;
708 	}
709 
710 	if (!strcmp(key, "opacity")) {
711 		lua_pushinteger(L, sprite->opacity);
712 		return 1;
713 	}
714 
715 	if (!strcmp(key, "visible")) {
716 		lua_pushboolean(L, sprite->visible);
717 		return 1;
718 	}
719 
720 	if (!strcmp(key, "image")) {
721 		if (sprite->image) {
722 			nscript_new_image_var(L, sprite->image);
723 			return 1;
724 		}
725 	}
726 
727 	if (!strcmp(key, "text")) {
728 		lua_pushstring(L, sprite->text.c_str());
729 		return 1;
730 	}
731 
732 	if (!strcmp(key, "text_color")) {
733 		lua_pushinteger(L, sprite->text_color);
734 		return 1;
735 	}
736 
737 	if (!strcmp(key, "text_width")) {
738 		lua_pushinteger(L, cutScene->get_text_width(sprite->text.c_str()));
739 		return 1;
740 	}
741 
742 	return 0;
743 }
744 
nscript_sprite_gc(lua_State * L)745 static int nscript_sprite_gc(lua_State *L) {
746 	//DEBUG(0, LEVEL_INFORMATIONAL, "\nSprite garbage Collection!\n");
747 
748 	CSSprite **p_sprite = (CSSprite **)lua_touserdata(L, 1);
749 	CSSprite *sprite;
750 
751 	if (p_sprite == NULL)
752 		return false;
753 
754 	sprite = *p_sprite;
755 
756 	if (sprite) {
757 		if (sprite->image) {
758 			if (nscript_dec_image_ref_count(sprite->image) == 0)
759 				delete sprite->image;
760 		}
761 		cutScene->remove_sprite(sprite);
762 		delete sprite;
763 	}
764 
765 	return 0;
766 }
767 
nscript_sprite_new(lua_State * L)768 static int nscript_sprite_new(lua_State *L) {
769 	CSSprite *sprite = new CSSprite();
770 
771 	if (lua_gettop(L) >= 1 && !lua_isnil(L, 1)) {
772 		sprite->image = nscript_get_image_from_args(L, 1);
773 		if (sprite->image)
774 			sprite->image->refcount++;
775 	}
776 
777 	if (lua_gettop(L) >= 2 && !lua_isnil(L, 2)) {
778 		sprite->x = lua_tointeger(L, 2);
779 	}
780 
781 	if (lua_gettop(L) >= 3 && !lua_isnil(L, 3)) {
782 		sprite->y = lua_tointeger(L, 3);
783 	}
784 
785 	if (lua_gettop(L) >= 4 && !lua_isnil(L, 4)) {
786 		sprite->visible = lua_toboolean(L, 4);
787 	}
788 
789 	cutScene->add_sprite(sprite);
790 
791 	nscript_new_sprite_var(L, sprite);
792 	return 1;
793 }
794 
nscript_sprite_move_to_front(lua_State * L)795 static int nscript_sprite_move_to_front(lua_State *L) {
796 	CSSprite *sprite = nscript_get_sprite_from_args(L, 1);
797 	if (sprite) {
798 		cutScene->remove_sprite(sprite);
799 		cutScene->add_sprite(sprite);
800 	}
801 
802 	return 0;
803 }
804 
nscript_text_load(lua_State * L)805 static int nscript_text_load(lua_State *L) {
806 	const char *filename = lua_tostring(L, 1);
807 	uint8 idx = lua_tointeger(L, 2);
808 
809 	Std::vector<Std::string> text = cutScene->load_text(filename, idx);
810 
811 	if (text.empty()) {
812 		return 0;
813 	}
814 
815 	lua_newtable(L);
816 
817 	for (uint16 i = 0; i < text.size(); i++) {
818 		lua_pushinteger(L, i);
819 		lua_pushstring(L, text[i].c_str());
820 		lua_settable(L, -3);
821 	}
822 
823 	return 1;
824 }
825 
nscript_midgame_load(lua_State * L)826 static int nscript_midgame_load(lua_State *L) {
827 	const char *filename = lua_tostring(L, 1);
828 	Std::vector<CSMidGameData> v = cutScene->load_midgame_file(filename);
829 
830 	if (v.empty()) {
831 		return 0;
832 	}
833 
834 	lua_newtable(L);
835 
836 	for (uint16 i = 0; i < v.size(); i++) {
837 		lua_pushinteger(L, i);
838 
839 		lua_newtable(L);
840 
841 		lua_pushstring(L, "text");
842 		lua_newtable(L);
843 		for (uint16 j = 0; j < v[i].text.size(); j++) {
844 			lua_pushinteger(L, j);
845 			lua_pushstring(L, v[i].text[j].c_str());
846 			lua_settable(L, -3);
847 		}
848 		lua_settable(L, -3);
849 
850 		lua_pushstring(L, "images");
851 		lua_newtable(L);
852 		for (uint16 j = 0; j < v[i].images.size(); j++) {
853 			lua_pushinteger(L, j);
854 			nscript_new_image_var(L, v[i].images[j]);
855 			lua_settable(L, -3);
856 		}
857 		lua_settable(L, -3);
858 
859 		lua_settable(L, -3);
860 	}
861 
862 	return 1;
863 }
864 
nscript_canvas_set_bg_color(lua_State * L)865 static int nscript_canvas_set_bg_color(lua_State *L) {
866 	uint8 color = lua_tointeger(L, 1);
867 	cutScene->set_bg_color(color);
868 
869 	return 0;
870 }
871 
nscript_canvas_set_palette(lua_State * L)872 static int nscript_canvas_set_palette(lua_State *L) {
873 	const char *filename = lua_tostring(L, 1);
874 	uint8 idx = lua_tointeger(L, 2);
875 
876 	cutScene->load_palette(filename, idx);
877 
878 	return 0;
879 }
880 
nscript_canvas_set_palette_entry(lua_State * L)881 static int nscript_canvas_set_palette_entry(lua_State *L) {
882 	uint8 idx = lua_tointeger(L, 1);
883 	uint8 r = lua_tointeger(L, 2);
884 	uint8 g = lua_tointeger(L, 3);
885 	uint8 b = lua_tointeger(L, 4);
886 
887 	cutScene->set_palette_entry(idx, r, g, b);
888 
889 	return 0;
890 }
891 
nscript_canvas_rotate_palette(lua_State * L)892 static int nscript_canvas_rotate_palette(lua_State *L) {
893 	uint8 idx = lua_tointeger(L, 1);
894 	uint8 len = lua_tointeger(L, 2);
895 
896 	cutScene->rotate_palette(idx, len);
897 
898 	return 0;
899 }
900 
nscript_canvas_set_update_interval(lua_State * L)901 static int nscript_canvas_set_update_interval(lua_State *L) {
902 	uint16 loop_interval = lua_tointeger(L, 1);
903 
904 	cutScene->set_update_interval(loop_interval);
905 	return 0;
906 }
907 
nscript_canvas_set_solid_bg(lua_State * L)908 static int nscript_canvas_set_solid_bg(lua_State *L) {
909 	bool solid_bg = lua_toboolean(L, 1);
910 	cutScene->set_solid_bg(solid_bg);
911 	return 0;
912 }
913 
nscript_canvas_set_opacity(lua_State * L)914 static int nscript_canvas_set_opacity(lua_State *L) {
915 	uint8 opacity = lua_tointeger(L, 1);
916 
917 	cutScene->set_screen_opacity(opacity);
918 	return 0;
919 }
920 
nscript_canvas_update(lua_State * L)921 static int nscript_canvas_update(lua_State *L) {
922 	cutScene->update();
923 	return 0;
924 }
925 
nscript_canvas_show(lua_State * L)926 static int nscript_canvas_show(lua_State *L) {
927 	cutScene->moveToFront();
928 	return 0;
929 }
930 
nscript_canvas_hide(lua_State * L)931 static int nscript_canvas_hide(lua_State *L) {
932 	cutScene->Hide();
933 	return 0;
934 }
935 
nscript_canvas_hide_all_sprites(lua_State * L)936 static int nscript_canvas_hide_all_sprites(lua_State *L) {
937 	cutScene->hide_sprites();
938 	return 0;
939 }
940 
nscript_canvas_string_length(lua_State * L)941 static int nscript_canvas_string_length(lua_State *L) {
942 	Font *font = cutScene->get_font();
943 	const char *str = lua_tostring(L, 1);
944 
945 	lua_pushinteger(L, font->getStringWidth(str));
946 	return 1;
947 }
948 
nscript_canvas_rotate_game_palette(lua_State * L)949 static int nscript_canvas_rotate_game_palette(lua_State *L) {
950 	bool val = lua_toboolean(L, 1);
951 	cutScene->enable_game_palette_rotation(val);
952 	return 0;
953 }
954 
nscript_music_play(lua_State * L)955 static int nscript_music_play(lua_State *L) {
956 	uint16 song_num = 0;
957 	const char *filename = lua_tostring(L, 1);
958 
959 	if (lua_gettop(L) >= 2 && !lua_isnil(L, 2)) {
960 		song_num = lua_tointeger(L, 2);
961 	}
962 
963 	cutScene->get_sound_manager()->musicPlay(filename, song_num);
964 
965 	return 0;
966 }
967 
nscript_music_stop(lua_State * L)968 static int nscript_music_stop(lua_State *L) {
969 	cutScene->get_sound_manager()->musicStop();
970 
971 	return 0;
972 }
973 
nscript_get_mouse_x(lua_State * L)974 static int nscript_get_mouse_x(lua_State *L) {
975 	int x, y;
976 	cutScene->get_screen()->get_mouse_location(&x, &y);
977 	x -= cutScene->get_x_off();
978 	lua_pushinteger(L, x);
979 	return 1;
980 }
981 
nscript_get_mouse_y(lua_State * L)982 static int nscript_get_mouse_y(lua_State *L) {
983 	int x, y;
984 	cutScene->get_screen()->get_mouse_location(&x, &y);
985 	y -= cutScene->get_y_off();
986 	lua_pushinteger(L, y);
987 	return 1;
988 }
989 
nscript_input_poll(lua_State * L)990 static int nscript_input_poll(lua_State *L) {
991 	Common::Event event;
992 	bool poll_mouse_motion;
993 	if (lua_isnil(L, 1))
994 		poll_mouse_motion = false;
995 	else
996 		poll_mouse_motion = lua_toboolean(L, 1);
997 
998 	while (Events::get()->pollEvent(event)) {
999 		//FIXME do something here.
1000 		KeyBinder *keybinder = Game::get_game()->get_keybinder();
1001 
1002 		if (event.type == Common::EVENT_JOYAXIS_MOTION ||
1003 				event.type == Common::EVENT_JOYBUTTON_DOWN ||
1004 				event.type == Common::EVENT_JOYBUTTON_UP) {
1005 			event.kbd.flags = 0;
1006 			event.kbd.keycode = keybinder->get_key_from_joy_events(&event);
1007 			if (event.kbd.keycode == Common::KEYCODE_INVALID)
1008 				// button isn't mapped or was in deadzone
1009 				return 0; // pretend nothing happened
1010 
1011 			event.type = Common::EVENT_KEYDOWN;
1012 		}
1013 
1014 		if (event.type == Common::EVENT_KEYDOWN) {
1015 			Common::KeyState key = event.kbd;
1016 
1017 			if ((((key.flags & Common::KBD_CAPS) == Common::KBD_CAPS
1018 					&& (key.flags & Common::KBD_SHIFT) == 0) || ((key.flags & Common::KBD_CAPS) == 0 && (key.flags & Common::KBD_SHIFT)))
1019 			        && key.keycode >= Common::KEYCODE_a && key.keycode <= Common::KEYCODE_z)
1020 				key.keycode = (Common::KeyCode)(key.keycode - 32);
1021 			if (key.keycode > 0xFF || !Common::isPrint((char)key.keycode) || (key.flags & Common::KBD_ALT) || (key.flags & Common::KBD_CTRL)) {
1022 				ActionType a = keybinder->get_ActionType(key);
1023 				switch (keybinder->GetActionKeyType(a)) {
1024 				case WEST_KEY:
1025 					lua_pushinteger(L, INPUT_KEY_LEFT);
1026 					return 1;
1027 				case EAST_KEY:
1028 					lua_pushinteger(L, INPUT_KEY_RIGHT);
1029 					return 1;
1030 				case SOUTH_KEY:
1031 					lua_pushinteger(L, INPUT_KEY_DOWN);
1032 					return 1;
1033 				case NORTH_KEY:
1034 					lua_pushinteger(L, INPUT_KEY_UP);
1035 					return 1;
1036 				case CANCEL_ACTION_KEY:
1037 					key.keycode = Common::KEYCODE_ESCAPE;
1038 					break;
1039 				case DO_ACTION_KEY:
1040 					key.keycode = Common::KEYCODE_RETURN;
1041 					break;
1042 				default:
1043 					if (keybinder->handle_always_available_keys(a)) return 0;
1044 					break;
1045 				}
1046 			}
1047 			lua_pushinteger(L, key.keycode);
1048 			return 1;
1049 		}
1050 		if (event.type == Common::EVENT_QUIT) {
1051 			lua_pushinteger(L, 'Q');
1052 			return 1;
1053 		}
1054 
1055 		if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_RBUTTONDOWN) {
1056 			lua_pushinteger(L, 0);
1057 			return 1;
1058 		}
1059 		if (poll_mouse_motion && event.type == Common::EVENT_MOUSEMOVE) {
1060 			lua_pushinteger(L, 1);
1061 			return 1;
1062 		}
1063 	}
1064 
1065 	return 0;
1066 }
1067 
nscript_config_set(lua_State * L)1068 static int nscript_config_set(lua_State *L) {
1069 	const char *config_key = lua_tostring(L, 1);
1070 
1071 	if (lua_isstring(L, 2)) {
1072 		cutScene->get_config()->set(config_key, lua_tostring(L, 2));
1073 	} else if (lua_isnumber(L, 2)) {
1074 		cutScene->get_config()->set(config_key, (int)lua_tointeger(L, 2));
1075 	} else if (lua_isboolean(L, 2)) {
1076 		cutScene->get_config()->set(config_key, (bool)lua_toboolean(L, 2));
1077 	}
1078 
1079 	return 0;
1080 }
1081 
nscript_engine_should_quit(lua_State * L)1082 static int nscript_engine_should_quit(lua_State *L) {
1083 	int x = g_engine->shouldQuit();
1084 	lua_pushinteger(L, x);
1085 	return 1;
1086 }
1087 
ScriptCutscene(GUI * g,Configuration * cfg,SoundManager * sm)1088 ScriptCutscene::ScriptCutscene(GUI *g, Configuration *cfg, SoundManager *sm) : GUI_Widget(NULL) {
1089 	config = cfg;
1090 	gui = g;
1091 
1092 	cursor = Game::get_game()->get_cursor();
1093 	x_off = Game::get_game()->get_game_x_offset();
1094 	y_off = Game::get_game()->get_game_y_offset();
1095 
1096 	x_off += (Game::get_game()->get_game_width() - 320) / 2; // center it
1097 	y_off += (Game::get_game()->get_game_height() - 200) / 2; // center it
1098 
1099 	nuvie_game_t game_type = Game::get_game()->get_game_type();
1100 
1101 	GUI_Widget::Init(NULL, 0, 0, g->get_width(), g->get_height());
1102 
1103 	clip_rect = Common::Rect(x_off, y_off, x_off + 320, y_off + 200);
1104 	screen = g->get_screen();
1105 	gui->AddWidget(this);
1106 	Hide();
1107 	sound_manager = sm;
1108 
1109 	//FIXME this should be loaded by script.
1110 	Std::string path;
1111 
1112 
1113 	font = new WOUFont();
1114 
1115 	if (game_type == NUVIE_GAME_U6) {
1116 		config_get_path(config, "u6.set", path);
1117 		font->init(path.c_str());
1118 	}
1119 	//FIXME load other fonts for MD / SE if needed here.
1120 	if (game_type == NUVIE_GAME_SE) {
1121 		Std::string filePath;
1122 		U6Lib_n lib_file;
1123 
1124 		config_get_path(config, "savage.fnt", filePath);
1125 
1126 		lib_file.open(filePath, 4, NUVIE_GAME_SE); //can be either SE or MD just as long as it isn't set to U6 type.
1127 
1128 		unsigned char *buf = lib_file.get_item(0);
1129 		font->initWithBuffer(buf, lib_file.get_item_size(0)); //buf will be freed by ~Font()
1130 	}
1131 
1132 	if (game_type == NUVIE_GAME_MD) {
1133 		Std::string filePath;
1134 		U6Lib_n lib_file;
1135 
1136 		config_get_path(config, "fonts.lzc", filePath);
1137 
1138 		lib_file.open(filePath, 4, NUVIE_GAME_MD);
1139 
1140 		unsigned char *buf = lib_file.get_item(0);
1141 		font->initWithBuffer(buf, lib_file.get_item_size(0)); //buf will be freed by ~Font()
1142 	}
1143 	next_time = 0;
1144 	loop_interval = 40;
1145 
1146 	screen_opacity = 255;
1147 	bg_color = 0;
1148 	solid_bg = true;
1149 	rotate_game_palette = false;
1150 	palette = NULL;
1151 }
1152 
~ScriptCutscene()1153 ScriptCutscene::~ScriptCutscene() {
1154 	delete font;
1155 }
1156 
is_lzc(const char * filename)1157 bool ScriptCutscene::is_lzc(const char *filename) {
1158 	if (strlen(filename) > 4 && scumm_stricmp((const char *)&filename[strlen(filename) - 4], ".lzc") == 0)
1159 		return true;
1160 
1161 	return false;
1162 }
1163 
load_image_from_lzc(Std::string filename,uint16 idx,uint16 sub_idx)1164 CSImage *ScriptCutscene::load_image_from_lzc(Std::string filename, uint16 idx, uint16 sub_idx) {
1165 	CSImage *image = nullptr;
1166 	U6Lib_n lib_n;
1167 	unsigned char *buf = NULL;
1168 
1169 	if (!lib_n.open(filename, 4, NUVIE_GAME_MD)) {
1170 		return NULL;
1171 	}
1172 
1173 	if (idx >= lib_n.get_num_items()) {
1174 		return NULL;
1175 	}
1176 
1177 	buf = lib_n.get_item(idx, NULL);
1178 	NuvieIOBuffer io;
1179 	io.open(buf, lib_n.get_item_size(idx), false);
1180 	U6Lib_n lib1;
1181 	lib1.open(&io, 4, NUVIE_GAME_MD);
1182 
1183 	if (sub_idx >= lib1.get_num_items()) {
1184 		return NULL;
1185 	}
1186 
1187 	U6Shape *shp = new U6Shape();
1188 	if (shp->load(&lib1, (uint32)sub_idx)) {
1189 		image = new CSImage(shp);
1190 	}
1191 
1192 	free(buf);
1193 
1194 	return image;
1195 }
1196 
load_image(const char * filename,int idx,int sub_idx)1197 CSImage *ScriptCutscene::load_image(const char *filename, int idx, int sub_idx) {
1198 	U6Lib_n lib_n;
1199 	Std::string path;
1200 	CSImage *image = NULL;
1201 
1202 	config_get_path(config, filename, path);
1203 
1204 	if (is_lzc(filename)) {
1205 		return load_image_from_lzc(path, (uint16)idx, (uint16)sub_idx);
1206 	}
1207 
1208 	U6Shape *shp = new U6Shape();
1209 
1210 	if (idx >= 0) {
1211 		U6Lzw lzw;
1212 
1213 		uint32 decomp_size;
1214 		unsigned char *buf = lzw.decompress_file(path.c_str(), decomp_size);
1215 		NuvieIOBuffer io;
1216 		io.open(buf, decomp_size, false);
1217 		{
1218 			// Note: libN needs to be destroyed before the io object.
1219 			U6Lib_n libN;
1220 			if (libN.open(&io, 4, NUVIE_GAME_MD)) {
1221 				if (shp->load(&libN, (uint32)idx)) {
1222 					image = new CSImage(shp);
1223 				}
1224 			}
1225 		}
1226 		free(buf);
1227 	} else {
1228 		if (shp->load(path)) {
1229 			image = new CSImage(shp);
1230 		}
1231 	}
1232 
1233 	if (image == NULL)
1234 		delete shp;
1235 
1236 	return image;
1237 }
1238 
load_all_images(const char * filename)1239 Std::vector<Std::vector<CSImage *> > ScriptCutscene::load_all_images(const char *filename) {
1240 	Std::string path;
1241 	CSImage *image = NULL;
1242 
1243 	config_get_path(config, filename, path);
1244 
1245 	Std::vector<Std::vector<CSImage *> > v;
1246 	U6Lzw lzw;
1247 
1248 	U6Lib_n lib_n;
1249 	unsigned char *buf = NULL;
1250 
1251 	if (is_lzc(filename)) {
1252 		if (!lib_n.open(path, 4, NUVIE_GAME_MD)) {
1253 			return v;
1254 		}
1255 		for (uint32 idx = 0; idx < lib_n.get_num_items(); idx++) {
1256 			buf = lib_n.get_item(idx, NULL);
1257 			NuvieIOBuffer io;
1258 			io.open(buf, lib_n.get_item_size(idx), false);
1259 			U6Lib_n lib1;
1260 			lib1.open(&io, 4, NUVIE_GAME_MD);
1261 			//printf("lib_size = %d\n", lib1.get_num_items());
1262 			Std::vector<CSImage *> v1;
1263 			for (uint32 idx1 = 0; idx1 < lib1.get_num_items(); idx1++) {
1264 				U6Shape *shp = new U6Shape();
1265 				if (shp->load(&lib1, (uint32)idx1)) {
1266 					image = new CSImage(shp);
1267 					v1.push_back(image);
1268 				}
1269 			}
1270 			free(buf);
1271 			buf = NULL;
1272 			v.push_back(v1);
1273 		}
1274 	} else {
1275 		uint32 decomp_size;
1276 		buf = lzw.decompress_file(path.c_str(), decomp_size);
1277 		NuvieIOBuffer io;
1278 		io.open(buf, decomp_size, false);
1279 		if (!lib_n.open(&io, 4, NUVIE_GAME_MD)) {
1280 			free(buf);
1281 			return v;
1282 		}
1283 
1284 		for (uint32 idx = 0; idx < lib_n.get_num_items(); idx++) {
1285 			Std::vector<CSImage *> v1;
1286 			U6Shape *shp = new U6Shape();
1287 			if (shp->load(&lib_n, (uint32)idx)) {
1288 				image = new CSImage(shp);
1289 				v1.push_back(image);
1290 				v.push_back(v1);
1291 			}
1292 		}
1293 
1294 		lib_n.close();
1295 	}
1296 
1297 	if (buf)
1298 		free(buf);
1299 
1300 	return v;
1301 
1302 }
1303 
load_images_from_lib(Std::vector<CSImage * > * images,U6Lib_n * lib,uint32 index)1304 void load_images_from_lib(Std::vector<CSImage *> *images, U6Lib_n *lib, uint32 index) {
1305 	unsigned char *buf = lib->get_item(index, NULL);
1306 	if (buf == NULL) {
1307 		return;
1308 	}
1309 
1310 	NuvieIOBuffer io;
1311 	io.open(buf, lib->get_item_size(index), false);
1312 	U6Lib_n lib1;
1313 	lib1.open(&io, 4, NUVIE_GAME_MD);
1314 
1315 	for (uint16 i = 0; i < lib1.get_num_items(); i++) {
1316 		U6Shape *shp = new U6Shape();
1317 		if (shp->load(&lib1, i)) {
1318 			images->push_back(new CSImage(shp));
1319 		}
1320 	}
1321 	free(buf);
1322 }
1323 
load_midgame_file(const char * filename)1324 Std::vector<CSMidGameData> ScriptCutscene::load_midgame_file(const char *filename) {
1325 	Std::string path;
1326 	U6Lib_n lib_n;
1327 	Std::vector<CSMidGameData> v;
1328 	nuvie_game_t game_type = Game::get_game()->get_game_type();
1329 
1330 	config_get_path(config, filename, path);
1331 
1332 	if (!lib_n.open(path, 4, NUVIE_GAME_MD)) {
1333 		return v;
1334 	}
1335 
1336 	for (uint32 idx = 0; idx < lib_n.get_num_items();) {
1337 		if (game_type == NUVIE_GAME_MD && idx == 0) { //Skip the first entry in the lib for MD it is *bogus*
1338 			idx++;
1339 			continue;
1340 		}
1341 
1342 		CSMidGameData data;
1343 		for (int i = 0; i < 3; i++, idx++) {
1344 			unsigned char *buf = lib_n.get_item(idx, NULL);
1345 			data.text.push_back(string((const char *)buf));
1346 			free(buf);
1347 		}
1348 
1349 		load_images_from_lib(&data.images, &lib_n, idx++);
1350 
1351 		if (game_type == NUVIE_GAME_MD) {
1352 			load_images_from_lib(&data.images, &lib_n, idx++);
1353 		}
1354 
1355 		v.push_back(data);
1356 	}
1357 
1358 	return v;
1359 }
1360 
load_text(const char * filename,uint8 idx)1361 Std::vector<Std::string> ScriptCutscene::load_text(const char *filename, uint8 idx) {
1362 	Std::string path;
1363 	U6Lib_n lib_n;
1364 	Std::vector<string> v;
1365 	unsigned char *buf = NULL;
1366 
1367 	config_get_path(config, filename, path);
1368 
1369 	if (!lib_n.open(path, 4, NUVIE_GAME_MD) || idx >= lib_n.get_num_items()) {
1370 		return v;
1371 	}
1372 
1373 	buf = lib_n.get_item(idx, NULL);
1374 	uint16 len = lib_n.get_item_size(idx);
1375 	if (buf != NULL) {
1376 		uint16 start = 0;
1377 		for (uint16 i = 0; i < len; i++) {
1378 			if (buf[i] == '\r') {
1379 				buf[i] = '\0';
1380 				v.push_back(string((const char *)&buf[start]));
1381 				i++;
1382 				buf[i] = '\0'; // skip the '\n' character
1383 				start = i + 1;
1384 			}
1385 		}
1386 
1387 		free(buf);
1388 	}
1389 
1390 	return v;
1391 }
1392 
print_text(CSImage * image,const char * s,uint16 * x,uint16 * y,uint16 startx,uint16 width,uint8 color)1393 void ScriptCutscene::print_text(CSImage *image, const char *s, uint16 *x, uint16 *y, uint16 startx, uint16 width, uint8 color) {
1394 	int len = *x - startx;
1395 	size_t start = 0;
1396 	size_t found;
1397 	Std::string str = s;
1398 	Std::list<Std::string> tokens;
1399 	int space_width = font->getStringWidth(" ");
1400 	//uint16 x1 = startx;
1401 
1402 	found = str.findFirstOf(" ", start);
1403 	while (found != string::npos) {
1404 		Std::string token = str.substr(start, found - start);
1405 
1406 		int token_len = font->getStringWidth(token.c_str());
1407 
1408 		if (len + token_len + space_width > width) {
1409 			//FIXME render line here.
1410 			list<Std::string>::iterator it;
1411 			int new_space = 0;
1412 			if (tokens.size() > 1)
1413 				new_space = floor((width - (len - space_width * (tokens.size() - 1))) / (tokens.size() - 1));
1414 
1415 			for (it = tokens.begin() ; it != tokens.end() ; it++) {
1416 				*x = ((WOUFont *)font)->drawStringToShape(image->shp, (*it).c_str(), *x, *y, color);
1417 				*x += new_space;
1418 			}
1419 			*y += 8;
1420 			*x = startx;
1421 			len = token_len + space_width;
1422 			tokens.clear();
1423 			tokens.push_back(token);
1424 		} else {
1425 			tokens.push_back(token);
1426 			len += token_len + space_width;
1427 		}
1428 
1429 		start = found + 1;
1430 		found = str.findFirstOf(" ", start);
1431 	}
1432 
1433 	list<Std::string>::iterator it;
1434 
1435 	for (it = tokens.begin() ; it != tokens.end() ; it++) {
1436 		*x = ((WOUFont *)font)->drawStringToShape(image->shp, (*it).c_str(), *x, *y, color);
1437 		*x += space_width;
1438 	}
1439 
1440 	if (start < str.length()) {
1441 		Std::string token = str.substr(start, str.length() - start);
1442 		if (len + font->getStringWidth(token.c_str()) > width) {
1443 			*y += 8;
1444 			*x = startx;
1445 		}
1446 		*x = ((WOUFont *)font)->drawStringToShape(image->shp, token.c_str(), *x, *y, color);
1447 	}
1448 
1449 
1450 	//font->drawStringToShape(image->shp, string, x, y, color);
1451 }
1452 
load_palette(const char * filename,int idx)1453 void ScriptCutscene::load_palette(const char *filename, int idx) {
1454 	NuvieIOFileRead file;
1455 	uint8 buf[0x240 + 1];
1456 	uint8 unpacked_palette[0x300];
1457 	Std::string path;
1458 
1459 	config_get_path(config, filename, path);
1460 
1461 
1462 	if (file.open(path.c_str()) == false) {
1463 		DEBUG(0, LEVEL_ERROR, "loading palette.\n");
1464 		return;
1465 	}
1466 
1467 	if (file.read4() == DELUXE_PAINT_MAGIC || has_file_extension(filename, ".lbm")) {
1468 		//deluxe paint palette file.
1469 		file.seek(0x30);
1470 		file.readToBuf(unpacked_palette, 0x300);
1471 	} else if (has_file_extension(filename, ".pal")) {
1472 		U6Lib_n lib;
1473 		lib.open(path, 4, NUVIE_GAME_MD);
1474 		unsigned char *decomp_buf = lib.get_item(0, NULL);
1475 		memcpy(unpacked_palette, &decomp_buf[idx * 0x300], 0x300);
1476 
1477 		free(decomp_buf);
1478 	} else {
1479 		file.seek(idx * 0x240);
1480 
1481 		file.readToBuf(buf, 0x240);
1482 		buf[0x240] = 0; //protect from buf[byte_pos+1] overflow when processing last byte of data.
1483 
1484 		for (int i = 0; i < 0x100; i++) {
1485 			for (int j = 0; j < 3; j++) {
1486 				int byte_pos = (i * 3 * 6 + j * 6) / 8;
1487 				int shift_val = (i * 3 * 6 + j * 6) % 8;
1488 				int color = ((buf[byte_pos] +
1489 				              (buf[byte_pos + 1] << 8))
1490 				             >> shift_val) & 0x3F;
1491 				unpacked_palette[i * 3 + j] = (uint8)(color << 2);
1492 			}
1493 		}
1494 	}
1495 
1496 	/*
1497 	printf("GIMP Palette\nName: U6 ending\n#\n");
1498 	for (int i = 0; i < 0x100; i++)
1499 	{
1500 	    for (int j = 0; j < 3; j++)
1501 	    {
1502 	        printf("% 3d ", unpacked_palette[i*3+j]);
1503 	    }
1504 	    printf(" untitled\n");
1505 	}
1506 	*/
1507 	screen->set_palette(unpacked_palette);
1508 }
1509 
set_palette_entry(uint8 idx,uint8 r,uint8 g,uint8 b)1510 void ScriptCutscene::set_palette_entry(uint8 idx, uint8 r, uint8 g, uint8 b) {
1511 	screen->set_palette_entry(idx, r, g, b);
1512 }
1513 
rotate_palette(uint8 idx,uint8 length)1514 void ScriptCutscene::rotate_palette(uint8 idx, uint8 length) {
1515 	screen->rotate_palette(idx, length);
1516 }
1517 
set_update_interval(uint16 interval)1518 void ScriptCutscene::set_update_interval(uint16 interval) {
1519 	loop_interval = interval;
1520 }
1521 
set_screen_opacity(uint8 new_opacity)1522 void ScriptCutscene::set_screen_opacity(uint8 new_opacity) {
1523 	screen_opacity = new_opacity;
1524 }
1525 
hide_sprites()1526 void ScriptCutscene::hide_sprites() {
1527 	for (Std::list<CSSprite *>::iterator it = sprite_list.begin(); it != sprite_list.end(); it++) {
1528 		CSSprite *s = *it;
1529 		if (s->visible)
1530 			s->visible = false;
1531 	}
1532 }
1533 
update()1534 void ScriptCutscene::update() {
1535 	if (cutScene->Status() == WIDGET_HIDDEN) {
1536 		cutScene->Show();
1537 		gui->force_full_redraw();
1538 	}
1539 
1540 	if (rotate_game_palette) {
1541 		GamePalette *pal = Game::get_game()->get_palette();
1542 		if (pal) {
1543 			pal->rotatePalette();
1544 		}
1545 	}
1546 	gui->Display();
1547 	screen->preformUpdate();
1548 	sound_manager->update();
1549 	wait();
1550 }
1551 
wait()1552 void ScriptCutscene::wait() {
1553 	uint32 now = SDL_GetTicks();
1554 	if (next_time <= now) {
1555 		next_time = now + loop_interval;
1556 		return;
1557 	}
1558 
1559 	uint32 delay = next_time - now;
1560 	next_time += loop_interval;
1561 	g_system->delayMillis(delay);
1562 }
1563 
1564 /* Show the widget  */
Display(bool full_redraw)1565 void ScriptCutscene::Display(bool full_redraw) {
1566 	if (cursor && cursor->is_visible())
1567 		cursor->clear();
1568 
1569 	if (solid_bg) {
1570 		if (full_redraw)
1571 			screen->fill(bg_color, 0, 0, area.width(), area.height());
1572 		else
1573 			screen->fill(bg_color, x_off, y_off, 320, 200);
1574 	}
1575 
1576 	if (screen_opacity > 0) {
1577 		for (Std::list<CSSprite *>::iterator it = sprite_list.begin(); it != sprite_list.end(); it++) {
1578 			CSSprite *s = *it;
1579 			if (s->visible) {
1580 				if (s->image) {
1581 					uint16 w, h;
1582 					s->image->shp->get_size(&w, &h);
1583 					uint16 x, y;
1584 					s->image->shp->get_hot_point(&x, &y);
1585 					screen->blit(x_off + s->x - x, y_off + s->y - y, s->image->shp->get_data(), 8, w, h, w, true, s->clip_rect.width() != 0 ? &s->clip_rect : &clip_rect, s->opacity);
1586 				}
1587 
1588 				if (s->text.length() > 0) {
1589 					if (s->text_align != 0) {
1590 						display_wrapped_text(s);
1591 					} else {
1592 						if (s->text_color == 0xffff) {
1593 							font->drawString(screen, s->text.c_str(), s->x + x_off, s->y + y_off);
1594 						} else {
1595 							font->drawString(screen, s->text.c_str(), s->x + x_off, s->y + y_off, (uint8) s->text_color, (uint8) s->text_color);
1596 						}
1597 					}
1598 				}
1599 			}
1600 		}
1601 
1602 		if (screen_opacity < 255) {
1603 			screen->fade(x_off, y_off, 320, 200, screen_opacity, bg_color);
1604 		}
1605 	}
1606 
1607 	if (cursor)
1608 		cursor->display();
1609 
1610 	if (full_redraw)
1611 		screen->update(0, 0, area.width(), area.height());
1612 	else
1613 		screen->update(x_off, y_off, 320, 200);
1614 }
1615 
Hide()1616 void ScriptCutscene::Hide() {
1617 	GUI_Widget::Hide();
1618 	gui->force_full_redraw();
1619 }
1620 
display_wrapped_text(CSSprite * s)1621 void ScriptCutscene::display_wrapped_text(CSSprite *s) {
1622 	uint8 text_color = (uint8) s->text_color;
1623 
1624 	size_t start = 0;
1625 	size_t found;
1626 	Std::string str = s->text + "^";
1627 	Std::list<Std::string> tokens;
1628 	int y = s->y;
1629 
1630 
1631 	Std::string line = "";
1632 
1633 	found = str.findFirstOf("^", start);
1634 	while (found != string::npos) {
1635 		Std::string token = str.substr(start, found - start);
1636 
1637 		y = display_wrapped_text_line(token, text_color, s->x, y, s->text_align);
1638 
1639 		start = found + 1;
1640 		found = str.findFirstOf("^", start);
1641 	}
1642 }
1643 
display_wrapped_text_line(Std::string str,uint8 text_color,int x,int y,uint8 align_val)1644 int ScriptCutscene::display_wrapped_text_line(Std::string str, uint8 text_color, int x, int y, uint8 align_val) {
1645 
1646 	//font->drawString(screen, s->text.c_str(), s->x + x_off, s->y + y_off, text_color, text_color);
1647 	int len = 0;
1648 	size_t start = 0;
1649 	size_t found;
1650 	str = str + " ";
1651 	Std::list<Std::string> tokens;
1652 	int space_width = font->getStringWidth(" ");
1653 	//uint16 x1 = startx;
1654 	int width = 320 - x * 2;
1655 
1656 	int char_height = font->getCharHeight();
1657 
1658 	Std::string line = "";
1659 
1660 	found = str.findFirstOf(" ", start);
1661 	while (found != string::npos) {
1662 		Std::string token = str.substr(start, found - start);
1663 
1664 		int token_len = font->getStringWidth(token.c_str());
1665 
1666 		if (len + token_len > width) {
1667 			if (len > 0) {
1668 				len -= space_width;
1669 			}
1670 			font->drawString(screen, line.c_str(), x + x_off + (align_val == 1 ? 0 : (width - len)) / 2, y + y_off, text_color, text_color);
1671 			line = "";
1672 			y += char_height + 2;
1673 			len = 0;
1674 		}
1675 
1676 		len += token_len + space_width;
1677 		line = line + token + " ";
1678 
1679 		start = found + 1;
1680 		found = str.findFirstOf(" ", start);
1681 	}
1682 
1683 	if (len > 0) {
1684 		len -= space_width;
1685 		font->drawString(screen, line.c_str(), x + x_off + (align_val == 1 ? 0 : (width - len)) / 2, y + y_off, text_color, text_color);
1686 		y += char_height + 2;
1687 	}
1688 
1689 	return y;
1690 }
setScale(uint16 percentage)1691 void CSImage::setScale(uint16 percentage) {
1692 	if (scale == percentage) {
1693 		return;
1694 	}
1695 
1696 	if (scaled_shp)
1697 		delete scaled_shp;
1698 
1699 	scale = percentage;
1700 	if (scale == 100) {
1701 		scaled_shp = NULL;
1702 		shp = orig_shp;
1703 		return;
1704 	}
1705 
1706 	uint16 sw, sh;
1707 	uint16 sx, sy;
1708 
1709 	uint16 tw, th;
1710 	uint16 tx, ty;
1711 
1712 	float scale_factor = (float)scale / 100;
1713 
1714 	orig_shp->get_size(&sw, &sh);
1715 	orig_shp->get_hot_point(&sx, &sy);
1716 
1717 	tw = (uint16)((float)sw * scale_factor);
1718 	th = (uint16)((float)sh * scale_factor);
1719 	tx = (uint16)((float)sx * scale_factor);
1720 	ty = (uint16)((float)sy * scale_factor);
1721 
1722 	scaled_shp = new U6Shape();
1723 	if (!scaled_shp->init(tw, th, tx, ty)) {
1724 		scale = 100;
1725 		delete scaled_shp;
1726 		scaled_shp = NULL;
1727 		return;
1728 	}
1729 
1730 	scale_rect_8bit(orig_shp->get_data(), scaled_shp->get_data(), sw, sh, tw, th);
1731 	shp = scaled_shp;
1732 
1733 	return;
1734 }
1735 
CSStarFieldImage(U6Shape * shape)1736 CSStarFieldImage::CSStarFieldImage(U6Shape *shape) : CSImage(shape) {
1737 	shp->get_size(&w, &h);
1738 
1739 	for (int i = 0; i < STAR_FIELD_NUM_STARS; i++) {
1740 		stars[i].color = 2;
1741 		stars[i].line = NULL;
1742 	}
1743 }
1744 
updateEffect()1745 void CSStarFieldImage::updateEffect() {
1746 	unsigned char *data = shp->get_data();
1747 
1748 	memset(data, 0, w * h);
1749 
1750 	for (int i = 0; i < STAR_FIELD_NUM_STARS; i++) {
1751 		if (stars[i].line == NULL) {
1752 			switch (NUVIE_RAND() % 4) {
1753 			case 0 :
1754 				stars[i].line = new U6LineWalker(w / 2, h / 2, 0, NUVIE_RAND() % h);
1755 				break;
1756 			case 1 :
1757 				stars[i].line = new U6LineWalker(w / 2, h / 2, w - 1, NUVIE_RAND() % h);
1758 				break;
1759 			case 2 :
1760 				stars[i].line = new U6LineWalker(w / 2, h / 2, NUVIE_RAND() % w, 0);
1761 				break;
1762 			case 3 :
1763 				stars[i].line = new U6LineWalker(w / 2, h / 2, NUVIE_RAND() % w, h - 1);
1764 				break;
1765 			}
1766 
1767 			stars[i].color = NUVIE_RAND() % 10 + 229;
1768 			uint16 start_pos = NUVIE_RAND() % (w / 2);
1769 			for (int j = 0; j < start_pos; j++) {
1770 				if (stars[i].line->step() == false) {
1771 					delete stars[i].line;
1772 					stars[i].line = NULL;
1773 					break;
1774 				}
1775 			}
1776 		} else {
1777 			uint32 cur_x, cur_y;
1778 			if (stars[i].line->next(&cur_x, &cur_y) == false) {
1779 				delete stars[i].line;
1780 				stars[i].line = NULL;
1781 			} else {
1782 				data[cur_y * w + cur_x] = stars[i].color;
1783 			}
1784 		}
1785 	}
1786 }
1787 
1788 } // End of namespace Nuvie
1789 } // End of namespace Ultima
1790