Merge pull request #11 from OpenDriver2/develop-SoapyMan

General fixes and improvements
This commit is contained in:
Ilya 2020-11-14 16:53:16 +06:00 committed by GitHub
commit 8e976e3b9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 4522 additions and 2003 deletions

View File

@ -1,4 +1,4 @@
version: 3.0.{build}
version: 4.2.{build}
branches:
only:
@ -64,7 +64,7 @@ after_build:
- cmd: cd %project_folder%\bin\%configuration%
- cmd: copy %SDL2_DIR%\lib\x86\SDL2.dll SDL2.dll /Y
- cmd: copy %OPENAL_DIR%\bin\Win32\soft_oal.dll OpenAL32.dll /Y
- cmd: copy %data_folder%\config.ini config.ini /Y
- cmd: xcopy /e /v %data_folder% .\ /Y
- 7z a "REDRIVER2_%configuration%.zip" ".\*"
#build: off

37
changelog.txt Normal file
View File

@ -0,0 +1,37 @@
REDRIVER2 4.2 alpha
Changelog since Oct 12 2000
Gameplay:
- Improved cop AI batter logic to better balance difficulty
- Restored Tanner felony (can be seen in two Vegas missions)
- Cops no longer can see player if on different heights
- Fixed cop AI activation when player without felony touches roadblock car
- Fixed and improved Cop AI navigation/pathfinding
- Fixed player car drowning bug in tunnels
- Fixed Tanner "drowning" by non-moving train in Vegas Ghost Town
- Restored Tanner drowning movement in water
- Fixed Tanner sitting on chairs
- Easier jump in "Boat Jump"
Effects/Visuals:
- Improved draw distance and resolved glitches
- Restored street lamp damage
- Restored street light trails
- Fixed some polygons not drawing (Chicago Goose island's white barrels)
- Car lost hubcaps are now bound to single car
- Restored Havana secret car elevator sound
- Restored multiplayer follow camera
- Restored car engine smoke
- Leaves are now affected properly by player car and chased car
Film Director:
- Fix camera invalidation bugs
- Added variable zoom for non-locked tripod camera
- Added target height adjustment to locked tripod camera
- Improved chase camera, restored height and distance editing
Other:
- PC version now automatically saves undercover campaign progress
- PC version now has command line arguments
- Memory card overlay removed

View File

@ -0,0 +1,279 @@
REFLECTIONS
(In alphabetical order)
GAME CONCEPT AND DEVELOPMENT DIRECTOR
Martin Edmondson
PROJECT MANAGEMENT
Gareth Edmondson
Tony M Roberts
PROGRAMMING TEAM
Steve Burrows
Jon Head
James Hopkin
Russ Lazzari
Will Musson
Christopher Phillips (Lead Technical)
Jeanette Phillips
ADDITIONAL PROGRAMMING
Wayne Coles
Chris Jenner
CITY ART TEAM
Dave Oxford (Art Manager)
CHICAGO
Mike Thompson
Chris Willacy
HAVANA
Steven Adams
Andreas Tawn
LAS VEGAS
Andrew Bales
Carl Jackson
Dave Oxford Jnr
Andrew Sharratt
RIO
Andrew Bales
Dave Oxford Jnr
ADDITIONAL ARTWORK
Phil Baxter
Jack Couvela
Richard Daglish
Paul Foster
Michael Jeffries
Alex Mallinson
Daniel Oxford
CUT SCENE ANIMATION TEAM
Mark Akester
Robin Armstrong
Davo Cockburn
Marcus Hardy
Matthew Hughes
Doug Lewis (Storyboarding)
Simon McKeown (Head of Animation)
Jonathan Redhead
Richard Robinson
GAME DESIGN
Martin Edmondson
Craig Lawson
SCREEN PLAY
Maurice Suckling
MISSION SCRIPTING
James Hume
Martin Oliver
IN HOUSE TESTING
William Brown
ADDITIONAL CREDITS
VOICE RECORDING
Arranged by
All in the Game Ltd
POST PRODUCTION & SOUND EFFECTS
Supplied by PC Music Ltd
LOCALISATION
Browns Language Services
SPECIAL THANKS:
Giselle Stewart (General Manager)
Alistair Brimble
Lee Kirton
Keith Leary
North East American Car Club
Forsters of Consett
Viewpoint Digital
Deadline Technical Services
Daniel Matray
Mz.Lynn.Danielz.
INFOGRAMES
An Infogrames Motion Production
EXECUTIVE VICE-PRESIDENT, PRODUCTION AND PUBLISHING
Jean-Philippe Agati
HEAD OF LABEL - INFOGRAMES MOTION
Olivier Goulay
INFOGRAMES MOTION PRODUCTION TEAM
Gareth Betts
Ivan Davies
Eric Labelle
Jay Sharples
INFOGRAMES MOTION MARKETING TEAM
Larry Sparks
Monique Crusot
Cindy Church
Lynn Daniel
Florence Rigaut
Anne Roy
Renaud Marin
Richard Hall
Daniel Matray
INFOGRAMES EUROPE SHEFFIELD Q.A TEAM
Lewis Glover
Robert Lunt
Phil Eckford
SPECIAL Q.A THANKS
Carrie Hobson
Dan Webster
TESTERS
Martin Berridge
Steve Woodward
Rob Taylor
Wayne Adkin
Dominic Hartley
Stef Reali
Jack Bishop
INFOGRAMES EUROPE LYON Q.A TEAM
Stephane Pradier
Stephane Charrier
Christian Ampere
Xavier Martin
Hakim Belayati
Philippe Trignat
Manuel "Franchu" Rubira
ADDITIONAL THANKS
The remaining Sheffield Q.A Dept
James McCarthy
INFOGRAMES LOCALISATION GROUP
Sylviane Pivot
Valerie Maillot
Sarah Bennett
Danielle Perez
Beatrice Rodriguez
Monica Steinhauer
SPECIAL THANKS:
Jim Murdoch
Rebecka Pernered
Sophie Wibaux
Jean Marcel Nicolai
Audrey Chapot
Paul Fox
Matt Woodley
Mercier Gray
Red Pepper Design
INFOGRAMES DISTRIBUTION EUROPE
Penrose Tackie
Lee Kirton
Alexandre Enklaar
Arnaud Blacher
Cecile Fouques Du Parc
Jerome Barbe
Duarte Nuno
Beatriz Doval
Aida Guerra
Frans Mittermayer
Achim Schmauss
Guido Alt
Corine Beroud
Mathieu Brossette
Bart Hufen
Matt Broughton
Louise Malouf
Kym Warner
MUSIC
Dust Junkies - Fever
Nicholas Lockett / Sam Hickling / Stephen Jones / Paul Billington.
Published by Universal Music Publishing Limited / Copyright Control.
P&C 1996 Polydor Ltd (UK)
Etta James - In The Basement
Composed by Raynard Miner / Billy Davis / Carl Smith. Published by Chevis
Publishing Corp. By permission of EMI Music Publishing Ltd. P&C 1966 MCA
Records Inc
Sonny Boy Williamson - HELP ME
Composed by Sonny Boy Williamson, Willie Dixon and Ralph Bass.
Copyright Arc Music Corp and Hoochie Coochie Music Music. Used by kind
permission of Jewel Music Ltd and Bug Music Ltd. P&C 1963 MCA Records Inc
Hound Dog Taylor & The House Rockers - Sitting At Home Alone
Written by Theodore R. Taylor. Published by Gazell Publishing International
for Eyeball Music and Alligator Records. P&C 1973 Alligator Records
Kenny Rogers - Just Dropped In
Written by Mickey Newbury. Published by Acuff Rose Music Publishing.
P&C 1985 MCA Records Inc
Mozart - Lacrimosa
Couresy of The Decca Record Company Limited. Licensed by kind permission
from The Film & TV Licensing Division, part of the Universal Music Group
IN GAME MUSIC
Alistair Brimble
Semi-Precious Studios
Richard Narco
All events and characters depicted in this game are fictitious. Any similarity
to actual persons, living or dead, is purely coincidental.
Driver 2 (C)2000 Infogrames. All rights Reserved. Created by Reflections
Interactive Limited, an Infogrames, Inc studio. Published & distributed by
Infogrames. Reflections and the Reflections logo are trademarks of Reflections
Interactive Limited. Infogrames and the Infogrames logo are trademarks of
Infogrames. All other trademarks are the property of their respective companies.
Tanner and Jones last seen in 2011

BIN
data/DRIVER2/FMV/FONT.TIM Normal file

Binary file not shown.

View File

@ -11,5 +11,7 @@ bilinearFiltering=0
pgxpZbuffer=0
[game]
drawDistance=600
freeCamera=1
drawDistance=1200
freeCamera=1
driver1music=0
userChases=RacingFreak,Snoopi,Olanov,Vortex,Fireboyd78

View File

@ -0,0 +1,25 @@
[settings]
loadExistingCutscene=1
mission=6
baseMission=50
subindex=2
streams=2
player=0
[stream0]
type=2 # 1=car, 2=tanner
model=0
palette=0
controlType=1 # 1=player, 7=cutscene
startRot=2048
startPosX=-36898
startPosZ=267729
[stream1]
type=1 # 1=car, 2=tanner
model=1
palette=0
controlType=7 # 1=player, 7=cutscene
startRot=2048
startPosX=-39288
startPosZ=263528

View File

@ -3,7 +3,6 @@
#if defined (_WINDOWS)
#include <windows.h>
#include <Dbghelp.h>
#include <tchar.h>
LONG WINAPI unhandled_handler(struct _EXCEPTION_POINTERS* apExceptionInfo);

View File

@ -3,10 +3,10 @@
#include "EMULATOR_VERSION.H"
#include "EMULATOR_GLOBALS.H"
#include "EMULATOR_PRIVATE.H"
#include "CRASHHANDLER.H"
#include "LIBETC.H"
#include "LIBPAD.H"
//#include <stdio.h>
//#include <string.h>
@ -29,6 +29,8 @@
#include <string.h>
#include <SDL.h>
#include "EMULATOR_TIMER.H"
SDL_Window* g_window = NULL;
TextureID vramTexture;
TextureID whiteTexture;
@ -45,8 +47,9 @@ SysCounter counters[3] = { 0 };
//std::thread counter_thread;
#endif
double g_swapTime;
timerCtx_t g_swapTimer;
int g_swapInterval = SWAP_INTERVAL;
int g_wireframeMode = 0;
int g_texturelessMode = 0;
int g_emulatorPaused = 0;
@ -276,53 +279,12 @@ static int Emulator_InitialiseGLEW()
return TRUE;
}
#ifdef _WIN32
LARGE_INTEGER g_performanceFrequency;
LARGE_INTEGER g_clockStart;
#else
timeval g_timeStart;
#endif // _WIN32
void Emulator_InitHPCTimer()
{
#ifdef _WIN32
QueryPerformanceFrequency(&g_performanceFrequency);
#else
gettimeofday(&g_timeStart, NULL);
#endif // _WIN32
}
double Emulator_GetHPCTime(int reset = 0)
{
#ifdef _WIN32
LARGE_INTEGER curr;
QueryPerformanceCounter( &curr);
double value = double(curr.QuadPart - g_clockStart.QuadPart) / double(g_performanceFrequency.QuadPart);
if (reset)
g_clockStart = curr;
#else
timeval curr;
gettimeofday(&curr, NULL);
double value = (float(curr.tv_sec - g_timeStart.tv_sec) + 0.000001f * float(curr.tv_usec - g_timeStart.tv_usec));
if (reset)
g_timeStart = curr;
#endif // _WIN32
return value;
}
SDL_Thread* g_vblankThread = NULL;
SDL_mutex* g_vblankMutex = NULL;
volatile bool g_stopVblank = false;
volatile int g_vblanksDone = 0;
volatile int g_lastVblankCnt = 0;
timerCtx_t g_vblankTimer;
extern void(*vsync_callback)(void);
@ -330,6 +292,7 @@ int Emulator_DoVSyncCallback()
{
SDL_LockMutex(g_vblankMutex);
#if 1
int vblcnt = g_vblanksDone - g_lastVblankCnt;
static bool canDoCb = true;
@ -348,7 +311,7 @@ int Emulator_DoVSyncCallback()
canDoCb = true;
}
#endif
g_lastVblankCnt = g_vblanksDone;
if (g_swapInterval == 0)
@ -359,7 +322,6 @@ int Emulator_DoVSyncCallback()
g_lastVblankCnt += 1;
}
SDL_UnlockMutex(g_vblankMutex);
return g_vblanksDone;
@ -367,20 +329,25 @@ int Emulator_DoVSyncCallback()
int vblankThreadMain(void* data)
{
double vblankTime = Emulator_GetHPCTime();
Emulator_InitHPCTimer(&g_vblankTimer);
do
{
double delta = vblankTime + FIXED_TIME_STEP - Emulator_GetHPCTime();
if (delta < 0)
double delta = Emulator_GetHPCTime(&g_vblankTimer, 0);
if (delta > FIXED_TIME_STEP)
{
// do vblank events
SDL_LockMutex(g_vblankMutex);
g_vblanksDone++;
vblankTime = Emulator_GetHPCTime();// SDL_GetTicks();
Emulator_GetHPCTime(&g_vblankTimer, 1);
#if 0
if(vsync_callback)
vsync_callback();
#endif
SDL_UnlockMutex(g_vblankMutex);
}
} while (!g_stopVblank);
@ -390,7 +357,7 @@ int vblankThreadMain(void* data)
static int Emulator_InitialiseCore()
{
Emulator_InitHPCTimer();
Emulator_InitHPCTimer(&g_swapTimer);
g_vblankThread = SDL_CreateThread(vblankThreadMain, "vbl", NULL);
@ -407,10 +374,6 @@ static int Emulator_InitialiseCore()
return FALSE;
}
g_swapTime = Emulator_GetHPCTime();
return TRUE;
}
@ -950,18 +913,20 @@ GLint u_Projection3D;
" fragColor.xyz += vec3(dither[dc.x][dc.y] * v_texcoord.w);\n"
#define GPU_SAMPLE_TEXTURE_4BIT_FUNC\
" // returns 16 bit colour\n"\
" float samplePSX(vec2 tc){\n"\
" vec2 uv = (tc * vec2(0.25, 1.0) + v_page_clut.xy) * vec2(1.0 / 1024.0, 1.0 / 512.0);\n"\
" vec2 comp = VRAM(uv);\n"\
" int index = int(fract(tc.x / 4.0) * 4.0);\n"\
" float v = comp[index / 2] * (255.0 / 16.0);\n"\
" float f = floor(v);\n"\
" vec2 c = vec2( (v - f) * 16.0, f );\n"\
" vec2 clut_pos = v_page_clut.zw;\n"\
" clut_pos.x += mix(c[0], c[1], fract(float(index) / 2.0) * 2.0) / 1024.0;\n"\
" return packRG(VRAM(clut_pos));\n"\
" }\n"
" // returns 16 bit colour\n"\
" float samplePSX(vec2 tc){\n"\
" vec2 uv = (tc * vec2(0.25, 1.0) + v_page_clut.xy) * vec2(1.0 / 1024.0, 1.0 / 512.0);\n"\
" vec2 comp = VRAM(uv);\n"\
" int index = int(fract(tc.x / 4.0 + 0.0001) * 4.0);\n"\
" float v = comp[index / 2] * (255.0 / 16.0);\n"\
" float f = floor(v);\n"\
" vec2 c = vec2( (v - f) * 16.0, f );\n"\
" vec2 clut_pos = v_page_clut.zw;\n"\
" clut_pos.x += mix(c[0], c[1], mod(index, 2)) / 1024.0;\n"\
" clut_pos.x += 0.0001;\n"\
" clut_pos.y += 0.0001;\n"\
" return packRG(VRAM(clut_pos));\n"\
" }\n"
#define GPU_SAMPLE_TEXTURE_8BIT_FUNC\
" // returns 16 bit colour\n"\
@ -1379,10 +1344,11 @@ void Emulator_Perspective3D(const float fov, const float width, const float heig
void Emulator_SetupClipMode(const RECT16& rect)
{
bool enabled = rect.x - activeDispEnv.disp.x > 0 ||
// [A] isinterlaced dirty hack for widescreen
bool enabled = activeDispEnv.isinter || (rect.x - activeDispEnv.disp.x > 0 ||
rect.y - activeDispEnv.disp.y > 0 ||
rect.w < activeDispEnv.disp.w - 1 ||
rect.h < activeDispEnv.disp.h - 1;
rect.h < activeDispEnv.disp.h - 1);
float psxScreenW = activeDispEnv.disp.w;
float psxScreenH = activeDispEnv.disp.h;
@ -1479,6 +1445,7 @@ extern void Emulator_Clear(int x, int y, int w, int h, unsigned char r, unsigned
{
// TODO clear rect if it's necessary
#if defined(OGL) || defined(OGLES)
glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#endif
@ -1715,7 +1682,6 @@ void Emulator_DoPollEvent()
}
bool begin_scene_flag = false;
bool vbo_was_dirty_flag = false;
bool Emulator_BeginScene()
{
@ -1911,16 +1877,15 @@ void Emulator_WaitForTimestep(int count)
// additional wait for swap
if (g_swapInterval > 0)
{
double curTime;
double waitTime = FIXED_TIME_STEP * count;
double delta;
do
{
SDL_Delay(0); // yield
curTime = Emulator_GetHPCTime();
} while (curTime - g_swapTime < waitTime);
}
delta = Emulator_GetHPCTime(&g_swapTimer, 0);
} while (delta < FIXED_TIME_STEP * count);
g_swapTime = Emulator_GetHPCTime();
Emulator_GetHPCTime(&g_swapTimer, 1);
}
}
void Emulator_EndScene()
@ -1928,9 +1893,6 @@ void Emulator_EndScene()
if (!begin_scene_flag)
return;
if (!vbo_was_dirty_flag)
return;
assert(begin_scene_flag);
if (g_wireframeMode)
@ -1943,7 +1905,6 @@ void Emulator_EndScene()
#endif
begin_scene_flag = false;
vbo_was_dirty_flag = false;
Emulator_SwapWindow();
}
@ -2095,8 +2056,6 @@ void Emulator_UpdateVertexBuffer(const Vertex *vertices, int num_vertices)
#else
#error
#endif
vbo_was_dirty_flag = true;
}
void Emulator_DrawTriangles(int start_vertex, int triangles)

View File

@ -0,0 +1,37 @@
#include <windows.h>
#include "EMULATOR_TIMER.H"
void Emulator_InitHPCTimer(timerCtx_t* timer)
{
#ifdef _WIN32
QueryPerformanceFrequency(&timer->performanceFrequency);
#else
gettimeofday(&timer.timeStart, NULL);
#endif // _WIN32
}
double Emulator_GetHPCTime(timerCtx_t* timer, int reset)
{
#ifdef _WIN32
LARGE_INTEGER curr;
QueryPerformanceCounter( &curr);
double value = double(curr.QuadPart - timer->clockStart.QuadPart) / double(timer->performanceFrequency.QuadPart);
if (reset)
timer->clockStart = curr;
#else
timeval curr;
gettimeofday(&curr, NULL);
double value = (float(curr.tv_sec - timer->timeStart.tv_sec) + 0.000001f * float(curr.tv_usec - timer.timeStart->tv_usec));
if (reset)
timer->timeStart = curr;
#endif // _WIN32
return value;
}

View File

@ -0,0 +1,24 @@
#ifndef EMULATOR_TIMER_H
#define EMULATOR_TIMER_H
#ifdef _WIN32
#include <profileapi.h>
#else
#include <sys/time.h>
#endif
struct timerCtx_t
{
#ifdef _WIN32
LARGE_INTEGER performanceFrequency;
LARGE_INTEGER clockStart;
#else
timeval timeStart;
#endif // _WIN32
};
extern void Emulator_InitHPCTimer(timerCtx_t* timer);
extern double Emulator_GetHPCTime(timerCtx_t* timer, int reset = 0);
#endif // EMULATOR_TIMER_H

