scummvm/engines/icb/game_script.cpp
2020-10-06 09:51:20 +02:00

305 lines
7.2 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* file distributed with this source distribution.
*
* Additional copyright for this file:
* Copyright (C) 1999-2000 Revolution Software Ltd.
* This code is based on source code created by Revolution Software,
* used with permission.
*
* 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 "engines/icb/res_man.h"
#include "engines/icb/game_script.h"
#include "engines/icb/debug.h"
#include "engines/icb/mission.h"
#include "engines/icb/p4.h"
#include "engines/icb/global_objects.h"
#include "engines/icb/global_switches.h"
#include "engines/icb/sound.h"
#include "engines/icb/global_vars.h"
#include "engines/icb/main_menu.h"
#include "common/events.h"
#include "common/textconsole.h"
namespace ICB {
void _game_script::Restart_game_script() {
pc = 0;
Init_globals(); // must reload the global vars for the new game!
}
bool8 _game_script::Running_from_gamescript() { return running_from_game_script; }
bool8 _game_script::Init_game_script() {
// assume
running_from_game_script = FALSE8;
// If we are running tt mode (translator mode) then ignore any game scripts
if (tt)
return FALSE8;
// build name
sprintf(fname, GAMESCRIPT_PATH);
sprintf(cluster, GLOBAL_CLUSTER_PATH);
fn_hash = HashString(fname);
cluster_hash = HashString(cluster);
warning("Init_gs::'%s'::'%s'", fname, cluster);
if (private_session_resman->Test_file(fname, fn_hash, cluster, cluster_hash)) {
// program counter in gameScript
pc = 0;
warning("Gamescript found");
running_from_game_script = TRUE8;
return TRUE8;
}
warning("Gamescript: %s %s not found", fname, cluster);
return FALSE8;
}
void Init_play_movie(const char *param0, bool8 param1);
// runs the gamescript until a given bookmark then returns
// so the pc is set to the correct place for a mission....
void _game_script::Run_to_bookmark(const char *name) {
if ((g_mission) && (g_mission->session)) {
// global
buf = private_session_resman->Res_open(fname, fn_hash, cluster, cluster_hash);
} else {
// global
buf = private_session_resman->Res_open(fname, fn_hash, cluster, cluster_hash);
}
char command;
char p1[ENGINE_STRING_LEN];
// reset program counter (but keep demo flag!)
int demo = g_globalScriptVariables.GetVariable("demo");
Restart_game_script();
g_globalScriptVariables.SetVariable("demo", demo);
// now loop through gamescript...
while (1) {
command = buf[pc];
switch (command) {
case 0:
Fatal_error("Bookmark %s not found in gamescript", name);
break;
case 'B':
pc += 2;
Fetch_next_param(p1);
Fetch_next_line();
// if this is the bookmark then return, pc is in the right place...
if (strcmp(p1, name) == 0)
return;
// otherwise we keep looking...
break;
default: // any other command
Fetch_next_line();
break;
}
}
}
void _game_script::Process_game_script() {
// process the next command
// this is a stub routine and so drops out at end and is then called again
char command;
char p1[ENGINE_STRING_LEN];
char p2[ENGINE_STRING_LEN];
char p3[ENGINE_STRING_LEN];
// global
buf = private_session_resman->Res_open(fname, fn_hash, cluster, cluster_hash);
// get next command
command = buf[pc];
switch (command) {
case 0:
Message_box("thank you for playing In Cold Blood (c) Revolution Software Ltd 1999");
{
Common::Event event;
event.type = Common::EVENT_QUIT;
g_system->getEventManager()->pushEvent(event);
}
break;
// bookmark
// these are ignored
case 'B':
pc += 2;
Fetch_next_param(p1);
Fetch_next_line(); // ignored in normal gamescript
warning("Hit bookmark mission %s", p1);
break;
case 'X': // yes, its the amazing X mode - t h e m a i n m e n u -
Fetch_next_line();
stub.Push_stub_mode(__toe_on_door);
break;
case 'W':
Fetch_next_line();
Fatal_error("midWay legal screen not supported on PC!");
break;
case 'M':
pc += 2;
Fetch_next_param(p1);
Fetch_next_param(p2);
Fetch_next_line();
if (Setup_new_mission(p1, p2)) { // mission_name, session_name
// only do actor relative on pc
MS->player.Set_control_mode(ACTOR_RELATIVE);
stub.Push_stub_mode(__mission_and_console);
} else {
Fatal_error("no such mission-session [%s][%s]", p1, p2);
}
break;
case 'L': // load a mission, but dont play it
pc += 2;
Fetch_next_param(p1);
Fetch_next_param(p2);
Fetch_next_line();
if (!Setup_new_mission(p1, p2)) // mission_name, session_name
Fatal_error("no such mission-session [%s][%s]", p1, p2);
// disable sounds for now...
PauseSounds();
g_mission->Game_cycle(); // do a cycle - load the set graphics
g_mission->Create_display(); // test
break;
case 'P':
Fetch_next_line();
MS->player.Set_control_mode(ACTOR_RELATIVE);
stub.Push_stub_mode(__mission_and_console);
break;
case 'T':
pc += 2; // skip the T
Fetch_next_param(p1);
Fetch_next_param(p2);
Fetch_next_param(p3);
Fetch_next_line();
warning("text scrolly %s over movie/screen %s starting frame %d", p1, p2, atoi(p3));
InitisliaseScrollingText(p1, p2, atoi(p3));
stub.Push_stub_mode(__scrolling_text);
break;
case 'G':
pc += 2;
Fetch_next_param(p1);
Fetch_next_param(p2);
Fetch_next_line();
g_globalScriptVariables.SetVariable(p1, (atoi(p2)));
break;
case 'R': // restart
Restart_game_script();
break;
case 'D': // debugging on again
px.debugging_and_console = TRUE8;
Fetch_next_line();
break;
case 'S': // play a movie sequence
pc += 2;
Fetch_next_param(p1);
Fetch_next_param(p2);
Fetch_next_line();
Init_play_movie(p1, (bool8)atoi(p2));
break;
case 'C': // set cd number
pc += 2;
Fetch_next_param(p1);
Fetch_next_line();
px.current_cd = atoi(p1);
if ((!px.current_cd) || (px.current_cd > 3))
Fatal_error("gamescript tried to set silly cd number %d", px.current_cd);
break;
case 'Z': // Signify that the game has been completed
Fetch_next_line();
GameCompleted();
break;
default:
Fatal_error("unknown game script command '%s'", buf[pc]);
break;
}
}
void _game_script::Fetch_next_param(char *p) {
uint8 c = 0;
while ((buf[pc]) && (buf[pc] != 0x0d) && (buf[pc] != ' '))
p[c++] = buf[pc++];
p[c] = 0;
Zdebug("%s", p);
pc++;
}
void _game_script::Fetch_next_line() {
// seek to next line
// return false if current line is the last line
do {
while ((buf[pc]) && (buf[pc] != 0x0a))
pc++;
if (!buf[pc]) // end of file
return;
pc++; // past the 0x0a
} while (buf[pc] == 0x0d); // keep skipping blank line
}
} // End of namespace ICB