summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNikolay Korolev <nickvnuk@gmail.com>2019-06-26 22:34:14 +0200
committerNikolay Korolev <nickvnuk@gmail.com>2019-06-26 22:34:14 +0200
commit08b053a568e15dd318dcfc46eaa6393af4a5f8c4 (patch)
tree7e6a0bc15376f347c13029b99f2f0ec1427bf2c1 /src
parentMore replay stuff (diff)
parentbla (diff)
downloadre3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar
re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.gz
re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.bz2
re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.lz
re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.xz
re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.tar.zst
re3-08b053a568e15dd318dcfc46eaa6393af4a5f8c4.zip
Diffstat (limited to 'src')
-rw-r--r--src/FileLoader.cpp7
-rw-r--r--src/Frontend.cpp1150
-rw-r--r--src/Frontend.h455
-rw-r--r--src/MenuScreens.h380
-rw-r--r--src/PCSave.cpp5
-rw-r--r--src/PCSave.h9
-rw-r--r--src/Placeable.cpp71
-rw-r--r--src/Radar.cpp1148
-rw-r--r--src/Radar.h83
-rw-r--r--src/RwHelper.cpp17
-rw-r--r--src/RwHelper.h1
-rw-r--r--src/Streaming.cpp1009
-rw-r--r--src/Streaming.h56
-rw-r--r--src/Timer.h7
-rw-r--r--src/World.cpp2
-rw-r--r--src/World.h2
-rw-r--r--src/animation/AnimBlendAssociation.h5
-rw-r--r--src/audio/AudioManager.cpp17
-rw-r--r--src/audio/AudioManager.h9
-rw-r--r--src/audio/DMAudio.h2
-rw-r--r--src/audio/MusicManager.cpp2
-rw-r--r--src/audio/MusicManager.h1
-rw-r--r--src/config.h4
-rw-r--r--src/control/CarCtrl.cpp2
-rw-r--r--src/control/CarCtrl.h2
-rw-r--r--src/control/Garages.cpp14
-rw-r--r--src/control/PedPlacement.cpp40
-rw-r--r--src/control/PedPlacement.h8
-rw-r--r--src/control/PedType.h4
-rw-r--r--src/control/Replay.cpp20
-rw-r--r--src/entities/Building.cpp1
-rw-r--r--src/entities/Building.h2
-rw-r--r--src/entities/Entity.cpp5
-rw-r--r--src/entities/Entity.h1
-rw-r--r--src/entities/Ped.cpp598
-rw-r--r--src/entities/Ped.h38
-rw-r--r--src/entities/Physical.cpp2
-rw-r--r--src/entities/Vehicle.cpp52
-rw-r--r--src/entities/Vehicle.h93
-rw-r--r--src/main.cpp22
-rw-r--r--src/math/Matrix.h24
-rw-r--r--src/math/Rect.h16
-rw-r--r--src/modelinfo/ModelIndices.h2
-rw-r--r--src/modelinfo/VehicleModelInfo.h10
-rw-r--r--src/render/Font.h24
-rw-r--r--src/render/Hud.cpp49
-rw-r--r--src/render/Hud.h6
-rw-r--r--src/skel/win/win.cpp6
-rw-r--r--src/skel/win/win.h2
-rw-r--r--src/weapons/Weapon.h3
50 files changed, 4811 insertions, 677 deletions
diff --git a/src/FileLoader.cpp b/src/FileLoader.cpp
index f50638b4..dd58614d 100644
--- a/src/FileLoader.cpp
+++ b/src/FileLoader.cpp
@@ -501,7 +501,7 @@ CFileLoader::LoadObjectTypes(const char *filename)
CARS,
PEDS,
PATH,
- TWO2FX
+ TWODFX
};
char *line;
int fd;
@@ -528,7 +528,7 @@ CFileLoader::LoadObjectTypes(const char *filename)
else if(strncmp(line, "cars", 4) == 0) section = CARS;
else if(strncmp(line, "peds", 4) == 0) section = PEDS;
else if(strncmp(line, "path", 4) == 0) section = PATH;
- else if(strncmp(line, "2dfx", 4) == 0) section = TWO2FX;
+ else if(strncmp(line, "2dfx", 4) == 0) section = TWODFX;
}else if(strncmp(line, "end", 3) == 0){
section = section == MLO ? OBJS : NONE;
}else switch(section){
@@ -571,7 +571,7 @@ CFileLoader::LoadObjectTypes(const char *filename)
pathIndex = -1;
}
break;
- case TWO2FX:
+ case TWODFX:
Load2dEffect(line);
break;
}
@@ -848,6 +848,7 @@ CFileLoader::LoadCarPathNode(const char *line, int id, int node)
ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight);
}
+
void
CFileLoader::Load2dEffect(const char *line)
{
diff --git a/src/Frontend.cpp b/src/Frontend.cpp
index b8ee10f4..de9e8a65 100644
--- a/src/Frontend.cpp
+++ b/src/Frontend.cpp
@@ -1,6 +1,25 @@
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
#include "common.h"
#include "patcher.h"
+#include "win.h"
#include "Frontend.h"
+#include "Font.h"
+#include "Pad.h"
+#include "Text.h"
+#include "main.h"
+#include "Timer.h"
+#include "Game.h"
+#include "DMAudio.h"
+#include "MusicManager.h"
+#include "FileMgr.h"
+#include "Streaming.h"
+#include "TxdStore.h"
+#include "General.h"
+#include "PCSave.h"
+#include "Script.h"
+#include "Camera.h"
+#include "MenuScreens.h"
int32 &CMenuManager::OS_Language = *(int32*)0x5F2F78;
int8 &CMenuManager::m_PrefsUseVibration = *(int8*)0x95CD92;
@@ -17,6 +36,7 @@ int8 &CMenuManager::m_PrefsLanguage = *(int8*)0x941238;
bool &CMenuManager::m_PrefsAllowNastyGame = *(bool*)0x5F2E64;
bool &CMenuManager::m_bStartUpFrontEndRequested = *(bool*)0x95CCF4;
+bool &CMenuManager::m_bShutDownFrontEndRequested = *(bool*)0x95CD6A;
int8 &CMenuManager::m_PrefsUseWideScreen = *(int8*)0x95CD23;
int8 &CMenuManager::m_PrefsRadioStation = *(int8*)0x95CDA4;
@@ -29,17 +49,806 @@ int32 &CMenuManager::m_PrefsSfxVolume = *(int32*)0x5F2E48;
CMenuManager &FrontEndMenuManager = *(CMenuManager*)0x8F59D8;
-WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); }
+char *FrontendFilenames[] = {
+ "fe2_mainpanel_ul",
+ "fe2_mainpanel_ur",
+ "fe2_mainpanel_dl",
+ "fe2_mainpanel_dr",
+ "fe2_mainpanel_dr2",
+ "fe2_tabactive",
+ "fe_iconbrief",
+ "fe_iconstats",
+ "fe_iconcontrols",
+ "fe_iconsave",
+ "fe_iconaudio",
+ "fe_icondisplay",
+ "fe_iconlanguage",
+ "fe_controller",
+ "fe_controllersh",
+ "fe_arrows1",
+ "fe_arrows2",
+ "fe_arrows3",
+ "fe_arrows4",
+ "fe_radio1", // HEAD_RADIO
+ "fe_radio2", // DOUBLE_CLEF
+ "fe_radio5", // JAH_RADIO
+ "fe_radio7", // RISE_FM
+ "fe_radio8", // LIPS_106
+ "fe_radio3", // GAME_FM
+ "fe_radio4", // MSX_FM
+ "fe_radio6", // FLASHBACK
+ "fe_radio9", // CHATTERBOX
+};
+
+char *MenuFilenames[] = {
+ "connection24", "",
+ "findgame24", "",
+ "hostgame24", "",
+ "mainmenu24", "",
+ "Playersetup24", "",
+ "singleplayer24", "",
+ "multiplayer24", "",
+ "dmalogo128", "dmalogo128m",
+ "gtaLogo128", "gtaLogo128",
+ "rockstarLogo128", "rockstarlogo128m",
+ "gamespy256", "gamespy256a",
+ "mouse", "mousetimera",
+ "mousetimer", "mousetimera",
+ "mp3logo", "mp3logoA",
+ "downOFF", "buttonA",
+ "downON", "buttonA",
+ "upOFF", "buttonA",
+ "upON", "buttonA",
+ "gta3logo256", "gta3logo256m",
+ nil, nil
+};
+
+#if 1
+WRAPPER void CMenuManager::BuildStatLine(char *, void *, uint16, void *) { EAXJMP(0x483870); }
+#else
+void CMenuManager::BuildStatLine(char *, void *, uint16, void *)
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::CentreMousePointer() { EAXJMP(0x48ACE0); }
+#else
+void CMenuManager::CentreMousePointer()
+{
+ tagPOINT Point;
+
+ if (SCREENW * 0.5f == 0.0f && 0.0f == SCREENH * 0.5f) {
+ Point.x = SCREEN_WIDTH / 2;
+ Point.y = SCREEN_HEIGHT / 2;
+ ClientToScreen(PSGLOBAL(window), &Point);
+ SetCursorPos(Point.x, Point.y);
+
+ PSGLOBAL(lastMousePos.x) = SCREEN_WIDTH / 2;
+ PSGLOBAL(lastMousePos.y) = SCREEN_HEIGHT / 2;
+ }
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::CheckCodesForControls(int, int) { EAXJMP(0x48A950); }
+#else
+void CMenuManager::CheckCodesForControls()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER bool CMenuManager::CheckHover(int, int, int, int) { EAXJMP(0x48ACA0); }
+#else
+bool CMenuManager::CheckHover(int x1, int x2, int y1, int y2)
+{
+ return m_nMousePosX > x1 && m_nMousePosX < x2 &&
+ m_nMousePosY > y1 && m_nMousePosY < y2;
+}
+#endif
+
+#if 1
+WRAPPER int CMenuManager::CostructStatLine(int) { EAXJMP(0x482800); }
+#else
+int CMenuManager::CostructStatLine(int)
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::DisplayHelperText() { EAXJMP(0x48B490); }
+#else
+void CMenuManager::DisplayHelperText()
+{
+ wchar *str = nil;
+ switch (m_nHelperTextMsgId) {
+ case 0:
+ str = TheText.Get("FET_MIG");
+ break;
+ case 1:
+ str = TheText.Get("FET_APP");
+ break;
+ case 2:
+ str = TheText.Get("FET_HRD");
+ break;
+ case 3:
+ str = TheText.Get("FET_RSO");
+ break;
+ case 4:
+ str = TheText.Get("FET_RSC");
+ break;
+ default:
+ break;
+ };
+
+ CFont::SetAlignment(ALIGN_CENTER);
+ CFont::SetScale(SCREEN_SCALE_X(0.4f), SCREEN_SCALE_Y(0.6f));
+ CFont::SetFontStyle(FONT_HEADING);
+ CFont::SetDropColor(CRGBA(0, 0, 0, MENUDROP_COLOR_A));
+ CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE);
+
+ CFont::SetColor(CRGBA(255, 255, 255, 255));
+ CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_SCALE_FROM_BOTTOM(120.0f), str);
+}
+#endif
+
+#if 0
+WRAPPER float CMenuManager::DisplaySlider(float, float, float, float, float, float) { EAXJMP(0x488420); }
+#else
+float CMenuManager::DisplaySlider(float x, float y, float leftSize, float rightSize, float rectSize, float progress)
+{
+ CRGBA color;
+ float sizeRange;
+
+ float input = 0.0f;
+ for (int i = 0; i < 16; i++) {
+ input = i * rectSize/16.0f + x;
+
+ if (i/16.0f + 1/32.0f < progress)
+ color = CRGBA(255, 217, 106, FadeIn(255));
+ else
+ color = CRGBA(185, 120, 0, FadeIn(255));
+
+ sizeRange = max(leftSize, rightSize);
+
+ float _x = i * rectSize/16.0f + x;
+ float _y = y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f;
+ float _w = SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x;
+ float _h = y + sizeRange;
+ float _s = SCREEN_SCALE_X(2.0f);
+ CSprite2d::DrawRect(CRect(_x + _s, _y + _s, _w + _s, _h + _s), CRGBA(0, 0, 0, FadeIn(255))); // Shadow
+ CSprite2d::DrawRect(CRect(i * rectSize/16.0f + x, y + sizeRange - ((16 - i) * leftSize + i * rightSize)/16.0f, SCREEN_SCALE_X(10.0f) + i * rectSize/16.0f + x, y + sizeRange), color);
+ };
+ return input;
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame() { EAXJMP(0x48AB40); }
+#else
+WRAPPER void CMenuManager::DoSettingsBeforeStartingAGame()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::Draw() { EAXJMP(0x47AE00); }
+#else
+void CMenuManager::Draw()
+{
+ CFont::SetBackgroundOff();
+ CFont::SetPropOn();
+ CFont::SetCentreOff();
+ CFont::SetJustifyOn();
+ CFont::SetBackGroundOnlyTextOn();
+ CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(40.0f));
+ CFont::SetRightJustifyWrap(0.0f);
+ CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A)));
+
+ switch (m_nCurrScreen) {
+ case MENUPAGE_STATS:
+ PrintStats();
+ break;
+ case MENUPAGE_BRIEFS:
+ PrintBriefs();
+ break;
+ case MENUPAGE_CONTROLLER_DEBUG:
+ DrawControllerScreenExtraText(0, 350, 20);
+ break;
+ }
+
+ // Header.
+ if (aScreens[m_nCurrScreen].m_ScreenName[0]) {
+ CFont::SetDropShadowPosition(0);
+ CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255)));
+ CFont::SetRightJustifyOn();
+ CFont::SetFontStyle(FONT_HEADING);
+ CFont::SetScale(SCREEN_SCALE_X(MENUHEADER_WIDTH), SCREEN_SCALE_Y(MENUHEADER_HEIGHT));
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(MENUHEADER_POS_X), SCREEN_SCALE_FROM_BOTTOM(MENUHEADER_POS_Y), TheText.Get(aScreens[m_nCurrScreen].m_ScreenName));
+ }
+
+ // Action text.
+ wchar *str;
+ if (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL) {
+ switch (m_nCurrScreen) {
+ case MENUPAGE_LOAD_SLOT_CONFIRM:
+ if (m_bGameNotLoaded)
+ str = TheText.Get("FES_LCG");
+ else
+ str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName);
+ break;
+ case MENUPAGE_SAVE_OVERWRITE_CONFIRM:
+ if (Slots[m_nCurrSaveSlot] == 1)
+ str = TheText.Get("FESZ_QZ");
+ else
+ str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName);
+ break;
+ case MENUPAGE_EXIT:
+ if (m_bGameNotLoaded)
+ str = TheText.Get("FEQ_SRW");
+ else
+ str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName);
+ break;
+ default:
+ str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName);
+ break;
+ };
+
+ CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE);
+ CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A)));
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetScale(SCREEN_SCALE_X(MENUACTION_WIDTH), SCREEN_SCALE_Y(MENUACTION_HEIGHT));
+ CFont::SetAlignment(ALIGN_LEFT);
+ CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+ CFont::PrintString(SCREEN_SCALE_X(MENUACTION_POS_X), SCREEN_SCALE_Y(MENUACTION_POS_Y), str);
+ }
+
+ for (int i = 0; i < MENUROWS; ++i) {
+ if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action != MENUACTION_LABEL && aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName[0]) {
+ wchar *textToPrint[MENUCOLUMNS] = { nil, nil };
+
+ if (aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot >= SAVESLOT_1 && aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot <= SAVESLOT_8) {
+ textToPrint[MENUCOLUMN_LEFT] = GetNameOfSavedGame(i - 1);
+ textToPrint[MENUCOLUMN_RIGHT] = GetSavedGameDateAndTime(i - 1);
+
+ if (!textToPrint[MENUCOLUMN_LEFT][0]) {
+ sprintf(gString, "FEM_SL%d", i);
+ textToPrint[MENUCOLUMN_LEFT] = TheText.Get(gString);
+ }
+ }
+ else {
+ textToPrint[MENUCOLUMN_LEFT] = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName);
+ }
+
+ switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) {
+ case MENUACTION_CTRLVIBRATION:
+ break;
+ case MENUACTION_CTRLCONFIG:
+ switch (CPad::GetPad(0)->Mode) {
+ case 0:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF1");
+ break;
+ case 1:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF2");
+ break;
+ case 2:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF3");
+ break;
+ case 3:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEC_CF4");
+ break;
+ };
+ break;
+ case MENUACTION_CTRLDISPLAY:
+ break;
+ case MENUACTION_FRAMESYNC:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsVsyncDisp ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_FRAMELIMIT:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsFrameLimiter ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_TRAILS:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(BlurOn ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_SUBTITLES:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsShowSubtitles ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_WIDESCREEN:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsUseWideScreen ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_RADIO:
+ sprintf(gString, "FEA_FM%d", m_PrefsRadioStation);
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(gString);
+ break;
+ case MENUACTION_SETDBGFLAG:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_SWITCHBIGWHITEDEBUGLIGHT:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(CTheScripts::DbgFlag ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_INVVERT:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(MousePointerStateHelper.bInvertVertically ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_SCREENRES:
+ {
+ char *res = _psGetVideoModeList()[m_nDisplayVideoMode];
+
+ if (!res)
+ res = "";
+
+ AsciiToUnicode(res, gUString);
+ textToPrint[MENUCOLUMN_RIGHT] = gUString;
+ }
+ break;
+ case MENUACTION_AUDIOHW:
+ if (FrontEndMenuManager.m_nPrefsAudio3DProviderIndex == -1)
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_NAH");
+ else {
+ char *provider = MusicManager.Get3DProviderName(FrontEndMenuManager.m_nPrefsAudio3DProviderIndex);
+ AsciiToUnicode(provider, gUString);
+ textToPrint[MENUCOLUMN_RIGHT] = gUString;
+ }
+ break;
+ case MENUACTION_SPEAKERCONF:
+ if (FrontEndMenuManager.m_nPrefsAudio3DProviderIndex == -1)
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_NAH");
+ else {
+ switch (m_PrefsSpeakers) {
+ case 0:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_2SP");
+ break;
+ case 1:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_EAR");
+ break;
+ case 2:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get("FEA_4SP");
+ break;
+ };
+ }
+ break;
+ case MENUACTION_CTRLMETHOD:
+ switch (m_ControlMethod) {
+ case 0:
+ textToPrint[MENUCOLUMN_LEFT] = TheText.Get("FET_SCN");
+ break;
+ case 1:
+ textToPrint[MENUCOLUMN_LEFT] = TheText.Get("FET_CCN");
+ break;
+ };
+ break;
+ case MENUACTION_DYNAMICACOUSTIC:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_PrefsDMA ? "FEM_ON" : "FEM_OFF");
+ break;
+ case MENUACTION_MOUSESTEER:
+ textToPrint[MENUCOLUMN_RIGHT] = TheText.Get(m_bDisableMouseSteering ? "FEM_ON" : "FEM_OFF");
+ break;
+ };
+
+ CFont::SetDropShadowPosition(MENUDROP_COLOR_SIZE);
+ CFont::SetDropColor(CRGBA(0, 0, 0, FadeIn(MENUDROP_COLOR_A)));
+ CFont::SetCentreSize(SCREEN_WIDTH);
+ CFont::SetWrapx(SCREEN_WIDTH);
+ CFont::SetRightJustifyWrap(-SCREEN_WIDTH);
+
+ // Set alignment.
+ CVector2D vecPositions = { 0.0f, 0.0f };
+ float fVerticalSpacing;
+ float fBarSize;
+
+ int SavePageSlot =
+ m_nCurrScreen == MENUPAGE_CHOOSE_LOAD_SLOT ||
+ m_nCurrScreen == MENUPAGE_CHOOSE_DELETE_SLOT ||
+ m_nCurrScreen == MENUPAGE_CHOOSE_SAVE_SLOT;
+
+ if (SavePageSlot) {
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetAlignment(ALIGN_LEFT);
+ CFont::SetScale(SCREEN_SCALE_X(0.45f), SCREEN_SCALE_Y(0.7f));
+ fVerticalSpacing = MENUCOLUMN_SPACING_MIN;
+ fBarSize = MENUSELECT_BOX_MIN;
+
+ vecPositions.x = SCREEN_SCALE_X(MENUCOLUMN_SAVE_X);
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_SAVE_Y);
+ }
+ else {
+ CFont::SetFontStyle(FONT_HEADING);
+
+ int LeftMenuColumn =
+ m_nCurrScreen == MENUPAGE_SOUND_SETTINGS ||
+ m_nCurrScreen == MENUPAGE_GRAPHICS_SETTINGS ||
+ m_nCurrScreen == MENUPAGE_MOUSE_CONTROLS;
+
+ if (LeftMenuColumn) {
+ CFont::SetAlignment(ALIGN_LEFT);
+ CFont::SetScale(SCREEN_SCALE_X(0.55f), SCREEN_SCALE_Y(0.8f));
+ fVerticalSpacing = MENUCOLUMN_SPACING_MIN;
+ fBarSize = MENUSELECT_BOX_MIN;
+ }
+ else {
+ CFont::SetAlignment(ALIGN_CENTER);
+ CFont::SetScale(SCREEN_SCALE_X(0.75f), SCREEN_SCALE_Y(0.9f));
+ fVerticalSpacing = MENUCOLUMN_SPACING_MAX;
+ fBarSize = MENUSELECT_BOX_MAX;
+ }
+
+ // Set positions.
+ if (CFont::GetDetails().centre)
+ vecPositions.x = SCREEN_WIDTH / 2;
+ else
+ vecPositions.x = SCREEN_SCALE_X(MENUCOLUMN_POS_X);
+
+ switch (m_nCurrScreen) {
+ case MENUPAGE_BRIEFS:
+ case MENUPAGE_STATS:
+ vecPositions.y = SCREEN_SCALE_FROM_BOTTOM(MENUCOLUMN_FEDS);
+ break;
+ case MENUPAGE_SOUND_SETTINGS:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MAX_Y);
+
+ if (i > 5)
+ vecPositions.y += SCREEN_SCALE_Y(MENURADIO_ICON_H * 1.16f);
+ break;
+ case MENUPAGE_LANGUAGE_SETTINGS:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MIN_Y);
+ break;
+ case MENUPAGE_GRAPHICS_SETTINGS:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MAX_Y);
+ break;
+ case MENUPAGE_OPTIONS:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y);
+ break;
+ case MENUPAGE_PAUSE_MENU:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_PAUSE_Y);
+ break;
+ case MENUPAGE_NEW_GAME:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y);
+ break;
+ case MENUPAGE_START_MENU:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_START_Y);
+ break;
+ default:
+ vecPositions.y = (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENUCOLUMN_MID_Y);
+ break;
+ };
+ }
+
+ if (i > 0)
+ vecPositions.y += SCREEN_SCALE_Y(fVerticalSpacing * i);
+
+ // Set color and draw selection bar.
+ if (i == m_nCurrOption && m_nMenuFadeAlpha >= 255) {
+ CFont::SetColor(CRGBA(255, 217, 106, FadeIn(255)));
+ CSprite2d::DrawRect(CRect(SCREEN_STRETCH_X(11.0f), vecPositions.y - SCREEN_STRETCH_Y(fBarSize * 0.13f), SCREEN_STRETCH_FROM_RIGHT(11.0f), vecPositions.y + SCREEN_STRETCH_Y(fBarSize)), CRGBA(100, 200, 50, 50));
+ }
+ else
+ CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255)));
+
+ // Draw
+ if (textToPrint[MENUCOLUMN_LEFT])
+ CFont::PrintString(vecPositions.x, vecPositions.y, textToPrint[MENUCOLUMN_LEFT]);
+
+ if (textToPrint[MENUCOLUMN_RIGHT]) {
+ CFont::SetAlignment(ALIGN_RIGHT);
+ CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(SavePageSlot ? MENUCOLUMN_SAVE_X : MENUCOLUMN_POS_X), vecPositions.y, textToPrint[MENUCOLUMN_RIGHT]);
+ }
+
+ // Mouse support.
+ bool bIsMouseInPosition = false;
+ if (m_nMenuFadeAlpha >= 255) {
+ CVector2D vecInputSize = { SCREEN_SCALE_X(20.0f), SCREEN_SCALE_FROM_RIGHT(20.0f) };
+ if (m_bShowMouse &&
+ ((CheckHover(vecInputSize.x, vecInputSize.y, vecPositions.y, vecPositions.y + SCREEN_STRETCH_Y(20.0f)))))
+ bIsMouseInPosition = true;
+ else
+ bIsMouseInPosition = false;
+
+ if (bIsMouseInPosition) {
+ if (m_nCurrOption != i) {
+ m_nCurrOption = i;
+ DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_DENIED, 0);
+ }
+
+ m_nCurrentInput = m_nCurrOption;
+
+ if (CPad::GetPad(0)->NewMouseControllerState.LMB && !CPad::GetPad(0)->OldMouseControllerState.LMB)
+ m_nHoverOption = IGNORE_OPTION;
+ else
+ m_nHoverOption = ACTIVATE_OPTION;
+ }
+ }
+
+ // Sliders
+ // TODO: CheckHover
+ switch (aScreens[m_nCurrScreen].m_aEntries[i].m_Action) {
+ case MENUACTION_BRIGHTNESS:
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsBrightness/512.0f);
+ break;
+ case MENUACTION_DRAWDIST:
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), (m_PrefsLOD - 0.8f) * 1.0f);
+ break;
+ case MENUACTION_MUSICVOLUME:
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsMusicVolume/128.0f);
+ break;
+ case MENUACTION_SFXVOLUME:
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), m_PrefsSfxVolume/128.0f);
+ break;
+ case MENUACTION_MOUSESENS:
+ DisplaySlider(SCREEN_SCALE_FROM_RIGHT(MENUSLIDER_X), vecPositions.y - SCREEN_SCALE_Y(3.0f), SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(18.0f), SCREEN_SCALE_X(256.0f), TheCamera.m_fMouseAccelHorzntl * 200.0f);
+ break;
+ };
+
+ // Radio icons.
+ float fIconSpacing = 59.52f;
+ if (m_nCurrScreen == MENUPAGE_SOUND_SETTINGS) {
+ for (int i = 0; i < POLICE_RADIO; i++) {
+
+ if (i == MSX_FM)
+ fIconSpacing -= 1.5f;
+
+ if (i < USERTRACK)
+ m_aFrontEndSprites[i + FE_RADIO1].Draw(SCREEN_STRETCH_X(MENURADIO_ICON_X + fIconSpacing * i), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, 170));
+ if (i > CHATTERBOX)
+ m_aMenuSprites[MENUSPRITE_MP3LOGO].Draw(SCREEN_STRETCH_X(MENURADIO_ICON_X + fIconSpacing * i), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(MENURADIO_ICON_Y), SCREEN_SCALE_X(MENURADIO_ICON_W), SCREEN_SCALE_Y(MENURADIO_ICON_H), i == m_PrefsRadioStation ? CRGBA(255, 255, 255, 255) : CRGBA(225, 0, 0, DMAudio.IsMP3RadioChannelAvailable() ? 170 : 25));
+ }
+ }
+
+ // Helpers
+ if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FED_RES")) {
+ if (m_nDisplayVideoMode == m_nPrefsVideoMode) {
+ if (m_nHelperTextMsgId == 1)
+ ResetHelperText();
+ }
+ else
+ SetHelperText(1);
+ }
+ else {
+ if (m_nDisplayVideoMode != m_nPrefsVideoMode) {
+ m_nDisplayVideoMode = m_nPrefsVideoMode;
+ SetHelperText(3);
+ }
+ }
+
+ switch (m_nCurrScreen) {
+ case MENUPAGE_CONTROLLER_SETTINGS:
+ case MENUPAGE_SOUND_SETTINGS:
+ case MENUPAGE_GRAPHICS_SETTINGS:
+ case MENUPAGE_SKIN_SELECT:
+ case MENUPAGE_CONTROLLER_PC:
+ case MENUPAGE_MOUSE_CONTROLS:
+ DisplayHelperText();
+ break;
+ };
+ }
+ };
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::DrawControllerBound(int, int, int, uint8) { EAXJMP(0x489710); }
+#else
+void CMenuManager::DrawControllerBound(int, int, int, uint8)
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::DrawControllerScreenExtraText(int, int, int) { EAXJMP(0x4892F0); }
+#else
+void CMenuManager::DrawControllerScreenExtraText(int, int, int)
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::DrawControllerSetupScreen() { EAXJMP(0x481210); }
+#else
+void CMenuManager::DrawControllerSetupScreen()
+{
+
+}
+#endif
+
+#if 0
WRAPPER void CMenuManager::DrawFrontEnd(void) { EAXJMP(0x47A540); }
-WRAPPER void CMenuManager::UnloadTextures(void) { EAXJMP(0x47A440); }
-WRAPPER void CMenuManager::LoadAllTextures(void) { EAXJMP(0x47A230); }
-WRAPPER void CMenuManager::LoadSettings(void) { EAXJMP(0x488EE0); }
-WRAPPER void CMenuManager::WaitForUserCD(void) { EAXJMP(0x48ADD0); }
+#else
+void CMenuManager::DrawFrontEnd()
+{
+ CFont::SetAlphaFade(255.0f);
+
+ if (m_nCurrScreen == MENUPAGE_NONE) {
+ m_nMenuFadeAlpha = 0;
+
+ if (m_bGameNotLoaded)
+ m_nCurrScreen = MENUPAGE_START_MENU;
+ else
+ m_nCurrScreen = MENUPAGE_PAUSE_MENU;
+ }
+
+ if (!m_nCurrOption && aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL)
+ m_nCurrOption = MENUROW_1;
+
+ CMenuManager::DrawFrontEndNormal();
+ CMenuManager::PrintErrorMessage();
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::DrawFrontEndNormal(void) { EAXJMP(0x47A5B0); }
+#else
+void CMenuManager::DrawFrontEndNormal()
+{
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void *)rwTEXTUREADDRESSCLAMP);
+
+ CSprite2d::InitPerFrame();
+ CFont::InitPerFrame();
+
+ eMenuSprites previousSprite = MENUSPRITE_MAINMENU;
+ if (m_nMenuFadeAlpha < 255) {
+ switch (m_nPrevScreen) {
+ case MENUPAGE_STATS:
+ case MENUPAGE_START_MENU:
+ case MENUPAGE_PAUSE_MENU:
+ previousSprite = MENUSPRITE_MAINMENU;
+ break;
+ case MENUPAGE_NEW_GAME:
+ case MENUPAGE_CHOOSE_LOAD_SLOT:
+ case MENUPAGE_CHOOSE_DELETE_SLOT:
+ case MENUPAGE_NEW_GAME_RELOAD:
+ case MENUPAGE_LOAD_SLOT_CONFIRM:
+ case MENUPAGE_DELETE_SLOT_CONFIRM:
+ case MENUPAGE_EXIT:
+ previousSprite = MENUSPRITE_SINGLEPLAYER;
+ break;
+ case MENUPAGE_MULTIPLAYER_MAIN:
+ previousSprite = MENUSPRITE_MULTIPLAYER;
+ break;
+ case MENUPAGE_MULTIPLAYER_MAP:
+ case MENUPAGE_MULTIPLAYER_FIND_GAME:
+ case MENUPAGE_SKIN_SELECT:
+ case MENUPAGE_KEYBOARD_CONTROLS:
+ case MENUPAGE_MOUSE_CONTROLS:
+ previousSprite = MENUSPRITE_FINDGAME;
+ break;
+ case MENUPAGE_MULTIPLAYER_CONNECTION:
+ case MENUPAGE_MULTIPLAYER_MODE:
+ previousSprite = MENUSPRITE_CONNECTION;
+ break;
+ case MENUPAGE_MULTIPLAYER_CREATE:
+ previousSprite = MENUSPRITE_HOSTGAME;
+ break;
+ case MENUPAGE_SKIN_SELECT_OLD:
+ case MENUPAGE_OPTIONS:
+ previousSprite = MENUSPRITE_PLAYERSET;
+ break;
+ };
+
+ if (m_nPrevScreen == MENUPAGE_NONE)
+ CSprite2d::DrawRect(CRect(0.0f, 0.0f, SCREENW, SCREENH), CRGBA(0, 0, 0, 255));
+ else
+ m_aMenuSprites[previousSprite].Draw(CRect(0.0f, 0.0f, SCREENW, SCREENH), CRGBA(255, 255, 255, 255));
+ }
+
+ eMenuSprites currentSprite = MENUSPRITE_MAINMENU;
+ switch (m_nCurrScreen) {
+ case MENUPAGE_STATS:
+ case MENUPAGE_START_MENU:
+ case MENUPAGE_PAUSE_MENU:
+ currentSprite = MENUSPRITE_MAINMENU;
+ break;
+ case MENUPAGE_NEW_GAME:
+ case MENUPAGE_CHOOSE_LOAD_SLOT:
+ case MENUPAGE_CHOOSE_DELETE_SLOT:
+ case MENUPAGE_NEW_GAME_RELOAD:
+ case MENUPAGE_LOAD_SLOT_CONFIRM:
+ case MENUPAGE_DELETE_SLOT_CONFIRM:
+ case MENUPAGE_EXIT:
+ currentSprite = MENUSPRITE_SINGLEPLAYER;
+ break;
+ case MENUPAGE_MULTIPLAYER_MAIN:
+ currentSprite = MENUSPRITE_MULTIPLAYER;
+ break;
+ case MENUPAGE_MULTIPLAYER_MAP:
+ case MENUPAGE_MULTIPLAYER_FIND_GAME:
+ case MENUPAGE_SKIN_SELECT:
+ case MENUPAGE_KEYBOARD_CONTROLS:
+ case MENUPAGE_MOUSE_CONTROLS:
+ currentSprite = MENUSPRITE_FINDGAME;
+ break;
+ case MENUPAGE_MULTIPLAYER_CONNECTION:
+ case MENUPAGE_MULTIPLAYER_MODE:
+ currentSprite = MENUSPRITE_CONNECTION;
+ break;
+ case MENUPAGE_MULTIPLAYER_CREATE:
+ currentSprite = MENUSPRITE_HOSTGAME;
+ break;
+ case MENUPAGE_SKIN_SELECT_OLD:
+ case MENUPAGE_OPTIONS:
+ currentSprite = MENUSPRITE_PLAYERSET;
+ break;
+ };
+
+ uint32 savedShade;
+ uint32 savedAlpha;
+ RwRenderStateGet(rwRENDERSTATESHADEMODE, &savedShade);
+ RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast<void *>(rwSHADEMODEGOURAUD));
+ RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &savedAlpha);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast<void *>(TRUE));
+ if (m_nMenuFadeAlpha >= 255) {
+ m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREENW, SCREENH), CRGBA(255, 255, 255, 255));
+ }
+ else {
+ if (m_nMenuFadeAlpha < 255) {
+ m_nMenuFadeAlpha += 0.1f * 255.0f;
+
+ if (m_nMenuFadeAlpha >= 255)
+ m_nMenuFadeAlpha = 255;
+
+ m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREENW, SCREENH), CRGBA(255, 255, 255, m_nMenuFadeAlpha));
+ }
+ else
+ m_aMenuSprites[currentSprite].Draw(CRect(0.0f, 0.0f, SCREENW, SCREENH), CRGBA(255, 255, 255, 255));
+ }
-int CMenuManager::FadeIn(int alpha) {
- if (m_nCurrScreen == MENU_LOADING_IN_PROGRESS ||
- m_nCurrScreen == MENU_SAVING_IN_PROGRESS ||
- m_nCurrScreen == MENU_DELETING)
+ // GTA LOGO
+ if (m_nCurrScreen == MENUPAGE_START_MENU || m_nCurrScreen == MENUPAGE_PAUSE_MENU) {
+ if (CGame::frenchGame || CGame::germanGame || !CGame::nastyGame)
+ m_aMenuSprites[MENUSPRITE_GTA3LOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(70.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(115.0f), SCREEN_SCALE_Y(180.0f)), CRGBA(255, 255, 255, FadeIn(255)));
+ else
+ m_aMenuSprites[MENUSPRITE_GTALOGO].Draw(CRect((SCREEN_WIDTH / 2) - SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(40.0f), (SCREEN_WIDTH / 2) + SCREEN_SCALE_X(95.0f), SCREEN_SCALE_Y(210.0f)), CRGBA(255, 255, 255, FadeIn(255)));
+ }
+ RwRenderStateSet(rwRENDERSTATESHADEMODE, reinterpret_cast<void *>(savedShade));
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, reinterpret_cast<void *>(savedAlpha));
+
+ switch (m_nCurrScreen) {
+ case MENUPAGE_SKIN_SELECT:
+ CMenuManager::DrawPlayerSetupScreen();
+ break;
+ case MENUPAGE_KEYBOARD_CONTROLS:
+ CMenuManager::DrawControllerSetupScreen();
+ break;
+ default:
+ CMenuManager::Draw();
+ break;
+ };
+
+ CFont::DrawFonts();
+
+ // Draw mouse
+ if (m_bShowMouse)
+ m_aMenuSprites[MENUSPRITE_MOUSE].Draw(m_nMousePosX, m_nMousePosY, SCREEN_SCALE_X(60.0f), SCREEN_SCALE_Y(60.0f), CRGBA(255, 255, 255, 255));
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::DrawPlayerSetupScreen() { EAXJMP(0x47F2B0); }
+#else
+void CMenuManager::DrawPlayerSetupScreen()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER int CMenuManager::FadeIn(int alpha) { EAXJMP(0x48AC60); }
+#else
+int CMenuManager::FadeIn(int alpha)
+{
+ if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS ||
+ m_nCurrScreen == MENUPAGE_SAVING_IN_PROGRESS ||
+ m_nCurrScreen == MENUPAGE_DELETING)
return alpha;
if (m_nMenuFadeAlpha >= alpha)
@@ -47,7 +856,328 @@ int CMenuManager::FadeIn(int alpha) {
return m_nMenuFadeAlpha;
}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &) { EAXJMP(0x4889C0); }
+#else
+void CMenuManager::FilterOutColorMarkersFromString(uint16, CRGBA &)
+{
+
+}
+#endif
+
+#if 1
+WRAPPER int CMenuManager::GetStartOptionsCntrlConfigScreens() { EAXJMP(0x489270); }
+#else
+int CMenuManager::GetStartOptionsCntrlConfigScreens()
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::InitialiseChangedLanguageSettings() { EAXJMP(0x47A4D0); }
+#else
+void CMenuManager::InitialiseChangedLanguageSettings()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::LoadAllTextures() { EAXJMP(0x47A230); }
+#else
+void CMenuManager::LoadAllTextures()
+{
+ if (!m_bSpritesLoaded) {
+ CMenuManager::CentreMousePointer();
+ DMAudio.ChangeMusicMode(0);
+ DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_STARTING, 0);
+ m_nCurrOption = MENUROW_0;
+ m_PrefsRadioStation = DMAudio.GetRadioInCar();
+
+ if (DMAudio.IsMP3RadioChannelAvailable()) {
+ if (CMenuManager::m_PrefsRadioStation > USERTRACK)
+ CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 10;
+ }
+ else if (CMenuManager::m_PrefsRadioStation > CHATTERBOX)
+ CMenuManager::m_PrefsRadioStation = CGeneral::GetRandomNumber() % 9;
+
+ CFileMgr::SetDir("");
+ CTimer::Stop();
+ CStreaming::MakeSpaceFor(716800);
+ CStreaming::ImGonnaUseStreamingMemory();
+ CTxdStore::PushCurrentTxd();
+
+ int frontend = CTxdStore::AddTxdSlot("frontend");
+ CTxdStore::LoadTxd(frontend, "MODELS/FRONTEND.TXD");
+ CTxdStore::AddRef(frontend);
+ CTxdStore::SetCurrentTxd(frontend);
+ CStreaming::IHaveUsedStreamingMemory();
+ CTimer::Update();
+
+ debug("LOAD frontend\n");
+ for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); i++) {
+ m_aFrontEndSprites[i].SetTexture(FrontendFilenames[i]);
+ m_aFrontEndSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER);
+ };
+
+ CTxdStore::PopCurrentTxd();
+
+ int menu = CTxdStore::AddTxdSlot("menu");
+ CTxdStore::LoadTxd(menu, "MODELS/MENU.TXD");
+ CTxdStore::AddRef(menu);
+ CTxdStore::SetCurrentTxd(menu);
+
+ debug("LOAD sprite\n");
+ for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; i++) {
+ m_aMenuSprites[i].SetTexture(MenuFilenames[i*2], MenuFilenames[i*2+1]);
+ m_aMenuSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER);
+ };
+
+ CTxdStore::PopCurrentTxd();
+
+ m_bSpritesLoaded = true;
+ }
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::LoadSettings() { EAXJMP(0x488EE0); }
+#else
+void CMenuManager::LoadSettings()
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::MessageScreen(char *) { EAXJMP(0x48B7E0); }
+#else
+void CMenuManager::MessageScreen(char *)
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::PickNewPlayerColour() { EAXJMP(0x488C40); }
+#else
+void CMenuManager::PickNewPlayerColour()
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::PrintBriefs() { EAXJMP(0x484D60); }
+#else
+void CMenuManager::PrintBriefs()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::PrintErrorMessage() { EAXJMP(0x484F70); }
+#else
+void CMenuManager::PrintErrorMessage()
+{
+ if (!CPad::bDisplayNoControllerMessage && !CPad::bObsoleteControllerMessage)
+ return;
+
+ CSprite2d::DrawRect(CRect(SCREEN_SCALE_X(20.0f), SCREEN_SCALE_Y(140.0f), SCREEN_WIDTH - SCREEN_SCALE_X(20.0f), SCREEN_HEIGHT - SCREEN_SCALE_Y(140.0f)), CRGBA(64, 16, 16, 224));
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetBackgroundOff();
+ CFont::SetPropOn();
+ CFont::SetCentreOff();
+ CFont::SetJustifyOn();
+ CFont::SetRightJustifyOff();
+ CFont::SetBackGroundOnlyTextOn();
+ CFont::SetWrapx(SCREEN_WIDTH - 40.0f);
+ CFont::SetColor(CRGBA(165, 165, 165, 255));
+ CFont::SetScale(SCREEN_SCALE_X(0.9f), SCREEN_SCALE_Y(0.9f));
+ CFont::PrintString(SCREEN_SCALE_X(40.0f), (SCREEN_HEIGHT / 2) - SCREEN_SCALE_Y(60.0f), TheText.Get(CPad::bDisplayNoControllerMessage ? "NOCONT" : "WRCONT"));
+ CFont::DrawFonts();
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::PrintStats() { EAXJMP(0x482100); }
+#else
+void CMenuManager::PrintStats()
+{
+
+}
+#endif
+
+
+#if 1
+WRAPPER void CMenuManager::Process(void) { EAXJMP(0x485100); }
+#else
+void CMenuManager::Process(void)
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::ProcessButtonPresses() { EAXJMP(0x4856F0); }
+#else
+void CMenuManager::ProcessButtonPresses()
+{
+
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::ProcessOnOffMenuOptions() { EAXJMP(0x48AE60); }
+#else
+void CMenuManager::ProcessOnOffMenuOptions()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::RequestFrontEndShutdown() { EAXJMP(0x488750); }
+#else
+void CMenuManager::RequestFrontEndShutdown()
+{
+ m_bShutDownFrontEndRequested = true;
+ DMAudio.ChangeMusicMode(1);
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::RequestFrontEndStartUp() { EAXJMP(0x488770); }
+#else
+void CMenuManager::RequestFrontEndStartUp()
+{
+ m_bStartUpFrontEndRequested = 1;
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::ResetHelperText() { EAXJMP(0x48B470); }
+#else
+void CMenuManager::ResetHelperText()
+{
+ m_nHelperTextMsgId = 0;
+ m_nHelperTextAlpha = 300;
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::SaveLoadFileError_SetUpErrorScreen() { EAXJMP(0x488930); }
+#else
+void CMenuManager::SaveLoadFileError_SetUpErrorScreen()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::SetHelperText() { EAXJMP(0x48B450); }
+#else
+void CMenuManager::SetHelperText(int text)
+{
+ m_nHelperTextMsgId = text;
+ m_nHelperTextAlpha = 300;
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::SaveSettings() { EAXJMP(0x488CC0); }
+#else
+void CMenuManager::SaveSettings()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::ShutdownJustMenu() { EAXJMP(0x488920); }
+#else
+void CMenuManager::ShutdownJustMenu()
+{
+ m_bMenuActive = false;
+ CTimer::EndUserPause();
+}
+#endif
+
+#if 0
+WRAPPER float CMenuManager::StretchX(float) { EAXJMP(0x48ABE0); }
+#else
+float CMenuManager::StretchX(float x)
+{
+ if (SCREENW == 640)
+ return x;
+ else
+ return SCREENW * x * 0.0015625f;
+}
+#endif
+
+#if 0
+WRAPPER float CMenuManager::StretchY(float) { EAXJMP(0x48AC20); }
+#else
+float CMenuManager::StretchY(float y)
+{
+ if (SCREENH == 448)
+ return y;
+ else
+ return SCREENH * y * 0.002232143f;
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::SwitchMenuOnAndOff() { EAXJMP(0x488790); }
+#else
+void CMenuManager::SwitchMenuOnAndOff()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CMenuManager::UnloadTextures() { EAXJMP(0x47A440); }
+#else
+void CMenuManager::UnloadTextures()
+{
+ if (m_bSpritesLoaded) {
+ debug("Remove frontend\n");
+ for (int i = 0; i < ARRAY_SIZE(FrontendFilenames); ++i)
+ m_aFrontEndSprites[i].Delete();
+
+ int frontend = CTxdStore::FindTxdSlot("frontend");
+ CTxdStore::RemoveTxdSlot(frontend);
+
+ debug("Remove menu textures\n");
+ for (int i = 0; i < ARRAY_SIZE(MenuFilenames)/2; ++i)
+ m_aMenuSprites[i].Delete();
+
+ int menu = CTxdStore::FindTxdSlot("menu");
+ CTxdStore::RemoveTxdSlot(menu);
+
+ m_bSpritesLoaded = false;
+ }
+}
+#endif
+
+#if 1
+WRAPPER void CMenuManager::WaitForUserCD(void) { EAXJMP(0x48ADD0); }
+#else
+void CMenuManager::WaitForUserCD()
+{
+
+}
+#endif
STARTPATCHES
- InjectHook(0x48AC60, &CMenuManager::FadeIn, PATCH_JUMP);
+ InjectHook(0x47A230, &CMenuManager::LoadAllTextures, PATCH_JUMP);
+ InjectHook(0x47A440, &CMenuManager::UnloadTextures, PATCH_JUMP);
+
+ for (int i = 1; i < ARRAY_SIZE(aScreens); i++)
+ Patch(0x611930 + sizeof(CMenuScreen) * i, aScreens[i]);
ENDPATCHES \ No newline at end of file
diff --git a/src/Frontend.h b/src/Frontend.h
index 2e95d582..dd6464b8 100644
--- a/src/Frontend.h
+++ b/src/Frontend.h
@@ -2,7 +2,45 @@
#include "Sprite2d.h"
-enum {
+#define MENUHEADER_POS_X 35.0f
+#define MENUHEADER_POS_Y 93.0f
+#define MENUHEADER_WIDTH 0.84f
+#define MENUHEADER_HEIGHT 1.6f
+
+#define MENUACTION_POS_X 20.0f
+#define MENUACTION_POS_Y 37.5f
+#define MENUACTION_WIDTH 0.675f
+#define MENUACTION_HEIGHT 0.81f
+
+#define MENUCOLUMN_POS_X MENUHEADER_POS_X + 16.0f
+#define MENUCOLUMN_MAX_Y 149.0f
+#define MENUCOLUMN_MID_Y 100.0f
+#define MENUCOLUMN_MIN_Y 110.0f
+#define MENUCOLUMN_PAUSE_Y 25.0f
+#define MENUCOLUMN_START_Y 9.0f
+#define MENUCOLUMN_FEDS 139.0f
+
+#define MENUCOLUMN_SAVE_X 121.0f
+#define MENUCOLUMN_SAVE_Y 111.0f
+
+#define MENUCOLUMN_SPACING_MAX 24.0f
+#define MENUCOLUMN_SPACING_MIN 20.0f
+
+#define MENUSELECT_BOX_MAX 20.5f
+#define MENUSELECT_BOX_MIN 17.0f
+
+#define MENURADIO_ICON_X 31.5f
+#define MENURADIO_ICON_Y 29.5f
+#define MENURADIO_ICON_W 60.0f
+#define MENURADIO_ICON_H 60.0f
+
+#define MENUDROP_COLOR_A 150
+#define MENUDROP_COLOR_SIZE -1
+
+#define MENUSLIDER_X 306.0f
+
+enum eLanguages
+{
LANGUAGE_AMERICAN,
LANGUAGE_FRENCH,
LANGUAGE_GERMAN,
@@ -10,66 +48,291 @@ enum {
LANGUAGE_SPANISH,
};
-enum eMenuScreen {
- MENU_NONE = 0,
- MENU_STATS = 1,
- MENU_NEW_GAME = 2,
- MENU_BRIEFS = 3,
- MENU_CONTROLLER_SETTINGS = 4,
- MENU_SOUND_SETTINGS = 5,
- MENU_GRAPHICS_SETTINGS = 6,
- MENU_LANGUAGE_SETTINGS = 7,
- MENU_CHOOSE_LOAD_SLOT = 8,
- MENU_CHOOSE_DELETE_SLOT = 9,
- MENU_NEW_GAME_RELOAD = 10,
- MENU_LOAD_SLOT_CONFIRM = 11,
- MENU_DELETE_SLOT_CONFIRM = 12,
- MENU_13 = 13,
- MENU_LOADING_IN_PROGRESS = 14,
- MENU_DELETING_IN_PROGRESS = 15,
- MENU_16 = 16,
- MENU_DELETE_FAILED = 17,
- MENU_DEBUG_MENU = 18,
- MENU_MEMORY_CARD_1 = 19,
- MENU_MEMORY_CARD_2 = 20,
- MENU_MULTIPLAYER_MAIN = 21,
- MENU_SAVE_FAILED_1 = 22,
- MENU_SAVE_FAILED_2 = 23,
- MENU_SAVE = 24,
- MENU_NO_MEMORY_CARD = 25,
- MENU_CHOOSE_SAVE_SLOT = 26,
- MENU_SAVE_OVERWRITE_CONFIRM = 27,
- MENU_MULTIPLAYER_MAP = 28,
- MENU_MULTIPLAYER_CONNECTION = 29,
- MENU_MULTIPLAYER_FIND_GAME = 30,
- MENU_MULTIPLAYER_MODE = 31,
- MENU_MULTIPLAYER_CREATE = 32,
- MENU_MULTIPLAYER_START = 33,
- MENU_SKIN_SELECT_OLD = 34,
- MENU_CONTROLLER_PC = 35,
- MENU_CONTROLLER_PC_OLD1 = 36,
- MENU_CONTROLLER_PC_OLD2 = 37,
- MENU_CONTROLLER_PC_OLD3 = 38,
- MENU_CONTROLLER_PC_OLD4 = 39,
- MENU_CONTROLLER_DEBUG = 40,
- MENU_OPTIONS = 41,
- MENU_EXIT = 42,
- MENU_SAVING_IN_PROGRESS = 43,
- MENU_SAVE_SUCCESSFUL = 44,
- MENU_DELETING = 45,
- MENU_DELETE_SUCCESS = 46,
- MENU_SAVE_FAILED = 47,
- MENU_LOAD_FAILED = 48,
- MENU_LOAD_FAILED_2 = 49,
- MENU_FILTER_GAME = 50,
- MENU_START_MENU = 51,
- MENU_PAUSE_MENU = 52,
- MENU_CHOOSE_MODE = 53,
- MENU_SKIN_SELECT = 54,
- MENU_KEYBOARD_CONTROLS = 55,
- MENU_MOUSE_CONTROLS = 56,
- MENU_57 = 57,
- MENU_58 = 58,
+enum eFrontendSprites
+{
+ FE2_MAINPANEL_UL,
+ FE2_MAINPANEL_UR,
+ FE2_MAINPANEL_DL,
+ FE2_MAINPANEL_DR,
+ FE2_MAINPANEL_DR2,
+ FE2_TABACTIVE,
+ FE_ICONBRIEF,
+ FE_ICONSTATS,
+ FE_ICONCONTROLS,
+ FE_ICONSAVE,
+ FE_ICONAUDIO,
+ FE_ICONDISPLAY,
+ FE_ICONLANGUAGE,
+ FE_CONTROLLER,
+ FE_CONTROLLERSH,
+ FE_ARROWS1,
+ FE_ARROWS2,
+ FE_ARROWS3,
+ FE_ARROWS4,
+ FE_RADIO1,
+ FE_RADIO2,
+ FE_RADIO3,
+ FE_RADIO4,
+ FE_RADIO5,
+ FE_RADIO6,
+ FE_RADIO7,
+ FE_RADIO8,
+ FE_RADIO9,
+};
+
+enum eMenuSprites
+{
+ MENUSPRITE_CONNECTION,
+ MENUSPRITE_FINDGAME,
+ MENUSPRITE_HOSTGAME,
+ MENUSPRITE_MAINMENU,
+ MENUSPRITE_PLAYERSET,
+ MENUSPRITE_SINGLEPLAYER,
+ MENUSPRITE_MULTIPLAYER,
+ MENUSPRITE_DMALOGO,
+ MENUSPRITE_GTALOGO,
+ MENUSPRITE_RSTARLOGO,
+ MENUSPRITE_GAMESPY,
+ MENUSPRITE_MOUSE,
+ MENUSPRITE_MOUSET,
+ MENUSPRITE_MP3LOGO,
+ MENUSPRITE_DOWNOFF,
+ MENUSPRITE_DOWNON,
+ MENUSPRITE_UPOFF,
+ MENUSPRITE_UPON,
+ MENUSPRITE_GTA3LOGO,
+};
+
+enum eSaveSlot
+{
+ SAVESLOT_NONE,
+ SAVESLOT_0,
+ SAVESLOT_1,
+ SAVESLOT_2,
+ SAVESLOT_3,
+ SAVESLOT_4,
+ SAVESLOT_5,
+ SAVESLOT_6,
+ SAVESLOT_7,
+ SAVESLOT_8,
+ SAVESLOT_LABEL = 36
+};
+
+enum eMenuScreen
+{
+ MENUPAGE_DISABLED = -1,
+ MENUPAGE_NONE = 0,
+ MENUPAGE_STATS = 1,
+ MENUPAGE_NEW_GAME = 2,
+ MENUPAGE_BRIEFS = 3,
+ MENUPAGE_CONTROLLER_SETTINGS = 4,
+ MENUPAGE_SOUND_SETTINGS = 5,
+ MENUPAGE_GRAPHICS_SETTINGS = 6,
+ MENUPAGE_LANGUAGE_SETTINGS = 7,
+ MENUPAGE_CHOOSE_LOAD_SLOT = 8,
+ MENUPAGE_CHOOSE_DELETE_SLOT = 9,
+ MENUPAGE_NEW_GAME_RELOAD = 10,
+ MENUPAGE_LOAD_SLOT_CONFIRM = 11,
+ MENUPAGE_DELETE_SLOT_CONFIRM = 12,
+ MENUPAGE_13 = 13,
+ MENUPAGE_LOADING_IN_PROGRESS = 14,
+ MENUPAGE_DELETING_IN_PROGRESS = 15,
+ MENUPAGE_16 = 16,
+ MENUPAGE_DELETE_FAILED = 17,
+ MENUPAGE_DEBUG_MENU = 18,
+ MENUPAGE_MEMORY_CARD_1 = 19,
+ MENUPAGE_MEMORY_CARD_2 = 20,
+ MENUPAGE_MULTIPLAYER_MAIN = 21,
+ MENUPAGE_SAVE_FAILED_1 = 22,
+ MENUPAGE_SAVE_FAILED_2 = 23,
+ MENUPAGE_SAVE = 24,
+ MENUPAGE_NO_MEMORY_CARD = 25,
+ MENUPAGE_CHOOSE_SAVE_SLOT = 26,
+ MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27,
+ MENUPAGE_MULTIPLAYER_MAP = 28,
+ MENUPAGE_MULTIPLAYER_CONNECTION = 29,
+ MENUPAGE_MULTIPLAYER_FIND_GAME = 30,
+ MENUPAGE_MULTIPLAYER_MODE = 31,
+ MENUPAGE_MULTIPLAYER_CREATE = 32,
+ MENUPAGE_MULTIPLAYER_START = 33,
+ MENUPAGE_SKIN_SELECT_OLD = 34,
+ MENUPAGE_CONTROLLER_PC = 35,
+ MENUPAGE_CONTROLLER_PC_OLD1 = 36,
+ MENUPAGE_CONTROLLER_PC_OLD2 = 37,
+ MENUPAGE_CONTROLLER_PC_OLD3 = 38,
+ MENUPAGE_CONTROLLER_PC_OLD4 = 39,
+ MENUPAGE_CONTROLLER_DEBUG = 40,
+ MENUPAGE_OPTIONS = 41,
+ MENUPAGE_EXIT = 42,
+ MENUPAGE_SAVING_IN_PROGRESS = 43,
+ MENUPAGE_SAVE_SUCCESSFUL = 44,
+ MENUPAGE_DELETING = 45,
+ MENUPAGE_DELETE_SUCCESS = 46,
+ MENUPAGE_SAVE_FAILED = 47,
+ MENUPAGE_LOAD_FAILED = 48,
+ MENUPAGE_LOAD_FAILED_2 = 49,
+ MENUPAGE_FILTER_GAME = 50,
+ MENUPAGE_START_MENU = 51,
+ MENUPAGE_PAUSE_MENU = 52,
+ MENUPAGE_CHOOSE_MODE = 53,
+ MENUPAGE_SKIN_SELECT = 54,
+ MENUPAGE_KEYBOARD_CONTROLS = 55,
+ MENUPAGE_MOUSE_CONTROLS = 56,
+ MENUPAGE_57 = 57,
+ MENUPAGE_58 = 58,
+ MENUPAGES
+};
+
+enum eMenuAction
+{
+ MENUACTION_NOTHING,
+ MENUACTION_LABEL,
+ MENUACTION_CHANGEMENU,
+ MENUACTION_CTRLVIBRATION,
+ MENUACTION_CTRLCONFIG,
+ MENUACTION_CTRLDISPLAY,
+ MENUACTION_FRAMESYNC,
+ MENUACTION_FRAMELIMIT,
+ MENUACTION_TRAILS,
+ MENUACTION_SUBTITLES,
+ MENUACTION_WIDESCREEN,
+ MENUACTION_BRIGHTNESS,
+ MENUACTION_DRAWDIST,
+ MENUACTION_MUSICVOLUME,
+ MENUACTION_SFXVOLUME,
+ MENUACTION_UNK15,
+ MENUACTION_RADIO,
+ MENUACTION_LANG_ENG,
+ MENUACTION_LANG_FRE,
+ MENUACTION_LANG_GER,
+ MENUACTION_LANG_ITA,
+ MENUACTION_LANG_SPA,
+ MENUACTION_UPDATESAVE,
+ MENUACTION_CHECKSAVE,
+ MENUACTION_UNK24,
+ MENUACTION_NEWGAME,
+ MENUACTION_RELOADIDE,
+ MENUACTION_RELOADIPL,
+ MENUACTION_SETDBGFLAG,
+ MENUACTION_SWITCHBIGWHITEDEBUGLIGHT,
+ MENUACTION_PEDROADGROUPS,
+ MENUACTION_CARROADGROUPS,
+ MENUACTION_COLLISIONPOLYS,
+ MENUACTION_REGMEMCARD1,
+ MENUACTION_TESTFORMATMEMCARD1,
+ MENUACTION_TESTUNFORMATMEMCARD1,
+ MENUACTION_CREATEROOTDIR,
+ MENUACTION_CREATELOADICONS,
+ MENUACTION_FILLWITHGUFF,
+ MENUACTION_SAVEONLYTHEGAME,
+ MENUACTION_SAVEGAME,
+ MENUACTION_SAVEGAMEUNDERGTA,
+ MENUACTION_CREATECOPYPROTECTED,
+ MENUACTION_TESTSAVE,
+ MENUACTION_TESTLOAD,
+ MENUACTION_TESTDELETE,
+ MENUACTION_PARSEHEAP,
+ MENUACTION_SHOWCULL,
+ MENUACTION_MEMCARDSAVECONFIRM,
+ MENUACTION_UPDATEMEMCARDSAVE,
+ MENUACTION_UNK50,
+ MENUACTION_DEBUGSTREAM,
+ MENUACTION_MPMAP_LIBERTY,
+ MENUACTION_MPMAP_REDLIGHT,
+ MENUACTION_MPMAP_CHINATOWN,
+ MENUACTION_MPMAP_TOWER,
+ MENUACTION_MPMAP_SEWER,
+ MENUACTION_MPMAP_INDUSTPARK,
+ MENUACTION_MPMAP_DOCKS,
+ MENUACTION_MPMAP_STAUNTON,
+ MENUACTION_MPMAP_DEATHMATCH1,
+ MENUACTION_MPMAP_DEATHMATCH2,
+ MENUACTION_MPMAP_TEAMDEATH1,
+ MENUACTION_MPMAP_TEAMDEATH2,
+ MENUACTION_MPMAP_STASH,
+ MENUACTION_MPMAP_CAPTURE,
+ MENUACTION_MPMAP_RATRACE,
+ MENUACTION_MPMAP_DOMINATION,
+ MENUACTION_STARTMP,
+ MENUACTION_UNK69,
+ MENUACTION_UNK70,
+ MENUACTION_FINDMP,
+ MENUACTION_REDEFCTRL,
+ MENUACTION_UNK73,
+ MENUACTION_INITMP,
+ MENUACTION_MP_PLAYERCOLOR,
+ MENUACTION_MP_PLAYERNAME,
+ MENUACTION_MP_GAMENAME,
+ MENUACTION_GETKEY,
+ MENUACTION_SHOWHEADBOB,
+ MENUACTION_UNK80,
+ MENUACTION_INVVERT,
+ MENUACTION_CANCLEGAME,
+ MENUACTION_MP_PLAYERNUMBER,
+ MENUACTION_MOUSESENS,
+ MENUACTION_CHECKMPGAMES,
+ MENUACTION_CHECKMPPING,
+ MENUACTION_MP_SERVER,
+ MENUACTION_MP_MAP,
+ MENUACTION_MP_GAMETYPE,
+ MENUACTION_MP_LAN,
+ MENUACTION_MP_INTERNET,
+ MENUACTION_RESUME,
+ MENUACTION_DONTCANCLE,
+ MENUACTION_SCREENRES,
+ MENUACTION_AUDIOHW,
+ MENUACTION_SPEAKERCONF,
+ MENUACTION_PLAYERSETUP,
+ MENUACTION_RESTOREDEF,
+ MENUACTION_CTRLMETHOD,
+ MENUACTION_DYNAMICACOUSTIC,
+ MENUACTION_LOADRADIO,
+ MENUACTION_MOUSESTEER,
+ MENUACTION_UNK103,
+ MENUACTION_UNK104,
+ MENUACTION_UNK105,
+ MENUACTION_UNK106,
+ MENUACTION_UNK107,
+ MENUACTION_UNK108,
+ MENUACTION_UNK109,
+ MENUACTION_UNK110,
+};
+
+enum eCheckHover
+{
+ ACTIVATE_OPTION = 2,
+ IGNORE_OPTION = 42,
+};
+
+enum eMenuColumns
+{
+ MENUCOLUMN_LEFT,
+ MENUCOLUMN_CENTER,
+ MENUCOLUMN_RIGHT,
+ MENUCOLUMNS,
+};
+
+enum eMenuRow
+{
+ MENUROW_0,
+ MENUROW_1,
+ MENUROW_2,
+ MENUROW_3,
+ MENUROW_4,
+ MENUROW_5,
+ MENUROW_6,
+ MENUROW_7,
+ MENUROW_8,
+ MENUROW_9,
+ MENUROW_10,
+ MENUROW_11,
+ MENUROW_12,
+ MENUROW_13,
+ MENUROW_14,
+ MENUROW_15,
+ MENUROW_16,
+ MENUROW_17,
+ MENUROWS,
};
struct tSkinInfo
@@ -81,6 +344,21 @@ struct tSkinInfo
int field_304;
};
+struct CMenuScreen
+{
+ char m_ScreenName[8];
+ int32 m_PreviousPage[3]; // eMenuScreen
+ int32 m_ParentEntry[2]; // eMenuRow
+
+ struct CMenuEntry
+ {
+ int32 m_Action; // eMenuAction
+ char m_EntryName[8];
+ int32 m_SaveSlot; // eSaveSlot
+ int32 m_TargetMenu; // eMenuScreen
+ } m_aEntries[MENUROWS];
+};
+
class CMenuManager
{
public:
@@ -136,10 +414,10 @@ public:
int m_nHelperTextAlpha;
int m_nMouseOldPosX;
int m_nMouseOldPosY;
- int field_544;
+ int m_nHoverOption;
int m_nCurrScreen;
int m_nCurrOption;
- int field_550;
+ int m_nCurrentInput;
int m_nPrevScreen;
int field_558;
int m_nCurrSaveSlot;
@@ -165,17 +443,52 @@ public:
static int8 &m_bFrontEnd_ReloadObrTxtGxt;
static int32 &m_PrefsMusicVolume;
static int32 &m_PrefsSfxVolume;
-
- static bool &m_PrefsAllowNastyGame;
static bool &m_bStartUpFrontEndRequested;
+ static bool &m_bShutDownFrontEndRequested;
+ static bool &m_PrefsAllowNastyGame;
- void Process(void);
- void DrawFrontEnd(void);
- void UnloadTextures(void);
- void LoadAllTextures(void);
- void LoadSettings(void);
- void WaitForUserCD(void);
+public:
+ void BuildStatLine(char *, void *, uint16, void *);
+ static void CentreMousePointer();
+ void CheckCodesForControls(int, int);
+ bool CheckHover(int x1, int x2, int y1, int y2);
+ int CostructStatLine(int);
+ void DisplayHelperText();
+ float DisplaySlider(float, float, float, float, float, float);
+ void DoSettingsBeforeStartingAGame();
+ void Draw();
+ void DrawControllerBound(int, int, int, uint8);
+ void DrawControllerScreenExtraText(int, int, int);
+ void DrawControllerSetupScreen();
+ void DrawFrontEnd();
+ void DrawFrontEndNormal();
+ void DrawPlayerSetupScreen();
int FadeIn(int alpha);
+ void FilterOutColorMarkersFromString(uint16, CRGBA &);
+ int GetStartOptionsCntrlConfigScreens();
+ static void InitialiseChangedLanguageSettings();
+ void LoadAllTextures();
+ void LoadSettings();
+ static void MessageScreen(char *);
+ static void PickNewPlayerColour();
+ void PrintBriefs();
+ static void PrintErrorMessage();
+ void PrintStats();
+ void Process();
+ void ProcessButtonPresses();
+ void ProcessOnOffMenuOptions();
+ static void RequestFrontEndShutdown();
+ static void RequestFrontEndStartUp();
+ void ResetHelperText();
+ void SaveLoadFileError_SetUpErrorScreen();
+ void SaveSettings();
+ void SetHelperText(int text);
+ void ShutdownJustMenu();
+ static float StretchX(float);
+ static float StretchY(float );
+ void SwitchMenuOnAndOff();
+ void UnloadTextures();
+ void WaitForUserCD();
};
static_assert(sizeof(CMenuManager) == 0x564, "CMenuManager: error");
diff --git a/src/MenuScreens.h b/src/MenuScreens.h
new file mode 100644
index 00000000..640952ed
--- /dev/null
+++ b/src/MenuScreens.h
@@ -0,0 +1,380 @@
+#pragma once
+
+const CMenuScreen aScreens[] = {
+ // MENUPAGE_NONE = 0
+ { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0, },
+
+ // MENUPAGE_STATS = 1
+ { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_5, MENUROW_2,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_NEW_GAME = 2
+ { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_0, MENUROW_1,
+ MENUACTION_CHANGEMENU, "FES_SNG", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD,
+ MENUACTION_UPDATESAVE, "GMLOAD", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
+ MENUACTION_CHANGEMENU, "FES_DGA", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_BRIEFS = 3
+ { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_6, MENUROW_3,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENU_CONTROLLER_SETTINGS = 4
+ { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_SOUND_SETTINGS = 5
+ { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_1, MENUROW_1,
+ MENUACTION_MUSICVOLUME, "FEA_MUS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_SFXVOLUME, "FEA_SFX", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_AUDIOHW, "FEA_3DH", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_SPEAKERCONF, "FEA_SPK", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_DYNAMICACOUSTIC, "FET_DAM", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_RADIO, "FEA_RSS", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ },
+
+ // MENUPAGE_GRAPHICS_SETTINGS = 6
+ { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_2, MENUROW_2,
+ MENUACTION_BRIGHTNESS, "FED_BRI", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_DRAWDIST, "FEM_LOD", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_FRAMESYNC, "FEM_VSC", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_FRAMELIMIT, "FEM_FRM", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_TRAILS, "FED_TRA", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_SUBTITLES, "FED_SUB", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_WIDESCREEN, "FED_WIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_SCREENRES, "FED_RES", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_LANGUAGE_SETTINGS = 7
+ { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_3, MENUROW_3,
+ MENUACTION_LANG_ENG, "FEL_ENG", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
+ MENUACTION_LANG_FRE, "FEL_FRE", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
+ MENUACTION_LANG_GER, "FEL_GER", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
+ MENUACTION_LANG_ITA, "FEL_ITA", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
+ MENUACTION_LANG_SPA, "FEL_SPA", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_CHOOSE_LOAD_SLOT = 8
+ { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_1, MENUROW_1,
+ MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
+ MENUACTION_CHECKSAVE, "FEM_SL1", SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM,
+ MENUACTION_CHECKSAVE, "FEM_SL2", SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM,
+ MENUACTION_CHECKSAVE, "FEM_SL3", SAVESLOT_3, MENUPAGE_LOAD_SLOT_CONFIRM,
+ MENUACTION_CHECKSAVE, "FEM_SL4", SAVESLOT_4, MENUPAGE_LOAD_SLOT_CONFIRM,
+ MENUACTION_CHECKSAVE, "FEM_SL5", SAVESLOT_5, MENUPAGE_LOAD_SLOT_CONFIRM,
+ MENUACTION_CHECKSAVE, "FEM_SL6", SAVESLOT_6, MENUPAGE_LOAD_SLOT_CONFIRM,
+ MENUACTION_CHECKSAVE, "FEM_SL7", SAVESLOT_7, MENUPAGE_LOAD_SLOT_CONFIRM,
+ MENUACTION_CHECKSAVE, "FEM_SL8", SAVESLOT_8, MENUPAGE_LOAD_SLOT_CONFIRM,
+ },
+
+ // MENUPAGE_CHOOSE_DELETE_SLOT = 9
+ { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_2, MENUROW_2,
+ MENUACTION_CHANGEMENU, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
+ MENUACTION_CHANGEMENU, "FEM_SL1", SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL2", SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL3", SAVESLOT_3, MENUPAGE_DELETE_SLOT_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL4", SAVESLOT_4, MENUPAGE_DELETE_SLOT_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL5", SAVESLOT_5, MENUPAGE_DELETE_SLOT_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL6", SAVESLOT_6, MENUPAGE_DELETE_SLOT_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL7", SAVESLOT_7, MENUPAGE_DELETE_SLOT_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL8", SAVESLOT_8, MENUPAGE_DELETE_SLOT_CONFIRM,
+ },
+
+ // MENUPAGE_NEW_GAME_RELOAD = 10
+ { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FESZ_QR", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
+ MENUACTION_NEWGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD,
+ },
+
+ // MENUPAGE_LOAD_SLOT_CONFIRM = 11
+ { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FESZ_QL", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
+ MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS,
+ },
+
+ // MENUPAGE_DELETE_SLOT_CONFIRM = 12
+ { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FESZ_QD", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
+ MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_DELETING,
+ },
+
+ // MENUPAGE_13 = 13
+ { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_LOADING_IN_PROGRESS = 14
+ { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FED_LDW", SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM,
+ },
+
+ // MENUPAGE_DELETING_IN_PROGRESS = 15
+ { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FEDL_WR", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_16 = 16
+ { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FES_LOE", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_DELETE_FAILED = 17
+ { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FES_DEE", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
+ },
+
+ // MENUPAGE_DEBUG_MENU = 18
+ { "FED_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MEMORY_CARD_1 = 19
+ { "FEM_MCM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MEMORY_CARD_2 = 20
+ { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MULTIPLAYER_MAIN = 21
+ { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_SAVE_FAILED_1 = 22
+ { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_SAVE_FAILED_2 = 23
+ { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_SAVE = 24
+ { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FES_SCG", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_UPDATESAVE, "GMSAVE", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
+ MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_NO_MEMORY_CARD = 25
+ { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_CHOOSE_SAVE_SLOT = 26
+ { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_UPDATEMEMCARDSAVE, "FESZ_CA", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEM_SL1", SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL2", SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL3", SAVESLOT_3, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL4", SAVESLOT_4, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL5", SAVESLOT_5, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL6", SAVESLOT_6, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL7", SAVESLOT_7, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ MENUACTION_CHANGEMENU, "FEM_SL8", SAVESLOT_8, MENUPAGE_SAVE_OVERWRITE_CONFIRM,
+ },
+
+ // MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FESZ_QO", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS,
+ MENUACTION_CHANGEMENU, "FEM_NO", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
+ },
+
+ // MENUPAGE_MULTIPLAYER_MAP = 28
+ { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MULTIPLAYER_CONNECTION = 29
+ { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MULTIPLAYER_FIND_GAME = 30
+ { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MULTIPLAYER_MODE = 31
+ { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MULTIPLAYER_CREATE = 32
+ { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_MULTIPLAYER_START = 33
+ { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_SKIN_SELECT_OLD = 34
+ { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_CONTROLLER_PC = 35
+ { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_0, MENUROW_0,
+ MENUACTION_CTRLMETHOD, "FET_CME", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+ MENUACTION_REDEFCTRL, "FET_RDK", SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS,
+ MENUACTION_CHANGEMENU, "FET_AMS", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS,
+ MENUACTION_RESTOREDEF, "FET_DEF", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_CONTROLLER_PC_OLD1 = 36
+ { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_CONTROLLER_PC_OLD2 = 37
+ { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_CONTROLLER_PC_OLD3 = 38
+ { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_CONTROLLER_PC_OLD4 = 39
+ { "FET_CTL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_CONTROLLER_DEBUG = 40
+ { "FEC_DBG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_OPTIONS = 41
+ { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_1, MENUROW_4,
+ MENUACTION_CHANGEMENU, "FET_CTL", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+ MENUACTION_LOADRADIO, "FET_AUD", SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS,
+ MENUACTION_CHANGEMENU, "FET_DIS", SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS,
+ MENUACTION_CHANGEMENU, "FET_LAN", SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS,
+ MENUACTION_PLAYERSETUP, "FET_PSU", SAVESLOT_NONE, MENUPAGE_SKIN_SELECT,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_EXIT = 42
+ { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, MENUPAGE_NONE, MENUROW_2, MENUROW_5,
+ MENUACTION_LABEL, "FEQ_SRE", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_DONTCANCLE, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CANCLEGAME, "FEM_YES", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_SAVING_IN_PROGRESS = 43
+ { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FES_WAR", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_SAVE_SUCCESSFUL = 44
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FES_SSC", SAVESLOT_LABEL, MENUPAGE_NONE,
+ MENUACTION_UPDATEMEMCARDSAVE, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
+ },
+
+ // MENUPAGE_DELETING = 45
+ { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FED_DLW", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_DELETE_SUCCESS = 46
+ { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "DEL_FNM", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT,
+ },
+
+ // MENUPAGE_SAVE_FAILED = 47
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEC_OKK", SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT,
+ },
+
+ // MENUPAGE_LOAD_FAILED = 48
+ { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FEC_SVU", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_LOAD_FAILED_2 = 49
+ { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, MENUROW_0, MENUROW_0,
+ MENUACTION_LABEL, "FEC_LUN", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT,
+ },
+
+ // MENUPAGE_FILTER_GAME = 50
+ { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_START_MENU = 51
+ { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
+ MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS,
+ MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT,
+ },
+
+ // MENUPAGE_PAUSE_MENU = 52
+ { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+ MENUACTION_RESUME, "FEM_RES", SAVESLOT_NONE, MENUPAGE_NONE,
+ MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME,
+ MENUACTION_CHANGEMENU, "FEP_STA", SAVESLOT_NONE, MENUPAGE_STATS,
+ MENUACTION_CHANGEMENU, "FEP_BRI", SAVESLOT_NONE, MENUPAGE_BRIEFS,
+ MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS,
+ MENUACTION_CHANGEMENU, "FEM_QT", SAVESLOT_NONE, MENUPAGE_EXIT,
+ },
+
+ // MENUPAGE_CHOOSE_MODE = 53
+ { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_SKIN_SELECT = 54
+ { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, MENUROW_4, MENUROW_4,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN,
+ },
+
+ // MENUPAGE_KEYBOARD_CONTROLS = 55
+ { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_1, MENUROW_1,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+ },
+
+ // MENUPAGE_MOUSE_CONTROLS = 56
+ { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, MENUROW_2, MENUROW_2,
+ MENUACTION_MOUSESENS, "FEC_MSH", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+ MENUACTION_INVVERT, "FEC_IVV", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+ MENUACTION_MOUSESTEER, "FET_MST", SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC,
+ MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE,
+ },
+
+ // MENUPAGE_57 = 57
+ { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+
+ // MENUPAGE_58 = 58
+ { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUPAGE_DISABLED, MENUROW_0, MENUROW_0,
+
+ },
+};
diff --git a/src/PCSave.cpp b/src/PCSave.cpp
index 2d49b23f..ae5e43b0 100644
--- a/src/PCSave.cpp
+++ b/src/PCSave.cpp
@@ -4,4 +4,9 @@
#include "PCSave.h"
WRAPPER void C_PcSave::SetSaveDirectory(const char *path) { EAXJMP(0x591EA0); }
+WRAPPER wchar *GetNameOfSavedGame(int counter) { EAXJMP(0x591B60); }
+WRAPPER wchar *GetSavedGameDateAndTime(int counter) { EAXJMP(0x591B50); }
+int *Slots = (int*)0x728040;
+int *SlotFileName = (int*)0x6F07C8;
+int *SlotSaveDate = (int*)0x72B858;
diff --git a/src/PCSave.h b/src/PCSave.h
index 324a3421..79202bc9 100644
--- a/src/PCSave.h
+++ b/src/PCSave.h
@@ -4,4 +4,11 @@ class C_PcSave
{
public:
static void SetSaveDirectory(const char *path);
-}; \ No newline at end of file
+};
+
+extern wchar *GetNameOfSavedGame(int counter);
+extern wchar *GetSavedGameDateAndTime(int counter);
+
+extern int *Slots;
+extern int *SlotFileName;
+extern int *SlotSaveDate;
diff --git a/src/Placeable.cpp b/src/Placeable.cpp
index 43708d3e..b4b2a37b 100644
--- a/src/Placeable.cpp
+++ b/src/Placeable.cpp
@@ -20,56 +20,47 @@ CPlaceable::SetHeading(float angle)
bool
CPlaceable::IsWithinArea(float x1, float y1, float x2, float y2)
{
- float x, xmin, xmax;
- float y, ymin, ymax;
- xmin = x1;
- xmax = x2;
- ymin = y1;
- ymax = y2;
- if(x2 > x1){
- xmin = x2;
- xmax = x1;
+ float tmp;
+
+ if(x1 > x2){
+ tmp = x1;
+ x1 = x2;
+ x2 = tmp;
}
- if(y2 > y1){
- ymin = y2;
- ymax = y1;
+ if(y1 > y2){
+ tmp = y1;
+ y1 = y2;
+ y2 = tmp;
}
- x = GetPosition().x;
- y = GetPosition().y;
- return xmin <= x && x <= xmax &&
- ymin <= y && y <= ymax;
+
+ return x1 <= GetPosition().x && GetPosition().x <= x2 &&
+ y1 <= GetPosition().y && GetPosition().y <= y2;
}
bool
CPlaceable::IsWithinArea(float x1, float y1, float z1, float x2, float y2, float z2)
{
- float x, xmin, xmax;
- float y, ymin, ymax;
- float z, zmin, zmax;
- xmin = x1;
- xmax = x2;
- ymin = y1;
- ymax = y2;
- zmin = z1;
- zmax = z2;
- if(x2 > x1){
- xmin = x2;
- xmax = x1;
+ float tmp;
+
+ if(x1 > x2){
+ tmp = x1;
+ x1 = x2;
+ x2 = tmp;
}
- if(y2 > y1){
- ymin = y2;
- ymax = y1;
+ if(y1 > y2){
+ tmp = y1;
+ y1 = y2;
+ y2 = tmp;
}
- if(z2 > z1){
- zmin = z2;
- zmax = z1;
+ if(z1 > z2){
+ tmp = z1;
+ z1 = z2;
+ z2 = tmp;
}
- x = GetPosition().x;
- y = GetPosition().y;
- z = GetPosition().z;
- return xmin <= x && x <= xmax &&
- ymin <= y && y <= ymax &&
- zmin <= z && z <= zmax;
+
+ return x1 <= GetPosition().x && GetPosition().x <= x2 &&
+ y1 <= GetPosition().y && GetPosition().y <= y2 &&
+ z1 <= GetPosition().z && GetPosition().z <= z2;
}
STARTPATCHES
diff --git a/src/Radar.cpp b/src/Radar.cpp
index 155ec5e0..1b6ca527 100644
--- a/src/Radar.cpp
+++ b/src/Radar.cpp
@@ -1,6 +1,7 @@
#include "config.h"
#include "common.h"
#include "patcher.h"
+#include "RwHelper.h"
#include "Radar.h"
#include "Camera.h"
#include "Hud.h"
@@ -14,16 +15,10 @@
#include "World.h"
#include "Streaming.h"
-WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); }
-WRAPPER int CRadar::ClipRadarPoly(CVector2D *out, CVector2D *in) { EAXJMP(0x4A64A0); }
-WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in) { EAXJMP(0x4A5300); }
-
float &CRadar::m_RadarRange = *(float*)0x8E281C;
-CVector2D &CRadar::vec2DRadarOrigin = *(CVector2D*)0x6299B8;
CBlip *CRadar::ms_RadarTrace = (CBlip*)0x6ED5E0;
-float CRadar::cachedSin;
-float CRadar::cachedCos;
+CVector2D &vec2DRadarOrigin = *(CVector2D*)0x6299B8;
int *gRadarTxdIds = (int*)0x6299C0;
CSprite2d *CRadar::AsukaSprite = (CSprite2d*)0x8F1A40;
@@ -71,222 +66,198 @@ CSprite2d *CRadar::RadarSprites[RADAR_SPRITE_COUNT] = {
WeaponSprite
};
-#if 0
-WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); }
-#else
-void CRadar::DrawMap()
-{
- if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
- if (FindPlayerVehicle()) {
- if (FindPlayerVehicle()->GetSpeed().Magnitude() > 0.3f) {
- if (FindPlayerVehicle()->GetSpeed().Magnitude() > 0.9f)
- CRadar::m_RadarRange = 350.0f;
- else
- CRadar::m_RadarRange = (FindPlayerVehicle()->GetSpeed().Magnitude() + 0.3f) * 200.0f;
- }
- else
- CRadar::m_RadarRange = 120.0f;
- }
- else
- CRadar::m_RadarRange = 120.0f;
+#define RADAR_NUM_TILES (8)
+#define RADAR_TILE_SIZE (WORLD_SIZE_X / RADAR_NUM_TILES)
+static_assert(RADAR_TILE_SIZE == (WORLD_SIZE_Y / RADAR_NUM_TILES), "CRadar: not a square");
- vec2DRadarOrigin.x = FindPlayerCentreOfWorld_NoSniperShift().x;
- vec2DRadarOrigin.y = FindPlayerCentreOfWorld_NoSniperShift().y;
- CRadar::DrawRadarMap();
- }
-}
-#endif
+#define RADAR_MIN_RANGE (120.0f)
+#define RADAR_MAX_RANGE (350.0f)
+#define RADAR_MIN_SPEED (0.3f)
+#define RADAR_MAX_SPEED (0.9f)
#if 0
-WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); }
+WRAPPER void CRadar::CalculateBlipAlpha(float) { EAXJMP(0x4A4F90); }
#else
-void CRadar::DrawRadarMask()
-{
- CVector2D vec2d[4] = {
- CVector2D(1.0f, -1.0f),
- CVector2D(1.0f, 1.0f),
- CVector2D(-1.0f, 1.0f),
- CVector2D(-1.0, -1.0f)
- };
-
- RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
- RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
- RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
- RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONALWAYS);
-
- CVector2D out[8];
- CVector2D in;
-
- for (int i = 0; i < 4; i++) {
- in.x = vec2d[i].x;
- in.y = vec2d[i].y;
-
- CRadar::TransformRadarPointToScreenSpace(out, &in);
-
- for (int j = 0; j < 7; j++) {
- CRadar::cachedCos = cos(j * (PI / 2.0f / 6.0f));
- CRadar::cachedSin = sin(j * (PI / 2.0f / 6.0f));
-
- in.x = vec2d[i].x * cachedCos;
- in.y = vec2d[i].y * cachedSin;
- CRadar::TransformRadarPointToScreenSpace(&out[j + 1], &in);
- };
+int CRadar::CalculateBlipAlpha(float dist)
+{
+ if (dist <= 1.0f)
+ return 255;
- CSprite2d::SetMaskVertices(8, (float *)out);
- RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8);
- };
+ if (dist <= 5.0f)
+ return (((1.0f - ((dist * 0.25f) - 0.25f)) * 255.0f) + (((dist * 0.25f) - 0.25f) * 128.0f));
- RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER);
+ return 128;
}
#endif
-#if 0
-WRAPPER void CRadar::SetRadarMarkerState(int counter, int flag) { EAXJMP(0x4A5C60); }
+#if 1
+WRAPPER void CRadar::ChangeBlipBrightness(int32, int32) { EAXJMP(0x4A57A0); }
#else
-void CRadar::SetRadarMarkerState(int counter, int flag)
+void CRadar::ChangeBlipBrightness(int32 i, int32 bright)
{
- CEntity *e;
- switch (ms_RadarTrace[counter].m_eBlipType) {
- case BLIP_CAR:
- e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
- break;
- case BLIP_CHAR:
- e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
- break;
- case BLIP_OBJECT:
- e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
- break;
- default:
- return;
- };
-
- if (e)
- e->bHasBlip = flag;
}
#endif
-#if 0
-WRAPPER void CRadar::ClearBlipForEntity(eBlipType type, int32 id) { EAXJMP(0x4A56C0); }
+#if 1
+WRAPPER void CRadar::ChangeBlipColour(int32) { EAXJMP(0x4A5770); }
#else
-void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
+void CRadar::ChangeBlipColour(int32 i)
{
- for (int i = 0; i < NUMBLIPS; i++) {
- if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) {
- CRadar::SetRadarMarkerState(i, 0);
- ms_RadarTrace[i].m_bInUse = 0;
- ms_RadarTrace[i].m_eBlipType = 0;
- ms_RadarTrace[i].m_eBlipDisplay = 0;
- ms_RadarTrace[i].m_IconID = 0;
- }
- };
+
}
#endif
#if 1
-WRAPPER void CRadar::DrawRadarSection(int x, int y) { EAXJMP(0x4A67E0); }
+WRAPPER void CRadar::ChangeBlipDisplay(int32, int16) { EAXJMP(0x4A5810); }
#else
-void CRadar::DrawRadarSection(int x, int y)
+void CRadar::ChangeBlipDisplay(int32 i, int16 flag)
{
-
+
}
#endif
-void CRadar::RequestMapSection(int x, int y)
+#if 1
+WRAPPER void CRadar::ChangeBlipScale(int32, int16) { EAXJMP(0x4A57E0); }
+#else
+void CRadar::ChangeBlipScale(int32 i, int16 scale)
{
- ClipRadarTileCoords(&x, &y);
- CStreaming::RequestModel(gRadarTxdIds[x + 8 * y] + 5500, 5);
+
}
+#endif
-void CRadar::RemoveMapSection(int x, int y)
+#if 1
+WRAPPER void CRadar::ClearBlip(int32) { EAXJMP(0x4A5720); }
+#else
+void CRadar::ClearBlip(int32 i)
{
- if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
- CStreaming::RemoveModel(gRadarTxdIds[x + 8 * y] + 5500);
+
}
+#endif
#if 0
-WRAPPER void CRadar::StreamRadarSections(int x, int y) { EAXJMP(0x4A6100); }
+WRAPPER void CRadar::ClearBlipForEntity(int16, int32) { EAXJMP(0x4A56C0); }
#else
-void CRadar::StreamRadarSections(int x, int y)
+void CRadar::ClearBlipForEntity(int16 type, int32 id)
{
- for (int i = 0; i < 8; ++i) {
- for (int j = 0; j < 8; ++j) {
- if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1))
- RequestMapSection(i, j);
- else
- RemoveMapSection(i, j);
- };
+ for (int i = 0; i < NUMRADARBLIPS; i++) {
+ if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) {
+ SetRadarMarkerState(i, 0);
+ ms_RadarTrace[i].m_bInUse = 0;
+ ms_RadarTrace[i].m_eBlipType = 0;
+ ms_RadarTrace[i].m_eBlipDisplay = 0;
+ ms_RadarTrace[i].m_IconID = 0;
+ }
};
}
#endif
#if 0
-WRAPPER float CRadar::LimitRadarPoint(CVector2D *point) { EAXJMP(0x4A4F30); }
+WRAPPER int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *in) { EAXJMP(0x4A64A0); }
#else
-float CRadar::LimitRadarPoint(CVector2D *point)
+// Why not a proper clipping algorithm?
+int CRadar::ClipRadarPoly(CVector2D *poly, const CVector2D *rect)
{
- float div;
+ CVector2D corners[4] = {
+ { 1.0f, -1.0f }, // top right
+ { 1.0f, 1.0f }, // bottom right
+ { -1.0f, 1.0f }, // bottom left
+ { -1.0f, -1.0f }, // top left
+ };
+ CVector2D tmp;
+ int i, j, n;
+ int laste, e, e1, e2;;
+ bool inside[4];
+
+ for (i = 0; i < 4; i++)
+ inside[i] = IsPointInsideRadar(rect[i]);
+
+ laste = -1;
+ n = 0;
+ for (i = 0; i < 4; i++)
+ if (inside[i]) {
+ // point is inside, just add
+ poly[n++] = rect[i];
+ }
+ else {
+ // point is outside but line to this point might be clipped
+ e1 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 4 - 1) % 4]);
+ if (e1 != -1) {
+ laste = e1;
+ n++;
+ }
+ // and line from this point might be clipped as well
+ e2 = LineRadarBoxCollision(poly[n], rect[i], rect[(i + 1) % 4]);
+ if (e2 != -1) {
+ if (e1 == -1) {
+ // if other line wasn't clipped, i.e. it was complete outside,
+ // we may have to insert another vertex if last clipped line
+ // was on a different edge
+
+ // find the last intersection if we haven't seen it yet
+ if (laste == -1)
+ for (j = 3; j >= i; j--) {
+ // game uses an if here for j == 0
+ e = LineRadarBoxCollision(tmp, rect[j], rect[(j + 4 - 1) % 4]);
+ if (e != -1) {
+ laste = e;
+ break;
+ }
+ }
+ assert(laste != -1);
+
+ // insert corners that were skipped
+ tmp = poly[n];
+ for (e = laste; e != e2; e = (e + 1) % 4)
+ poly[n++] = corners[e];
+ poly[n] = tmp;
+ }
+ n++;
+ }
+ }
- if (point->Magnitude() > 1.0f) {
- div = 1.0f / point->Magnitude();
- point->x *= div;
- point->y *= div;
+ if (n == 0) {
+ // If no points, either the rectangle is completely outside or completely surrounds the radar
+ // no idea what's going on here...
+ float m = (rect[0].y - rect[1].y) / (rect[0].x - rect[1].x);
+ if ((m*rect[3].x - rect[3].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
+ m = (rect[0].y - rect[3].y) / (rect[0].x - rect[3].x);
+ if ((m*rect[1].x - rect[1].y) * (m*rect[0].x - rect[0].y) < 0.0f) {
+ poly[0] = corners[0];
+ poly[1] = corners[1];
+ poly[2] = corners[2];
+ poly[3] = corners[3];
+ n = 4;
+ }
+ }
}
- return point->Magnitude();
+
+ return n;
}
#endif
-#if 0
-WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) { EAXJMP(0x4A5530); }
-#else
-void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) {
- out->x = in->x - (x * 500.0f - WORLD_MAX_X);
- out->y = -(in->y - ((8 - y) * 500.0f - WORLD_MAX_Y));
- out->x *= 0.002f;
- out->y *= 0.002f;
+bool CRadar::DisplayThisBlip(int32 counter)
+{
+ switch (ms_RadarTrace[counter].m_IconID) {
+ case RADAR_SPRITE_BOMB:
+ case RADAR_SPRITE_SPRAY:
+ case RADAR_SPRITE_WEAPON:
+ return true;
+ default:
+ return false;
+ }
}
-#endif
-#if 0
-WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); }
+#if 1
+WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); }
#else
-void CRadar::DrawRadarMap()
+void CRadar::Draw3dMarkers()
{
- CRadar::DrawRadarMask();
-
- int x = floorf((WORLD_MAX_X + vec2DRadarOrigin.x) * 0.002f);
- int y = round(7.0f - (WORLD_MAX_Y + vec2DRadarOrigin.y) * 0.002f);
- CRadar::StreamRadarSections(x, y);
- RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
- RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
- RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
- RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
- RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
- RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
- RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
- RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE);
-
- CRadar::DrawRadarSection(x - 1, y - 1);
- CRadar::DrawRadarSection(x, y - 1);
- CRadar::DrawRadarSection(x + 1, y - 1);
- CRadar::DrawRadarSection(x - 1, y);
- CRadar::DrawRadarSection(x, y);
- CRadar::DrawRadarSection(x + 1, y);
- CRadar::DrawRadarSection(x - 1, y + 1);
- CRadar::DrawRadarSection(x, y + 1);
- CRadar::DrawRadarSection(x + 1, y + 1);
}
#endif
+
#if 0
WRAPPER void CRadar::DrawBlips() { EAXJMP(0x4A42F0); }
#else
@@ -302,7 +273,7 @@ void CRadar::DrawBlips()
CVector2D out;
CVector2D in = CVector2D(0.0f, 0.0f);
- CRadar::TransformRadarPointToScreenSpace(&out, &in);
+ TransformRadarPointToScreenSpace(out, in);
float angle;
if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1)
@@ -310,20 +281,20 @@ void CRadar::DrawBlips()
else
angle = FindPlayerHeading() - (PI + atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y));
- CRadar::DrawRotatingRadarSprite(CentreSprite, out.x, out.y, angle, 255);
+ DrawRotatingRadarSprite(CentreSprite, out.x, out.y, angle, 255);
CVector2D vec2d;
vec2d.x = vec2DRadarOrigin.x;
vec2d.y = M_SQRT2 * m_RadarRange + vec2DRadarOrigin.y;
- CRadar::TransformRealWorldPointToRadarSpace(&in, &vec2d);
- CRadar::LimitRadarPoint(&in);
- CRadar::TransformRadarPointToScreenSpace(&out, &in);
- CRadar::DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255);
+ TransformRealWorldPointToRadarSpace(in, vec2d);
+ LimitRadarPoint(in);
+ TransformRadarPointToScreenSpace(out, in);
+ DrawRadarSprite(RADAR_SPRITE_NORTH, out.x, out.y, 255);
/*
DrawEntityBlip
*/
- for (int i = 0; i < NUMBLIPS; i++) {
+ for (int i = 0; i < NUMRADARBLIPS; i++) {
if (ms_RadarTrace[i].m_bInUse) {
if (ms_RadarTrace[i].m_eBlipType <= BLIP_OBJECT) {
CEntity *e = nil;
@@ -342,7 +313,7 @@ void CRadar::DrawBlips()
if (e) {
if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
if (CTheScripts::DbgFlag) {
- CRadar::ShowRadarMarker(e->GetPosition(), GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius);
+ ShowRadarMarker(e->GetPosition(), GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius);
ms_RadarTrace[i].m_Radius = ms_RadarTrace[i].m_Radius - 0.1f;
if (ms_RadarTrace[i].m_Radius >= 1.0f)
@@ -351,17 +322,17 @@ void CRadar::DrawBlips()
}
if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
vec2d = e->GetPosition();
- CRadar::TransformRealWorldPointToRadarSpace(&in, &vec2d);
- float dist = CRadar::LimitRadarPoint(&in);
- int a = CRadar::CalculateBlipAlpha(dist);
- CRadar::TransformRadarPointToScreenSpace(&out, &in);
+ TransformRealWorldPointToRadarSpace(in, vec2d);
+ float dist = LimitRadarPoint(in);
+ int a = CalculateBlipAlpha(dist);
+ TransformRadarPointToScreenSpace(out, in);
- CRGBA col = CRadar::GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim);
+ int32 col = GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim);
if (ms_RadarTrace[i].m_IconID)
- CRadar::DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a);
+ DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a);
else
- CRadar::ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, col.r, col.g, col.b, 255);
+ ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, ((col >> 24)), ((col >> 16) & 0xFF), ((col >> 8)), 255);
}
}
}
@@ -373,7 +344,7 @@ void CRadar::DrawBlips()
if (ms_RadarTrace[i].m_eBlipType != BLIP_CONTACT_POINT || ms_RadarTrace[i].m_eBlipType == BLIP_CONTACT_POINT && DisplayThisBlip(i) || !CTheScripts::IsPlayerOnAMission()) {
if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_MARKER_ONLY) {
if (CTheScripts::DbgFlag) {
- CRadar::ShowRadarMarker(ms_RadarTrace[i].m_vecPos, CRadar::GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius);
+ ShowRadarMarker(ms_RadarTrace[i].m_vecPos, GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim), ms_RadarTrace->m_Radius);
ms_RadarTrace[i].m_Radius = ms_RadarTrace[i].m_Radius - 0.1f;
if (ms_RadarTrace[i].m_Radius >= 1.0f)
ms_RadarTrace[i].m_Radius = 5.0f;
@@ -381,17 +352,17 @@ void CRadar::DrawBlips()
}
if (ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BOTH || ms_RadarTrace[i].m_eBlipDisplay == BLIP_DISPLAY_BLIP_ONLY) {
- CRadar::TransformRealWorldPointToRadarSpace(&in, &ms_RadarTrace[i].m_vec2DPos);
- float dist = CRadar::LimitRadarPoint(&in);
- int a = CRadar::CalculateBlipAlpha(dist);
- CRadar::TransformRadarPointToScreenSpace(&out, &in);
+ TransformRealWorldPointToRadarSpace(in, ms_RadarTrace[i].m_vec2DPos);
+ float dist = LimitRadarPoint(in);
+ int a = CalculateBlipAlpha(dist);
+ TransformRadarPointToScreenSpace(out, in);
- CRGBA col = CRadar::GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim);
+ int32 col = GetRadarTraceColour(ms_RadarTrace[i].m_nColor, ms_RadarTrace[i].m_bDim);
- if (CRadar::ms_RadarTrace[i].m_IconID)
- CRadar::DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a);
+ if (ms_RadarTrace[i].m_IconID)
+ DrawRadarSprite(ms_RadarTrace[i].m_IconID, out.x, out.y, a);
else
- CRadar::ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, col.r, col.g, col.b, 255);
+ ShowRadarTrace(out.x, out.y, ms_RadarTrace[i].m_wScale, ((col >> 24)), ((col >> 16) & 0xFF), ((col >> 8)), 255);
}
}
}
@@ -401,109 +372,436 @@ void CRadar::DrawBlips()
}
#endif
-int CRadar::CalculateBlipAlpha(float dist)
+
+#if 0
+WRAPPER void CRadar::DrawMap () { EAXJMP(0x4A4200); }
+#else
+void CRadar::DrawMap()
{
- if (dist <= 1.0f)
- return 255;
+ if (!TheCamera.m_WideScreenOn && CHud::m_Wants_To_Draw_Hud) {
+ if (FindPlayerVehicle()) {
+ float speed = FindPlayerSpeed().Magnitude();
+ if (speed < RADAR_MIN_SPEED)
+ m_RadarRange = RADAR_MIN_RANGE;
+ else if (speed < RADAR_MAX_SPEED)
+ m_RadarRange = (speed - RADAR_MIN_SPEED)/(RADAR_MAX_SPEED-RADAR_MIN_SPEED) * (RADAR_MAX_RANGE-RADAR_MIN_RANGE) + RADAR_MIN_RANGE;
+ else
+ m_RadarRange = RADAR_MAX_RANGE;
+ }
+ else
+ m_RadarRange = RADAR_MIN_RANGE;
- if (dist <= 5.0f)
- return (((1.0f - ((dist * 0.25f) - 0.25f)) * 255.0f) + (((dist * 0.25f) - 0.25f) * 128.0f));
+ vec2DRadarOrigin = CVector2D(FindPlayerCentreOfWorld_NoSniperShift());
+ DrawRadarMap();
+ }
+}
+#endif
- return 128;
+#if 0
+WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); }
+#else
+void CRadar::DrawRadarMap()
+{
+ // Game calculates an unused CRect here
+
+ DrawRadarMask();
+
+ // top left ist (0, 0)
+ int x = floorf((vec2DRadarOrigin.x - WORLD_MIN_X) / RADAR_TILE_SIZE);
+ int y = ceilf((RADAR_NUM_TILES - 1) - (vec2DRadarOrigin.y - WORLD_MIN_Y) / RADAR_TILE_SIZE);
+ StreamRadarSections(x, y);
+
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP);
+ RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void*)FALSE);
+
+ DrawRadarSection(x - 1, y - 1);
+ DrawRadarSection(x, y - 1);
+ DrawRadarSection(x + 1, y - 1);
+ DrawRadarSection(x - 1, y);
+ DrawRadarSection(x, y);
+ DrawRadarSection(x + 1, y);
+ DrawRadarSection(x - 1, y + 1);
+ DrawRadarSection(x, y + 1);
+ DrawRadarSection(x + 1, y + 1);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRadarMask() { EAXJMP(0x4A69C0); }
+#else
+void CRadar::DrawRadarMask()
+{
+ CVector2D corners[4] = {
+ CVector2D(1.0f, -1.0f),
+ CVector2D(1.0f, 1.0f),
+ CVector2D(-1.0f, 1.0f),
+ CVector2D(-1.0, -1.0f)
+ };
+
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
+ RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
+ RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
+ RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE);
+ RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
+ RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
+ RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONALWAYS);
+
+ CVector2D out[8];
+ CVector2D in;
+
+ // Draw the shape we want to mask out from the radar in four segments
+ for (int i = 0; i < 4; i++) {
+ // First point is always the corner itself
+ in.x = corners[i].x;
+ in.y = corners[i].y;
+ TransformRadarPointToScreenSpace(out[0], in);
+
+ // Then generate a quarter of the circle
+ for (int j = 0; j < 7; j++) {
+ in.x = corners[i].x * cos(j * (PI / 2.0f / 6.0f));
+ in.y = corners[i].y * sin(j * (PI / 2.0f / 6.0f));
+ TransformRadarPointToScreenSpace(out[j + 1], in);
+ };
+
+ CSprite2d::SetMaskVertices(8, (float *)out);
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), 8);
+ };
+
+ RwD3D8SetRenderState(rwRENDERSTATESTENCILFUNCTION, rwSTENCILFUNCTIONGREATER);
}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRadarSection(int32, int32) { EAXJMP(0x4A67E0); }
+#else
+void CRadar::DrawRadarSection(int32 x, int32 y)
+{
+ int i;
+ RwTexDictionary *txd;
+ CVector2D worldPoly[8];
+ CVector2D radarCorners[4];
+ CVector2D radarPoly[8];
+ CVector2D texCoords[8];
+ CVector2D screenPoly[8];
+ int numVertices;
+ RwTexture *texture = nil;
+
+ GetTextureCorners(x, y, worldPoly);
+ ClipRadarTileCoords(x, y);
+
+ assert(CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y]));
+ txd = CTxdStore::GetSlot(gRadarTxdIds[x + RADAR_NUM_TILES * y])->texDict;
+ if (txd)
+ texture = GetFirstTexture(txd);
+ if (texture == nil)
+ return;
+
+ for (i = 0; i < 4; i++)
+ TransformRealWorldPointToRadarSpace(radarCorners[i], worldPoly[i]);
+
+ numVertices = ClipRadarPoly(radarPoly, radarCorners);
-CRGBA CRadar::GetRadarTraceColour(uint32 color, bool bright)
+ // FIX: can return earlier here
+// if(numVertices == 0)
+ if (numVertices < 3)
+ return;
+
+ for (i = 0; i < numVertices; i++) {
+ TransformRadarPointToRealWorldSpace(worldPoly[i], radarPoly[i]);
+ TransformRealWorldToTexCoordSpace(texCoords[i], worldPoly[i], x, y);
+ TransformRadarPointToScreenSpace(screenPoly[i], radarPoly[i]);
+ }
+ RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(texture));
+ CSprite2d::SetVertices(numVertices, (float*)screenPoly, (float*)texCoords, CRGBA(255, 255, 255, 255));
+ // check done above now
+// if(numVertices > 2)
+ RwIm2DRenderPrimitive(rwPRIMTYPETRIFAN, CSprite2d::GetVertices(), numVertices);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRadarSprite(int32 sprite, float x, float y, int32 alpha) { EAXJMP(0x4A5EF0); }
+#else
+void CRadar::DrawRadarSprite(int32 sprite, float x, float y, int32 alpha)
+{
+ RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha) { EAXJMP(0x4A5D10); }
+#else
+void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha)
{
+ CVector curPosn[4];
+ CVector oldPosn[4];
+
+ curPosn[0].x = x - SCREEN_SCALE_X(5.6f);
+ curPosn[0].y = y + SCREEN_SCALE_Y(5.6f);
+
+ curPosn[1].x = x + SCREEN_SCALE_X(5.6f);
+ curPosn[1].y = y + SCREEN_SCALE_Y(5.6f);
+
+ curPosn[2].x = x - SCREEN_SCALE_X(5.6f);
+ curPosn[2].y = y - SCREEN_SCALE_Y(5.6f);
+
+ curPosn[3].x = x + SCREEN_SCALE_X(5.6f);
+ curPosn[3].y = y - SCREEN_SCALE_Y(5.6f);
+
+ for (uint32 i = 0; i < 4; i++) {
+ oldPosn[i] = curPosn[i];
+
+ curPosn[i].x = x + (oldPosn[i].x - x) * cosf(angle) + (oldPosn[i].y - y) * sinf(angle);
+ curPosn[i].y = y - (oldPosn[i].x - x) * sinf(angle) + (oldPosn[i].y - y) * cosf(angle);
+ }
+
+ sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
+}
+#endif
+
+#if 1
+WRAPPER int32 CRadar::GetActualBlipArray(int32) { EAXJMP(0x4A41C0); }
+#else
+int32 CRadar::GetActualBlipArray(int32 i)
+{
+ return int32();
+}
+#endif
+
+#if 1
+WRAPPER int32 CRadar::GetNewUniqueBlipIndex(int32) { EAXJMP(0x4A4180); }
+#else
+int32 CRadar::GetNewUniqueBlipIndex(int32 i)
+{
+ return int32();
+}
+#endif
+
+#if 0
+WRAPPER int32 CRadar::GetRadarTraceColour(int32 color, bool bright) { EAXJMP(0x4A5BB0); }
+#else
+int32 CRadar::GetRadarTraceColour(int32 color, bool bright)
+{
+ int32 c;
switch (color) {
case 0:
if (bright)
- return CRGBA(113, 43, 73, 255);
+ c = 0x712B49FF;
else
- return CRGBA(127, 0, 0, 255);
+ c = 0x7F0000FF;
+ break;
case 1:
if (bright)
- return CRGBA(95, 160, 106, 255);
+ c = 0x5FA06AFF;
else
- return CRGBA(127, 0, 255, 255);
+ c = 0x7F00FF;
+ break;
case 2:
if (bright)
- return CRGBA(128, 167, 243, 255);
+ c = 0x80A7F3FF;
else
- return CRGBA(0, 127, 255, 255);
+ c = 0x007FFF;
+ break;
case 3:
if (bright)
- return CRGBA(225, 225, 225, 255);
+ c = 0xE1E1E1FF;
else
- return CRGBA(127, 127, 127, 255);
+ c = 0x7F7F7FFF;
+ break;
case 4:
if (bright)
- return CRGBA(255, 225, 0, 255);
+ c = 0xFFFF00FF;
else
- return CRGBA(127, 127, 0, 255);
+ c = 0x7F7F00FF;
+ break;
case 5:
if (bright)
- return CRGBA(255, 0, 255, 255);
+ c = 0xFF00FFFF;
else
- return CRGBA(127, 0, 127, 255);
+ c = 0x7F007FFF;
+ break;
case 6:
if (bright)
- return CRGBA(255, 255, 255, 255);
+ c = 0xFFFFFF;
else
- return CRGBA(127, 127, 255, 255);
+ c = 0x7F7FFF;
+ break;
default:
- return CRGBA(0, 0, 0, 255);
- }
+ c = color;
+ break;
+ };
+ return c;
}
+#endif
-void CRadar::TransformRadarPointToScreenSpace(CVector2D *out, CVector2D *in)
+#if 0
+WRAPPER void CRadar::Initialise() { EAXJMP(0x4A3EF0); }
+#else
+void CRadar::Initialise()
{
- out->x = in->x * SCREEN_SCALE_X(47.0f) + SCREEN_SCALE_X(47.0f + 20.0f);
- out->y = (SCREEN_SCALE_Y(76.0f)) * 0.5f + SCREEN_HEIGHT - (SCREEN_SCALE_Y(123.0f)) - in->y * (SCREEN_SCALE_Y(76.0f)) * 0.5f;
+
}
+#endif
#if 0
-WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D *out, CVector2D *in) { EAXJMP(0x4A50D0); }
+WRAPPER float CRadar::LimitRadarPoint(CVector2D &point) { EAXJMP(0x4A4F30); }
#else
-void CRadar::TransformRealWorldPointToRadarSpace(CVector2D *out, CVector2D *in)
-{
- if (TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_TOPDOWN1 && TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_TOPDOWNPED) {
- if (TheCamera.GetLookDirection() != LOOKING_FORWARD) {
- cachedSin = sin(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y));
- cachedCos = cos(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y));
- }
- else {
- CVector vecCamera;
+float CRadar::LimitRadarPoint(CVector2D &point)
+{
+ float dist, invdist;
- if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON) {
- vecCamera = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->m_matrix.m_matrix.up;
- vecCamera.Normalise();
- }
- else
- vecCamera = TheCamera.GetForward();
-
- cachedSin = sin(atan2(-vecCamera.x, vecCamera.y));
- cachedCos = cos(atan2(-vecCamera.x, vecCamera.y));
- }
+ dist = point.Magnitude();
+ if (dist > 1.0f) {
+ invdist = 1.0f / dist;
+ point.x *= invdist;
+ point.y *= invdist;
}
- else {
- cachedSin = 0.0f;
- cachedCos = 1.0f;
+ return dist;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::LoadAllRadarBlips() { EAXJMP(0x4A6F30); }
+#else
+void CRadar::LoadAllRadarBlips(int32)
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::LoadTextures() { EAXJMP(0x4A4030); }
+#else
+void CRadar::LoadTextures()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::RemoveRadarSections() { EAXJMP(0x00); }
+#else
+void CRadar::RemoveRadarSections()
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::RemoveMapSection(int32, int32) { EAXJMP(0x00); }
+#else
+void CRadar::RemoveMapSection(int32 x, int32 y)
+{
+ if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
+ CStreaming::RemoveTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y]);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::RequestMapSection(int32, int32) { EAXJMP(0x00); }
+#else
+void CRadar::RequestMapSection(int32 x, int32 y)
+{
+ ClipRadarTileCoords(x, y);
+ CStreaming::RequestTxd(gRadarTxdIds[x + RADAR_NUM_TILES * y], STREAMFLAGS_DONT_REMOVE | STREAMFLAGS_DEPENDENCY);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SaveAllRadarBlips(int32) { EAXJMP(0x00); }
+#else
+void CRadar::SaveAllRadarBlips(int32)
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SetBlipSprite(int32, int32) { EAXJMP(0x00); }
+#else
+void CRadar::SetBlipSprite(int32 i, int32 icon)
+{
+
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SetCoordBlip(int32, CVector, int32) { EAXJMP(0x00); }
+#else
+int CRadar::SetCoordBlip(int32 type, CVector pos, int32 flag)
+{
+ return 0;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag) { EAXJMP(0x00); }
+#else
+int CRadar::SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag)
+{
+ return 0;
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::SetRadarMarkerState(int32, int32) { EAXJMP(0x4A5C60); }
+#else
+void CRadar::SetRadarMarkerState(int32 counter, int32 flag)
+{
+ CEntity *e;
+ switch (ms_RadarTrace[counter].m_eBlipType) {
+ case BLIP_CAR:
+ e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+ break;
+ case BLIP_CHAR:
+ e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+ break;
+ case BLIP_OBJECT:
+ e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+ break;
+ default:
+ return;
}
-
- float x = (in->x - vec2DRadarOrigin.x) * (1.0f / m_RadarRange);
- float y = (in->y - vec2DRadarOrigin.y) * (1.0f / m_RadarRange);
-
- out->x = cachedSin * y + cachedCos * x;
- out->y = cachedCos * y - cachedSin * x;
+
+ if (e)
+ e->bHasBlip = flag;
}
-#endif
+#endif
#if 0
-WRAPPER void CRadar::DrawRadarSprite(int sprite, float x, float y, int alpha) { EAXJMP(0x4A5EF0); }
+WRAPPER void CRadar::ShowRadarMarker(CVector pos, int16 color, float radius) { EAXJMP(0x4A59C0); }
#else
-void CRadar::DrawRadarSprite(int sprite, float x, float y, int alpha)
-{
- RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
+void CRadar::ShowRadarMarker(CVector pos, int16 color, float radius) {
+ float f1 = radius * 0.5f;
+ float f2 = radius * 1.4f;
+ CVector p1, p2;
+
+ p1 = pos + TheCamera.GetUp()*f1;
+ p2 = pos + TheCamera.GetUp()*f2;
+ CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+ p1 = pos - TheCamera.GetUp()*f1;
+ p2 = pos - TheCamera.GetUp()*f2;
+ CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+ p1 = pos + TheCamera.GetRight()*f1;
+ p2 = pos + TheCamera.GetRight()*f2;
+ CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
+
+ p1 = pos - TheCamera.GetRight()*f1;
+ p2 = pos - TheCamera.GetRight()*f2;
+ CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, color, color);
}
#endif
@@ -518,114 +816,302 @@ void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 gr
#endif
#if 0
-WRAPPER void CRadar::ShowRadarMarker(CVector pos, CRGBA color, float radius) { EAXJMP(0x4A59C0); }
+WRAPPER void CRadar::Shutdown() { EAXJMP(0x4A3F60); }
#else
-void CRadar::ShowRadarMarker(CVector pos, CRGBA color, float radius) {
- float z2 = pos.z + (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.at.z;
- float y2 = (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.at.y + pos.y;
- float x2 = (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.at.x + pos.x;
- float z1 = pos.z + (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.at.z;
- float y1 = (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.at.y + pos.y;
- float x1 = (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.at.x + pos.x;
- CTheScripts::ScriptDebugLine3D(x1, y1, z1, x2, y2, z2, color.color32, color.color32);
+void CRadar::Shutdown()
+{
- z2 = pos.z - (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.at.x;
- y2 = pos.y - (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.at.x;
- x2 = pos.x - (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.at.x;
- z1 = pos.z - (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.at.x;
- y1 = pos.y - (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.at.x;
- x1 = pos.x - (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.at.x;
- CTheScripts::ScriptDebugLine3D(x1, y1, z1, x2, y2, z2, color.color32, color.color32);
+}
+#endif
- z2 = (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.right.x + pos.z;
- y2 = (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.right.x + pos.y;
- x2 = (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.right.x + pos.x;
- z1 = (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.right.x + pos.z;
- y1 = (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.right.x + pos.y;
- x1 = (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.right.x + pos.x;
- CTheScripts::ScriptDebugLine3D(x1, y1, z1, x2, y2, z2, color.color32, color.color32);
+#if 0
+WRAPPER void CRadar::StreamRadarSections() { EAXJMP(0x4A6B60); }
+#else
+void CRadar::StreamRadarSections(CVector posn)
+{
- z2 = pos.z - (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.right.x;
- y2 = pos.y - (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.right.x;
- x2 = pos.x - (0.5f * color.color32) * TheCamera.m_matrix.m_matrix.right.x;
- z1 = pos.z - (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.right.x;
- y1 = pos.y - (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.right.x;
- x1 = pos.x - (1.4f * color.color32) * TheCamera.m_matrix.m_matrix.right.x;
- CTheScripts::ScriptDebugLine3D(x1, y1, z1, x2, y2, z2, color.color32, color.color32);
}
#endif
#if 0
-WRAPPER void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int alpha) { EAXJMP(0x4A5D10); }
+WRAPPER void CRadar::StreamRadarSections(int32 x, int32 y) { EAXJMP(0x4A6100); }
#else
-void CRadar::DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int alpha)
+void CRadar::StreamRadarSections(int32 x, int32 y)
{
- CVector curPosn[4];
- CVector oldPosn[4];
+ for (int i = 0; i < RADAR_NUM_TILES; ++i) {
+ for (int j = 0; j < RADAR_NUM_TILES; ++j) {
+ if ((i >= x - 1 && i <= x + 1) && (j >= y - 1 && j <= y + 1))
+ RequestMapSection(i, j);
+ else
+ RemoveMapSection(i, j);
+ };
+ };
+}
+#endif
- curPosn[0].x = x - SCREEN_SCALE_X(5.6f);
- curPosn[0].y = y + SCREEN_SCALE_Y(5.6f);
-
- curPosn[1].x = x + SCREEN_SCALE_X(5.6f);
- curPosn[1].y = y + SCREEN_SCALE_Y(5.6f);
-
- curPosn[2].x = x - SCREEN_SCALE_X(5.6f);
- curPosn[2].y = y - SCREEN_SCALE_Y(5.6f);
-
- curPosn[3].x = x + SCREEN_SCALE_X(5.6f);
- curPosn[3].y = y - SCREEN_SCALE_Y(5.6f);
+#if 0
+WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y) { EAXJMP(0x4A5530); }
+#else
+void CRadar::TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y)
+{
+ out.x = in.x - (x * RADAR_TILE_SIZE + WORLD_MIN_X);
+ out.y = -(in.y - ((RADAR_NUM_TILES - y) * RADAR_TILE_SIZE + WORLD_MIN_Y));
+ out.x /= RADAR_TILE_SIZE;
+ out.y /= RADAR_TILE_SIZE;
+}
+#endif
- for (uint32 i = 0; i < 4; i++) {
- oldPosn[i] = curPosn[i];
+#if 0
+WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A5300); }
+#else
+void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in)
+{
+ float s, c;
- curPosn[i].x = x + (oldPosn[i].x - x) * cosf(angle) + (oldPosn[i].y - y) * sinf(angle);
- curPosn[i].y = y - (oldPosn[i].x - x) * sinf(angle) + (oldPosn[i].y - y) * cosf(angle);
- }
+ s = -sin(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y));
+ c = cos(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y));
- sprite->Draw(curPosn[2].x, curPosn[2].y, curPosn[3].x, curPosn[3].y, curPosn[0].x, curPosn[0].y, curPosn[1].x, curPosn[1].y, CRGBA(255, 255, 255, alpha));
+ if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) {
+ s = 0.0f;
+ c = 1.0f;
+ }
+ else if (TheCamera.GetLookDirection() != LOOKING_FORWARD) {
+ CVector forward;
+
+ if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON) {
+ forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
+ forward.Normalise(); // a bit useless...
+ }
+ else
+ forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
+
+ s = -sin(atan2(-forward.x, forward.y));
+ c = cos(atan2(-forward.x, forward.y));
+ }
+
+ out.x = s * in.y + c * in.x;
+ out.y = c * in.y - s * in.x;
+
+ out = out * m_RadarRange + vec2DRadarOrigin;
}
-#endif
+#endif
-bool CRadar::DisplayThisBlip(int counter)
+// Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0)
+void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in)
{
- switch (ms_RadarTrace[counter].m_IconID) {
- case RADAR_SPRITE_BOMB:
- case RADAR_SPRITE_SPRAY:
- case RADAR_SPRITE_WEAPON:
- return true;
- default:
- return false;
+ // FIX: game doesn't scale RADAR_LEFT here
+ out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT);
+ out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT);
+}
+
+#if 0
+WRAPPER void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in) { EAXJMP(0x4A50D0); }
+#else
+void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in)
+{
+ float s, c;
+ if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) {
+ s = 0.0f;
+ c = 1.0f;
+ }
+ else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) {
+ s = sin(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y));
+ c = cos(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y));
}
+ else {
+ CVector forward;
+
+ if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FIRSTPERSON) {
+ forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetForward();
+ forward.Normalise(); // a bit useless...
+ }
+ else
+ forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind;
+
+ s = sin(atan2(-forward.x, forward.y));
+ c = cos(atan2(-forward.x, forward.y));
+ }
+
+ float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_RadarRange);
+ float y = (in.y - vec2DRadarOrigin.y) * (1.0f / m_RadarRange);
+
+ out.x = s * y + c * x;
+ out.y = c * y - s * x;
}
+#endif
#if 0
-WRAPPER void CRadar::GetTextureCorners(int x, int y, CVector2D *out) { EAXJMP(0x4A61C0); };
+WRAPPER void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out) { EAXJMP(0x4A61C0); };
#else
-void CRadar::GetTextureCorners(int x, int y, CVector2D *out)
+// Transform from section indices to world coordinates
+void CRadar::GetTextureCorners(int32 x, int32 y, CVector2D *out)
{
- out[0].x = 500.0f * (x - 4);
- out[0].y = 500.0f * (3 - y);
- out[1].x = 500.0f * (y - 4 + 1);
- out[1].y = 500.0f * (3 - y);
- out[2].x = 500.0f * (y - 4 + 1);
- out[2].y = 500.0f * (3 - y + 1);
- out[3].x = 500.0f * (x - 4);
- out[3].y = 500.0f * (3 - y + 1);
+ x = x - RADAR_NUM_TILES/2;
+ y = -(y - RADAR_NUM_TILES/2);
+
+ // bottom left
+ out[0].x = RADAR_TILE_SIZE * (x);
+ out[0].y = RADAR_TILE_SIZE * (y - 1);
+
+ // bottom right
+ out[1].x = RADAR_TILE_SIZE * (x + 1);
+ out[1].y = RADAR_TILE_SIZE * (y - 1);
+
+ // top right
+ out[2].x = RADAR_TILE_SIZE * (x + 1);
+ out[2].y = RADAR_TILE_SIZE * (y);
+
+ // top left
+ out[3].x = RADAR_TILE_SIZE * (x);
+ out[3].y = RADAR_TILE_SIZE * (y);
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ClipRadarTileCoords(int32 &, int32 &) { EAXJMP(0x00); };
+#else
+void CRadar::ClipRadarTileCoords(int32 &x, int32 &y)
+{
+ if (x < 0)
+ x = 0;
+ if (x > RADAR_NUM_TILES-1)
+ x = RADAR_NUM_TILES-1;
+ if (y < 0)
+ y = 0;
+ if (y > RADAR_NUM_TILES-1)
+ y = RADAR_NUM_TILES-1;
+}
+#endif
+
+
+#if 0
+WRAPPER bool CRadar::IsPointInsideRadar(const CVector2D &) { EAXJMP(0x4A6160); }
+#else
+bool CRadar::IsPointInsideRadar(const CVector2D &point)
+{
+ if (point.x < -1.0f || point.x > 1.0f) return false;
+ if (point.y < -1.0f || point.y > 1.0f) return false;
+ return true;
}
#endif
-void CRadar::ClipRadarTileCoords(int *x, int *y)
+// clip line p1,p2 against (-1.0, 1.0) in x and y, set out to clipped point closest to p1
+#if 0
+WRAPPER int CRadar::LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &) { EAXJMP(0x4A6250); }
+#else
+int CRadar::LineRadarBoxCollision(CVector2D &out, const CVector2D &p1, const CVector2D &p2)
{
- if (*x < 0)
- *x = 0;
- if (*x > 7)
- *x = 7;
- if (*y < 0)
- *y = 0;
- if (*y > 7)
- *y = 7;
+ float d1, d2;
+ float t;
+ float x, y;
+ float shortest = 1.0f;
+ int edge = -1;
+
+ // clip against left edge, x = -1.0
+ d1 = -1.0f - p1.x;
+ d2 = -1.0f - p2.x;
+ if (d1 * d2 < 0.0f) {
+ // they are on opposite sides, get point of intersection
+ t = d1 / (d1 - d2);
+ y = (p2.y - p1.y)*t + p1.y;
+ if (y >= -1.0f && y <= 1.0f && t <= shortest) {
+ out.x = -1.0f;
+ out.y = y;
+ edge = 3;
+ shortest = t;
+ }
+ }
+
+ // clip against right edge, x = 1.0
+ d1 = p1.x - 1.0f;
+ d2 = p2.x - 1.0f;
+ if (d1 * d2 < 0.0f) {
+ // they are on opposite sides, get point of intersection
+ t = d1 / (d1 - d2);
+ y = (p2.y - p1.y)*t + p1.y;
+ if (y >= -1.0f && y <= 1.0f && t <= shortest) {
+ out.x = 1.0f;
+ out.y = y;
+ edge = 1;
+ shortest = t;
+ }
+ }
+
+ // clip against top edge, y = -1.0
+ d1 = -1.0f - p1.y;
+ d2 = -1.0f - p2.y;
+ if (d1 * d2 < 0.0f) {
+ // they are on opposite sides, get point of intersection
+ t = d1 / (d1 - d2);
+ x = (p2.x - p1.x)*t + p1.x;
+ if (x >= -1.0f && x <= 1.0f && t <= shortest) {
+ out.y = -1.0f;
+ out.x = x;
+ edge = 0;
+ shortest = t;
+ }
+ }
+
+ // clip against bottom edge, y = 1.0
+ d1 = p1.y - 1.0f;
+ d2 = p2.y - 1.0f;
+ if (d1 * d2 < 0.0f) {
+ // they are on opposite sides, get point of intersection
+ t = d1 / (d1 - d2);
+ x = (p2.x - p1.x)*t + p1.x;
+ if (x >= -1.0f && x <= 1.0f && t <= shortest) {
+ out.y = 1.0f;
+ out.x = x;
+ edge = 2;
+ shortest = t;
+ }
+ }
+
+ return edge;
}
+#endif
STARTPATCHES
+// InjectHook(0x4A3EF0, CRadar::Initialise, PATCH_JUMP);
+// InjectHook(0x4A3F60, CRadar::Shutdown, PATCH_JUMP);
+// InjectHook(0x4A4030, CRadar::LoadTextures, PATCH_JUMP);
+// InjectHook(0x4A4180, CRadar::GetNewUniqueBlipIndex, PATCH_JUMP);
+// InjectHook(0x4A41C0, CRadar::GetActualBlipArrayIndex, PATCH_JUMP);
+ InjectHook(0x4A4200, CRadar::DrawMap, PATCH_JUMP);
+ InjectHook(0x4A42F0, CRadar::DrawBlips, PATCH_JUMP);
+// InjectHook(0x4A4C70, CRadar::Draw3dMarkers, PATCH_JUMP);
+ InjectHook(0x4A4F30, CRadar::LimitRadarPoint, PATCH_JUMP);
+ InjectHook(0x4A4F90, CRadar::CalculateBlipAlpha, PATCH_JUMP);
InjectHook(0x4A5040, CRadar::TransformRadarPointToScreenSpace, PATCH_JUMP);
+ InjectHook(0x4A50D0, CRadar::TransformRealWorldPointToRadarSpace, PATCH_JUMP);
+ InjectHook(0x4A5300, CRadar::TransformRadarPointToRealWorldSpace, PATCH_JUMP);
+ InjectHook(0x4A5530, CRadar::TransformRealWorldToTexCoordSpace, PATCH_JUMP);
+// InjectHook(0x4A5590, CRadar::SetCoordBlip, PATCH_JUMP);
+// InjectHook(0x4A5640, CRadar::SetEntityBlip, PATCH_JUMP);
+ InjectHook(0x4A56C0, CRadar::ClearBlipForEntity, PATCH_JUMP);
+// InjectHook(0x4A5720, CRadar::ClearBlip, PATCH_JUMP);
+// InjectHook(0x4A5770, CRadar::ChangeBlipColour, PATCH_JUMP);
+// InjectHook(0x4A57A0, CRadar::ChangeBlipBrightness, PATCH_JUMP);
+// InjectHook(0x4A57E0, CRadar::ChangeBlipScale, PATCH_JUMP);
+// InjectHook(0x4A5810, CRadar::ChangeBlipDisplay, PATCH_JUMP);
+// InjectHook(0x4A5840, CRadar::SetBlipSprite, PATCH_JUMP);
+ InjectHook(0x4A5870, CRadar::ShowRadarTrace, PATCH_JUMP);
+ InjectHook(0x4A59C0, CRadar::ShowRadarMarker, PATCH_JUMP);
+ //InjectHook(0x4A5BB0, CRadar::GetRadarTraceColour, PATCH_JUMP);
+ InjectHook(0x4A5C60, CRadar::SetRadarMarkerState, PATCH_JUMP);
+ InjectHook(0x4A5D10, CRadar::DrawRotatingRadarSprite, PATCH_JUMP);
+ InjectHook(0x4A5EF0, CRadar::DrawRadarSprite, PATCH_JUMP);
+// InjectHook(0x4A60E0, CRadar::RemoveRadarSections, PATCH_JUMP);
+// InjectHook(0x4A6100, CRadar::StreamRadarSections, PATCH_JUMP);
+ InjectHook(0x4A64A0, CRadar::ClipRadarPoly, PATCH_JUMP);
+ InjectHook(0x4A67E0, CRadar::DrawRadarSection, PATCH_JUMP);
+ InjectHook(0x4A69C0, CRadar::DrawRadarMask, PATCH_JUMP);
+// InjectHook(0x4A6B60, CRadar::StreamRadarSections, PATCH_JUMP);
+ InjectHook(0x4A6C20, CRadar::DrawRadarMap, PATCH_JUMP);
+// InjectHook(0x4A6E30, CRadar::SaveAllRadarBlips, PATCH_JUMP);
+// InjectHook(0x4A6F30, CRadar::LoadAllRadarBlips, PATCH_JUMP);
+
+ InjectHook(0x4A61C0, CRadar::GetTextureCorners, PATCH_JUMP);
+ InjectHook(0x4A6160, CRadar::IsPointInsideRadar, PATCH_JUMP);
+ InjectHook(0x4A6250, CRadar::LineRadarBoxCollision, PATCH_JUMP);
ENDPATCHES
diff --git a/src/Radar.h b/src/Radar.h
index 19fc9038..5943498f 100644
--- a/src/Radar.h
+++ b/src/Radar.h
@@ -53,26 +53,26 @@ struct CBlip
CVector2D m_vec2DPos;
CVector m_vecPos;
int16 m_BlipIndex;
- int8 m_bDim;
- int8 m_bInUse;
+ bool m_bDim;
+ bool m_bInUse;
float m_Radius;
int16 m_wScale;
int16 m_eBlipDisplay; // eBlipDisplay
int16 m_IconID; // eRadarSprite
- char gap_46[2];
};
-
static_assert(sizeof(CBlip) == 0x30, "CBlip: error");
+// Values for screen space
+#define RADAR_LEFT (40.0f)
+#define RADAR_BOTTOM (47.0f)
+#define RADAR_WIDTH (94.0f)
+#define RADAR_HEIGHT (76.0f)
+
class CRadar
{
- static float cachedSin;
- static float cachedCos;
-
public:
static float &m_RadarRange;
- static CVector2D &vec2DRadarOrigin;
- static CBlip *ms_RadarTrace;
+ static CBlip *ms_RadarTrace; //[NUMRADARBLIPS]
static CSprite2d *AsukaSprite;
static CSprite2d *BombSprite;
static CSprite2d *CatSprite;
@@ -96,30 +96,51 @@ public:
static CSprite2d *RadarSprites[21];
public:
- static void ClearBlipForEntity(eBlipType type, int32 id);
+ static int CalculateBlipAlpha(float dist);
+ static void ChangeBlipBrightness(int32 i, int32 bright);
+ static void ChangeBlipColour(int32 i);
+ static void ChangeBlipDisplay(int32 i, int16 flag);
+ static void ChangeBlipScale(int32 i, int16 scale);
+ static void ClearBlip(int32 i);
+ static void ClearBlipForEntity(int16 type, int32 id);
+ static int ClipRadarPoly(CVector2D *out, const CVector2D *in);
+ static bool DisplayThisBlip(int32 i);
static void Draw3dMarkers();
- static void DrawMap();
- static void StreamRadarSections(int x, int y);
- static int ClipRadarPoly(CVector2D *out, CVector2D *in);
- static void TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y);
- static void TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in);
- static void DrawRadarSection(int x, int y);
- static void RequestMapSection(int x, int y);
- static void RemoveMapSection(int x, int y);
- static void TransformRadarPointToScreenSpace(CVector2D * out, CVector2D * in);
static void DrawBlips();
- static int CalculateBlipAlpha(float dist);
- static CRGBA GetRadarTraceColour(uint32 color, bool bright);
+ static void DrawMap();
static void DrawRadarMap();
- static void DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int alpha);
- static void TransformRealWorldPointToRadarSpace(CVector2D *out, CVector2D *in);
- static float LimitRadarPoint(CVector2D *point);
- static void DrawRadarSprite(int sprite, float x, float y, int alpha);
- static void ShowRadarMarker(CVector pos, CRGBA color, float radius);
- static void ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha);
static void DrawRadarMask();
- static void SetRadarMarkerState(int counter, int flag);
- static bool DisplayThisBlip(int counter);
- static void GetTextureCorners(int x, int y, CVector2D * out);
- static void ClipRadarTileCoords(int *x, int *y);
+ static void DrawRadarSection(int32 x, int32 y);
+ static void DrawRadarSprite(int32 sprite, float x, float y, int32 alpha);
+ static void DrawRotatingRadarSprite(CSprite2d* sprite, float x, float y, float angle, int32 alpha);
+ static int32 GetActualBlipArray(int32 i);
+ static int32 GetNewUniqueBlipIndex(int32 i);
+ static int32 GetRadarTraceColour(int32 color, bool bright);
+ static void Initialise();
+ static float LimitRadarPoint(CVector2D &point);
+ static void LoadAllRadarBlips(int32);
+ static void LoadTextures();
+ static void RemoveRadarSections();
+ static void RemoveMapSection(int32 x, int32 y);
+ static void RequestMapSection(int32 x, int32 y);
+ static void SaveAllRadarBlips(int32);
+ static void SetBlipSprite(int32 i, int32 icon);
+ static int SetCoordBlip(int32 type, CVector pos, int32 flag);
+ static int SetEntityBlip(int32 type, CVector pos, int32 color, int32 flag);
+ static void SetRadarMarkerState(int32 i, int32 flag);
+ static void ShowRadarMarker(CVector pos, int16 color, float radius);
+ static void ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha);
+ static void Shutdown();
+ static void StreamRadarSections(CVector posn);
+ static void StreamRadarSections(int32 x, int32 y);
+ static void TransformRealWorldToTexCoordSpace(CVector2D &out, const CVector2D &in, int32 x, int32 y);
+ static void TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D &in);
+ static void TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in);
+ static void TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D &in);
+
+ // no in CRadar in the game:
+ static void GetTextureCorners(int32 x, int32 y, CVector2D *out);
+ static void ClipRadarTileCoords(int32 &x, int32 &y);
+ static bool IsPointInsideRadar(const CVector2D &);
+ static int LineRadarBoxCollision(CVector2D &, const CVector2D &, const CVector2D &);
};
diff --git a/src/RwHelper.cpp b/src/RwHelper.cpp
index 5aa31e92..3c198272 100644
--- a/src/RwHelper.cpp
+++ b/src/RwHelper.cpp
@@ -108,6 +108,23 @@ GetFirstAtomic(RpClump *clump)
return atm;
}
+RwTexture*
+GetFirstTextureCallback(RwTexture *tex, void *data)
+{
+ *(RwTexture**)data = tex;
+ return nil;
+}
+
+RwTexture*
+GetFirstTexture(RwTexDictionary *txd)
+{
+ RwTexture *tex;
+
+ tex = nil;
+ RwTexDictionaryForAllTextures(txd, GetFirstTextureCallback, &tex);
+ return tex;
+}
+
void
CameraSize(RwCamera * camera, RwRect * rect,
RwReal viewWindow, RwReal aspectRatio)
diff --git a/src/RwHelper.h b/src/RwHelper.h
index e0ec00a3..ef20467d 100644
--- a/src/RwHelper.h
+++ b/src/RwHelper.h
@@ -7,6 +7,7 @@ void DefinedState(void);
RwFrame *GetFirstChild(RwFrame *frame);
RwObject *GetFirstObject(RwFrame *frame);
RpAtomic *GetFirstAtomic(RpClump *clump);
+RwTexture *GetFirstTexture(RwTexDictionary *txd);
RwTexDictionary *RwTexDictionaryGtaStreamRead(RwStream *stream);
RwTexDictionary *RwTexDictionaryGtaStreamRead1(RwStream *stream);
diff --git a/src/Streaming.cpp b/src/Streaming.cpp
index 2504ed9c..149de7c3 100644
--- a/src/Streaming.cpp
+++ b/src/Streaming.cpp
@@ -1,5 +1,8 @@
#include "common.h"
#include "patcher.h"
+#include "Pad.h"
+#include "Hud.h"
+#include "Text.h"
#include "ModelInfo.h"
#include "TxdStore.h"
#include "ModelIndices.h"
@@ -13,11 +16,6 @@
#include "CdStream.h"
#include "Streaming.h"
-/*
-CStreaming::ms_channelError 0x880DB8
-CStreaming::ms_lastVehicleDeleted 0x95CBF8
-*/
-
bool &CStreaming::ms_disableStreaming = *(bool*)0x95CD6E;
bool &CStreaming::ms_bLoadingBigModel = *(bool*)0x95CDB0;
int32 &CStreaming::ms_numModelsRequested = *(int32*)0x8E2C10;
@@ -28,12 +26,14 @@ CStreamingInfo &CStreaming::ms_startRequestedList = *(CStreamingInfo*)0x8F1B3C;
CStreamingInfo &CStreaming::ms_endRequestedList = *(CStreamingInfo*)0x940738;
int32 &CStreaming::ms_oldSectorX = *(int32*)0x8F2C84;
int32 &CStreaming::ms_oldSectorY = *(int32*)0x8F2C88;
-uint32 &CStreaming::ms_streamingBufferSize = *(uint32*)0x942FB0;
-uint8 **CStreaming::ms_pStreamingBuffer = (uint8**)0x87F818;
+int32 &CStreaming::ms_streamingBufferSize = *(int32*)0x942FB0;
+int8 **CStreaming::ms_pStreamingBuffer = (int8**)0x87F818;
int32 &CStreaming::ms_memoryUsed = *(int32*)0x940568;
CStreamingChannel *CStreaming::ms_channel = (CStreamingChannel*)0x727EE0;
+int32 &CStreaming::ms_channelError = *(int32*)0x880DB8;
int32 &CStreaming::ms_numVehiclesLoaded = *(int32*)0x8F2C80;
int32 *CStreaming::ms_vehiclesLoaded = (int32*)0x773560;
+int32 &CStreaming::ms_lastVehicleDeleted = *(int32*)0x95CBF8;
CDirectory *&CStreaming::ms_pExtraObjectsDir = *(CDirectory**)0x95CB90;
int32 &CStreaming::ms_numPriorityRequests = *(int32*)0x8F31C4;
bool &CStreaming::ms_hasLoadedLODs = *(bool*)0x95CD47;
@@ -60,8 +60,8 @@ int32 &islandLODsubInd = *(int32*)0x6212D4;
int32 &islandLODsubCom = *(int32*)0x6212D8;
WRAPPER void CStreaming::MakeSpaceFor(int32 size) { EAXJMP(0x409B70); }
-WRAPPER bool CStreaming::IsTxdUsedByRequestedModels(int32 txdId) { EAXJMP(0x4094C0); }
-WRAPPER bool CStreaming::AddToLoadedVehiclesList(int32 modelId) { EAXJMP(0x40B060); }
+//WRAPPER bool CStreaming::IsTxdUsedByRequestedModels(int32 txdId) { EAXJMP(0x4094C0); }
+//WRAPPER bool CStreaming::AddToLoadedVehiclesList(int32 modelId) { EAXJMP(0x40B060); }
void
@@ -78,6 +78,8 @@ CStreaming::Init(void)
ms_aInfoForModel[i].m_position = 0;
}
+ ms_channelError = -1;
+
// init lists
ms_startLoadedList.m_next = &ms_endLoadedList;
@@ -101,12 +103,12 @@ CStreaming::Init(void)
// init channels
- ms_channel[0].state = CHANNELSTATE_0;
- ms_channel[1].state = CHANNELSTATE_0;
+ ms_channel[0].state = CHANNELSTATE_IDLE;
+ ms_channel[1].state = CHANNELSTATE_IDLE;
for(i = 0; i < 4; i++){
- ms_channel[0].modelIds[i] = -1;
+ ms_channel[0].streamIds[i] = -1;
ms_channel[0].offsets[i] = -1;
- ms_channel[1].modelIds[i] = -1;
+ ms_channel[1].streamIds[i] = -1;
ms_channel[1].offsets[i] = -1;
}
@@ -115,8 +117,8 @@ CStreaming::Init(void)
for(i = 0; i < MODELINFOSIZE; i++){
CBaseModelInfo *mi = CModelInfo::GetModelInfo(i);
if(mi && mi->GetRwObject()){
- ms_aInfoForModel[i + STREAM_OFFSET_MODEL].m_loadState = STREAMSTATE_LOADED;
- ms_aInfoForModel[i + STREAM_OFFSET_MODEL].m_flags = STREAMFLAGS_DONT_REMOVE;
+ ms_aInfoForModel[i].m_loadState = STREAMSTATE_LOADED;
+ ms_aInfoForModel[i].m_flags = STREAMFLAGS_DONT_REMOVE;
if(mi->IsSimple())
((CSimpleModelInfo*)mi)->m_alpha = 255;
}
@@ -143,7 +145,7 @@ CStreaming::Init(void)
// allocate streaming buffers
if(ms_streamingBufferSize & 1) ms_streamingBufferSize++;
- ms_pStreamingBuffer[0] = (uint8*)RwMallocAlign(ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE);
+ ms_pStreamingBuffer[0] = (int8*)RwMallocAlign(ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE);
ms_streamingBufferSize /= 2;
ms_pStreamingBuffer[1] = ms_pStreamingBuffer[0] + ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE;
debug("Streaming buffer size is %d sectors", ms_streamingBufferSize);
@@ -211,6 +213,9 @@ CStreaming::LoadCdDirectory(void)
ms_imageOffsets[i] = -1;
ms_imageSize = GetGTA3ImgSize();
+ // PS2 uses CFileMgr::GetCdFile on all IMG files to fill the array
+
+
i = CdStreamGetNumImages();
while(i-- >= 1){
strcpy(dirname, CdStreamGetImageName(i));
@@ -240,20 +245,20 @@ CStreaming::LoadCdDirectory(const char *dirname, int n)
while(CFileMgr::Read(fd, (char*)&direntry, sizeof(direntry))){
dot = strchr(direntry.name, '.');
if(dot) *dot = '\0';
- if(direntry.size > ms_streamingBufferSize)
+ if(direntry.size > (uint32)ms_streamingBufferSize)
ms_streamingBufferSize = direntry.size;
if(strcmp(dot+1, "DFF") == 0 || strcmp(dot+1, "dff") == 0){
if(CModelInfo::GetModelInfo(direntry.name, &modelId)){
- if(ms_aInfoForModel[modelId + STREAM_OFFSET_MODEL].GetCdPosnAndSize(posn, size)){
+ if(ms_aInfoForModel[modelId].GetCdPosnAndSize(posn, size)){
debug("%s appears more than once in %s\n", direntry.name, dirname);
lastID = -1;
}else{
direntry.offset |= imgSelector;
- ms_aInfoForModel[modelId + STREAM_OFFSET_MODEL].SetCdPosnAndSize(direntry.offset, direntry.size);
+ ms_aInfoForModel[modelId].SetCdPosnAndSize(direntry.offset, direntry.size);
if(lastID != -1)
- ms_aInfoForModel[lastID].m_nextID = modelId + STREAM_OFFSET_MODEL;
- lastID = modelId + STREAM_OFFSET_MODEL;
+ ms_aInfoForModel[lastID].m_nextID = modelId;
+ lastID = modelId;
}
}else{
// BUG: doesn't remember which cdimage this was in
@@ -300,15 +305,14 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
if(streamId < STREAM_OFFSET_TXD){
// Model
- mi = CModelInfo::GetModelInfo(streamId - STREAM_OFFSET_MODEL);
+ mi = CModelInfo::GetModelInfo(streamId);
// Txd has to be loaded
if(CTxdStore::GetSlot(mi->GetTxdSlot())->texDict == nil){
debug("failed to load %s because TXD %s is not in memory\n", mi->GetName(), CTxdStore::GetTxdName(mi->GetTxdSlot()));
RemoveModel(streamId);
- RemoveModel(mi->GetTxdSlot() + STREAM_OFFSET_TXD);
- // re-request
- RequestModel(streamId, ms_aInfoForModel[streamId].m_flags);
+ RemoveTxd(mi->GetTxdSlot());
+ ReRequestModel(streamId);
RwStreamClose(stream, &mem);
return false;
}
@@ -318,15 +322,15 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
CTxdStore::SetCurrentTxd(mi->GetTxdSlot());
if(mi->IsSimple()){
- success = CFileLoader::LoadAtomicFile(stream, streamId - STREAM_OFFSET_MODEL);
+ success = CFileLoader::LoadAtomicFile(stream, streamId);
}else if(mi->m_type == MITYPE_VEHICLE){
// load vehicles in two parts
- CModelInfo::GetModelInfo(streamId - STREAM_OFFSET_MODEL)->AddRef();
- success = CFileLoader::StartLoadClumpFile(stream, streamId - STREAM_OFFSET_MODEL);
+ CModelInfo::GetModelInfo(streamId)->AddRef();
+ success = CFileLoader::StartLoadClumpFile(stream, streamId);
if(success)
ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_STARTED;
}else{
- success = CFileLoader::LoadClumpFile(stream, streamId - STREAM_OFFSET_MODEL);
+ success = CFileLoader::LoadClumpFile(stream, streamId);
}
UpdateMemoryUsed();
@@ -335,10 +339,9 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot());
if(!success){
- debug("Failed to load %s\n", CModelInfo::GetModelInfo(streamId - STREAM_OFFSET_MODEL)->GetName());
+ debug("Failed to load %s\n", CModelInfo::GetModelInfo(streamId)->GetName());
RemoveModel(streamId);
- // re-request
- RequestModel(streamId, ms_aInfoForModel[streamId].m_flags);
+ ReRequestModel(streamId);
RwStreamClose(stream, &mem);
return false;
}
@@ -363,8 +366,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
if(!success){
debug("Failed to load %s.txd\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD));
RemoveModel(streamId);
- // re-request
- RequestModel(streamId, ms_aInfoForModel[streamId].m_flags);
+ ReRequestModel(streamId);
RwStreamClose(stream, &mem);
return false;
}
@@ -374,7 +376,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
// We shouldn't even end up here unless load was successful
if(!success){
- RequestModel(streamId, ms_aInfoForModel[streamId].m_flags);
+ ReRequestModel(streamId);
if(streamId < STREAM_OFFSET_TXD)
debug("Failed to load %s.dff\n", mi->GetName());
else
@@ -415,7 +417,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId)
timeDiff = endTime - startTime;
if(timeDiff > 5){
if(streamId < STREAM_OFFSET_TXD)
- debug("model %s took %d ms\n", CModelInfo::GetModelInfo(streamId - STREAM_OFFSET_MODEL)->GetName(), timeDiff);
+ debug("model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff);
else
debug("txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff);
}
@@ -437,7 +439,7 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId)
if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED){
if(streamId < STREAM_OFFSET_TXD)
- CModelInfo::GetModelInfo(streamId - STREAM_OFFSET_MODEL)->RemoveRef();
+ CModelInfo::GetModelInfo(streamId)->RemoveRef();
return false;
}
@@ -447,7 +449,7 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId)
if(streamId < STREAM_OFFSET_TXD){
// Model
- mi = CModelInfo::GetModelInfo(streamId - STREAM_OFFSET_MODEL);
+ mi = CModelInfo::GetModelInfo(streamId);
CTxdStore::SetCurrentTxd(mi->GetTxdSlot());
success = CFileLoader::FinishLoadClumpFile(stream, streamId);
if(success)
@@ -467,8 +469,7 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId)
if(!success){
RemoveModel(streamId);
- // re-request
- RequestModel(streamId, ms_aInfoForModel[streamId].m_flags);
+ ReRequestModel(streamId);
UpdateMemoryUsed();
return false;
}
@@ -479,7 +480,7 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId)
timeDiff = endTime - startTime;
if(timeDiff > 5){
if(streamId < STREAM_OFFSET_TXD)
- debug("finish model %s took %d ms\n", CModelInfo::GetModelInfo(streamId - STREAM_OFFSET_MODEL)->GetName(), timeDiff);
+ debug("finish model %s took %d ms\n", CModelInfo::GetModelInfo(streamId)->GetName(), timeDiff);
else
debug("finish txd %s took %d ms\n", CTxdStore::GetTxdName(streamId - STREAM_OFFSET_TXD), timeDiff);
}
@@ -494,7 +495,7 @@ CStreaming::RequestModel(int32 id, int32 flags)
if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_INQUEUE){
// updgrade to priority
- if(flags & STREAMFLAGS_PRIORITY && (ms_aInfoForModel[id].m_flags & STREAMFLAGS_PRIORITY) == 0){
+ if(flags & STREAMFLAGS_PRIORITY && !ms_aInfoForModel[id].IsPriority()){
ms_numPriorityRequests++;
ms_aInfoForModel[id].m_flags |= STREAMFLAGS_PRIORITY;
}
@@ -507,7 +508,7 @@ CStreaming::RequestModel(int32 id, int32 flags)
// Already loaded, only check changed flags
if(ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOFADE && id < STREAM_OFFSET_TXD){
- mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id - STREAM_OFFSET_MODEL);
+ mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id);
if(mi->IsSimple())
mi->m_alpha = 255;
}
@@ -523,7 +524,7 @@ CStreaming::RequestModel(int32 id, int32 flags)
if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_NOTLOADED){
if(id < STREAM_OFFSET_TXD)
- RequestTxd(CModelInfo::GetModelInfo(id - STREAM_OFFSET_MODEL)->GetTxdSlot(), flags);
+ RequestTxd(CModelInfo::GetModelInfo(id)->GetTxdSlot(), flags);
ms_aInfoForModel[id].AddToList(&ms_startRequestedList);
ms_numModelsRequested++;
if(flags & STREAMFLAGS_PRIORITY)
@@ -658,6 +659,16 @@ CStreaming::RequestSpecialChar(int32 charId, const char *modelName, int32 flags)
}
void
+CStreaming::DecrementRef(int32 id)
+{
+ ms_numModelsRequested--;
+ if(ms_aInfoForModel[id].IsPriority()){
+ ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_PRIORITY;
+ ms_numPriorityRequests--;
+ }
+}
+
+void
CStreaming::RemoveModel(int32 id)
{
int i;
@@ -667,7 +678,7 @@ CStreaming::RemoveModel(int32 id)
if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED){
if(id < STREAM_OFFSET_TXD)
- CModelInfo::GetModelInfo(id - STREAM_OFFSET_MODEL)->DeleteRwObject();
+ CModelInfo::GetModelInfo(id)->DeleteRwObject();
else
CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD);
ms_memoryUsed -= ms_aInfoForModel[id].GetCdSize()*CDSTREAM_SECTOR_SIZE;
@@ -675,20 +686,15 @@ CStreaming::RemoveModel(int32 id)
if(ms_aInfoForModel[id].m_next){
// Remove from list, model is neither loaded nor requested
- if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_INQUEUE){
- ms_numModelsRequested--;
- if(ms_aInfoForModel[id].m_flags & STREAMFLAGS_PRIORITY){
- ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_PRIORITY;
- ms_numPriorityRequests--;
- }
- }
+ if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_INQUEUE)
+ DecrementRef(id);
ms_aInfoForModel[id].RemoveFromList();
}else if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_READING){
for(i = 0; i < 4; i++){
- if(ms_channel[0].modelIds[i] == id - STREAM_OFFSET_MODEL)
- ms_channel[0].modelIds[i] = -1;
- if(ms_channel[1].modelIds[i] == id - STREAM_OFFSET_MODEL)
- ms_channel[1].modelIds[i] = -1;
+ if(ms_channel[0].streamIds[i] == id)
+ ms_channel[0].streamIds[i] = -1;
+ if(ms_channel[1].streamIds[i] == id)
+ ms_channel[1].streamIds[i] = -1;
}
}
@@ -702,10 +708,868 @@ CStreaming::RemoveModel(int32 id)
ms_aInfoForModel[id].m_loadState = STREAMSTATE_NOTLOADED;
}
+void
+CStreaming::RemoveUnusedBuildings(eLevelName level)
+{
+ if(level != LEVEL_INDUSTRIAL)
+ RemoveBuildings(LEVEL_INDUSTRIAL);
+ if(level != LEVEL_COMMERCIAL)
+ RemoveBuildings(LEVEL_COMMERCIAL);
+ if(level != LEVEL_SUBURBAN)
+ RemoveBuildings(LEVEL_SUBURBAN);
+}
+
+void
+CStreaming::RemoveBuildings(eLevelName level)
+{
+ int i, n;
+ CEntity *e;
+ CBaseModelInfo *mi;
+
+ n = CPools::GetBuildingPool()->GetSize();
+ for(i = 0; i < n; i++){
+ e = CPools::GetBuildingPool()->GetSlot(i);
+ if(e && e->m_level == level){
+ mi = CModelInfo::GetModelInfo(e->GetModelIndex());
+ if(!e->bImBeingRendered){
+ e->DeleteRwObject();
+ if(mi->m_refCount == 0)
+ RemoveModel(e->GetModelIndex());
+ }
+ }
+ }
+
+ n = CPools::GetTreadablePool()->GetSize();
+ for(i = 0; i < n; i++){
+ e = CPools::GetTreadablePool()->GetSlot(i);
+ if(e && e->m_level == level){
+ mi = CModelInfo::GetModelInfo(e->GetModelIndex());
+ if(!e->bImBeingRendered){
+ e->DeleteRwObject();
+ if(mi->m_refCount == 0)
+ RemoveModel(e->GetModelIndex());
+ }
+ }
+ }
+
+ n = CPools::GetObjectPool()->GetSize();
+ for(i = 0; i < n; i++){
+ e = CPools::GetObjectPool()->GetSlot(i);
+ if(e && e->m_level == level){
+ mi = CModelInfo::GetModelInfo(e->GetModelIndex());
+ if(!e->bImBeingRendered && ((CObject*)e)->ObjectCreatedBy == GAME_OBJECT){
+ e->DeleteRwObject();
+ if(mi->m_refCount == 0)
+ RemoveModel(e->GetModelIndex());
+ }
+ }
+ }
+
+ n = CPools::GetDummyPool()->GetSize();
+ for(i = 0; i < n; i++){
+ e = CPools::GetDummyPool()->GetSlot(i);
+ if(e && e->m_level == level){
+ mi = CModelInfo::GetModelInfo(e->GetModelIndex());
+ if(!e->bImBeingRendered){
+ e->DeleteRwObject();
+ if(mi->m_refCount == 0)
+ RemoveModel(e->GetModelIndex());
+ }
+ }
+ }
+}
+
+void
+CStreaming::RemoveUnusedBigBuildings(eLevelName level)
+{
+ if(level != LEVEL_INDUSTRIAL)
+ RemoveBigBuildings(LEVEL_INDUSTRIAL);
+ if(level != LEVEL_COMMERCIAL)
+ RemoveBigBuildings(LEVEL_COMMERCIAL);
+ if(level != LEVEL_SUBURBAN)
+ RemoveBigBuildings(LEVEL_SUBURBAN);
+ RemoveIslandsNotUsed(level);
+}
+
+void
+DeleteIsland(CEntity *island)
+{
+ if(island == nil)
+ return;
+ if(island->bImBeingRendered)
+ debug("Didn't delete island because it was being rendered\n");
+ else{
+ island->DeleteRwObject();
+ CStreaming::RemoveModel(island->GetModelIndex());
+ }
+}
+
+void
+CStreaming::RemoveIslandsNotUsed(eLevelName level)
+{
+ switch(level){
+ case LEVEL_INDUSTRIAL:
+ DeleteIsland(pIslandLODindustEntity);
+ DeleteIsland(pIslandLODcomSubEntity);
+ DeleteIsland(pIslandLODsubComEntity);
+ break;
+ case LEVEL_COMMERCIAL:
+ DeleteIsland(pIslandLODcomIndEntity);
+ DeleteIsland(pIslandLODcomSubEntity);
+ DeleteIsland(pIslandLODsubIndEntity);
+ break;
+ case LEVEL_SUBURBAN:
+ DeleteIsland(pIslandLODsubIndEntity);
+ DeleteIsland(pIslandLODsubComEntity);
+ DeleteIsland(pIslandLODcomIndEntity);
+ break;
+ default:
+ DeleteIsland(pIslandLODindustEntity);
+ DeleteIsland(pIslandLODcomIndEntity);
+ DeleteIsland(pIslandLODcomSubEntity);
+ DeleteIsland(pIslandLODsubIndEntity);
+ DeleteIsland(pIslandLODsubComEntity);
+ break;
+ }
+}
+
+void
+CStreaming::RemoveBigBuildings(eLevelName level)
+{
+ int i, n;
+ CEntity *e;
+ CBaseModelInfo *mi;
+
+ n = CPools::GetBuildingPool()->GetSize();
+ for(i = 0; i < n; i++){
+ e = CPools::GetBuildingPool()->GetSlot(i);
+ if(e && e->bIsBIGBuilding && e->m_level == level){
+ mi = CModelInfo::GetModelInfo(e->GetModelIndex());
+ if(!e->bImBeingRendered){
+ e->DeleteRwObject();
+ if(mi->m_refCount == 0)
+ RemoveModel(e->GetModelIndex());
+ }
+ }
+ }
+}
+
+bool
+CStreaming::RemoveLoadedVehicle(void)
+{
+ int i, id;
+
+ for(i = 0; i < MAXVEHICLESLOADED; i++){
+ ms_lastVehicleDeleted++;
+ if(ms_lastVehicleDeleted == MAXVEHICLESLOADED)
+ ms_lastVehicleDeleted = 0;
+ id = ms_vehiclesLoaded[ms_lastVehicleDeleted];
+ if(id != -1 &&
+ (ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 &&
+ CModelInfo::GetModelInfo(id)->m_refCount == 0 &&
+ ms_aInfoForModel[id].m_loadState == STREAMSTATE_LOADED)
+ goto found;
+ }
+ return false;
+found:
+ RemoveModel(ms_vehiclesLoaded[ms_lastVehicleDeleted]);
+ ms_numVehiclesLoaded--;
+ ms_vehiclesLoaded[ms_lastVehicleDeleted] = -1;
+ return true;
+}
+
+bool
+CStreaming::RemoveLeastUsedModel(void)
+{
+ CStreamingInfo *si;
+ int streamId;
+
+ for(si = ms_endLoadedList.m_prev; si != &ms_startLoadedList; si = si->m_prev){
+ streamId = si - ms_aInfoForModel;
+ if(streamId < STREAM_OFFSET_TXD){
+ if(CModelInfo::GetModelInfo(streamId)->m_refCount == 0){
+ RemoveModel(streamId);
+ return true;
+ }
+ }else{
+ if(CTxdStore::GetNumRefs(streamId - STREAM_OFFSET_TXD) == 0 &&
+ !IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD)){
+ RemoveModel(streamId);
+ return true;
+ }
+ }
+ }
+ return ms_numVehiclesLoaded > 7 && RemoveLoadedVehicle();
+}
+
+void
+CStreaming::RemoveAllUnusedModels(void)
+{
+ int i;
+
+ for(i = 0; i < MAXVEHICLESLOADED; i++)
+ RemoveLoadedVehicle();
+
+ for(i = NUM_DEFAULT_MODELS; i < MODELINFOSIZE; i++){
+ if(ms_aInfoForModel[i].m_loadState == STREAMSTATE_LOADED &&
+ ms_aInfoForModel[i].m_flags & STREAMFLAGS_DONT_REMOVE &&
+ CModelInfo::GetModelInfo(i)->m_refCount == 0){
+ RemoveModel(i);
+ ms_aInfoForModel[i].m_loadState = STREAMSTATE_NOTLOADED;
+ }
+ }
+}
+
+bool
+CStreaming::RemoveReferencedTxds(int32 mem)
+{
+ CStreamingInfo *si;
+ int streamId;
+
+ for(si = ms_endLoadedList.m_prev; si != &ms_startLoadedList; si = si->m_prev){
+ streamId = si - ms_aInfoForModel;
+ if(streamId >= STREAM_OFFSET_TXD &&
+ CTxdStore::GetNumRefs(streamId-STREAM_OFFSET_TXD) == 0){
+ RemoveModel(streamId);
+ if(ms_memoryUsed < mem)
+ return true;
+ }
+ }
+ return false;
+}
+
+// TODO: RemoveCurrentZonesModels
+
+void
+CStreaming::RemoveUnusedModelsInLoadedList(void)
+{
+ // empty
+}
+
+bool
+CStreaming::IsTxdUsedByRequestedModels(int32 txdId)
+{
+ CStreamingInfo *si;
+ int streamId;
+ int i;
+
+ for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = si->m_next){
+ streamId = si - ms_aInfoForModel;
+ if(streamId < STREAM_OFFSET_TXD &&
+ CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId)
+ return true;
+ }
+
+ for(i = 0; i < 4; i++){
+ streamId = ms_channel[0].streamIds[i];
+ if(streamId != -1 && streamId < STREAM_OFFSET_TXD &&
+ CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId)
+ return true;
+ streamId = ms_channel[1].streamIds[i];
+ if(streamId != -1 && streamId < STREAM_OFFSET_TXD &&
+ CModelInfo::GetModelInfo(streamId)->GetTxdSlot() == txdId)
+ return true;
+ }
+
+ return false;
+}
+
+int32
+CStreaming::GetAvailableVehicleSlot(void)
+{
+ int i;
+ for(i = 0; i < MAXVEHICLESLOADED; i++)
+ if(ms_vehiclesLoaded[i] == -1)
+ return i;
+ return -1;
+}
+
+bool
+CStreaming::AddToLoadedVehiclesList(int32 modelId)
+{
+ int i;
+ int id;
+
+ if(ms_numVehiclesLoaded < desiredNumVehiclesLoaded){
+ // still room for vehicles
+ for(i = 0; i < MAXVEHICLESLOADED; i++){
+ if(ms_vehiclesLoaded[ms_lastVehicleDeleted] == -1)
+ break;
+ ms_lastVehicleDeleted++;
+ if(ms_lastVehicleDeleted == MAXVEHICLESLOADED)
+ ms_lastVehicleDeleted = 0;
+ }
+ assert(ms_vehiclesLoaded[ms_lastVehicleDeleted] == -1);
+ ms_numVehiclesLoaded++;
+ }else{
+ // find vehicle we can remove
+ for(i = 0; i < MAXVEHICLESLOADED; i++){
+ id = ms_vehiclesLoaded[ms_lastVehicleDeleted];
+ if(id != -1 &&
+ (ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 &&
+ CModelInfo::GetModelInfo(id)->m_refCount == 0)
+ goto found;
+ ms_lastVehicleDeleted++;
+ if(ms_lastVehicleDeleted == MAXVEHICLESLOADED)
+ ms_lastVehicleDeleted = 0;
+ }
+ id = -1;
+found:
+ if(id == -1){
+ // didn't find anything, try a free slot
+ id = GetAvailableVehicleSlot();
+ if(id == -1)
+ return false; // still no luck
+ ms_lastVehicleDeleted = id;
+ // this is more that we wanted actually
+ ms_numVehiclesLoaded++;
+ }else
+ RemoveModel(id);
+ }
+
+ ms_vehiclesLoaded[ms_lastVehicleDeleted++] = modelId;
+ if(ms_lastVehicleDeleted == MAXVEHICLESLOADED)
+ ms_lastVehicleDeleted = 0;
+ return true;
+}
+
+bool
+CStreaming::IsObjectInCdImage(int32 id)
+{
+ uint32 posn, size;
+ return ms_aInfoForModel[id].GetCdPosnAndSize(posn, size);
+}
+
+void
+CStreaming::HaveAllBigBuildingsLoaded(eLevelName level)
+{
+ int i, n;
+ CEntity *e;
+
+ if(ms_hasLoadedLODs)
+ return;
+
+ if(level == LEVEL_INDUSTRIAL){
+ if(ms_aInfoForModel[islandLODcomInd].m_loadState != STREAMSTATE_LOADED ||
+ ms_aInfoForModel[islandLODsubInd].m_loadState != STREAMSTATE_LOADED)
+ return;
+ }else if(level == LEVEL_COMMERCIAL){
+ if(ms_aInfoForModel[islandLODindust].m_loadState != STREAMSTATE_LOADED ||
+ ms_aInfoForModel[islandLODsubCom].m_loadState != STREAMSTATE_LOADED)
+ return;
+ }else if(level == LEVEL_SUBURBAN){
+ if(ms_aInfoForModel[islandLODindust].m_loadState != STREAMSTATE_LOADED ||
+ ms_aInfoForModel[islandLODcomSub].m_loadState != STREAMSTATE_LOADED)
+ return;
+ }
+
+ n = CPools::GetBuildingPool()->GetSize();
+ for(i = 0; i < n; i++){
+ e = CPools::GetBuildingPool()->GetSlot(i);
+ if(e && e->bIsBIGBuilding && e->m_level == level &&
+ ms_aInfoForModel[e->GetModelIndex()].m_loadState != STREAMSTATE_LOADED)
+ return;
+ }
+
+ RemoveUnusedBigBuildings(level);
+ ms_hasLoadedLODs = true;
+}
+
+void
+CStreaming::SetModelIsDeletable(int32 id)
+{
+ ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_DONT_REMOVE;
+ if((id >= STREAM_OFFSET_TXD || CModelInfo::GetModelInfo(id)->m_type != MITYPE_VEHICLE) &&
+ (ms_aInfoForModel[id].m_flags & STREAMFLAGS_SCRIPTOWNED) == 0){
+ if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_LOADED)
+ RemoveModel(id);
+ else if(ms_aInfoForModel[id].m_next == nil)
+ ms_aInfoForModel[id].AddToList(&ms_startLoadedList);
+ }
+}
+
+void
+CStreaming::SetModelTxdIsDeletable(int32 id)
+{
+ SetModelIsDeletable(CModelInfo::GetModelInfo(id)->GetTxdSlot() + STREAM_OFFSET_TXD);
+}
+
+void
+CStreaming::SetMissionDoesntRequireModel(int32 id)
+{
+ ms_aInfoForModel[id].m_flags &= ~STREAMFLAGS_SCRIPTOWNED;
+ if((id >= STREAM_OFFSET_TXD || CModelInfo::GetModelInfo(id)->m_type != MITYPE_VEHICLE) &&
+ (ms_aInfoForModel[id].m_flags & STREAMFLAGS_DONT_REMOVE) == 0){
+ if(ms_aInfoForModel[id].m_loadState != STREAMSTATE_LOADED)
+ RemoveModel(id);
+ else if(ms_aInfoForModel[id].m_next == nil)
+ ms_aInfoForModel[id].AddToList(&ms_startLoadedList);
+ }
+}
+
+void
+CStreaming::LoadInitialPeds(void)
+{
+ RequestModel(MI_COP, STREAMFLAGS_DONT_REMOVE);
+ RequestModel(MI_MALE01, STREAMFLAGS_DONT_REMOVE);
+ RequestModel(MI_TAXI_D, STREAMFLAGS_DONT_REMOVE);
+}
+
+void
+CStreaming::LoadInitialVehicles(void)
+{
+ int id;
+
+ ms_numVehiclesLoaded = 0;
+ ms_lastVehicleDeleted = 0;
+
+ if(CModelInfo::GetModelInfo("taxi", &id))
+ RequestModel(id, STREAMFLAGS_DONT_REMOVE);
+ if(CModelInfo::GetModelInfo("police", &id))
+ RequestModel(id, STREAMFLAGS_DONT_REMOVE);
+}
+
+
+// Find starting offset of the cdimage we next want to read
+// Not useful at all on PC...
+int32
+CStreaming::GetCdImageOffset(int32 lastPosn)
+{
+ int offset, off;
+ int i, img;
+ int dist, mindist;
+
+ img = -1;
+ mindist = INT_MAX;
+ offset = ms_imageOffsets[ms_lastImageRead];
+ if(lastPosn <= offset || lastPosn > offset + ms_imageSize){
+ // last read position is not in last image
+ for(i = 0; i < NUMCDIMAGES; i++){
+ off = ms_imageOffsets[i];
+ if(off == -1) continue;
+ if((uint32)lastPosn > (uint32)off)
+ // after start of image, get distance from end
+ // negative if before end!
+ dist = lastPosn - (off + ms_imageSize);
+ else
+ // before image, get offset to start
+ // this will never be negative
+ dist = off - lastPosn;
+ if(dist < mindist){
+ img = i;
+ mindist = dist;
+ }
+ }
+ assert(img >= 0);
+ offset = ms_imageOffsets[img];
+ ms_lastImageRead = img;
+ }
+ return offset;
+}
+
+inline bool
+TxdAvailable(int32 txdId)
+{
+ CStreamingInfo *si = &CStreaming::ms_aInfoForModel[txdId + STREAM_OFFSET_TXD];
+ return si->m_loadState == STREAMSTATE_LOADED || si->m_loadState == STREAMSTATE_READING;
+}
+
+// Find stream id of next requested file in cdimage
+int32
+CStreaming::GetNextFileOnCd(int32 lastPosn, bool priority)
+{
+ CStreamingInfo *si, *next;
+ int streamId;
+ uint32 posn, size;
+ int streamIdFirst, streamIdNext;
+ uint32 posnFirst, posnNext;
+
+ streamIdFirst = -1;
+ streamIdNext = -1;
+ posnFirst = UINT_MAX;
+ posnNext = UINT_MAX;
+
+ for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = next){
+ next = si->m_next;
+ streamId = si - ms_aInfoForModel;
+
+ // only priority requests if there are any
+ if(priority && ms_numPriorityRequests != 0 && !si->IsPriority())
+ continue;
+
+ // request Txd if necessary
+ if(streamId < STREAM_OFFSET_TXD &&
+ !TxdAvailable(CModelInfo::GetModelInfo(streamId)->GetTxdSlot())){
+ ReRequestTxd(CModelInfo::GetModelInfo(streamId)->GetTxdSlot());
+ }else if(ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)){
+ if(posn < posnFirst){
+ // find first requested file in image
+ streamIdFirst = streamId;
+ posnFirst = posn;
+ }
+ if(posn < posnNext && posn >= (uint32)lastPosn){
+ // find first requested file after last read position
+ streamIdNext = streamId;
+ posnNext = posn;
+ }
+ }else{
+ // empty file
+ DecrementRef(streamId);
+ si->RemoveFromList();
+ si->m_loadState = STREAMSTATE_LOADED;
+ }
+ }
+
+ // wrap around
+ if(streamIdNext == -1)
+ streamIdNext = streamIdFirst;
+
+ if(streamIdNext == -1 && ms_numPriorityRequests != 0){
+ // try non-priority files
+ ms_numPriorityRequests = 0;
+ streamIdNext = GetNextFileOnCd(lastPosn, false);
+ }
+
+ return streamIdNext;
+}
+
+/*
+ * Streaming buffer size is half of the largest file.
+ * Files larger than the buffer size can only be loaded by channel 0,
+ * which then uses both buffers, while channel 1 is idle.
+ * ms_bLoadingBigModel is set to true to indicate this state.
+ *
+ * TODO: two-part files
+ */
+
+// Make channel read from disc
+void
+CStreaming::RequestModelStream(int32 ch)
+{
+ int lastPosn, imgOffset, streamId;
+ int totalSize;
+ uint32 posn, size, unused;
+ int i;
+ int haveBigFile, havePed;
+
+ lastPosn = CdStreamGetLastPosn();
+ imgOffset = GetCdImageOffset(lastPosn);
+ streamId = GetNextFileOnCd(lastPosn - imgOffset, true);
+
+ if(streamId == -1)
+ return;
+
+ // remove Txds that aren't requested anymore
+ while(streamId >= STREAM_OFFSET_TXD){
+ if(ms_aInfoForModel[streamId].m_flags & STREAMFLAGS_KEEP_IN_MEMORY ||
+ IsTxdUsedByRequestedModels(streamId - STREAM_OFFSET_TXD))
+ break;
+ RemoveModel(streamId);
+ // so try next file
+ ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size);
+ streamId = GetNextFileOnCd(posn + size, true);
+ }
+
+ if(streamId == -1)
+ return;
+
+ ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size);
+ if(size > (uint32)ms_streamingBufferSize){
+ // Can only load big models on channel 0, and 1 has to be idle
+ if(ch == 1 || ms_channel[1].state != CHANNELSTATE_IDLE)
+ return;
+ ms_bLoadingBigModel = true;
+ }
+
+ // Load up to 4 adjacent files
+ haveBigFile = 0;
+ havePed = 0;
+ totalSize = 0;
+ for(i = 0; i < 4; i++){
+ // no more files we can read
+ if(streamId == -1 || ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_INQUEUE)
+ break;
+
+ // also stop at non-priority files
+ ms_aInfoForModel[streamId].GetCdPosnAndSize(unused, size);
+ if(ms_numPriorityRequests != 0 && !ms_aInfoForModel[streamId].IsPriority())
+ break;
+
+ // Can't load certain combinations of files together
+ if(streamId < STREAM_OFFSET_TXD){
+ if(havePed && CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_PED ||
+ haveBigFile && CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_VEHICLE ||
+ !TxdAvailable(CModelInfo::GetModelInfo(streamId)->GetTxdSlot()))
+ break;
+ }else{
+ if(haveBigFile && size > 200)
+ break;
+ }
+
+ // Now add the file
+ ms_channel[ch].streamIds[i] = streamId;
+ ms_channel[ch].offsets[i] = totalSize;
+ totalSize += size;
+
+ // To big for buffer, remove again
+ if(totalSize > ms_streamingBufferSize && i > 0){
+ totalSize -= size;
+ break;
+ }
+ if(streamId < STREAM_OFFSET_TXD){
+ if(CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_PED)
+ havePed = 1;
+ if(CModelInfo::GetModelInfo(streamId)->m_type == MITYPE_VEHICLE)
+ haveBigFile = 1;
+ }else{
+ if(size > 200)
+ haveBigFile = 1;
+ }
+ ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_READING;
+ ms_aInfoForModel[streamId].RemoveFromList();
+ DecrementRef(streamId);
+
+ streamId = ms_aInfoForModel[streamId].m_nextID;
+ }
+
+ // clear remaining slots
+ for(; i < 4; i++)
+ ms_channel[ch].streamIds[i] = -1;
+ // Now read the data
+ assert(!(ms_bLoadingBigModel && ch == 1)); // this would clobber the buffer
+ if(CdStreamRead(ch, ms_pStreamingBuffer[ch], imgOffset+posn, totalSize) == STREAM_NONE)
+ debug("FUCKFUCKFUCK\n");
+ ms_channel[ch].state = CHANNELSTATE_READING;
+ ms_channel[ch].field24 = 0;
+ ms_channel[ch].size = totalSize;
+ ms_channel[ch].position = imgOffset+posn;
+ ms_channel[ch].numTries = 0;
+}
+
+// Load data previously read from disc
+bool
+CStreaming::ProcessLoadingChannel(int32 ch)
+{
+ int status;
+ int i, id, cdsize;
+
+ status = CdStreamGetStatus(ch);
+ if(status != STREAM_NONE){
+ // busy
+ if(status != STREAM_READING && status != STREAM_WAITING){
+ ms_channelError = ch;
+ ms_channel[ch].state = CHANNELSTATE_ERROR;
+ ms_channel[ch].status = status;
+ }
+ return false;
+ }
+
+ if(ms_channel[ch].state == CHANNELSTATE_STARTED){
+ ms_channel[ch].state = CHANNELSTATE_IDLE;
+ FinishLoadingLargeFile(&ms_pStreamingBuffer[ch][ms_channel[ch].offsets[0]*CDSTREAM_SECTOR_SIZE],
+ ms_channel[ch].streamIds[0]);
+ ms_channel[ch].streamIds[0] = -1;
+ }else{
+ ms_channel[ch].state = CHANNELSTATE_IDLE;
+ for(i = 0; i < 4; i++){
+ id = ms_channel[ch].streamIds[i];
+ if(id == -1)
+ continue;
+
+ cdsize = ms_aInfoForModel[id].GetCdSize();
+ if(id < STREAM_OFFSET_TXD &&
+ CModelInfo::GetModelInfo(id)->m_type == MITYPE_VEHICLE &&
+ ms_numVehiclesLoaded >= desiredNumVehiclesLoaded &&
+ !RemoveLoadedVehicle() &&
+ ((ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST) == 0 || GetAvailableVehicleSlot() == -1)){
+ // can't load vehicle
+ RemoveModel(id);
+ if(ms_aInfoForModel[id].m_flags & STREAMFLAGS_NOT_IN_LIST)
+ ReRequestModel(id);
+ else if(CTxdStore::GetNumRefs(CModelInfo::GetModelInfo(id)->GetTxdSlot()) == 0)
+ RemoveTxd(CModelInfo::GetModelInfo(id)->GetTxdSlot());
+ }else{
+ MakeSpaceFor(cdsize * CDSTREAM_SECTOR_SIZE);
+ ConvertBufferToObject(&ms_pStreamingBuffer[ch][ms_channel[ch].offsets[i]*CDSTREAM_SECTOR_SIZE],
+ id);
+ if(ms_aInfoForModel[id].m_loadState == STREAMSTATE_STARTED){
+ // queue for second part
+ ms_channel[ch].state = CHANNELSTATE_STARTED;
+ ms_channel[ch].offsets[0] = ms_channel[ch].offsets[i];
+ ms_channel[ch].streamIds[0] = id;
+ if(i != 0)
+ ms_channel[ch].streamIds[i] = -1;
+ }else
+ ms_channel[ch].streamIds[i] = -1;
+ }
+ }
+ }
+
+ if(ms_bLoadingBigModel && ms_channel[ch].state != CHANNELSTATE_STARTED){
+ ms_bLoadingBigModel = false;
+ // reset channel 1 after loading a big model
+ for(i = 0; i < 4; i++)
+ ms_channel[1].streamIds[i] = -1;
+ ms_channel[1].state = CHANNELSTATE_IDLE;
+ }
+
+ return true;
+}
+
+void
+CStreaming::RetryLoadFile(int32 ch)
+{
+ char *key;
+
+ CPad::StopPadsShaking();
+
+ if(ms_channel[ch].numTries >= 3){
+ switch(ms_channel[ch].status){
+ case STREAM_ERROR_NOCD: key = "NOCD"; break;
+ case STREAM_ERROR_OPENCD: key = "OPENCD"; break;
+ case STREAM_ERROR_WRONGCD: key = "WRONGCD"; break;
+ default: key = "CDERROR"; break;
+ }
+ CHud::SetMessage(TheText.Get(key));
+ CTimer::SetCodePause(true);
+ }
+
+ switch(ms_channel[ch].state){
+ case CHANNELSTATE_IDLE:
+streamread:
+ CdStreamRead(ch, ms_pStreamingBuffer[ch], ms_channel[ch].position, ms_channel[ch].size);
+ ms_channel[ch].state = CHANNELSTATE_READING;
+ ms_channel[ch].field24 = -600;
+ break;
+ case CHANNELSTATE_READING:
+ if(ProcessLoadingChannel(ch)){
+ ms_channelError = -1;
+ CTimer::SetCodePause(false);
+ }
+ break;
+ case CHANNELSTATE_ERROR:
+ ms_channel[ch].numTries++;
+ if(CdStreamGetStatus(ch) != STREAM_READING && CdStreamGetStatus(ch) != STREAM_WAITING)
+ goto streamread;
+ break;
+ }
+}
+
+void
+CStreaming::LoadRequestedModels(void)
+{
+ static int currentChannel = 0;
+
+ // We can't read with channel 1 while channel 0 is using its buffer
+ if(ms_bLoadingBigModel)
+ currentChannel = 0;
+
+ // We have data, load
+ if(ms_channel[currentChannel].state == CHANNELSTATE_READING ||
+ ms_channel[currentChannel].state == CHANNELSTATE_STARTED)
+ ProcessLoadingChannel(currentChannel);
+
+ if(ms_channelError == -1){
+ // Channel is idle, read more data
+ if(ms_channel[currentChannel].state == CHANNELSTATE_IDLE)
+ RequestModelStream(currentChannel);
+ // Switch channel
+ if(ms_channel[currentChannel].state != CHANNELSTATE_STARTED)
+ currentChannel = 1 - currentChannel;
+ }
+}
+
+void
+CStreaming::LoadAllRequestedModels(bool priority)
+{
+ static bool bInsideLoadAll = false;
+ int imgOffset, streamId, status;
+ int i;
+ uint32 posn, size;
+
+ if(bInsideLoadAll)
+ return;
+
+ FlushChannels();
+ imgOffset = GetCdImageOffset(CdStreamGetLastPosn());
+
+ while(ms_endRequestedList.m_prev != &ms_startRequestedList){
+ streamId = GetNextFileOnCd(0, priority);
+ if(streamId == -1)
+ break;
+
+ ms_aInfoForModel[streamId].RemoveFromList();
+ DecrementRef(streamId);
+
+ if(ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)){
+ do
+ status = CdStreamRead(0, ms_pStreamingBuffer[0], imgOffset+posn, size);
+ while(CdStreamSync(0) || status == STREAM_NONE);
+ ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_READING;
+
+ MakeSpaceFor(size * CDSTREAM_SECTOR_SIZE);
+ ConvertBufferToObject(ms_pStreamingBuffer[0], streamId);
+ if(ms_aInfoForModel[streamId].m_loadState == STREAMSTATE_STARTED)
+ FinishLoadingLargeFile(ms_pStreamingBuffer[0], streamId);
+
+ if(streamId < STREAM_OFFSET_TXD){
+ CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(streamId);
+ if(mi->IsSimple())
+ mi->m_alpha = 255;
+ }
+ }else{
+ // empty
+ ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED;
+ }
+ }
+
+ ms_bLoadingBigModel = false;
+ for(i = 0; i < 4; i++){
+ ms_channel[1].streamIds[i] = -1;
+ ms_channel[1].offsets[i] = -1;
+ }
+ ms_channel[1].state = CHANNELSTATE_IDLE;
+ bInsideLoadAll = false;
+}
+
+void
+CStreaming::FlushChannels(void)
+{
+ if(ms_channel[1].state == CHANNELSTATE_STARTED)
+ ProcessLoadingChannel(1);
+
+ if(ms_channel[0].state == CHANNELSTATE_READING){
+ CdStreamSync(0);
+ ProcessLoadingChannel(0);
+ }
+ if(ms_channel[0].state == CHANNELSTATE_STARTED)
+ ProcessLoadingChannel(0);
+
+ if(ms_channel[1].state == CHANNELSTATE_READING){
+ CdStreamSync(1);
+ ProcessLoadingChannel(1);
+ }
+ if(ms_channel[1].state == CHANNELSTATE_STARTED)
+ ProcessLoadingChannel(1);
+}
+
+void
+CStreaming::FlushRequestList(void)
+{
+ CStreamingInfo *si, *next;
+
+ for(si = ms_startRequestedList.m_next; si != &ms_endRequestedList; si = next){
+ next = si->m_next;
+ RemoveModel(si - ms_aInfoForModel);
+ }
+ FlushChannels();
+}
+
void
CStreaming::ImGonnaUseStreamingMemory(void)
{
+ // empty
}
void
@@ -717,6 +1581,7 @@ CStreaming::IHaveUsedStreamingMemory(void)
void
CStreaming::UpdateMemoryUsed(void)
{
+ // empty
}
WRAPPER void CStreaming::LoadScene(CVector *pos) { EAXJMP(0x40A6D0); }
@@ -771,7 +1636,39 @@ STARTPATCHES
InjectHook(0x408210, CStreaming::RequestIslands, PATCH_JUMP);
InjectHook(0x40A890, CStreaming::RequestSpecialModel, PATCH_JUMP);
InjectHook(0x40ADA0, CStreaming::RequestSpecialChar, PATCH_JUMP);
+
InjectHook(0x408830, CStreaming::RemoveModel, PATCH_JUMP);
+ InjectHook(0x4083A0, CStreaming::RemoveUnusedBuildings, PATCH_JUMP);
+ InjectHook(0x4083D0, CStreaming::RemoveBuildings, PATCH_JUMP);
+ InjectHook(0x408640, CStreaming::RemoveUnusedBigBuildings, PATCH_JUMP);
+ InjectHook(0x408680, CStreaming::RemoveBigBuildings, PATCH_JUMP);
+ InjectHook(0x408780, CStreaming::RemoveIslandsNotUsed, PATCH_JUMP);
+ InjectHook(0x40B180, CStreaming::RemoveLoadedVehicle, PATCH_JUMP);
+ InjectHook(0x4089B0, CStreaming::RemoveLeastUsedModel, PATCH_JUMP);
+ InjectHook(0x408940, CStreaming::RemoveAllUnusedModels, PATCH_JUMP);
+ InjectHook(0x409450, CStreaming::RemoveReferencedTxds, PATCH_JUMP);
+
+ InjectHook(0x40B160, CStreaming::GetAvailableVehicleSlot, PATCH_JUMP);
+ InjectHook(0x40B060, CStreaming::AddToLoadedVehiclesList, PATCH_JUMP);
+ InjectHook(0x4094C0, CStreaming::IsTxdUsedByRequestedModels, PATCH_JUMP);
+ InjectHook(0x407E70, CStreaming::IsObjectInCdImage, PATCH_JUMP);
+ InjectHook(0x408280, CStreaming::HaveAllBigBuildingsLoaded, PATCH_JUMP);
+ InjectHook(0x40A790, CStreaming::SetModelIsDeletable, PATCH_JUMP);
+ InjectHook(0x40A800, CStreaming::SetModelTxdIsDeletable, PATCH_JUMP);
+ InjectHook(0x40A820, CStreaming::SetMissionDoesntRequireModel, PATCH_JUMP);
+
+ InjectHook(0x40AA00, CStreaming::LoadInitialPeds, PATCH_JUMP);
+ InjectHook(0x40ADF0, CStreaming::LoadInitialVehicles, PATCH_JUMP);
+
+ InjectHook(0x409BE0, CStreaming::ProcessLoadingChannel, PATCH_JUMP);
+ InjectHook(0x40A610, CStreaming::FlushChannels, PATCH_JUMP);
+ InjectHook(0x40A680, CStreaming::FlushRequestList, PATCH_JUMP);
+ InjectHook(0x409FF0, CStreaming::GetCdImageOffset, PATCH_JUMP);
+ InjectHook(0x409E50, CStreaming::GetNextFileOnCd, PATCH_JUMP);
+ InjectHook(0x40A060, CStreaming::RequestModelStream, PATCH_JUMP);
+ InjectHook(0x4077F0, CStreaming::RetryLoadFile, PATCH_JUMP);
+ InjectHook(0x40A390, CStreaming::LoadRequestedModels, PATCH_JUMP);
+ InjectHook(0x40A440, CStreaming::LoadAllRequestedModels, PATCH_JUMP);
InjectHook(0x4063E0, &CStreamingInfo::GetCdPosnAndSize, PATCH_JUMP);
InjectHook(0x406410, &CStreamingInfo::SetCdPosnAndSize, PATCH_JUMP);
diff --git a/src/Streaming.h b/src/Streaming.h
index 2b2efe79..e92819e1 100644
--- a/src/Streaming.h
+++ b/src/Streaming.h
@@ -14,6 +14,7 @@ enum StreamFlags
STREAMFLAGS_PRIORITY = 0x08,
STREAMFLAGS_NOFADE = 0x10,
+ // TODO: this isn't named well, maybe CANT_REMOVE?
STREAMFLAGS_NOT_IN_LIST = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED,
STREAMFLAGS_KEEP_IN_MEMORY = STREAMFLAGS_DONT_REMOVE|STREAMFLAGS_SCRIPTOWNED|STREAMFLAGS_DEPENDENCY,
};
@@ -23,13 +24,16 @@ enum StreamLoadState
STREAMSTATE_NOTLOADED = 0,
STREAMSTATE_LOADED = 1,
STREAMSTATE_INQUEUE = 2,
- STREAMSTATE_READING = 3, // what is this?
- STREAMSTATE_STARTED = 4, // first part read
+ STREAMSTATE_READING = 3, // channel is reading
+ STREAMSTATE_STARTED = 4, // first part loaded
};
enum ChannelState
{
- CHANNELSTATE_0 = 0,
+ CHANNELSTATE_IDLE = 0,
+ CHANNELSTATE_READING = 1,
+ CHANNELSTATE_STARTED = 2,
+ CHANNELSTATE_ERROR = 3,
};
class CStreamingInfo
@@ -49,17 +53,18 @@ public:
void AddToList(CStreamingInfo *link);
void RemoveFromList(void);
uint32 GetCdSize(void) { return m_size; }
+ bool IsPriority(void) { return !!(m_flags & STREAMFLAGS_PRIORITY); }
};
struct CStreamingChannel
{
- int32 modelIds[4];
+ int32 streamIds[4];
int32 offsets[4];
int32 state;
int32 field24;
int32 position;
int32 size;
- int32 field30;
+ int32 numTries;
int32 status; // from CdStream
};
@@ -79,12 +84,14 @@ public:
static CStreamingInfo &ms_endRequestedList;
static int32 &ms_oldSectorX;
static int32 &ms_oldSectorY;
- static uint32 &ms_streamingBufferSize;
- static uint8 **ms_pStreamingBuffer; //[2]
+ static int32 &ms_streamingBufferSize;
+ static int8 **ms_pStreamingBuffer; //[2]
static int32 &ms_memoryUsed;
static CStreamingChannel *ms_channel; //[2]
+ static int32 &ms_channelError;
static int32 &ms_numVehiclesLoaded;
static int32 *ms_vehiclesLoaded; //[MAXVEHICLESLOADED]
+ static int32 &ms_lastVehicleDeleted;
static CDirectory *&ms_pExtraObjectsDir;
static int32 &ms_numPriorityRequests;
static bool &ms_hasLoadedLODs;
@@ -104,22 +111,55 @@ public:
static bool ConvertBufferToObject(int8 *buf, int32 streamId);
static bool FinishLoadingLargeFile(int8 *buf, int32 streamId);
static void RequestModel(int32 model, int32 flags);
+ static void ReRequestModel(int32 model) { RequestModel(model, ms_aInfoForModel[model].m_flags); }
static void RequestTxd(int32 txd, int32 flags) { RequestModel(txd + STREAM_OFFSET_TXD, flags); }
+ static void ReRequestTxd(int32 txd) { ReRequestModel(txd + STREAM_OFFSET_TXD); }
static void RequestSubway(void);
static void RequestBigBuildings(eLevelName level);
static void RequestIslands(eLevelName level);
static void RequestSpecialModel(int32 modelId, const char *modelName, int32 flags);
static void RequestSpecialChar(int32 charId, const char *modelName, int32 flags);
+ static void DecrementRef(int32 id);
static void RemoveModel(int32 id);
-
+ static void RemoveTxd(int32 id) { RemoveModel(id + STREAM_OFFSET_TXD); }
+ static void RemoveUnusedBuildings(eLevelName level);
+ static void RemoveBuildings(eLevelName level);
+ static void RemoveUnusedBigBuildings(eLevelName level);
+ static void RemoveIslandsNotUsed(eLevelName level);
+ static void RemoveBigBuildings(eLevelName level);
+ static bool RemoveLoadedVehicle(void);
+ static bool RemoveLeastUsedModel(void);
+ static void RemoveAllUnusedModels(void);
+ static void RemoveUnusedModelsInLoadedList(void);
+ static bool RemoveReferencedTxds(int32 mem);
+ static int32 GetAvailableVehicleSlot(void);
static bool IsTxdUsedByRequestedModels(int32 txdId);
static bool AddToLoadedVehiclesList(int32 modelId);
+ static bool IsObjectInCdImage(int32 id);
+ static void HaveAllBigBuildingsLoaded(eLevelName level);
+ static void SetModelIsDeletable(int32 id);
+ static void SetModelTxdIsDeletable(int32 id);
+ static void SetMissionDoesntRequireModel(int32 id);
+
+ static int32 GetCdImageOffset(int32 lastPosn);
+ static int32 GetNextFileOnCd(int32 position, bool priority);
+ static void RequestModelStream(int32 ch);
+ static bool ProcessLoadingChannel(int32 ch);
+ static void RetryLoadFile(int32 ch);
+ static void LoadRequestedModels(void);
+ static void LoadAllRequestedModels(bool priority);
+ static void FlushChannels(void);
+ static void FlushRequestList(void);
static void MakeSpaceFor(int32 size);
static void ImGonnaUseStreamingMemory(void);
static void IHaveUsedStreamingMemory(void);
static void UpdateMemoryUsed(void);
+
+ static void LoadInitialPeds(void);
+ static void LoadInitialVehicles(void);
+
static void LoadScene(CVector *pos);
static void LoadAllRequestedModels(bool);
};
diff --git a/src/Timer.h b/src/Timer.h
index b8b5864d..75d4048c 100644
--- a/src/Timer.h
+++ b/src/Timer.h
@@ -29,9 +29,10 @@ public:
static inline void SetPreviousTimeInMilliseconds(uint32 t) { m_snPreviousTimeInMilliseconds = t; }
static float GetTimeScale(void) { return ms_fTimeScale; }
static inline void SetTimeScale(float ts) { ms_fTimeScale = ts; }
-
- static inline bool GetIsPaused() { return m_UserPause || m_CodePause; }
- static inline bool GetIsUserPaused() { return m_UserPause; }
+
+ static bool GetIsPaused() { return m_UserPause || m_CodePause; }
+ static bool GetIsUserPaused() { return m_UserPause; }
+ static void SetCodePause(bool pause) { m_CodePause = pause; }
static void Initialise(void);
static void Shutdown(void);
diff --git a/src/World.cpp b/src/World.cpp
index 20203297..0a83c595 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -592,6 +592,6 @@ WRAPPER CPlayerPed *FindPlayerPed(void) { EAXJMP(0x4A1150); }
WRAPPER CVector &FindPlayerCoors(CVector &v) { EAXJMP(0x4A1030); }
WRAPPER CVehicle *FindPlayerVehicle(void) { EAXJMP(0x4A10C0); }
WRAPPER CVehicle *FindPlayerTrain(void) { EAXJMP(0x4A1120); }
-WRAPPER CVector FindPlayerSpeed(void) { EAXJMP(0x4A1090); }
+WRAPPER CVector &FindPlayerSpeed(void) { EAXJMP(0x4A1090); }
WRAPPER CVector FindPlayerCentreOfWorld_NoSniperShift(void) { EAXJMP(0x4A11C0); }
WRAPPER float FindPlayerHeading(void) { EAXJMP(0x4A1220); }
diff --git a/src/World.h b/src/World.h
index 13b9f254..e3a6a8f2 100644
--- a/src/World.h
+++ b/src/World.h
@@ -111,6 +111,6 @@ CPlayerPed *FindPlayerPed(void);
CVector &FindPlayerCoors(CVector &v);
CVehicle *FindPlayerVehicle(void);
CVehicle *FindPlayerTrain(void);
-CVector FindPlayerSpeed(void);
+CVector &FindPlayerSpeed(void);
CVector FindPlayerCentreOfWorld_NoSniperShift(void);
float FindPlayerHeading(void);
diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h
index 7eec69a0..076fa810 100644
--- a/src/animation/AnimBlendAssociation.h
+++ b/src/animation/AnimBlendAssociation.h
@@ -2,8 +2,7 @@
#include "AnimBlendList.h"
#include "AnimBlendNode.h"
-
-class CAnimBlendHierarchy;
+#include "AnimBlendHierarchy.h"
enum {
// TODO
@@ -78,6 +77,8 @@ public:
void UpdateTime(float timeDelta, float relSpeed);
bool UpdateBlend(float timeDelta);
+ float GetTimeLeft() { return hierarchy->totalLength - currentTime; }
+
static CAnimBlendAssociation *FromLink(CAnimBlendLink *l) {
return (CAnimBlendAssociation*)((uint8*)l - offsetof(CAnimBlendAssociation, link));
}
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
new file mode 100644
index 00000000..757ffa79
--- /dev/null
+++ b/src/audio/AudioManager.cpp
@@ -0,0 +1,17 @@
+#include "common.h"
+#include "patcher.h"
+#include "AudioManager.h"
+
+cAudioManager &AudioManager = *(cAudioManager*)0x880FC0;
+
+void
+cAudioManager::PlayerJustLeftCar(void)
+{
+ // UNUSED: This is a perfectly empty function.
+}
+
+WRAPPER void cAudioManager::Service() { EAXJMP(0x57A2A0); }
+
+STARTPATCHES
+ InjectHook(0x56AD20, &cAudioManager::PlayerJustLeftCar, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
new file mode 100644
index 00000000..9e25b0a3
--- /dev/null
+++ b/src/audio/AudioManager.h
@@ -0,0 +1,9 @@
+#pragma once
+
+class cAudioManager {
+public:
+ void PlayerJustLeftCar(void);
+ void Service();
+};
+
+extern cAudioManager &AudioManager; \ No newline at end of file
diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h
index 7a3d1477..6df2ceea 100644
--- a/src/audio/DMAudio.h
+++ b/src/audio/DMAudio.h
@@ -195,5 +195,7 @@ public:
int32 CreateEntity(int, void*);
void SetEntityStatus(int32, int8);
void SetRadioInCar(int32);
+ uint8 IsMP3RadioChannelAvailable();
+
};
extern cDMAudio &DMAudio;
diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp
index f9c02739..6f2d3d86 100644
--- a/src/audio/MusicManager.cpp
+++ b/src/audio/MusicManager.cpp
@@ -16,6 +16,8 @@ int32 &gNumRetunePresses = *(int32*)0x650B80;
wchar *pCurrentStation = (wchar*)0x650B9C;
uint8 &cDisplay = *(uint8*)0x650BA1;
+WRAPPER char* cMusicManager::Get3DProviderName(char) { EAXJMP(0x57A8C0); }
+
bool cMusicManager::PlayerInCar()
{
if (!FindPlayerVehicle())
diff --git a/src/audio/MusicManager.h b/src/audio/MusicManager.h
index 644c3df3..dcb34daf 100644
--- a/src/audio/MusicManager.h
+++ b/src/audio/MusicManager.h
@@ -264,6 +264,7 @@ public:
uint8 field_2395;
public:
+ char *Get3DProviderName(char);
bool PlayerInCar();
void DisplayRadioStationName();
};
diff --git a/src/config.h b/src/config.h
index 7eb3238d..83aa7b8f 100644
--- a/src/config.h
+++ b/src/config.h
@@ -58,9 +58,8 @@ enum Config {
NUMPOINTLIGHTS = 32,
NUMONSCREENTIMERENTRIES = 1,
-
+ NUMRADARBLIPS = 32,
NUMPICKUPS = 336,
- NUMBLIPS = 32
};
#define GTA3_1_1_PATCH
@@ -71,3 +70,4 @@ enum Config {
//#define NO_CDCHECK
#define NO_MOVIES
//#define USE_MY_DOCUMENTS
+#define NASTY_GAME \ No newline at end of file
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 730ccd16..4ce856f7 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -2,6 +2,8 @@
#include "patcher.h"
#include "CarCtrl.h"
+int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38;
+
WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
WRAPPER void CCarCtrl::AddToCarArray(int id, int vehclass) { EAXJMP(0x4182F0); }
WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); } \ No newline at end of file
diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h
index a6537e34..cc9327ee 100644
--- a/src/control/CarCtrl.h
+++ b/src/control/CarCtrl.h
@@ -8,4 +8,6 @@ public:
static void SwitchVehicleToRealPhysics(CVehicle*);
static void AddToCarArray(int id, int vehclass);
static void UpdateCarCount(CVehicle*, bool);
+
+ static int32 &NumLawEnforcerCars;
};
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 70a15476..d601db8e 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -68,7 +68,7 @@ WRAPPER void CGarages::PrintMessages(void) { EAXJMP(0x426310); }
#else
void CGarages::PrintMessages()
{
- if (CTimer::GetTimeInMilliseconds() > CGarages::MessageStartTime && CTimer::GetTimeInMilliseconds() < CGarages::MessageEndTime) {
+ if (CTimer::GetTimeInMilliseconds() > MessageStartTime && CTimer::GetTimeInMilliseconds() < MessageEndTime) {
CFont::SetScale(SCREEN_SCALE_X(1.2f / 2), SCREEN_SCALE_Y(1.5f / 2)); // BUG: game doesn't use macro here.
CFont::SetPropOn();
CFont::SetJustifyOff();
@@ -77,16 +77,16 @@ void CGarages::PrintMessages()
CFont::SetCentreOn();
CFont::SetFontStyle(FONT_BANK);
- if (CGarages::MessageNumberInString2 < 0) {
- if (CGarages::MessageNumberInString < 0) {
+ if (MessageNumberInString2 < 0) {
+ if (MessageNumberInString < 0) {
CFont::SetColor(CRGBA(0, 0, 0, 255));
- CFont::PrintString((SCREEN_WIDTH/ 2) + SCREEN_SCALE_X(2.0f), (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(-84.0f), TheText.Get(CGarages::MessageIDString));
+ CFont::PrintString((SCREEN_WIDTH/ 2) + SCREEN_SCALE_X(2.0f), (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(-84.0f), TheText.Get(MessageIDString));
CFont::SetColor(CRGBA(89, 115, 150, 255));
- CFont::PrintString((SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(-84.0f), TheText.Get(CGarages::MessageIDString));
+ CFont::PrintString((SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(-84.0f), TheText.Get(MessageIDString));
}
else {
- CMessages::InsertNumberInString(TheText.Get(CGarages::MessageIDString), CGarages::MessageNumberInString, -1, -1, -1, -1, -1, gUString);
+ CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, -1, -1, -1, -1, -1, gUString);
CFont::SetColor(CRGBA(0, 0, 0, 255));
CFont::PrintString((SCREEN_WIDTH / 2) + SCREEN_SCALE_X(2.0f), (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(-84.0f + 2.0 - 40.0f), gUString);
@@ -96,7 +96,7 @@ void CGarages::PrintMessages()
}
}
else {
- CMessages::InsertNumberInString(TheText.Get(CGarages::MessageIDString), CGarages::MessageNumberInString2, -1, -1, -1, -1, -1, gUString);
+ CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, MessageNumberInString2, -1, -1, -1, -1, gUString);
CFont::SetColor(CRGBA(0, 0, 0, 255));
CFont::PrintString((SCREEN_WIDTH / 2) + SCREEN_SCALE_X(2.0f), (SCREEN_HEIGHT / 2) + SCREEN_SCALE_Y(-84.0f + 2.0 - 40.0f), gUString);
diff --git a/src/control/PedPlacement.cpp b/src/control/PedPlacement.cpp
new file mode 100644
index 00000000..de4cdae1
--- /dev/null
+++ b/src/control/PedPlacement.cpp
@@ -0,0 +1,40 @@
+#include "common.h"
+#include "patcher.h"
+#include "PedPlacement.h"
+#include "World.h"
+
+void
+CPedPlacement::FindZCoorForPed(CVector* pos)
+{
+ float zForPed;
+ float startZ = pos->z - 100.0f;
+ float foundColZ = -100.0f;
+ float foundColZ2 = -100.0f;
+ CColPoint foundCol;
+ CEntity* foundEnt;
+
+ CVector vec(
+ pos->x,
+ pos->y,
+ pos->z + 1.0f
+ );
+
+ if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, false))
+ foundColZ = foundCol.point.z;
+
+ // Adjust coords and do a second test
+ vec.x += 0.1f;
+ vec.y += 0.1f;
+
+ if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, false, false, false, true, false, false))
+ foundColZ2 = foundCol.point.z;
+
+ zForPed = max(foundColZ, foundColZ2);
+
+ if (zForPed > -99.0f)
+ pos->z = 1.04f + zForPed;
+}
+
+STARTPATCHES
+ InjectHook(0x4EE340, &CPedPlacement::FindZCoorForPed, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/control/PedPlacement.h b/src/control/PedPlacement.h
new file mode 100644
index 00000000..4bd48b62
--- /dev/null
+++ b/src/control/PedPlacement.h
@@ -0,0 +1,8 @@
+#pragma once
+
+class CVector;
+
+class CPedPlacement {
+public:
+ static void FindZCoorForPed(CVector* pos);
+}; \ No newline at end of file
diff --git a/src/control/PedType.h b/src/control/PedType.h
index 02add8f6..455d8d8d 100644
--- a/src/control/PedType.h
+++ b/src/control/PedType.h
@@ -22,9 +22,9 @@ enum
PEDTYPE_EMERGENCY,
PEDTYPE_FIREMAN,
PEDTYPE_CRIMINAL,
- PEDTYPE_SPECIAL,
- PEDTYPE_PROSTITUTE,
PEDTYPE_UNUSED1,
+ PEDTYPE_PROSTITUTE,
+ PEDTYPE_SPECIAL,
PEDTYPE_UNUSED2,
NUM_PEDTYPES
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index dfc988c3..1c71f25f 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -24,6 +24,8 @@
#include "Timer.h"
#include "Weather.h"
#include "Zones.h"
+#include "Font.h"
+#include "Text.h"
uint8 &CReplay::Mode = *(uint8*)0x95CD5B;
CAddressInReplayBuffer &CReplay::Record = *(CAddressInReplayBuffer*)0x942F7C;
@@ -451,7 +453,6 @@ WRAPPER bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buf
WRAPPER void CReplay::FinishPlayback(void) { EAXJMP(0x595B20); }
WRAPPER void CReplay::Shutdown(void) { EAXJMP(0x595BD0); }
WRAPPER void CReplay::ProcessReplayCamera(void) { EAXJMP(0x595C40); }
-WRAPPER void CReplay::Display(void) { EAXJMP(0x595EE0); }
#if 0
WRAPPER void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene) { EAXJMP(0x596030); }
@@ -732,6 +733,23 @@ WRAPPER bool CReplay::ShouldStandardCameraBeProcessed(void) { EAXJMP(0x597680);
WRAPPER void CReplay::ProcessLookAroundCam(void) { EAXJMP(0x5976C0); }
WRAPPER size_t CReplay::FindSizeOfPacket(uint8 type) { EAXJMP(0x597CC0); }
+#if 0
+WRAPPER void CReplay::Display(void) { EAXJMP(0x595EE0); }
+#else
+void CReplay::Display()
+{
+ if (CReplay::IsPlayingBack() && CTimer::GetFrameCounter() + 1 & 0x20) {
+ CFont::SetPropOn();
+ CFont::SetBackgroundOff();
+ CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
+ CFont::SetAlignment(ALIGN_LEFT);
+ CFont::SetColor(CRGBA(255, 255, 200, 200));
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::PrintString(SCREEN_SCALE_X(63.5f), SCREEN_SCALE_Y(30.0f), TheText.Get("REPLAY"));
+ }
+}
+#endif
+
STARTPATCHES
InjectHook(0x592FC0, PrintElementsInPtrList, PATCH_JUMP);
InjectHook(0x592FE0, CReplay::Init, PATCH_JUMP);
diff --git a/src/entities/Building.cpp b/src/entities/Building.cpp
index 9e56b3a2..d69a65fe 100644
--- a/src/entities/Building.cpp
+++ b/src/entities/Building.cpp
@@ -22,5 +22,6 @@ CBuilding::ReplaceWithNewModel(int32 id)
}
STARTPATCHES
+ InjectHook(0x4057D0, &CBuilding::ctor, PATCH_JUMP);
InjectHook(0x405850, &CBuilding::ReplaceWithNewModel, PATCH_JUMP);
ENDPATCHES
diff --git a/src/entities/Building.h b/src/entities/Building.h
index 7b837f46..b1f96bae 100644
--- a/src/entities/Building.h
+++ b/src/entities/Building.h
@@ -15,5 +15,7 @@ public:
void ReplaceWithNewModel(int32 id);
virtual bool GetIsATreadable(void) { return false; }
+
+ CBuilding *ctor(void) { return ::new (this) CBuilding(); }
};
static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error");
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index d2b2577d..294518c8 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -339,9 +339,9 @@ CEntity::GetBoundRect(void)
return rect;
}
-void
+WRAPPER void
CEntity::PreRender(void)
-{
+{ EAXJMP(0x474350);
}
void
@@ -448,6 +448,7 @@ CEntity::PruneReferences(void)
}
STARTPATCHES
+ InjectHook(0x473C30, &CEntity::ctor, PATCH_JUMP);
InjectHook(0x4742C0, (void (CEntity::*)(CVector&))&CEntity::GetBoundCentre, PATCH_JUMP);
InjectHook(0x474310, &CEntity::GetBoundRadius, PATCH_JUMP);
InjectHook(0x474C10, &CEntity::GetIsTouching, PATCH_JUMP);
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index 0ce47428..8816e206 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -155,6 +155,7 @@ public:
// to make patching virtual functions possible
+ CEntity *ctor(void) { return ::new (this) CEntity(); }
void Add_(void) { CEntity::Add(); }
void Remove_(void) { CEntity::Remove(); }
void CreateRwObject_(void) { CEntity::CreateRwObject(); }
diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp
index 20a5b48c..c4109312 100644
--- a/src/entities/Ped.cpp
+++ b/src/entities/Ped.cpp
@@ -10,11 +10,19 @@
#include "PlayerPed.h"
#include "General.h"
#include "VisibilityPlugins.h"
+#include "AudioManager.h"
+#include "HandlingMgr.h"
+#include "Replay.h"
+#include "PedPlacement.h"
bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
bool &CPed::bPedCheat2 = *(bool*)0x95CD5A;
bool &CPed::bPedCheat3 = *(bool*)0x95CD59;
+CVector &CPed::offsetToOpenRegularCarDoor = *(CVector*)0x62E030;
+CVector &CPed::offsetToOpenLowCarDoor = *(CVector*)0x62E03C;
+CVector &CPed::offsetToOpenVanDoor = *(CVector*)0x62E048;
+
void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); }
void CPed::operator delete(void *p, size_t sz) { CPools::GetPedPool()->Delete((CPed*)p); }
@@ -24,6 +32,9 @@ WRAPPER void CPed::SetDie(AnimationId anim, float arg1, float arg2) { EAXJMP(0x4
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
WRAPPER void CPed::RestorePreviousState(void) { EAXJMP(0x4C5E30); }
WRAPPER void CPed::ClearAttack(void) { EAXJMP(0x4E6790); }
+WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2480); }
+WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *dragAssoc, void *arg) { EAXJMP(0x4E2920); }
+WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); }
static char ObjectiveText[34][28] = {
"No Obj",
@@ -183,9 +194,8 @@ static char WaitStateText[21][16] = {
static RwObject*
RemoveAllModelCB(RwObject *object, void *data)
{
- RpAtomic* atomic = (RpAtomic*)object;
- if (CVisibilityPlugins::GetAtomicModelInfo(atomic))
- {
+ RpAtomic *atomic = (RpAtomic*)object;
+ if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) {
RpClumpRemoveAtomic(atomic->clump, atomic);
RpAtomicDestroy(atomic);
}
@@ -299,6 +309,14 @@ CPed::UseGroundColModel(void)
m_nPedState == PED_DEAD;
}
+bool
+CPed::CanSetPedState(void)
+{
+ return m_nPedState != PED_DIE && m_nPedState != PED_ARRESTED &&
+ m_nPedState != PED_ENTER_CAR && m_nPedState != PED_CARJACK && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_STEAL_CAR;
+}
+
+
void
CPed::AddWeaponModel(int id)
{
@@ -398,8 +416,9 @@ CPed::RemoveBodyPart(PedNode nodeId, int8 unk)
RecurseFrameChildrenVisibilityCB(frame, 0);
pos.x = 0.0f;
- pos.z = 0.0f;
pos.y = 0.0f;
+ pos.z = 0.0f;
+
for (frame = RwFrameGetParent(frame); frame; frame = RwFrameGetParent(frame))
RwV3dTransformPoints(&pos, &pos, 1, RwFrameGetMatrix(frame));
@@ -490,11 +509,11 @@ CPed::OurPedCanSeeThisOne(CEntity *target)
// Check if target is behind ped
if (DotProduct2D(dist, CVector2D(this->GetForward())) < 0.0f)
- return 0;
+ return false;
// Check if target is too far away
- if (dist.Magnitude() < 40.0f)
- return 0;
+ if (dist.Magnitude() >= 40.0f)
+ return false;
// Check line of sight from head
CVector headPos = this->GetPosition();
@@ -589,7 +608,7 @@ CPed::IsPedHeadAbovePos(float zOffset)
RwMatrix mat;
CPedIK::GetWorldMatrix(GetNodeFrame(PED_HEAD), &mat);
- return zOffset + GetPosition().z >= mat.pos.z;
+ return zOffset + GetPosition().z < RwMatrixGetPos(&mat)->z;
}
void
@@ -602,22 +621,24 @@ CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg)
if (attackAssoc) {
switch (attackAssoc->animId) {
case ANIM_WEAPON_START_THROW:
- if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->field_1376) && ped->IsPlayer())
+ if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->field_1380) && ped->IsPlayer())
{
- attackAssoc->blendDelta = -1000.0;
+ attackAssoc->blendDelta = -1000.0f;
newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROWU);
} else {
- attackAssoc->blendDelta = -1000.0;
+ attackAssoc->blendDelta = -1000.0f;
newAnim = CAnimManager::AddAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WEAPON_THROW);
}
- newAnim->SetFinishCallback(CPed::FinishedAttackCB, ped);
- break;
+ newAnim->SetFinishCallback(FinishedAttackCB, ped);
+ return;
+
case ANIM_FIGHT_PPUNCH:
- attackAssoc->blendDelta = -8.0;
+ attackAssoc->blendDelta = -8.0f;
attackAssoc->flags |= ASSOC_DELETEFADEDOUT;
ped->ClearAttack();
- break;
+ return;
+
case ANIM_WEAPON_THROW:
case ANIM_WEAPON_THROWU:
if (ped->GetWeapon()->m_nAmmoTotal > 0) {
@@ -626,12 +647,11 @@ CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg)
}
break;
default:
- if (!ped->m_ped_flagA4)
- ped->ClearAttack();
-
break;
}
- } else if (!ped->m_ped_flagA4)
+ }
+
+ if (!ped->m_ped_flagA4)
ped->ClearAttack();
}
@@ -658,7 +678,7 @@ CPed::Attack(void)
ourWeaponFire = ourWeapon->m_eWeaponFire;
weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_AnimToPlay);
lastReloadWasInFuture = m_ped_flagA4;
- reloadAnimAssoc = 0;
+ reloadAnimAssoc = nil;
reloadAnim = NUM_ANIMS;
delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire;
weaponAnim = ourWeapon->m_AnimToPlay;
@@ -676,7 +696,7 @@ CPed::Attack(void)
if (reloadAnimAssoc) {
if (!CPed::IsPlayer() || ((CPlayerPed*)this)->field_1380)
- CPed::ClearAttack();
+ ClearAttack();
return;
}
@@ -686,12 +706,13 @@ CPed::Attack(void)
lastReloadWasInFuture = true;
if (!weaponAnimAssoc) {
- if (ourWeapon->m_bThrow) {
+ weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ourWeapon->m_Anim2ToPlay);
+ delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire;
+
+ // Long throw granade, molotov
+ if (!weaponAnimAssoc && ourWeapon->m_bThrow) {
weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_WEAPON_THROWU);
delayBetweenAnimAndFire = 0.2f;
- } else {
- weaponAnimAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ourWeapon->m_Anim2ToPlay);
- delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire;
}
}
if (weaponAnimAssoc) {
@@ -739,15 +760,15 @@ CPed::Attack(void)
// If reloading just began, start the animation
if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS && !reloadAnimAssoc) {
CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, reloadAnim, 8.0f);
- CPed::ClearLookFlag();
- CPed::ClearAimFlag();
+ ClearLookFlag();
+ ClearAimFlag();
m_ped_flagA4 = false;
- m_ped_flagA8 = false;
+ bIsPointingGunAt = false;
m_lastHitTime = CTimer::GetTimeInMilliseconds();
return;
}
} else {
- if (weaponAnimAssoc->animId <= ANIM_WEAPON_BAT_V) {
+ if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) {
DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f);
} else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) {
DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f);
@@ -814,24 +835,22 @@ CPed::Attack(void)
CAnimManager::BlendAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f);
}
} else {
- CPed::ClearAimFlag();
+ ClearAimFlag();
// Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading)
- if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep < ourWeapon->m_fAnimLoopEnd) {
- if (ourWeaponType < WEAPONTYPE_SNIPERRIFLE) {
- switch (ourWeaponType) {
- case WEAPONTYPE_UZI:
- DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f);
- break;
- case WEAPONTYPE_AK47:
- DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f);
- break;
- case WEAPONTYPE_M16:
- DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f);
- break;
- default:
- break;
- }
+ if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) {
+ switch (ourWeaponType) {
+ case WEAPONTYPE_UZI:
+ DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f);
+ break;
+ case WEAPONTYPE_AK47:
+ DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f);
+ break;
+ case WEAPONTYPE_M16:
+ DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f);
+ break;
+ default:
+ break;
}
}
@@ -885,7 +904,7 @@ CPed::RemoveWeaponModel(int modelId)
void
CPed::SetCurrentWeapon(eWeaponType weaponType)
{
- CWeaponInfo* weaponInfo;
+ CWeaponInfo *weaponInfo;
if (HasWeapon(weaponType)) {
weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
@@ -909,9 +928,7 @@ CPed::SelectGunIfArmed(void)
if (m_weapons[i].m_nAmmoTotal > 0) {
weaponType = m_weapons[i].m_eWeaponType;
- // Original condition was ridiculous
- // if (weaponType == WEAPONTYPE_COLT45 || weaponType < WEAPONTYPE_M16 || weaponType < WEAPONTYPE_FLAMETHROWER || weaponType == WEAPONTYPE_FLAMETHROWER)
- if (weaponType < WEAPONTYPE_MOLOTOV) {
+ if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) {
SetCurrentWeapon(weaponType);
return true;
}
@@ -960,7 +977,7 @@ CPed::ClearPointGunAt(void)
ClearLookFlag();
ClearAimFlag();
- m_ped_flagA8 = false;
+ bIsPointingGunAt = false;
if (m_nPedState == PED_AIM_GUN) {
RestorePreviousState();
weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
@@ -975,6 +992,477 @@ CPed::ClearPointGunAt(void)
}
}
+void
+CPed::BeingDraggedFromCar(void)
+{
+ CAnimBlendAssociation *animAssoc;
+ AnimationId enterAnim;
+ bool dontRunAnim = false;
+ PedLineUpPhase lineUpType;
+
+ if (!m_pVehicleAnim) {
+ CAnimManager::BlendAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE, 100.0f);
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SIT);
+ if (!animAssoc) {
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_LSIT);
+ if (!animAssoc) {
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITP);
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_CAR_SITPLO);
+ }
+ }
+ if (animAssoc)
+ animAssoc->blendDelta = -1000.0f;
+
+ if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) {
+ if (m_ped_flagF10) {
+ enterAnim = ANIM_CAR_QJACKED;
+ } else if (m_pMyVehicle->bIsLow) {
+ enterAnim = ANIM_CAR_LJACKED_LHS;
+ } else {
+ enterAnim = ANIM_CAR_JACKED_LHS;
+ }
+ } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) {
+ if (m_pMyVehicle->bIsLow)
+ enterAnim = ANIM_CAR_LJACKED_RHS;
+ else
+ enterAnim = ANIM_CAR_JACKED_RHS;
+ } else
+ dontRunAnim = true;
+
+
+ if (!dontRunAnim)
+ m_pVehicleAnim = CAnimManager::AddAnimation((RpClump*) m_rwObject, ASSOCGRP_STD, enterAnim);
+
+ m_pVehicleAnim->SetFinishCallback(PedSetDraggedOutCarCB, this);
+ lineUpType = LINE_UP_TO_CAR_START;
+ } else if (m_pVehicleAnim->currentTime <= 1.4f) {
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ lineUpType = LINE_UP_TO_CAR_START;
+ } else {
+ lineUpType = LINE_UP_TO_CAR_2;
+ }
+
+ LineUpPedWithCar(lineUpType);
+}
+
+void
+CPed::RestartNonPartialAnims(void)
+{
+ CAnimBlendAssociation* assoc;
+
+ for (assoc = RpAnimBlendClumpGetFirstAssociation((RpClump*)m_rwObject); !assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) {
+ if (!assoc->IsPartial())
+ assoc->flags |= ASSOC_RUNNING;
+ }
+}
+
+void
+CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg)
+{
+ CAnimBlendAssociation *quickJackedAssoc;
+ CVehicle *vehicle;
+ CPed *ped = (CPed*)arg;
+ eWeaponType weaponType = ped->GetWeapon()->m_eWeaponType;
+
+ quickJackedAssoc = RpAnimBlendClumpGetAssociation((RpClump*) ped->m_rwObject, ANIM_CAR_QJACKED);
+ if (ped->m_nPedState != PED_ARRESTED) {
+ ped->m_nLastPedState = PED_NONE;
+ if (dragAssoc)
+ dragAssoc->blendDelta = -1000.0;
+ }
+ ped->RestartNonPartialAnims();
+ ped->m_pVehicleAnim = nil;
+ ped->m_pSeekTarget = nil;
+ vehicle = ped->m_pMyVehicle;
+
+ switch (ped->m_vehEnterType) {
+ case VEHICLE_ENTER_FRONT_RIGHT:
+ vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_FR;
+ break;
+ case VEHICLE_ENTER_REAR_RIGHT:
+ vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_RR;
+ break;
+ case VEHICLE_ENTER_FRONT_LEFT:
+ vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_FL;
+ break;
+ case VEHICLE_ENTER_REAR_LEFT:
+ vehicle->m_nGettingOutFlags &= ~GETTING_IN_OUT_RL;
+ break;
+ }
+
+ if (vehicle->pDriver == ped) {
+ vehicle->RemoveDriver();
+ if (vehicle->m_nDoorLock == CARLOCK_COP_CAR)
+ vehicle->m_nDoorLock = CARLOCK_UNLOCKED;
+
+ if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle())
+ vehicle->ChangeLawEnforcerState(false);
+ } else {
+ for (int i = 0; i < vehicle->m_nNumMaxPassengers; i++) {
+ if (vehicle->pPassengers[i] == ped) {
+ vehicle->pPassengers[i] = nil;
+ vehicle->m_nNumPassengers--;
+ }
+ }
+ }
+
+ ped->bInVehicle = false;
+ if (ped->IsPlayer())
+ AudioManager.PlayerJustLeftCar();
+
+ if (quickJackedAssoc) {
+ dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped);
+ } else {
+ dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped);
+ if (ped->CanSetPedState())
+ CAnimManager::BlendAnimation((RpClump*) ped->m_rwObject, ASSOCGRP_STD, ANIM_GETUP1, 1000.0f);
+ }
+
+ // Only uzi can be used on cars, so previous weapon was stored
+ if (ped->IsPlayer() && weaponType == WEAPONTYPE_UZI) {
+ if (ped->m_storedWeapon != NO_STORED_WEAPON) {
+ ped->SetCurrentWeapon(ped->m_storedWeapon);
+ ped->m_storedWeapon = NO_STORED_WEAPON;
+ }
+ } else {
+ ped->AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId);
+ }
+ ped->m_nStoredActionState = 0;
+ ped->m_ped_flagI4 = false;
+}
+
+void
+CPed::GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult)
+{
+ CVehicleModelInfo *vehModel;
+ CVector vehDoorPos;
+ CVector vehDoorOffset;
+ float seatOffset;
+
+ vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(veh->m_modelIndex);
+ if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) {
+ seatOffset = 0.0f;
+ vehDoorOffset = offsetToOpenVanDoor;
+ } else {
+ seatOffset = veh->m_handling->fSeatOffsetDistance * seatPosMult;
+ if (veh->bIsLow) {
+ vehDoorOffset = offsetToOpenLowCarDoor;
+ } else {
+ vehDoorOffset = offsetToOpenRegularCarDoor;
+ }
+ }
+
+ switch (enterType) {
+ case VEHICLE_ENTER_FRONT_RIGHT:
+ if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER];
+ else
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS];
+
+ vehDoorPos.x += seatOffset;
+ vehDoorOffset.x = -vehDoorOffset.x;
+ break;
+
+ case VEHICLE_ENTER_REAR_RIGHT:
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS];
+ vehDoorPos.x += seatOffset;
+ vehDoorOffset.x = -vehDoorOffset.x;
+ break;
+
+ case VEHICLE_ENTER_FRONT_LEFT:
+ if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER];
+ else
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS];
+
+ vehDoorPos.x = -(vehDoorPos.x + seatOffset);
+ break;
+
+ case VEHICLE_ENTER_REAR_LEFT:
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_REAR_SEATS];
+ vehDoorPos.x = -(vehDoorPos.x + seatOffset);
+ break;
+
+ default:
+ if (vehModel->m_vehicleType == VEHICLE_TYPE_BOAT)
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_BOAT_RUDDER];
+ else
+ vehDoorPos = vehModel->m_positions[VEHICLE_DUMMY_FRONT_SEATS];
+
+ vehDoorOffset = CVector(0.0f, 0.0f, 0.0f);
+ }
+ *output = vehDoorPos - vehDoorOffset;
+}
+
+// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it.
+void
+CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType)
+{
+ CVector localPos;
+ CVector vehDoorPos;
+
+ GetLocalPositionToOpenCarDoor(&localPos, veh, enterType, 1.0f);
+ vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition();
+
+/*
+ // Not used.
+ CVector localVehDoorOffset;
+
+ if (veh->bIsVan && (enterType == VEHICLE_ENTER_REAR_LEFT || enterType == VEHICLE_ENTER_REAR_RIGHT)) {
+ localVehDoorOffset = offsetToOpenVanDoor;
+ } else {
+ if (veh->bIsLow) {
+ localVehDoorOffset = offsetToOpenLowCarDoor;
+ } else {
+ localVehDoorOffset = offsetToOpenRegularCarDoor;
+ }
+ }
+
+ vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition();
+*/
+ *output = vehDoorPos;
+}
+
+void
+CPed::GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset)
+{
+ CVector doorPos;
+ CMatrix vehMat(veh->GetMatrix());
+
+ GetLocalPositionToOpenCarDoor(output, veh, enterType, offset);
+ doorPos = Multiply3x3(vehMat, *output);
+
+ *output = *veh->GetPosition() + doorPos;
+}
+
+void
+CPed::LineUpPedWithCar(PedLineUpPhase phase)
+{
+ bool vehIsUpsideDown = false;
+ int vehAnim;
+ float seatPosMult = 0.0f;
+ float currentZ;
+ float adjustedTimeStep;
+
+ if (CReplay::IsPlayingBack())
+ return;
+
+ if (!m_ped_flagC8 && phase != LINE_UP_TO_CAR_2) {
+ if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SIT)) {
+ SetPedPositionInCar();
+ return;
+ }
+ if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_LSIT)) {
+ SetPedPositionInCar();
+ return;
+ }
+ if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITP)) {
+ SetPedPositionInCar();
+ return;
+ }
+ if (RpAnimBlendClumpGetAssociation((RpClump*)m_rwObject, ANIM_CAR_SITPLO)) {
+ SetPedPositionInCar();
+ return;
+ }
+ m_ped_flagC8 = 1;
+ }
+ if (phase == LINE_UP_TO_CAR_START) {
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ }
+ CVehicle *veh = m_pMyVehicle;
+
+ // Not quite right, IsUpsideDown func. checks for <= -0.9f.
+ // Since that function is also used in this file, doesn't this variable indicate upsidedownness?!
+ if (veh->GetUp().z <= -0.8f)
+ vehIsUpsideDown = true;
+
+ if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) {
+ if (vehIsUpsideDown) {
+ m_fRotationDest = -PI + atan2(-veh->GetForward().x, veh->GetForward().y);
+ } else if (veh->bIsBus) {
+ m_fRotationDest = 0.5 * PI + atan2(-veh->GetForward().x, veh->GetForward().y);
+ } else {
+ m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y);
+ }
+ } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) {
+ if (vehIsUpsideDown) {
+ m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y);
+ } else if (veh->bIsBus) {
+ m_fRotationDest = -0.5 * PI + atan2(-veh->GetForward().x, veh->GetForward().y);
+ } else {
+ m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y);
+ }
+ }
+
+ if (!bInVehicle)
+ seatPosMult = 1.0f;
+
+ if (m_pVehicleAnim) {
+ vehAnim = m_pVehicleAnim->animId;
+
+ switch (vehAnim) {
+ case ANIM_CAR_JACKED_RHS:
+ case ANIM_CAR_LJACKED_RHS:
+ case ANIM_CAR_JACKED_LHS:
+ case ANIM_CAR_LJACKED_LHS:
+ case ANIM_CAR_QJACKED:
+ case ANIM_CAR_GETOUT_LHS:
+ case ANIM_CAR_GETOUT_LOW_LHS:
+ case ANIM_CAR_GETOUT_RHS:
+ case ANIM_CAR_GETOUT_LOW_RHS:
+ case ANIM_CAR_CRAWLOUT_RHS:
+ case ANIM_CAR_CRAWLOUT_RHS2:
+ case ANIM_VAN_GETIN_L:
+ case ANIM_VAN_GETOUT_L:
+ case ANIM_VAN_GETIN:
+ case ANIM_VAN_GETOUT:
+ seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength;
+ break;
+ case ANIM_CAR_QJACK:
+ case ANIM_CAR_GETIN_LHS:
+ case ANIM_CAR_GETIN_LOW_LHS:
+ case ANIM_CAR_GETIN_RHS:
+ case ANIM_CAR_GETIN_LOW_RHS:
+ case ANIM_DRIVE_BOAT:
+ seatPosMult = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength;
+ break;
+ case ANIM_CAR_CLOSEDOOR_LHS:
+ case ANIM_CAR_CLOSEDOOR_LOW_LHS:
+ case ANIM_CAR_CLOSEDOOR_RHS:
+ case ANIM_CAR_CLOSEDOOR_LOW_RHS:
+ case ANIM_CAR_SHUFFLE_RHS:
+ case ANIM_CAR_LSHUFFLE_RHS:
+ seatPosMult = 0.0f;
+ break;
+ case ANIM_CAR_CLOSE_LHS:
+ case ANIM_CAR_CLOSE_RHS:
+ case ANIM_COACH_OPEN_L:
+ case ANIM_COACH_OPEN_R:
+ case ANIM_COACH_IN_L:
+ case ANIM_COACH_IN_R:
+ case ANIM_COACH_OUT_L:
+ seatPosMult = 1.0f;
+ break;
+ default:
+ break;
+ }
+ }
+
+ CVector neededPos;
+
+ if (phase == LINE_UP_TO_CAR_2) {
+ neededPos = *GetPosition();
+ } else {
+ GetPositionToOpenCarDoor(&neededPos, veh, m_vehEnterType, seatPosMult);
+ }
+
+ CVector autoZPos = neededPos;
+
+ if (veh->bIsInWater) {
+ if (veh->m_vehType == VEHICLE_TYPE_BOAT && veh->IsUpsideDown())
+ autoZPos.z += 1.0f;
+ } else {
+ CPedPlacement::FindZCoorForPed(&autoZPos);
+ }
+
+ if (phase == LINE_UP_TO_CAR_END || phase == LINE_UP_TO_CAR_2) {
+ neededPos.z = GetPosition().z;
+
+ // Getting out
+ if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) {
+ float pedZSpeedOnExit = m_vecMoveSpeed.z - 0.008f * CTimer::GetTimeStep();
+
+ // If we're not in ground at next step, apply animation
+ if (neededPos.z + pedZSpeedOnExit > autoZPos.z) {
+ m_vecMoveSpeed.z = pedZSpeedOnExit;
+ ApplyMoveSpeed();
+ // Removing below line breaks the animation
+ neededPos.z = GetPosition().z;
+ } else {
+ neededPos.z = autoZPos.z;
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ }
+ }
+ }
+
+ if (autoZPos.z > neededPos.z) {
+ currentZ = GetPosition().z;
+ if (m_pVehicleAnim && vehAnim != ANIM_VAN_GETIN_L && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE && vehAnim != ANIM_VAN_GETIN) {
+ neededPos.z = autoZPos.z;
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ } else if (neededPos.z <= currentZ && m_pVehicleAnim && vehAnim != ANIM_VAN_CLOSE_L && vehAnim != ANIM_VAN_CLOSE) {
+ adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f);
+
+ // Smoothly change ped position
+ neededPos.z = currentZ - (currentZ - neededPos.z) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep);
+ }
+ } else {
+ // We may need to raise up the ped
+ if (phase == LINE_UP_TO_CAR_START) {
+ currentZ = GetPosition().z;
+
+ if (neededPos.z > currentZ) {
+
+ if (m_pVehicleAnim &&
+ (vehAnim == ANIM_CAR_GETIN_RHS || vehAnim == ANIM_CAR_GETIN_LOW_RHS || vehAnim == ANIM_CAR_GETIN_LHS || vehAnim == ANIM_CAR_GETIN_LOW_LHS
+ || vehAnim == ANIM_CAR_QJACK || vehAnim == ANIM_VAN_GETIN_L || vehAnim == ANIM_VAN_GETIN)) {
+ adjustedTimeStep = min(m_pVehicleAnim->timeStep, 0.1f);
+
+ // Smoothly change ped position
+ neededPos.z = (neededPos.z - currentZ) / (m_pVehicleAnim->GetTimeLeft() / adjustedTimeStep) + currentZ;
+ } else if (m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK) {
+ neededPos.z = max(currentZ, autoZPos.z);
+ }
+ }
+ }
+ }
+
+ // I hope
+ bool stillGettingInOut = false;
+ if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer)
+ stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || m_ped_flagG10;
+
+ if (!stillGettingInOut) {
+ m_fRotationCur = m_fRotationDest;
+ } else {
+ float limitedAngle = CGeneral::LimitRadianAngle(m_fRotationDest);
+ float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f;
+
+ m_vecOffsetSeek.z = 0.0;
+ if (timeUntilStateChange <= 0.0f) {
+ m_vecOffsetSeek.x = 0.0;
+ m_vecOffsetSeek.y = 0.0;
+ } else {
+ neededPos -= timeUntilStateChange * m_vecOffsetSeek;
+ }
+
+ if (limitedAngle >= PI + m_fRotationCur) {
+ limitedAngle -= 2 * PI;
+ } else if (limitedAngle <= m_fRotationCur - PI) {
+ limitedAngle += 2 * PI;
+ }
+ m_fRotationCur -= (m_fRotationCur - limitedAngle) * (1.0f - timeUntilStateChange);
+ }
+
+ if (seatPosMult > 0.2f || vehIsUpsideDown) {
+ GetPosition() = neededPos;
+
+ GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur);
+
+ // It will be all 0 after rotate.
+ GetPosition() = neededPos;
+ } else {
+ CVector output;
+ CMatrix vehDoorMat(veh->GetMatrix());
+
+ GetLocalPositionToOpenCarDoor(&output, veh, m_vehEnterType, 0.0f);
+ *vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, output);
+ GetMatrix() = vehDoorMat;
+ }
+
+}
+
WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); }
WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); }
WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); }
@@ -989,7 +1477,6 @@ WRAPPER void CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *assoc, void *arg) {
WRAPPER void CPed::SetInCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CF220); }
WRAPPER void CPed::PedSetOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8F0); }
WRAPPER void CPed::PedAnimAlignCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE130); }
-WRAPPER void CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CF000); }
WRAPPER void CPed::PedAnimStepOutCarCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DF5C0); }
WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); }
WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); }
@@ -999,8 +1486,6 @@ WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJM
WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); }
WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6620); }
WRAPPER void CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6550); }
-WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E2480); }
-WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E2920); }
STARTPATCHES
InjectHook(0x4CF8F0, &CPed::AddWeaponModel, PATCH_JUMP);
@@ -1024,4 +1509,11 @@ STARTPATCHES
InjectHook(0x4E4A10, &CPed::Duck, PATCH_JUMP);
InjectHook(0x4E4A30, &CPed::ClearDuck, PATCH_JUMP);
InjectHook(0x4E6180, &CPed::ClearPointGunAt, PATCH_JUMP);
+ InjectHook(0x4E07D0, &CPed::BeingDraggedFromCar, PATCH_JUMP);
+ InjectHook(0x4CF000, &CPed::PedSetDraggedOutCarCB, PATCH_JUMP);
+ InjectHook(0x4C5D80, &CPed::RestartNonPartialAnims, PATCH_JUMP);
+ InjectHook(0x4E4730, &CPed::GetLocalPositionToOpenCarDoor, PATCH_JUMP);
+ InjectHook(0x4E4660, (void (*)(CVector*, CVehicle*, uint32, float)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP);
+ InjectHook(0x4E1A30, (void (*)(CVector*, CVehicle*, uint32)) CPed::GetPositionToOpenCarDoor, PATCH_JUMP);
+ InjectHook(0x4DF940, &CPed::LineUpPedWithCar, PATCH_JUMP);
ENDPATCHES
diff --git a/src/entities/Ped.h b/src/entities/Ped.h
index 43131533..34c7a485 100644
--- a/src/entities/Ped.h
+++ b/src/entities/Ped.h
@@ -12,6 +12,19 @@
struct CPathNode;
+enum {
+ VEHICLE_ENTER_FRONT_RIGHT = 11,
+ VEHICLE_ENTER_REAR_RIGHT = 12,
+ VEHICLE_ENTER_FRONT_LEFT = 15,
+ VEHICLE_ENTER_REAR_LEFT = 16,
+};
+
+enum PedLineUpPhase {
+ LINE_UP_TO_CAR_START,
+ LINE_UP_TO_CAR_END,
+ LINE_UP_TO_CAR_2
+};
+
enum PedOnGroundState {
NO_PED,
PED_BELOW_PLAYER,
@@ -102,7 +115,7 @@ public:
uint8 m_ped_flagA1 : 1;
uint8 m_ped_flagA2 : 1;
uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime)
- uint8 m_ped_flagA8 : 1;
+ uint8 bIsPointingGunAt : 1;
uint8 bIsLooking : 1;
uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA
uint8 bIsRestoringLook : 1;
@@ -177,15 +190,15 @@ public:
int32 m_pEventEntity;
float m_fAngleToEvent;
AnimBlendFrameData *m_pFrames[PED_NODE_MAX];
- int32 m_animGroup;
- int32 m_pVehicleAnim;
+ AssocGroupId m_animGroup;
+ CAnimBlendAssociation *m_pVehicleAnim;
CVector2D m_vecAnimMoveDelta;
CVector m_vecOffsetSeek;
CPedIK m_pedIK;
uint8 stuff1[8];
uint32 m_nPedStateTimer;
PedState m_nPedState;
- int32 m_nLastPedState;
+ PedState m_nLastPedState;
int32 m_nMoveState;
int32 m_nStoredActionState;
int32 m_nPrevActionState;
@@ -207,7 +220,9 @@ public:
uint8 stuff2[20];
float m_fRotationCur;
float m_fRotationDest;
- uint8 stuff13[6];
+ uint32 m_headingRate;
+ uint16 m_vehEnterType;
+ uint16 m_walkAroundType;
CEntity *m_pCurrentPhysSurface;
CVector m_vecOffsetFromPhysSurface;
CEntity *m_pCurSurface;
@@ -222,7 +237,7 @@ public:
CEntity *m_pCollidingEntity;
uint8 stuff6[12];
CWeapon m_weapons[NUM_PED_WEAPONTYPES];
- int32 stuff7;
+ eWeaponType m_storedWeapon;
uint8 m_currentWeapon; // eWeaponType
uint8 m_maxWeaponTypeAllowed; // eWeaponType
uint8 stuff[2];
@@ -253,6 +268,7 @@ public:
bool IsPlayer(void);
bool UseGroundColModel(void);
+ bool CanSetPedState(void);
void AddWeaponModel(int id);
void AimGun(void);
void KillPedWithCar(CVehicle *veh, float impulse);
@@ -278,6 +294,13 @@ public:
void Duck(void);
void ClearDuck(void);
void ClearPointGunAt(void);
+ void BeingDraggedFromCar(void);
+ void RestartNonPartialAnims(void);
+ void LineUpPedWithCar(PedLineUpPhase phase);
+ void SetPedPositionInCar(void);
+ static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset);
+ static void GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult);
+ static void GetPositionToOpenCarDoor(CVector* output, CVehicle* veh, uint32 enterType);
static RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data);
static RwFrame *RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data);
static void PedGetupCB(CAnimBlendAssociation *assoc, void *arg);
@@ -311,6 +334,9 @@ public:
CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; }
RwFrame *GetNodeFrame(int nodeId) { return m_pFrames[nodeId]->frame; }
+ static CVector &offsetToOpenRegularCarDoor;
+ static CVector &offsetToOpenLowCarDoor;
+ static CVector &offsetToOpenVanDoor;
static bool &bNastyLimbsCheat;
static bool &bPedCheat2;
static bool &bPedCheat3;
diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp
index adc53525..b35b2d11 100644
--- a/src/entities/Physical.cpp
+++ b/src/entities/Physical.cpp
@@ -1504,7 +1504,7 @@ CPhysical::ProcessCollisionSectorList(CPtrList *lists)
else if(A->GetUp().z > 0.3f)
adhesion = 0.0f;
else
- adhesion *= max(5.0f, 0.03f*impulseA + 1.0f);
+ adhesion *= min(5.0f, 0.03f*impulseA + 1.0f);
}
if(A->ApplyFriction(adhesion, aColPoints[i]))
diff --git a/src/entities/Vehicle.cpp b/src/entities/Vehicle.cpp
index bac05f7b..ced504a3 100644
--- a/src/entities/Vehicle.cpp
+++ b/src/entities/Vehicle.cpp
@@ -2,6 +2,8 @@
#include "patcher.h"
#include "Vehicle.h"
#include "Pools.h"
+#include "CarCtrl.h"
+#include "ModelIndices.h"
bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78;
bool &CVehicle::bAllDodosCheat = *(bool *)0x95CD75;
@@ -11,3 +13,53 @@ bool &CVehicle::bCheat5 = *(bool *)0x95CD64;
void *CVehicle::operator new(size_t sz) { return CPools::GetVehiclePool()->New(); }
void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); }
+
+bool
+CVehicle::IsLawEnforcementVehicle(void)
+{
+ switch (m_modelIndex) {
+ case MI_FBICAR:
+ case MI_POLICE:
+ case MI_ENFORCER:
+ case MI_PREDATOR:
+ case MI_RHINO:
+ case MI_BARRACKS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void
+CVehicle::ChangeLawEnforcerState(bool enable)
+{
+ if (enable) {
+ if (!bIsLawEnforcer) {
+ bIsLawEnforcer = true;
+ CCarCtrl::NumLawEnforcerCars++;
+ }
+ } else {
+ if (bIsLawEnforcer) {
+ bIsLawEnforcer = false;
+ CCarCtrl::NumLawEnforcerCars--;
+ }
+ }
+}
+
+void
+CVehicle::RemoveDriver(void)
+{
+ m_status = STATUS_ABANDONED;
+ pDriver = nil;
+}
+
+bool
+CVehicle::IsUpsideDown(void)
+{
+ return GetUp().z <= -0.9f;
+}
+
+STARTPATCHES
+ InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP);
+ InjectHook(0x5520A0, &CVehicle::RemoveDriver, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/entities/Vehicle.h b/src/entities/Vehicle.h
index fea15d35..f11e9e97 100644
--- a/src/entities/Vehicle.h
+++ b/src/entities/Vehicle.h
@@ -3,26 +3,53 @@
#include "Physical.h"
class CPed;
+class CFire;
+struct tHandlingData;
+
+enum {
+ GETTING_IN_OUT_FL = 1,
+ GETTING_IN_OUT_RL = 2,
+ GETTING_IN_OUT_FR = 4,
+ GETTING_IN_OUT_RR = 8
+};
+
+enum eCarLock : uint8 {
+ CARLOCK_NOT_USED,
+ CARLOCK_UNLOCKED,
+ CARLOCK_LOCKED,
+ CARLOCK_LOCKOUT_PLAYER_ONLY,
+ CARLOCK_LOCKED_PLAYER_INSIDE,
+ CARLOCK_COP_CAR,
+ CARLOCK_FORCE_SHUT_DOORS,
+ CARLOCK_SKIP_SHUT_DOORS
+};
class CVehicle : public CPhysical
{
public:
// 0x128
- uint8 stuff1[116];
+ tHandlingData *m_handling;
+ uint8 stuff1[112];
uint8 m_currentColour1;
uint8 m_currentColour2;
- uint8 m_extra1;
- uint8 m_extra2;
- int16 m_nAlarmState;
+ uint8 m_anExtras[2];
+ int16 m_nAlarmState; // m_nWantedStarsOnEnter on DK22
+ int16 m_nMissionValue;
CPed *pDriver;
CPed *pPassengers[8];
- uint8 stuff2[24];
+ uint8 m_nNumPassengers;
+ int8 m_nNumGettingIn;
+ int8 m_nGettingInFlags;
+ int8 m_nGettingOutFlags;
+ uint8 m_nNumMaxPassengers;
+ char field_1CD[19];
CEntity *m_pCurSurface;
- void* m_pFire;
- float m_fWheelState;
- float m_fAcceleration;
- uint8 stuff4[5];
- uint8 m_veh_flagA1 : 1;
+ CFire *m_pCarFire;
+ float m_fSteerAngle;
+ float m_fGasPedal;
+ float m_fBreakPedal;
+ uint8 m_nCreatedBy; // eVehicleCreatedBy
+ uint8 bIsLawEnforcer : 1;
uint8 m_veh_flagA2 : 1;
uint8 m_veh_flagA4 : 1;
uint8 m_veh_flagA8 : 1;
@@ -30,10 +57,10 @@ public:
uint8 m_veh_flagA20 : 1;
uint8 m_veh_flagA40 : 1;
uint8 m_veh_flagA80 : 1;
- uint8 m_veh_flagB1 : 1;
- uint8 m_veh_flagB2 : 1;
- uint8 m_veh_flagB4 : 1;
- uint8 m_veh_flagB8 : 1;
+ uint8 bIsVan : 1;
+ uint8 bIsBus : 1;
+ uint8 bIsBig : 1;
+ uint8 bIsLow : 1;
uint8 m_veh_flagB10 : 1;
uint8 m_veh_flagB20 : 1;
uint8 m_veh_flagB40 : 1;
@@ -54,10 +81,34 @@ public:
uint8 m_veh_flagD20 : 1;
uint8 m_veh_flagD40 : 1;
uint8 m_veh_flagD80 : 1;
- uint8 stuff5[7];
- float m_fHealth;
- uint8 stuff6[128];
- int32 m_vehType;
+ int8 field_1F9;
+ uint8 m_nAmmoInClip[1]; // Used to make the guns on boat do a reload (20 by default)
+ int8 field_1FB;
+ int8 field_1FC[4];
+ float m_fHealth; // 1000.0f = full health. 0 -> explode
+ uint8 m_nCurrentGear;
+ int8 field_205[3];
+ int field_208;
+ uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats)
+ uint32 m_nTimeOfDeath;
+ int16 field_214;
+ int16 m_nBombTimer; // goes down with each frame
+ CPed *m_pWhoDetonatedMe;
+ float field_21C;
+ float field_220;
+ eCarLock m_nDoorLock;
+ int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage
+ int8 m_nRadioStation;
+ int8 field_22A;
+ int8 field_22B;
+ uint8 m_nCarHornTimer;
+ int8 field_22D;
+ uint8 m_nSirenOrAlarm;
+ int8 field_22F;
+ CStoredCollPoly m_frontCollPoly; // poly which is under front part of car
+ CStoredCollPoly m_rearCollPoly; // poly which is under rear part of car
+ float m_fSteerRatio;
+ eVehicleType m_vehType;
static void *operator new(size_t);
static void operator delete(void*, size_t);
@@ -67,6 +118,10 @@ public:
bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; }
bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; }
bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; }
+ bool IsLawEnforcementVehicle(void);
+ void ChangeLawEnforcerState(bool enable);
+ void RemoveDriver(void);
+ bool IsUpsideDown(void);
static bool &bWheelsOnlyCheat;
static bool &bAllDodosCheat;
@@ -74,5 +129,7 @@ public:
static bool &bCheat4;
static bool &bCheat5;
};
+
static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error");
static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error");
+static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error");
diff --git a/src/main.cpp b/src/main.cpp
index f9ede02d..0dadc131 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -85,6 +85,7 @@ extern void (*DebugMenuProcess)(void);
extern void (*DebugMenuRender)(void);
void DebugMenuInit(void);
+void PrintGameVersion();
RwRGBA gColourTop;
@@ -154,6 +155,7 @@ Idle(void *arg)
}
RenderMenus();
+ PrintGameVersion();
DoFade();
Render2dStuffAfterFade();
CCredits::Render();
@@ -186,6 +188,7 @@ FrontendIdle(void)
DefinedState();
RenderMenus();
+ PrintGameVersion();
DoFade();
Render2dStuffAfterFade();
CFont::DrawFonts();
@@ -772,6 +775,25 @@ AppEventHandler(RsEvent event, void *param)
}
}
+void PrintGameVersion()
+{
+ CFont::SetPropOn();
+ CFont::SetBackgroundOff();
+ CFont::SetScale(SCREEN_SCALE_X(0.7f), SCREEN_SCALE_Y(0.5f));
+ CFont::SetCentreOff();
+ CFont::SetRightJustifyOff();
+ CFont::SetBackGroundOnlyTextOff();
+ CFont::SetFontStyle(FONT_BANK);
+ CFont::SetWrapx(SCREEN_WIDTH);
+ CFont::SetDropShadowPosition(0);
+ CFont::SetDropColor(CRGBA(0, 0, 0, 255));
+ CFont::SetColor(CRGBA(235, 170, 50, 255));
+
+ strcpy(gString, "RE3");
+ AsciiToUnicode(gString, gUString);
+ CFont::PrintString(SCREEN_SCALE_X(10.5f), SCREEN_SCALE_Y(8.0f), gUString);
+}
+
STARTPATCHES
InjectHook(0x48E480, Idle, PATCH_JUMP);
InjectHook(0x48E700, FrontendIdle, PATCH_JUMP);
diff --git a/src/math/Matrix.h b/src/math/Matrix.h
index 2ee3863f..e2e5394e 100644
--- a/src/math/Matrix.h
+++ b/src/math/Matrix.h
@@ -145,6 +145,30 @@ public:
m_matrix.pos.y = 0.0f;
m_matrix.pos.z = 0.0f;
}
+ void SetRotate(float xAngle, float yAngle, float zAngle) {
+ float cX = cos(xAngle);
+ float sX = sin(xAngle);
+ float cY = cos(yAngle);
+ float sY = sin(yAngle);
+ float cZ = cos(zAngle);
+ float sZ = sin(zAngle);
+
+ m_matrix.right.x = cZ * cY - (sZ * sX) * sY;
+ m_matrix.right.y = (cZ * sX) * sY + sZ * cY;
+ m_matrix.right.z = -cX * sY;
+
+ m_matrix.up.x = -sZ * cX;
+ m_matrix.up.y = cZ * cX;
+ m_matrix.up.z = sX;
+
+ m_matrix.at.x = (sZ * sX) * cY + cZ * sY;
+ m_matrix.at.y = sZ * sY - (cZ * sX) * cY;
+ m_matrix.at.z = cX * cY;
+
+ m_matrix.pos.x = 0.0f;
+ m_matrix.pos.y = 0.0f;
+ m_matrix.pos.z = 0.0f;
+ }
void Reorthogonalise(void){
CVector &r = *GetRight();
CVector &f = *GetForward();
diff --git a/src/math/Rect.h b/src/math/Rect.h
index d0824987..fd1bd05e 100644
--- a/src/math/Rect.h
+++ b/src/math/Rect.h
@@ -26,4 +26,20 @@ public:
if(v.y < top) top = v.y;
if(v.y > bottom) bottom = v.y;
}
+
+ void Translate(float x, float y){
+ left += x;
+ right += x;
+ bottom += y;
+ top += y;
+ }
+ void Grow(float r){
+ left -= r;
+ right += r;
+ top -= r;
+ bottom += r;
+ }
+
+ float GetWidth(void) { return right - left; }
+ float GetHeight(void) { return bottom - top; }
};
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index be091e9b..feafcd40 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -326,6 +326,8 @@ enum
MI_AIRTRAIN_VLO = 198,
MI_LOPOLYGUY,
+
+ NUM_DEFAULT_MODELS,
};
void InitModelIndices(void);
diff --git a/src/modelinfo/VehicleModelInfo.h b/src/modelinfo/VehicleModelInfo.h
index 8068d359..2e2f1be2 100644
--- a/src/modelinfo/VehicleModelInfo.h
+++ b/src/modelinfo/VehicleModelInfo.h
@@ -3,7 +3,6 @@
#include "ClumpModelInfo.h"
enum {
- NUM_VEHICLE_POSITIONS = 10,
NUM_FIRST_MATERIALS = 26,
NUM_SECOND_MATERIALS = 26,
NUM_VEHICLE_COLOURS = 8,
@@ -25,7 +24,7 @@ enum {
ATOMIC_FLAG_NOCULL = 0x800,
};
-enum {
+enum eVehicleType {
VEHICLE_TYPE_CAR,
VEHICLE_TYPE_BOAT,
VEHICLE_TYPE_TRAIN,
@@ -46,6 +45,13 @@ enum {
NUM_VEHICLE_CLASSES
};
+enum {
+ VEHICLE_DUMMY_BOAT_RUDDER = 0,
+ VEHICLE_DUMMY_FRONT_SEATS = 2,
+ VEHICLE_DUMMY_REAR_SEATS = 3,
+ NUM_VEHICLE_POSITIONS = 10
+};
+
class CVehicleModelInfo : public CClumpModelInfo
{
public:
diff --git a/src/render/Font.h b/src/render/Font.h
index 2e698533..11c0f8ec 100644
--- a/src/render/Font.h
+++ b/src/render/Font.h
@@ -33,6 +33,12 @@ enum {
FONT_HEADING,
};
+enum {
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT,
+};
+
class CFont
{
static CFontDetails &Details;
@@ -56,6 +62,7 @@ public:
static void DrawFonts(void);
static uint16 character_code(uint8 c);
+ static CFontDetails GetDetails() { return Details; }
static void SetScale(float x, float y) { Details.scaleX = x; Details.scaleY = y; }
static void SetSlantRefPoint(float x, float y) { Details.slantRefX = x; Details.slantRefY = y; }
static void SetSlant(float s) { Details.slant = s; }
@@ -86,6 +93,23 @@ public:
static void SetCentreOff(void) {
Details.centre = false;
}
+ static void SetAlignment(uint8 alignment) {
+ if (alignment == ALIGN_LEFT) {
+ CFont::Details.justify = true;
+ CFont::Details.centre = false;
+ CFont::Details.rightJustify = false;
+ }
+ else if (alignment == ALIGN_CENTER) {
+ CFont::Details.justify = false;
+ CFont::Details.centre = true;
+ CFont::Details.rightJustify = false;
+ }
+ else if (alignment == ALIGN_RIGHT) {
+ CFont::Details.justify = false;
+ CFont::Details.centre = false;
+ CFont::Details.rightJustify = true;
+ }
+ }
static void SetWrapx(float x) { Details.wrapX = x; }
static void SetCentreSize(float s) { Details.centreSize = s; }
static void SetBackgroundOn(void) { Details.background = true; }
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index 23a796e6..9243bc3a 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -53,9 +53,9 @@ wchar *CHud::m_PagerMessage = (wchar*)0x878840;
bool &CHud::m_Wants_To_Draw_Hud = *(bool*)0x95CD89;
bool &CHud::m_Wants_To_Draw_3dMarkers = *(bool*)0x95CD62;
wchar(*CHud::m_BigMessage)[128] = (wchar(*)[128])0x664CE0;
-float *CHud::BigMessageInUse = (float*)0x862140;
-float *CHud::BigMessageAlpha = (float*)0x862108;
-float *CHud::BigMessageX = (float*)0x773248;
+float CHud::BigMessageInUse[6];
+float CHud::BigMessageAlpha[6];
+float CHud::BigMessageX[6];
float &CHud::OddJob2OffTimer = *(float*)0x942FA0;
int8 &CHud::CounterOnLastFrame = *(int8*)0x95CD67;
@@ -231,8 +231,8 @@ void CHud::Draw()
CRect rect;
float fWidescreenOffset[2] = { 0.0f, 0.0f };
-
- if (CMenuManager::m_PrefsUseWideScreen) {
+
+ if (FrontEndMenuManager.m_PrefsUseWideScreen) {
fWidescreenOffset[0] = 0.0f;
fWidescreenOffset[1] = SCREEN_SCALE_Y(18.0f);
}
@@ -362,25 +362,32 @@ void CHud::Draw()
/*
DrawAmmo
*/
+ int16 AmmoAmount = CWeaponInfo::GetWeaponInfo(FindPlayerPed()->GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition;
int32 AmmoInClip = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoInClip;
int32 TotalAmmo = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_weapons[CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_currentWeapon].m_nAmmoTotal;
+ int32 Ammo, Clip;
- if (AmmoInClip <= 1 || AmmoInClip >= 1000) {
+ if (AmmoAmount <= 1 || AmmoAmount >= 1000)
sprintf(sTemp, "%d", TotalAmmo);
- }
else {
if (WeaponType == WEAPONTYPE_FLAMETHROWER) {
- int tot_min_clip_div_10 = (TotalAmmo - AmmoInClip) / 10;
- if (tot_min_clip_div_10 > 9999)
- tot_min_clip_div_10 = 9999;
+ Clip = AmmoInClip / 10;
- sprintf(sTemp, "%d-%d", tot_min_clip_div_10, AmmoInClip / 10);
+ if ((TotalAmmo - AmmoInClip) / 10 <= 9999)
+ Ammo = (TotalAmmo - AmmoInClip) / 10;
+ else
+ Ammo = 9999;
}
else {
- if (AmmoInClip > 9999)
- AmmoInClip = 9999;
- sprintf(sTemp, "%d-%d", (TotalAmmo - AmmoInClip), AmmoInClip);
+ Clip = AmmoInClip;
+
+ if (TotalAmmo - AmmoInClip > 9999)
+ Ammo = 9999;
+ else
+ Ammo = TotalAmmo - AmmoInClip;
}
+
+ sprintf(sTemp, "%d-%d", Ammo, Clip);
}
AsciiToUnicode(sTemp, sPrint);
@@ -580,7 +587,7 @@ void CHud::Draw()
CFont::SetPropOn();
CFont::SetBackgroundOff();
- if (CMenuManager::m_PrefsLanguage == 4)
+ if (FrontEndMenuManager.m_PrefsLanguage == 4)
CFont::SetScale(SCREEN_SCALE_X(1.2f * 0.8f), SCREEN_SCALE_Y(1.2f));
else
CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f));
@@ -676,7 +683,7 @@ void CHud::Draw()
CFont::SetPropOn();
CFont::SetBackgroundOff();
- if (CMenuManager::m_PrefsLanguage != 3 && CMenuManager::m_PrefsLanguage != 4)
+ if (FrontEndMenuManager.m_PrefsLanguage != 3 && FrontEndMenuManager.m_PrefsLanguage != 4)
CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f));
else
CFont::SetScale(SCREEN_SCALE_X(1.2f * 0.85f), SCREEN_SCALE_Y(1.2f));
@@ -856,7 +863,11 @@ void CHud::Draw()
*/
if (CHud::m_ItemToFlash == ITEM_RADAR && CTimer::GetFrameCounter() & 8 || CHud::m_ItemToFlash != ITEM_RADAR) {
CRadar::DrawMap();
- CHud::Sprites[HUD_RADARDISC].Draw(CRect(SCREEN_SCALE_X(16.0f), SCREEN_SCALE_FROM_BOTTOM(123.0f + 4.0f), SCREEN_SCALE_X(94.0f + 20.0f + 5.0f), SCREEN_SCALE_FROM_BOTTOM(-76.0f + 123.0f - 6.0f)), CRGBA(0, 0, 0, 255));
+ CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(RADAR_WIDTH), SCREEN_SCALE_Y(RADAR_HEIGHT));
+ // FIX: game doesn't scale RADAR_LEFT here
+ rect.Translate(SCREEN_SCALE_X(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT));
+ rect.Grow(4.0f);
+ CHud::Sprites[HUD_RADARDISC].Draw(rect, CRGBA(0, 0, 0, 255));
CRadar::DrawBlips();
}
}
@@ -972,7 +983,7 @@ void CHud::Draw()
DrawBigMessage
*/
// MissionCompleteFailedText
- if (CHud::m_BigMessage[0][0]) {
+ if (m_BigMessage[0][0]) {
if (BigMessageInUse[0] != 0.0f) {
CFont::SetJustifyOff();
CFont::SetBackgroundOff();
@@ -1247,7 +1258,7 @@ void CHud::DrawAfterFade()
CFont::SetJustifyOff();
CFont::SetBackgroundOff();
- if (CGame::frenchGame || CMenuManager::m_PrefsLanguage == 4)
+ if (CGame::frenchGame || FrontEndMenuManager.m_PrefsLanguage == 4)
CFont::SetScale(SCREEN_SCALE_X(0.884f), SCREEN_SCALE_Y(1.36f));
else
CFont::SetScale(SCREEN_SCALE_X(1.04f), SCREEN_SCALE_Y(1.6f));
diff --git a/src/render/Hud.h b/src/render/Hud.h
index 8f4b6fb6..260e5312 100644
--- a/src/render/Hud.h
+++ b/src/render/Hud.h
@@ -62,9 +62,9 @@ public:
static bool &m_Wants_To_Draw_Hud;
static bool &m_Wants_To_Draw_3dMarkers;
static wchar(*m_BigMessage)[128];
- static float *BigMessageInUse;
- static float *BigMessageAlpha;
- static float *BigMessageX;
+ static float BigMessageInUse[6];
+ static float BigMessageAlpha[6];
+ static float BigMessageX[6];
static float &OddJob2OffTimer;
static int8 &CounterOnLastFrame;
static float &OddJob2XOffset;
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
index a8abe1dd..814cac84 100644
--- a/src/skel/win/win.cpp
+++ b/src/skel/win/win.cpp
@@ -633,8 +633,10 @@ psInitialise(void)
C_PcSave::SetSaveDirectory(_psGetUserFilesFolder());
- InitialiseLanguage();
-
+#ifndef NASTY_GAME
+ InitialiseLanguage();
+#endif
+
FrontEndMenuManager.LoadSettings();
gGameState = GS_START_UP;
diff --git a/src/skel/win/win.h b/src/skel/win/win.h
index d3b0169f..371b9e44 100644
--- a/src/skel/win/win.h
+++ b/src/skel/win/win.h
@@ -78,6 +78,8 @@ RwBool _psSetVideoMode(RwInt32 subSystem, RwInt32 videoMode);
void CenterVideo(void);
void CloseClip(void);
+RwChar **_psGetVideoModeList();
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h
index 6009a549..aebcb2c6 100644
--- a/src/weapons/Weapon.h
+++ b/src/weapons/Weapon.h
@@ -18,7 +18,8 @@ enum eWeaponType
WEAPONTYPE_DETONATOR,
NUM_PED_WEAPONTYPES = 13,
WEAPONTYPE_HELICANNON = 13,
- NUM_WEAPONTYPES
+ NUM_WEAPONTYPES,
+ NO_STORED_WEAPON = 22
};
enum eWeaponFire {