scummvm/engines/glk/adrift/scresour.cpp
2019-09-25 20:13:27 -07:00

316 lines
9.4 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "glk/adrift/scare.h"
#include "glk/adrift/scprotos.h"
#include "glk/adrift/scgamest.h"
namespace Glk {
namespace Adrift {
/* Assorted definitions and constants. */
static const sc_char NUL = '\0';
/*
* res_has_sound()
* res_has_graphics()
*
* Return TRUE if the game uses sound or graphics.
*/
sc_bool res_has_sound(sc_gameref_t game) {
const sc_prop_setref_t bundle = gs_get_bundle(game);
sc_vartype_t vt_key[2];
sc_bool has_sound;
assert(gs_is_game_valid(game));
vt_key[0].string = "Globals";
vt_key[1].string = "Sound";
has_sound = prop_get_boolean(bundle, "B<-ss", vt_key);
return has_sound;
}
sc_bool res_has_graphics(sc_gameref_t game) {
const sc_prop_setref_t bundle = gs_get_bundle(game);
sc_vartype_t vt_key[2];
sc_bool has_graphics;
assert(gs_is_game_valid(game));
vt_key[0].string = "Globals";
vt_key[1].string = "Graphics";
has_graphics = prop_get_boolean(bundle, "B<-ss", vt_key);
return has_graphics;
}
/*
* res_set_resource()
* res_clear_resource()
* res_compare_resource()
*
* Convenience functions to set, clear, and compare resource fields.
*/
static void res_set_resource(sc_resourceref_t resource, const sc_char *name,
sc_int offset, sc_int length) {
resource->name = name;
resource->offset = offset;
resource->length = length;
}
void res_clear_resource(sc_resourceref_t resource) {
res_set_resource(resource, "", 0, 0);
}
sc_bool res_compare_resource(sc_resourceref_t from, sc_resourceref_t with) {
return strcmp(from->name, with->name) == 0
&& from->offset == with->offset && from->length == with->length;
}
/*
* res_handle_resource()
*
* General helper for handling graphics and sound resources. Supplied with a
* partial key to the node containing resources, it identifies what resource
* is appropriate, and sets this as the requested resource in the game, for
* later use on sync'ing, using the handler appropriate for the game version.
*
* The partial format is something like "sis" (the bit to follow I<- or S<-
* in prop_get), and the partial key is guaranteed to contain at least
* strlen(partial_format) elements.
*/
void res_handle_resource(sc_gameref_t game, const sc_char *partial_format,
const sc_vartype_t vt_partial[]) {
const sc_prop_setref_t bundle = gs_get_bundle(game);
sc_vartype_t vt_key[2], *vt_full;
sc_int partial_length, resource_start_offset;
sc_bool embedded;
sc_char *format;
assert(gs_is_game_valid(game));
assert(partial_format && vt_partial);
/*
* Check for resources. If this game doesn't use any, exit now to avoid the
* overhead of pointless lookups and allocations.
*/
if (!(res_has_sound(game) || res_has_graphics(game)))
return;
/*
* Get the global offset for all resources. For version 3.9 games this
* should be zero. For version 4.0 games, it's the start of resource data
* in the TAF file where resources are embedded.
*/
vt_key[0].string = "ResourceOffset";
resource_start_offset = prop_get_integer(bundle, "I<-s", vt_key);
/*
* Get the flag that indicated embedded resources. For version 3.9 games
* this should be false. If not set, offset and length are forced to zero
* for interface functions.
*/
vt_key[0].string = "Globals";
vt_key[1].string = "Embedded";
embedded = prop_get_boolean(bundle, "B<-ss", vt_key);
/*
* Allocate a format for use with properties calls, five characters longer
* than the partial passed in. Build a key one element larger than the
* partial supplied, and copy over all supplied elements.
*/
partial_length = strlen(partial_format);
format = (sc_char *)sc_malloc(partial_length + 5);
vt_full = (sc_vartype_t *)sc_malloc((partial_length + 1) * sizeof(vt_partial[0]));
memcpy(vt_full, vt_partial, partial_length * sizeof(vt_partial[0]));
/* Search for sound resources, and offer if found. */
if (res_has_sound(game)) {
const sc_char *soundfile;
sc_int soundoffset, soundlen;
/* Get soundfile property from the node supplied. */
vt_full[partial_length].string = "SoundFile";
strcpy(format, "S<-");
strcat(format, partial_format);
strcat(format, "s");
soundfile = prop_get_string(bundle, format, vt_full);
/* If a sound is defined, handle it. */
if (!sc_strempty(soundfile)) {
if (embedded) {
/* Retrieve offset and length. */
vt_full[partial_length].string = "SoundOffset";
strcpy(format, "I<-");
strcat(format, partial_format);
strcat(format, "s");
soundoffset = prop_get_integer(bundle, format, vt_full)
+ resource_start_offset;
vt_full[partial_length].string = "SoundLen";
strcpy(format, "I<-");
strcat(format, partial_format);
strcat(format, "s");
soundlen = prop_get_integer(bundle, format, vt_full);
} else {
/* Coerce offset and length to zero. */
soundoffset = 0;
soundlen = 0;
}
/*
* If the sound is the special "##", latch stop, otherwise note
* details to play on sync.
*/
if (!strcmp(soundfile, "##")) {
game->stop_sound = TRUE;
res_clear_resource(&game->requested_sound);
} else {
res_set_resource(&game->requested_sound,
soundfile, soundoffset, soundlen);
}
}
}
/* Now do the same thing for graphics resources. */
if (res_has_graphics(game)) {
const sc_char *graphicfile;
sc_int graphicoffset, graphiclen;
/* Get graphicfile property from the node supplied. */
vt_full[partial_length].string = "GraphicFile";
strcpy(format, "S<-");
strcat(format, partial_format);
strcat(format, "s");
graphicfile = prop_get_string(bundle, format, vt_full);
/* If a graphic is defined, handle it. */
if (!sc_strempty(graphicfile)) {
if (embedded) {
/* Retrieve offset and length. */
vt_full[partial_length].string = "GraphicOffset";
strcpy(format, "I<-");
strcat(format, partial_format);
strcat(format, "s");
graphicoffset = prop_get_integer(bundle, format, vt_full)
+ resource_start_offset;
vt_full[partial_length].string = "GraphicLen";
strcpy(format, "I<-");
strcat(format, partial_format);
strcat(format, "s");
graphiclen = prop_get_integer(bundle, format, vt_full);
} else {
/* Coerce offset and length to zero. */
graphicoffset = 0;
graphiclen = 0;
}
/* Graphics resource retrieved, note to show on sync. */
res_set_resource(&game->requested_graphic,
graphicfile, graphicoffset, graphiclen);
}
}
/* Free allocated memory. */
sc_free(format);
sc_free(vt_full);
}
/*
* res_sync_resources()
*
* Bring resources into line with the game; called on undo, restart,
* restore, and so on.
*/
void res_sync_resources(sc_gameref_t game) {
assert(gs_is_game_valid(game));
/* Deal with any latched sound stop first. */
if (game->stop_sound) {
if (game->sound_active) {
if_update_sound("", 0, 0, FALSE);
game->sound_active = FALSE;
res_clear_resource(&game->playing_sound);
}
game->stop_sound = FALSE;
}
/* Look for a change of sound, and pass to interface on change. */
if (!res_compare_resource(&game->playing_sound,
&game->requested_sound)) {
const sc_char *name;
sc_char *clean_name;
sc_bool is_looping;
/* If the sound name ends '##', this is a looping sound. */
name = game->requested_sound.name;
is_looping = !strcmp(name + strlen(name) - 2, "##");
clean_name = (sc_char *)sc_malloc(strlen(name) + 1);
strcpy(clean_name, name);
if (is_looping)
clean_name[strlen(clean_name) - 2] = NUL;
if_update_sound(clean_name,
game->requested_sound.offset,
game->requested_sound.length, is_looping);
game->playing_sound = game->requested_sound;
game->sound_active = TRUE;
sc_free(clean_name);
}
/* Look for a change of graphic, and pass to interface on change. */
if (!res_compare_resource(&game->displayed_graphic,
&game->requested_graphic)) {
if_update_graphic(game->requested_graphic.name,
game->requested_graphic.offset,
game->requested_graphic.length);
game->displayed_graphic = game->requested_graphic;
}
}
/*
* res_cancel_resources()
*
* Turn off sound and graphics, and reset the game's tracking of resources in
* use to match. Called on game restart or restore.
*/
void res_cancel_resources(sc_gameref_t game) {
assert(gs_is_game_valid(game));
/* Request that everything stops and clears. */
game->stop_sound = FALSE;
res_clear_resource(&game->requested_sound);
res_clear_resource(&game->requested_graphic);
/* Synchronize to have the above take effect. */
res_sync_resources(game);
}
} // End of namespace Adrift
} // End of namespace Glk