scummvm/saga/game.cpp

819 lines
16 KiB
C++
Raw Normal View History

/* ScummVM - Scumm Interpreter
* Copyright (C) 2004 The ScummVM project
*
* The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*
*/
/*
Description:
Game detection, general game parameters
Notes:
*/
#include "reinherit.h"
#include "yslib.h"
#include "common/file.h"
/*
* Uses the following modules:
\*--------------------------------------------------------------------------*/
#include "rscfile_mod.h"
#include "cvar_mod.h"
#include "ite_introproc_mod.h"
#include "interface_mod.h"
/*
* Begin module component
\*--------------------------------------------------------------------------*/
#include "game_mod.h"
#include "game.h"
namespace Saga {
/*--------------------------------------------------------------------------*\
* Inherit the Earth - Demo version
\*--------------------------------------------------------------------------*/
R_GAME_FILEDESC ITEDEMO_GameFiles[] = {
{"ITE.RSC", R_GAME_RESOURCEFILE}
,
{"ITE.DMO", R_GAME_DEMOFILE}
,
{"SCRIPTS.RSC", R_GAME_SCRIPTFILE}
,
{"VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE}
};
R_GAME_FONTDESC ITEDEMO_GameFonts[] = {
{R_GAME_FONT_SMALL, 0}
,
{R_GAME_FONT_MEDIUM, 1}
};
R_GAME_SOUNDINFO ITEDEMO_GameSound = {
R_GAME_SOUND_VOC, 0, 0, 0
};
/*--------------------------------------------------------------------------*\
* Inherit the Earth - Diskette version
\*--------------------------------------------------------------------------*/
R_GAME_FILEDESC ITEDISK_GameFiles[] = {
{"ITE.RSC", R_GAME_RESOURCEFILE}
,
{"SCRIPTS.RSC", R_GAME_SCRIPTFILE}
,
{"VOICES.RSC", R_GAME_SOUNDFILE | R_GAME_VOICEFILE}
};
R_GAME_FONTDESC ITEDISK_GameFonts[] = {
{R_GAME_FONT_MEDIUM, 0}
,
{R_GAME_FONT_LARGE, 1}
,
{R_GAME_FONT_SMALL, 2}
};
R_GAME_RESOURCEDESC ITE_Resources = {
ITE_SCENE_LUT, /* Scene lookup table RN */
ITE_SCRIPT_LUT, /* Script lookup table RN */
ITE_COMMAND_PANEL,
ITE_DIALOGUE_PANEL
};
R_GAME_SOUNDINFO ITE_GameSound = {
R_GAME_SOUND_VOC, 0, 0, 0
};
/*--------------------------------------------------------------------------*\
* Inherit the Earth - CD Enhanced version
\*--------------------------------------------------------------------------*/
R_GAME_FILEDESC ITECD_GameFiles[] = {
{"ITE.RSC", R_GAME_RESOURCEFILE}
,
{"SCRIPTS.RSC", R_GAME_SCRIPTFILE}
,
{"SOUNDS.RSC", R_GAME_SOUNDFILE}
,
{"VOICES.RSC", R_GAME_VOICEFILE}
};
R_GAME_FONTDESC ITECD_GameFonts[] = {
{R_GAME_FONT_MEDIUM, 0}
,
{R_GAME_FONT_LARGE, 1}
,
{R_GAME_FONT_SMALL, 2}
};
R_GAME_SOUNDINFO ITECD_GameSound = {
R_GAME_SOUND_PCM,
22050,
16,
0
};
/*--------------------------------------------------------------------------*\
* I Have No Mouth and I Must Scream - Demo version
\*--------------------------------------------------------------------------*/
R_GAME_FILEDESC IHNMDEMO_GameFiles[] = {
{"SCREAM.RES", R_GAME_RESOURCEFILE}
,
{"SCRIPTS.RES", R_GAME_SCRIPTFILE}
,
{"SFX.RES", R_GAME_SOUNDFILE}
,
{"VOICESD.RES", R_GAME_VOICEFILE}
};
/*--------------------------------------------------------------------------*\
* I Have No Mouth and I Must Scream - Retail CD version
\*--------------------------------------------------------------------------*/
R_GAME_FILEDESC IHNMCD_GameFiles[] = {
{"MUSICFM.RES", R_GAME_MUSICFILE}
,
{"MUSICGM.RES", R_GAME_MUSICFILE}
,
{"SCREAM.RES", R_GAME_RESOURCEFILE}
,
{"SCRIPTS.RES", R_GAME_SCRIPTFILE}
,
{"SFX.RES", R_GAME_SOUNDFILE}
,
{"VOICES1.RES", R_GAME_VOICEFILE}
,
{"VOICES2.RES", R_GAME_VOICEFILE}
,
{"VOICES3.RES", R_GAME_VOICEFILE}
,
{"VOICES4.RES", R_GAME_VOICEFILE}
,
{"VOICES5.RES", R_GAME_VOICEFILE}
,
{"VOICES6.RES", R_GAME_VOICEFILE}
,
{"VOICESS.RES", R_GAME_VOICEFILE}
};
R_GAME_FONTDESC IHNMCD_GameFonts[] = {
{R_GAME_FONT_MEDIUM, 2}
,
{R_GAME_FONT_LARGE, 3}
,
{R_GAME_FONT_SMALL, 4}
,
{R_GAME_FONT_SMALL2, 5}
,
{R_GAME_FONT_MEDIUM2, 6}
,
{R_GAME_FONT_LARGE2, 7}
,
{R_GAME_FONT_LARGE3, 8}
};
R_GAME_RESOURCEDESC IHNM_Resources[] = {
IHNM_SCENE_LUT, /* Scene lookup table RN */
IHNM_SCRIPT_LUT, /* Script lookup table RN */
IHNM_COMMAND_PANEL,
IHNM_DIALOGUE_PANEL
};
R_GAME_SOUNDINFO IHNM_GameSound = {
R_GAME_SOUND_WAV, 0, 0, 0
};
R_GAMEDESC GameDescs[] = {
/* Inherit the earth - Demo version
* \*------------------------------------------------------------- */
{
R_GAMETYPE_ITE,
R_GAME_ITE_DEMO, /* Game id */
"Inherit the Earth - Demo version", /* Game title */
320, 200, /* Logical resolution */
137, /* Scene viewport height */
ITE_DEFAULT_SCENE, /* Starting scene number */
&ITE_Resources,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(ITEDEMO_GameFiles), /* Game datafiles */
ITEDEMO_GameFiles,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(ITEDEMO_GameFonts),
ITEDEMO_GameFonts,
&ITEDEMO_GameSound,
Verify_ITEDEMO, /* Game verification func */
0 /* Game supported flag */
}
,
/* Inherit the earth - Disk version
* \*------------------------------------------------------------- */
{
R_GAMETYPE_ITE,
R_GAME_ITE_DISK,
"Inherit the Earth - Disk version",
320, 200,
137,
ITE_DEFAULT_SCENE,
&ITE_Resources,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(ITEDISK_GameFiles),
ITEDISK_GameFiles,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(ITEDISK_GameFonts),
ITEDISK_GameFonts,
&ITE_GameSound,
Verify_ITEDISK,
1}
,
/* Inherit the earth - CD version
* \*------------------------------------------------------------- */
{
R_GAMETYPE_ITE,
R_GAME_ITE_CD,
"Inherit the Earth - CD version",
320, 200,
137,
ITE_DEFAULT_SCENE,
&ITE_Resources,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(ITECD_GameFiles),
ITECD_GameFiles,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(ITECD_GameFonts),
ITECD_GameFonts,
&ITECD_GameSound,
NULL,
1}
,
/* I Have No Mouth And I Must Scream - Demo version
* \*------------------------------------------------------------- */
{
R_GAMETYPE_IHNM,
R_GAME_IHNM_DEMO,
"I Have No Mouth - Demo version",
640, 480,
304,
0,
IHNM_Resources,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(IHNMDEMO_GameFiles),
IHNMDEMO_GameFiles,
0,
NULL,
&IHNM_GameSound,
NULL,
0}
,
/* I Have No Mouth And I Must Scream - CD version
* \*------------------------------------------------------------- */
{
R_GAMETYPE_IHNM,
R_GAME_IHNM_CD,
"I Have No Mouth - CD version",
640, 480,
304,
1,
IHNM_Resources,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(IHNMCD_GameFiles),
IHNMCD_GameFiles,
2004-04-25 15:14:46 +00:00
ARRAYSIZE(IHNMCD_GameFonts),
IHNMCD_GameFonts,
&IHNM_GameSound,
NULL,
1}
};
static R_GAMEMODULE GameModule;
void GAME_setGameDirectory(const char *gamedir) {
assert(gamedir != NULL);
debug(0, "Using game data path: %s", gamedir);
strcpy(GameModule.game_dir, gamedir);
strcpy(GameModule.data_dir, ".");
}
int GAME_Register(void)
{
return R_SUCCESS;
/* Register "gamedir" cfg cvar
* \*----------------------------------------- */
strncpy(GameModule.game_dir, "./", R_MAXPATH);
if (CVAR_Register_S(GameModule.game_dir,
"gamedir", NULL, R_CVAR_CFG, R_MAXPATH) != R_SUCCESS) {
return R_FAILURE;
}
/* Register "datadir" cfg cvar
* \*----------------------------------------- */
strncpy(GameModule.data_dir, "./", R_MAXPATH);
if (CVAR_Register_S(GameModule.data_dir,
"datadir", NULL, R_CVAR_CFG, R_MAXPATH) != R_SUCCESS) {
return R_FAILURE;
}
/* Register "g_language" cfg cvar
* \*----------------------------------------- */
strncpy(GameModule.game_dir, "us", R_MAXPATH);
if (CVAR_Register_S(GameModule.game_language,
"g_language",
NULL, R_CVAR_CFG, R_GAME_LANGSTR_LIMIT) != R_SUCCESS) {
return R_FAILURE;
}
/* Register "g_skipintro" cfg cvar
* \*----------------------------------------- */
if (CVAR_Register_I(&GameModule.g_skipintro,
"g_skipintro", NULL, R_CVAR_CFG, 0, 1) != R_SUCCESS) {
return R_FAILURE;
}
return R_SUCCESS;
}
int GAME_Init(void)
{
uint game_n;
char *game_dir;
game_dir = GameModule.game_dir;
if (DetectGame(game_dir, &game_n) != R_SUCCESS) {
GameModule.err_str = "No valid games were found in the "
"specified directory.";
return R_FAILURE;
}
if (!GameDescs[game_n].gd_supported) {
GameModule.err_str = "This game is not currently supported.";
return R_FAILURE;
}
if (LoadGame(game_dir, game_n) != R_SUCCESS) {
GameModule.err_str = "Error loading game resource files.";
return R_FAILURE;
}
/* Load dialogue file
* \*------------------------------------------------------------- */
LoadLanguage();
return R_SUCCESS;
}
int LoadLanguage(void)
{
char lang_file[R_MAXPATH];
char lang_path[R_MAXPATH];
uint game_n;
File test_file;
game_n = GameModule.game_number;
if (GameDescs[game_n].gd_game_type == R_GAMETYPE_ITE) {
snprintf(lang_file, R_MAXPATH,
"%s%s.%s",
R_GAME_ITE_LANG_PREFIX,
GameModule.game_language, R_GAME_LANG_EXT);
if (!test_file.open(lang_file)) {
R_printf(R_STDOUT,
"Couldn't open language file %s. "
"Using default (US English)\n", lang_path);
return R_SUCCESS;
}
test_file.close();
if (INTERFACE_RegisterLang() != R_SUCCESS) {
R_printf(R_STDERR,
"Error registering interface language cvars.");
return R_FAILURE;
}
if (ITE_IntroRegisterLang() != R_SUCCESS) {
R_printf(R_STDERR,
"Error registering intro sequence language cvars.");
return R_FAILURE;
}
R_printf(R_STDOUT, "Using language file %s.\n", lang_path);
// FIXME
//CFG_Read(lang_path);
} else {
R_printf(R_STDOUT,
"Language support for this game not implemented.\n");
}
return R_SUCCESS;
}
int GAME_GetErrN(void)
{
return 0;
}
const char *GAME_GetErrS(void)
{
return GameModule.err_str == NULL
? "No error description." : GameModule.err_str;
}
int GAME_GetFileContext(R_RSCFILE_CONTEXT ** ctxt_p, uint r_type, int param)
{
R_RSCFILE_CONTEXT *found_ctxt = NULL;
uint i;
YS_IGNORE_PARAM(param);
if (ctxt_p == NULL) {
return R_FAILURE;
}
for (i = 0; i < GameModule.gfile_n; i++) {
if (GameModule.gfile_data[i].file_types & r_type) {
found_ctxt = GameModule.gfile_data[i].file_ctxt;
}
}
if (found_ctxt != NULL) {
*ctxt_p = found_ctxt;
} else {
*ctxt_p = NULL;
}
return R_SUCCESS;
}
int DetectGame(const char *game_dir, uint * game_n_p)
{
2004-04-25 15:14:46 +00:00
uint game_count = ARRAYSIZE(GameDescs);
uint game_n;
uint file_count;
uint file_n;
File test_file;
int file_missing = 0;
int found_game = 0;
if ((game_dir == NULL) || (game_n_p == NULL)) {
return R_FAILURE;
}
for (game_n = 0; (game_n < game_count) && !found_game; game_n++) {
file_count = GameDescs[game_n].gd_filect;
file_missing = 0;
/* Try to open all files for this game */
for (file_n = 0; file_n < file_count; file_n++) {
if (!test_file.open(GameDescs[game_n].gd_filedescs[file_n].gf_fname)) {
file_missing = 1;
break;
}
test_file.close();
}
/* Try the next game, couldn't find all files for the current
* game */
if (file_missing) {
continue;
}
/* If there's a verification function for this game, use it,
* otherwise assume we've found the game if all files are found. */
found_game = 1;
if (GameDescs[game_n].gd_verifyf != NULL &&
GameDescs[game_n].gd_verifyf(game_dir) != R_SUCCESS) {
found_game = 0;
}
if (found_game) {
R_printf(R_STDOUT,
"Found game: %s\n", GameDescs[game_n].gd_title);
*game_n_p = game_n;
return R_SUCCESS;
}
}
return R_FAILURE;
}
int LoadGame(const char *game_dir, uint game_n)
{
R_RSCFILE_CONTEXT *load_ctxt;
2004-04-25 15:14:46 +00:00
uint game_count = ARRAYSIZE(GameDescs);
const char *game_fname;
uint game_filect;
uint i;
if ((game_dir == NULL) || (game_n >= game_count)) {
return R_FAILURE;
}
game_filect = GameDescs[game_n].gd_filect;
GameModule.gfile_data = (R_GAME_FILEDATA *)malloc(game_filect *
sizeof *GameModule.gfile_data);
if (GameModule.gfile_data == NULL) {
return R_MEM;
}
GameModule.gfile_n = game_filect;
/* Load game resource files
* \*------------------------------------------------------------- */
for (i = 0; i < game_filect; i++) {
load_ctxt = RSC_CreateContext();
game_fname = GameDescs[game_n].gd_filedescs[i].gf_fname;
if (RSC_OpenContext(load_ctxt, game_fname) != R_SUCCESS) {
return R_FAILURE;
}
R_printf(R_STDOUT, "Opened resource file: %s\n", game_fname);
GameModule.gfile_data[i].file_ctxt = load_ctxt;
GameModule.gfile_data[i].file_types =
GameDescs[game_n].gd_filedescs[i].gf_type;
GameModule.gfile_data[i].file_flags = 0;
}
/* Load game font data
* \*------------------------------------------------------------- */
GameModule.gd_fontct = GameDescs[game_n].gd_fontct;
GameModule.gd_fontdescs = GameDescs[game_n].gd_fontdescs;
/* Finish initialization
* \*------------------------------------------------------------- */
GameModule.game_number = game_n;
GameModule.gamedesc = &GameDescs[game_n];
GameModule.game_init = 1;
return R_SUCCESS;
}
int GAME_GetResourceInfo(R_GAME_RESOURCEDESC * rsc_desc)
{
assert(rsc_desc != NULL);
*rsc_desc = *GameModule.gamedesc->gd_resource_desc;
return R_SUCCESS;
}
int GAME_GetSoundInfo(R_GAME_SOUNDINFO * snd_info)
{
assert(snd_info != NULL);
*snd_info = *GameModule.gamedesc->gd_soundinfo;
return R_SUCCESS;
}
int GAME_GetDisplayInfo(R_GAME_DISPLAYINFO * disp_info)
{
int game_n;
assert(disp_info != NULL);
if (!GameModule.game_init) {
return R_FAILURE;
}
game_n = GameModule.game_number;
disp_info->logical_w = GameDescs[game_n].gd_logical_w;
disp_info->logical_h = GameDescs[game_n].gd_logical_h;
disp_info->scene_h = GameDescs[game_n].gd_scene_h;
return R_SUCCESS;
}
int GAME_GetFontInfo(R_GAME_FONTDESC ** gf_desc, int *font_n)
{
assert((gf_desc != NULL) && (font_n != NULL));
*gf_desc = GameModule.gd_fontdescs;
*font_n = GameModule.gd_fontct;
return R_SUCCESS;
}
int GAME_GetSceneInfo(R_GAME_SCENEDESC * gs_desc)
{
assert(gs_desc != NULL);
gs_desc->first_scene = GameModule.gamedesc->gd_startscene;
gs_desc->scene_lut_rn =
GameModule.gamedesc->gd_resource_desc->scene_lut_rn;
return R_SUCCESS;
}
int GAME_GetGame(void)
{
return GameModule.gamedesc->gd_game_id;
}
int GAME_GetGameType(void)
{
return GameModule.gamedesc->gd_game_type;
}
int Verify_ITEDEMO(const char *game_dir)
{
YS_IGNORE_PARAM(game_dir);
return R_SUCCESS;
}
int Verify_ITEDISK(const char *game_dir)
{
R_RSCFILE_CONTEXT *test_ctx;
ulong script_lut_len;
ulong script_lut_rn;
int verified = 0;
test_ctx = RSC_CreateContext();
if (RSC_OpenContext(test_ctx, "ITE.RSC") != R_SUCCESS) {
return R_FAILURE;
}
script_lut_rn =
GameDescs[R_GAME_ITE_DISK].gd_resource_desc->script_lut_rn;
if (RSC_GetResourceSize(test_ctx,
script_lut_rn, &script_lut_len) != R_SUCCESS) {
RSC_DestroyContext(test_ctx);
return R_FAILURE;
}
RSC_DestroyContext(test_ctx);
if (script_lut_len % R_SCR_LUT_ENTRYLEN_ITEDISK == 0) {
verified = 1;
}
if (!verified) {
return R_FAILURE;
}
return R_SUCCESS;
}
int Verify_ITECD(const char *game_dir)
{
YS_IGNORE_PARAM(game_dir);
return R_SUCCESS;
}
int Verify_IHNMDEMO(const char *game_dir)
{
YS_IGNORE_PARAM(game_dir);
return R_SUCCESS;
}
int Verify_IHNMCD(const char *game_dir)
{
YS_IGNORE_PARAM(game_dir);
return R_SUCCESS;
}
} // End of namespace Saga