mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-21 09:21:08 +00:00
1161 lines
32 KiB
C++
1161 lines
32 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/common/px_rccommon.h"
|
|
#include "engines/icb/common/px_string.h"
|
|
#include "engines/icb/res_man_pc.h"
|
|
#include "engines/icb/debug_pc.h"
|
|
#include "engines/icb/global_objects.h"
|
|
#include "engines/icb/cluster_manager_pc.h"
|
|
#include "engines/icb/options_manager_pc.h"
|
|
#include "engines/icb/movie_pc.h"
|
|
|
|
#include "common/textconsole.h"
|
|
#include "common/file.h"
|
|
|
|
namespace ICB {
|
|
|
|
// Global ClusterManger instance
|
|
ClusterManager *g_theClusterManager;
|
|
|
|
// Function prototypes
|
|
void RecursivelyDeleteDirectory(const char *path);
|
|
void ValidateDirectoryToDelete(const char *path);
|
|
uint32 GetFileSize(const char *path);
|
|
void MakeDirectoryTree(MISSION_ID mission);
|
|
|
|
// Number of bytes to read from CD and write to hard disk per cycle
|
|
#define CHUNKSIZE 25600 // ((300 * 1024) / 12) based on 12fps for 2xCD drive
|
|
|
|
// This is the number of attempts we check the cd drive on the prompt screen
|
|
#define CD_SEARCH_DELAY 1000
|
|
|
|
// Private for the title background movie handling
|
|
MovieManager *g_while_u_wait_SequenceManager;
|
|
|
|
// Colours used by progress display
|
|
uint32 g_progressColourMap[7] = {
|
|
0x3C3C3C, // OFF 60 60 60
|
|
0xFEFEFE, // | 254 254 254
|
|
0xCAD5E4, // | 202 213 228
|
|
0xA6B8D4, // | 166 184 212
|
|
0x89A1C7, // | 137 161 199
|
|
0x587AB0, // V 88 122 176
|
|
0x2E579C // ON 46 87 156
|
|
};
|
|
|
|
// Controls the decay on the progress bit colouring
|
|
#define PROGRESS_BIT_DELAY 6
|
|
|
|
ClusterManager::ClusterManager() {
|
|
memset(m_cdroot1, 0, 1024);
|
|
memset(m_cdroot2, 0, 1024);
|
|
m_multipleCDDrives = FALSE8;
|
|
m_activeCDDrive = 1;
|
|
memset(m_missionDir, 0, 8);
|
|
m_bytesFreeOnInstalledDrive = 0;
|
|
m_minimumInstall = FALSE8;
|
|
|
|
memset(m_theList, 0, MAX_BYTESIZE_OF_A_FILELIST);
|
|
m_filelistTotalBytes = 0;
|
|
m_filelistCursor = -1;
|
|
m_filelistSize = 0;
|
|
|
|
m_src_fp = NULL;
|
|
m_dst_fp = NULL;
|
|
|
|
m_currentFileSize = 0;
|
|
m_chunkCounter = 0;
|
|
m_bytesDone = 0;
|
|
|
|
m_movieMemoryPointer = NULL;
|
|
|
|
m_installDone = FALSE8;
|
|
|
|
memset(m_progressBits, 0, NUMBER_OF_PROGRESS_BITS);
|
|
m_bitsDone = 0;
|
|
m_frameCounter = 0;
|
|
m_currentLanguage = T_ENGLISH;
|
|
}
|
|
|
|
ClusterManager::~ClusterManager() {}
|
|
|
|
void ClusterManager::Initialise() {
|
|
// First we need to discover what install method has been employed.
|
|
MinimumInstallCheck();
|
|
|
|
// Obtain drive information (CD path(s) and free space)
|
|
InterrogateDrives();
|
|
|
|
// Starting with an empty mission directory covers against the game
|
|
// crashing out or data being modified between executes.
|
|
CleanHardDisk();
|
|
|
|
// Require a disc on startup
|
|
CheckAnyDiscInserted();
|
|
|
|
// Line number 7398
|
|
const char *testline = g_theOptionsManager->GetTextFromReference(HashString("opt_missingdisc"));
|
|
|
|
if (strcmp(testline, "Please insert disc %d") == 0)
|
|
m_currentLanguage = T_ENGLISH;
|
|
else if (strcmp(testline, "Veuillez ins\xE9rer le disque %d") == 0)
|
|
m_currentLanguage = T_FRENCH;
|
|
else if (strcmp(testline, "Inserisci il disco %d") == 0)
|
|
m_currentLanguage = T_ITALIAN;
|
|
else if (strcmp(testline, "Bitte CD %d einlegen") == 0)
|
|
m_currentLanguage = T_GERMAN;
|
|
else if (strcmp(testline, "Por favor, inserta el disco %d") == 0)
|
|
m_currentLanguage = T_SPANISH;
|
|
else if (strcmp(testline, "\xC2\xF1\xF2\xE0\xE2\xFC\xF2\xE5 \xE4\xE8\xF1\xEA %d") == 0)
|
|
m_currentLanguage = T_RUSSIAN;
|
|
else
|
|
// Must be polish by default
|
|
m_currentLanguage = T_POLISH;
|
|
}
|
|
|
|
void ClusterManager::CheckDiscInserted(MISSION_ID /*mission*/) {
|
|
#if 0
|
|
// To kill compiler warning
|
|
mission;
|
|
|
|
#ifdef PC_DEMO
|
|
return;
|
|
#endif
|
|
|
|
#ifdef FROM_PC_CD
|
|
int cd = WhichCD(mission);
|
|
|
|
if (!CheckForCD(cd)) {
|
|
MissingCD(cd);
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
bool8 ClusterManager::CheckDiscInsertedWithCancel(MISSION_ID mission) {
|
|
#if 0
|
|
#ifdef PC_DEMO
|
|
return TRUE8;
|
|
#endif
|
|
|
|
#if 0 // was #ifdef FROM_PC_CD
|
|
|
|
int cd = WhichCD(mission);
|
|
|
|
if (!CheckForCD(cd)) {
|
|
return MissingCDWithCancel(cd);
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
// No user cancel
|
|
return FALSE8;
|
|
}
|
|
|
|
void ClusterManager::CheckAnyDiscInserted() {
|
|
#if 0
|
|
#ifdef PC_DEMO
|
|
return;
|
|
#endif
|
|
|
|
if (!CheckForCD(1)) {
|
|
if (!CheckForCD(2)) {
|
|
if (!CheckForCD(3))
|
|
MissingCD(1);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool8 ClusterManager::StartMissionInstall(MISSION_ID /*mission*/) {
|
|
return FALSE8;
|
|
|
|
#if 0
|
|
// First off ensure we have the correct CD in the drive for this mission
|
|
CheckDiscInserted(mission);
|
|
|
|
// Nothing more to do on a full install
|
|
if (m_minimumInstall == FALSE8)
|
|
return FALSE8;
|
|
|
|
// Check if we already have this mission on the disk
|
|
MISSION_ID on_disk;
|
|
if (IsMissionDataInstalled(on_disk)) {
|
|
if (mission == on_disk) {
|
|
// Data already there
|
|
return FALSE8;
|
|
}
|
|
}
|
|
|
|
// Set flag to false
|
|
m_installDone = FALSE8;
|
|
|
|
// Pointer to the mission name
|
|
char *missionName = mission_names[mission];
|
|
|
|
// Load the loading movie :)
|
|
|
|
// Full path to the torture movie (from hard disk at the moment)
|
|
pxString loadingMovie;
|
|
loadingMovie.Format("gmovies\\loading.bik");
|
|
loadingMovie.ConvertPath();
|
|
// Load the movie into memory for playback
|
|
uint32 movieSize = GetFileSize(loadingMovie);
|
|
if (movieSize == 0)
|
|
Fatal_error("Couldn't get filesize of loading movie");
|
|
|
|
// Get storage
|
|
m_movieMemoryPointer = new char[movieSize];
|
|
|
|
// Open the movie file and read it straight into memory
|
|
FILE *movieFp = openDiskFileForBinaryRead(loadingMovie);
|
|
if (movieFp == NULL)
|
|
Fatal_error(pxVString("Failed to open movie file: %s for reading", (const char *)loadingMovie));
|
|
|
|
if (fread(m_movieMemoryPointer, 1, movieSize, movieFp) != movieSize)
|
|
Fatal_error("ClusterManager::StartMissionInstall() failed to read from file");
|
|
|
|
// Close the file
|
|
fclose(movieFp);
|
|
|
|
// Register this pointer with bink
|
|
if (!g_while_u_wait_SequenceManager.Register(m_movieMemoryPointer, FALSE8, TRUE8, BINKFROMMEMORY)) {
|
|
Fatal_error("ClusterManager::StartMissionInstall() - Couldn't register loading movie");
|
|
}
|
|
|
|
// Reset progress display
|
|
InitialiseProgressBits();
|
|
m_bytesDone = 0;
|
|
m_frameCounter = 0;
|
|
|
|
// Deletion might take a second or so, so draw initial frame
|
|
DrawCoverFrame();
|
|
|
|
// First thing to do is ensure no mission data is on the hard disk
|
|
CleanHardDisk();
|
|
|
|
// Load the appropriate filelist to memory for parsing
|
|
LoadFileList(mission);
|
|
|
|
// As we now know that mission directory is empty check current disk space
|
|
CalculateFreeDiskSpace();
|
|
|
|
// Now validate that we have room to put this mission to the hard-disk
|
|
if (m_filelistTotalBytes > m_bytesFreeOnInstalledDrive) {
|
|
// Hard to know how to deal with this really
|
|
Fatal_error("Not enough disk space to install mission. Please make some room and try again.");
|
|
}
|
|
|
|
// Ensure all required directories exist for this mission
|
|
MakeDirectoryTree(mission);
|
|
|
|
return TRUE8;
|
|
#endif
|
|
}
|
|
|
|
bool8 ClusterManager::InstallMission() {
|
|
// Nothing to do on a full install
|
|
if (m_minimumInstall == FALSE8)
|
|
return FALSE8;
|
|
|
|
// Just to allow compilation on XCode:
|
|
return FALSE8;
|
|
#if 0
|
|
char *filename;
|
|
char sourcePath[128];
|
|
char destPath[128];
|
|
|
|
// Do we need to open new files
|
|
if (m_src_fp == NULL && m_dst_fp == NULL) {
|
|
// Get next filename from the filelist
|
|
filename = GetFileListEntry();
|
|
|
|
// Have we finished
|
|
if (filename != NULL) {
|
|
// Construct the new source and destination names
|
|
sprintf(sourcePath, "m\\%s\\%s", m_missionDir, filename);
|
|
sprintf(destPath, "m\\%s\\%s", m_missionDir, filename);
|
|
|
|
// Get size
|
|
m_currentFileSize = GetFileSize(sourcePath);
|
|
if (m_currentFileSize == 0)
|
|
Fatal_error(pxVString("Couldn't get size of file: %s", sourcePath));
|
|
|
|
// New file so reset chunk counter
|
|
m_chunkCounter = 0;
|
|
|
|
// Open the source file
|
|
m_src_fp = openDiskFileForBinaryRead(sourcePath);
|
|
if (m_src_fp == NULL)
|
|
Fatal_error(pxVString("ClusterManager::InstallMission() couldn't open file: %s for reading", sourcePath));
|
|
|
|
// Now open the destination file
|
|
m_dst_fp = openDiskFileForBinaryWrite(destPath);
|
|
if (m_dst_fp == NULL)
|
|
Fatal_error(pxVString("ClusterManager::InstallMission() couldn't open file: %s for writing", destPath));
|
|
} else {
|
|
// Huzzah! All done!
|
|
m_installDone = TRUE8;
|
|
}
|
|
}
|
|
|
|
if (m_installDone == FALSE8) {
|
|
// Default chunk size
|
|
uint32 chunkSize = CHUNKSIZE;
|
|
|
|
// End of file flag
|
|
bool8 endOfFile = FALSE8;
|
|
|
|
// Do we need to deal with the dreggs of a file
|
|
if ((m_chunkCounter + 1) * CHUNKSIZE > m_currentFileSize) {
|
|
// Calculate size of dog end
|
|
chunkSize = m_currentFileSize - (m_chunkCounter * CHUNKSIZE);
|
|
endOfFile = TRUE8;
|
|
}
|
|
|
|
// Get a chunk sized piece of memory
|
|
char *data = new char[chunkSize];
|
|
if (data == NULL)
|
|
Fatal_error("ClusterManager::InstallMission() couldn't get memory!");
|
|
|
|
// Read source file to memory
|
|
if (fread(data, 1, chunkSize, m_src_fp) != chunkSize)
|
|
Fatal_error("ClusterManager::InstallMission() failed to read from file");
|
|
|
|
// Write memory to destination file
|
|
if (fwrite(data, 1, chunkSize, m_dst_fp) != chunkSize)
|
|
Fatal_error("ClusterManager::InstallMission() failed to write to file");
|
|
|
|
// Free up the memory we've used
|
|
delete [] data;
|
|
|
|
// Done a chunk
|
|
m_chunkCounter++;
|
|
m_bytesDone += chunkSize;
|
|
|
|
// End of file check
|
|
if (endOfFile) {
|
|
// End of file reached
|
|
|
|
// Close the source file
|
|
fclose(m_src_fp);
|
|
m_src_fp = NULL;
|
|
// Close the destination file
|
|
fclose(m_dst_fp);
|
|
m_dst_fp = NULL;
|
|
}
|
|
}
|
|
|
|
// Update progress status
|
|
UpdateProgressBits();
|
|
|
|
// Increment counter
|
|
m_frameCounter++;
|
|
|
|
// Update the screen visuals
|
|
return DrawCoverFrame();
|
|
#endif
|
|
}
|
|
|
|
void ClusterManager::InterrogateDrives() {
|
|
#if 0
|
|
int buffersize = 128;
|
|
char driveStrings[128];
|
|
|
|
m_multipleCDDrives = FALSE8;
|
|
|
|
// Fill with terminators
|
|
memset(driveStrings, 0, buffersize);
|
|
|
|
// This function lists all drives on the current system separated by terminators
|
|
int len = GetLogicalDriveStrings(buffersize, driveStrings);
|
|
|
|
// A pointer to the string list
|
|
char *ptr = driveStrings;
|
|
int cursor = 0;
|
|
bool8 foundCDdrive = FALSE8;
|
|
|
|
while (cursor < len) {
|
|
if (GetDriveType(ptr + cursor) == DRIVE_CDROM) {
|
|
if (foundCDdrive == FALSE) {
|
|
// Record the drive that's the (first) CD drive
|
|
strcpy(m_cdroot1, (const char *)(ptr + cursor));
|
|
foundCDdrive = TRUE8;
|
|
} else {
|
|
// Record the drive that's the (second) CD drive
|
|
strcpy(m_cdroot2, (const char *)(ptr + cursor));
|
|
m_multipleCDDrives = TRUE8;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Move to next drive sting in the list
|
|
cursor += strlen((const char *)ptr + cursor) + 1;
|
|
}
|
|
|
|
// Now see how much space we have on the current (therefore installed) drive
|
|
CalculateFreeDiskSpace();
|
|
#endif
|
|
}
|
|
|
|
void ClusterManager::CalculateFreeDiskSpace(void) {
|
|
warning("STUB: ClusterManager::CalculateFreeDiskSpace()");
|
|
#if 0
|
|
DWORD sectorsPerCluster;
|
|
DWORD bytesPerSector;
|
|
DWORD numberOfFreeClusters;
|
|
DWORD totalNumberOfClusters;
|
|
|
|
if (GetDiskFreeSpace(NULL, §orsPerCluster, &bytesPerSector, &numberOfFreeClusters, &totalNumberOfClusters) == 0) {
|
|
char error_message[256];
|
|
// Figure out why we failed
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
(LPTSTR)&error_message, 0, NULL);
|
|
|
|
Fatal_error(pxVString("ClusterManager::InterrogateDrives() GetLastError(): %s", error_message));
|
|
}
|
|
|
|
// For megabytes free, divide this number by (1024*1024)
|
|
m_bytesFreeOnInstalledDrive = numberOfFreeClusters * sectorsPerCluster * bytesPerSector;
|
|
#endif
|
|
m_bytesFreeOnInstalledDrive = 256 * 1024 * 1024;
|
|
}
|
|
|
|
char *ClusterManager::GetCDRoot(void) {
|
|
if (m_activeCDDrive == 1)
|
|
return m_cdroot1;
|
|
else
|
|
return m_cdroot2;
|
|
}
|
|
|
|
int ClusterManager::WhichCD(MISSION_ID mission) {
|
|
// All demos exist on one CD only
|
|
int demo = g_globalScriptVariables.GetVariable("demo");
|
|
if (demo != 0)
|
|
return 1;
|
|
|
|
if (mission >= MISSION1 && mission <= MISSION3)
|
|
return 1;
|
|
else if (mission >= MISSION4 && mission <= MISSION7)
|
|
return 2;
|
|
else if (mission >= MISSION8 && mission <= MISSION10)
|
|
return 3;
|
|
else
|
|
Fatal_error("ClusterManager::WhichCD() can't resolve unknown mission parameter");
|
|
|
|
// Never gonna get here are we
|
|
return 0;
|
|
}
|
|
|
|
bool8 ClusterManager::CheckForCD(int /*number*/) {
|
|
#if 1 // was #ifdef FROM_PC_CD
|
|
strcpy(m_cdroot1, "");
|
|
strcpy(m_cdroot2, "");
|
|
return TRUE8;
|
|
#else // FROM_PC_CD
|
|
|
|
return TRUE8;
|
|
|
|
#endif
|
|
|
|
#if 0
|
|
char volumeName[128];
|
|
char volumeName2[128];
|
|
DWORD volumeNameLength = 128;
|
|
DWORD unused = 0;
|
|
|
|
// This is to prevent against windows getting arsey when there's no CD in the CD
|
|
// drive; which, of course, is what we're trying to handle within this code.
|
|
UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
// Get the volume name - don't care about anything else
|
|
GetVolumeInformation(m_cdroot1, volumeName, volumeNameLength, NULL, NULL, NULL, NULL, unused);
|
|
|
|
if (m_multipleCDDrives)
|
|
GetVolumeInformation(m_cdroot2, volumeName2, volumeNameLength, NULL, NULL, NULL, NULL, unused);
|
|
|
|
// Return this to it's previous state now that we've finished
|
|
SetErrorMode(oldErrorMode);
|
|
|
|
char *seekingVolume = NULL;
|
|
|
|
if (number == 1)
|
|
seekingVolume = "ICB_CD1";
|
|
else if (number == 2)
|
|
seekingVolume = "ICB_CD2";
|
|
else if (number == 3)
|
|
seekingVolume = "ICB_CD3";
|
|
else
|
|
Fatal_error(pxVString("ClusterManager::CheckForCD(# %d) unknown CD number to find!", number));
|
|
|
|
// Is the correctly named CD in the drive
|
|
if (strcmp(volumeName, seekingVolume) == 0) {
|
|
m_activeCDDrive = 1;
|
|
return TRUE8;
|
|
}
|
|
|
|
// Multiple drive support
|
|
if (m_multipleCDDrives) {
|
|
if (strcmp(volumeName2, seekingVolume) == 0) {
|
|
m_activeCDDrive = 2;
|
|
return TRUE8;
|
|
}
|
|
}
|
|
|
|
return FALSE8;
|
|
#endif
|
|
}
|
|
|
|
void ClusterManager::MinimumInstallCheck() {
|
|
#if 0
|
|
// Look for an empty file that the installer placed next to the engine
|
|
if (checkFileExists("minimum", 0))
|
|
m_minimumInstall = TRUE8;
|
|
else
|
|
#endif
|
|
m_minimumInstall = FALSE8;
|
|
}
|
|
|
|
bool8 ClusterManager::IsMissionDataInstalled(MISSION_ID &m) {
|
|
for (uint32 i = 0; i < NUMBER_OF_MISSIONS; i++) {
|
|
// Make the mission directories one by one and see if any exist
|
|
char h_mission[8];
|
|
HashFile(g_mission_names[i], h_mission);
|
|
|
|
pxString missionDirectory;
|
|
missionDirectory.Format("m\\%s\\", h_mission);
|
|
|
|
if (checkFileExists(missionDirectory)) {
|
|
m = (MISSION_ID)i;
|
|
return TRUE8;
|
|
}
|
|
}
|
|
|
|
// No mission directories on the hard disk
|
|
return FALSE8;
|
|
}
|
|
|
|
void ClusterManager::CleanHardDisk() {
|
|
// Can't be letting that happen now can we
|
|
if (m_minimumInstall == FALSE8)
|
|
return;
|
|
|
|
#if 0
|
|
// This needs to be a recursive delete under the clustered mission directory
|
|
|
|
// Ideally this would only need to remove a single mission at a time
|
|
// but to be safe I think it should try to remove everything under missions
|
|
|
|
// For all missions
|
|
for (uint32 i = 0; i < NUMBER_OF_MISSIONS; i++) {
|
|
char h_mission[8];
|
|
HashFile(mission_names[i], h_mission);
|
|
|
|
pxString missionDirectory;
|
|
missionDirectory.Format("m\\%s\\", h_mission);
|
|
|
|
// First determine if this mission is on the hard disk
|
|
if (!checkFileExists(missionDirectory)) // amode = 0
|
|
continue;
|
|
|
|
// Validation function (don't want to be deleting shit without being 100%)
|
|
ValidateDirectoryToDelete(missionDirectory);
|
|
|
|
// Remove everything under the mission directory
|
|
RecursivelyDeleteDirectory(missionDirectory);
|
|
|
|
// Finally delete the mission directory itself (only possible if empty)
|
|
|
|
// Need to make sure that it's not read-only first
|
|
_chmod(missionDirectory, _S_IWRITE);
|
|
|
|
// Delete directory
|
|
if (rmdir(missionDirectory) == -1) {
|
|
int lastChar = missionDirectory.GetLen() - 1;
|
|
|
|
// Need to chop of slash character
|
|
if (missionDirectory[lastChar] == '\\') {
|
|
missionDirectory[lastChar] = '\0';
|
|
|
|
// Try again
|
|
if (rmdir(missionDirectory) == -1) {
|
|
// Couldn't delete this!
|
|
Fatal_error(pxVString("Couldn't delete directory: %s", (const char *)missionDirectory));
|
|
}
|
|
} else {
|
|
// Couldn't delete this!
|
|
Fatal_error(pxVString("Couldn't delete directory: %s", (const char *)missionDirectory));
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ClusterManager::MissingCD(int /*number*/) {
|
|
#if 0
|
|
uint32 halfScreen = SCREEN_WIDTH / 2;
|
|
uint32 temp;
|
|
char msg[128];
|
|
uint8 *ad;
|
|
uint32 pitch;
|
|
|
|
// This function needs to display a pleasant message and loop internally until we either
|
|
// detect the correct cd in the drive or the user cancels
|
|
|
|
const char *message = g_theOptionsManager->GetTextFromReference(HashString("opt_missingdisc"));
|
|
char *ok = (char *)g_theOptionsManager->GetTextFromReference(HashString("opt_continue"));
|
|
char *quit = (char *)g_theOptionsManager->GetTextFromReference(HashString("opt_quit"));
|
|
|
|
// Blank the screen
|
|
surface_manager->Clear_surface(working_buffer_id);
|
|
|
|
sprintf(msg, message, number);
|
|
bool8 okSelected = TRUE8;
|
|
bool8 checking = FALSE8;
|
|
bool8 gotCD = FALSE8;
|
|
|
|
while (gotCD == FALSE8) {
|
|
// Important this bit
|
|
Poll_direct_input();
|
|
|
|
// Deal with user input first
|
|
if (Read_DI_once_keys(Common::KEYCODE_RETURN) || Read_DI_once_keys(Common::KEYCODE_SPACE)) {
|
|
if (okSelected) {
|
|
checking = TRUE8;
|
|
} else {
|
|
// User wishes to quit
|
|
Common::Event event;
|
|
event.type = Common::EVENT_QUIT;
|
|
g_system->getEventManager()->pushEvent(event);
|
|
return;
|
|
}
|
|
}
|
|
if (Read_DI_once_keys(Common::KEYCODE_LEFT) || Read_DI_once_keys(Common::KEYCODE_RIGHT)) {
|
|
// Toggle selection
|
|
if (okSelected)
|
|
okSelected = FALSE8;
|
|
else
|
|
okSelected = TRUE8;
|
|
}
|
|
|
|
// This block looks for the cd over a short loop
|
|
if (checking) {
|
|
// Alter the screen display to show we are checking
|
|
ad = surface_manager->Lock_surface(working_buffer_id);
|
|
pitch = surface_manager->Get_pitch(working_buffer_id);
|
|
|
|
// Display message
|
|
g_theOptionsManager->DisplayText(ad, pitch, msg, 0, 90, PALEFONT, TRUE8);
|
|
|
|
// Display choices
|
|
temp = g_theOptionsManager->CalculateStringWidth(ok);
|
|
g_theOptionsManager->DisplayText(ad, pitch, ok, halfScreen - temp - 20, 130, PALEFONT, FALSE8);
|
|
g_theOptionsManager->DisplayText(ad, pitch, quit, halfScreen + 20, 130, PALEFONT, FALSE8);
|
|
|
|
surface_manager->Unlock_surface(working_buffer_id);
|
|
|
|
// Update screen manually
|
|
surface_manager->Flip();
|
|
|
|
for (uint32 tik = 0; tik < CD_SEARCH_DELAY; tik++) {
|
|
// Check for the CD again
|
|
if (CheckForCD(number)) {
|
|
// Cool, got it
|
|
|
|
// Black out screen manually
|
|
surface_manager->Clear_surface(working_buffer_id);
|
|
surface_manager->Flip();
|
|
|
|
gotCD = TRUE8;
|
|
break;
|
|
}
|
|
}
|
|
checking = FALSE8;
|
|
}
|
|
|
|
// we don't use this function so SendMessage is just disabled
|
|
//SendMessage(windowHandle, WM_PAINT, 0, 0);
|
|
|
|
if (gotCD)
|
|
break;
|
|
|
|
ad = surface_manager->Lock_surface(working_buffer_id);
|
|
pitch = surface_manager->Get_pitch(working_buffer_id);
|
|
|
|
// Display message
|
|
g_theOptionsManager->DisplayText(ad, pitch, msg, 0, 90, NORMALFONT, TRUE8, TRUE8);
|
|
|
|
// Display choices
|
|
temp = g_theOptionsManager->CalculateStringWidth(ok);
|
|
g_theOptionsManager->DisplayText(ad, pitch, ok, halfScreen - temp - 20, 130, (bool8)(okSelected == TRUE8) ? SELECTEDFONT : NORMALFONT, FALSE8);
|
|
g_theOptionsManager->DisplayText(ad, pitch, quit, halfScreen + 20, 130, (bool8)(okSelected == FALSE8) ? SELECTEDFONT : NORMALFONT, FALSE8);
|
|
|
|
surface_manager->Unlock_surface(working_buffer_id);
|
|
|
|
// Update screen manually
|
|
surface_manager->Flip();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool8 ClusterManager::MissingCDWithCancel(int /*number*/) {
|
|
#if 0
|
|
uint32 halfScreen = SCREEN_WIDTH / 2;
|
|
uint32 temp;
|
|
char msg[128];
|
|
uint8 *ad;
|
|
uint32 pitch;
|
|
|
|
// This function needs to display a pleasant message and loop internally until we either
|
|
// detect the correct cd in the drive or the user cancels
|
|
|
|
const char *message = g_theOptionsManager->GetTextFromReference(HashString("opt_missingdisc"));
|
|
char *ok = (char *)g_theOptionsManager->GetTextFromReference(HashString("opt_continue"));
|
|
char *quit = (char *)g_theOptionsManager->GetTextFromReference(HashString("opt_exitgame"));
|
|
char *cancel = (char *)g_theOptionsManager->GetTextFromReference(HashString("opt_back"));
|
|
|
|
// Blank the screen
|
|
surface_manager->Clear_surface(working_buffer_id);
|
|
|
|
sprintf(msg, message, number);
|
|
int selection = 0;
|
|
bool8 checking = FALSE8;
|
|
bool8 gotCD = FALSE8;
|
|
|
|
while (gotCD == FALSE8) {
|
|
// Important this bit
|
|
Poll_direct_input();
|
|
|
|
// Deal with user input first
|
|
if (Read_DI_once_keys(Common::KEYCODE_RETURN) || Read_DI_once_keys(Common::KEYCODE_SPACE)) {
|
|
if (selection == 0) {
|
|
checking = TRUE8;
|
|
} else if (selection == 1) {
|
|
// User cancelled
|
|
return TRUE8;
|
|
} else {
|
|
// User wishes to quit
|
|
Common::Event event;
|
|
event.type = Common::EVENT_QUIT;
|
|
g_system->getEventManager()->pushEvent(event);
|
|
return TRUE8;
|
|
}
|
|
}
|
|
if (Read_DI_once_keys(Common::KEYCODE_UP)) {
|
|
// Toggle selection
|
|
if (selection == 0)
|
|
selection = 2;
|
|
else
|
|
selection--;
|
|
}
|
|
if (Read_DI_once_keys(Common::KEYCODE_DOWN)) {
|
|
// Toggle selection
|
|
if (selection == 2)
|
|
selection = 0;
|
|
else
|
|
selection++;
|
|
}
|
|
|
|
// This block looks for the cd over a short loop
|
|
if (checking) {
|
|
// Alter the screen display to show we are checking
|
|
ad = surface_manager->Lock_surface(working_buffer_id);
|
|
pitch = surface_manager->Get_pitch(working_buffer_id);
|
|
|
|
// Display message
|
|
g_theOptionsManager->DisplayText(ad, pitch, msg, 0, 90, PALEFONT, TRUE8);
|
|
|
|
// Display choices
|
|
temp = g_theOptionsManager->CalculateStringWidth(ok);
|
|
g_theOptionsManager->DisplayText(ad, pitch, ok, halfScreen - (temp / 2), 130, PALEFONT, FALSE8);
|
|
temp = g_theOptionsManager->CalculateStringWidth(cancel);
|
|
g_theOptionsManager->DisplayText(ad, pitch, cancel, halfScreen - (temp / 2), 160, PALEFONT, FALSE8);
|
|
temp = g_theOptionsManager->CalculateStringWidth(quit);
|
|
g_theOptionsManager->DisplayText(ad, pitch, quit, halfScreen - (temp / 2), 200, PALEFONT, FALSE8);
|
|
|
|
surface_manager->Unlock_surface(working_buffer_id);
|
|
|
|
// Update screen manually
|
|
surface_manager->Flip();
|
|
|
|
for (uint32 tik = 0; tik < CD_SEARCH_DELAY; tik++) {
|
|
// Check for the CD again
|
|
if (CheckForCD(number)) {
|
|
// Cool, got it
|
|
|
|
// Black out screen manually
|
|
surface_manager->Clear_surface(working_buffer_id);
|
|
surface_manager->Flip();
|
|
|
|
gotCD = TRUE8;
|
|
break;
|
|
}
|
|
}
|
|
checking = FALSE8;
|
|
}
|
|
|
|
// we don't use this function so SendMessage is just disabled
|
|
//SendMessage(windowHandle, WM_PAINT, 0, 0);
|
|
|
|
if (gotCD)
|
|
break;
|
|
|
|
ad = surface_manager->Lock_surface(working_buffer_id);
|
|
pitch = surface_manager->Get_pitch(working_buffer_id);
|
|
|
|
// Display message
|
|
g_theOptionsManager->DisplayText(ad, pitch, msg, 0, 90, NORMALFONT, TRUE8, TRUE8);
|
|
|
|
// Display choices
|
|
temp = g_theOptionsManager->CalculateStringWidth(ok);
|
|
g_theOptionsManager->DisplayText(ad, pitch, ok, halfScreen - (temp / 2), 130, (bool8)(selection == 0) ? SELECTEDFONT : NORMALFONT, FALSE8);
|
|
temp = g_theOptionsManager->CalculateStringWidth(cancel);
|
|
g_theOptionsManager->DisplayText(ad, pitch, cancel, halfScreen - (temp / 2), 160, (bool8)(selection == 1) ? SELECTEDFONT : NORMALFONT, FALSE8);
|
|
temp = g_theOptionsManager->CalculateStringWidth(quit);
|
|
g_theOptionsManager->DisplayText(ad, pitch, quit, halfScreen - (temp / 2), 200, (bool8)(selection == 2) ? SELECTEDFONT : NORMALFONT, FALSE8);
|
|
|
|
surface_manager->Unlock_surface(working_buffer_id);
|
|
|
|
// Update screen manually
|
|
surface_manager->Flip();
|
|
}
|
|
#endif
|
|
return FALSE8;
|
|
}
|
|
|
|
void ClusterManager::LoadFileList(MISSION_ID /*mission*/) {
|
|
if (m_minimumInstall == FALSE8)
|
|
return;
|
|
|
|
#if 0
|
|
// Unload if we need to
|
|
if (m_filelistCursor != -1) {
|
|
memset(m_theList, 0, MAX_BYTESIZE_OF_A_FILELIST);
|
|
m_filelistCursor = -1;
|
|
}
|
|
|
|
// Make path to the correct filelist (on the CD)
|
|
pxString filelist;
|
|
HashFile(mission_names[mission], m_missionDir);
|
|
|
|
filelist.Format("%sm\\%s\\filelist.txt", GetCDRoot(), m_missionDir);
|
|
|
|
// Cool, now find out how big it is
|
|
m_filelistSize = GetFileSize(filelist);
|
|
if (m_filelistSize == 0)
|
|
Fatal_error(pxVString("Couldn't get size of %s", (const char *)filelist));
|
|
|
|
// Less four bytes for the total byte count
|
|
m_filelistSize -= 4;
|
|
|
|
// Open the file in binary mode
|
|
FILE *fp = openDiskFileForBinaryRead(filelist);
|
|
if (fp == NULL)
|
|
Fatal_error(pxVString("Couldn't open file %s for reading", (const char *)filelist));
|
|
|
|
// Read the total byte count
|
|
if (fread(&m_filelistTotalBytes, 1, 4, fp) != 4)
|
|
Fatal_error("Failed to read total byte count from filelist");
|
|
|
|
// Read that puppy in
|
|
if (fread(m_theList, 1, m_filelistSize, fp) != (uint32)m_filelistSize)
|
|
Fatal_error("Failed to read total byte count from filelist");
|
|
|
|
fclose(fp);
|
|
|
|
// Reset our cursor
|
|
m_filelistCursor = 0;
|
|
|
|
// Get pointer to the list in memory
|
|
char *ptr = (char *)m_theList;
|
|
|
|
// Now change all the newline markers to terminators
|
|
while (ptr[m_filelistCursor]) {
|
|
// New line encountered
|
|
if (ptr[m_filelistCursor] == 0x0d) {
|
|
// Overwrite with terminators
|
|
ptr[m_filelistCursor] = 0;
|
|
ptr[m_filelistCursor + 1] = 0;
|
|
m_filelistCursor++;
|
|
}
|
|
|
|
m_filelistCursor++;
|
|
}
|
|
|
|
// Reset our cursor
|
|
m_filelistCursor = 0;
|
|
#endif
|
|
}
|
|
|
|
char *ClusterManager::GetFileListEntry() {
|
|
if (m_filelistCursor == -1)
|
|
Fatal_error("Can't retrieve filelist entry without loading a filelist first!");
|
|
|
|
char *line = NULL;
|
|
|
|
// End of file check
|
|
if (m_filelistCursor < m_filelistSize) {
|
|
line = &(m_theList[m_filelistCursor]);
|
|
|
|
// Move to next line
|
|
m_filelistCursor += strlen((const char *)&(m_theList[m_filelistCursor]));
|
|
|
|
// Skip any terminators to get to the start of the next line
|
|
while (m_theList[m_filelistCursor] == 0)
|
|
m_filelistCursor++;
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
bool8 ClusterManager::DrawCoverFrame(void) {
|
|
// Draw a frame of the torture movie
|
|
g_while_u_wait_SequenceManager->drawFrame(working_buffer_id);
|
|
|
|
// Have we finished both movie playback and mission install
|
|
if (m_installDone) {
|
|
// Release bink from playing the movie
|
|
g_while_u_wait_SequenceManager->kill();
|
|
// Free up resources
|
|
delete[] m_movieMemoryPointer;
|
|
|
|
// Quit only when movie has finished
|
|
return FALSE8;
|
|
}
|
|
|
|
DrawProgressBits();
|
|
|
|
// Update screen manually
|
|
surface_manager->Flip();
|
|
|
|
return TRUE8;
|
|
}
|
|
|
|
void ClusterManager::InitialiseProgressBits() {
|
|
// Tweakable
|
|
int width = 5;
|
|
int height = 15;
|
|
int spacing = 2;
|
|
int initialY = SCREEN_DEPTH - height - 30;
|
|
|
|
// Calculate entire width so we can centre things
|
|
int length = (NUMBER_OF_PROGRESS_BITS * (width + spacing)) - spacing;
|
|
int initialX = (SCREEN_WIDTH / 2) - (length / 2);
|
|
|
|
for (int i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
|
|
m_progressBits[i].r.left = initialX;
|
|
m_progressBits[i].r.top = initialY;
|
|
m_progressBits[i].r.right = initialX + width;
|
|
m_progressBits[i].r.bottom = initialY + height;
|
|
|
|
m_progressBits[i].state = 0;
|
|
|
|
// Now increment
|
|
initialX += width + spacing;
|
|
}
|
|
|
|
m_bitsDone = 0;
|
|
}
|
|
|
|
void ClusterManager::UpdateProgressBits() {
|
|
if (m_frameCounter % PROGRESS_BIT_DELAY == 0) {
|
|
// Update the state of all bits
|
|
for (int i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
|
|
if (m_progressBits[i].state > 0 && m_progressBits[i].state != 6) {
|
|
m_progressBits[i].state = m_progressBits[i].state + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bytes per progress bit
|
|
float progress_inc = (float)(m_filelistTotalBytes / NUMBER_OF_PROGRESS_BITS);
|
|
|
|
// The number of bits that should bit switched on
|
|
uint bitsOn = (int)((float)m_bytesDone / progress_inc);
|
|
|
|
// Do we need to switch on a new bit
|
|
if (bitsOn > m_bitsDone) {
|
|
m_progressBits[m_bitsDone].state = 1;
|
|
m_bitsDone++;
|
|
}
|
|
}
|
|
|
|
void ClusterManager::DrawProgressBits() {
|
|
for (int i = 0; i < NUMBER_OF_PROGRESS_BITS; i++) {
|
|
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]);
|
|
}
|
|
}
|
|
|
|
void ClusterManager::Shutdown(void) {
|
|
// Only works on minimum install
|
|
CleanHardDisk();
|
|
}
|
|
|
|
void RecursivelyDeleteDirectory(const char * /*path*/) {
|
|
warning("STUB: RecursivelyDeleteDirectory()");
|
|
#if 0
|
|
// Parse this directory
|
|
DirectorySearch search(path);
|
|
|
|
// While there are things in the directory
|
|
while (search.GetNextFile()) {
|
|
// Is this a file or a directory
|
|
if (search.GetFileType() & _A_SUBDIR) {
|
|
pxString subdir = search.GetPathName();
|
|
|
|
// Recurse on this directory
|
|
RecursivelyDeleteDirectory(subdir);
|
|
|
|
// Then remove it too
|
|
|
|
// Ensure write access
|
|
_chmod(subdir, _S_IWRITE);
|
|
|
|
// Delete subdirectory
|
|
if (rmdir(subdir) == -1) {
|
|
int lastChar = subdir.GetLen() - 1;
|
|
|
|
// Need to chop of slash character
|
|
if (subdir[lastChar] == '\\') {
|
|
subdir[lastChar] = '\0';
|
|
|
|
// Try again
|
|
if (rmdir(subdir) == -1) {
|
|
// Couldn't delete this!
|
|
Fatal_error(pxVString("Couldn't delete directory: %s", (const char *)subdir));
|
|
}
|
|
} else {
|
|
// Couldn't delete this!
|
|
Fatal_error(pxVString("Couldn't delete directory: %s", (const char *)subdir));
|
|
}
|
|
}
|
|
} else {
|
|
// Need to make sure that files aren't read-only first
|
|
_chmod(search.GetPathName(), _S_IWRITE);
|
|
|
|
// Delete file
|
|
if (_unlink(search.GetPathName()) == -1) {
|
|
// Couldn't delete this file
|
|
MessageBox(NULL, pxVString("Couldn't delete file: %s", (const char *)search.GetPathName()), "ClusterManager Says:", MB_OK);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ValidateDirectoryToDelete(const char *path) {
|
|
if (strcmp(path, pxVString("m\\FP3YNHA\\")) == 0)
|
|
return;
|
|
else if (strcmp(path, pxVString("m\\HWYIPVA\\")) == 0)
|
|
return;
|
|
else if (strcmp(path, pxVString("m\\TPQUB4D\\")) == 0)
|
|
return;
|
|
else if (strcmp(path, pxVString("m\\RIGABTB\\")) == 0)
|
|
return;
|
|
else if (strcmp(path, pxVString("m\\GAIYO3A\\")) == 0)
|
|
return;
|
|
else if (strcmp(path, pxVString("m\\NMUFF0B\\")) == 0)
|
|
return;
|
|
else if (strcmp(path, pxVString("m\\1QYUOAA\\")) == 0)
|
|
return;
|
|
else if (strcmp(path, pxVString("m\\TT3WADD\\")) == 0)
|
|
return;
|
|
else
|
|
Fatal_error(pxVString("ValidateDirectoryToDelete() failed on: %s", path));
|
|
}
|
|
|
|
uint32 GetFileSize(const char *path) {
|
|
Common::File file;
|
|
|
|
if (!file.open(path)) {
|
|
return 0;
|
|
}
|
|
|
|
return (uint32)file.size();
|
|
}
|
|
|
|
const char *MissionIdToName(MISSION_ID mission) {
|
|
switch (mission) {
|
|
case MISSION1:
|
|
return g_m01;
|
|
case MISSION2:
|
|
return g_m02;
|
|
case MISSION3:
|
|
return g_m03;
|
|
case MISSION4:
|
|
return g_m04;
|
|
case MISSION5:
|
|
return g_m05;
|
|
case MISSION7:
|
|
return g_m07;
|
|
case MISSION8:
|
|
return g_m08;
|
|
case MISSION9:
|
|
return g_m08;
|
|
case MISSION10:
|
|
return g_m10;
|
|
}
|
|
|
|
Fatal_error("MissionIdToName() should never get here - smack AndyB");
|
|
return NULL;
|
|
}
|
|
|
|
void MakeDirectoryTree(MISSION_ID /*mission*/) {
|
|
warning("STUB: MakeDirectoryTree()");
|
|
#if 0
|
|
char pathToMake[128];
|
|
|
|
// First make the mission directory
|
|
char missionDir[8];
|
|
HashFile(mission_names[mission], missionDir);
|
|
|
|
sprintf(pathToMake, "m\\%s", missionDir);
|
|
if (_mkdir(pathToMake) != 0)
|
|
Fatal_error(pxVString("MakeDirectoryTree(): Failed to make directory: %s", pathToMake));
|
|
|
|
// Get the name of this mission
|
|
char *mission_name = MissionIdToName(mission);
|
|
|
|
// Now the session directories
|
|
for (uint32 i = 0; i < MAX_SESSIONS; i += 2) {
|
|
// Only build the session directories for this mission
|
|
if (strcmp(mission_name, sessions[i]) == 0) {
|
|
char sessionDir[8];
|
|
HashFile(sessions[i + 1], sessionDir);
|
|
|
|
sprintf(pathToMake, "m\\%s\\%s", missionDir, sessionDir);
|
|
if (_mkdir(pathToMake) != 0)
|
|
Fatal_error(pxVString("MakeDirectoryTree(): Failed to make directory: %s", pathToMake));
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
} // End of namespace ICB
|