/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "common/lua/lauxlib.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/files/u6_lib_n.h"
#include "ultima/nuvie/files/nuvie_io.h"
#include "ultima/nuvie/files/nuvie_io_file.h"
#include "ultima/nuvie/files/u6_lzw.h"
#include "ultima/nuvie/misc/u6_line_walker.h"
#include "ultima/nuvie/screen/game_palette.h"
#include "ultima/nuvie/sound/sound_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/fonts/wou_font.h"
#include "ultima/nuvie/core/cursor.h"
#include "ultima/nuvie/keybinding/keys.h"
#include "ultima/nuvie/script/script_cutscene.h"
#include "common/system.h"
namespace Ultima {
namespace Nuvie {
static const uint32 DELUXE_PAINT_MAGIC = 0x4d524f46; // "FORM"
static const int INPUT_KEY_RIGHT = 79 | (1<<30);
static const int INPUT_KEY_LEFT = 80 | (1<<30);
static const int INPUT_KEY_DOWN = 81 | (1<<30);
static const int INPUT_KEY_UP = 82 | (1<<30);
static ScriptCutscene *cutScene = nullptr;
ScriptCutscene *get_cutscene() {
return cutScene;
}
static int nscript_image_set(lua_State *L);
static int nscript_image_get(lua_State *L);
bool nscript_new_image_var(lua_State *L, CSImage *image);
static int nscript_image_gc(lua_State *L);
static sint32 nscript_dec_image_ref_count(CSImage *image);
static int nscript_image_new(lua_State *L);
static int nscript_image_new_starfield(lua_State *L);
static int nscript_image_copy(lua_State *L);
static int nscript_image_load(lua_State *L);
static int nscript_image_load_all(lua_State *L);
static int nscript_image_print(lua_State *L);
static int nscript_image_print_raw(lua_State *L);
static int nscript_image_draw_line(lua_State *L);
static int nscript_image_blit(lua_State *L);
static int nscript_image_update_effect(lua_State *L);
static int nscript_image_static(lua_State *L);
static int nscript_image_set_transparency_colour(lua_State *L);
static int nscript_image_bubble_effect_add_color(lua_State *L);
static int nscript_image_bubble_effect(lua_State *L);
static const struct luaL_Reg nscript_imagelib_m[] = {
{ "__index", nscript_image_get },
{ "__newindex", nscript_image_set },
{ "__gc", nscript_image_gc },
{ nullptr, nullptr }
};
static int nscript_sprite_set(lua_State *L);
static int nscript_sprite_get(lua_State *L);
bool nscript_new_sprite_var(lua_State *L, CSSprite *image);
static int nscript_sprite_gc(lua_State *L);
static const struct luaL_Reg nscript_spritelib_m[] = {
{ "__index", nscript_sprite_get },
{ "__newindex", nscript_sprite_set },
{ "__gc", nscript_sprite_gc },
{ nullptr, nullptr }
};
static int nscript_sprite_new(lua_State *L);
static int nscript_sprite_move_to_front(lua_State *L);
static int nscript_text_load(lua_State *L);
static int nscript_midgame_load(lua_State *L);
static int nscript_canvas_set_bg_color(lua_State *L);
static int nscript_canvas_set_palette(lua_State *L);
static int nscript_canvas_set_palette_entry(lua_State *L);
static int nscript_canvas_rotate_palette(lua_State *L);
static int nscript_canvas_set_update_interval(lua_State *L);
static int nscript_canvas_set_opacity(lua_State *L);
static int nscript_canvas_set_solid_bg(lua_State *L);
static int nscript_canvas_update(lua_State *L);
static int nscript_canvas_show(lua_State *L);
static int nscript_canvas_hide(lua_State *L);
static int nscript_canvas_hide_all_sprites(lua_State *L);
static int nscript_canvas_string_length(lua_State *L);
static int nscript_canvas_rotate_game_palette(lua_State *L);
static int nscript_music_play(lua_State *L);
static int nscript_music_stop(lua_State *L);
static int nscript_get_mouse_x(lua_State *L);
static int nscript_get_mouse_y(lua_State *L);
static int nscript_input_poll(lua_State *L);
static int nscript_config_set(lua_State *L);
static int nscript_engine_should_quit(lua_State *L);
static int nscript_transfer_save_game(lua_State *L);
void nscript_init_cutscene(lua_State *L, Configuration *cfg, GUI *gui, SoundManager *sm) {
cutScene = new ScriptCutscene(gui, cfg, sm);
luaL_newmetatable(L, "nuvie.Image");
luaL_register(L, nullptr, nscript_imagelib_m);
luaL_newmetatable(L, "nuvie.Sprite");
luaL_register(L, nullptr, nscript_spritelib_m);
lua_pushcfunction(L, nscript_image_new);
lua_setglobal(L, "image_new");
lua_pushcfunction(L, nscript_image_new_starfield);
lua_setglobal(L, "image_new_starfield");
lua_pushcfunction(L, nscript_image_copy);
lua_setglobal(L, "image_copy");
lua_pushcfunction(L, nscript_image_load);
lua_setglobal(L, "image_load");
lua_pushcfunction(L, nscript_image_load_all);
lua_setglobal(L, "image_load_all");
lua_pushcfunction(L, nscript_image_print);
lua_setglobal(L, "image_print");
lua_pushcfunction(L, nscript_image_print_raw);
lua_setglobal(L, "image_print_raw");
lua_pushcfunction(L, nscript_image_static);
lua_setglobal(L, "image_static");
lua_pushcfunction(L, nscript_image_set_transparency_colour);
lua_setglobal(L, "image_set_transparency_colour");
lua_pushcfunction(L, nscript_image_update_effect);
lua_setglobal(L, "image_update_effect");
lua_pushcfunction(L, nscript_sprite_new);
lua_setglobal(L, "sprite_new");
lua_pushcfunction(L, nscript_sprite_move_to_front);
lua_setglobal(L, "sprite_move_to_front");
lua_pushcfunction(L, nscript_image_bubble_effect_add_color);
lua_setglobal(L, "image_bubble_effect_add_color");
lua_pushcfunction(L, nscript_image_bubble_effect);
lua_setglobal(L, "image_bubble_effect");
lua_pushcfunction(L, nscript_image_draw_line);
lua_setglobal(L, "image_draw_line");
lua_pushcfunction(L, nscript_image_blit);
lua_setglobal(L, "image_blit");
lua_pushcfunction(L, nscript_text_load);
lua_setglobal(L, "text_load");
lua_pushcfunction(L, nscript_midgame_load);
lua_setglobal(L, "midgame_load");
lua_pushcfunction(L, nscript_canvas_set_bg_color);
lua_setglobal(L, "canvas_set_bg_color");
lua_pushcfunction(L, nscript_canvas_set_palette);
lua_setglobal(L, "canvas_set_palette");
lua_pushcfunction(L, nscript_canvas_set_palette_entry);
lua_setglobal(L, "canvas_set_palette_entry");
lua_pushcfunction(L, nscript_canvas_rotate_palette);
lua_setglobal(L, "canvas_rotate_palette");
lua_pushcfunction(L, nscript_canvas_set_update_interval);
lua_setglobal(L, "canvas_set_update_interval");
lua_pushcfunction(L, nscript_canvas_set_solid_bg);
lua_setglobal(L, "canvas_set_solid_bg");
lua_pushcfunction(L, nscript_canvas_set_opacity);
lua_setglobal(L, "canvas_set_opacity");
lua_pushcfunction(L, nscript_canvas_update);
lua_setglobal(L, "canvas_update");
lua_pushcfunction(L, nscript_canvas_show);
lua_setglobal(L, "canvas_show");
lua_pushcfunction(L, nscript_canvas_hide);
lua_setglobal(L, "canvas_hide");
lua_pushcfunction(L, nscript_canvas_hide_all_sprites);
lua_setglobal(L, "canvas_hide_all_sprites");
lua_pushcfunction(L, nscript_canvas_string_length);
lua_setglobal(L, "canvas_string_length");
lua_pushcfunction(L, nscript_canvas_rotate_game_palette);
lua_setglobal(L, "canvas_rotate_game_palette");
lua_pushcfunction(L, nscript_music_play);
lua_setglobal(L, "music_play");
lua_pushcfunction(L, nscript_music_stop);
lua_setglobal(L, "music_stop");
lua_pushcfunction(L, nscript_get_mouse_x);
lua_setglobal(L, "get_mouse_x");
lua_pushcfunction(L, nscript_get_mouse_y);
lua_setglobal(L, "get_mouse_y");
lua_pushcfunction(L, nscript_input_poll);
lua_setglobal(L, "input_poll");
lua_pushcfunction(L, nscript_config_set);
lua_setglobal(L, "config_set");
lua_pushcfunction(L, nscript_engine_should_quit);
lua_setglobal(L, "engine_should_quit");
lua_pushcfunction(L, nscript_transfer_save_game);
lua_setglobal(L, "transfer_save_game");
}
bool nscript_new_image_var(lua_State *L, CSImage *image) {
CSImage **userdata;
userdata = (CSImage **)lua_newuserdata(L, sizeof(CSImage *));
luaL_getmetatable(L, "nuvie.Image");
lua_setmetatable(L, -2);
*userdata = image;
if (image)
image->refcount++;
return true;
}
CSImage *nscript_get_image_from_args(lua_State *L, int lua_stack_offset) {
CSImage **s_image = (CSImage **)luaL_checkudata(L, lua_stack_offset, "nuvie.Image");
if (s_image == nullptr)
return nullptr;
return *s_image;
}
static int nscript_image_set(lua_State *L) {
CSImage **s_image;
CSImage *image;
const char *key;
s_image = (CSImage **)lua_touserdata(L, 1);
if (s_image == nullptr)
return 0;
image = *s_image;
if (image == nullptr)
return 0;
key = lua_tostring(L, 2);
if (!strcmp(key, "scale")) {
image->setScale((uint16)lua_tointeger(L, 3));
return 0;
}
return 0;
}
static int nscript_image_get(lua_State *L) {
CSImage **s_image;
CSImage *image;
const char *key;
s_image = (CSImage **)lua_touserdata(L, 1);
if (s_image == nullptr)
return 0;
image = *s_image;
if (image == nullptr)
return 0;
key = lua_tostring(L, 2);
if (!strcmp(key, "w")) {
uint16 w, h;
image->shp->get_size(&w, &h);
lua_pushinteger(L, w);
return 1;
}
if (!strcmp(key, "h")) {
uint16 w, h;
image->shp->get_size(&w, &h);
lua_pushinteger(L, h);
return 1;
}
if (!strcmp(key, "scale")) {
lua_pushinteger(L, image->getScale());
return 1;
}
return 0;
}
static sint32 nscript_dec_image_ref_count(CSImage *image) {
if (image == nullptr)
return -1;
image->refcount--;
return image->refcount;
}
static int nscript_image_gc(lua_State *L) {
//DEBUG(0, LEVEL_INFORMATIONAL, "\nImage garbage Collection!\n");
CSImage **p_image = (CSImage **)lua_touserdata(L, 1);
CSImage *image;
if (p_image == nullptr)
return false;
image = *p_image;
if (nscript_dec_image_ref_count(image) == 0) {
if (image->shp)
delete image->shp;
delete image;
}
return 0;
}
static int nscript_image_new(lua_State *L) {
uint16 width = lua_tointeger(L, 1);
uint16 height = lua_tointeger(L, 2);
U6Shape *shp = new U6Shape();
if (shp->init(width, height) == false)
return 0;
if (lua_gettop(L) >= 3)
shp->fill((uint8)lua_tointeger(L, 3));
CSImage *image = new CSImage(shp);
nscript_new_image_var(L, image);
return 1;
}
static int nscript_image_new_starfield(lua_State *L) {
uint16 width = lua_tointeger(L, 1);
uint16 height = lua_tointeger(L, 2);
U6Shape *shp = new U6Shape();
if (shp->init(width, height) == false)
return 0;
CSStarFieldImage *image = new CSStarFieldImage(shp);
nscript_new_image_var(L, image);
return 1;
}
static int nscript_image_copy(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
uint16 w, h;
U6Shape *shp = new U6Shape();
img->shp->get_size(&w, &h);
if (shp->init(w, h) == false) {
return 0;
}
shp->blit(img->shp, 0, 0);
CSImage *image = new CSImage(shp);
nscript_new_image_var(L, image);
return 1;
}
static int nscript_image_load(lua_State *L) {
const char *filename = lua_tostring(L, 1);
int idx = -1;
int sub_idx = 0;
if (lua_gettop(L) >= 2)
idx = lua_tointeger(L, 2);
if (lua_gettop(L) >= 3)
sub_idx = lua_tointeger(L, 3);
CSImage *image = cutScene->load_image(filename, idx, sub_idx);
if (image) {
nscript_new_image_var(L, image);
return 1;
}
return 0;
}
static int nscript_image_load_all(lua_State *L) {
const char *filename = lua_tostring(L, 1);
Std::vector > images = cutScene->load_all_images(filename);
if (images.empty()) {
return 0;
}
lua_newtable(L);
for (uint16 i = 0; i < images.size(); i++) {
lua_pushinteger(L, i);
if (images[i].size() > 1) {
lua_newtable(L);
for (uint16 j = 0; j < images[i].size(); j++) {
lua_pushinteger(L, j);
nscript_new_image_var(L, images[i][j]);
lua_settable(L, -3);
}
} else {
nscript_new_image_var(L, images[i][0]);
}
lua_settable(L, -3);
}
return 1;
}
static int nscript_image_print_raw(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
const char *text = lua_tostring(L, 2);
uint16 x = lua_tointeger(L, 3);
uint16 y = lua_tointeger(L, 4);
uint8 color = lua_tointeger(L, 5);
cutScene->print_text_raw(img, text, x, y, color);
return 0;
}
static int nscript_image_print(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
const char *text = lua_tostring(L, 2);
uint16 startx = lua_tointeger(L, 3);
uint16 width = lua_tointeger(L, 4);
uint16 x = lua_tointeger(L, 5);
uint16 y = lua_tointeger(L, 6);
uint8 color = lua_tointeger(L, 7);
cutScene->print_text(img, text, &x, &y, startx, width, color);
lua_pushinteger(L, x);
lua_pushinteger(L, y);
return 2;
}
static int nscript_image_draw_line(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
uint16 sx = lua_tointeger(L, 2);
uint16 sy = lua_tointeger(L, 3);
uint16 ex = lua_tointeger(L, 4);
uint16 ey = lua_tointeger(L, 5);
uint8 color = lua_tointeger(L, 6);
if (img) {
img->shp->draw_line(sx, sy, ex, ey, color);
}
return 0;
}
static int nscript_image_blit(lua_State *L) {
CSImage *dest_img = nscript_get_image_from_args(L, 1);
CSImage *src_img = nscript_get_image_from_args(L, 2);
uint16 x = lua_tointeger(L, 3);
uint16 y = lua_tointeger(L, 4);
if (dest_img && src_img) {
dest_img->shp->blit(src_img->shp, x, y);
}
return 0;
}
static int nscript_image_update_effect(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
if (img) {
img->updateEffect();
}
return 0;
}
static uint8 u6_flask_num_colors = 0;
static uint8 u6_flask_liquid_colors[8];
static int nscript_image_bubble_effect_add_color(lua_State *L) {
if (u6_flask_num_colors != 8) {
u6_flask_liquid_colors[u6_flask_num_colors++] = lua_tointeger(L, 1);
}
return 0;
}
static int nscript_image_bubble_effect(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
if (img && u6_flask_num_colors > 0) {
unsigned char *data = img->shp->get_data();
uint16 w, h;
img->shp->get_size(&w, &h);
for (int i = 0; i < w * h; i++) {
if (*data != 0xff) {
*data = u6_flask_liquid_colors[NUVIE_RAND() % u6_flask_num_colors];
}
data++;
}
}
return 0;
}
static int nscript_image_set_transparency_colour(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
uint8 pal_index = lua_tointeger(L, 2);
if (img) {
unsigned char *data = img->shp->get_data();
uint16 w, h;
img->shp->get_size(&w, &h);
for (int i = 0; i < w * h; i++) {
if (data[i] == pal_index)
data[i] = 0xff;
}
}
return 0;
}
static int nscript_image_static(lua_State *L) {
CSImage *img = nscript_get_image_from_args(L, 1);
if (img) {
unsigned char *data = img->shp->get_data();
uint16 w, h;
img->shp->get_size(&w, &h);
memset(data, 16, w * h);
for (int i = 0; i < 1000; i++) {
data[NUVIE_RAND() % (w * h)] = 0;
}
}
return 0;
}
CSSprite *nscript_get_sprite_from_args(lua_State *L, int lua_stack_offset) {
CSSprite **s_sprite;
CSSprite *sprite;
s_sprite = (CSSprite **)lua_touserdata(L, 1);
if (s_sprite == nullptr)
return nullptr;
sprite = *s_sprite;
return sprite;
}
bool nscript_new_sprite_var(lua_State *L, CSSprite *sprite) {
CSSprite **userdata;
userdata = (CSSprite **)lua_newuserdata(L, sizeof(CSSprite *));
luaL_getmetatable(L, "nuvie.Sprite");
lua_setmetatable(L, -2);
*userdata = sprite;
return true;
}
static int nscript_sprite_set(lua_State *L) {
CSSprite **s_sprite;
CSSprite *sprite;
const char *key;
s_sprite = (CSSprite **)lua_touserdata(L, 1);
if (s_sprite == nullptr)
return 0;
sprite = *s_sprite;
if (sprite == nullptr)
return 0;
key = lua_tostring(L, 2);
if (!strcmp(key, "x")) {
sprite->x = lua_tointeger(L, 3);
return 0;
}
if (!strcmp(key, "y")) {
sprite->y = lua_tointeger(L, 3);
return 0;
}
if (!strcmp(key, "opacity")) {
int opacity = lua_tointeger(L, 3);
sprite->opacity = (uint8)clamp(opacity, 0, 255);
return 0;
}
if (!strcmp(key, "visible")) {
sprite->visible = lua_toboolean(L, 3);
return 0;
}
if (!strcmp(key, "image")) {
if (sprite->image) {
sprite->image->refcount--;
if (sprite->image->refcount == 0)
delete sprite->image;
}
sprite->image = nscript_get_image_from_args(L, 3);
if (sprite->image)
sprite->image->refcount++;
return 0;
}
if (!strcmp(key, "clip_x")) {
sprite->clip_rect.left = lua_tointeger(L, 3) + cutScene->get_x_off();
return 0;
}
if (!strcmp(key, "clip_y")) {
sprite->clip_rect.top = lua_tointeger(L, 3) + cutScene->get_y_off();
return 0;
}
if (!strcmp(key, "clip_w")) {
sprite->clip_rect.setWidth(lua_tointeger(L, 3));
return 0;
}
if (!strcmp(key, "clip_h")) {
sprite->clip_rect.setHeight(lua_tointeger(L, 3));
return 0;
}
if (!strcmp(key, "text")) {
const char *text = lua_tostring(L, 3);
sprite->text = Std::string(text);
}
if (!strcmp(key, "text_color")) {
sprite->text_color = lua_tointeger(L, 3);
return 0;
}
if (!strcmp(key, "text_align")) {
int align_val = lua_tointeger(L, 3);
sprite->text_align = (uint8) align_val;
return 0;
}
return 0;
}
static int nscript_sprite_get(lua_State *L) {
CSSprite **s_sprite;
CSSprite *sprite;
const char *key;
s_sprite = (CSSprite **)lua_touserdata(L, 1);
if (s_sprite == nullptr)
return 0;
sprite = *s_sprite;
if (sprite == nullptr)
return 0;
key = lua_tostring(L, 2);
if (!strcmp(key, "x")) {
lua_pushinteger(L, sprite->x);
return 1;
}
if (!strcmp(key, "y")) {
lua_pushinteger(L, sprite->y);
return 1;
}
if (!strcmp(key, "opacity")) {
lua_pushinteger(L, sprite->opacity);
return 1;
}
if (!strcmp(key, "visible")) {
lua_pushboolean(L, sprite->visible);
return 1;
}
if (!strcmp(key, "image")) {
if (sprite->image) {
nscript_new_image_var(L, sprite->image);
return 1;
}
}
if (!strcmp(key, "text")) {
lua_pushstring(L, sprite->text.c_str());
return 1;
}
if (!strcmp(key, "text_color")) {
lua_pushinteger(L, sprite->text_color);
return 1;
}
if (!strcmp(key, "text_width")) {
lua_pushinteger(L, cutScene->get_text_width(sprite->text.c_str()));
return 1;
}
return 0;
}
static int nscript_sprite_gc(lua_State *L) {
//DEBUG(0, LEVEL_INFORMATIONAL, "\nSprite garbage Collection!\n");
CSSprite **p_sprite = (CSSprite **)lua_touserdata(L, 1);
CSSprite *sprite;
if (p_sprite == nullptr)
return false;
sprite = *p_sprite;
if (sprite) {
if (sprite->image) {
if (nscript_dec_image_ref_count(sprite->image) == 0)
delete sprite->image;
}
cutScene->remove_sprite(sprite);
delete sprite;
}
return 0;
}
static int nscript_sprite_new(lua_State *L) {
CSSprite *sprite = new CSSprite();
if (lua_gettop(L) >= 1 && !lua_isnil(L, 1)) {
sprite->image = nscript_get_image_from_args(L, 1);
if (sprite->image)
sprite->image->refcount++;
}
if (lua_gettop(L) >= 2 && !lua_isnil(L, 2)) {
sprite->x = lua_tointeger(L, 2);
}
if (lua_gettop(L) >= 3 && !lua_isnil(L, 3)) {
sprite->y = lua_tointeger(L, 3);
}
if (lua_gettop(L) >= 4 && !lua_isnil(L, 4)) {
sprite->visible = lua_toboolean(L, 4);
}
cutScene->add_sprite(sprite);
nscript_new_sprite_var(L, sprite);
return 1;
}
static int nscript_sprite_move_to_front(lua_State *L) {
CSSprite *sprite = nscript_get_sprite_from_args(L, 1);
if (sprite) {
cutScene->remove_sprite(sprite);
cutScene->add_sprite(sprite);
}
return 0;
}
static int nscript_text_load(lua_State *L) {
const char *filename = lua_tostring(L, 1);
uint8 idx = lua_tointeger(L, 2);
Std::vector text = cutScene->load_text(filename, idx);
if (text.empty()) {
return 0;
}
lua_newtable(L);
for (uint16 i = 0; i < text.size(); i++) {
lua_pushinteger(L, i);
lua_pushstring(L, text[i].c_str());
lua_settable(L, -3);
}
return 1;
}
static int nscript_midgame_load(lua_State *L) {
const char *filename = lua_tostring(L, 1);
Std::vector v = cutScene->load_midgame_file(filename);
if (v.empty()) {
return 0;
}
lua_newtable(L);
for (uint16 i = 0; i < v.size(); i++) {
lua_pushinteger(L, i);
lua_newtable(L);
lua_pushstring(L, "text");
lua_newtable(L);
for (uint16 j = 0; j < v[i].text.size(); j++) {
lua_pushinteger(L, j);
lua_pushstring(L, v[i].text[j].c_str());
lua_settable(L, -3);
}
lua_settable(L, -3);
lua_pushstring(L, "images");
lua_newtable(L);
for (uint16 j = 0; j < v[i].images.size(); j++) {
lua_pushinteger(L, j);
nscript_new_image_var(L, v[i].images[j]);
lua_settable(L, -3);
}
lua_settable(L, -3);
lua_settable(L, -3);
}
return 1;
}
static int nscript_canvas_set_bg_color(lua_State *L) {
uint8 color = lua_tointeger(L, 1);
cutScene->set_bg_color(color);
return 0;
}
static int nscript_canvas_set_palette(lua_State *L) {
const char *filename = lua_tostring(L, 1);
uint8 idx = lua_tointeger(L, 2);
cutScene->load_palette(filename, idx);
return 0;
}
static int nscript_canvas_set_palette_entry(lua_State *L) {
uint8 idx = lua_tointeger(L, 1);
uint8 r = lua_tointeger(L, 2);
uint8 g = lua_tointeger(L, 3);
uint8 b = lua_tointeger(L, 4);
cutScene->set_palette_entry(idx, r, g, b);
return 0;
}
static int nscript_canvas_rotate_palette(lua_State *L) {
uint8 idx = lua_tointeger(L, 1);
uint8 len = lua_tointeger(L, 2);
cutScene->rotate_palette(idx, len);
return 0;
}
static int nscript_canvas_set_update_interval(lua_State *L) {
uint16 loop_interval = lua_tointeger(L, 1);
cutScene->set_update_interval(loop_interval);
return 0;
}
static int nscript_canvas_set_solid_bg(lua_State *L) {
bool solid_bg = lua_toboolean(L, 1);
cutScene->set_solid_bg(solid_bg);
return 0;
}
static int nscript_canvas_set_opacity(lua_State *L) {
uint8 opacity = lua_tointeger(L, 1);
cutScene->set_screen_opacity(opacity);
return 0;
}
static int nscript_canvas_update(lua_State *L) {
cutScene->update();
return 0;
}
static int nscript_canvas_show(lua_State *L) {
cutScene->moveToFront();
return 0;
}
static int nscript_canvas_hide(lua_State *L) {
cutScene->Hide();
return 0;
}
static int nscript_canvas_hide_all_sprites(lua_State *L) {
cutScene->hide_sprites();
return 0;
}
static int nscript_canvas_string_length(lua_State *L) {
Font *font = cutScene->get_font();
const char *str = lua_tostring(L, 1);
lua_pushinteger(L, font->getStringWidth(str));
return 1;
}
static int nscript_canvas_rotate_game_palette(lua_State *L) {
bool val = lua_toboolean(L, 1);
cutScene->enable_game_palette_rotation(val);
return 0;
}
static int nscript_music_play(lua_State *L) {
uint16 song_num = 0;
const char *filename = lua_tostring(L, 1);
if (lua_gettop(L) >= 2 && !lua_isnil(L, 2)) {
song_num = lua_tointeger(L, 2);
}
cutScene->get_sound_manager()->musicPlay(filename, song_num);
return 0;
}
static int nscript_music_stop(lua_State *L) {
cutScene->get_sound_manager()->musicStop();
return 0;
}
static int nscript_get_mouse_x(lua_State *L) {
int x, y;
cutScene->get_screen()->get_mouse_location(&x, &y);
x -= cutScene->get_x_off();
lua_pushinteger(L, x);
return 1;
}
static int nscript_get_mouse_y(lua_State *L) {
int x, y;
cutScene->get_screen()->get_mouse_location(&x, &y);
y -= cutScene->get_y_off();
lua_pushinteger(L, y);
return 1;
}
static int nscript_input_poll(lua_State *L) {
Common::Event event;
bool poll_mouse_motion;
if (lua_isnil(L, 1))
poll_mouse_motion = false;
else
poll_mouse_motion = lua_toboolean(L, 1);
while (Events::get()->pollEvent(event)) {
//FIXME do something here.
KeyBinder *keybinder = Game::get_game()->get_keybinder();
if (event.type == Common::EVENT_JOYAXIS_MOTION ||
event.type == Common::EVENT_JOYBUTTON_DOWN ||
event.type == Common::EVENT_JOYBUTTON_UP) {
event.kbd.flags = 0;
event.kbd.keycode = keybinder->get_key_from_joy_events(&event);
if (event.kbd.keycode == Common::KEYCODE_INVALID)
// button isn't mapped or was in deadzone
continue; // pretend nothing happened
event.type = Common::EVENT_KEYDOWN;
}
if (event.type == Common::EVENT_KEYDOWN) {
Common::KeyState key = event.kbd;
if ((((key.flags & Common::KBD_CAPS) == Common::KBD_CAPS
&& (key.flags & Common::KBD_SHIFT) == 0) || ((key.flags & Common::KBD_CAPS) == 0 && (key.flags & Common::KBD_SHIFT)))
&& key.keycode >= Common::KEYCODE_a && key.keycode <= Common::KEYCODE_z)
key.keycode = (Common::KeyCode)(key.keycode - 32);
if (key.keycode > 0xFF || !Common::isPrint((char)key.keycode) || (key.flags & Common::KBD_ALT) || (key.flags & Common::KBD_CTRL)) {
ActionType a = keybinder->get_ActionType(key);
switch (keybinder->GetActionKeyType(a)) {
case WEST_KEY:
lua_pushinteger(L, INPUT_KEY_LEFT);
return 1;
case EAST_KEY:
lua_pushinteger(L, INPUT_KEY_RIGHT);
return 1;
case SOUTH_KEY:
lua_pushinteger(L, INPUT_KEY_DOWN);
return 1;
case NORTH_KEY:
lua_pushinteger(L, INPUT_KEY_UP);
return 1;
case CANCEL_ACTION_KEY:
key.keycode = Common::KEYCODE_ESCAPE;
break;
case DO_ACTION_KEY:
key.keycode = Common::KEYCODE_RETURN;
break;
default:
if (keybinder->handle_always_available_keys(a)) continue;
break;
}
}
lua_pushinteger(L, key.keycode);
return 1;
}
if (event.type == Common::EVENT_QUIT) {
lua_pushinteger(L, 'Q');
return 1;
}
if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_RBUTTONDOWN) {
lua_pushinteger(L, 0);
return 1;
}
if (poll_mouse_motion && event.type == Common::EVENT_MOUSEMOVE) {
lua_pushinteger(L, 1);
return 1;
}
}
return 0;
}
static int nscript_config_set(lua_State *L) {
const char *config_key = lua_tostring(L, 1);
if (lua_isstring(L, 2)) {
cutScene->get_config()->set(config_key, lua_tostring(L, 2));
} else if (lua_isnumber(L, 2)) {
cutScene->get_config()->set(config_key, (int)lua_tointeger(L, 2));
} else if (lua_isboolean(L, 2)) {
cutScene->get_config()->set(config_key, (bool)lua_toboolean(L, 2));
}
return 0;
}
static int nscript_engine_should_quit(lua_State *L) {
int x = g_engine->shouldQuit();
lua_pushinteger(L, x);
return 1;
}
int nscript_transfer_save_game(lua_State *L) {
TransferSaveData saveData = cutScene->load_transfer_save();
lua_newtable(L);
lua_pushstring(L, "game_type");
lua_pushinteger(L, saveData.gameType);
lua_settable(L, -3);
lua_pushstring(L, "name");
lua_pushstring(L, saveData.name.c_str());
lua_settable(L, -3);
lua_pushstring(L, "gender");
lua_pushinteger(L, saveData.gender);
lua_settable(L, -3);
lua_pushstring(L, "class");
lua_pushstring(L, saveData.className.c_str());
lua_settable(L, -3);
lua_pushstring(L, "str");
lua_pushinteger(L, saveData.str);
lua_settable(L, -3);
lua_pushstring(L, "dex");
lua_pushinteger(L, saveData.dex);
lua_settable(L, -3);
lua_pushstring(L, "int");
lua_pushinteger(L, saveData.intelligence);
lua_settable(L, -3);
lua_pushstring(L, "magic");
lua_pushinteger(L, saveData.magic);
lua_settable(L, -3);
lua_pushstring(L, "exp");
lua_pushinteger(L, saveData.exp);
lua_settable(L, -3);
lua_pushstring(L, "level");
lua_pushinteger(L, saveData.level);
lua_settable(L, -3);
return 1;
}
ScriptCutscene::ScriptCutscene(GUI *g, Configuration *cfg, SoundManager *sm) : GUI_Widget(nullptr) {
config = cfg;
gui = g;
cursor = Game::get_game()->get_cursor();
x_off = Game::get_game()->get_game_x_offset();
y_off = Game::get_game()->get_game_y_offset();
x_off += (Game::get_game()->get_game_width() - 320) / 2; // center it
y_off += (Game::get_game()->get_game_height() - 200) / 2; // center it
nuvie_game_t game_type = Game::get_game()->get_game_type();
GUI_Widget::Init(nullptr, 0, 0, g->get_width(), g->get_height());
clip_rect = Common::Rect(x_off, y_off, x_off + 320, y_off + 200);
screen = g->get_screen();
gui->AddWidget(this);
Hide();
sound_manager = sm;
//FIXME this should be loaded by script.
Common::Path path;
font = new WOUFont();
if (game_type == NUVIE_GAME_U6) {
config_get_path(config, "u6.set", path);
font->init(path);
}
//FIXME load other fonts for MD / SE if needed here.
if (game_type == NUVIE_GAME_SE) {
Common::Path filePath;
U6Lib_n lib_file;
config_get_path(config, "savage.fnt", filePath);
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.
unsigned char *buf = lib_file.get_item(0);
font->initWithBuffer(buf, lib_file.get_item_size(0)); //buf will be freed by ~Font()
}
if (game_type == NUVIE_GAME_MD) {
Common::Path filePath;
U6Lib_n lib_file;
config_get_path(config, "fonts.lzc", filePath);
lib_file.open(filePath, 4, NUVIE_GAME_MD);
unsigned char *buf = lib_file.get_item(0);
font->initWithBuffer(buf, lib_file.get_item_size(0)); //buf will be freed by ~Font()
}
next_time = 0;
loop_interval = 40;
screen_opacity = 255;
bg_color = 0;
solid_bg = true;
rotate_game_palette = false;
palette = nullptr;
}
ScriptCutscene::~ScriptCutscene() {
delete font;
}
bool ScriptCutscene::is_lzc(const char *filename) {
if (strlen(filename) > 4 && scumm_stricmp((const char *)&filename[strlen(filename) - 4], ".lzc") == 0)
return true;
return false;
}
CSImage *ScriptCutscene::load_image_from_lzc(const Common::Path &filename, uint16 idx, uint16 sub_idx) {
CSImage *image = nullptr;
U6Lib_n lib_n;
unsigned char *buf = nullptr;
if (!lib_n.open(filename, 4, NUVIE_GAME_MD)) {
return nullptr;
}
if (idx >= lib_n.get_num_items()) {
return nullptr;
}
buf = lib_n.get_item(idx, nullptr);
NuvieIOBuffer io;
io.open(buf, lib_n.get_item_size(idx), false);
U6Lib_n lib1;
lib1.open(&io, 4, NUVIE_GAME_MD);
if (sub_idx >= lib1.get_num_items()) {
return nullptr;
}
U6Shape *shp = new U6Shape();
if (shp->load(&lib1, (uint32)sub_idx)) {
image = new CSImage(shp);
}
free(buf);
return image;
}
CSImage *ScriptCutscene::load_image(const char *filename, int idx, int sub_idx) {
U6Lib_n lib_n;
Common::Path path;
CSImage *image = nullptr;
config_get_path(config, filename, path);
if (is_lzc(filename)) {
return load_image_from_lzc(path, (uint16)idx, (uint16)sub_idx);
}
U6Shape *shp = new U6Shape();
if (idx >= 0) {
U6Lzw lzw;
uint32 decomp_size;
unsigned char *buf = lzw.decompress_file(path, decomp_size);
NuvieIOBuffer io;
io.open(buf, decomp_size, false);
{
// Note: libN needs to be destroyed before the io object.
U6Lib_n libN;
if (libN.open(&io, 4, NUVIE_GAME_MD)) {
if (shp->load(&libN, (uint32)idx)) {
image = new CSImage(shp);
}
}
}
free(buf);
} else {
if (shp->load(path)) {
image = new CSImage(shp);
}
}
if (image == nullptr)
delete shp;
return image;
}
Std::vector > ScriptCutscene::load_all_images(const char *filename) {
Common::Path path;
CSImage *image = nullptr;
config_get_path(config, filename, path);
Std::vector > v;
U6Lzw lzw;
U6Lib_n lib_n;
unsigned char *buf = nullptr;
if (is_lzc(filename)) {
if (!lib_n.open(path, 4, NUVIE_GAME_MD)) {
return v;
}
for (uint32 idx = 0; idx < lib_n.get_num_items(); idx++) {
buf = lib_n.get_item(idx, nullptr);
NuvieIOBuffer io;
io.open(buf, lib_n.get_item_size(idx), false);
U6Lib_n lib1;
lib1.open(&io, 4, NUVIE_GAME_MD);
//printf("lib_size = %d\n", lib1.get_num_items());
Std::vector v1;
for (uint32 idx1 = 0; idx1 < lib1.get_num_items(); idx1++) {
U6Shape *shp = new U6Shape();
if (shp->load(&lib1, idx1)) {
image = new CSImage(shp);
v1.push_back(image);
}
}
free(buf);
buf = nullptr;
v.push_back(v1);
}
} else {
uint32 decomp_size;
buf = lzw.decompress_file(path, decomp_size);
if (!buf) // failed to open or decompress
return v;
NuvieIOBuffer io;
if (!buf || !io.open(buf, decomp_size, false) ||
!lib_n.open(&io, 4, NUVIE_GAME_MD)) {
free(buf);
return v;
}
for (uint32 idx = 0; idx < lib_n.get_num_items(); idx++) {
Std::vector v1;
U6Shape *shp = new U6Shape();
if (shp->load(&lib_n, idx)) {
image = new CSImage(shp);
v1.push_back(image);
v.push_back(v1);
}
}
lib_n.close();
}
if (buf)
free(buf);
return v;
}
void load_images_from_lib(Std::vector *images, U6Lib_n *lib, uint32 index) {
unsigned char *buf = lib->get_item(index, nullptr);
if (buf == nullptr) {
return;
}
NuvieIOBuffer io;
io.open(buf, lib->get_item_size(index), false);
U6Lib_n lib1;
lib1.open(&io, 4, NUVIE_GAME_MD);
for (uint16 i = 0; i < lib1.get_num_items(); i++) {
U6Shape *shp = new U6Shape();
if (shp->load(&lib1, i)) {
images->push_back(new CSImage(shp));
}
}
free(buf);
}
Std::vector ScriptCutscene::load_midgame_file(const char *filename) {
Common::Path path;
U6Lib_n lib_n;
Std::vector v;
nuvie_game_t game_type = Game::get_game()->get_game_type();
config_get_path(config, filename, path);
if (!lib_n.open(path, 4, NUVIE_GAME_MD)) {
return v;
}
for (uint32 idx = 0; idx < lib_n.get_num_items();) {
if (game_type == NUVIE_GAME_MD && idx == 0) { //Skip the first entry in the lib for MD it is *bogus*
idx++;
continue;
}
CSMidGameData data;
for (int i = 0; i < 3; i++, idx++) {
unsigned char *buf = lib_n.get_item(idx, nullptr);
data.text.push_back(string((const char *)buf));
free(buf);
}
load_images_from_lib(&data.images, &lib_n, idx++);
if (game_type == NUVIE_GAME_MD) {
load_images_from_lib(&data.images, &lib_n, idx++);
}
v.push_back(data);
}
return v;
}
TransferSaveData ScriptCutscene::load_transfer_save() {
TransferSaveData data;
data.gameType = 0;
data.name = "";
data.gender = 0;
data.className = "Avatar";
data.str = 0;
data.dex = 0;
data.intelligence = 0;
data.magic = 0;
data.exp = 0;
data.level = 0;
if (load_u5_save_file(data)) {
return data;
}
load_u4_save_file(data);
return data;
}
Std::vector ScriptCutscene::load_text(const char *filename, uint8 idx) {
Common::Path path;
U6Lib_n lib_n;
Std::vector v;
unsigned char *buf = nullptr;
config_get_path(config, filename, path);
if (!lib_n.open(path, 4, NUVIE_GAME_MD) || idx >= lib_n.get_num_items()) {
return v;
}
buf = lib_n.get_item(idx, nullptr);
uint16 len = lib_n.get_item_size(idx);
if (buf != nullptr) {
uint16 start = 0;
for (uint16 i = 0; i < len; i++) {
if (buf[i] == '\r') {
buf[i] = '\0';
v.push_back(string((const char *)&buf[start]));
i++;
buf[i] = '\0'; // skip the '\n' character
start = i + 1;
}
}
free(buf);
}
return v;
}
void ScriptCutscene::print_text(CSImage *image, const char *s, uint16 *x, uint16 *y, uint16 startx, uint16 width, uint8 color) {
int len = *x - startx;
size_t start = 0;
size_t found;
Std::string str = s;
Std::list tokens;
int space_width = font->getStringWidth(" ");
//uint16 x1 = startx;
found = str.findFirstOf(" ", start);
while (found != string::npos) {
Std::string token = str.substr(start, found - start);
int token_len = font->getStringWidth(token.c_str());
if (len + token_len + space_width > width) {
//FIXME render line here.
int new_space = 0;
if (tokens.size() > 1)
new_space = floor((width - (len - space_width * (tokens.size() - 1))) / (tokens.size() - 1));
for (const Std::string &ss : tokens) {
*x = ((WOUFont *)font)->drawStringToShape(image->shp, ss.c_str(), *x, *y, color);
*x += new_space;
}
*y += 8;
*x = startx;
len = token_len + space_width;
tokens.clear();
tokens.push_back(token);
} else {
tokens.push_back(token);
len += token_len + space_width;
}
start = found + 1;
found = str.findFirstOf(" ", start);
}
for (const Std::string &ss : tokens) {
*x = ((WOUFont *)font)->drawStringToShape(image->shp, ss.c_str(), *x, *y, color);
*x += space_width;
}
if (start < str.size()) {
Std::string token = str.substr(start, str.size() - start);
if (len + font->getStringWidth(token.c_str()) > width) {
*y += 8;
*x = startx;
}
*x = ((WOUFont *)font)->drawStringToShape(image->shp, token.c_str(), *x, *y, color);
}
//font->drawStringToShape(image->shp, string, x, y, color);
}
void ScriptCutscene::print_text_raw(CSImage *image, const char *string, uint16 x, uint16 y, uint8 color) const {
((WOUFont *)font)->drawStringToShape(image->shp, string, x, y, color);
}
void ScriptCutscene::load_palette(const char *filename, int idx) {
NuvieIOFileRead file;
uint8 buf[0x240 + 1];
uint8 unpacked_palette[0x300];
Common::Path path;
config_get_path(config, filename, path);
if (file.open(path) == false) {
DEBUG(0, LEVEL_ERROR, "loading palette.\n");
return;
}
if (file.read4() == DELUXE_PAINT_MAGIC || has_file_extension(filename, ".lbm")) {
//deluxe paint palette file.
file.seek(0x30);
file.readToBuf(unpacked_palette, 0x300);
} else if (has_file_extension(filename, ".pal")) {
U6Lib_n lib;
lib.open(path, 4, NUVIE_GAME_MD);
unsigned char *decomp_buf = lib.get_item(0, nullptr);
memcpy(unpacked_palette, &decomp_buf[idx * 0x300], 0x300);
free(decomp_buf);
} else {
file.seek(idx * 0x240);
file.readToBuf(buf, 0x240);
buf[0x240] = 0; //protect from buf[byte_pos+1] overflow when processing last byte of data.
for (int i = 0; i < 0x100; i++) {
for (int j = 0; j < 3; j++) {
int byte_pos = (i * 3 * 6 + j * 6) / 8;
int shift_val = (i * 3 * 6 + j * 6) % 8;
int color = ((buf[byte_pos] +
(buf[byte_pos + 1] << 8))
>> shift_val) & 0x3F;
unpacked_palette[i * 3 + j] = (uint8)(color << 2);
}
}
}
/*
printf("GIMP Palette\nName: U6 ending\n#\n");
for (int i = 0; i < 0x100; i++)
{
for (int j = 0; j < 3; j++)
{
printf("% 3d ", unpacked_palette[i*3+j]);
}
printf(" untitled\n");
}
*/
screen->set_palette(unpacked_palette);
}
void ScriptCutscene::set_palette_entry(uint8 idx, uint8 r, uint8 g, uint8 b) {
screen->set_palette_entry(idx, r, g, b);
}
void ScriptCutscene::rotate_palette(uint8 idx, uint8 length) {
screen->rotate_palette(idx, length);
}
void ScriptCutscene::set_update_interval(uint16 interval) {
loop_interval = interval;
}
void ScriptCutscene::set_screen_opacity(uint8 new_opacity) {
screen_opacity = new_opacity;
}
void ScriptCutscene::hide_sprites() {
for (CSSprite *s : sprite_list) {
if (s->visible)
s->visible = false;
}
}
void ScriptCutscene::update() {
if (cutScene->Status() == WIDGET_HIDDEN) {
cutScene->Show();
gui->force_full_redraw();
}
if (rotate_game_palette) {
GamePalette *pal = Game::get_game()->get_palette();
if (pal) {
pal->rotatePalette();
}
}
gui->Display();
screen->performUpdate();
sound_manager->update();
wait();
}
void ScriptCutscene::wait() {
uint32 now = SDL_GetTicks();
if (next_time <= now) {
next_time = now + loop_interval;
return;
}
uint32 delay = next_time - now;
next_time += loop_interval;
g_system->delayMillis(delay);
}
/* Show the widget */
void ScriptCutscene::Display(bool full_redraw) {
if (cursor && cursor->is_visible())
cursor->clear();
if (solid_bg) {
if (full_redraw)
screen->fill(bg_color, 0, 0, area.width(), area.height());
else
screen->fill(bg_color, x_off, y_off, 320, 200);
}
if (screen_opacity > 0) {
for (CSSprite *s : sprite_list) {
if (s->visible) {
if (s->image) {
uint16 w, h;
s->image->shp->get_size(&w, &h);
uint16 x, y;
s->image->shp->get_hot_point(&x, &y);
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);
}
if (!s->text.empty()) {
if (s->text_align != 0) {
display_wrapped_text(s);
} else {
if (s->text_color == 0xffff) {
font->drawString(screen, s->text.c_str(), s->x + x_off, s->y + y_off);
} else {
font->drawString(screen, s->text.c_str(), s->x + x_off, s->y + y_off, (uint8) s->text_color, (uint8) s->text_color);
}
}
}
}
}
if (screen_opacity < 255) {
screen->fade(x_off, y_off, 320, 200, screen_opacity, bg_color);
}
}
if (cursor)
cursor->display();
if (full_redraw)
screen->update(0, 0, area.width(), area.height());
else
screen->update(x_off, y_off, 320, 200);
}
void ScriptCutscene::Hide() {
GUI_Widget::Hide();
gui->force_full_redraw();
}
void ScriptCutscene::display_wrapped_text(CSSprite *s) {
uint8 text_color = (uint8) s->text_color;
size_t start = 0;
size_t found;
Std::string str = s->text + "^";
Std::list tokens;
int y = s->y;
Std::string line = "";
found = str.findFirstOf("^", start);
while (found != string::npos) {
Std::string token = str.substr(start, found - start);
y = display_wrapped_text_line(token, text_color, s->x, y, s->text_align);
start = found + 1;
found = str.findFirstOf("^", start);
}
}
int ScriptCutscene::display_wrapped_text_line(Std::string str, uint8 text_color, int x, int y, uint8 align_val) {
//font->drawString(screen, s->text.c_str(), s->x + x_off, s->y + y_off, text_color, text_color);
int len = 0;
size_t start = 0;
size_t found;
str = str + " ";
Std::list tokens;
int space_width = font->getStringWidth(" ");
//uint16 x1 = startx;
int width = 320 - x * 2;
int char_height = font->getCharHeight();
Std::string line = "";
found = str.findFirstOf(" ", start);
while (found != string::npos) {
Std::string token = str.substr(start, found - start);
int token_len = font->getStringWidth(token.c_str());
if (len + token_len > width) {
if (len > 0) {
len -= space_width;
}
font->drawString(screen, line.c_str(), x + x_off + (align_val == 1 ? 0 : (width - len)) / 2, y + y_off, text_color, text_color);
line = "";
y += char_height + 2;
len = 0;
}
len += token_len + space_width;
line = line + token + " ";
start = found + 1;
found = str.findFirstOf(" ", start);
}
if (len > 0) {
len -= space_width;
font->drawString(screen, line.c_str(), x + x_off + (align_val == 1 ? 0 : (width - len)) / 2, y + y_off, text_color, text_color);
y += char_height + 2;
}
return y;
}
static constexpr char u4ClassNameTbl[9][9] = {
"Mage",
"Bard",
"Fighter",
"Druid",
"Tinker",
"Paladin",
"Ranger",
"Shepherd",
"Avatar",
};
bool ScriptCutscene::load_u4_save_file(TransferSaveData &saveData) {
NuvieIOFileRead file;
Common::Path filename;
char name[16];
config_get_path(config, "party.sav", filename);
if (file.open(filename) == false) {
return false;
}
saveData.gameType = 4;
file.seek(10);
saveData.level = file.read2() / 100;
saveData.exp = file.read2();
saveData.str = file.read2();
saveData.dex = file.read2();
saveData.intelligence = file.read2();
saveData.magic = file.read2();
file.seek(28);
file.readToBuf((unsigned char *)name, 16);
saveData.name = Common::String(name).substr(0, 8);
saveData.gender = file.read1() == 0xc ? 0 : 1;
int classId = file.read1();
if (classId < 9) {
saveData.className = Common::String(u4ClassNameTbl[classId]);
}
return true;
}
bool ScriptCutscene::load_u5_save_file(TransferSaveData &saveData) {
NuvieIOFileRead file;
Common::Path filename;
char name[9];
config_get_path(config, "saved.gam", filename);
if (file.open(filename) == false) {
return false;
}
saveData.gameType = 5;
file.seek(2);
file.readToBuf((unsigned char *)name, 9);
saveData.name = Common::String(name);
saveData.gender = file.read1() == 0xc ? 0 : 1;
file.read1(); // class
file.read1(); // status
saveData.str = file.read1();
saveData.dex = file.read1();
saveData.intelligence = file.read1();
saveData.magic = file.read1();
file.seek(0x16);
saveData.exp = file.read2();
saveData.level = file.read1();
file.close();
return true;
}
void CSImage::setScale(uint16 percentage) {
if (scale == percentage) {
return;
}
if (scaled_shp)
delete scaled_shp;
scale = percentage;
if (scale == 100) {
scaled_shp = nullptr;
shp = orig_shp;
return;
}
uint16 sw, sh;
uint16 sx, sy;
uint16 tw, th;
uint16 tx, ty;
float scale_factor = (float)scale / 100;
orig_shp->get_size(&sw, &sh);
orig_shp->get_hot_point(&sx, &sy);
tw = (uint16)((float)sw * scale_factor);
th = (uint16)((float)sh * scale_factor);
tx = (uint16)((float)sx * scale_factor);
ty = (uint16)((float)sy * scale_factor);
scaled_shp = new U6Shape();
if (!scaled_shp->init(tw, th, tx, ty)) {
scale = 100;
delete scaled_shp;
scaled_shp = nullptr;
return;
}
scale_rect_8bit(orig_shp->get_data(), scaled_shp->get_data(), sw, sh, tw, th);
shp = scaled_shp;
return;
}
CSStarFieldImage::CSStarFieldImage(U6Shape *shape) : CSImage(shape), w(0), h(0) {
shp->get_size(&w, &h);
for (int i = 0; i < STAR_FIELD_NUM_STARS; i++) {
stars[i].color = 2;
stars[i].line = nullptr;
}
}
void CSStarFieldImage::updateEffect() {
unsigned char *data = shp->get_data();
memset(data, 0, w * h);
for (int i = 0; i < STAR_FIELD_NUM_STARS; i++) {
if (stars[i].line == nullptr) {
switch (NUVIE_RAND() % 4) {
case 0 :
stars[i].line = new U6LineWalker(w / 2, h / 2, 0, NUVIE_RAND() % h);
break;
case 1 :
stars[i].line = new U6LineWalker(w / 2, h / 2, w - 1, NUVIE_RAND() % h);
break;
case 2 :
stars[i].line = new U6LineWalker(w / 2, h / 2, NUVIE_RAND() % w, 0);
break;
case 3 :
stars[i].line = new U6LineWalker(w / 2, h / 2, NUVIE_RAND() % w, h - 1);
break;
}
stars[i].color = NUVIE_RAND() % 10 + 229;
uint16 start_pos = NUVIE_RAND() % (w / 2);
for (int j = 0; j < start_pos; j++) {
if (stars[i].line->step() == false) {
delete stars[i].line;
stars[i].line = nullptr;
break;
}
}
} else {
uint32 cur_x, cur_y;
if (stars[i].line->next(&cur_x, &cur_y) == false) {
delete stars[i].line;
stars[i].line = nullptr;
} else {
data[cur_y * w + cur_x] = stars[i].color;
}
}
}
}
} // End of namespace Nuvie
} // End of namespace Ultima