1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/res_man.h"
29 #include "engines/icb/game_script.h"
30 #include "engines/icb/debug.h"
31 #include "engines/icb/mission.h"
32 #include "engines/icb/p4.h"
33 #include "engines/icb/global_objects.h"
34 #include "engines/icb/global_switches.h"
35 #include "engines/icb/sound.h"
36 #include "engines/icb/global_vars.h"
37 #include "engines/icb/main_menu.h"
38 
39 #include "common/events.h"
40 #include "common/textconsole.h"
41 
42 namespace ICB {
43 
Restart_game_script()44 void _game_script::Restart_game_script() {
45 	pc = 0;
46 	Init_globals(); // must reload the global vars for the new game!
47 }
48 
Running_from_gamescript()49 bool8 _game_script::Running_from_gamescript() { return running_from_game_script; }
50 
Init_game_script()51 bool8 _game_script::Init_game_script() {
52 	// assume
53 	running_from_game_script = FALSE8;
54 
55 	// If we are running tt mode (translator mode) then ignore any game scripts
56 	if (tt)
57 		return FALSE8;
58 
59 	// build name
60 
61 	sprintf(fname, GAMESCRIPT_PATH);
62 	sprintf(cluster, GLOBAL_CLUSTER_PATH);
63 	fn_hash = HashString(fname);
64 	cluster_hash = HashString(cluster);
65 
66 	Zdebug("Init_gs::'%s'::'%s'", fname, cluster);
67 	if (private_session_resman->Test_file(fname, fn_hash, cluster, cluster_hash)) {
68 		// program counter in gameScript
69 
70 		pc = 0;
71 
72 		Zdebug("Gamescript found");
73 		running_from_game_script = TRUE8;
74 
75 		return TRUE8;
76 	}
77 	warning("Gamescript: %s %s not found", fname, cluster);
78 
79 	return FALSE8;
80 }
81 
82 void Init_play_movie(const char *param0, bool8 param1);
83 
84 // runs the gamescript until a given bookmark then returns
85 // so the pc is set to the correct place for a mission....
Run_to_bookmark(const char * name)86 void _game_script::Run_to_bookmark(const char *name) {
87 	if ((g_mission) && (g_mission->session)) {
88 		// global
89 		buf = private_session_resman->Res_open(fname, fn_hash, cluster, cluster_hash);
90 	} else {
91 		// global
92 		buf = private_session_resman->Res_open(fname, fn_hash, cluster, cluster_hash);
93 	}
94 
95 	char command;
96 	char p1[ENGINE_STRING_LEN];
97 
98 	// reset program counter (but keep demo flag!)
99 	int32 demo = g_globalScriptVariables->GetVariable("demo");
100 	Restart_game_script();
101 	g_globalScriptVariables->SetVariable("demo", demo);
102 
103 	// now loop through gamescript...
104 	while (1) {
105 		command = buf[pc];
106 
107 		switch (command) {
108 		case 0:
109 			Fatal_error("Bookmark %s not found in gamescript", name);
110 			break;
111 
112 		case 'B':
113 			pc += 2;
114 			Fetch_next_param(p1);
115 			Fetch_next_line();
116 
117 			// if this is the bookmark then return, pc is in the right place...
118 			if (strcmp(p1, name) == 0)
119 				return;
120 
121 			// otherwise we keep looking...
122 			break;
123 
124 		default: // any other command
125 			Fetch_next_line();
126 			break;
127 		}
128 	}
129 }
130 
Process_game_script()131 void _game_script::Process_game_script() {
132 	// process the next command
133 	// this is a stub routine and so drops out at end and is then called again
134 
135 	char command;
136 	char p1[ENGINE_STRING_LEN];
137 	char p2[ENGINE_STRING_LEN];
138 	char p3[ENGINE_STRING_LEN];
139 
140 	// global
141 	buf = private_session_resman->Res_open(fname, fn_hash, cluster, cluster_hash);
142 
143 	// get next command
144 	command = buf[pc];
145 
146 	switch (command) {
147 	case 0:
148 		Message_box("thank you for playing In Cold Blood (c) Revolution Software Ltd 1999");
149 		{
150 			Common::Event event;
151 			event.type = Common::EVENT_QUIT;
152 			g_system->getEventManager()->pushEvent(event);
153 		}
154 		break;
155 
156 	// bookmark
157 	// these are ignored
158 	case 'B':
159 		pc += 2;
160 		Fetch_next_param(p1);
161 		Fetch_next_line(); // ignored in normal gamescript
162 		Zdebug("Hit bookmark mission %s", p1);
163 		break;
164 
165 	case 'X': // yes, its the amazing X mode   - t h e  m a i n  m e n u -
166 		Fetch_next_line();
167 		g_stub->Push_stub_mode(__toe_on_door);
168 		break;
169 
170 	case 'W':
171 		Fetch_next_line();
172 		Fatal_error("midWay legal screen not supported on PC!");
173 		break;
174 
175 	case 'M':
176 		pc += 2;
177 
178 		Fetch_next_param(p1);
179 		Fetch_next_param(p2);
180 		Fetch_next_line();
181 
182 		if (Setup_new_mission(p1, p2)) { // mission_name, session_name
183 			// only do actor relative on pc
184 			MS->player.Set_control_mode(ACTOR_RELATIVE);
185 			g_stub->Push_stub_mode(__mission_and_console);
186 		} else {
187 			Fatal_error("no such mission-session [%s][%s]", p1, p2);
188 		}
189 		break;
190 
191 	case 'L': // load a mission, but dont play it
192 		pc += 2;
193 
194 		Fetch_next_param(p1);
195 		Fetch_next_param(p2);
196 		Fetch_next_line();
197 
198 		if (!Setup_new_mission(p1, p2)) // mission_name, session_name
199 			Fatal_error("no such mission-session [%s][%s]", p1, p2);
200 
201 		// disable sounds for now...
202 		PauseSounds();
203 
204 		g_mission->Game_cycle();     // do a cycle - load the set graphics
205 		g_mission->Create_display(); // test
206 		break;
207 
208 	case 'P':
209 		Fetch_next_line();
210 		MS->player.Set_control_mode(ACTOR_RELATIVE);
211 		g_stub->Push_stub_mode(__mission_and_console);
212 		break;
213 
214 	case 'T':
215 		pc += 2; // skip the T
216 
217 		Fetch_next_param(p1);
218 		Fetch_next_param(p2);
219 		Fetch_next_param(p3);
220 		Fetch_next_line();
221 
222 		warning("text scrolly %s over movie/screen %s starting frame %d", p1, p2, atoi(p3));
223 
224 		InitisliaseScrollingText(p1, p2, atoi(p3));
225 		g_stub->Push_stub_mode(__scrolling_text);
226 		break;
227 
228 	case 'G':
229 		pc += 2;
230 
231 		Fetch_next_param(p1);
232 		Fetch_next_param(p2);
233 		Fetch_next_line();
234 		g_globalScriptVariables->SetVariable(p1, (atoi(p2)));
235 		break;
236 
237 	case 'R': // restart
238 		Restart_game_script();
239 		break;
240 
241 	case 'D': // debugging on again
242 		g_px->debugging_and_console = TRUE8;
243 		Fetch_next_line();
244 		break;
245 
246 	case 'S': // play a movie sequence
247 		pc += 2;
248 		Fetch_next_param(p1);
249 		Fetch_next_param(p2);
250 		Fetch_next_line();
251 		Init_play_movie(p1, (bool8)atoi(p2));
252 		break;
253 
254 	case 'C': // set cd number
255 		pc += 2;
256 		Fetch_next_param(p1);
257 		Fetch_next_line();
258 		g_px->current_cd = atoi(p1);
259 
260 		if ((!g_px->current_cd) || (g_px->current_cd > 3))
261 			Fatal_error("gamescript tried to set silly cd number %d", g_px->current_cd);
262 		break;
263 
264 	case 'Z': // Signify that the game has been completed
265 		Fetch_next_line();
266 		GameCompleted();
267 		break;
268 
269 	default:
270 		Fatal_error("unknown game script command '%s'", buf[pc]);
271 		break;
272 	}
273 }
274 
Fetch_next_param(char * p)275 void _game_script::Fetch_next_param(char *p) {
276 	uint8 c = 0;
277 
278 	while ((buf[pc]) && (buf[pc] != 0x0d) && (buf[pc] != ' '))
279 		p[c++] = buf[pc++];
280 
281 	p[c] = 0;
282 	Zdebug("%s", p);
283 
284 	pc++;
285 }
286 
Fetch_next_line()287 void _game_script::Fetch_next_line() {
288 	// seek to next line
289 
290 	// return false if current line is the last line
291 
292 	do {
293 		while ((buf[pc]) && (buf[pc] != 0x0a))
294 			pc++;
295 
296 		if (!buf[pc]) // end of file
297 			return;
298 
299 		pc++; // past the 0x0a
300 
301 	} while (buf[pc] == 0x0d); // keep skipping blank line
302 }
303 
304 } // End of namespace ICB
305