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