407 lines
11 KiB
C++
407 lines
11 KiB
C++
/* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/system.h"
|
|
#include "common/savefile.h"
|
|
#include "common/util.h"
|
|
#include "m4/adv_r/adv_file.h"
|
|
#include "m4/adv_r/adv_chk.h"
|
|
#include "m4/adv_r/adv_walk.h"
|
|
#include "m4/adv_r/db_env.h"
|
|
#include "m4/core/errors.h"
|
|
#include "m4/core/imath.h"
|
|
#include "m4/fileio/extensions.h"
|
|
#include "m4/fileio/info.h"
|
|
#include "m4/graphics/gr_pal.h"
|
|
#include "m4/gui/gui_buffer.h"
|
|
#include "m4/gui/gui_vmng.h"
|
|
#include "m4/platform/tile/tile_read.h"
|
|
#include "m4/m4.h"
|
|
|
|
namespace M4 {
|
|
|
|
static Common::String get_background_filename(const SceneDef *rdef);
|
|
static Common::String get_attribute_filename(const SceneDef *rdef);
|
|
static void recreate_animation_draw_screen(GrBuff **loadBuf);
|
|
static void troll_for_colors(RGB8 *newPal, uint8 minPalEntry, uint8 maxPalEntry);
|
|
|
|
void kernel_unload_room(SceneDef *rdef, GrBuff **code_data, GrBuff **loadBuffer) {
|
|
term_message("Unloading scene %d", _G(game).room_id);
|
|
|
|
if (_G(gameDrawBuff)) {
|
|
gui_buffer_deregister((Buffer *)_G(gameDrawBuff));
|
|
delete _G(gameDrawBuff);
|
|
_G(gameDrawBuff) = nullptr;
|
|
}
|
|
|
|
if (*code_data)
|
|
delete *code_data;
|
|
*code_data = nullptr;
|
|
|
|
if (*loadBuffer)
|
|
delete *loadBuffer;
|
|
*loadBuffer = nullptr;
|
|
|
|
if (!rdef)
|
|
return;
|
|
|
|
// Must we deallocate existing hot spots?
|
|
if (rdef->hotspots != nullptr) {
|
|
hotspot_delete_all(rdef->hotspots);
|
|
rdef->hotspots = nullptr;
|
|
}
|
|
rdef->num_hotspots = 0;
|
|
|
|
// Must we deallocate existing parallax?
|
|
if (rdef->parallax != nullptr) {
|
|
hotspot_delete_all(rdef->parallax);
|
|
rdef->parallax = nullptr;
|
|
}
|
|
rdef->num_parallax = 0;
|
|
|
|
// Must we deallocate existing props?
|
|
if (rdef->props != nullptr) {
|
|
hotspot_delete_all(rdef->props);
|
|
rdef->props = nullptr;
|
|
}
|
|
rdef->num_props = 0;
|
|
|
|
ClearRails();
|
|
}
|
|
|
|
|
|
bool kernel_load_room(int minPalEntry, int maxPalEntry, SceneDef *rdef, GrBuff **scr_orig_data, GrBuff **scr_orig) {
|
|
if (!scr_orig_data || !scr_orig) {
|
|
error_show(FL, 'BUF!', "load_picture_and_codes");
|
|
}
|
|
|
|
term_message("Reading scene %d", _G(game).new_room);
|
|
|
|
if (_G(game).previous_room != KERNEL_RESTORING_GAME) {
|
|
_G(game).previous_room = _G(game).room_id;
|
|
}
|
|
|
|
// Read DEF file
|
|
if (db_def_chk_read(_G(game).new_room, rdef) != -1) {
|
|
error_show(FL, 'DF:(', "trying to find %d.CHK", (uint32)_G(game).new_room);
|
|
}
|
|
|
|
set_walker_scaling(rdef);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Select background picture
|
|
|
|
_G(currBackgroundFN) = get_background_filename(rdef);
|
|
|
|
char *tempName = env_find(_G(currBackgroundFN));
|
|
if (tempName) {
|
|
// In normal rooms.db mode
|
|
_G(currBackgroundFN) = f_extension_new(tempName, "TT");
|
|
} else {
|
|
// In concat hag mode
|
|
_G(currBackgroundFN) = f_extension_new(_G(currBackgroundFN), "TT");
|
|
}
|
|
|
|
SysFile *pic_file = new SysFile(_G(currBackgroundFN));
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Select attributes code file
|
|
|
|
_G(currCodeFN) = get_attribute_filename(rdef);
|
|
|
|
tempName = env_find(_G(currCodeFN));
|
|
if (tempName) {
|
|
// In normal rooms.db mode
|
|
_G(currCodeFN) = f_extension_new(tempName, "COD");
|
|
} else {
|
|
// In concat hag mode
|
|
_G(currCodeFN) = f_extension_new(_G(currCodeFN), "COD");
|
|
}
|
|
|
|
SysFile *code_file = new SysFile(_G(currCodeFN));
|
|
if (!code_file->exists()) {
|
|
delete code_file;
|
|
code_file = nullptr;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Load background picture
|
|
|
|
term_message("load background");
|
|
RGB8 newPal[256];
|
|
load_background(pic_file, scr_orig, newPal);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Load attributes code file
|
|
|
|
term_message("load codes");
|
|
*scr_orig_data = load_codes(code_file);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Prepare buffers for display
|
|
|
|
recreate_animation_draw_screen(scr_orig);
|
|
troll_for_colors(newPal, minPalEntry, maxPalEntry);
|
|
|
|
gr_pal_reset_ega_colors(&_G(master_palette)[0]);
|
|
|
|
RestoreScreens(MIN_VIDEO_X, MIN_VIDEO_Y, MAX_VIDEO_X, MAX_VIDEO_Y);
|
|
|
|
pic_file->close();
|
|
delete pic_file;
|
|
|
|
if (code_file) {
|
|
code_file->close();
|
|
delete code_file;
|
|
}
|
|
|
|
if (*scr_orig_data) {
|
|
Buffer *scr_orig_data_buffer = (**scr_orig_data).get_buffer();
|
|
RestoreEdgeList(scr_orig_data_buffer);
|
|
(**scr_orig_data).release();
|
|
} else
|
|
RestoreEdgeList(nullptr);
|
|
|
|
_G(game).room_id = _G(game).new_room;
|
|
return true;
|
|
}
|
|
|
|
bool kernel_load_variant(const char *variant) {
|
|
SceneDef &sceneDef = _G(currentSceneDef);
|
|
GrBuff *codeBuff = _G(screenCodeBuff);
|
|
Common::String filename;
|
|
|
|
if (!codeBuff)
|
|
return false;
|
|
|
|
if (_G(kernel).hag_mode) {
|
|
filename = f_extension_new(variant, "COD");
|
|
} else {
|
|
char *base = env_find(sceneDef.art_base);
|
|
char *dotPos = nullptr;
|
|
if (base)
|
|
dotPos = strchr(base, '.');
|
|
|
|
if (!dotPos)
|
|
return false;
|
|
|
|
filename = f_extension_new(base, "COD");
|
|
|
|
if (!f_info_exists(Common::Path(filename)))
|
|
return false;
|
|
}
|
|
|
|
SysFile code_file(filename);
|
|
if (!code_file.exists())
|
|
error("Failed to load variant %s", filename.c_str());
|
|
|
|
// TODO: This is just copied from the room loading code,
|
|
// rather than disassembling the reset of the original method.
|
|
// Need to determine whether this is correct or not,
|
|
// then modified to clean screenCodeBuff and the edges.
|
|
|
|
GrBuff *scr_orig_data = load_codes(&code_file);
|
|
|
|
code_file.close();
|
|
|
|
if (scr_orig_data) {
|
|
_G(screenCodeBuff)->release();
|
|
free _G(screenCodeBuff);
|
|
RestoreEdgeList(nullptr);
|
|
|
|
Buffer *scr_orig_data_buffer = scr_orig_data->get_buffer();
|
|
RestoreEdgeList(scr_orig_data_buffer);
|
|
|
|
_G(screenCodeBuff) = scr_orig_data;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
GrBuff *load_codes(SysFile *code_file) {
|
|
// No this is not a cheat to allow bugs to live,
|
|
// if there is no code file, then we don't need a code buffer, either.
|
|
// it's perfectly acceptable, so there, NYAH!
|
|
if (!code_file)
|
|
return nullptr;
|
|
|
|
const int16 x_size = code_file->readSint16LE();
|
|
const int16 y_size = code_file->readSint16LE();
|
|
|
|
GrBuff *temp = new GrBuff(x_size, y_size);
|
|
Buffer *myBuff = temp->get_buffer();
|
|
byte *bufferHandle = myBuff->data;
|
|
|
|
for (int i = 0; i < y_size; i++) {
|
|
code_file->read(bufferHandle, x_size);
|
|
bufferHandle += myBuff->stride;
|
|
}
|
|
|
|
// Let the memory float
|
|
temp->release();
|
|
return temp;
|
|
}
|
|
|
|
bool load_background(SysFile *pic_file, GrBuff **loadBuffer, RGB8 *palette) {
|
|
int32 num_x_tiles, num_y_tiles, tile_x, tile_y, file_x, file_y;
|
|
int32 count = 0;
|
|
|
|
tt_read_header(pic_file, &file_x, &file_y,
|
|
&num_x_tiles, &num_y_tiles, &tile_x, &tile_y, palette);
|
|
|
|
*loadBuffer = new GrBuff(file_x, file_y);
|
|
|
|
if (!*loadBuffer)
|
|
error_show(FL, 'OOM!');
|
|
|
|
Buffer *theBuff = (**loadBuffer).get_buffer();
|
|
|
|
for (int i = 0; i < num_y_tiles; i++) {
|
|
for (int j = 0; j < num_x_tiles; j++) {
|
|
Buffer *out = tt_read(pic_file, count, tile_x, tile_y);
|
|
count++;
|
|
|
|
if (out && (out->data)) {
|
|
const int32 x_end = imath_min(file_x, (1 + j) * tile_x);
|
|
const int32 y_end = imath_min(file_y, (1 + i) * tile_y);
|
|
gr_buffer_rect_copy_2(out, theBuff, 0, 0, j * tile_x, i * tile_y,
|
|
x_end - (j * tile_x), y_end - (i * tile_y));
|
|
mem_free(out->data);
|
|
}
|
|
|
|
if (out)
|
|
mem_free(out);
|
|
}
|
|
}
|
|
|
|
(**loadBuffer).release();
|
|
return true;
|
|
}
|
|
|
|
static Common::SeekableReadStream *openForLoading(int slot) {
|
|
const Common::String slotName = g_engine->getSaveStateName(slot);
|
|
return g_system->getSavefileManager()->openForLoading(slotName);
|
|
}
|
|
|
|
bool kernel_save_game_exists(int32 slot) {
|
|
Common::SeekableReadStream *save = openForLoading(slot);
|
|
const bool result = save != nullptr;
|
|
delete save;
|
|
|
|
return result;
|
|
}
|
|
|
|
int kernel_save_game(int slot, const char *desc, int32 sizeofDesc, M4sprite *thumbNail, int32 sizeofThumbData) {
|
|
return g_engine->saveGameState(slot, desc, slot == 0).getCode() == Common::kNoError ? 0 : 1;
|
|
}
|
|
|
|
bool kernel_load_game(int slot) {
|
|
return g_engine->loadGameStateDoIt(slot).getCode() == Common::kNoError;
|
|
}
|
|
|
|
int32 extract_room_num(const Common::String &name) {
|
|
if ((name[0] == 'C' || name[0] == 'c') &&
|
|
(name[1] == 'O' || name[1] == 'o') &&
|
|
(name[2] == 'M' || name[2] == 'm'))
|
|
return _G(global_sound_room);
|
|
|
|
if (Common::isDigit(name[0]) && Common::isDigit(name[1]) && Common::isDigit(name[2])) {
|
|
return ((int32)(name[0] - '0')) * 100 + ((int32)(name[1] - '0')) * 10 + ((int32)(name[2] - '0'));
|
|
}
|
|
|
|
return _G(game).room_id;
|
|
}
|
|
|
|
static Common::String get_background_filename(const SceneDef *rdef) {
|
|
if (_G(art_base_override) != nullptr) {
|
|
return _G(art_base_override);
|
|
}
|
|
|
|
return rdef->art_base;
|
|
}
|
|
|
|
static Common::String get_attribute_filename(const SceneDef *rdef) {
|
|
if (_G(art_base_override) == nullptr || !_G(use_alternate_attribute_file)) {
|
|
return rdef->art_base;
|
|
}
|
|
|
|
return _G(art_base_override);
|
|
}
|
|
|
|
static void recreate_animation_draw_screen(GrBuff **loadBuf) {
|
|
// Remove previous animation draw screen
|
|
if (_G(gameDrawBuff)) {
|
|
gui_buffer_deregister((Buffer *)_G(gameDrawBuff));
|
|
delete _G(gameDrawBuff);
|
|
_G(gameDrawBuff) = nullptr;
|
|
_G(game_buff_ptr) = nullptr;
|
|
}
|
|
_G(gameDrawBuff) = new GrBuff((**loadBuf).w, (**loadBuf).h);
|
|
gui_GrBuff_register(_G(kernel).letter_box_x, _G(kernel).letter_box_y, _G(gameDrawBuff), SF_BACKGRND | SF_GET_ALL | SF_BLOCK_NONE, nullptr);
|
|
gui_buffer_activate((Buffer *)_G(gameDrawBuff));
|
|
vmng_screen_to_back((void *)_G(gameDrawBuff));
|
|
_G(game_buff_ptr) = vmng_screen_find(_G(gameDrawBuff), nullptr);
|
|
|
|
Buffer *theBuff = (**loadBuf).get_buffer();
|
|
Buffer *game_buff = (*_G(gameDrawBuff)).get_buffer();
|
|
gr_buffer_rect_copy_2(theBuff, game_buff, 0, 0, 0, 0,
|
|
imath_min((**loadBuf).w, game_buff->w), imath_min((**loadBuf).h, game_buff->h));
|
|
|
|
(**loadBuf).release();
|
|
(*_G(gameDrawBuff)).release();
|
|
}
|
|
|
|
static void troll_for_colors(RGB8 *newPal, uint8 minPalEntry, uint8 maxPalEntry) {
|
|
bool gotOne = false;
|
|
for (int16 pal_iter = minPalEntry; pal_iter <= maxPalEntry; pal_iter++) { // accept any colors that came with the background
|
|
if (gotOne || (newPal[pal_iter].r | newPal[pal_iter].g | newPal[pal_iter].b)) {
|
|
gotOne = true;
|
|
// colors are 6 bit...
|
|
_G(master_palette)[pal_iter].r = newPal[pal_iter].r << 2;
|
|
_G(master_palette)[pal_iter].g = newPal[pal_iter].g << 2;
|
|
_G(master_palette)[pal_iter].b = newPal[pal_iter].b << 2;
|
|
}
|
|
}
|
|
|
|
if (gotOne) {
|
|
gr_pal_interface(&_G(master_palette)[0]); // enforce interface colors
|
|
}
|
|
}
|
|
|
|
Common::String expand_name_2_RAW(const Common::String &name, int32 room_num) {
|
|
Common::String tempName = f_extension_new(name, "RAW");
|
|
|
|
if (!_G(kernel).hag_mode) {
|
|
if (room_num == -1)
|
|
room_num = extract_room_num(name);
|
|
|
|
return Common::String::format("%d\\%s", room_num, tempName.c_str());
|
|
}
|
|
|
|
return tempName;
|
|
}
|
|
|
|
Common::String expand_name_2_HMP(const Common::String &name, int32 room_num) {
|
|
return f_extension_new(name, "HMP");
|
|
}
|
|
|
|
} // End of namespace M4
|