mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-25 11:52:32 +01:00
1049 lines
19 KiB
C
1049 lines
19 KiB
C
#include "driver2.h"
|
|
|
|
#ifndef PSX
|
|
#include <stdint.h>
|
|
#include <SDL.h>
|
|
#endif // !PSX
|
|
#include "system.h"
|
|
|
|
#include "platform.h"
|
|
#include "xaplay.h"
|
|
#include "loadview.h"
|
|
#include "mission.h"
|
|
#include "glaunch.h"
|
|
#include "main.h"
|
|
#include "pad.h"
|
|
#include "draw.h"
|
|
#include "pause.h"
|
|
|
|
char gDataFolder[32] = "DRIVER2\\";
|
|
|
|
#ifdef PSX
|
|
|
|
/* those should be passed to linker script
|
|
|
|
------------------------------------------------------------------------------------
|
|
NAME | OFFSET | SIZE | DESCRIPTION
|
|
------------------------|----------|---------|--------------------------------------
|
|
_path_org | 0xE7000 | 0xB7C8 |
|
|
_otag1_org | 0xF3000 | 0x4200 |
|
|
_otag2_org | 0xF7200 | 0x4200 |
|
|
_primTab1_org | 0xFB400 | 1E000 |
|
|
_primTab2_org | 0x119400 | 1E000 |
|
|
_mallocTab_org | 0x137400 | 0xD47BC |(this is bigger, real is 0xC37BC)
|
|
_frnt_org | 0x1C0000 | no size | inside mallocTab
|
|
_sbnk_org | 0x180000 | no size | inside mallocTab
|
|
_repl_org | 0x1FABBC | 0x3444 | probably inside mallocTab
|
|
|
|
*/
|
|
|
|
|
|
#else
|
|
|
|
// Initialized in redriver2_main
|
|
volatile char* _frontend_buffer = NULL; // 0xFB400
|
|
volatile char* _other_buffer = NULL; // 0xF3000
|
|
volatile char* _other_buffer2 = NULL; // 0xE7000
|
|
volatile OTTYPE* _OT1 = NULL; // 0xF3000
|
|
volatile OTTYPE* _OT2 = NULL; // 0xF7200
|
|
volatile char* _primTab1 = NULL; // 0xFB400
|
|
volatile char* _primTab2 = NULL; // 0x119400
|
|
volatile char* _sbank_buffer = NULL; // 0x180000
|
|
volatile char* _overlay_buffer = NULL; // 0x1C0000
|
|
volatile char* _replay_buffer = NULL; // 0x1FABBC
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(USE_CRT_MALLOC)
|
|
|
|
char* mallocptr = NULL;
|
|
volatile char* malloctab = NULL;
|
|
|
|
void* g_dynamicAllocs[1024] = { 0 };
|
|
int g_numDynamicAllocs = 0;
|
|
|
|
char* sys_malloc(int size, char* funcname, int line)
|
|
{
|
|
if (g_numDynamicAllocs & 0x10000)
|
|
sys_tempfree();
|
|
|
|
#ifdef _DEBUG
|
|
printWarning("CRT malloc(%d) in %s, line %d\n", size, funcname, __LINE__);
|
|
#endif // _DEBUG
|
|
|
|
void* ptr = malloc(size);
|
|
g_dynamicAllocs[g_numDynamicAllocs++] = ptr;
|
|
|
|
return (char*)ptr;
|
|
}
|
|
|
|
void sys_freeall()
|
|
{
|
|
int numAlloc = g_numDynamicAllocs & 0xfff;
|
|
|
|
for (int i = 0; i < numAlloc; i++)
|
|
{
|
|
free(g_dynamicAllocs[i]);
|
|
g_dynamicAllocs[i] = NULL;
|
|
}
|
|
|
|
g_numDynamicAllocs = 0;
|
|
}
|
|
|
|
char* sys_tempalloc(int size)
|
|
{
|
|
if (g_numDynamicAllocs & 0x10000)
|
|
{
|
|
printError("sys_tempalloc: another alloc in use!\n");
|
|
trap(1000);
|
|
return NULL;
|
|
}
|
|
|
|
char* tmp_ptr = (char*)malloc(size);
|
|
|
|
g_dynamicAllocs[g_numDynamicAllocs] = tmp_ptr;
|
|
g_numDynamicAllocs |= 0x10000;
|
|
|
|
return tmp_ptr;
|
|
}
|
|
|
|
void sys_tempfree()
|
|
{
|
|
g_numDynamicAllocs &= ~0x10000;
|
|
free(g_dynamicAllocs[g_numDynamicAllocs]);
|
|
g_dynamicAllocs[g_numDynamicAllocs] = NULL;
|
|
}
|
|
#elif !defined(PSX)
|
|
|
|
char g_allocatedMem[0x200000]; // 0x137400 (_ramsize). TODO: use real malloc size: 870332
|
|
volatile char* mallocptr = g_allocatedMem;
|
|
volatile char* malloctab = g_allocatedMem;
|
|
|
|
#endif
|
|
|
|
int leadAIRequired = 0;
|
|
int leadAILoaded = 0;
|
|
int pathAILoaded = 0;
|
|
|
|
char* LevelNames[] = {
|
|
"CHICAGO",
|
|
"HAVANA",
|
|
"VEGAS",
|
|
"RIO",
|
|
};
|
|
|
|
char* LevelFiles[] = {
|
|
"LEVELS\\CHICAGO.LEV",
|
|
"LEVELS\\HAVANA.LEV",
|
|
"LEVELS\\VEGAS.LEV",
|
|
"LEVELS\\RIO.LEV",
|
|
};
|
|
|
|
char* LoadingScreenNames[] = {
|
|
"GFX\\LOADCHIC.TIM",
|
|
"GFX\\LOADHAVA.TIM",
|
|
"GFX\\LOADVEGA.TIM",
|
|
"GFX\\LOADRIO.TIM",
|
|
};
|
|
|
|
CdlFILE currentfileinfo;
|
|
char currentfilename[128] = { 0 };
|
|
|
|
DRAW_MODE draw_mode_pal =
|
|
{ 0, 0, 0, 0, 512, 256, 0, 16 };
|
|
|
|
DRAW_MODE draw_mode_ntsc =
|
|
{ 0, 0, 0, 8, 512, 240, 0, 0 };
|
|
|
|
DB MPBuff[2][2];
|
|
DB* last;
|
|
DB* current;
|
|
|
|
static CITYTYPE lasttype = (CITYTYPE)-1;
|
|
static int lastcity = -1;
|
|
|
|
int citystart[8];
|
|
XYPAIR citylumps[8][4];
|
|
|
|
#ifndef PSX
|
|
int gContentOverride = 1; // use unpacked filesystem?
|
|
char g_CurrentLevelFileName[64];
|
|
char* g_CurrentLevelSpoolData = NULL;
|
|
#endif // !PSX
|
|
|
|
// TODO: to game vars
|
|
|
|
// [D] [T]
|
|
void ClearMem(char* mem, int size)
|
|
{
|
|
// 16 bit aligned clear
|
|
#ifndef PSX
|
|
memset(mem, 0, size);
|
|
#else
|
|
char* end;
|
|
end = mem + size;
|
|
|
|
while ((((u_int)mem & 3) != 0 && (mem < end))) {
|
|
*mem = 0;
|
|
mem = (char*)((int)mem + 1);
|
|
}
|
|
|
|
while (mem <= end + -0x10) {
|
|
*(u_int*)mem = 0;
|
|
((u_int*)mem)[1] = 0;
|
|
((u_int*)mem)[2] = 0;
|
|
((u_int*)mem)[3] = 0;
|
|
mem = (char*)((u_int*)mem + 4);
|
|
}
|
|
|
|
while (mem <= end + -4) {
|
|
*(u_int*)mem = 0;
|
|
mem = (char*)((u_int*)mem + 1);
|
|
}
|
|
|
|
while (mem < end) {
|
|
*mem = 0;
|
|
mem = (char*)((int)mem + 1);
|
|
}
|
|
#endif // !PSX
|
|
}
|
|
|
|
// [D] [T]
|
|
void setMem8(unsigned char* mem, unsigned char val, int size)
|
|
{
|
|
while (--size > 0)
|
|
*mem++ = val;
|
|
|
|
// TODO: check alignment/bounds?
|
|
}
|
|
|
|
// [D] [T]
|
|
void setMem16(ushort* mem, ushort val, int size)
|
|
{
|
|
while (--size > 0)
|
|
*mem++ = val;
|
|
|
|
// TODO: check alignment/bounds?
|
|
}
|
|
|
|
// [T]
|
|
void Init_FileSystem(void)
|
|
{
|
|
CdInit();
|
|
VSync(3);
|
|
|
|
// Driver 1 were looking up level files on CD...
|
|
}
|
|
|
|
int gNumCDRetries = 0;
|
|
|
|
// [D] [T]
|
|
void DoCDRetry(void)
|
|
{
|
|
if (gNumCDRetries++ > 9)
|
|
{
|
|
CdInit();
|
|
VSync(3);
|
|
|
|
gNumCDRetries = 0;
|
|
}
|
|
}
|
|
|
|
// loads whole file into buffer
|
|
// [D] [T]
|
|
int Loadfile(char* name, char* addr)
|
|
{
|
|
int nread;
|
|
unsigned char res[8];
|
|
char namebuffer[64];
|
|
|
|
#if USE_PC_FILESYSTEM
|
|
int fileSize;
|
|
|
|
sprintf(namebuffer, "%s%s", gDataFolder, name);
|
|
FS_FixPathSlashes(namebuffer);
|
|
|
|
FILE* fptr = fopen(namebuffer, "rb");
|
|
if (fptr)
|
|
{
|
|
fseek(fptr, 0, SEEK_END);
|
|
fileSize = ftell(fptr);
|
|
|
|
fseek(fptr, 0, SEEK_SET);
|
|
int numRead = fread(addr, 1, fileSize, fptr);
|
|
|
|
fclose(fptr);
|
|
|
|
//SDL_Delay(200); // [A] PSX-like CD delay
|
|
|
|
return numRead;
|
|
}
|
|
#endif
|
|
|
|
#if USE_CD_FILESYSTEM
|
|
return LoadfileSeg(name, addr, 0, -1);
|
|
#endif
|
|
}
|
|
|
|
// [D] [T]
|
|
int FileExists(char* filename)
|
|
{
|
|
char namebuffer[128];
|
|
|
|
if (*filename == '\0')
|
|
return 0;
|
|
|
|
#if USE_PC_FILESYSTEM
|
|
sprintf(namebuffer, "%s%s", gDataFolder, filename);
|
|
FS_FixPathSlashes(namebuffer);
|
|
|
|
FILE* fp = fopen(namebuffer, "rb");
|
|
if (fp)
|
|
{
|
|
fclose(fp);
|
|
return 1;
|
|
}
|
|
#endif // USE_PC_FILESYSTEM
|
|
|
|
#if USE_CD_FILESYSTEM
|
|
int retries;
|
|
CdlFILE cdfile;
|
|
|
|
sprintf(namebuffer, "\\%s%s;1", gDataFolder, filename);
|
|
|
|
#ifdef PSX
|
|
retries = 9;
|
|
do {
|
|
|
|
if (CdSearchFile(&cdfile, namebuffer) != NULL)
|
|
return 1;
|
|
|
|
retries--;
|
|
DoCDRetry();
|
|
} while (retries >= 0);
|
|
|
|
#else
|
|
// don't retry or we'll have problems
|
|
if(CdSearchFile(&cdfile, namebuffer) != NULL)
|
|
return 1;
|
|
#endif
|
|
|
|
#endif // USE_CD_FILESYSTEM
|
|
|
|
return 0;
|
|
}
|
|
|
|
// loads file partially into buffer
|
|
// [D] [T]
|
|
int LoadfileSeg(char* name, char* addr, int offset, int loadsize)
|
|
{
|
|
char namebuffer[64];
|
|
|
|
#if USE_PC_FILESYSTEM
|
|
int fileSize;
|
|
|
|
sprintf(namebuffer, "%s%s", gDataFolder, name);
|
|
FS_FixPathSlashes(namebuffer);
|
|
|
|
FILE* fptr = fopen(namebuffer, "rb");
|
|
if (fptr)
|
|
{
|
|
fseek(fptr, 0, SEEK_END);
|
|
fileSize = ftell(fptr);
|
|
|
|
if (loadsize == -1 || loadsize > fileSize)
|
|
loadsize = fileSize;
|
|
|
|
fseek(fptr, offset, SEEK_SET);
|
|
int numRead = fread(addr, 1, loadsize, fptr);
|
|
|
|
fclose(fptr);
|
|
|
|
//SDL_Delay(200); // [A] PSX-like CD delay
|
|
|
|
return numRead;
|
|
}
|
|
#endif // USE_PC_FILESYSTEM
|
|
|
|
#if USE_CD_FILESYSTEM
|
|
char* readPtr;
|
|
char* sectorPtr;
|
|
int remainingBytes;
|
|
int remainingOffset;
|
|
int sector;
|
|
u_char result[8];
|
|
char sectorbuffer[CDSECTOR_SIZE];
|
|
CdlLOC pos;
|
|
|
|
sprintf(namebuffer, "\\%s%s;1", gDataFolder, name);
|
|
|
|
if (strcmp(currentfilename, namebuffer) != 0)
|
|
{
|
|
strcpy(currentfilename, namebuffer);
|
|
|
|
while (CdSearchFile(¤tfileinfo, namebuffer) == NULL)
|
|
{
|
|
DoCDRetry();
|
|
}
|
|
}
|
|
|
|
if (loadsize == -1)
|
|
loadsize = currentfileinfo.size - offset;
|
|
|
|
remainingOffset = offset & 0x7ff;
|
|
remainingBytes = loadsize;
|
|
|
|
// seek to the sector
|
|
sector = offset / CDSECTOR_SIZE + CdPosToInt(¤tfileinfo.pos);
|
|
|
|
// start reading sectors from CD
|
|
while(remainingBytes > 0)
|
|
{
|
|
// start reading if we getting to desired offset
|
|
CdIntToPos(sector, &pos);
|
|
|
|
// if we don't have offset or we have more than 2048 bytes
|
|
// - we can read into buffer directly (which is faster)
|
|
if (remainingBytes >= CDSECTOR_SIZE && remainingOffset == 0)
|
|
sectorPtr = addr;
|
|
else
|
|
sectorPtr = sectorbuffer;
|
|
|
|
// read sector
|
|
do
|
|
{
|
|
if (CdDiskReady(0) != CdlComplete)
|
|
DoCDRetry();
|
|
|
|
} while (CdControlB(CdlSetloc, (u_char*)&pos, NULL) == 0 ||
|
|
CdRead(1, (u_long*)sectorPtr, CdlModeSpeed) == 0 ||
|
|
CdReadSync(0, result) != 0);
|
|
|
|
// non-direct reads must be handled
|
|
if(sectorPtr == sectorbuffer)
|
|
{
|
|
// fetch
|
|
readPtr = sectorbuffer + remainingOffset;
|
|
|
|
// copy bytes
|
|
while (remainingBytes > 0 &&
|
|
readPtr - sectorbuffer < CDSECTOR_SIZE) // don't leave boundary
|
|
{
|
|
*addr++ = *readPtr++;
|
|
remainingBytes--;
|
|
}
|
|
|
|
remainingOffset = 0;
|
|
}
|
|
else
|
|
{
|
|
addr += CDSECTOR_SIZE;
|
|
remainingBytes -= CDSECTOR_SIZE;
|
|
}
|
|
|
|
// go to next sector
|
|
sector++;
|
|
}
|
|
|
|
return loadsize;
|
|
#elif USE_PC_FILESYSTEM && !defined(__EMSCRIPTEN__)
|
|
char errPrint[1024];
|
|
sprintf(errPrint, "Cannot open '%s'\n", namebuffer);
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR", errPrint, NULL);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void ReportMode(int on)
|
|
{
|
|
static u_char param[8];
|
|
|
|
if (XAPrepared() == 0)
|
|
{
|
|
if (on)
|
|
param[0] = CdlModeSpeed | CdlModeRept;
|
|
else
|
|
param[0] = CdlModeSpeed;
|
|
|
|
CdControlB(CdlSetmode, param, 0);
|
|
}
|
|
}
|
|
|
|
static volatile u_char endread = 0;
|
|
static volatile u_char load_complete = 0;
|
|
|
|
// [D] [T]
|
|
void data_ready(void)
|
|
{
|
|
if (endread)
|
|
{
|
|
CdDataCallback(NULL);
|
|
load_complete = 1;
|
|
}
|
|
}
|
|
|
|
static int current_sector = 0; // offset 0xAB27C
|
|
static char* current_address = NULL; // offset 0xAB288
|
|
static int sectors_left = 0; // offset 0xAB280
|
|
|
|
// [D] [T]
|
|
void sector_ready(u_char intr, u_char* result)
|
|
{
|
|
CdlLOC p;
|
|
|
|
if (intr == 1)
|
|
{
|
|
// read sector data
|
|
CdGetSector(current_address, SECTOR_SIZE);
|
|
|
|
current_address += CDSECTOR_SIZE;
|
|
current_sector++;
|
|
sectors_left--;
|
|
|
|
if (sectors_left == 0)
|
|
{
|
|
endread = 1;
|
|
|
|
CdReadyCallback(NULL);
|
|
CdControlF(CdlPause, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (*result & CdlStatShellOpen)
|
|
{
|
|
CdReadyCallback(NULL);
|
|
|
|
do {
|
|
} while (CdDiskReady(1) != CdlComplete);
|
|
|
|
CdReadyCallback(sector_ready);
|
|
}
|
|
|
|
CdIntToPos(current_sector, &p);
|
|
CdControlF(CdlReadS, (u_char*)&p);
|
|
}
|
|
}
|
|
|
|
#if USE_PC_FILESYSTEM
|
|
|
|
// It has to be this way
|
|
int loadsectorsPC(char* addr, int sector, int nsectors)
|
|
{
|
|
char namebuffer[64];
|
|
|
|
if (g_CurrentLevelFileName[0] == 0)
|
|
return 0;
|
|
|
|
strcpy(namebuffer, g_CurrentLevelFileName);
|
|
FS_FixPathSlashes(namebuffer);
|
|
|
|
FILE* fp = fopen(namebuffer, "rb");
|
|
|
|
if (fp)
|
|
{
|
|
// constrain nsectors to the maximum that can be read from the file
|
|
int maxSectors;
|
|
fseek(fp, 0, SEEK_END);
|
|
maxSectors = (ftell(fp) - (sector * CDSECTOR_SIZE)) / CDSECTOR_SIZE;
|
|
nsectors = MIN(nsectors, maxSectors);
|
|
|
|
fseek(fp, sector * CDSECTOR_SIZE, SEEK_SET);
|
|
fread(addr, CDSECTOR_SIZE, nsectors, fp);
|
|
|
|
fclose(fp);
|
|
|
|
ShowLoading();
|
|
return 1;
|
|
}
|
|
|
|
#if USE_PC_FILESYSTEM && !defined(__EMSCRIPTEN__)
|
|
char errPrint[512];
|
|
sprintf(errPrint, "loadsectorsPC: failed to open '%s'\n", namebuffer);
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR", errPrint, NULL);
|
|
#endif // USE_PC_FILESYSTEM && !PSX
|
|
return 0;
|
|
}
|
|
|
|
#endif // USE_PC_FILESYSTEM
|
|
|
|
// [D] [T]
|
|
void loadsectors(char* addr, int sector, int nsectors)
|
|
{
|
|
CdlLOC pos;
|
|
|
|
// [A]
|
|
if (nsectors == 0)
|
|
return;
|
|
|
|
#if USE_PC_FILESYSTEM
|
|
if (loadsectorsPC(addr, sector, nsectors))
|
|
return;
|
|
#endif
|
|
|
|
load_complete = 0;
|
|
endread = 0;
|
|
|
|
current_sector = sector;
|
|
sectors_left = nsectors;
|
|
current_address = addr;
|
|
|
|
CdDataCallback(data_ready);
|
|
CdReadyCallback(sector_ready);
|
|
|
|
// start asynchronous reading...
|
|
CdIntToPos(sector, &pos);
|
|
CdControlF(CdlReadS, (u_char*)&pos);
|
|
|
|
// ... but wait synchronously
|
|
do {
|
|
#ifdef __EMSCRIPTEN__
|
|
emscripten_sleep(0);
|
|
#endif // __EMSCRIPTEN__
|
|
} while (load_complete == 0);
|
|
|
|
ShowLoading();
|
|
}
|
|
|
|
// [D] [T]
|
|
void EnableDisplay(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < NumPlayers; i++) // [A]
|
|
{
|
|
ClearOTagR((u_long*)MPBuff[i][0].ot, OTSIZE);
|
|
ClearOTagR((u_long*)MPBuff[i][1].ot, OTSIZE);
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void DisableDisplay(void)
|
|
{
|
|
SetDispMask(0);
|
|
}
|
|
|
|
int DoNotSwap = 0;
|
|
DB* MPlast[2];
|
|
DB* MPcurrent[2];
|
|
|
|
// [A]
|
|
void ClearCurrentDrawBuffers()
|
|
{
|
|
ClearOTagR((u_long*)current->ot, OTSIZE);
|
|
current->primptr = current->primtab;
|
|
}
|
|
|
|
// [D] [T]
|
|
void SwapDrawBuffers(void)
|
|
{
|
|
DrawSync(0);
|
|
|
|
if (DoNotSwap == 0)
|
|
{
|
|
PutDispEnv(¤t->disp);
|
|
}
|
|
|
|
DoNotSwap = 0;
|
|
|
|
PutDrawEnv(¤t->draw);
|
|
DrawOTag((u_long*)(current->ot + OTSIZE-1));
|
|
|
|
if ((FrameCnt & 1) != 0)
|
|
{
|
|
current = &MPBuff[0][0];
|
|
last = &MPBuff[0][1];
|
|
}
|
|
else
|
|
{
|
|
current = &MPBuff[0][1];
|
|
last = &MPBuff[0][0];
|
|
}
|
|
|
|
ClearCurrentDrawBuffers();
|
|
}
|
|
|
|
// [D] [T]
|
|
void SwapDrawBuffers2(int player)
|
|
{
|
|
int toggle;
|
|
|
|
DrawSync(0);
|
|
|
|
if (player == 0)
|
|
{
|
|
PutDispEnv(¤t->disp);
|
|
}
|
|
|
|
PutDrawEnv(¤t->draw);
|
|
DrawOTag((u_long*)(current->ot + OTSIZE - 1));
|
|
|
|
if (player == 1)
|
|
{
|
|
toggle = FrameCnt & 1;
|
|
|
|
// [A] i guess it should work as intended
|
|
MPcurrent[0] = &MPBuff[0][-toggle + 1];
|
|
MPlast[0] = &MPBuff[0][toggle];
|
|
|
|
MPcurrent[1] = &MPBuff[1][-toggle + 1];
|
|
MPlast[1] = &MPBuff[1][toggle];
|
|
}
|
|
|
|
current = MPcurrent[1 - player];
|
|
last = MPlast[1 - player];
|
|
|
|
ClearOTagR((u_long*)current->ot, OTSIZE);
|
|
current->primptr = current->primtab;
|
|
}
|
|
|
|
short paddp;
|
|
short padd;
|
|
|
|
// [D] [T]
|
|
void UpdatePadData(void)
|
|
{
|
|
ReadControllers();
|
|
|
|
paddp = Pads[0].mapnew;
|
|
padd = Pads[0].mapped;
|
|
|
|
#ifndef PSX
|
|
extern void SwitchMappings(int menu);
|
|
SwitchMappings(pauseflag || CurrentGameMode == GAMEMODE_DIRECTOR); // FIXME: maybe gDrawPauseMenus instead of pauseflag?
|
|
#endif
|
|
}
|
|
|
|
// [D] [T]
|
|
void SetupDrawBuffers(void)
|
|
{
|
|
int i;
|
|
RECT16 rect;
|
|
|
|
// PAL: 256
|
|
// NTSC: 240
|
|
|
|
SetDefDispEnv(&MPBuff[0][0].disp, 0, 256, 320, SCREEN_H);
|
|
SetDefDispEnv(&MPBuff[0][1].disp, 0, 0, 320, SCREEN_H);
|
|
|
|
MPBuff[0][0].disp.screen.h = SCREEN_H;
|
|
MPBuff[0][1].disp.screen.h = SCREEN_H;
|
|
MPBuff[0][0].disp.screen.x = draw_mode.framex;
|
|
MPBuff[0][1].disp.screen.x = draw_mode.framex;
|
|
|
|
if (NoPlayerControl == 0)
|
|
SetupDrawBufferData(NumPlayers);
|
|
else
|
|
SetupDrawBufferData(1);
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
MPlast[i] = &MPBuff[i][1];
|
|
MPcurrent[i] = &MPBuff[i][0];
|
|
}
|
|
|
|
rect.w = 320;
|
|
rect.h = 512;
|
|
rect.x = 0;
|
|
rect.y = 0;
|
|
|
|
current = MPcurrent[0];
|
|
last = MPlast[0];
|
|
|
|
ClearImage(&rect, 0, 0, 0);
|
|
DrawSync(0);
|
|
}
|
|
|
|
// [D] [T]
|
|
void SetupDrawBufferData(int num_players)
|
|
{
|
|
int i, j;
|
|
int x[2], y[2];
|
|
int height;
|
|
int toggle;
|
|
|
|
if (num_players == 1)
|
|
{
|
|
height = SCREEN_H; // 240 on NTSC
|
|
x[0] = 0;
|
|
y[0] = 0;
|
|
x[1] = 0;
|
|
y[1] = 0;
|
|
}
|
|
else if (num_players == 2)
|
|
{
|
|
height = (SCREEN_H / 2 - 1); // 127; // 119 on NTSC
|
|
x[0] = 0;
|
|
y[0] = 0;
|
|
x[1] = 0;
|
|
y[1] = SCREEN_H / 2; // 120 on NTSC
|
|
}
|
|
else
|
|
{
|
|
D_CHECK_ERROR(true, "Erm... too many players selected. FATAL!");
|
|
}
|
|
|
|
SetGeomOffset(320 / 2, height / 2);
|
|
|
|
toggle = 0;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
for (j = 0; j < num_players; j++)
|
|
{
|
|
u_long* otpt;
|
|
u_char* primpt;
|
|
|
|
if (toggle)
|
|
{
|
|
otpt = (u_long*)_OT2;
|
|
primpt = (u_char*)_primTab2; // _primTab1 + PRIMTAB_SIZE
|
|
}
|
|
else
|
|
{
|
|
otpt = (u_long*)_OT1;
|
|
primpt = (u_char*)_primTab1;
|
|
}
|
|
|
|
toggle ^= 1;
|
|
InitaliseDrawEnv(MPBuff[j], x[j], y[j], 320, height);
|
|
|
|
MPBuff[i][j].primtab = (char*)primpt;
|
|
MPBuff[i][j].primptr = (char*)primpt;
|
|
MPBuff[i][j].ot = (OTTYPE*)otpt;
|
|
}
|
|
}
|
|
|
|
#ifdef PAL_VERSION
|
|
InitMatrix(aspect);
|
|
aspect.m[1][1] = 4300;
|
|
#else
|
|
InitMatrix(aspect);
|
|
aspect.m[1][1] = 4096;
|
|
#endif
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitaliseDrawEnv(DB* pBuff, int x, int y, int w, int h)
|
|
{
|
|
#ifdef PSX
|
|
#define DB1 pBuff[0]
|
|
#define DB2 pBuff[1]
|
|
#else
|
|
// on PsyX we have to prevent flicker
|
|
#define DB1 pBuff[1]
|
|
#define DB2 pBuff[0]
|
|
#endif
|
|
|
|
SetDefDrawEnv(&DB1.draw, x, y, w, h);
|
|
SetDefDrawEnv(&DB2.draw, x, y + 256, w, h);
|
|
|
|
pBuff[0].id = 0;
|
|
pBuff[0].draw.dfe = 1;
|
|
|
|
pBuff[1].id = 1;
|
|
pBuff[1].draw.dfe = 1;
|
|
|
|
#ifdef USE_PGXP
|
|
if(NumPlayers == 2)
|
|
{
|
|
pBuff[0].draw.clip.x -= 256;
|
|
pBuff[0].draw.clip.w += 512;
|
|
|
|
pBuff[1].draw.clip.x -= 256;
|
|
pBuff[1].draw.clip.w += 512;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// [D] [T]
|
|
void ResetCityType(void)
|
|
{
|
|
lasttype = (CITYTYPE)-1;
|
|
lastcity = -1;
|
|
|
|
#ifndef PSX
|
|
free(g_CurrentLevelSpoolData);
|
|
g_CurrentLevelSpoolData = NULL;
|
|
#endif // PSX
|
|
}
|
|
|
|
// [A]
|
|
CITYTYPE GetCityType()
|
|
{
|
|
return lasttype;
|
|
}
|
|
|
|
// [D] [T]
|
|
void SetCityType(CITYTYPE type)
|
|
{
|
|
char* format;
|
|
char filename[64];
|
|
unsigned char result[8];
|
|
|
|
if (type == lasttype && GameLevel == lastcity)
|
|
return;
|
|
|
|
ResetCityType();
|
|
|
|
lastcity = GameLevel;
|
|
lasttype = type;
|
|
|
|
#if USE_PC_FILESYSTEM
|
|
// PC code
|
|
switch (type)
|
|
{
|
|
case CITYTYPE_NIGHT:
|
|
format = "%sN%s";
|
|
break;
|
|
case CITYTYPE_MULTI_DAY:
|
|
format = "%sM%s";
|
|
break;
|
|
case CITYTYPE_MULTI_NIGHT:
|
|
format = "%sMN%s";
|
|
break;
|
|
default:
|
|
format = "%s%s";
|
|
break;
|
|
}
|
|
|
|
sprintf(filename, format, gDataFolder, LevelFiles[GameLevel]);
|
|
FS_FixPathSlashes(filename);
|
|
|
|
FILE* levFp = fopen(filename, "rb");
|
|
|
|
if (levFp)
|
|
{
|
|
// store level name as it's required by loadsectorsPC
|
|
strcpy(g_CurrentLevelFileName, filename);
|
|
|
|
// spool position is forced to 0
|
|
citystart[GameLevel] = 0;
|
|
|
|
// skip LUMP type (37) and size, it's already hardcoded
|
|
fseek(levFp, 8, SEEK_CUR);
|
|
fread(citylumps[GameLevel], 1, sizeof(citylumps[GameLevel]), levFp);
|
|
|
|
fclose(levFp);
|
|
|
|
return;
|
|
}
|
|
#endif // USE_PC_FILESYSTEM
|
|
|
|
#if USE_CD_FILESYSTEM
|
|
CdlFILE cdfile;
|
|
int i;
|
|
int sector;
|
|
int* data;
|
|
|
|
switch (type)
|
|
{
|
|
case CITYTYPE_NIGHT:
|
|
format = "\\%sN%s;1";
|
|
break;
|
|
case CITYTYPE_MULTI_DAY:
|
|
format = "\\%sM%s;1";
|
|
break;
|
|
case CITYTYPE_MULTI_NIGHT:
|
|
format = "\\%sMN%s;1";
|
|
break;
|
|
default:
|
|
format = "\\%s%s;1";
|
|
break;
|
|
}
|
|
|
|
sprintf(filename, format, gDataFolder, LevelFiles[GameLevel]);
|
|
|
|
while (CdSearchFile(&cdfile, filename) == NULL)
|
|
{
|
|
#if USE_PC_FILESYSTEM
|
|
#ifndef __EMSCRIPTEN__
|
|
char errPrint[512];
|
|
sprintf(errPrint, "SetCityType: failed to open '%s'\n", filename);
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR", errPrint, NULL);
|
|
exit(0);
|
|
#endif // !__EMSCRIPTEN__
|
|
#else
|
|
DoCDRetry();
|
|
#endif // USE_PC_FILESYSTEM
|
|
}
|
|
|
|
sector = CdPosToInt((CdlLOC*)&cdfile);
|
|
citystart[GameLevel] = sector;
|
|
|
|
do {
|
|
do {
|
|
|
|
if (CdDiskReady(0) != CdlComplete)
|
|
DoCDRetry();
|
|
|
|
} while (CdControlB(CdlSetloc, (u_char*)&cdfile, 0) == 0 ||
|
|
CdRead(1, (u_long*)_OT1, CdlModeSpeed) == 0);
|
|
|
|
} while (CdReadSync(0, result) != 0);
|
|
|
|
data = (int*)_OT1 + 2;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
citylumps[GameLevel][i].x = data[0] + sector * CDSECTOR_SIZE;
|
|
citylumps[GameLevel][i].y = data[1];
|
|
|
|
data += 2;
|
|
}
|
|
#elif USE_PC_FILESYSTEM && !defined(__EMSCRIPTEN__)
|
|
char errPrint[1024];
|
|
sprintf(errPrint, "SetCityType: cannot open level '%s'\n", filename);
|
|
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "ERROR", errPrint, NULL);
|
|
#endif // PSX
|
|
}
|
|
|
|
// [D] [T]
|
|
CDTYPE DiscSwapped(char* filename)
|
|
{
|
|
#if 1//ndef PSX
|
|
return CDTYPE_CORRECTDISC;
|
|
#else
|
|
CDTYPE ret;
|
|
CdlFILE cdfile;
|
|
|
|
switch(CdDiskReady(1))
|
|
{
|
|
case CdlStatStandby:
|
|
{
|
|
switch(CdGetDiskType())
|
|
{
|
|
case CdlStatNoDisk:
|
|
ret = CDTYPE_NODISC;
|
|
break;
|
|
case CdlOtherFormat:
|
|
ret = CDTYPE_WRONGDISC;
|
|
break;
|
|
case CdlCdromFormat:
|
|
{
|
|
if (CdSearchFile(&cdfile, filename) != NULL)
|
|
ret = CDTYPE_CORRECTDISC;
|
|
else
|
|
ret = CDTYPE_DISCERROR;
|
|
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case CdlStatShellOpen:
|
|
ret = CDTYPE_SHELLOPEN;
|
|
break;
|
|
default:
|
|
ret = CDTYPE_DISCERROR;
|
|
}
|
|
|
|
return ret;
|
|
#endif
|
|
}
|