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/common/px_string.h"
29 #include "engines/icb/res_man_pc.h"
30 #include "engines/icb/debug_pc.h"
31 #include "engines/icb/global_objects.h"
32 #include "engines/icb/cluster_manager_pc.h"
33 #include "engines/icb/options_manager_pc.h"
34 #include "engines/icb/movie_pc.h"
35
36 #include "common/textconsole.h"
37 #include "common/file.h"
38
39 namespace ICB {
40
41 // Global ClusterManger instance
42 ClusterManager *g_theClusterManager;
43
44 // Function prototypes
45 void RecursivelyDeleteDirectory(const char *path);
46 void ValidateDirectoryToDelete(const char *path);
47 uint32 GetFileSize(const char *path);
48 void MakeDirectoryTree(MISSION_ID mission);
49
50 // Number of bytes to read from CD and write to hard disk per cycle
51 #define CHUNKSIZE 25600 // ((300 * 1024) / 12) based on 12fps for 2xCD drive
52
53 // This is the number of attempts we check the cd drive on the prompt screen
54 #define CD_SEARCH_DELAY 1000
55
56 // Private for the title background movie handling
57 MovieManager *g_while_u_wait_SequenceManager;
58
59 // Colours used by progress display
60 uint32 g_progressColourMap[7] = {
61 0x3C3C3C, // OFF 60 60 60
62 0xFEFEFE, // | 254 254 254
63 0xCAD5E4, // | 202 213 228
64 0xA6B8D4, // | 166 184 212
65 0x89A1C7, // | 137 161 199
66 0x587AB0, // V 88 122 176
67 0x2E579C // ON 46 87 156
68 };
69
70 // Controls the decay on the progress bit colouring
71 #define PROGRESS_BIT_DELAY 6
72
ClusterManager()73 ClusterManager::ClusterManager() {
74 memset(m_cdroot1, 0, 1024);
75 memset(m_cdroot2, 0, 1024);
76 m_multipleCDDrives = FALSE8;
77 m_activeCDDrive = 1;
78 memset(m_missionDir, 0, 8);
79 m_bytesFreeOnInstalledDrive = 0;
80 m_minimumInstall = FALSE8;
81
82 memset(m_theList, 0, MAX_BYTESIZE_OF_A_FILELIST);
83 m_filelistTotalBytes = 0;
84 m_filelistCursor = -1;
85 m_filelistSize = 0;
86
87 m_src_fp = NULL;
88 m_dst_fp = NULL;
89
90 m_currentFileSize = 0;
91 m_chunkCounter = 0;
92 m_bytesDone = 0;
93
94 m_movieMemoryPointer = NULL;
95
96 m_installDone = FALSE8;
97
98 memset(m_progressBits, 0, sizeof(PROGRESS_BIT) * NUMBER_OF_PROGRESS_BITS);
99 m_bitsDone = 0;
100 m_frameCounter = 0;
101 m_currentLanguage = T_ENGLISH;
102 }
103
~ClusterManager()104 ClusterManager::~ClusterManager() {}
105
Initialise()106 void ClusterManager::Initialise() {
107 // First we need to discover what install method has been employed.
108 MinimumInstallCheck();
109
110 // Obtain drive information (CD path(s) and free space)
111 InterrogateDrives();
112
113 // Starting with an empty mission directory covers against the game
114 // crashing out or data being modified between executes.
115 CleanHardDisk();
116
117 // Require a disc on startup
118 CheckAnyDiscInserted();
119
120 // Line number 7398
121 const char *testline = g_theOptionsManager->GetTextFromReference(HashString("opt_missingdisc"));
122
123 if (strcmp(testline, "Please insert disc %d") == 0)
124 m_currentLanguage = T_ENGLISH;
125 else if (strcmp(testline, "Veuillez ins\xE9rer le disque %d") == 0)
126 m_currentLanguage = T_FRENCH;
127 else if (strcmp(testline, "Inserisci il disco %d") == 0)
128 m_currentLanguage = T_ITALIAN;
129 else if (strcmp(testline, "Bitte CD %d einlegen") == 0)
130 m_currentLanguage = T_GERMAN;
131 else if (strcmp(testline, "Por favor, inserta el disco %d") == 0)
132 m_currentLanguage = T_SPANISH;
133 else if (strcmp(testline, "\xC2\xF1\xF2\xE0\xE2\xFC\xF2\xE5 \xE4\xE8\xF1\xEA %d") == 0)
134 m_currentLanguage = T_RUSSIAN;
135 else
136 // Must be polish by default
137 m_currentLanguage = T_POLISH;
138 }
139
CheckDiscInserted(MISSION_ID)140 void ClusterManager::CheckDiscInserted(MISSION_ID /*mission*/) {
141 }
142
CheckDiscInsertedWithCancel(MISSION_ID mission)143 bool8 ClusterManager::CheckDiscInsertedWithCancel(MISSION_ID mission) {
144 // No user cancel
145 return FALSE8;
146 }
147
CheckAnyDiscInserted()148 void ClusterManager::CheckAnyDiscInserted() {
149 }
150
StartMissionInstall(MISSION_ID)151 bool8 ClusterManager::StartMissionInstall(MISSION_ID /*mission*/) {
152 return FALSE8;
153 }
154
InstallMission()155 bool8 ClusterManager::InstallMission() {
156 // Nothing to do on a full install
157 if (m_minimumInstall == FALSE8)
158 return FALSE8;
159
160 return FALSE8;
161 }
162
InterrogateDrives()163 void ClusterManager::InterrogateDrives() {
164 }
165
CalculateFreeDiskSpace(void)166 void ClusterManager::CalculateFreeDiskSpace(void) {
167 m_bytesFreeOnInstalledDrive = 256 * 1024 * 1024;
168 }
169
GetCDRoot(void)170 char *ClusterManager::GetCDRoot(void) {
171 if (m_activeCDDrive == 1)
172 return m_cdroot1;
173 else
174 return m_cdroot2;
175 }
176
WhichCD(MISSION_ID mission)177 int32 ClusterManager::WhichCD(MISSION_ID mission) {
178 // All demos exist on one CD only
179 int32 demo = g_globalScriptVariables->GetVariable("demo");
180 if (demo != 0)
181 return 1;
182
183 if (mission >= MISSION1 && mission <= MISSION3)
184 return 1;
185 else if (mission >= MISSION4 && mission <= MISSION7)
186 return 2;
187 else if (mission >= MISSION8 && mission <= MISSION10)
188 return 3;
189 else
190 Fatal_error("ClusterManager::WhichCD() can't resolve unknown mission parameter");
191
192 // Never gonna get here are we
193 return 0;
194 }
195
CheckForCD(int32)196 bool8 ClusterManager::CheckForCD(int32 /*number*/) {
197 strcpy(m_cdroot1, "");
198 strcpy(m_cdroot2, "");
199 return TRUE8;
200 }
201
MinimumInstallCheck()202 void ClusterManager::MinimumInstallCheck() {
203 m_minimumInstall = FALSE8;
204 }
205
IsMissionDataInstalled(MISSION_ID & m)206 bool8 ClusterManager::IsMissionDataInstalled(MISSION_ID &m) {
207 for (uint32 i = 0; i < NUMBER_OF_MISSIONS; i++) {
208 // Make the mission directories one by one and see if any exist
209 char h_mission[8];
210 HashFile(g_mission_names[i], h_mission);
211
212 pxString missionDirectory;
213 missionDirectory.Format("m\\%s\\", h_mission);
214
215 if (checkFileExists(missionDirectory)) {
216 m = (MISSION_ID)i;
217 return TRUE8;
218 }
219 }
220
221 // No mission directories on the hard disk
222 return FALSE8;
223 }
224
CleanHardDisk()225 void ClusterManager::CleanHardDisk() {
226 // Can't be letting that happen now can we
227 if (m_minimumInstall == FALSE8)
228 return;
229 }
230
MissingCD(int32)231 void ClusterManager::MissingCD(int32 /*number*/) {
232 }
233
MissingCDWithCancel(int32)234 bool8 ClusterManager::MissingCDWithCancel(int32 /*number*/) {
235 return FALSE8;
236 }
237
LoadFileList(MISSION_ID)238 void ClusterManager::LoadFileList(MISSION_ID /*mission*/) {
239 if (m_minimumInstall == FALSE8)
240 return;
241 }
242
GetFileListEntry()243 char *ClusterManager::GetFileListEntry() {
244 if (m_filelistCursor == -1)
245 Fatal_error("Can't retrieve filelist entry without loading a filelist first!");
246
247 char *line = NULL;
248
249 // End of file check
250 if (m_filelistCursor < m_filelistSize) {
251 line = &(m_theList[m_filelistCursor]);
252
253 // Move to next line
254 m_filelistCursor += strlen((const char *)&(m_theList[m_filelistCursor]));
255
256 // Skip any terminators to get to the start of the next line
257 while (m_theList[m_filelistCursor] == 0)
258 m_filelistCursor++;
259 }
260
261 return line;
262 }
263
DrawCoverFrame(void)264 bool8 ClusterManager::DrawCoverFrame(void) {
265 // Draw a frame of the torture movie
266 g_while_u_wait_SequenceManager->drawFrame(working_buffer_id);
267
268 // Have we finished both movie playback and mission install
269 if (m_installDone) {
270 // Release bink from playing the movie
271 g_while_u_wait_SequenceManager->kill();
272 // Free up resources
273 delete[] m_movieMemoryPointer;
274
275 // Quit only when movie has finished
276 return FALSE8;
277 }
278
279 DrawProgressBits();
280
281 // Update screen manually
282 surface_manager->Flip();
283
284 return TRUE8;
285 }
286
InitialiseProgressBits()287 void ClusterManager::InitialiseProgressBits() {
288 // Tweakable
289 int32 width = 5;
290 int32 height = 15;
291 int32 spacing = 2;
292 int32 initialY = SCREEN_DEPTH - height - 30;
293
294 // Calculate entire width so we can centre things
295 int32 length = (NUMBER_OF_PROGRESS_BITS * (width + spacing)) - spacing;
296 int32 initialX = (SCREEN_WIDTH / 2) - (length / 2);
297
298 for (int32 i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
299 m_progressBits[i].r.left = initialX;
300 m_progressBits[i].r.top = initialY;
301 m_progressBits[i].r.right = initialX + width;
302 m_progressBits[i].r.bottom = initialY + height;
303
304 m_progressBits[i].state = 0;
305
306 // Now increment
307 initialX += width + spacing;
308 }
309
310 m_bitsDone = 0;
311 }
312
UpdateProgressBits()313 void ClusterManager::UpdateProgressBits() {
314 if (m_frameCounter % PROGRESS_BIT_DELAY == 0) {
315 // Update the state of all bits
316 for (int32 i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
317 if (m_progressBits[i].state > 0 && m_progressBits[i].state != 6) {
318 m_progressBits[i].state = m_progressBits[i].state + 1;
319 }
320 }
321 }
322
323 // Bytes per progress bit
324 float progress_inc = (float)(m_filelistTotalBytes / NUMBER_OF_PROGRESS_BITS);
325
326 // The number of bits that should bit switched on
327 uint32 bitsOn = (int32)((float)m_bytesDone / progress_inc);
328
329 // Do we need to switch on a new bit
330 if (bitsOn > m_bitsDone) {
331 m_progressBits[m_bitsDone].state = 1;
332 m_bitsDone++;
333 }
334 }
335
DrawProgressBits()336 void ClusterManager::DrawProgressBits() {
337 for (int32 i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
338 Fill_rect(m_progressBits[i].r.left, m_progressBits[i].r.top, m_progressBits[i].r.right, m_progressBits[i].r.bottom, g_progressColourMap[m_progressBits[i].state]);
339 }
340 }
341
Shutdown(void)342 void ClusterManager::Shutdown(void) {
343 }
344
RecursivelyDeleteDirectory(const char *)345 void RecursivelyDeleteDirectory(const char * /*path*/) {
346 }
347
ValidateDirectoryToDelete(const char * path)348 void ValidateDirectoryToDelete(const char *path) {
349 if (strcmp(path, pxVString("m\\FP3YNHA\\")) == 0)
350 return;
351 else if (strcmp(path, pxVString("m\\HWYIPVA\\")) == 0)
352 return;
353 else if (strcmp(path, pxVString("m\\TPQUB4D\\")) == 0)
354 return;
355 else if (strcmp(path, pxVString("m\\RIGABTB\\")) == 0)
356 return;
357 else if (strcmp(path, pxVString("m\\GAIYO3A\\")) == 0)
358 return;
359 else if (strcmp(path, pxVString("m\\NMUFF0B\\")) == 0)
360 return;
361 else if (strcmp(path, pxVString("m\\1QYUOAA\\")) == 0)
362 return;
363 else if (strcmp(path, pxVString("m\\TT3WADD\\")) == 0)
364 return;
365 else
366 Fatal_error(pxVString("ValidateDirectoryToDelete() failed on: %s", path));
367 }
368
GetFileSize(const char * path)369 uint32 GetFileSize(const char *path) {
370 Common::File file;
371
372 if (!file.open(path)) {
373 return 0;
374 }
375
376 return (uint32)file.size();
377 }
378
MissionIdToName(MISSION_ID mission)379 const char *MissionIdToName(MISSION_ID mission) {
380 switch (mission) {
381 case MISSION1:
382 return g_m01;
383 case MISSION2:
384 return g_m02;
385 case MISSION3:
386 return g_m03;
387 case MISSION4:
388 return g_m04;
389 case MISSION5:
390 return g_m05;
391 case MISSION7:
392 return g_m07;
393 case MISSION8:
394 return g_m08;
395 case MISSION9:
396 return g_m08;
397 case MISSION10:
398 return g_m10;
399 }
400
401 Fatal_error("MissionIdToName() should never get here - smack AndyB");
402 return NULL;
403 }
404
MakeDirectoryTree(MISSION_ID)405 void MakeDirectoryTree(MISSION_ID /*mission*/) {
406 }
407
408 } // End of namespace ICB
409