View File

@ -246,7 +246,6 @@ int DrawSync(int mode)
drawsync_callback();
}
return 0;
}
@ -453,6 +452,8 @@ DRAWENV* SetDefDrawEnv(DRAWENV* env, int x, int y, int w, int h)//(F)
env->clip.x = x;
env->clip.y = y;
env->clip.w = w;
env->clip.h = h;
env->tw.x = 0;
env->tw.y = 0;
env->tw.w = 0;
@ -461,7 +462,6 @@ DRAWENV* SetDefDrawEnv(DRAWENV* env, int x, int y, int w, int h)//(F)
env->g0 = 0;
env->b0 = 0;
env->dtd = 1;
env->clip.h = h;
if (GetVideoMode() == 0)
{

View File

@ -7,17 +7,21 @@
SDL_GameController* padHandle[MAX_CONTROLLERS];
unsigned char* padData[MAX_CONTROLLERS];
const unsigned char* keyboardState;
const unsigned char* keyboardState = NULL;
void PadInitDirect(unsigned char* pad1, unsigned char* pad2)
{
// do not init second time!
if (keyboardState != NULL)
return;
if (pad1 != NULL)
{
padData[0] = pad1;
PADRAW* pad = (PADRAW*)pad1;
pad->id = 0x41; // always init first controller
pad->id = 0;
pad->analog[0] = 128;
pad->analog[1] = 128;
pad->analog[2] = 128;
@ -361,10 +365,10 @@ void InternalPadUpdates()
pad->status = 0; // PadStateStable?
// switch to analog state
if(pad->analog[0] != 127 ||
pad->analog[1] != 127 ||
pad->analog[2] != 127 ||
pad->analog[3] != 127 ||
if((pad->analog[0] == 255 ||
pad->analog[1] == 255 ||
pad->analog[2] == 255 ||
pad->analog[3] == 255) &&
pad->id == 0x41)
{
eprintf("Switched controller type to ANALOG\n");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1229,14 +1229,14 @@ void DrawCarWheels(CAR_DATA *cp, MATRIX *RearMatrix, VECTOR *pos, int zclip)
VertPtr[11].vz = -FW2z;
VertPtr[12].vz = -FW2z;
VertPtr[0x17].vz = 0;
VertPtr[0x16].vz = 0;
VertPtr[0x15].vy = 0;
VertPtr[0x14].vy = 0;
VertPtr[0x13].vy = 0;
VertPtr[0x12].vy = 0;
VertPtr[0x11].vz = 0;
VertPtr[0x10].vz = 0;
VertPtr[23].vz = 0;
VertPtr[22].vz = 0;
VertPtr[21].vy = 0;
VertPtr[20].vy = 0;
VertPtr[19].vy = 0;
VertPtr[18].vy = 0;
VertPtr[17].vz = 0;
VertPtr[16].vz = 0;
VertPtr[23].vy = wheelSize;
VertPtr[22].vy = wheelSize;
@ -1273,14 +1273,14 @@ void DrawCarWheels(CAR_DATA *cp, MATRIX *RearMatrix, VECTOR *pos, int zclip)
VertPtr[11].vz = -BW2z;
VertPtr[12].vz = -BW2z;
VertPtr[0x17].vz = 0;
VertPtr[0x16].vz = 0;
VertPtr[0x15].vy = 0;
VertPtr[0x14].vy = 0;
VertPtr[0x13].vy = 0;
VertPtr[0x12].vy = 0;
VertPtr[0x11].vz = 0;
VertPtr[0x10].vz = 0;
VertPtr[23].vz = 0;
VertPtr[22].vz = 0;
VertPtr[21].vy = 0;
VertPtr[20].vy = 0;
VertPtr[19].vy = 0;
VertPtr[18].vy = 0;
VertPtr[17].vz = 0;
VertPtr[16].vz = 0;
VertPtr[23].vy = wheelSize;
VertPtr[22].vy = wheelSize;
@ -1294,7 +1294,7 @@ void DrawCarWheels(CAR_DATA *cp, MATRIX *RearMatrix, VECTOR *pos, int zclip)
SteerMatrix.m[0][0] = rcossin_tbl[(cp->wheel_angle & 0xfff) * 2 + 1];
SteerMatrix.m[0][2] = rcossin_tbl[(cp->wheel_angle & 0xfff) * 2];
SteerMatrix.m[1][1] = 4096;
SteerMatrix.m[1][1] = ONE;
SteerMatrix.m[2][1] = 0;
SteerMatrix.m[1][2] = 0;
SteerMatrix.m[1][0] = 0;

View File

@ -90,6 +90,10 @@ PACKED_CELL_OBJECT * GetFirstPackedCop(int cellx, int cellz, CELL_ITERATOR *pci,
if (NumPlayers == 2)
#endif // else do this check always
{
// [A] don't draw loading region
if (loading_region[index] != -1)
return NULL;
if (RoadMapRegions[index] != (cellx / MAP_REGION_SIZE) + (cellz / MAP_REGION_SIZE) * (cells_across / MAP_REGION_SIZE))
return NULL;
}

View File

@ -3260,6 +3260,7 @@ int PingInCivCar(int minPingInDist)
int i;
int oldCookieCount;
uint retDistSq;
unsigned char* slot;
//straight = NULL;
//curve = NULL;
@ -3286,12 +3287,12 @@ int PingInCivCar(int minPingInDist)
tryPingInParkedCars = 1;
}
playerNum = 0;
if (NumPlayers == 2)
playerNum = CameraCnt & 1;
else
playerNum = 0;
if ((MissionHeader->type & 4U) != 0)
if (MissionHeader->type & 0x4)
{
PingOutCivsOnly = 1;
return 0;
@ -3317,6 +3318,27 @@ int PingInCivCar(int minPingInDist)
newCar = NULL;
// find a free slot
carCnt = car_data;
slot = reservedSlots;
do {
if (carCnt->controlType == CONTROL_TYPE_NONE && *slot == 0)
{
newCar = carCnt;
break;
}
carCnt++;
slot++;
} while (carCnt < &car_data[MAX_TRAFFIC_CARS]);
if (newCar == NULL)
{
PingOutCivsOnly = 1;
return 0;
}
ClearMem((char*)&civDat, sizeof(civDat));
baseLoc.vx = player[playerNum].spoolXZ->vx;
@ -3334,8 +3356,8 @@ int PingInCivCar(int minPingInDist)
if (newCarId == -1)
return 0;
if (newCarId > MAX_CARS - 1)
return 0;
//if (newCarId > MAX_CARS - 1)
// return 0;
newCar = &car_data[newCarId];
@ -3369,34 +3391,12 @@ int PingInCivCar(int minPingInDist)
// randomized pings
int angle;
int dx, dz;
unsigned char* slot;
const int maxCookies = requestCopCar ? 55 : 43;
if (requestCopCar == 0 && cookieCount > 43)
cookieCount -= 25;
// find a free slot
carCnt = car_data;
slot = reservedSlots;
do {
if (carCnt->controlType == CONTROL_TYPE_NONE && *slot == 0)
{
newCar = carCnt;
break;
}
carCnt++;
slot++;
} while (carCnt < &car_data[MAX_TRAFFIC_CARS]);
if (newCar == NULL)
{
PingOutCivsOnly = 1;
return 0;
}
oldCookieCount = cookieCount;
do {
@ -3406,7 +3406,9 @@ int PingInCivCar(int minPingInDist)
cookieCount = 0;
if (cookieCount == oldCookieCount)
{
break;
}
if (requestCopCar == 0)
{
@ -3438,9 +3440,9 @@ int PingInCivCar(int minPingInDist)
}
{
int numPossibleLanes;
int numLanes;
int allowedToPark;
volatile int numPossibleLanes;
volatile int numLanes;
volatile int allowedToPark;
if (ROAD_LANES_COUNT(&roadInfo) == 0) // BAD ROAD
{
@ -3779,7 +3781,7 @@ int PingInCivCar(int minPingInDist)
PingOutCivsOnly = 0;
// [A] REDRIVER2 always stores pings
StorePingInfo(cookieCount, newCar->id);
StorePingInfo(cookieCount, newCar->id); // + 1 since car with id 1 is not getting pinged in chases
return newCar->id + 1;
}

View File

@ -19,10 +19,11 @@
#include "PAUSE.H"
#include "OVERMAP.H"
#include "DIRECTOR.H"
#include "XAPLAY.H"
#include "LIBETC.H"
#include "STRINGS.H"
#include "XAPLAY.H"
#include "RAND.H"
int gSkipInGameCutscene = 0;
@ -56,6 +57,52 @@ static int CutsceneCameraOffset = 0;
#ifndef PSX
char* gCustomCutsceneBuffer;
char gUserReplayFolderList[MAX_USER_REPLAYS][48];
int gNumUserChases = 0;
int gUserChaseLoaded = -1;
// [A] user replay folders initialization
void InitUserReplays(const char* str)
{
int quit;
char* ptr;
char* strStart;
gNumUserChases = 0;
if (!str)
return;
ptr = (char*)str;
strStart = NULL;
memset(gUserReplayFolderList, 0, sizeof(gUserReplayFolderList));
quit = 0;
while(true)
{
if (strStart == NULL)
strStart = ptr;
// if we're encountered string end go on
if(*ptr == ',' || *ptr == ' ' || *ptr == '\0')
{
if (*ptr == '\0')
quit = 1;
*ptr = '\0';
strcpy(gUserReplayFolderList[gNumUserChases++], strStart);
strStart = NULL;
}
ptr++;
if (quit)
break;
}
}
#endif
// decompiled code
@ -103,6 +150,10 @@ void InitInGameCutsceneVariables(void)
gSkipInGameCutscene = 0;
#ifndef PSX
gUserChaseLoaded = -1;
#endif
FreeCutsceneBuffer();
}
@ -255,7 +306,21 @@ void DrawInGameCutscene(void)
#endif
if (gInGameCutsceneActive == 0 && gInGameCutsceneDelay == 0)
{
#ifndef PSX
if(gInGameChaseActive && gUserChaseLoaded != -1 && (CameraCnt - frameStart) < 200)
{
// [A] print user chaser name on screen
char tempStr[80];
sprintf(tempStr, "Getaway is %s", gUserReplayFolderList[gUserChaseLoaded]);
SetTextColour(128, 128, 64);
PrintString(tempStr, 16, 230);
}
#endif
return;
}
tile = (TILE *)current->primptr;
SetTile(tile);
@ -1281,7 +1346,73 @@ int LoadCutsceneToReplayBuffer(int residentCutscene)
return 1;
}
#ifndef PSX
int LoadCutsceneFile(char *filename, int subindex, int userId = -1)
{
gUserChaseLoaded = userId;
int size = LoadfileSeg(filename, gCustomCutsceneBuffer, 0, 0xffff);
if (size != 0)
{
// load into custom buffer
printInfo("Custom chase '%s' loaded\n", filename);
CutsceneBuffer.residentCutscenes[CutsceneBuffer.numResident] = subindex;
CutsceneBuffer.residentPointers[CutsceneBuffer.numResident] = gCustomCutsceneBuffer;
CutsceneBuffer.numResident++;
gCustomCutsceneBuffer += size;
return 1;
}
return 0;
}
int LoadUserCutscene(int subindex, int userId = -1)
{
char customFilename[64];
int userIndex = -1;
if (userId >= 0 && userId < gNumUserChases)
{
// get user chase instantly
sprintf(customFilename, "REPLAYS\\User\\%s\\CUT%d_%d.D2RP", gUserReplayFolderList[userId], gCurrentMissionNumber, subindex);
if (FileExists(customFilename))
userIndex = userId;
}
// if still no valid user replay from input
if (userIndex == -1)
{
// find first valid user replay
for (int i = 0; i < gNumUserChases; i++)
{
sprintf(customFilename, "REPLAYS\\User\\%s\\CUT%d_%d.D2RP", gUserReplayFolderList[i], gCurrentMissionNumber, subindex);
if (FileExists(customFilename))
{
userIndex = i;
break;
}
}
// if it doesn't exist under someone's name, get an anonymous one
if (userIndex == -1)
{
sprintf(customFilename, "REPLAYS\\User\\CUT%d_%d.D2RP", gCurrentMissionNumber, subindex);
// and if it still doesn't exist, let the game handle it
if (!FileExists(customFilename))
return 0;
}
}
return LoadCutsceneFile(customFilename, subindex, userIndex);
}
#endif
// decompiled code
// original method signature:
@ -1323,7 +1454,6 @@ int LoadCutsceneToBuffer(int subindex)
CUTSCENE_HEADER header;
char filename[64];
char customFilename[64];
if (gCurrentMissionNumber < 21)
sprintf(filename, "REPLAYS\\CUT%d.R", gCurrentMissionNumber);
@ -1332,6 +1462,23 @@ int LoadCutsceneToBuffer(int subindex)
printInfo("Loading cutscene '%s' (%d)\n", filename, subindex);
#ifndef PSX
int userId = -1;
// [A] REDRIVER2 PC - custom cutcenes or chases for debugging
if (gNumUserChases)
{
userId = rand() % (gNumUserChases + 1);
// if random decides to have no user chase - get og or replacement one
if (userId == gNumUserChases)
userId = -1;
}
if (LoadUserCutscene(subindex, userId))
return 1;
#endif
if (FileExists(filename))
{
LoadfileSeg(filename, (char *)&header, 0, sizeof(CUTSCENE_HEADER));
@ -1340,25 +1487,7 @@ int LoadCutsceneToBuffer(int subindex)
{
offset = header.data[subindex].offset * 4;
size = header.data[subindex].size;
#ifndef PSX
// [A] REDRIVER2 PC - custom cutcenes or chases for debugging
sprintf(customFilename, "REPLAYS\\CUT%d\\%d.D2RP", gCurrentMissionNumber, subindex);
if (FileExists(customFilename))
{
printInfo("Custom cutscene replay file loaded\n");
size = LoadfileSeg(customFilename, gCustomCutsceneBuffer, 0, 0xffff);
// load into custom buffer
CutsceneBuffer.residentCutscenes[CutsceneBuffer.numResident] = subindex;
CutsceneBuffer.residentPointers[CutsceneBuffer.numResident] = gCustomCutsceneBuffer;
CutsceneBuffer.numResident++;
gCustomCutsceneBuffer += size;
return 1;
}
#endif
if (CutsceneBuffer.bytesFree < size)
{
// load into lead/path AI buffer

View File

@ -1,6 +1,16 @@
#ifndef CUTSCENE_H
#define CUTSCENE_H
#ifndef PSX
#define MAX_USER_REPLAYS 16
extern char gUserReplayFolderList[MAX_USER_REPLAYS][48];
extern int gNumUserChases;
extern void InitUserReplays(const char* str);
#endif
extern CUTSCENE_BUFFER CutsceneBuffer;
extern int gSkipInGameCutscene;

View File

@ -3009,6 +3009,10 @@ int InvalidCamera(int car_num)
int dz;
int numEventModels;
// [A] bug fix of invalid player camera
if (CameraCnt < 3)
return 0;
// check if camera is not too far
if (cameraview != 2)
{

View File

@ -264,10 +264,10 @@ void HandleDrivingGames(void)
gPlayerScore.items++;
else
gPlayerScore.P2items++;
}
gTrailblazerConeIndex += i + 1;
gTrailblazerPrevConeDelay = 10;
gTrailblazerConeIndex += i + 1;
gTrailblazerPrevConeDelay = 10;
}
// reset side
for(j = 0; j < 2; j++)

View File

@ -6,6 +6,7 @@
#include "SYSTEM.H"
#include "PRES.H"
#include "PAUSE.H"
#include "SOUND.H"
#undef v0
@ -171,7 +172,7 @@ void FadeInHiresScreen(char *filename)
DrawSync(0);
setRECT16(&rect, 640, 0, 320, 511);
LoadImage(&rect, (u_long*)&_overlay_buffer[512]);
LoadImage(&rect, (u_long*)&_overlay_buffer[524]);
DrawSync(0);
SetDispMask(1);
@ -199,8 +200,6 @@ void FadeInHiresScreen(char *filename)
setRGB0(prim, 128, 128, 128);
}
// UNCERTAIN CODE
// LEARN TO DECOMPILE MIPS FIRST
addPrim(&ot, prim);
addPrim(&ot, poly);
poly++; prim++;
@ -218,6 +217,158 @@ void FadeInHiresScreen(char *filename)
DrawSync(0);
}
#define GALLERY_IMAGES 24
// [A] displays bonus gallery
void ShowBonusGallery()
{
char filename[64];
int currentImage;
DISPENV disp;
DRAWENV draw;
SPRT prims[6];
POLY_FT3 nulls[6];
RECT16 rect;
OTTYPE ot;
POLY_FT3 *poly;
SPRT *prim;
POLYCOORD *pc;
DrawSync(0);
VSync(0);
SetDispMask(0);
ResetGraph(3);
setRECT16(&rect, 0, 0, 512, 512);
ClearImage2(&rect, 0, 0, 0);
DrawSync(0);
setRECT16(&rect, 512, 0, 512, 512);
ClearImage2(&rect, 0, 0, 0);
DrawSync(0);
poly = nulls;
pc = polycoords;
prim = prims;
// prepare polygons
for(int i = 0; i < 6; i++)
{
// set primitive
setSprt(prim);
setUV0(prim, 0, 0);
setClut(prim, 640, 511);
setXY0(prim, pc->x, pc->y);
setWH(prim, pc->w, pc->h);
// set poly
setPolyFT3(poly);
setXY3(poly, -1,-1,-1,-1,-1,-1);
setTPage(poly, 1, 0, pc->u, pc->v);
prim++;
poly++;
pc++;
}
SetupDefDrawEnv(&draw, 0, 0, 640, 512);
SetupDefDispEnv(&disp, 0, 0, 640, 512);
VSync(0);
PutDispEnv(&disp);
PutDrawEnv(&draw);
currentImage = 0;
// draw image cycle
while(currentImage <= GALLERY_IMAGES)
{
if(currentImage == 0)
sprintf(filename, "GFX\\GAL\\INTRO.TIM");
else
sprintf(filename, "GFX\\GAL\\IMG%d.TIM", currentImage-1);
LoadfileSeg(filename, _other_buffer, 20, 0x4ff80);
LoadClut((u_long*)_other_buffer, 640, 511);
DrawSync(0);
setRECT16(&rect, 640, 0, 320, 511);
LoadImage(&rect, (u_long*)&_other_buffer[524]);
DrawSync(0);
SetDispMask(1);
// now draw image
DrawSync(0);
VSync(0);
PutDispEnv(&disp);
PutDrawEnv(&draw);
ClearOTagR((u_long*)&ot, 1);
poly = nulls;
prim = prims;
for (int i = 0; i < 6; i++)
{
setRGB0(prim, 128, 128, 128);
addPrim(&ot, prim);
addPrim(&ot, poly);
poly++; prim++;
}
DrawOTag((u_long*)&ot);
#ifndef PSX
Emulator_EndScene();
#endif
// wait for user input
do {
ReadControllers();
VSync(-1);
if(Pads[0].dirnew & 0x8000)
{
currentImage--;
if (currentImage < 0)
{
FESound(1);
currentImage = 0;
}
else
{
FESound(3);
break;
}
}
if(Pads[0].dirnew & 0x2000)
{
FESound(3);
currentImage++;
break;
}
if(Pads[0].dirnew & 0x10)
{
FESound(0);
currentImage = GALLERY_IMAGES+1; // quit
break;
}
} while (true);
}
DrawSync(0);
}
// decompiled code
@ -395,8 +546,6 @@ void SetupDefDrawEnv(DRAWENV *env, int x, int y, int w, int h)
// [D] [T]
void SetupDefDispEnv(DISPENV *env, int x, int y, int w, int h)
{
short framey;
if (h < 257)
{
SetDefDispEnv(env, x, y, w, 256);

View File

@ -16,5 +16,6 @@ extern void SetPleaseWait(char *buffer); // 0x000448CC
extern void CheckForCorrectDisc(int disc); // 0x00044A40
extern void ShowBonusGallery();
#endif

View File

@ -33,28 +33,34 @@
// TODO: put more meaning into those arrays
int ElTrainData[83] = {
6, // train count (WRONG)
6, // train count
// train 1 (n 1)
80, 130, 32768, 336284, -220364, 283420, PATH_NODE_STATION,
80, 130, 0x8000, // speed 1, 2, start direction
336284, -220364, 283420, PATH_NODE_STATION,
-204500, -158924, 247580, -123084, 188624, -158924, 73520, -138444, 17200, -124148, -39120, PATH_NODE_STATION,
-109276, -82131, -80103, -17628, -203568, -124712, -39728, -265000, 129620, -386012, PATH_NODE_WRAP,
// train 2 (n 31)
80, 130, 0, -158928, 189219, -123684, 246995, PATH_NODE_CYCLE,
80, 130, 0,
-158928, 189219, -123684, 246995, PATH_NODE_CYCLE,
// train 3 (n 39)
0, 90, 32768, 188402, -425768, 354291, PATH_NODE_WRAP,
0, 90, 0x8000,
188402, -425768, 354291, PATH_NODE_WRAP,
// train 4 (n 46)
0, 90, 32768, 354291, -425168, 188402, PATH_NODE_WRAP,
0, 90, 0x8000,
354291, -425168, 188402, PATH_NODE_WRAP,
// train 4 (n 53)
60, 110, 0, -386012, 130215, -264404, -39132, -124688, 16619, -139048, 72943, -159520, 282863, PATH_NODE_STATION,
// train 5 (n 53)
60, 110, 0,
-386012, 130215, -264404, -39132, -124688, 16619, -139048, 72943, -159520, 282863, PATH_NODE_STATION,
-204991, -220964, 336284, PATH_NODE_WRAP,
// train 5 (n 71)
70, 120, 0, -82719, -39712, PATH_NODE_STATION,
// train 6 (n 71)
70, 120, 0,
-82719, -39712, PATH_NODE_STATION,
-115487, -124120, -202968,-18216, -80683, PATH_NODE_CYCLE
};
@ -79,15 +85,42 @@ int HavanaMiniData[4] = {
};
int LiftingBridges[55] = {
8, -182784, -175616, -168448,
8, // bridge count
// 1
-182784, -175616, -168448,
7, -227328, -162304, -141824, -121344, -100864, -80384, -59904,
256, -312832, -305664, -298496,
1, 324096, -311808, -304640, -297472,
1, 247296, -256512, -249344, -242176,
1, 247296, -262656, -255488, -248320,
1, 324096, 32768, 170496, 177664, 184832,
1, -271360, -12800, -5632, 1536,
5, -162304, -102912, -82432, -61952, -39936, -6656, 512, 7680,
0x100, // goose island start
// 2
-312832, -305664, -298496,
1, 324096,
// 3
-311808, -304640, -297472,
1, 247296,
// 4
-256512, -249344, -242176,
1, 247296,
// 5
-262656, -255488, -248320,
1, 324096,
0x8000, // goose island end
// 6
170496, 177664, 184832,
1, -271360,
// 7
-12800, -5632, 1536,
5, -162304, -102912, -82432, -61952, -39936,
// 8
-6656, 512, 7680,
3, 4137, 27648, 128000
};
@ -1157,16 +1190,17 @@ void SetUpEvents(int full)
int timeOffset;
cameraEventsActive = 1;
if (p[0] == 0x8000)
{
direction = true;
p++;
}
else if (p[0] == 0x100)
// goose island bridges start/end?
if (p[0] == 0x100)
{
firstMissionEvent = &event[cEvents];
p++;
}
else if (p[0] == 0x8000)
{
direction = true;
p++;
}
evt = &event[cEvents];
@ -1195,7 +1229,7 @@ void SetUpEvents(int full)
{
if (direction)
{
evt[i].flags = 1;
evt[i].flags = 0x1;
evt[i].position.vx = *p;
}
else
@ -2313,7 +2347,7 @@ void StepPathEvent(EVENT* ev)
centre.z = turn[1] - 2048;
if (ev->flags & 0x400)
speed = *ev->data;
speed = ev->data[0];
offset.x = (ev->position.vz - centre.z) * speed / 2048;
offset.z = (centre.x - ev->position.vx) * speed / 2048;

View File

@ -633,7 +633,7 @@ void LoadLevelSFX(int missionNum)
LoadSoundBankDynamic(NULL, 1, 0);
LoadSoundBankDynamic(NULL, 3, 3);
if (gCurrentMissionNumber - 39U < 2)
if (missionNum - 39U < 2 || missionNum >= 400 && missionNum <= 404)
LoadBankFromLump(SOUND_BANK_CARS, MapCarIndexToBank(4));
else
LoadBankFromLump(SOUND_BANK_CARS, SpecialVehicleKludge(0));
@ -645,17 +645,17 @@ void LoadLevelSFX(int missionNum)
LoadBankFromLump(SOUND_BANK_CARS, SpecialVehicleKludge(1));
}
if (missionNum - 50U < 16)
if (missionNum - 50U < 16 || missionNum >= 400)
{
LoadBankFromLump(SOUND_BANK_CARS, SpecialVehicleKludge(2));
}
// disable cop speech on specific missions (gangs)
// and set cop model (car sound bank)
if (gCurrentMissionNumber == 7 || gCurrentMissionNumber == 9 ||
gCurrentMissionNumber == 11 || gCurrentMissionNumber == 20 ||
gCurrentMissionNumber == 26 || gCurrentMissionNumber == 31 ||
gCurrentMissionNumber == 33 || gCurrentMissionNumber == 40)
if (missionNum == 7 || missionNum == 9 ||
missionNum == 11 || missionNum == 20 ||
missionNum == 26 || missionNum == 31 ||
missionNum == 33 || missionNum == 40)
{
gDoCopSpeech = 0;
@ -3630,7 +3630,18 @@ unsigned int horn_time;
// [D] [T]
void InitLeadHorn(void)
{
horn_time = 0;
// [A] disable horns in some missions
switch (gCurrentMissionNumber)
{
case 4: // Tailing the drop
case 10: // Follow up the lead
case 18: // Tail Jericho
case 26: // Steal the ambulance
horn_time = 0xFFFFFFFF;
break;
default:
horn_time = 0;
}
}
@ -3665,6 +3676,10 @@ void LeadHorn(CAR_DATA* cp)
int carBank;
int dx,dz;
// [A] disabled horn in those missions
if (horn_time == 0xFFFFFFFF)
return;
// [A] do not horn if too far from camera
dx = cp->hd.where.t[0] - camera_position.vx >> 8;
dz = cp->hd.where.t[2] - camera_position.vz >> 8;

View File

@ -8,9 +8,11 @@
#include "DRAW.H"
#include "DEBRIS.H"
#include "SYSTEM.H"
#include "../ASM/ASMTEST.H"
#include "INLINE_C.H"
#include "RAND.H"
EXOBJECT explosion[MAX_EXPLOSION_OBJECTS];
@ -51,7 +53,7 @@ MATRIX SS = { 0 };
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D]
// [D] [T]
void InitExObjects(void)
{
int i;
@ -87,7 +89,7 @@ void InitExObjects(void)
/* end block 3 */
// End Line: 264
// [D]
// [D] [T]
void AddExplosion(VECTOR pos, int type)
{
EXOBJECT *newExplosion;
@ -96,13 +98,10 @@ void AddExplosion(VECTOR pos, int type)
i = 0;
newExplosion = explosion;
while (newExplosion->time != -1)
while (newExplosion->time != -1 && i < MAX_EXPLOSION_OBJECTS)
{
i++;
newExplosion++;
if (i > 4)
return;
i++;
}
newExplosion->time = 0;
@ -111,21 +110,21 @@ void AddExplosion(VECTOR pos, int type)
if (type == LITTLE_BANG)
{
newExplosion->speed = 0xc0;
newExplosion->hscale = 0x400;
newExplosion->rscale = 0x400;
newExplosion->speed = 192;
newExplosion->hscale = 1024;
newExplosion->rscale = 1024;
}
else if (type == BIG_BANG)
{
newExplosion->speed = 0x80;
newExplosion->hscale = 0x1000;
newExplosion->rscale = 0x1000;
newExplosion->speed = 128;
newExplosion->hscale = 4096;
newExplosion->rscale = 4096;
}
else if (type == HEY_MOMMA)
{
newExplosion->speed = 0x40;
newExplosion->hscale = 0x4000;
newExplosion->rscale = 0x4000;
newExplosion->speed = 64;
newExplosion->hscale = 16384;
newExplosion->rscale = 16384;
}
}
@ -175,13 +174,17 @@ void AddExplosion(VECTOR pos, int type)
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D]
// [D] [T]
void HandleExplosion(void)
{
VECTOR drift;
VECTOR smokePos;
CAR_DATA *cp;
EXOBJECT *exp;
int i;
GetSmokeDrift(&drift); // [A]
if (pauseflag != 0)
return;
@ -204,7 +207,7 @@ void HandleExplosion(void)
i++;
exp++;
};
}
i = 0;
@ -214,7 +217,17 @@ void HandleExplosion(void)
if (exp->time != -1)
{
if (exp->time == 0)
{
ExplosionSound(&exp->pos, exp->type);
}
// [A] add smoke to explosions
if(exp->time > 1500 && (CameraCnt & 0x3) == 0)
{
smokePos = exp->pos;
smokePos.vy -= 120;
Setup_Smoke(&smokePos, 100 + (rand() & 15) * 20, 900, SMOKE_BLACK, 0, &drift, 0);
}
exp->time += exp->speed;
@ -224,7 +237,7 @@ void HandleExplosion(void)
exp++;
i++;
};
}
}
@ -274,7 +287,7 @@ void HandleExplosion(void)
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D]
// [D] [T]
void DrawAllExplosions(void)
{
int i;
@ -285,7 +298,7 @@ void DrawAllExplosions(void)
DrawExplosion(explosion[i].time, explosion[i].pos, explosion[i].hscale, explosion[i].rscale);
i++;
};
}
}
@ -327,85 +340,86 @@ void DrawAllExplosions(void)
SVECTOR globemesh[54];
// [D]
// [D] [T]
void initExplosion(void)
{
short sVar1;
short sVar2;
uint uVar3;
SVECTOR *pSVar4;
uint uVar5;
int iVar6;
uint uVar7;
int puVar8;
uint uVar9;
SVECTOR *vert;
int i;
int d1, d2;
uVar7 = 128;
pSVar4 = globemesh;
uVar9 = 0;
// generate half-globe mesh
vert = globemesh;
d1 = 0;
d2 = 128;
i = 0;
do {
uVar3 = uVar7 & 0xfff;
uVar7 = uVar7 + 0x200;
uVar5 = uVar9 + 2;
vert[0].vy = 5;
vert[1].vy = -265;
pSVar4->vy = 5;
pSVar4[1].vy = -0x109;
vert[0].vx = FIXEDH(rcossin_tbl[(d1 & 0xf) * 512 + 1] * 512);
vert[0].vz = FIXEDH(rcossin_tbl[(d1 & 0xf) * 512] * 512);
pSVar4->vx = FIXEDH(rcossin_tbl[(uVar9 & 0xf) * 0x200 + 1] * 0x200);
pSVar4->vz = FIXEDH(rcossin_tbl[(uVar9 & 0xf) * 0x200] * 0x200);
vert[1].vx = FIXEDH(rcossin_tbl[(d2 & 0xfff) * 2 + 1] * 490);
vert[1].vz = FIXEDH(rcossin_tbl[(d2 & 0xfff) * 2] * 490);
pSVar4[1].vx = FIXEDH(rcossin_tbl[uVar3 * 2 + 1] * 0x1ea);
pSVar4[1].vz = FIXEDH(rcossin_tbl[uVar3 * 2] * 0x1ea);
vert += 2;
d1 += 2;
d2 += 512;
i++;
} while (i < 18);
pSVar4 = pSVar4 + 2;
uVar9 = uVar5;
} while (uVar5 < 0x12);
vert = globemesh + 18;
d1 = 0x1280;
d2 = 0x1300;
uVar9 = 0x1300;
pSVar4 = globemesh + 18;
puVar8 = 0x1280;
iVar6 = 0x10;
i = 0;
do {
uVar3 = uVar9 & 0xfff;
uVar9 = uVar9 + 0x200;
uVar7 = (uint)puVar8 & 0xfff;
puVar8 = puVar8 + 0x200;
iVar6 = iVar6 + -2;
vert[0].vy = -265;
vert[1].vy = -505;
pSVar4->vy = -0x109;
pSVar4[1].vy = -0x1f9;
vert[0].vx = FIXEDH(rcossin_tbl[(d1 & 0xfff) * 2 + 1] * 490);
vert[0].vz = FIXEDH(rcossin_tbl[(d1 & 0xfff) * 2] * 490);
pSVar4->vx = FIXEDH(rcossin_tbl[uVar7 * 2 + 1] * 0x1ea);
pSVar4->vz = FIXEDH(rcossin_tbl[uVar7 * 2] * 0x1ea);
vert[1].vx = FIXEDH(rcossin_tbl[(d2 & 0xfff) * 2 + 1] * 330);
vert[1].vz = FIXEDH(rcossin_tbl[(d2 & 0xfff) * 2] * 330);
pSVar4[1].vx = FIXEDH(rcossin_tbl[uVar3 * 2 + 1] * 0x14a);
pSVar4[1].vz = FIXEDH(rcossin_tbl[uVar3 * 2] * 0x14a);
vert += 2;
pSVar4 = pSVar4 + 2;
} while (-1 < iVar6);
d1 += 512;
d2 += 512;
i += 2;
} while (i < 18);
puVar8 = 9600;
pSVar4 = globemesh + 36;
uVar9 = 0x2500;
iVar6 = 0x10;
vert = globemesh + 36;
d1 = 0x2500;
d2 = 9600;
i = 0;
do {
uVar3 = (uint)puVar8 & 0xfff;
puVar8 = puVar8 + 0x200;
uVar7 = uVar9 & 0xfff;
uVar9 = uVar9 + 0x200;
iVar6 = iVar6 + -2;
vert[0].vy = -505;
vert[1].vy = -617;
pSVar4->vy = -0x1f9;
pSVar4[1].vy = -0x269;
vert[0].vx = FIXEDH(rcossin_tbl[(d1 & 0xfff) * 2 + 1] * 330);
vert[0].vz = FIXEDH(rcossin_tbl[(d1 & 0xfff) * 2] * 330);
pSVar4->vx = FIXEDH(rcossin_tbl[uVar7 * 2 + 1] * 0x14a);
pSVar4->vz = FIXEDH(rcossin_tbl[uVar7 * 2] * 0x14a);
vert[1].vx = FIXEDH(rcossin_tbl[(d2 & 0xfff) * 2 + 1] * 100);
vert[1].vz = FIXEDH(rcossin_tbl[(d2 & 0xfff) * 2] * 100);
pSVar4[1].vx = FIXEDH(rcossin_tbl[uVar3 * 2 + 1] * 100);
pSVar4[1].vz = FIXEDH(rcossin_tbl[uVar3 * 2] * 100);
vert += 2;
d1 += 512;
d2 += 512;
pSVar4 = pSVar4 + 2;
} while (-1 < iVar6);
i += 2;
} while (i < 18);
}
@ -492,51 +506,52 @@ void initExplosion(void)
/* end block 3 */
// End Line: 1279
// [D]
// [D] [T]
void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
{
int iVar3;
int i;
int j;
POLY_FT4 *poly;
SVECTOR *src;
int uVar6;
uint uVar7;
uint uVar8;
int iVar9;
int iVar10;
int iVar11;
int iVar12;
int iVar13;
int rgb, transparency;
int red, green, blue;
int sf, sf1, sf2;
uint u0, u1,u2,u3;
int i;
VECTOR v;
MATRIX workmatrix;
int z;
uVar8 = *(ushort*)&smoke_texture.coords.u0 + 0x200 | *(ushort*)&smoke_texture.clutid << 0x10;
uVar7 = *(ushort*)&smoke_texture.coords.u1 + 0x200 | (*(ushort*)&smoke_texture.tpageid | 0x20) << 0x10;
iVar11 = *(ushort*)&smoke_texture.coords.u2 - 0x800;
iVar10 = *(ushort*)&smoke_texture.coords.u3 - 0x800;
u0 = *(ushort*)&smoke_texture.coords.u0 + 0x200 | *(ushort*)&smoke_texture.clutid << 0x10;
u1 = *(ushort*)&smoke_texture.coords.u1 + 0x200 | (*(ushort*)&smoke_texture.tpageid | 0x20) << 0x10;
u2 = *(ushort*)&smoke_texture.coords.u2 - 0x800;
u3 = *(ushort*)&smoke_texture.coords.u3 - 0x800;
v.vx = position.vx - camera_position.vx;
v.vy = position.vy - camera_position.vy;
v.vz = position.vz - camera_position.vz;
uVar6 = 255 - (time >> 4);
uVar6 = (((uVar6 * uVar6) >> 10) << 8 | ((255 - uVar6) * (uVar6 >> 2) + uVar6 * (uVar6 >> 1)) >> 8) << 8 | uVar6 | 0x2e000000;
transparency = 255 - (time >> 4);
rgb = (transparency * transparency >> 10 << 8 |
(255 - transparency) * (transparency >> 2) + transparency * (transparency >> 1) >> 8) << 8 |
transparency |
0x2e000000;
Apply_Inv_CameraMatrix(&v);
gte_SetTransVector(&v);
iVar12 = 0;
iVar9 = 1;
// [A] modify scale factor to make explosions prettier
sf1 = FIXEDH(time * (5000 - time) * 4) + 12;
sf2 = FIXEDH(time * (10000 - time) * 2) + 12;
i = 0;
do {
iVar3 = (time * (0x37a0 - time) + 0x800 >> 0xc) + 0xc;
i = CameraCnt * (0x40 - iVar12) & 0xfff;
SS.m[1][1] = (short)(iVar3 * hscale >> 0xc);
SS.m[0][0] = (short)((iVar3 * rscale >> 0xc) * (int)rcossin_tbl[i * 2 + 1] + 0x800 >> 0xc);
SS.m[2][0] = (short)((iVar3 * rscale >> 0xc) * (int)rcossin_tbl[i * 2] + 0x800 >> 0xc);
sf = CameraCnt * (64 - i*90) & 0xfff;
SS.m[1][1] = FIXED(sf1 * hscale);
SS.m[0][0] = FIXEDH(FIXED(sf1 * rscale) * rcossin_tbl[sf * 2 + 1]);
SS.m[2][0] = FIXEDH(FIXED(sf1 * rscale) * rcossin_tbl[sf * 2]);
SS.m[0][2] = -SS.m[2][0];
SS.m[2][2] = SS.m[0][0];
@ -545,7 +560,7 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
gte_SetRotMatrix(&workmatrix);
src = globemesh;
i = 0;
j = 0;
do {
poly = (POLY_FT4 *)current->primptr;
@ -553,8 +568,14 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
gte_ldv3(&src[0], &src[1], &src[2]);
gte_rtpt();
*(uint *)&poly[0].r0 = uVar6;
*(uint *)&poly[1].r0 = uVar6;
*(uint *)&poly[0].r0 = rgb;
*(uint *)&poly[1].r0 = rgb;
setPolyFT4(&poly[0]);
setSemiTrans(&poly[0], 1);
setPolyFT4(&poly[1]);
setSemiTrans(&poly[1], 1);
gte_stsxy3(&poly[0].x0, &poly[0].x1, &poly[0].x2);
@ -562,21 +583,20 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
gte_stsz(&z);
iVar3 = 32; // 4 verts step?
if (z > 32)
{
gte_ldv3(&src[3], &src[4], &src[5]);
gte_rtpt();
*(uint *)&poly[0].u0 = uVar8;
*(uint *)&poly[0].u1 = uVar7;
*(uint *)&poly[0].u2 = iVar11;
*(uint *)&poly[0].u3 = iVar10;
*(uint *)&poly[1].u0 = uVar8;
*(uint *)&poly[1].u1 = uVar7;
*(uint *)&poly[1].u2 = iVar11;
*(uint *)&poly[1].u3 = iVar10;
*(uint *)&poly[0].u0 = u0;
*(uint *)&poly[0].u1 = u1;
*(uint *)&poly[0].u2 = u2;
*(uint *)&poly[0].u3 = u3;
*(uint *)&poly[1].u0 = u0;
*(uint *)&poly[1].u1 = u1;
*(uint *)&poly[1].u2 = u2;
*(uint *)&poly[1].u3 = u3;
setPolyFT4(poly);
setSemiTrans(poly, 1);
@ -594,29 +614,30 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
current->primptr += sizeof(POLY_FT4) * 2;
}
if ((i & 3) == 3)
iVar3 = 48; // 6 verts step?
if ((j & 3) == 3)
src += 6;
else
src += 4;
src = (SVECTOR *)((int)&src->vx + iVar3);
j++;
} while (j < 12);
i++;
} while (i < 12);
i++;
} while (i < 2);
iVar9--;
iVar12 += 90;
} while (-1 < iVar9);
transparency = 255 - (time >> 4);
iVar9 = 255 - (time >> 4);
uVar6 = iVar9 >> 1;
iVar12 = 0;
uVar6 = (((uVar6 + (iVar9 * iVar9 >> 10)) >> 1) << 8 | (uVar6 + (((255 - iVar9) * (iVar9 >> 2) + iVar9 * uVar6) >> 8)) >> 1) << 8 | uVar6 | 0x2e000000;
rgb = transparency >> 1;
rgb = (rgb + (transparency * transparency >> 10) >> 1 << 8 |
rgb + ((255 - transparency) * (transparency >> 2) + transparency * rgb >> 8) >> 1) << 8 |
rgb | 0x2e000000;
i = 0;
do {
iVar3 = (time * (0x3930 - time) + 0x800 >> 0xc) + 0xc;
i = CameraCnt * (iVar12 * -0x5a + 0x40) & 0xfff;
SS.m[1][1] = (short)(iVar3 * hscale >> 0xc);
SS.m[0][0] = (short)((iVar3 * rscale >> 0xc) * (int)rcossin_tbl[i * 2 + 1] + 0x800 >> 0xc);
SS.m[2][0] = (short)((iVar3 * rscale >> 0xc) * (int)rcossin_tbl[i * 2] + 0x800 >> 0xc);
sf = CameraCnt * (i * -90 + 64) & 0xfff;
SS.m[1][1] = FIXED(sf2 * hscale);
SS.m[0][0] = FIXEDH(FIXED(sf2 * rscale) * rcossin_tbl[sf * 2 + 1]);
SS.m[2][0] = FIXEDH(FIXED(sf2 * rscale) * rcossin_tbl[sf * 2]);
SS.m[0][2] = -SS.m[2][0];
SS.m[2][2] = SS.m[0][0];
@ -624,9 +645,7 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
gte_SetRotMatrix(&workmatrix);
src = globemesh;
i = 0;
iVar12 = iVar12 + 1;
j = 0;
do {
poly = (POLY_FT4 *)current->primptr;
@ -634,8 +653,8 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
gte_rtpt();
*(uint *)&poly[1].r0 = uVar6;
*(uint *)&poly->r0 = uVar6;
*(uint *)&poly[1].r0 = rgb;
*(uint *)&poly[0].r0 = rgb;
gte_stsxy3(&poly[0].x0, &poly[0].x1, &poly[0].x2);
@ -648,14 +667,14 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
gte_ldv3(&src[3], &src[4], &src[5]);
gte_rtpt();
*(uint *)&poly->u0 = uVar8;
*(uint *)&poly->u1 = uVar7;
*(uint *)&poly->u2 = iVar11;
*(uint *)&poly->u3 = iVar10;
*(uint *)&poly[1].u0 = uVar8;
*(uint *)&poly[1].u1 = uVar7;
*(uint *)&poly[1].u2 = iVar11;
*(uint *)&poly[1].u3 = iVar10;
*(uint *)&poly[0].u0 = u0;
*(uint *)&poly[0].u1 = u1;
*(uint *)&poly[0].u2 = u2;
*(uint *)&poly[0].u3 = u3;
*(uint *)&poly[1].u0 = u0;
*(uint *)&poly[1].u1 = u1;
*(uint *)&poly[1].u2 = u2;
*(uint *)&poly[1].u3 = u3;
setPolyFT4(poly);
setSemiTrans(poly, 1);
@ -673,16 +692,16 @@ void DrawExplosion(int time, VECTOR position, int hscale, int rscale)
current->primptr += sizeof(POLY_FT4) * 2;
}
iVar9 = 0x20;
if (j & 3 == 3)
src += 6;
else
src += 4;
j++;
} while (j < 8);
if (i & 3 == 3)
iVar9 = 0x30;
src = (SVECTOR *)((int)&src->vx + iVar9);
i++;
} while (i < 8);
} while (iVar12 < 2);
i++;
} while (i < 2);
}

