mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-12 14:09:28 +00:00
316 lines
9.4 KiB
C++
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
|