872 lines
28 KiB
C++
872 lines
28 KiB
C++
|
//
|
|||
|
// Copyright 2020 Electronic Arts Inc.
|
|||
|
//
|
|||
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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 3 of the License, or (at your option) any later version.
|
|||
|
|
|||
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
|
|||
|
// in the hope that it will be useful, but with permitted additional restrictions
|
|||
|
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
|
|||
|
// distributed with this program. You should have received a copy of the
|
|||
|
// GNU General Public License along with permitted additional restrictions
|
|||
|
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
|
|||
|
|
|||
|
/* $Header: F:\projects\c&c\vcs\code\startup.cpv 2.17 16 Oct 1995 16:48:12 JOE_BOSTIC $ */
|
|||
|
/***********************************************************************************************
|
|||
|
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
|||
|
***********************************************************************************************
|
|||
|
* *
|
|||
|
* Project Name : Command & Conquer *
|
|||
|
* *
|
|||
|
* File Name : STARTUP.CPP *
|
|||
|
* *
|
|||
|
* Programmer : Joe L. Bostic *
|
|||
|
* *
|
|||
|
* Start Date : October 3, 1994 *
|
|||
|
* *
|
|||
|
* Last Update : August 27, 1995 [JLB] *
|
|||
|
* *
|
|||
|
*---------------------------------------------------------------------------------------------*
|
|||
|
* Functions: *
|
|||
|
* Delete_Swap_Files -- Deletes previously existing swap files. *
|
|||
|
* Prog_End -- Cleans up library systems in prep for game exit. *
|
|||
|
* main -- Initial startup routine (preps library systems). *
|
|||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|||
|
|
|||
|
#include "function.h"
|
|||
|
#include <conio.h>
|
|||
|
#include <io.h>
|
|||
|
#include "ccdde.h"
|
|||
|
|
|||
|
bool Read_Private_Config_Struct(char *profile, NewConfigType *config);
|
|||
|
void Delete_Swap_Files(void);
|
|||
|
void Print_Error_End_Exit(char *string);
|
|||
|
void Print_Error_Exit(char *string);
|
|||
|
WinTimerClass *WinTimer;
|
|||
|
extern void Create_Main_Window ( HANDLE instance , int command_show , int width , int height);
|
|||
|
|
|||
|
extern bool ReadyToQuit;
|
|||
|
void Read_Setup_Options(RawFileClass *config_file);
|
|||
|
|
|||
|
bool VideoBackBufferAllowed = true;
|
|||
|
void Check_From_WChat(char *wchat_name);
|
|||
|
bool SpawnedFromWChat = false;
|
|||
|
bool ProgEndCalled = false;
|
|||
|
|
|||
|
|
|||
|
extern "C"{
|
|||
|
bool __cdecl Detect_MMX_Availability(void);
|
|||
|
void __cdecl Init_MMX(void);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if (0)
|
|||
|
char WibbleBuffer[1024*1024];
|
|||
|
|
|||
|
void CD_Test(void)
|
|||
|
{
|
|||
|
HANDLE handle;
|
|||
|
DWORD size;
|
|||
|
|
|||
|
handle= CreateFile("e:\\scores.mix", GENERIC_READ, FILE_SHARE_READ,
|
|||
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|||
|
|
|||
|
if (handle== INVALID_HANDLE_VALUE){
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
unsigned bytes_read;
|
|||
|
|
|||
|
do{
|
|||
|
bytes_read = ReadFile (handle , WibbleBuffer , 1024*1024, &size, NULL);
|
|||
|
|
|||
|
}while(size == 1024*1024);
|
|||
|
|
|||
|
|
|||
|
CloseHandle (handle);
|
|||
|
}
|
|||
|
#endif //(0)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/***********************************************************************************************
|
|||
|
* main -- Initial startup routine (preps library systems). *
|
|||
|
* *
|
|||
|
* This is the routine that is first called when the program starts up. It basically *
|
|||
|
* handles the command line parsing and setting up library systems. *
|
|||
|
* *
|
|||
|
* INPUT: argc -- Number of command line arguments. *
|
|||
|
* *
|
|||
|
* argv -- Pointer to array of comman line argument strings. *
|
|||
|
* *
|
|||
|
* OUTPUT: Returns with execution failure code (if any). *
|
|||
|
* *
|
|||
|
* WARNINGS: none *
|
|||
|
* *
|
|||
|
* HISTORY: *
|
|||
|
* 03/20/1995 JLB : Created. *
|
|||
|
*=============================================================================================*/
|
|||
|
|
|||
|
HINSTANCE ProgramInstance;
|
|||
|
extern BOOL CC95AlreadyRunning;
|
|||
|
void Move_Point(short &x, short &y, register DirType dir, unsigned short distance);
|
|||
|
|
|||
|
void Check_Use_Compressed_Shapes (void);
|
|||
|
extern void DLL_Shutdown(void);
|
|||
|
|
|||
|
|
|||
|
BOOL WINAPI DllMain(HINSTANCE instance, unsigned int fdwReason, void *lpvReserved)
|
|||
|
{
|
|||
|
lpvReserved;
|
|||
|
|
|||
|
switch (fdwReason) {
|
|||
|
|
|||
|
case DLL_PROCESS_ATTACH:
|
|||
|
ProgramInstance = instance;
|
|||
|
break;
|
|||
|
|
|||
|
case DLL_PROCESS_DETACH:
|
|||
|
if (WindowsTimer) {
|
|||
|
delete WindowsTimer;
|
|||
|
WindowsTimer = NULL;
|
|||
|
}
|
|||
|
DLL_Shutdown();
|
|||
|
|
|||
|
MixFileClass::Free_All();
|
|||
|
|
|||
|
Uninit_Game();
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case DLL_THREAD_ATTACH:
|
|||
|
case DLL_THREAD_DETACH:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//int PASCAL WinMain ( HINSTANCE instance , HINSTANCE , char * command_line , int command_show )
|
|||
|
//{
|
|||
|
// Heap_Dump_Check( "first thing in main" );
|
|||
|
// malloc(1);
|
|||
|
|
|||
|
int DLL_Startup(const char * command_line_in)
|
|||
|
{
|
|||
|
RunningAsDLL = true;
|
|||
|
int command_show = SW_HIDE;
|
|||
|
HINSTANCE instance = ProgramInstance;
|
|||
|
char command_line[1024];
|
|||
|
strcpy(command_line, command_line_in);
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Starting up.\n");
|
|||
|
|
|||
|
|
|||
|
//WindowsTimer = new WinTimerClass(60,FALSE);
|
|||
|
//CD_Test();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
** These values return 0x47 if code is working correctly
|
|||
|
*/
|
|||
|
// int temp = Desired_Facing256 (1070, 5419, 1408, 5504);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
** If we are already running then switch to the existing process and exit
|
|||
|
*/
|
|||
|
SpawnedFromWChat = false;
|
|||
|
|
|||
|
if (CC95AlreadyRunning) { //Set in the DDEServer constructor
|
|||
|
//MessageBox (NULL, "Error - attempt to restart C&C95 when already running.", "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
|
|||
|
|
|||
|
HWND ccwindow;
|
|||
|
ccwindow = FindWindow ("Command & Conquer", "Command & Conquer");
|
|||
|
if (ccwindow){
|
|||
|
SetForegroundWindow ( ccwindow );
|
|||
|
ShowWindow ( ccwindow, SW_RESTORE );
|
|||
|
}
|
|||
|
|
|||
|
return (EXIT_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
// ST - 3/6/2019 1:36PM
|
|||
|
//DDSCAPS surface_capabilities;
|
|||
|
|
|||
|
if (Ram_Free(MEM_NORMAL) < 5000000) {
|
|||
|
#ifdef GERMAN
|
|||
|
printf("Zuwenig Hauptspeicher verf<72>gbar.\n");
|
|||
|
#else
|
|||
|
#ifdef FRENCH
|
|||
|
printf("M<EFBFBD>moire vive (RAM) insuffisante.\n");
|
|||
|
#else
|
|||
|
printf("Insufficient RAM available.\n");
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
return(EXIT_FAILURE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//void *test_buffer = Alloc(20,MEM_NORMAL);
|
|||
|
|
|||
|
//memset ((char*)test_buffer, 0, 21);
|
|||
|
|
|||
|
//Free(test_buffer);
|
|||
|
|
|||
|
|
|||
|
int argc; //Command line argument count
|
|||
|
unsigned command_scan;
|
|||
|
char command_char;
|
|||
|
char * argv[20]; //Pointers to command line arguments
|
|||
|
char path_to_exe[280];
|
|||
|
|
|||
|
ProgramInstance = instance;
|
|||
|
|
|||
|
/*
|
|||
|
** Get the full path to the .EXE
|
|||
|
*/
|
|||
|
GetModuleFileName (instance, &path_to_exe[0], 280);
|
|||
|
|
|||
|
/*
|
|||
|
** First argument is supposed to be a pointer to the .EXE that is running
|
|||
|
**
|
|||
|
*/
|
|||
|
argc=1; //Set argument count to 1
|
|||
|
argv[0]=&path_to_exe[0]; //Set 1st command line argument to point to full path
|
|||
|
|
|||
|
/*
|
|||
|
** Get pointers to command line arguments just like if we were in DOS
|
|||
|
**
|
|||
|
** The command line we get is cr/zero? terminated.
|
|||
|
**
|
|||
|
*/
|
|||
|
|
|||
|
command_scan=0;
|
|||
|
|
|||
|
do {
|
|||
|
/*
|
|||
|
** Scan for non-space character on command line
|
|||
|
*/
|
|||
|
do {
|
|||
|
command_char = *( command_line+command_scan++ );
|
|||
|
} while ( command_char==' ' );
|
|||
|
|
|||
|
if ( command_char!=0 && command_char != 13 ){
|
|||
|
argv[argc++]=command_line+command_scan-1;
|
|||
|
|
|||
|
/*
|
|||
|
** Scan for space character on command line
|
|||
|
*/
|
|||
|
bool in_quotes = false;
|
|||
|
do {
|
|||
|
command_char = *( command_line+command_scan++ );
|
|||
|
if (command_char == '"') {
|
|||
|
in_quotes = !in_quotes;
|
|||
|
}
|
|||
|
} while ( (in_quotes || command_char!=' ') && command_char != 0 && command_char!=13 );
|
|||
|
|
|||
|
*( command_line+command_scan-1 ) = 0;
|
|||
|
}
|
|||
|
|
|||
|
} while ( command_char != 0 && command_char != 13 && argc<20 );
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
** Remember the current working directory and drive.
|
|||
|
*/
|
|||
|
#if (0) //PG_TO_FIX
|
|||
|
unsigned olddrive;
|
|||
|
char oldpath[MAX_PATH];
|
|||
|
getcwd(oldpath, sizeof(oldpath));
|
|||
|
_dos_getdrive(&olddrive);
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
** Change directory to the where the executable is located. Handle the
|
|||
|
** case where there is no path attached to argv[0].
|
|||
|
*/
|
|||
|
char drive[_MAX_DRIVE];
|
|||
|
char path[_MAX_PATH];
|
|||
|
unsigned drivecount;
|
|||
|
_splitpath(argv[0], drive, path, NULL, NULL);
|
|||
|
if (!drive[0]) {
|
|||
|
drive[0] = ('A' + olddrive)-1;
|
|||
|
}
|
|||
|
if (!path[0]) {
|
|||
|
strcpy(path, ".");
|
|||
|
}
|
|||
|
_dos_setdrive(toupper((drive[0])-'A')+1, &drivecount);
|
|||
|
if (path[strlen(path)-1] == '\\') {
|
|||
|
path[strlen(path)-1] = '\0';
|
|||
|
}
|
|||
|
chdir(path);
|
|||
|
#endif
|
|||
|
|
|||
|
#ifdef JAPANESE
|
|||
|
ForceEnglish = false;
|
|||
|
#endif
|
|||
|
if (Parse_Command_Line(argc, argv)) {
|
|||
|
|
|||
|
WindowsTimer = new WinTimerClass(60,FALSE);
|
|||
|
|
|||
|
int time_test = WindowsTimer->Get_System_Tick_Count();
|
|||
|
Sleep (1000);
|
|||
|
if (WindowsTimer->Get_System_Tick_Count() == time_test){
|
|||
|
#ifdef FRENCH
|
|||
|
MessageBox(0, "Error - L'horloge syst<73>me n'a pas pu s'initialiser en raison de l'instabilit<69> du syt<79>me. Vous devez red<65>marrer Windows.", "Command & Conquer" , MB_OK|MB_ICONSTOP);
|
|||
|
#else
|
|||
|
#ifdef GERMAN
|
|||
|
MessageBox(0, "Fehler - das Timer-System konnte aufgrund einer Instabilit<69>t des Systems nicht initialisiert werden. Bitte starten Sie Windows neu.", "Command & Conquer", MB_OK|MB_ICONSTOP);
|
|||
|
#else
|
|||
|
MessageBox(0, "Error - Timer system failed to start due to system instability. You need to restart Windows.", "Command & Conquer", MB_OK|MB_ICONSTOP);
|
|||
|
#endif //GERMAN
|
|||
|
#endif //FRENCH
|
|||
|
return(EXIT_FAILURE);
|
|||
|
}
|
|||
|
|
|||
|
RawFileClass cfile("CONQUER.INI");
|
|||
|
|
|||
|
#ifdef JAPANESE
|
|||
|
//////////////////////////////////////if(!ForceEnglish) KBLanguage = 1;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
/*
|
|||
|
** Check for existance of MMX support on the processor
|
|||
|
*/
|
|||
|
if (Detect_MMX_Availability()){
|
|||
|
//MessageBox(NULL, "MMX extensions detected - enabling MMX support.", "Command & Conquer",MB_ICONEXCLAMATION|MB_OK);
|
|||
|
MMXAvailable = true;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
** If there is loads of memory then use uncompressed shapes
|
|||
|
*/
|
|||
|
Check_Use_Compressed_Shapes();
|
|||
|
|
|||
|
/*
|
|||
|
** If there is not enough disk space free, dont allow the product to run.
|
|||
|
*/
|
|||
|
if (Disk_Space_Available() < INIT_FREE_DISK_SPACE) {
|
|||
|
#ifdef GERMAN
|
|||
|
char disk_space_message [512];
|
|||
|
sprintf (disk_space_message, "Nicht genug Festplattenplatz f<>r Command & Conquer.\nSie brauchen %d MByte freien Platz auf der Festplatte.", (INIT_FREE_DISK_SPACE) / (1024 * 1024));
|
|||
|
MessageBox(NULL, disk_space_message, "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
|
|||
|
if ( WindowsTimer )
|
|||
|
delete WindowsTimer;
|
|||
|
return (EXIT_FAILURE);
|
|||
|
#endif
|
|||
|
#ifdef FRENCH
|
|||
|
char disk_space_message [512];
|
|||
|
sprintf (disk_space_message, "Espace disque insuffisant pour lancer Command & Conquer.\nVous devez disposer de %d Mo d'espace disponsible sur disque dur.", (INIT_FREE_DISK_SPACE) / (1024 * 1024));
|
|||
|
MessageBox(NULL, disk_space_message, "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
|
|||
|
if ( WindowsTimer )
|
|||
|
delete WindowsTimer;
|
|||
|
return (EXIT_FAILURE);
|
|||
|
#endif
|
|||
|
#if !(FRENCH | GERMAN)
|
|||
|
int reply = MessageBox(NULL, "Warning - you are critically low on free disk space for virtual memory and save games. Do you want to play C&C anyway?", "Command & Conquer", MB_ICONQUESTION|MB_YESNO);
|
|||
|
if (reply == IDNO){
|
|||
|
|
|||
|
if ( WindowsTimer )
|
|||
|
delete WindowsTimer;
|
|||
|
return (EXIT_FAILURE);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
#if (0) // ST - 1/2/2019 5:50PM
|
|||
|
CDFileClass::Set_CD_Drive (CDList.Get_First_CD_Drive());
|
|||
|
#endif
|
|||
|
if (cfile.Is_Available()) {
|
|||
|
|
|||
|
#ifndef NOMEMCHECK
|
|||
|
char * cdata = (char *)Load_Alloc_Data(cfile);
|
|||
|
Read_Private_Config_Struct(cdata, &NewConfig);
|
|||
|
delete [] cdata;
|
|||
|
#else
|
|||
|
Read_Private_Config_Struct((char *)Load_Alloc_Data(cfile), &NewConfig);
|
|||
|
#endif
|
|||
|
Read_Setup_Options( &cfile );
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Creating main window.\n");
|
|||
|
|
|||
|
Create_Main_Window( instance , command_show , ScreenWidth , ScreenHeight );
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Initialising audio.\n");
|
|||
|
|
|||
|
SoundOn = Audio_Init ( MainWindow , 16 , false , 11025*2 , 0 );
|
|||
|
|
|||
|
Palette = new(MEM_CLEAR) unsigned char[768];
|
|||
|
|
|||
|
BOOL video_success = FALSE;
|
|||
|
CCDebugString ("C&C95 - Setting video mode.\n");
|
|||
|
/*
|
|||
|
** Set 640x400 video mode. If its not available then try for 640x480
|
|||
|
*/
|
|||
|
if (ScreenHeight == 400){
|
|||
|
if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)){
|
|||
|
video_success = TRUE;
|
|||
|
}else{
|
|||
|
if (Set_Video_Mode (MainWindow, ScreenWidth, 480, 8)){
|
|||
|
video_success = TRUE;
|
|||
|
ScreenHeight = 480;
|
|||
|
}
|
|||
|
}
|
|||
|
}else{
|
|||
|
if (Set_Video_Mode (MainWindow, ScreenWidth, ScreenHeight, 8)){
|
|||
|
video_success = TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!video_success){
|
|||
|
CCDebugString ("C&C95 - Failed to set video mode.\n");
|
|||
|
MessageBox(MainWindow, Text_String(TXT_UNABLE_TO_SET_VIDEO_MODE), "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
|
|||
|
if (WindowsTimer) delete WindowsTimer;
|
|||
|
if (Palette) delete [] Palette;
|
|||
|
return (EXIT_FAILURE);
|
|||
|
}
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Initialising video surfaces.\n");
|
|||
|
|
|||
|
if (ScreenWidth==320){
|
|||
|
VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
|
|||
|
ModeXBuff.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM));
|
|||
|
} else {
|
|||
|
|
|||
|
#if (1) //ST - 1/3/2019 2:11PM
|
|||
|
|
|||
|
VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
|
|||
|
HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
|
|||
|
|
|||
|
|
|||
|
#else
|
|||
|
VisiblePage.Init( ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)(GBC_VISIBLE | GBC_VIDEOMEM));
|
|||
|
|
|||
|
/*
|
|||
|
** Check that we really got a video memory page. Failure is fatal.
|
|||
|
*/
|
|||
|
memset (&surface_capabilities, 0, sizeof(surface_capabilities));
|
|||
|
VisiblePage.Get_DD_Surface()->GetCaps(&surface_capabilities);
|
|||
|
if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY){
|
|||
|
/*
|
|||
|
** Aaaarrgghh!
|
|||
|
*/
|
|||
|
CCDebugString ("C&C95 - Unable to allocate primary surface.\n");
|
|||
|
MessageBox(MainWindow, Text_String(TXT_UNABLE_TO_ALLOCATE_PRIMARY_VIDEO_BUFFER), "Command & Conquer", MB_ICONEXCLAMATION|MB_OK);
|
|||
|
if (WindowsTimer) delete WindowsTimer;
|
|||
|
if (Palette) delete [] Palette;
|
|||
|
return (EXIT_FAILURE);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
** If we have enough left then put the hidpage in video memory unless...
|
|||
|
**
|
|||
|
** If there is no blitter then we will get better performance with a system
|
|||
|
** memory hidpage
|
|||
|
**
|
|||
|
** Use a system memory page if the user has specified it via the ccsetup program.
|
|||
|
*/
|
|||
|
CCDebugString ("C&C95 - Allocating back buffer ");
|
|||
|
long video_memory = Get_Free_Video_Memory();
|
|||
|
unsigned video_capabilities = Get_Video_Hardware_Capabilities();
|
|||
|
if (video_memory < ScreenWidth*ScreenHeight ||
|
|||
|
(! (video_capabilities & VIDEO_BLITTER)) ||
|
|||
|
(video_capabilities & VIDEO_NO_HARDWARE_ASSIST) ||
|
|||
|
!VideoBackBufferAllowed){
|
|||
|
CCDebugString ("in system memory.\n");
|
|||
|
HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
|
|||
|
} else {
|
|||
|
//HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
|
|||
|
CCDebugString ("in video memory.\n");
|
|||
|
HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)GBC_VIDEOMEM);
|
|||
|
|
|||
|
/*
|
|||
|
** Make sure we really got a video memory hid page. If we didnt then things
|
|||
|
** will run very slowly.
|
|||
|
*/
|
|||
|
memset (&surface_capabilities, 0, sizeof(surface_capabilities));
|
|||
|
HiddenPage.Get_DD_Surface()->GetCaps(&surface_capabilities);
|
|||
|
if (surface_capabilities.dwCaps & DDSCAPS_SYSTEMMEMORY){
|
|||
|
/*
|
|||
|
** Oh dear, big trub. This must be an IBM Aptiva or something similarly cruddy.
|
|||
|
** We must redo the Hidden Page as system memory.
|
|||
|
*/
|
|||
|
AllSurfaces.Remove_DD_Surface(HiddenPage.Get_DD_Surface()); // Remove the old surface from the AllSurfaces list
|
|||
|
HiddenPage.Get_DD_Surface()->Release();
|
|||
|
HiddenPage.Init (ScreenWidth , ScreenHeight , NULL , 0 , (GBC_Enum)0);
|
|||
|
}else{
|
|||
|
VisiblePage.Attach_DD_Surface(&HiddenPage);
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
ScreenHeight = 1536;
|
|||
|
|
|||
|
if (VisiblePage.Get_Height() == 480){
|
|||
|
SeenBuff.Attach(&VisiblePage,0, 40, 1536, 1536);
|
|||
|
HidPage.Attach(&HiddenPage, 0, 40, 1536, 1536);
|
|||
|
}else{
|
|||
|
SeenBuff.Attach(&VisiblePage,0, 0, 1536, 1536);
|
|||
|
HidPage.Attach(&HiddenPage, 0, 0, 1536, 1536);
|
|||
|
}
|
|||
|
CCDebugString ("C&C95 - Adjusting variables for resolution.\n");
|
|||
|
Options.Adjust_Variables_For_Resolution();
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Setting palette.\n");
|
|||
|
/////////Set_Palette(Palette);
|
|||
|
|
|||
|
WindowList[0][WINDOWWIDTH] = SeenBuff.Get_Width() >> 3;
|
|||
|
WindowList[0][WINDOWHEIGHT] = SeenBuff.Get_Height();
|
|||
|
|
|||
|
/*
|
|||
|
** Install the memory error handler
|
|||
|
*/
|
|||
|
Memory_Error = &Memory_Error_Handler;
|
|||
|
|
|||
|
/*
|
|||
|
** Initialise MMX support if its available
|
|||
|
*/
|
|||
|
CCDebugString ("C&C95 - Entering MMX detection.\n");
|
|||
|
if (MMXAvailable){
|
|||
|
Init_MMX();
|
|||
|
}
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Creating mouse class.\n");
|
|||
|
WWMouse = new WWMouseClass(&SeenBuff, 32, 32);
|
|||
|
// MouseInstalled = Install_Mouse(32,24,320,200);
|
|||
|
MouseInstalled = TRUE;
|
|||
|
|
|||
|
/*
|
|||
|
** See if we should run the intro
|
|||
|
*/
|
|||
|
CCDebugString ("C&C95 - Reading CONQUER.INI.\n");
|
|||
|
char *buffer = (char*)Alloc(64000 , MEM_NORMAL); //(char *)HidPage.Get_Buffer();
|
|||
|
cfile.Read(buffer, cfile.Size());
|
|||
|
buffer[cfile.Size()] = '\0';
|
|||
|
|
|||
|
/*
|
|||
|
** Check for forced intro movie run disabling. If the conquer
|
|||
|
** configuration file says "no", then don't run the intro.
|
|||
|
*/
|
|||
|
char tempbuff[5];
|
|||
|
WWGetPrivateProfileString("Intro", "PlayIntro", "Yes", tempbuff, 4, buffer);
|
|||
|
if ((stricmp(tempbuff, "No") == 0) || SpawnedFromWChat) {
|
|||
|
Special.IsFromInstall = false;
|
|||
|
}else{
|
|||
|
Special.IsFromInstall = true;
|
|||
|
}
|
|||
|
SlowPalette = WWGetPrivateProfileInt("Options", "SlowPalette", 1, buffer);
|
|||
|
|
|||
|
#ifdef DEMO
|
|||
|
/*
|
|||
|
** Check for override directory path for CD searches.
|
|||
|
*/
|
|||
|
WWGetPrivateProfileString("CD", "Path", ".", OverridePath, sizeof(OverridePath), buffer);
|
|||
|
#endif
|
|||
|
|
|||
|
/*
|
|||
|
** Regardless of whether we should run it or not, here we're
|
|||
|
** gonna change it to say "no" in the future.
|
|||
|
*/
|
|||
|
WWWritePrivateProfileString("Intro", "PlayIntro", "No", buffer);
|
|||
|
cfile.Write(buffer, strlen(buffer));
|
|||
|
|
|||
|
Free(buffer);
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Checking availability of C&CSPAWN.INI packet from WChat.\n");
|
|||
|
if (DDEServer.Get_MPlayer_Game_Info()){
|
|||
|
CCDebugString ("C&C95 - C&CSPAWN.INI packet available.\n");
|
|||
|
Check_From_WChat(NULL);
|
|||
|
}else{
|
|||
|
CCDebugString ("C&C95 - C&CSPAWN.INI packet not arrived yet.\n");
|
|||
|
//Check_From_WChat("C&CSPAWN.INI");
|
|||
|
//if (Special.IsFromWChat){
|
|||
|
// DDEServer.Disable();
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
** If the intro is being run for the first time, then don't
|
|||
|
** allow breaking out of it with the <ESC> key.
|
|||
|
*/
|
|||
|
if (Special.IsFromInstall) {
|
|||
|
BreakoutAllowed = false;
|
|||
|
}
|
|||
|
|
|||
|
Memory_Error_Exit = Print_Error_End_Exit;
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Entering main game.\n");
|
|||
|
Main_Game(argc, argv);
|
|||
|
|
|||
|
if (RunningAsDLL) {
|
|||
|
return (EXIT_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
VisiblePage.Clear();
|
|||
|
HiddenPage.Clear();
|
|||
|
// Set_Video_Mode(RESET_MODE);
|
|||
|
|
|||
|
Memory_Error_Exit = Print_Error_Exit;
|
|||
|
|
|||
|
CCDebugString ("C&C95 - About to exit.\n");
|
|||
|
ReadyToQuit = 1;
|
|||
|
|
|||
|
PostMessage(MainWindow, WM_DESTROY, 0, 0);
|
|||
|
do
|
|||
|
{
|
|||
|
Keyboard::Check();
|
|||
|
}while (ReadyToQuit == 1);
|
|||
|
|
|||
|
CCDebugString ("C&C95 - Returned from final message loop.\n");
|
|||
|
//Prog_End();
|
|||
|
//Invalidate_Cached_Icons();
|
|||
|
//VisiblePage.Un_Init();
|
|||
|
//HiddenPage.Un_Init();
|
|||
|
//AllSurfaces.Release();
|
|||
|
//Reset_Video_Mode();
|
|||
|
//Stop_Profiler();
|
|||
|
return (EXIT_SUCCESS);
|
|||
|
|
|||
|
} else {
|
|||
|
#ifdef GERMAN
|
|||
|
puts("Bitte erst das SETUP-Programm starten.\n");
|
|||
|
#else
|
|||
|
#ifdef FRENCH
|
|||
|
puts("Lancez d'abord le programme de configuration SETUP.\n");
|
|||
|
#else
|
|||
|
puts("Run SETUP program first.");
|
|||
|
puts("\n");
|
|||
|
#endif
|
|||
|
Kbd.Get();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
// Remove_Keyboard_Interrupt();
|
|||
|
if (WindowsTimer){
|
|||
|
delete WindowsTimer;
|
|||
|
WindowsTimer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (Palette){
|
|||
|
delete [] Palette;
|
|||
|
Palette = NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
** Restore the current drive and directory.
|
|||
|
*/
|
|||
|
#ifdef NOT_FOR_WIN95
|
|||
|
_dos_setdrive(olddrive, &drivecount);
|
|||
|
chdir(oldpath);
|
|||
|
#endif //NOT_FOR_WIN95
|
|||
|
|
|||
|
return(EXIT_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/***********************************************************************************************
|
|||
|
* Prog_End -- Cleans up library systems in prep for game exit. *
|
|||
|
* *
|
|||
|
* This routine should be called before the game terminates. It handles cleaning up *
|
|||
|
* library systems so that a graceful return to the host operating system is achieved. *
|
|||
|
* *
|
|||
|
* INPUT: none *
|
|||
|
* *
|
|||
|
* OUTPUT: none *
|
|||
|
* *
|
|||
|
* WARNINGS: none *
|
|||
|
* *
|
|||
|
* HISTORY: *
|
|||
|
* 03/20/1995 JLB : Created. *
|
|||
|
*=============================================================================================*/
|
|||
|
void __cdecl Prog_End(const char *why, bool fatal) // Added why and fatal parameters. ST - 6/27/2019 10:10PM
|
|||
|
{
|
|||
|
GlyphX_Debug_Print("Prog_End()");
|
|||
|
|
|||
|
if (why) {
|
|||
|
GlyphX_Debug_Print(why);
|
|||
|
}
|
|||
|
if (fatal) {
|
|||
|
*((int*)0) = 0;
|
|||
|
}
|
|||
|
|
|||
|
#ifndef DEMO
|
|||
|
if (GameToPlay == GAME_MODEM || GameToPlay == GAME_NULL_MODEM) {
|
|||
|
// NullModem.Change_IRQ_Priority(0);
|
|||
|
}
|
|||
|
#endif
|
|||
|
CCDebugString ("C&C95 - About to call Sound_End.\n");
|
|||
|
Sound_End();
|
|||
|
CCDebugString ("C&C95 - Returned from Sound_End.\n");
|
|||
|
if (WWMouse){
|
|||
|
CCDebugString ("C&C95 - Deleting mouse object.\n");
|
|||
|
delete WWMouse;
|
|||
|
WWMouse = NULL;
|
|||
|
}
|
|||
|
if (WindowsTimer){
|
|||
|
CCDebugString ("C&C95 - Deleting windows timer.\n");
|
|||
|
delete WindowsTimer;
|
|||
|
WindowsTimer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (Palette){
|
|||
|
CCDebugString ("C&C95 - Deleting palette object.\n");
|
|||
|
delete [] Palette;
|
|||
|
Palette = NULL;
|
|||
|
}
|
|||
|
|
|||
|
ProgEndCalled = true;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/***********************************************************************************************
|
|||
|
* Delete_Swap_Files -- Deletes previously existing swap files. *
|
|||
|
* *
|
|||
|
* This routine will scan through the current directory and delete any swap files it may *
|
|||
|
* find. This is used to clear out any left over swap files from previous runs (crashes) *
|
|||
|
* of the game. This routine presumes that it cannot delete the swap file that is created *
|
|||
|
* by the current run of the game. *
|
|||
|
* *
|
|||
|
* INPUT: none *
|
|||
|
* *
|
|||
|
* OUTPUT: none *
|
|||
|
* *
|
|||
|
* WARNINGS: none *
|
|||
|
* *
|
|||
|
* HISTORY: *
|
|||
|
* 08/27/1995 JLB : Created. *
|
|||
|
*=============================================================================================*/
|
|||
|
void Delete_Swap_Files(void)
|
|||
|
{
|
|||
|
#if (0)
|
|||
|
struct find_t ff; // for _dos_findfirst
|
|||
|
|
|||
|
if (!_dos_findfirst("*.SWP", _A_NORMAL, &ff)) {
|
|||
|
do {
|
|||
|
unlink(ff.name);
|
|||
|
} while(!_dos_findnext(&ff));
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void Print_Error_End_Exit(char *string)
|
|||
|
{
|
|||
|
printf( "%s\n", string );
|
|||
|
Get_Key();
|
|||
|
Prog_End();
|
|||
|
printf( "%s\n", string );
|
|||
|
if (!RunningAsDLL) {
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void Print_Error_Exit(char *string)
|
|||
|
{
|
|||
|
printf( "%s\n", string );
|
|||
|
if (!RunningAsDLL) {
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/***********************************************************************************************
|
|||
|
* Read_Setup_Options -- Read stuff in from the INI file that we need to know sooner *
|
|||
|
* *
|
|||
|
* *
|
|||
|
* *
|
|||
|
* INPUT: Nothing *
|
|||
|
* *
|
|||
|
* OUTPUT: Nothing *
|
|||
|
* *
|
|||
|
* WARNINGS: None *
|
|||
|
* *
|
|||
|
* HISTORY: *
|
|||
|
* 6/7/96 4:09PM ST : Created *
|
|||
|
*=============================================================================================*/
|
|||
|
void Read_Setup_Options( RawFileClass *config_file )
|
|||
|
{
|
|||
|
char *buffer = new char [config_file->Size()];
|
|||
|
|
|||
|
if (config_file->Is_Available()){
|
|||
|
|
|||
|
config_file->Read (buffer, config_file->Size());
|
|||
|
|
|||
|
VideoBackBufferAllowed = WWGetPrivateProfileInt ("Options", "VideoBackBuffer", 1, buffer);
|
|||
|
AllowHardwareBlitFills = WWGetPrivateProfileInt ("Options", "HardwareFills", 1, buffer);
|
|||
|
ScreenHeight = WWGetPrivateProfileInt ("Options", "Resolution", 0, buffer) ? 1536 : 1536;
|
|||
|
IsV107 = WWGetPrivateProfileInt ("Options", "Compatibility", 0, buffer);
|
|||
|
|
|||
|
/*
|
|||
|
** See if an alternative socket number has been specified
|
|||
|
*/
|
|||
|
int socket = WWGetPrivateProfileInt ("Options", "Socket", 0, buffer);
|
|||
|
if (socket >0 ){
|
|||
|
socket += 0x4000;
|
|||
|
if (socket >= 0x4000 && socket < 0x8000) {
|
|||
|
Ipx.Set_Socket (socket);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
** See if a destination network has been specified
|
|||
|
*/
|
|||
|
char netbuf [512];
|
|||
|
memset (netbuf, 0, sizeof (netbuf) );
|
|||
|
char *netptr = WWGetPrivateProfileString ("Options", "DestNet", NULL, netbuf, sizeof (netbuf), buffer);
|
|||
|
|
|||
|
if (netptr && strlen (netbuf)){
|
|||
|
NetNumType net;
|
|||
|
NetNodeType node;
|
|||
|
|
|||
|
/*
|
|||
|
** Scan the string, pulling off each address piece
|
|||
|
*/
|
|||
|
int i = 0;
|
|||
|
char * p = strtok(netbuf,".");
|
|||
|
int x;
|
|||
|
while (p) {
|
|||
|
sscanf(p,"%x",&x); // convert from hex string to int
|
|||
|
if (i < 4) {
|
|||
|
net[i] = (char)x; // fill NetNum
|
|||
|
} else {
|
|||
|
node[i-4] = (char)x; // fill NetNode
|
|||
|
}
|
|||
|
i++;
|
|||
|
p = strtok(NULL,".");
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
** If all the address components were successfully read, fill in the
|
|||
|
** BridgeNet with a broadcast address to the network across the bridge.
|
|||
|
*/
|
|||
|
if (i >= 4) {
|
|||
|
IsBridge = 1;
|
|||
|
memset(node, 0xff, 6);
|
|||
|
BridgeNet = IPXAddressClass(net, node);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
delete [] buffer;
|
|||
|
}
|