View File

@ -274,7 +274,7 @@ void ShowLoadingScreen(char *screen_name, int effect, int loading_steps)
SPRT prims[4];
POLY_FT3 nulls[4];
int fade_step;
if (effect == 1)
SetDispMask(0);
@ -282,6 +282,13 @@ void ShowLoadingScreen(char *screen_name, int effect, int loading_steps)
SetupDefDispEnv(&load_disp, 0, 0, 320, 512);
load_draw.dfe = 1;
#ifndef PSX
load_draw.clip.x = 0;
load_draw.clip.y = 0;
load_draw.clip.w = 320;
load_draw.clip.h = 512;
load_disp.isinter = 1;
#endif
PutDispEnv(&load_disp);
PutDrawEnv(&load_draw);

View File

@ -2374,7 +2374,7 @@ void PrintCommandLineArguments()
#endif // DEBUG_OPTIONS
" -replay <filename> : starts replay from file\n"
#ifdef CUTSCENE_RECORDER
" -recordcutscene : starts cutscene recording session\n"
" -recordcutscene <filename> : starts cutscene recording session. Specify INI filename with it\n"
#endif
" -nointro : disable intro screens\n"
" -nofmv : disable all FMVs\n";
@ -2616,9 +2616,10 @@ int redriver2_main(int argc, char** argv)
gInFrontend = 0;
AttractMode = 0;
extern void LoadCutsceneRecorder();
extern void LoadCutsceneRecorder(char* filename);
LoadCutsceneRecorder();
LoadCutsceneRecorder(argv[i+1]);
i++;
}
#endif
else

View File

@ -797,10 +797,11 @@ void ControlMap(void)
UnpackRegion(region_to_unpack, region_x & 1U | (region_z & 1U) * 2); // is that ever valid for 'target_barrel_region'?
current_region = region_to_unpack;
CheckUnpackNewRegions();
CheckLoadAreaData(current_barrel_region_xcell, current_barrel_region_zcell);
CheckUnpackNewRegions();
current_cell_x = (camera_position.vx + units_across_halved) / MAP_CELL_SIZE;
current_cell_z = (camera_position.vz + units_down_halved) / MAP_CELL_SIZE;

View File

@ -3,10 +3,8 @@
#include "PRES.H"
#include "MISSION.H"
#include "OVERMAP.H"
#include "PRES.H"
#include "CUTSCENE.H"
#include "GLAUNCH.H"
#include "MDRAW.H"
#include "OVERLAY.H"
#include "REPLAYS.H"
#include "PAUSE.H"
@ -600,6 +598,7 @@ void DrawWorldTarget(MS_TARGET *target)
tv.vz = target->data[4];
tv.vy = 10000;
// Capture the Flag target properties
switch(target->data[1] & 0x30000)
{
case 0x20000:
@ -743,6 +742,7 @@ void DrawMultiplayerTarget(MS_TARGET *target)
tv.vz = target->data[4];
tv.vy = 10000;
// Capture the Flag target properties
switch(target->data[1] & 0x30000)
{
case 0x10000:

View File

@ -3354,6 +3354,12 @@ int MRRequestCar(MS_TARGET *target)
// [D] [T]
void MRHandleCarRequests(void)
{
#ifdef CUTSCENE_RECORDER
extern int gCutsceneAsReplay;
if (gCutsceneAsReplay != 0)
return;
#endif
if (Mission.CarTarget)
MRCreateCar(Mission.CarTarget);
}

View File

@ -49,6 +49,22 @@ unsigned short *Low2LowerDetailTable = NULL;
/* end block 3 */
// End Line: 79
// [A]
void CleanSpooledModelSlots()
{
int i;
// assign model pointers
for (i = 0; i < MAX_MODEL_SLOTS; i++) // [A] bug fix. Init with dummyModel
{
if(!(modelpointers[i]->shape_flags & 0x8000))
{
modelpointers[i] = &dummyModel;
pLodModels[i] = &dummyModel;
}
}
}
// [D] [T]
void ProcessMDSLump(char *lump_file, int lump_size)
{
@ -74,8 +90,13 @@ void ProcessMDSLump(char *lump_file, int lump_size)
size = *(int*)mdsfile;
mdsfile += sizeof(int);
if (size)
modelpointers[i] = (MODEL*)mdsfile;
if (size)
{
model = (MODEL*)mdsfile;
model->shape_flags |= 0x8000; // [A] non-spooled flag
modelpointers[i] = model;
}
mdsfile += size;
}

View File

@ -14,6 +14,8 @@ extern unsigned short *Low2LowerDetailTable;
extern int num_models_in_pack;
void CleanSpooledModelSlots();
extern void ProcessMDSLump(char *lump_file, int lump_size); // 0x00064CFC
extern int ProcessCarModelLump(char *lump_ptr, int lump_size); // 0x00064E6C

View File

@ -18,21 +18,23 @@
COLOUR_BAND felonyColour[3] =
{
{ { 0u, 0u, 255u, 0u }, 0, 0 },
{ { 255u, 0u, 0u, 0u }, 659, 0 },
{ { 0u, 0u, 255u, 0u }, 4096, 2 }
{ { 0, 0, 255, 0 }, 0, 0 },
{ { 255, 0, 0, 0 }, 659, 0 },
{ { 0, 0, 255, 0 }, 4096, 2 }
};
COLOUR_BAND playerDamageColour[3] =
{
{ { 0u, 255u, 0u, 0u }, 0, 0 },
{ { 255u, 0u, 0u, 0u }, 3686, 0 },
{ { 0u, 0u, 0u, 0u }, 4096, 2 }
{ { 0, 255, 0, 0 }, 0, 0 },
{ { 255, 0, 0, 0 }, 3686, 0 },
{ { 0, 0, 0, 0 }, 4096, 2 }
};
COLOUR_BAND damageColour[2] =
{ { { 0u, 255u, 0u, 0u }, 0, 0 }, { { 255u, 0u, 0u, 0u }, 4096, 0 } };
{
{ { 0, 255, 0, 0 }, 0, 0 },
{ { 255, 0, 0, 0 }, 4096, 0 }
};
// decompiled code
// original method signature:
@ -58,50 +60,53 @@ PERCENTAGE_BAR ProxyBar;
int gDoOverlays = 1;
// [D]
// [D] [T]
void InitOverlays(void)
{
bool bVar1;
gDoOverlays = 1;
InitPercentageBar(&PlayerDamageBar, MaxPlayerDamage[0], playerDamageColour, "Damage");
PlayerDamageBar.xpos = 0x10;
PlayerDamageBar.ypos = 0x18;
PlayerDamageBar.xpos = 16;
PlayerDamageBar.ypos = 24;
bVar1 = 1 < NumPlayers;
PlayerDamageBar.active = 1;
if (bVar1)
if (NumPlayers > 1)
{
InitPercentageBar(&Player2DamageBar, MaxPlayerDamage[1], playerDamageColour, "Damage");
Player2DamageBar.xpos = 0x10;
Player2DamageBar.ypos = 0x8c;
Player2DamageBar.xpos = 16;
Player2DamageBar.ypos = 140;
Player2DamageBar.active = 1;
}
else
{
Player2DamageBar.active = 0;
}
Player2DamageBar.active = (bVar1);
InitPercentageBar(&FelonyBar, 0x1000, felonyColour, "Felony");
FelonyBar.xpos = 0x10;
FelonyBar.ypos = 0x2e;
FelonyBar.xpos = 16;
FelonyBar.ypos = 46;
FelonyBar.active = 0;
InitPercentageBar(&DamageBar, 1, damageColour, "Damage");
DamageBar.xpos = 0xd0;
DamageBar.ypos = 0x18;
DamageBar.xpos = 208;
DamageBar.ypos = 24;
DamageBar.flags = 1;
DamageBar.active = 0;
InitPercentageBar(&ProxyBar, TAIL_TOOFAR - TAIL_TOOCLOSE, felonyColour, "Proximity");
ProxyBar.xpos = 0x10;
ProxyBar.ypos = 0x2e;
ProxyBar.xpos = 16;
ProxyBar.ypos = 46;
ProxyBar.active = 0;
InitOverheadMap();
if (GameType == GAME_CAPTURETHEFLAG) {
if (GameType == GAME_CAPTURETHEFLAG)
{
PlayerDamageBar.active = 0;
Player2DamageBar.active = 0;
gInvincibleCar = 1;
}
}
@ -124,55 +129,55 @@ void InitOverlays(void)
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D]
// [D] [T]
void DisplayOverlays(void)
{
short *felony;
if (NoPlayerControl == 0 && gInGameCutsceneActive == 0 && gInGameCutsceneDelay == 0)
if (NoPlayerControl != 0 || gInGameCutsceneActive != 0 || gInGameCutsceneDelay != 0)
return;
if (NumPlayers > 1)
{
if (NumPlayers > 1)
if (CurrentPlayerView == 0)
return;
SetFullscreenDrawing();
}
UpdateFlashValue();
if (gShowMap == 0)
{
FastForward = 0;
if (!gDoOverlays)
return;
DrawPercentageBar(&PlayerDamageBar);
DrawPercentageBar(&Player2DamageBar);
DrawPercentageBar(&DamageBar);
DrawPercentageBar(&FelonyBar);
DrawDrivingGameOverlays();
DrawOverheadMap();
if (CopsCanSeePlayer)
{
if (CurrentPlayerView == 0)
return;
if (player[0].playerCarId < 0)
felony = &pedestrianFelony;
else
felony = &car_data[player[0].playerCarId].felonyRating;
SetFullscreenDrawing();
}
UpdateFlashValue();
if (gShowMap == 0)
{
FastForward = 0;
if (!gDoOverlays)
return;
DrawPercentageBar(&PlayerDamageBar);
DrawPercentageBar(&Player2DamageBar);
DrawPercentageBar(&DamageBar);
DrawPercentageBar(&FelonyBar);
DrawDrivingGameOverlays();
DrawOverheadMap();
if (CopsCanSeePlayer)
{
if (player[0].playerCarId < 0)
felony = &pedestrianFelony;
else
felony = &car_data[player[0].playerCarId].felonyRating;
if (*felony > FELONY_MIN_VALUE)
DrawCopIndicators();
}
}
else
{
FastForward = 1;
DrawFullscreenMap();
if (*felony > FELONY_MIN_VALUE)
DrawCopIndicators();
}
}
else
{
FastForward = 1;
DrawFullscreenMap();
}
}
@ -213,7 +218,7 @@ void DisplayOverlays(void)
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D]
// [D] [T]
void SetFullscreenDrawing(void)
{
DR_ENV *drenv;
@ -222,7 +227,7 @@ void SetFullscreenDrawing(void)
drenv = (DR_ENV *)current->primptr;
drawenv.clip.x = 256;
SetDefDrawEnv((DRAWENV *)&drawenv, 0, current->draw.clip.y & 256, 320, 256);
SetDefDrawEnv(&drawenv, 0, current->draw.clip.y & 256, 320, 256);
SetDrawEnv(drenv, &drawenv);
@ -251,15 +256,15 @@ void SetFullscreenDrawing(void)
/* end block 3 */
// End Line: 1486
// [D]
// [D] [T]
void InitPercentageBar(PERCENTAGE_BAR *bar, int size, COLOUR_BAND *pColourBand, char *tag)
{
bar->xpos = 0x96;
bar->xpos = 150;
bar->ypos = 10;
bar->width = 0x66;
bar->width = 102;
bar->height = 10;
bar->position = 0;
bar->max = (ushort)size;
bar->max = size;
bar->pColourBand = pColourBand;
bar->flags = 0;
bar->tag = tag;
@ -287,11 +292,11 @@ void InitPercentageBar(PERCENTAGE_BAR *bar, int size, COLOUR_BAND *pColourBand,
/* end block 3 */
// End Line: 1528
// [D]
// [D] [T]
void EnablePercentageBar(PERCENTAGE_BAR *bar, int max)
{
bar->position = 0;
bar->max = (ushort)max;
bar->max = max;
bar->active = 1;
}
@ -331,16 +336,15 @@ void EnablePercentageBar(PERCENTAGE_BAR *bar, int max)
/* end block 2 */
// End Line: 896
// [D]
// [D] [T]
void DrawPercentageBar(PERCENTAGE_BAR *bar)
{
short sVar1;
short sVar3;
uint uVar4;
POLY_G4 *poly;
POLY_G4 *poly2;
short sVar5;
short sVar9;
int min_x;
int max_x;
int min_y;
int max_y;
CVECTOR temp;
if (bar->active == 0)
@ -353,69 +357,75 @@ void DrawPercentageBar(PERCENTAGE_BAR *bar)
if (bar->max == 0)
{
sVar5 = bar->xpos;
uVar4 = bar->flags;
sVar9 = sVar5;
min_x = bar->xpos;
max_x = min_x;
}
else
{
uVar4 = bar->flags;
if ((uVar4 & 1) == 0)
if (bar->flags & 1)
{
sVar5 = bar->xpos;
sVar9 = sVar5 + ((bar->width * bar->position) / bar->max);
max_x = bar->xpos + bar->width;
min_x = max_x - ((bar->width * bar->position) / bar->max);
}
else
{
sVar9 = bar->xpos + bar->width;
sVar5 = sVar9 - ((bar->width * bar->position) / bar->max);
min_x = bar->xpos;
max_x = min_x + ((bar->width * bar->position) / bar->max);
}
}
sVar1 = bar->ypos;
sVar3 = bar->ypos + bar->height;
min_y = bar->ypos;
max_y = bar->ypos + bar->height;
if ((uVar4 & 2) == 0)
// draw the colour band that fills the bar
if ((bar->flags & 2) == 0)
{
poly = (POLY_G4 *)current->primptr;
setPolyG4(poly);
SetColourByValue(bar->pColourBand, (bar->position << 0xc) / bar->max, &temp);
SetColourByValue(bar->pColourBand, (bar->position * 4096) / bar->max, &temp);
poly->r0 = temp.r;
poly->g0 = temp.g;
poly->b0 = temp.b;
poly->r1 = temp.r;
poly->g1 = temp.g;
poly->b1 = temp.b;
temp.r = temp.r >> 2;
temp.g = temp.g >> 2;
temp.b = temp.b >> 2;
temp.r = temp.r / 4;
temp.g = temp.g / 4;
temp.b = temp.b / 4;
poly->r2 = temp.r;
poly->g2 = temp.g;
poly->b2 = temp.b;
poly->r3 = temp.r;
poly->g3 = temp.g;
poly->x0 = sVar5;
poly->y0 = bar->ypos;
poly->x1 = sVar9;
poly->y1 = bar->ypos;
poly->x0 = min_x;
poly->y0 = min_y;
poly->x1 = max_x;
poly->y1 = min_y;
poly->b3 = temp.b;
poly->x2 = sVar5;
poly->x3 = sVar9;
poly->y2 = bar->ypos + bar->height;
poly->y3 = bar->ypos + bar->height;
poly->x2 = min_x;
poly->x3 = max_x;
poly->y2 = max_y;
poly->y3 = max_y;
addPrim((u_long*)(current->ot + 1), poly);
current->primptr += sizeof(POLY_G4);
}
// draw transparent part
min_x = bar->xpos;
max_x = bar->xpos + bar->width;
poly2 = (POLY_G4 *)current->primptr;
setPolyG4(poly2);
setSemiTrans(poly2,1);
poly2->x0 = bar->xpos;
poly2->x2 = bar->xpos;
poly2->x0 = min_x;
poly2->x2 = min_x;
poly2->r0 = 0;
poly2->g0 = 0;
poly2->b0 = 0;
@ -428,33 +438,34 @@ void DrawPercentageBar(PERCENTAGE_BAR *bar)
poly2->r3 = 100;
poly2->g3 = 100;
poly2->b3 = 100;
poly2->y0 = bar->ypos;
poly2->x1 = bar->xpos + bar->width;
poly2->y1 = bar->ypos;
poly2->x3 = bar->xpos + bar->width;
poly2->y2 = bar->ypos + bar->height;
poly2->y3 = bar->ypos + bar->height;
poly2->y0 = min_y;
poly2->x1 = max_x;
poly2->y1 = min_y;
poly2->x3 = max_x;
poly2->y2 = max_y;
poly2->y3 = max_y;
addPrim((u_long*)(current->ot+1), poly2);
current->primptr += sizeof(POLY_G4);
// draw contours
LINE_F4* lineF4 = (LINE_F4*)current->primptr;
setLineF4(lineF4);
lineF4->r0 = 80;
lineF4->g0 = 80;
lineF4->b0 = 80;
lineF4->x0 = bar->xpos - 1;
lineF4->y0 = bar->ypos - 1;
lineF4->x0 = min_x - 1;
lineF4->y0 = min_y - 1;
lineF4->x1 = bar->xpos + bar->width;
lineF4->y1 = bar->ypos - 1;
lineF4->x1 = max_x;
lineF4->y1 = min_y - 1;
lineF4->x2 = bar->xpos + bar->width;
lineF4->x3 = bar->xpos - 1;
lineF4->x2 = max_x;
lineF4->x3 = min_x - 1;
lineF4->y2 = bar->ypos + bar->height;
lineF4->y3 = bar->ypos + bar->height;
lineF4->y2 = max_y;
lineF4->y3 = max_y;
addPrim((u_long*)(current->ot + 1), lineF4);
current->primptr += sizeof(LINE_F4);
@ -465,25 +476,25 @@ void DrawPercentageBar(PERCENTAGE_BAR *bar)
lineF2->g0 = 80;
lineF2->b0 = 80;
lineF2->x0 = bar->xpos - 1;
lineF2->y0 = bar->ypos - 1;
lineF2->x0 = min_x - 1;
lineF2->y0 = min_y - 1;
lineF2->x1 = bar->xpos - 1;
lineF2->y1 = bar->ypos + bar->height;
lineF2->x1 = min_x - 1;
lineF2->y1 = max_y;
addPrim((u_long*)(current->ot + 1), lineF2);
current->primptr += sizeof(LINE_F2);
TransparencyOn(current->ot + 1, 0x20);
if (bar->tag != NULL)
{
SetTextColour(128, 128, 64);
if ((bar->flags & 1U) == 0)
PrintString(bar->tag, bar->xpos + 8, bar->ypos - 11);
PrintString(bar->tag, min_x + 8, min_y - 11);
else
PrintStringRightAligned(bar->tag, bar->xpos + bar->width - 8, bar->ypos - 11);
PrintStringRightAligned(bar->tag, max_x - 8, min_y - 11);
}
}
@ -528,22 +539,35 @@ void DrawPercentageBar(PERCENTAGE_BAR *bar)
/* end block 3 */
// End Line: 1179
// [D]
// [D] [T]
void DrawProximityBar(PERCENTAGE_BAR *bar)
{
int iVar3;
TILE *tile;
short total;
int min_x;
int max_x;
int min_y;
int max_y;
int half_width;
if (bar->active == 0)
return;
if (bar->position < TAIL_TOOCLOSE)
bar->position = TAIL_TOOCLOSE;
total = bar->position;
if (TAIL_TOOFAR < bar->position)
bar->position = TAIL_TOOFAR;
if (total < TAIL_TOOCLOSE)
total = TAIL_TOOCLOSE;
if (total > TAIL_TOOFAR)
total = TAIL_TOOFAR;
iVar3 = bar->position - TAIL_TOOCLOSE;
min_x = bar->xpos;
max_x = bar->xpos + bar->width;
min_y = bar->ypos;
max_y = bar->ypos + bar->height;
half_width = bar->width / 2;
tile = (TILE *)current->primptr;
setTile(tile);
@ -551,9 +575,9 @@ void DrawProximityBar(PERCENTAGE_BAR *bar)
tile->g0 = 16;
tile->b0 = 16;
tile->x0 = ((bar->width * iVar3) / (TAIL_TOOFAR - TAIL_TOOCLOSE) - 1) + bar->xpos;
tile->x0 = ((bar->width * (total - TAIL_TOOCLOSE)) / (TAIL_TOOFAR - TAIL_TOOCLOSE) - 1) + min_x;
tile->w = 2;
tile->y0 = bar->ypos;
tile->y0 = min_y;
tile->h = bar->height;
addPrim(current->ot + 1, tile);
@ -574,14 +598,14 @@ void DrawProximityBar(PERCENTAGE_BAR *bar)
poly2->g3 = 255;
poly2->b3 = 0;
poly2->x0 = bar->xpos;
poly2->y0 = bar->ypos;
poly2->x1 = bar->xpos + (bar->width / 2);
poly2->y1 = bar->ypos;
poly2->x2 = bar->xpos;
poly2->y2 = bar->ypos + bar->height;
poly2->x3 = bar->xpos + (bar->width / 2);
poly2->y3 = bar->ypos + bar->height;
poly2->x0 = min_x;
poly2->y0 = min_y;
poly2->x1 = min_x + half_width;
poly2->y1 = min_y;
poly2->x2 = min_x;
poly2->y2 = max_y;
poly2->x3 = min_x + half_width;
poly2->y3 = max_y;
addPrim(current->ot + 1, poly2);
current->primptr += sizeof(POLY_G4);
@ -602,14 +626,14 @@ void DrawProximityBar(PERCENTAGE_BAR *bar)
poly2->g3 = 0;
poly2->b3 = 0;
poly2->x0 = bar->xpos + (bar->width / 2);
poly2->y0 = bar->ypos;
poly2->x1 = bar->xpos + bar->width;
poly2->y1 = bar->ypos;
poly2->x2 = bar->xpos + (bar->width / 2);
poly2->y2 = bar->ypos + bar->height;
poly2->x3 = bar->xpos + bar->width;
poly2->y3 = bar->ypos + bar->height;
poly2->x0 = min_x + half_width;
poly2->y0 = min_y;
poly2->x1 = max_x;
poly2->y1 = min_y;
poly2->x2 = min_x + half_width;
poly2->y2 = max_y;
poly2->x3 = max_x;
poly2->y3 = max_y;
addPrim(current->ot + 1, poly2);
current->primptr += sizeof(POLY_G4);
@ -620,17 +644,17 @@ void DrawProximityBar(PERCENTAGE_BAR *bar)
lineF4->g0 = 80;
lineF4->b0 = 80;
lineF4->x0 = bar->xpos - 1;
lineF4->y0 = bar->ypos - 1;
lineF4->x0 = min_x - 1;
lineF4->y0 = min_y - 1;
lineF4->x1 = bar->xpos + bar->width;
lineF4->y1 = bar->ypos - 1;
lineF4->x1 = max_x;
lineF4->y1 = min_y - 1;
lineF4->x2 = bar->xpos + bar->width;
lineF4->x3 = bar->xpos - 1;
lineF4->x2 = max_x;
lineF4->x3 = min_x - 1;
lineF4->y2 = bar->ypos + bar->height;
lineF4->y3 = bar->ypos + bar->height;
lineF4->y2 = max_y;
lineF4->y3 = max_y;
addPrim((u_long*)(current->ot + 1), lineF4);
current->primptr += sizeof(LINE_F4);
@ -641,27 +665,25 @@ void DrawProximityBar(PERCENTAGE_BAR *bar)
lineF2->g0 = 80;
lineF2->b0 = 80;
lineF2->x0 = bar->xpos - 1;
lineF2->y0 = bar->ypos - 1;
lineF2->x0 = min_x - 1;
lineF2->y0 = min_y - 1;
lineF2->x1 = bar->xpos - 1;
lineF2->y1 = bar->ypos + bar->height;
lineF2->x1 = min_x - 1;
lineF2->y1 = max_y;
addPrim((u_long*)(current->ot + 1), lineF2);
current->primptr += sizeof(LINE_F2);
TransparencyOn(current->ot + 1, 0x20);
TransparencyOn(current->ot + 1, 0x20);
if (bar->tag != NULL)
{
SetTextColour(128, 128, 64);
if ((bar->flags & 1U) == 0)
PrintString(bar->tag, bar->xpos + 8, bar->ypos - 11);
PrintString(bar->tag, min_x + 8, min_y - 11);
else
PrintStringRightAligned(bar->tag, bar->xpos + bar->width - 8, bar->ypos - 11);
PrintStringRightAligned(bar->tag, max_x - 8, min_y - 11);
}
}
@ -694,40 +716,34 @@ void DrawProximityBar(PERCENTAGE_BAR *bar)
char OverlayFlashValue = 0;
// [D]
// [D] [T]
void SetColourByValue(COLOUR_BAND *pColourBand, int value, CVECTOR *pOut)
{
COLOUR_BAND *pCVar1;
COLOUR_BAND *pCVar2;
COLOUR_BAND *pPrevColourBand;
int iVar3;
int iVar4;
int temp;
int scale;
int inv;
pCVar2 = pColourBand + 1;
if (pColourBand[1].value < value)
pPrevColourBand = pColourBand + 1;
while (pPrevColourBand->value < value)
{
pCVar1 = pColourBand + 2;
do {
pCVar2 = pCVar1;
pCVar1 = pCVar2 + 1;
} while (pCVar2->value < value);
pColourBand++;
pPrevColourBand++;
}
if ((pCVar2->flags != 0) && (pCVar2->flags == 2))
{
iVar3 = OverlayFlashValue * (pCVar2->value - pCVar2[-1].value);
value = pCVar2[-1].value + (iVar3 >> 3);
}
if (pPrevColourBand->flags == 2)
scale = pColourBand->value + OverlayFlashValue * (pPrevColourBand->value - pColourBand->value) / 8;
else
scale = value;
iVar3 = pCVar2->value - pCVar2[-1].value;
iVar4 = ((value - pCVar2[-1].value) * 0x1000) / iVar3;
temp = ((scale - pColourBand->value) * 0x1000) / (pPrevColourBand->value - pColourBand->value);
iVar3 = 0x1000 - iVar4;
inv = 4096 - temp;
pOut->r = ((iVar3 * pCVar2[-1].colour.r + iVar4 * (pCVar2->colour).r) >> 0xc);
pOut->g = ((iVar3 * pCVar2[-1].colour.g + iVar4 * (pCVar2->colour).g) >> 0xc);
pOut->b = ((iVar3 * pCVar2[-1].colour.b + iVar4 * (pCVar2->colour).b) >> 0xc);
pOut->r = FIXED(inv * pColourBand->colour.r + temp * pPrevColourBand->colour.r);
pOut->g = FIXED(inv * pColourBand->colour.g + temp * pPrevColourBand->colour.g);
pOut->b = FIXED(inv * pColourBand->colour.b + temp * pPrevColourBand->colour.b);
}
@ -760,16 +776,12 @@ void SetColourByValue(COLOUR_BAND *pColourBand, int value, CVECTOR *pOut)
/* end block 4 */
// End Line: 2049
// [D] [A] - bugged
// [D] [T]
void TransparencyOn(void *potz, ushort tpage)
{
DR_TPAGE *null;
null = (DR_TPAGE*)current->primptr;
setDrawTPage(null, 1, 0, tpage); // [A] might be incorrect
// original mode:
//*(char *)((int)puVar2 + 3) = '\x01';
//puVar2[1] = (uint)tpage & 0x9ff | 0xe1000600;
setDrawTPage(null, 1, 0, tpage);
addPrim(potz, null);
current->primptr += sizeof(DR_TPAGE);
@ -812,24 +824,23 @@ void TransparencyOn(void *potz, ushort tpage)
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D] [T]
void UpdateFlashValue(void)
{
int iVar1;
int iVar2;
uint uVar3;
iVar2 = CameraCnt;
int size;
int flash;
if (gShowMap != 0)
iVar2 = FrameCnt;
size = FrameCnt;
else
size = CameraCnt;
flash = size % 16;
iVar1 = iVar2;
uVar3 = iVar2 - (iVar1 >> 4) * 16 & 0xff;
OverlayFlashValue = uVar3;
if (7 < uVar3)
OverlayFlashValue = 16 - OverlayFlashValue;
if (flash > 7)
flash = 16 - flash;
OverlayFlashValue = flash;
}
@ -894,14 +905,13 @@ void UpdateFlashValue(void)
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D]
// [D] [T]
void DrawDrivingGameOverlays(void)
{
int iVar1;
int iVar2;
SCORE_ENTRY* table;
int x;
int i;
int y;
int y_00;
char string[32];
SetTextColour(128, 128, 64);
@ -909,115 +919,137 @@ void DrawDrivingGameOverlays(void)
switch (GameType)
{
case GAME_GETAWAY:
iVar1 = PrintString("Best: ", 0x10, 0x3c);
PrintScoreTableTime(iVar1 + 3, 0x3c, ScoreTables.GetawayTable[GameLevel][gSubGameNumber][0].time);
table = &ScoreTables.GetawayTable[GameLevel][gSubGameNumber][0];
x = PrintString("Best: ", 16, 60);
PrintScoreTableTime(x + 3, 60, table->time);
break;
case GAME_GATERACE:
if (NumPlayers != 1)
if (NumPlayers == 1)
{
y = PrintString("Gate:", 0x10, 0x24);
table = &ScoreTables.GateRaceTable[GameLevel][gSubGameNumber][0];
PrintStringRightAligned("Gate:", 270, 16);
sprintf(string, "%d / %d", gPlayerScore.items, 100);
PrintString(string, y + 3, 0x24);
y = PrintString("Gate:", 0x10, 0x96);
sprintf(string, "%d / %d", gPlayerScore.P2items, 100);
LAB_00015b28:
PrintString(string, y + 3, 0x96);
return;
PrintString(string, 273, 16);
x = PrintString("Best:", 16, 36);
PrintScoreTableTime(x + 3, 36, table->time);
x = PrintString("Gate:", 16, 0x34);
if (table->items == -1)
sprintf(string, "-");
else
sprintf(string, "%d", table->items);
PrintString(string, x + 3, 52);
}
table = &ScoreTables.GateRaceTable[GameLevel][gSubGameNumber][0];
PrintStringRightAligned("Gate:", 0x10e, 0x10);
sprintf(string, "%d / %d", gPlayerScore.items, 100);
PrintString(string, 0x111, 0x10);
y = PrintString("Best:", 0x10, 0x24);
PrintScoreTableTime(y + 3, 0x24, table->time);
y = PrintString("Gate:", 0x10, 0x34);
if (table->items == -1)
goto LAB_00015c00;
LAB_00015c20:
sprintf(string, "%d", table->items);
goto LAB_00015c2c;
else
{
x = PrintString("Gate:", 16, 36);
sprintf(string, "%d / %d", gPlayerScore.items, 100);
PrintString(string, x + 3, 36);
x = PrintString("Gate:", 16, 150);
sprintf(string, "%d / %d", gPlayerScore.P2items, 100);
PrintString(string, x + 3, 150);
}
break;
case GAME_CHECKPOINT:
if (NumPlayers != 1)
if (NumPlayers > 1)
{
y = PrintString("Checks", 0x10, 0x24);
x = PrintString("Checks", 16, 36);
sprintf(string, "%d/5", gPlayerScore.items);
PrintString(string, y + 3, 0x24);
y = PrintString("Checks", 0x10, 0x96);
PrintString(string, x + 3, 36);
x = PrintString("Checks", 16, 150);
sprintf(string, "%d/5", gPlayerScore.P2items);
goto LAB_00015b28;
PrintString(string, x + 3, 150);
}
else
{
table = &ScoreTables.CheckpointTable[GameLevel][gSubGameNumber][0];
PrintStringRightAligned("Checks", 270, 16);
table = &ScoreTables.CheckpointTable[GameLevel][gSubGameNumber][0];
PrintStringRightAligned("Checks", 0x10e, 0x10);
sprintf(string, "%d/5", gPlayerScore.items);
PrintString(string, 0x111, 0x10);
sprintf(string, "%d/5", gPlayerScore.items);
PrintString(string, 273, 16);
goto LAB_00015c88;
x = PrintString("Best:", 16, 36);
PrintScoreTableTime(x + 3, 36, table->time);
}
break;
case GAME_TRAILBLAZER:
table = &ScoreTables.TrailblazerTable[GameLevel][gSubGameNumber][0];
PrintStringRightAligned("Cones:", 0xfa, 0x10);
PrintStringRightAligned("Cones:", 250, 16);
sprintf(string, "%d / %d", gPlayerScore.items, 100);
PrintString(string, 0xfd, 0x10);
y = PrintString("Best", 0x10, 0x24);
PrintScoreTableTime(y + 3, 0x24, table->time);
y = PrintString("Cones:", 0x10, 0x34);
PrintString(string, 253, 16);
x = PrintString("Best", 16, 36);
PrintScoreTableTime(x + 3, 36, table->time);
x = PrintString("Cones:", 16, 52);
if (table->items != -1)
goto LAB_00015c20;
LAB_00015c00:
sprintf(string, "-");
LAB_00015c2c:
PrintString(string, y + 3, 0x34);
sprintf(string, "%d", table->items);
else
sprintf(string, "-");
PrintString(string, x + 3, 52);
break;
case GAME_SURVIVAL:
table = &ScoreTables.SurvivalTable[GameLevel][gSubGameNumber][0];
LAB_00015c88:
y = PrintString("Best:", 0x10, 0x24);
PrintScoreTableTime(y + 3, 0x24, table->time);
x = PrintString("Best:", 16, 36);
PrintScoreTableTime(x + 3, 36, table->time);
break;
case GAME_CAPTURETHEFLAG:
y = PrintString("Flags:", 0x10, 0x10);
x = PrintString("Flags:", 16, 16);
sprintf(string, "%d", gPlayerScore.items);
PrintString(string, y + 3, 0x10);
y = PrintString("Flags:", 0x10, 0x84);
PrintString(string, x + 3, 16);
x = PrintString("Flags:", 16, 132);
sprintf(string, "%d", gPlayerScore.P2items);
PrintString(string, y + 3, 0x84);
PrintString(string, x + 3, 132);
break;
case GAME_SECRET:
y_00 = 0x24;
y = 0;
if (0 < gNumRaceTrackLaps)
{
do {
iVar2 = y + 1;
sprintf(string, "%s %d:", "Lap", iVar2);
iVar1 = PrintString(string, 0x10, y_00);
PrintScoreTableTime(iVar1 + 3, y_00, gLapTimes[0][y]);
y = iVar2;
y_00 = y_00 + 0x10;
} while (iVar2 < gNumRaceTrackLaps);
}
y = 36;
y = 0x96;
if ((1 < NumPlayers) && (y_00 = 0, 0 < gNumRaceTrackLaps))
i = 0;
do
{
do {
iVar2 = y_00 + 1;
sprintf(string, "%s %d:", "Lap", iVar2);
iVar1 = PrintString(string, 0x10, y);
PrintScoreTableTime(iVar1 + 3, y, gLapTimes[1][y_00]);
y_00 = iVar2;
y = y + 0x10;
} while (iVar2 < gNumRaceTrackLaps);
sprintf(string, "%s %d:", "Lap", i+1);
x = PrintString(string, 0x10, y);
PrintScoreTableTime(x + 3, y, gLapTimes[0][i]);
y += 16;
i++;
} while (i < gNumRaceTrackLaps);
if (NumPlayers > 1)
{
y = 150;
i = 0;
do
{
sprintf(string, "%s %d:", "Lap", i+1);
x = PrintString(string, 0x10, y);
PrintScoreTableTime(x + 3, y, gLapTimes[1][i]);
y += 16;
i++;
} while (i < gNumRaceTrackLaps);
}
break;
}
@ -1050,7 +1082,7 @@ void DrawDrivingGameOverlays(void)
/* end block 3 */
// End Line: 2407
// [D]
// [D] [T]
void PrintScoreTableTime(int x, int y, int time)
{
char string[32];

View File

@ -136,67 +136,53 @@ static int gUseRotatedMap = 0;
/* WARNING: Could not reconcile some variable overlaps */
// [D]
// [D] [T]
void DrawTargetBlip(VECTOR *pos, unsigned char r, unsigned char g, unsigned char b, ulong flags)
{
int ysize;
POLY_FT4 *poly;
VECTOR vec;
if ((flags & 0x20) == 0)
{
if ((flags & 8) == 0)
{
if ((flags & 1) == 0)
{
WorldToFullscreenMap2(pos, &vec);
}
else
{
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
if (0x5e < vec.vx - 0xe9U)
return;
if (vec.vz < 0xae)
return;
if (0xfa < vec.vz)
return;
}
}
else {
vec.vx = pos->vx;
vec.vy = pos->vy;
vec.vz = pos->vz;
vec.pad = pos->pad;
}
if ((flags & 1) == 0) {
vec.vx = vec.vx + map_x_offset;
vec.vz = vec.vz + map_z_offset;
}
}
else
if (flags & 0x20)
{
WorldToMultiplayerMap(pos, &vec);
vec.vx += 240;
vec.vz += 96;
}
if ((flags & 0x10) == 0)
else if (flags & 0x8)
{
ysize = 4;
vec.vx = pos->vx;
vec.vz = pos->vz;
}
else if (flags & 0x1)
{
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
if ((flags & 2) != 0)
{
ysize = 3;
}
if (vec.vx - 233U > 94)
return;
if (vec.vz < 174 || vec.vz > 250)
return;
}
else
{
ysize = OverlayFlashValue >> 1;
WorldToFullscreenMap2(pos, &vec);
}
if ((flags & 1) == 0)
{
vec.vx += map_x_offset;
vec.vz += map_z_offset;
}
if (flags & 0x10)
ysize = OverlayFlashValue / 2;
else if (flags & 0x2)
ysize = 3;
else
ysize = 4;
poly = (POLY_FT4 *)current->primptr;
setPolyFT4(poly);
@ -204,10 +190,13 @@ void DrawTargetBlip(VECTOR *pos, unsigned char r, unsigned char g, unsigned char
poly->x0 = vec.vx - ysize;
poly->y0 = vec.vz - ysize;
poly->x1 = vec.vx + ysize;
poly->y1 = vec.vz - ysize;
poly->x2 = vec.vx - ysize;
poly->y2 = vec.vz + ysize;
poly->x3 = vec.vx + ysize;
poly->y3 = vec.vz + ysize;
@ -215,30 +204,27 @@ void DrawTargetBlip(VECTOR *pos, unsigned char r, unsigned char g, unsigned char
poly->g0 = g;
poly->b0 = b;
poly->u0 = light_texture.coords.u0;
poly->v0 = light_texture.coords.v0;
poly->u1 = light_texture.coords.u1;
poly->v1 = light_texture.coords.v1;
poly->u2 = light_texture.coords.u2;
poly->v2 = light_texture.coords.v2;
poly->u3 = light_texture.coords.u3;
poly->v3 = light_texture.coords.v3;
*(ushort*)&poly->u0 = *(ushort*)&light_texture.coords.u0;
*(ushort*)&poly->u1 = *(ushort*)&light_texture.coords.u1;
*(ushort*)&poly->u2 = *(ushort*)&light_texture.coords.u2;
*(ushort*)&poly->u3 = *(ushort*)&light_texture.coords.u3;
if ((flags & 2) == 0)
poly->tpage = light_texture.tpageid | 0x20;
else
if (flags & 0x2)
poly->tpage = light_texture.tpageid | 0x40;
else
poly->tpage = light_texture.tpageid | 0x20;
poly->clut = light_texture.clutid;
if ((flags & 4) == 0)
if (flags & 0x4)
{
addPrim(current->ot, poly);
current->primptr += sizeof(POLY_FT4);
// fullscreen map mode
DrawPrim(poly);
}
else
{
DrawPrim(poly);
addPrim(current->ot, poly);
current->primptr += sizeof(POLY_FT4);
}
}
@ -269,74 +255,65 @@ void DrawTargetBlip(VECTOR *pos, unsigned char r, unsigned char g, unsigned char
/* WARNING: Could not reconcile some variable overlaps */
// [D]
// [D] [T]
void DrawTargetArrow(VECTOR *pos, ulong flags)
{
short sVar1;
short sVar2;
int y;
int x;
int dy;
int dx;
POLY_G3 *poly;
VECTOR vec;
VECTOR vec2;
if ((flags & 8) == 0)
{
if ((flags & 1) == 0)
{
WorldToFullscreenMap2(pos, &vec);
}
else
{
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
}
}
else
if (flags & 0x8)
{
vec.vx = pos->vx;
vec.vy = pos->vy;
vec.vz = pos->vz;
vec.pad = pos->pad;
}
if ((flags & 1) == 0)
else if (flags & 0x1)
{
vec.vx = vec.vx + map_x_offset;
vec.vz = vec.vz + map_z_offset;
vec2.vx = map_x_offset + 0xa0;
vec2.vz = map_z_offset + 0x80;
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
}
else
{
WorldToFullscreenMap2(pos, &vec);
}
if (flags & 0x1)
{
WorldToOverheadMapPositions((VECTOR *)player, &vec2, 1, '\0', 0);
}
else
{
vec.vx = vec.vx + map_x_offset;
vec.vz = vec.vz + map_z_offset;
x = vec2.vx - vec.vx;
y = vec2.vz - vec.vz;
vec2.vx = map_x_offset + 160;
vec2.vz = map_z_offset + 128;
}
// target arrow perpendicular
dx = (vec2.vx - vec.vx) / 8;
dy = (vec2.vz - vec.vz) / 8;
poly = (POLY_G3 *)current->primptr;
setPolyG3(poly);
setSemiTrans(poly, 1);
poly->r0 = 24;
poly->g0 = 24;
poly->b0 = 24;
poly->r1 = 24;
poly->g1 = 24;
poly->b1 = 24;
poly->r0 = poly->r1 = 24;
poly->g0 = poly->g1 = 24;
poly->b0 = poly->b1 = 24;
poly->r2 = 64;
poly->g2 = 64;
poly->b2 = 64;
sVar1 = (y >> 3);
sVar2 = (x >> 3);
poly->x0 = vec2.vx + dy;
poly->y0 = vec2.vz - dx;
poly->x1 = vec2.vx - dy;
poly->y1 = vec2.vz + dx;
poly->x0 = vec2.vx + sVar1;
poly->y0 = vec2.vz - sVar2;
poly->x1 = vec2.vx - sVar1;
poly->y1 = vec2.vz + sVar2;
poly->x2 = vec.vx;
poly->y2 = vec.vz;
@ -354,16 +331,18 @@ void DrawTargetArrow(VECTOR *pos, ulong flags)
null->tpage = 0x40;
if ((flags & 4) == 0)
if (flags & 0x4)
{
addPrim(current->ot, poly);
addPrim(current->ot, null);
current->primptr += sizeof(POLY_G3) + sizeof(POLY_FT3);
// fullscreen map
DrawPrim(null);
DrawPrim(poly);
}
else
{
DrawPrim(null);
DrawPrim(poly);
addPrim(current->ot, poly);
addPrim(current->ot, null);
current->primptr += sizeof(POLY_G3) + sizeof(POLY_FT3);
}
}
@ -397,74 +376,65 @@ void DrawTargetArrow(VECTOR *pos, ulong flags)
/* end block 3 */
// End Line: 1822
// [D]
// [D] [T]
void DrawPlayerDot(VECTOR *pos, short rot, unsigned char r, unsigned char g, int b, ulong flags)
{
int iVar2;
int iVar3;
int sn;
int cs;
POLY_F3 *poly;
VECTOR direction;
SVECTOR apos[3];
VECTOR opos[3];
VECTOR vec;
if ((flags & 0x20) == 0)
{
if ((flags & 8) == 0)
{
if ((flags & 1) == 0)
{
WorldToFullscreenMap2(pos, &vec);
}
else
{
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
if (0x5e < vec.vx - 0xe9U)
return;
if (vec.vz < 0xae)
return;
if (0xfa < vec.vz)
return;
}
}
else
{
vec.vx = pos->vx;
vec.vy = pos->vy;
vec.vz = pos->vz;
vec.pad = pos->pad;
}
if ((flags & 1) == 0)
{
vec.vx = vec.vx + map_x_offset;
vec.vz = vec.vz + map_z_offset;
}
}
else
if (flags & 0x20)
{
WorldToMultiplayerMap(pos, &vec);
vec.vx += 240;
vec.vz += 96;
}
else
{
if (flags & 0x8)
{
vec.vx = pos->vx;
vec.vz = pos->vz;
}
else if (flags & 0x1)
{
WorldToOverheadMapPositions(pos, &vec, 1, 0, 0);
if (vec.vx - 233U > 94)
return;
iVar2 = rcossin_tbl[(rot & 0xfffU) * 2];
iVar3 = rcossin_tbl[(rot & 0xfffU) * 2 + 1];
if (vec.vz < 174 || vec.vz > 250)
return;
}
else
{
WorldToFullscreenMap2(pos, &vec);
}
}
if ((flags & 0x1) == 0)
{
vec.vx += map_x_offset;
vec.vz += map_z_offset;
}
sn = rcossin_tbl[(rot & 0xfffU) * 2];
cs = rcossin_tbl[(rot & 0xfffU) * 2 + 1];
opos[2].vx = vec.vx;
opos[2].vz = vec.vz;
opos[0].vx = opos[2].vx + (iVar2 * -3 + 0x800 >> 0xc);
opos[0].vz = opos[2].vz + FIXEDH(iVar3 * -3);
opos[0].vx = vec.vx + FIXEDH(sn * -3);
opos[0].vz = vec.vz + FIXEDH(cs * -3);
opos[1].vx = opos[2].vx + FIXEDH(iVar2 * 3 + iVar3 * -2);
opos[1].vz = opos[2].vz + FIXEDH(iVar3 * 3 + iVar2 * 2);
opos[1].vx = vec.vx + FIXEDH(sn * 3 + cs * -2);
opos[1].vz = vec.vz + FIXEDH(cs * 3 + sn * 2);
opos[2].vx = opos[2].vx + FIXEDH(iVar3 * 2 + iVar2 * 3);
opos[2].vz = opos[2].vz + FIXEDH(iVar2 * -2 + iVar3 * 3);
opos[2].vx = vec.vx + FIXEDH(cs * 2 + sn * 3);
opos[2].vz = vec.vz + FIXEDH(sn * -2 + cs * 3);
poly = (POLY_F3 *)current->primptr;
setPolyF3(poly);
@ -475,19 +445,21 @@ void DrawPlayerDot(VECTOR *pos, short rot, unsigned char r, unsigned char g, int
poly->x0 = opos[0].vx;
poly->y0 = opos[0].vz;
poly->x1 = opos[1].vx;
poly->y1 = opos[1].vz;
poly->x2 = opos[2].vx;
poly->y2 = opos[2].vz;
if ((flags & 4) == 0)
if (flags & 0x4)
{
addPrim(current->ot, poly);
current->primptr += sizeof(POLY_F3);
DrawPrim(poly);
}
else
{
DrawPrim(poly);
addPrim(current->ot, poly);
current->primptr += sizeof(POLY_F3);
}
}
@ -514,7 +486,7 @@ void DrawPlayerDot(VECTOR *pos, short rot, unsigned char r, unsigned char g, int
/* end block 2 */
// End Line: 1983
// [D]
// [D] [T]
void ProcessOverlayLump(char *lump_ptr, int lump_size)
{
int i;
@ -525,15 +497,15 @@ void ProcessOverlayLump(char *lump_ptr, int lump_size)
MapTPage = info.tpageid;
MapClut = GetClut(mapclutpos.x, mapclutpos.y);
MapRect.w = 0x40;
MapRect.h = 0x100;
MapRect.x = (MapTPage & 0xf) << 6;
MapRect.y = (MapTPage & 0x10) << 4;
MapRect.w = 64;
MapRect.h = 256;
MapRect.x = (MapTPage & 15) << 6;
MapRect.y = (MapTPage & 16) << 4;
i = 0;
do {
MapSegmentPos[i].x = (((i & 3) * 32 + info.coords.u0) >> 2);
MapSegmentPos[i].y = info.coords.v0 + (i >> 2) * 32;
MapSegmentPos[i].x = ((i & 3) * 32 + info.coords.u0) / 4;
MapSegmentPos[i].y = info.coords.v0 + (i / 4) * 32;
i++;
} while (i < 16);
@ -545,7 +517,7 @@ void ProcessOverlayLump(char *lump_ptr, int lump_size)
MALLOC_END();
LoadImage(&mapclutpos, (u_long *)(MapBitMaps + 0x200));
LoadImage(&mapclutpos, (u_long *)(MapBitMaps + 512));
DrawSync(0);
}
@ -603,45 +575,36 @@ void ProcessOverlayLump(char *lump_ptr, int lump_size)
/* end block 3 */
// End Line: 2100
// [D]
// [D] [T]
ulong Long2DDistance(VECTOR *pPoint1, VECTOR *pPoint2)
{
short sVar1;
int iVar2;
uint uVar3;
long y;
int x;
ulong uVar4;
int tempTheta;
int theta;
ulong result;
VECTOR delta;
x = pPoint1->vx - pPoint2->vx;
delta.vx = ABS(pPoint1->vx - pPoint2->vx);
delta.vz = ABS(pPoint1->vz - pPoint2->vz);
if (x < 0)
x = pPoint2->vx - pPoint1->vx;
theta = ratan2(delta.vz, delta.vx);
y = pPoint1->vz - pPoint2->vz;
if (y < 0)
y = pPoint2->vz - pPoint1->vz;
uVar3 = ratan2(y, x);
if ((uVar3 & 0x7ff) - 0x200 < 0x401)
if ((theta & 0x7ff) - 512U <= 1024)
{
sVar1 = rcossin_tbl[(uVar3 & 0xfff) * 2];
x = y;
tempTheta = rcossin_tbl[(theta & 0xfff) * 2];
result = delta.vz;
}
else
{
sVar1 = rcossin_tbl[(uVar3 & 0xfff) * 2 + 1];
tempTheta = rcossin_tbl[(theta & 0xfff) * 2 + 1];
result = delta.vx;
}
iVar2 = sVar1;
if (x < 0x80000)
uVar4 = (x << 0xc) / iVar2;
if (result < 0x80000)
result = (result << 12) / tempTheta;
else
uVar4 = (x << 9) / iVar2 << 3;
result = (result << 9) / tempTheta << 3;
return uVar4;
return result;
}
@ -678,42 +641,37 @@ ulong Long2DDistance(VECTOR *pPoint1, VECTOR *pPoint2)
/* WARNING: Unknown calling convention yet parameter storage is locked */
// [D]
// [D] [T]
void InitOverheadMap(void)
{
int d;
int c;
int tpage;
if (gMultiplayerLevels == 0)
{
SetMapPos();
tilehnum = overlaidmaps[GameLevel].width / 32;
c = 0;
tpage = 0;
do {
d = 0;
do {
maptile[d][c] = tpage;
LoadMapTile(tpage, (x_map >> 5) + d, (y_map >> 5) + c);
d++;
tpage++;
} while (d < 4);
c++;
} while (c < 4);
old_x_mod = x_map & 0x1f;
old_y_mod = y_map & 0x1f;
}
else
if (gMultiplayerLevels)
{
InitMultiplayerMap();
return;
}
SetMapPos();
tilehnum = overlaidmaps[GameLevel].width / 32;
tpage = 0;
for (c = 0; c < 4; c++)
{
for (d = 0; d < 4; d++)
{
maptile[d][c] = tpage;
LoadMapTile(tpage, (x_map >> 5) + d, (y_map >> 5) + c);
tpage++;
}
}
old_x_mod = x_map & 0x1f;
old_y_mod = y_map & 0x1f;
}
@ -854,7 +812,7 @@ void DrawOverheadMap(void)
short uVar7;
short uVar8;
unsigned char uVar10;
short *psVar11;
short *playerFelony;
TILE_1 *tile1;
POLY_F4 *polyf4;
int x;
@ -910,66 +868,57 @@ void DrawOverheadMap(void)
VECTOR translate = { 280, 0, 212 };
if (gMultiplayerLevels != 0)
if (gMultiplayerLevels)
{
DrawMultiplayerMap();
return;
}
if (1 < NumPlayers)
if (NumPlayers > 1)
return;
SetMapPos();
uVar28 = x_map & 0x1f;
uVar30 = y_map & 0x1f;
SetMapPos();
draw_box();
if (0 < player_position_known)
// flash the overhead map
if (player_position_known > 0)
{
if (player[0].playerCarId < 0)
psVar11 = &pedestrianFelony;
playerFelony = &pedestrianFelony;
else
psVar11 = &car_data[player[0].playerCarId].felonyRating;
playerFelony = &car_data[player[0].playerCarId].felonyRating;
if (*psVar11 > FELONY_MIN_VALUE)
{
if (*playerFelony > FELONY_MIN_VALUE)
FlashOverheadMap(ptab[CameraCnt & 0xf], 0, ptab[CameraCnt + 8U & 0xf]);
goto LAB_00016fac;
}
}
if (player_position_known == -1)
{
if (flashtimer == 0)
{
if (player[0].playerCarId < 0)
psVar11 = &pedestrianFelony;
else
psVar11 = &car_data[player[0].playerCarId].felonyRating;
if (*psVar11 > FELONY_MIN_VALUE)
flashtimer = 48;
goto LAB_00016ee8;
}
}
else
{
LAB_00016ee8:
if (flashtimer == 0)
goto LAB_00016fac;
if (player_position_known == -1)
{
if (flashtimer == 0)
{
if (player[0].playerCarId < 0)
playerFelony = &pedestrianFelony;
else
playerFelony = &car_data[player[0].playerCarId].felonyRating;
if (*playerFelony > FELONY_MIN_VALUE)
flashtimer = 48;
}
}
if (flashtimer)
{
flashtimer--;
r = -flashtimer;
r = ptab2[r + 47 >> 2] + ptab2[r + 48 >> 2] + ptab2[r + 49 >> 2] + ptab2[r + 50 >> 2];
r = r >> 2;
FlashOverheadMap(r, r, r);
}
}
flashtimer--;
r = -flashtimer;
r = ptab2[r + 47 >> 2] + ptab2[r + 48 >> 2] + ptab2[r + 49 >> 2] + ptab2[r + 50 >> 2];
r = r >> 2;
FlashOverheadMap(r, r, r);
LAB_00016fac:
drarea = (DR_AREA *)current->primptr;
SetDrawArea(drarea, &current->draw.clip);
@ -978,14 +927,14 @@ LAB_00016fac:
WorldToOverheadMapPositions((VECTOR *)player->pos, &vec, 1, 0, 0);
if (((vec.vx - 0xe9U < 0x5f) && (0xad < vec.vz)) && (vec.vz < 0xfb))
if (vec.vx - 233U < 95 && vec.vz > 173 && vec.vz < 251)
{
tile1 = (TILE_1 *)current->primptr;
setTile1(tile1);
tile1->r0 = -1;
tile1->g0 = -1;
tile1->b0 = -1;
tile1->r0 = 255;
tile1->g0 = 255;
tile1->b0 = 255;
tile1->x0 = vec.vx;
tile1->y0 = vec.vz;
@ -998,17 +947,20 @@ LAB_00016fac:
DrawCompass();
DrawOverheadTargets();
sVar3 = -uVar30;
// draw cop sight
cp = car_data;
do {
if (cp->controlType == CONTROL_TYPE_PURSUER_AI && cp->ai.p.dying == 0 || (cp->controlFlags & 1) != 0)
if (cp->controlType == CONTROL_TYPE_PURSUER_AI && cp->ai.p.dying == 0 || (cp->controlFlags & CONTROL_FLAG_COP))
DrawSightCone(&copSightData, (VECTOR *)cp->hd.where.t, cp->hd.direction);
cp++;
} while (cp <= &car_data[MAX_CARS]);
uVar28 = x_map & 0x1f;
uVar30 = y_map & 0x1f;
sVar2 = -uVar28;
sVar3 = -uVar30;
// X axis
if ((uVar28 < 16) && (old_x_mod > 16))
@ -1024,7 +976,7 @@ LAB_00016fac:
maptile[2][r] = maptile[3][r];
maptile[3][r] = bVar1;
LoadMapTile(bVar1, x_map / 32 + 3, y_map / 32 + r);
LoadMapTile(bVar1, (x_map >> 5) + 3, (y_map >> 5) + r);
r++;
} while (r < 4);
@ -1043,7 +995,7 @@ LAB_00016fac:
maptile[1][r] = maptile[0][r];
maptile[0][r] = bVar1;
LoadMapTile(bVar1, x_map / 32, y_map / 32 + r);
LoadMapTile(bVar1, (x_map >> 5), (y_map >> 5) + r);
r++;
} while (r < 4);
}
@ -1061,7 +1013,7 @@ LAB_00016fac:
maptile[r][2] = maptile[r][3];
maptile[r][3] = bVar1;
LoadMapTile(bVar1, x_map / 32 + r, y_map / 32 + 3);
LoadMapTile(bVar1, (x_map >> 5) + r, (y_map >> 5) + 3);
r++;
} while (r < 4);
}
@ -1078,7 +1030,7 @@ LAB_00016fac:
maptile[r][1] = maptile[r][0];
maptile[r][0] = bVar1;
LoadMapTile(bVar1, x_map / 32 + r, y_map / 32);
LoadMapTile(bVar1, (x_map >> 5) + r, (y_map >> 5));
r++;
} while (r < 4);
}
@ -1202,7 +1154,7 @@ LAB_00016fac:
pbVar25 = (char*)maptile + y;
plVar18 = &((VECTOR*)MapMeshO)[5].vz + iVar27 * 4;
plVar16 = &((VECTOR*)MapMeshO)[5].vz + y * 4;
psVar11 = &MapTex[0].w;
playerFelony = &MapTex[0].w;
while (y_00 < r)
{
@ -1258,7 +1210,7 @@ LAB_00016fac:
local_a3_2816->u3 = MapTex[y_00].u + MapSegmentPos[*pbVar25].x * 4 + cVar22;
local_a3_2816->v3 = MapTex[y].v + MapSegmentPos[*pbVar25].y + cVar20;
psVar11 = psVar11 + 4;
playerFelony = playerFelony + 4;
plVar16 = plVar16 + 0x14;
plVar18 = plVar18 + 0x14;
pbVar25 = pbVar25 + 4;

View File

@ -686,14 +686,45 @@ void DrawPauseMenus(void)
void SaveReplay(int direction)
{
char filename[64];
#ifdef PSX
CallMemoryCard(0x10, 1);
#else
int size = SaveReplayToBuffer(_other_buffer);
FILE* fp = fopen("chase.d2rp", "wb");
#ifdef CUTSCENE_RECORDER
extern int gCutsceneAsReplay;
if(gCutsceneAsReplay != 0)
{
FILE* temp;
int cnt;
cnt = 2;
while(cnt < 14)
{
sprintf(filename, "CUT%d_%d.D2RP", gCutsceneAsReplay, cnt);
temp = fopen(filename, "rb");
if (temp)
{
fclose(temp);
cnt++;
}
else
break;
}
}
else
{
sprintf(filename, "CHASE.D2RP", gCurrentMissionNumber);
}
#else
sprintf(filename, "CHASE.D2RP", gCurrentMissionNumber);
#endif
FILE* fp = fopen(filename, "wb");
if (fp)
{
printInfo("Saving replay '%s'\n", filename);
fwrite(_other_buffer, 1, size, fp);
fclose(fp);
}

View File

@ -8,18 +8,18 @@
extern TEXTURE_DETAILS digit_texture;
FONT_DIGIT fontDigit[] = {
{ 2, 0xE },
{ 0x11, 0xE},
{ 0x20, 0x10},
{ 0x31, 0xF},
{ 0x41, 0xE },
{ 0x50, 0xE },
{ 4, 0x10 },
{ 0x15, 0xE },
{ 0x24, 0xF },
{ 0x34, 0x11 },
{ 0x46, 0xB },
{ 0x52, 7 },
{ 2, 14 },
{ 17, 14},
{ 32, 16},
{ 49, 15},
{ 65, 14 },
{ 80, 14 },
{ 4, 16 },
{ 21, 14 },
{ 36, 15 },
{ 52, 17 },
{ 70, 11 },
{ 82, 7 },
};
TEXTURE_DETAILS button_textures[11];

View File

@ -12,6 +12,7 @@
#include "CIV_AI.H"
#include "STRINGS.H"
#include "RAND.H"
char AnalogueUnpack[16] = {
0, -51, -63, -75, -87, -99, -111, -123,
@ -378,17 +379,17 @@ int LoadCutsceneAsReplay(int subindex)
return 0;
}
void LoadCutsceneRecorder()
void LoadCutsceneRecorder(char* configFilename)
{
ini_t* config;
int loadExistingCutscene;
int subindex;
config = ini_load("cutscene_recorder.ini");
config = ini_load(configFilename);
if(!config)
{
printError("Unable to open 'cutscene_recorder.ini!'\n");
printError("Unable to open '%s'!\n", configFilename);
return;
}
@ -586,7 +587,25 @@ int LoadReplayFromBuffer(char *buffer)
return 1;
}
#ifndef PSX
int LoadUserAttractReplay(int mission, int userId)
{
char customFilename[64];
if (userId >= 0 && userId < gNumUserChases)
{
sprintf(customFilename, "REPLAYS\\User\\%s\\ATTRACT.%d", gUserReplayFolderList[userId], mission);
if (FileExists(customFilename))
{
if (Loadfile(customFilename, _other_buffer))
return LoadReplayFromBuffer(_other_buffer);
}
}
return 0;
}
#endif
// decompiled code
// original method signature:
@ -616,7 +635,26 @@ int LoadAttractReplay(int mission)
{
char filename[32];
sprintf(filename,"REPLAYS\\ATTRACT.%d", mission);
#ifndef PSX
int userId = -1;
// [A] REDRIVER2 PC - custom attract replays
if (gNumUserChases)
{
userId = rand() % (gNumUserChases + 1);
if (userId == gNumUserChases)
userId = -1;
}
if (LoadUserAttractReplay(mission, userId))
{
printInfo("Loaded custom attract replay (%d) by %s\n", mission, gUserReplayFolderList[userId]);
return 1;
}
#endif
sprintf(filename, "REPLAYS\\ATTRACT.%d", mission);
if (!FileExists(filename))
return 0;
@ -675,6 +713,10 @@ char GetPingInfo(char *cookieCount)
PingBufferPos++;
}
else
{
printInfo("-1 frame!\n");
}
return retCarId;
}
@ -694,7 +736,12 @@ int StorePingInfo(int cookieCount, int carId)
{
packet = &PingBuffer[PingBufferPos++];
packet->frame = (CameraCnt - frameStart & 0xffffU);
packet->carId = carId;
if(carId == 1)
packet->carId = MAX_CARS-1;
else
packet->carId = carId;
packet->cookieCount = cookieCount;
return 1;

View File

@ -110,7 +110,7 @@ int chunk_complete;
int new_area_location;
int LoadingArea = 0;
unsigned short *newmodels;
unsigned short *newmodels = NULL;
SPOOLQ spooldata[48];
@ -1168,6 +1168,8 @@ void InitSpooling(void)
ClearRegion(i);
}
CleanSpooledModelSlots();
newmodels = NULL;
spool_regioncounter = 0;
spoolerror = 0;
@ -1727,17 +1729,30 @@ void SetupModels(void)
// [D] [T]
void LoadInAreaModels(int area)
{
if (newmodels)
int i;
MODEL* model;
int nmodels;
unsigned short* new_model_numbers;
int model_number;
if(newmodels)
{
// clear old model ids
int nmodels = *newmodels;
unsigned short* new_model_numbers = newmodels + 1;
nmodels = *newmodels;
new_model_numbers = newmodels + 1;
// set old model ids to dummy
for (int i = 0; i < nmodels; i++)
for (i = 0; i < nmodels; i++)
{
int model_number = new_model_numbers[i];
modelpointers[model_number] = &dummyModel;
model_number = new_model_numbers[i];
model = modelpointers[model_number];
if(model->shape_flags & 0x8000)
{
modelpointers[model_number] = &dummyModel;
pLodModels[model_number] = &dummyModel;
}
}
SPOOL_INFO("freed %d model slots\n", nmodels);

View File

@ -1003,7 +1003,8 @@ void SwapDrawBuffers2(int player)
DrawSync(0);
if (player == 0) {
if (player == 0)
{
PutDispEnv(&current->disp);
}
@ -1265,6 +1266,8 @@ void SetupDrawBufferData(int num_players)
// [D] [T]
void InitaliseDrawEnv(DB* pBuff, int x, int y, int w, int h)
{
RECT16 clipRect;
SetDefDrawEnv(&pBuff[0].draw, x, y + 256, w, h);
SetDefDrawEnv(&pBuff[1].draw, x, y, w, h);

View File

@ -426,14 +426,10 @@ void DrawStopZone(VECTOR *pPosition)
pPoly->g0 = 64;
pPoly->b0 = 64;
pPoly->u0 = light_texture.coords.u0;
pPoly->v0 = light_texture.coords.v0;
pPoly->u1 = light_texture.coords.u1;
pPoly->v1 = light_texture.coords.v1;
pPoly->u2 = light_texture.coords.u2;
pPoly->v2 = light_texture.coords.v2;
pPoly->u3 = light_texture.coords.u3;
pPoly->v3 = light_texture.coords.v3;
*(ushort*)&pPoly->u0 = *(ushort*)&light_texture.coords.u0;
*(ushort*)&pPoly->u1 = *(ushort*)&light_texture.coords.u1;
*(ushort*)&pPoly->u2 = *(ushort*)&light_texture.coords.u2;
*(ushort*)&pPoly->u3 = *(ushort*)&light_texture.coords.u3;
if (gTimeOfDay == 3)
pPoly->tpage = light_texture.tpageid | 0x20;

View File

@ -10,6 +10,7 @@
#include "SYSTEM.H"
#ifndef PSX
#include "STRINGS.H"
#include "../utils/riff.h"
#include "../utils/audio_source/snd_al_source.h"
@ -49,6 +50,16 @@ static unsigned long buffer[8];
XA_TRACK XAMissionMessages[4];
#ifndef PSX
struct XA_SUBTITLE
{
char text[48];
int startframe;
int endframe;
};
XA_SUBTITLE gXASubtitles[30];
int gNumXASubtitles = 0;
int gXASubtitleTime = 0;
int gXASubtitlePauseTime = 0;
@ -63,12 +74,12 @@ void PrintXASubtitles()
int curTime = (VSync(-1) - gXASubtitleTime) * 17;
// find subtitles
for(int i = 0; i < g_wavData->m_numSubtitles; i++)
for(int i = 0; i < gNumXASubtitles; i++)
{
CUESubtitle_t* sub = &g_wavData->m_subtitles[i];
XA_SUBTITLE* sub = &gXASubtitles[i];
int subStartFrame = sub->sampleStart;
int subEndFrame = sub->sampleStart + sub->sampleLength;
int subStartFrame = sub->startframe;
int subEndFrame = sub->endframe;
if(curTime >= subStartFrame && curTime <= subEndFrame)
{
@ -347,6 +358,48 @@ void PlayXA(int num, int index)
if (g_wavData->Load(fileName))
{
#if 0
// Save subtitles file
{
sprintf(fileName, "%sXA\\XABNK0%d.XA[%d].SBN", gDataFolder, num + 1, index);
FILE* fp = fopen(fileName, "wb");
if (fp)
{
int numSubtitles = g_wavData->m_numSubtitles;
XA_SUBTITLE subtitles[30];
// save subtitle count
fwrite(&numSubtitles, sizeof(int), 1, fp);
for (int i = 0; i < numSubtitles; i++)
{
CUESubtitle_t* sub = &g_wavData->m_subtitles[i];
strcpy(subtitles[i].text, sub->text);
subtitles[i].startframe = sub->sampleStart;
subtitles[i].endframe = sub->sampleStart + sub->sampleLength;
}
// write all subtitles
fwrite(subtitles, sizeof(XA_SUBTITLE), numSubtitles, fp);
fclose(fp);
}
}
#else
// Load subtitles for XA
sprintf(fileName, "%sXA\\XABNK0%d.XA[%d].SBN", gDataFolder, num + 1, index);
FILE* fp = fopen(fileName, "rb");
if (fp)
{
fread(&gNumXASubtitles, sizeof(int), 1, fp);
fread(gXASubtitles, sizeof(XA_SUBTITLE), gNumXASubtitles, fp);
fclose(fp);
}
#endif
g_XAWave = new CSoundSource_OpenALCache(g_wavData);
alSourcei(g_XASource, AL_BUFFER, g_XAWave->m_alBuffer);

View File

@ -16,6 +16,7 @@
#include "C/PRES.H"
#include "C/SOUND.H"
#include "C/DEBRIS.H"
#include "C/E3STUFF.H"
#include "C/FMVPLAY.H"
#include "C/SCORES.H"
#include "C/LOADSAVE.H"
@ -48,7 +49,7 @@ screenFunc fpUserFunctions[] = {
GamePlayScreen,
GameNameScreen,
CheatNumlayerSelect,
BonusGalleryScreen
};
char* gfxNames[4] = {
@ -337,7 +338,7 @@ void SetVariable(int var)
#ifdef PSX
if (CallMemoryCard(0x11, 0) == 0)
#else
if(LoadReplayFromFile("chase.d2rp") == 0) // [A] temporary
if(LoadReplayFromFile("CHASE.D2RP") == 0) // [A] temporary
#endif
{
ReInitFrontend();
@ -412,6 +413,12 @@ void SetVariable(int var)
GameType = GAME_IDLEDEMO;
gCurrentMissionNumber = (value + 400);
break;
case 14: // [A]
{
ShowBonusGallery();
LoadFrontendScreens();
}
}
}
@ -1041,25 +1048,30 @@ void SetupExtraPoly(char *fileName, int offset, int offset2)
FEDrawCDicon();
Loadfile(fileName, _frontend_buffer + offset2);
setSprt(&extraSprt);
setXY0(&extraSprt, 100, 226);
setRGB0(&extraSprt, 128, 128, 128);
setUV0(&extraSprt, 0, 0);
setWH(&extraSprt, 255, 219);
setClut(&extraSprt, 960, 256);
rect.x = 896;
rect.y = 256;
rect.w = 64;
rect.h = 219;
LoadImage(&rect, (u_long *)(_frontend_buffer + offset2 + offset * 0x8000));
DrawSync(0);
VSync(0);
setPolyFT3(&extraDummy);
setXY3(&extraDummy, -1, -1, -1, -1, -1, -1);
setTPage(&extraDummy, 0, 0, 896, 256);
if(bDrawExtra == 0)
{
setSprt(&extraSprt);
setPolyFT3(&extraDummy);
setXY0(&extraSprt, 100, 226);
setRGB0(&extraSprt, 128, 128, 128);
setUV0(&extraSprt, 0, 0);
setWH(&extraSprt, 255, 219);
setClut(&extraSprt, 960, 256);
setXY3(&extraDummy, -1, -1, -1, -1, -1, -1);
setTPage(&extraDummy, 0, 0, 896, 256);
}
bDrawExtra = 1;
@ -1417,12 +1429,10 @@ int HandleKeyPress(void)
{
if (ScreenDepth > 0)
{
if (!bDoneAllready) {
if (!bDoneAllready)
FESound(0);
}
else {
else
bDoneAllready = 0;
}
if (--ScreenDepth == 0)
{
@ -3485,6 +3495,7 @@ int CutSceneCitySelectScreen(int bSetup)
LoadImage(&rect, (u_long *)_frontend_buffer);
DrawSync(0);
#ifdef PSX
DisplayOnScreenText();
@ -4284,11 +4295,11 @@ int CheatScreen(int bSetup)
0x121,
0x11E,
0x11F,
(40 & 0xFF) | (1 << 8)
0,
};
int hackLookup2[5] = {
0xC01, 0xC00, -1, -1, -1
0xC01, 0xC00, -1, -1, 0xE00
};
if (bSetup == 0)
@ -4439,77 +4450,6 @@ int CheatScreen(int bSetup)
return 0;
}
int g_GalleryImage = 0;
char* GalleryImageNames[] = {
"GFX\\GAL\\IMG1.TIM",
"GFX\\GAL\\IMG2.TIM",
"GFX\\GAL\\IMG3.TIM"
};
// [A]
int BonusGalleryScreen(int bSetup)
{
char tmpStr[64];
int imageChanged;
RECT16 rect;
imageChanged = 0;
if(bSetup)
{
bDoingScores = 1;
g_GalleryImage = 0;
imageChanged = 1;
}
if (fePad & 0x10)
{
// goint back
bDoingScores = 0;
LoadFrontendScreens();
//LoadBackgroundFile("DATA\\GFX.RAW");
}
else if(fePad & 0x8000)
{
imageChanged = 1;
g_GalleryImage--;
if (g_GalleryImage < 0)
g_GalleryImage = 2;
FESound(3);
}
else if(fePad & 0x2000)
{
imageChanged = 1;
g_GalleryImage++;
if (g_GalleryImage > 2)
g_GalleryImage = 0;
FESound(3);
}
if(imageChanged)
{
FEDrawCDicon();
LoadfileSeg(GalleryImageNames[g_GalleryImage], _overlay_buffer, 20, 0x4ff80);
LoadClut((u_long*)_overlay_buffer, 640, 511);
DrawSync(0);
setRECT16(&rect, 640, 0, 320, 511);
LoadImage(&rect, (u_long*)&_overlay_buffer[512]);
DrawSync(0);
}
//sprintf(tmpStr, "Gallery %d of %d", g_GalleryImage + 1, 3);
//FEPrintStringSized(tmpStr, 10, 10, 4, 0, 128, 64, 0 );
return 0;
}
// decompiled code
// original method signature:

View File

@ -1,7 +1,7 @@
#ifndef VERSION_H
#define VERSION_H
#define GAME_VERSION_N "3.4 alpha"
#define GAME_VERSION_N "4.2 alpha"
#define GAME_TITLE "REDRIVER2"
#define GAME_VERSION GAME_TITLE " " GAME_VERSION_N

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include <SDL_scancode.h>
#include "C/CUTSCENE.H"
// eq engine console output
@ -355,7 +356,7 @@ void GameDebugKeys(int nKey, bool down)
#ifndef USE_CRT_MALLOC
char g_Overlay_buffer[0x50000]; // 0x1C0000
char g_Frontend_buffer[0x50000]; // 0xFB400
char g_Frontend_buffer[0x60000]; // 0xFB400
char g_Other_buffer[0x50000]; // 0xF3000
char g_Other_buffer2[0x50000]; // 0xE7000
OTTYPE g_OT1[OTSIZE]; // 0xF3000
@ -371,7 +372,7 @@ int main(int argc, char** argv)
#ifdef USE_CRT_MALLOC
_overlay_buffer = (char*)malloc(0x50000); // 0x1C0000
_frontend_buffer = (char*)malloc(0x50000); // 0xFB400
_frontend_buffer = (char*)malloc(0x60000); // 0xFB400
_other_buffer = (char*)malloc(0x50000); // 0xF3000
_other_buffer2 = (char*)malloc(0x50000); // 0xE7000
_OT1 = (OTTYPE*)malloc(OTSIZE * sizeof(OTTYPE)); // 0xF3000
@ -412,6 +413,9 @@ int main(int argc, char** argv)
if (config)
{
const char* dataFolderStr = ini_get(config, "fs", "dataFolder");
const char* userReplaysStr = ini_get(config, "game", "userChases");
InitUserReplays(userReplaysStr);
ini_sget(config, "render", "windowWidth", "%d", &windowWidth);
ini_sget(config, "render", "windowHeight", "%d", &windowHeight);
@ -422,7 +426,6 @@ int main(int argc, char** argv)
ini_sget(config, "game", "drawDistance", "%d", &gDrawDistance);
ini_sget(config, "game", "freeCamera", "%d", &enableFreecamera);
ini_sget(config, "game", "driver1music", "%d", &gDriver1Music);
if (dataFolderStr)
{

View File

@ -1,11 +1,11 @@
#include "ReadAVI.h" // WTF, ostream/fstream
#include <EMULATOR.H>
#include <EMULATOR_TIMER.H>
#include "DRIVER2.H"
#include "C/PAD.H"
#include "C/SYSTEM.H"
#include "C/E3STUFF.H"
#include "C/PRES.H"
#include "C/PAUSE.H"
#include "STRINGS.H"
@ -14,7 +14,257 @@
#include <AL/al.h>
#include <jpeglib.h>
struct UVWH
{
uchar u, v;
uchar w, h;
};
struct FMV_FONT
{
uchar u, v;
uchar w, h;
short unk1;
};
// TODO: NEED SAVE
UVWH fontUV[256] =
{
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 222, 18, 3, 18 }, { 22, 36, 5, 18 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 94, 54, 6, 18 }, { 70, 54, 3, 18 },
{ 10, 36, 4, 18 }, { 16, 36, 4, 18 }, { 0, 0, 0, 0 }, { 34, 36, 6, 18 },
{ 246, 18, 2, 18 }, { 28, 36, 4, 18 }, { 0, 36, 2, 18 }, { 4, 36, 5, 18 },
{ 144, 18, 6, 18 }, { 152, 18, 4, 18 }, { 158, 18, 6, 18 }, { 166, 18, 6, 18 },
{ 174, 18, 7, 18 }, { 182, 18, 6, 18 }, { 190, 18, 6, 18 }, { 198, 18, 6, 18 },
{ 206, 18, 6, 18 }, { 214, 18, 6, 18 }, { 42, 36, 2, 18 }, { 66, 54, 3, 18 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 226, 18, 6, 18 },
{ 0, 0, 0, 0 }, { 0, 0, 7, 18 }, { 8, 0, 6, 18 }, { 16, 0, 6, 18 },
{ 24, 0, 6, 18 }, { 32, 0, 6, 18 }, { 40, 0, 5, 18 }, { 46, 0, 6, 18 },
{ 54, 0, 6, 18 }, { 62, 0, 3, 18 }, { 66, 0, 6, 18 }, { 74, 0, 6, 18 },
{ 82, 0, 5, 18 }, { 88, 0, 9, 18 }, { 98, 0, 6, 18 }, { 106, 0, 6, 18 },
{ 114, 0, 6, 18 }, { 122, 0, 6, 18 }, { 130, 0, 7, 18 }, { 138, 0, 7, 18 },
{ 146, 0, 6, 18 }, { 154, 0, 6, 18 }, { 162, 0, 7, 18 }, { 170, 0, 10, 18 },
{ 182, 0, 7, 18 }, { 190, 0, 7, 18 }, { 198, 0, 6, 18 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 206, 0, 6, 18 }, { 214, 0, 6, 18 }, { 222, 0, 5, 18 },
{ 228, 0, 5, 18 }, { 234, 0, 6, 18 }, { 242, 0, 5, 18 }, { 248, 0, 6, 18 },
{ 0, 18, 6, 18 }, { 8, 18, 3, 18 }, { 12, 18, 4, 18 }, { 18, 18, 6, 18 },
{ 26, 18, 3, 18 }, { 30, 18, 9, 18 }, { 40, 18, 6, 18 }, { 48, 18, 6, 18 },
{ 56, 18, 6, 18 }, { 64, 18, 6, 18 }, { 72, 18, 6, 18 }, { 80, 18, 6, 18 },
{ 88, 18, 5, 18 }, { 94, 18, 6, 18 }, { 102, 18, 7, 18 }, { 110, 18, 9, 18 },
{ 120, 18, 6, 18 }, { 128, 18, 7, 18 }, { 136, 18, 6, 18 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 238, 18, 6, 18 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 38, 54, 3, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 30, 54, 6, 18 },
{ 50, 36, 8, 18 }, { 60, 36, 7, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 68, 36, 7, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 152, 36, 6, 18 },
{ 76, 36, 5, 18 }, { 82, 36, 5, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 88, 36, 3, 18 }, { 92, 36, 3, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 144, 36, 7, 18 }, { 96, 36, 6, 18 }, { 104, 36, 7, 18 },
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 112, 36, 6, 18 }, { 0, 0, 0, 0 },
{ 120, 36, 7, 18 }, { 0, 0, 0, 0 }, { 128, 36, 6, 18 }, { 0, 0, 0, 0 },
{ 136, 36, 6, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 22, 54, 7, 18 },
{ 160, 36, 5, 18 }, { 166, 36, 6, 18 }, { 0, 54, 5, 18 }, { 0, 0, 0, 0 },
{ 174, 36, 5, 18 }, { 0, 0, 0, 0 }, { 84, 54, 8, 18 }, { 250, 36, 5, 18 },
{ 180, 36, 6, 18 }, { 188, 36, 6, 18 }, { 6, 54, 6, 18 }, { 0, 0, 0, 0 },
{ 196, 36, 3, 18 }, { 200, 36, 3, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 50, 54, 6, 18 }, { 204, 36, 6, 18 }, { 212, 36, 6, 18 },
{ 58, 54, 6, 18 }, { 0, 0, 0, 0 }, { 220, 36, 6, 18 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 }, { 228, 36, 6, 18 }, { 236, 36, 6, 18 }, { 14, 54, 6, 18 },
{ 244, 36, 5, 18 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }
};
FMV_FONT font[256];
// Partially decompiled function from FMV EXE
void InitFMVFont()
{
int i;
RECT16 fontRect;
Loadfile("FMV\\FONT.TIM", _other_buffer);
//fontRect.x = 512;
//fontRect.y = 0;
//fontRect.w = 384;
//fontRect.h = 72;
//DrawSync(0);
//LoadImage2(&fontRect,(u_long *)(_other_buffer + 20));
//DrawSync(0);
DrawSync(0);
LoadClut((u_long *)(_other_buffer + 20),960,72);
DrawSync(0);
fontRect.x = 960;
fontRect.y = 0;
fontRect.w = 64;
fontRect.h = 72;
LoadImage2(&fontRect,(u_long *)(_other_buffer + 64));
DrawSync(0);
/*
i = 0;
while (i < 256)
{
font[i].u = fontUV[i].u + (fontUV[i].u >> 1);
font[i].w = fontUV[i].w + (fontUV[i].w >> 1);
if (fontUV[i].w & 1)
font[i].w += 1;
if (i == 46)
font[i].w += 1;
if (font[i].u + font[i].w < 256)
{
font[i].unk1 = 0x108;
}
else if (font[i].u >= 256)
{
font[i].unk1 = 0x10c;
}
else if (font[i].u + font[i].w > 255)
{
font[i].unk1 = 0x109;
font[i].u -= 64;
}
//font[i].u = local_14;
font[i].v = fontUV[i].v;
font[i].h = fontUV[i].h;
i = i + 1;
}
font[180].u = font[39].u;
font[180].v = font[39].v;
font[180].unk1 = font[39].unk1;
font[146].u = font[39].u;
font[146].v = font[39].v;
font[146].unk1 = font[39].unk1;
*/
i = 0;
while (i < 256)
{
font[i].u = fontUV[i].u;
font[i].v = fontUV[i].v;
font[i].w = fontUV[i].w;
font[i].h = fontUV[i].h;
i++;
}
}
POLY_FT4 fmvTextPolys[512];
// partially decompiled
void PrintFMVText(char *str, int x, short y, int brightness)
{
char chr;
char *ptr;
int x_ofs;
int i;
int str_w;
int drawnChars;
OTTYPE ot;
POLY_FT4* poly;
ClearOTagR((ulong*)&ot, 1);
poly = fmvTextPolys;
str_w = 0;
if (brightness > 128)
brightness = 128;
i = 0;
while (chr = str[i], chr != 0)
{
if (chr == 32)
str_w += 4;
else
str_w += font[chr].w;
i++;
}
x_ofs = x - str_w / 2;
drawnChars = 0;
ptr = (char *)str;
while( true )
{
chr = *ptr;
ptr++;
if (chr == 0 || drawnChars > 511)
break;
if (chr == 32) // space
{
x_ofs += 4;
}
else
{
setPolyFT4(poly);
poly->x0 = x_ofs;
poly->y0 = y;
poly->x1 = x_ofs + font[chr].w;
poly->y1 = y;
poly->x2 = x_ofs;
poly->y2 = y + font[chr].h;
poly->x3 = x_ofs + font[chr].w;
poly->y3 = y + font[chr].h;
poly->u0 = font[chr].u;
poly->v0 = font[chr].v;
poly->u1 = font[chr].u + font[chr].w;
poly->v1 = font[chr].v;
poly->u2 = font[chr].u;
poly->v2 = font[chr].v + font[chr].h;
poly->u3 = font[chr].u + font[chr].w;
poly->v3 = font[chr].v + font[chr].h;
poly->tpage = getTPage(0,0, 960, 0);
poly->clut = getClut(960, 72);
poly->r0 = brightness;
poly->g0 = brightness;
poly->b0 = brightness;
addPrim(&ot, poly);
x_ofs += font[chr].w;
drawnChars++;
poly++;
}
}
DrawOTag((ulong*)&ot);
}
int UnpackJPEG(unsigned char* src_buf, unsigned src_length, unsigned bpp, unsigned char* dst_buf)
{
@ -164,6 +414,15 @@ void FMVPlayerInitGL()
void FMVPlayerShutdownGL()
{
RECT16 rect;
rect.x = 0;
rect.y = 0;
rect.w = 512;
rect.h = 256;
ClearImage(&rect, 0, 0, 0);
Emulator_SwapWindow();
Emulator_DestroyTexture(g_FMVTexture);
}
@ -178,7 +437,7 @@ struct SUBTITLE
char text[32];
};
SUBTITLE g_Subtitles[512];
SUBTITLE g_Subtitles[128];
int g_NumSubtitles = 0;
void InitSubtitles(const char* filename)
@ -188,7 +447,6 @@ void InitSubtitles(const char* filename)
if (subFile)
{
fread(&g_NumSubtitles, sizeof(int), 1, subFile);
printInfo("Subtitle text count: %d\n", g_NumSubtitles);
fread(g_Subtitles, sizeof(g_Subtitles), g_NumSubtitles, subFile);
@ -196,10 +454,59 @@ void InitSubtitles(const char* filename)
}
}
char* g_CreditsBuffer = NULL;
char* g_CreditsLines[512];
void InitCredits(const char* filename)
{
memset(g_CreditsLines, 0, sizeof(g_CreditsLines));
FILE* credFile = fopen(filename, "rb");
if (credFile)
{
fseek(credFile, 0, SEEK_END);
int credits_buffer_size = ftell(credFile);
fseek(credFile, 0, SEEK_SET);
g_CreditsBuffer = (char*)malloc(credits_buffer_size + 1);
fread(g_CreditsBuffer, 1, credits_buffer_size, credFile);
g_CreditsBuffer[credits_buffer_size] = 0;
fclose(credFile);
}
if(g_CreditsBuffer)
{
// make credits into lines
char* str = g_CreditsBuffer;
int numCreditsLines = 0;
while(*str)
{
if(!g_CreditsLines[numCreditsLines])
g_CreditsLines[numCreditsLines] = str;
if(*str == '\r')
{
*str = '\0';
if (*++str == '\n')
numCreditsLines++;
}
else if(*str == '\n')
{
*str = '\0';
numCreditsLines++;
}
str++;
}
}
}
void PrintSubtitleText(SUBTITLE* sub)
{
gShowMap = 1;
char* str = sub->text;
// skip some trailing spaces
@ -207,10 +514,7 @@ void PrintSubtitleText(SUBTITLE* sub)
str++;
}
SetTextColour(128, 128, 128);
PrintString(str, (600 - StringWidth(str)) * 0x8000 >> 0x10, sub->y - 25);
gShowMap = 0;
PrintFMVText(str, 256, sub->y - 25, 128);
}
void DisplaySubtitles(int frame_number)
@ -223,9 +527,46 @@ void DisplaySubtitles(int frame_number)
}
}
#define CREDITS_START_FRAME 700
#define CREDITS_STOP_FRAME 5450
#define CREDITS_FADE_START_FRAME 5900
void DisplayCredits(int frame_number)
{
int i;
int frame = frame_number;
if (frame > CREDITS_STOP_FRAME)
frame = CREDITS_STOP_FRAME;
int height = (frame - CREDITS_START_FRAME) * 30 >> 5;
int fade = 0;
if (frame_number > CREDITS_FADE_START_FRAME)
{
fade = (frame_number - CREDITS_FADE_START_FRAME) * 2;
if (fade > 128)
fade = 128;
}
for(i = 0; i < 512; i++)
{
int text_h = 250 - height + i * 16;
if (text_h < -20 || text_h > 260)
continue;
char* str = g_CreditsLines[i];
if(str)
PrintFMVText(str, 256, text_h, 128 - fade);
}
}
extern void Emulator_Ortho2D(float left, float right, float bottom, float top, float znear, float zfar);
void DrawFrame(ReadAVI::stream_format_t& stream_format, int frame_number)
void DrawFrame(ReadAVI::stream_format_t& stream_format, int frame_number, int credits)
{
int windowWidth, windowHeight;
Emulator_GetScreenSize(windowWidth, windowHeight);
@ -248,6 +589,11 @@ void DrawFrame(ReadAVI::stream_format_t& stream_format, int frame_number)
DisplaySubtitles(frame_number);
if(credits && frame_number >= CREDITS_START_FRAME)
{
DisplayCredits(frame_number);
}
Emulator_EndScene();
}
@ -261,7 +607,7 @@ void DoPlayFMV(RENDER_ARG* arg, int subtitles)
sprintf(filename, "%sFMV\\%d\\RENDER%d.STR[0].AVI", gDataFolder, fd, arg->render);
ReadAVI readAVI(filename);
// also load subtitle file
if (subtitles)
{
@ -273,6 +619,12 @@ void DoPlayFMV(RENDER_ARG* arg, int subtitles)
g_NumSubtitles = 0;
}
if(arg->credits)
{
sprintf(filename, "%sDATA\\CREDITS.ENG", gDataFolder);
InitCredits(filename);
}
ReadAVI::avi_header_t avi_header = readAVI.GetAviHeader();
ReadAVI::stream_format_t stream_format = readAVI.GetVideoFormat();
@ -294,8 +646,11 @@ void DoPlayFMV(RENDER_ARG* arg, int subtitles)
alGenBuffers(4, audioStreamBuffers);
alSourcei(audioStreamSource, AL_LOOPING, AL_FALSE);
int nextTime = SDL_GetTicks();
int oldTime = nextTime;
timerCtx_t fmvTimer;
Emulator_InitHPCTimer(&fmvTimer);
double nextFrameDelay = 0.0;
int frame_size;
int queue_counter = 0;
@ -303,20 +658,19 @@ void DoPlayFMV(RENDER_ARG* arg, int subtitles)
int fade_out = 0;
int done_frames = 0;
Emulator_GetHPCTime(&fmvTimer, 1);
// main loop
while (true)
{
int curTime = SDL_GetTicks();
int deltaTime = curTime - oldTime;
double delta = Emulator_GetHPCTime(&fmvTimer, 1);
if (deltaTime > 1000)
{
nextTime += deltaTime;
oldTime = curTime;
}
if (delta > 1.0)
delta = 0.0;
nextFrameDelay -= delta;
if (curTime <= nextTime) // wait for frame
if (nextFrameDelay > 0) // wait for frame
{
Emulator_EndScene();
continue;
@ -351,16 +705,16 @@ void DoPlayFMV(RENDER_ARG* arg, int subtitles)
int ret = UnpackJPEG(frame_entry.buf, frame_size, stream_format.bits_per_pixel, (unsigned char*)_frontend_buffer);
if (ret == 0)
DrawFrame(stream_format, done_frames);
{
DrawFrame(stream_format, done_frames, arg->credits);
}
// set next step time
if (g_swapInterval == 0)
nextTime = curTime;
if (g_swapInterval == 1)
nextFrameDelay += double(avi_header.TimeBetweenFrames) / 1000000.0;
else
nextTime += avi_header.TimeBetweenFrames / 1000;
oldTime = curTime;
nextFrameDelay = 0.0;
done_frames++;
}
else if (frame_entry.type == ReadAVI::ctype_audio_data)
@ -400,7 +754,7 @@ void DoPlayFMV(RENDER_ARG* arg, int subtitles)
if (queue_counter < 4)
QueueAudioBuffer(audioStreamBuffers[queue_counter++], audioStreamSource, frame_entry, audio_format, 0, frame_size);
if(queue_counter > 0 && state != AL_PLAYING)
if((queue_counter > 1 || numProcessed == -1) && state != AL_PLAYING)
alSourcePlay(audioStreamSource);
}
}
@ -423,14 +777,27 @@ int FMV_main(RENDER_ARGS* args)
DRAWENV draw;
FMVPlayerInitGL();
LoadFont(NULL);
//LoadFont(NULL);
InitFMVFont();
SetupDefDrawEnv(&draw, 0, 0, 512, 256);
SetupDefDispEnv(&disp, 0, 0, 512, 256);
SetupDefDrawEnv(&draw, 0, 0, 600, 250);
SetupDefDispEnv(&disp, 0, 0, 600, 250);
draw.dfe = 1;
draw.clip.x = -512;
draw.clip.w = 1200;
draw.clip.y = -1;
draw.clip.h = 512;
disp.isinter = 0;
PutDrawEnv(&draw);
PutDispEnv(&disp);
Emulator_SetupClipMode(draw.clip);
for (int i = 0; i < args->nRenders; i++)
{
DoPlayFMV(&args->Args[i], args->subtitle);
@ -438,6 +805,10 @@ int FMV_main(RENDER_ARGS* args)
FMVPlayerShutdownGL();
if (g_CreditsBuffer)
free(g_CreditsBuffer);
g_CreditsBuffer = NULL;
return 0;
}