From 5654347c5d511c53146fe4ce1710938b311d986e Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:50:57 +0300 Subject: [PATCH 001/129] Use glfwSetFramebufferSizeCallback instead of glfwSetWindowSizeCallback Framebuffer size is scaled by the display scale. This fixes the game being shrunk to the bottom left quarter of the window on Wayland HiDPI setups. Corresponding change in librw: glfwGetWindowSize -> glfwGetFramebufferSize. --- src/skel/glfw/glfw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index b9dbf5ac..f1b9c695 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -881,7 +881,7 @@ void psPostRWinit(void) RwEngineGetVideoModeInfo(&vm, GcurSelVM); glfwSetKeyCallback(PSGLOBAL(window), keypressCB); - glfwSetWindowSizeCallback(PSGLOBAL(window), resizeCB); + glfwSetFramebufferSizeCallback(PSGLOBAL(window), resizeCB); glfwSetScrollCallback(PSGLOBAL(window), scrollCB); glfwSetCursorPosCallback(PSGLOBAL(window), cursorCB); glfwSetCursorEnterCallback(PSGLOBAL(window), cursorEnterCB); From b95accb8ff6a594d1a920b94823b38be3515f149 Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:52:13 +0300 Subject: [PATCH 002/129] glfw: scale cursor position by the ratio of framebuffer to screen size This fixes the mouse being constrained to the top left quarter of the window on Wayland HiDPI setups. --- src/skel/glfw/glfw.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index f1b9c695..d7054b9c 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -1397,8 +1397,11 @@ _InputTranslateShiftKeyUpDown(RsKeyCodes *rs) { // TODO this only works in frontend(and luckily only frontend use this). Fun fact: if I get pos manually in game, glfw reports that it's > 32000 void cursorCB(GLFWwindow* window, double xpos, double ypos) { - FrontEndMenuManager.m_nMouseTempPosX = xpos; - FrontEndMenuManager.m_nMouseTempPosY = ypos; + int bufw, bufh, winw, winh; + glfwGetWindowSize(window, &winw, &winh); + glfwGetFramebufferSize(window, &bufw, &bufh); + FrontEndMenuManager.m_nMouseTempPosX = xpos * (bufw / winw); + FrontEndMenuManager.m_nMouseTempPosY = ypos * (bufh / winh); } void From 0205960a2fe13174b5dc17abf080b6821a3c883a Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:53:15 +0300 Subject: [PATCH 003/129] Use GLFW_CURSOR_DISABLED (glfw's native mouse restriction) On Wayland, clients cannot move the mouse pointer. Mouse constraints, as required for 3D camera movement, are an explicit specific thing, and glfw supports it with GLFW_CURSOR_DISABLED. Use DISABLED, unless we're in a menu in windowed mode, where HIDDEN is still appropriate. --- src/skel/glfw/glfw.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index d7054b9c..e954e04b 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -1628,6 +1628,8 @@ main(int argc, char *argv[]) #endif { glfwPollEvents(); + glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, + (FrontEndMenuManager.m_bMenuActive && !PSGLOBAL(fullScreen)) ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_DISABLED); if( ForegroundApp ) { switch ( gGameState ) From 7d31b7005a24dce07fe02db0bac6717951751898 Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:57:41 +0300 Subject: [PATCH 004/129] Add non-amd64 architectures for bsd --- premake5.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/premake5.lua b/premake5.lua index 881035ef..1be945d9 100644 --- a/premake5.lua +++ b/premake5.lua @@ -82,7 +82,10 @@ workspace "re3" filter { "system:bsd" } platforms { - "bsd-amd64-librw_gl3_glfw-oal" + "bsd-x86-librw_gl3_glfw-oal", + "bsd-amd64-librw_gl3_glfw-oal", + "bsd-arm-librw_gl3_glfw-oal", + "bsd-arm64-librw_gl3_glfw-oal" } filter "configurations:Debug" From 7d03a6fe291ff72edcf517dda1de8aee40941019 Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:59:14 +0300 Subject: [PATCH 005/129] Use CLOCK_MONOTONIC_FAST when available (FreeBSD) CLOCK_MONOTONIC_FAST is the equivalent of Linux's CLOCK_MONOTONIC_RAW. --- src/skel/glfw/glfw.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index e954e04b..02546ffc 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -235,8 +235,10 @@ double psTimer(void) { struct timespec start; -#ifdef __linux__ +#if defined(CLOCK_MONOTONIC_RAW) clock_gettime(CLOCK_MONOTONIC_RAW, &start); +#elif defined(CLOCK_MONOTONIC_FAST) + clock_gettime(CLOCK_MONOTONIC_FAST, &start); #else clock_gettime(CLOCK_MONOTONIC, &start); #endif From ec69a0e57d4c507e3749c0a3f47c3bdc362c7ae7 Mon Sep 17 00:00:00 2001 From: Roman Masanin <36927roma@gmail.com> Date: Sat, 17 Oct 2020 21:38:02 +0300 Subject: [PATCH 006/129] fix audio bug and some refractoring --- src/audio/AudioLogic.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 174bd5fa..1b147425 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -813,7 +813,7 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params) int32 emittingVol; uint32 freq; - float modificator; + float multiplier; int sampleFreq; float velocity; @@ -836,9 +836,9 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params) freq = 6050 * emittingVol / 30 + 16000; } else { m_sQueueSample.m_nSampleIndex = SFX_ROAD_NOISE; - modificator = m_sQueueSample.m_fDistance / 190.f; + multiplier = (m_sQueueSample.m_fDistance / SOUND_INTENSITY) * 0.5f; sampleFreq = SampleManager.GetSampleBaseFrequency(SFX_ROAD_NOISE); - freq = (sampleFreq * modificator) + ((3 * sampleFreq) / 4); + freq = (sampleFreq * multiplier) + ((3 * sampleFreq) / 4); } m_sQueueSample.m_nFrequency = freq; m_sQueueSample.m_nLoopCount = 0; @@ -866,7 +866,7 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params) float relativeVelocity; int32 emittingVol; - float modificator; + float multiplier; int freq; float velChange; @@ -886,9 +886,9 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params) m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_bIs2D = false; m_sQueueSample.m_nReleasingVolumeModificator = 3; - modificator = m_sQueueSample.m_fDistance / 6.f; + multiplier = (m_sQueueSample.m_fDistance / SOUND_INTENSITY) * 0.5f; freq = SampleManager.GetSampleBaseFrequency(SFX_ROAD_NOISE); - m_sQueueSample.m_nFrequency = freq + freq * modificator; + m_sQueueSample.m_nFrequency = freq + freq * multiplier; m_sQueueSample.m_nLoopCount = 0; m_sQueueSample.m_nEmittingVolume = emittingVol; m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); @@ -6488,15 +6488,15 @@ cAudioManager::ProcessFires(int32) void cAudioManager::ProcessWaterCannon(int32) { - const float SOUND_INTENSITY = 900.0f; + const float SOUND_INTENSITY = 30.0f; for (int32 i = 0; i < NUM_WATERCANNONS; i++) { if (CWaterCannons::aCannons[i].m_nId) { m_sQueueSample.m_vecPos = CWaterCannons::aCannons[0].m_avecPos[CWaterCannons::aCannons[i].m_nCur]; float distSquared = GetDistanceSquared(m_sQueueSample.m_vecPos); - if (distSquared < SOUND_INTENSITY) { + if (distSquared < SQR(SOUND_INTENSITY)) { m_sQueueSample.m_fDistance = Sqrt(distSquared); - m_sQueueSample.m_nVolume = ComputeVolume(50, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); + m_sQueueSample.m_nVolume = ComputeVolume(50, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_fSoundIntensity = SOUND_INTENSITY; m_sQueueSample.m_nSampleIndex = SFX_JUMBO_TAXI; From f5f9b8b79f3803335838cfa7789a07319d0fcc13 Mon Sep 17 00:00:00 2001 From: Roman Masanin <36927roma@gmail.com> Date: Sat, 17 Oct 2020 21:53:13 +0300 Subject: [PATCH 007/129] mark original bugs --- src/audio/AudioLogic.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 1b147425..5d72f099 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -886,7 +886,11 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params) m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_bIs2D = false; m_sQueueSample.m_nReleasingVolumeModificator = 3; +#ifdef FIX_BUGS multiplier = (m_sQueueSample.m_fDistance / SOUND_INTENSITY) * 0.5f; +#else + multiplier = (m_sQueueSample.m_fDistance / 3.0f) * 0.5f; +#endif freq = SampleManager.GetSampleBaseFrequency(SFX_ROAD_NOISE); m_sQueueSample.m_nFrequency = freq + freq * multiplier; m_sQueueSample.m_nLoopCount = 0; @@ -6496,9 +6500,17 @@ cAudioManager::ProcessWaterCannon(int32) float distSquared = GetDistanceSquared(m_sQueueSample.m_vecPos); if (distSquared < SQR(SOUND_INTENSITY)) { m_sQueueSample.m_fDistance = Sqrt(distSquared); +#ifdef FIX_BUGS m_sQueueSample.m_nVolume = ComputeVolume(50, SOUND_INTENSITY, m_sQueueSample.m_fDistance); +#else + m_sQueueSample.m_nVolume = ComputeVolume(50, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); +#endif if (m_sQueueSample.m_nVolume != 0) { +#ifdef FIX_BUGS m_sQueueSample.m_fSoundIntensity = SOUND_INTENSITY; +#else + m_sQueueSample.m_fSoundIntensity = SQR(SOUND_INTENSITY); +#endif m_sQueueSample.m_nSampleIndex = SFX_JUMBO_TAXI; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nFrequency = 15591; From 922d06ab1fb1c2222b2738bd12cbc7549dc52ded Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 28 Oct 2020 05:11:34 +0300 Subject: [PATCH 008/129] rewrite CFO + postfx/pipeline options --- src/core/Frontend.cpp | 290 +++++------- src/core/Frontend.h | 115 ++++- src/core/Game.cpp | 11 - src/core/MenuScreens.cpp | 15 +- src/core/MenuScreensCustom.cpp | 804 +++++++++++++++++++++++++++++++++ src/core/config.h | 4 +- src/core/main.cpp | 8 + src/core/re3.cpp | 452 +++--------------- src/extras/frontendoption.cpp | 246 +++------- src/extras/frontendoption.h | 121 +---- 10 files changed, 1177 insertions(+), 889 deletions(-) create mode 100644 src/core/MenuScreensCustom.cpp diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 89b5ba3d..8f1204e3 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -435,29 +435,17 @@ CMenuManager::ThingsToDoBeforeGoingBack() } #ifdef CUSTOM_FRONTEND_OPTIONS - for (int i = 0; i < numCustomFrontendOptions; i++) { - FrontendOption &option = customFrontendOptions[i]; - if (option.type != FEOPTION_REDIRECT && option.type != FEOPTION_GOBACK && m_nCurrScreen == option.screen) { - if (option.returnPrevPageFunc) - option.returnPrevPageFunc(); + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; - if (m_nCurrOption == option.screenOptionOrder && (option.type == FEOPTION_DYNAMIC || option.type == FEOPTION_BUILTIN_ACTION)) - if(option.buttonPressFunc) - option.buttonPressFunc(FEOPTION_ACTION_FOCUSLOSS); + if (option.m_Action == MENUACTION_CFO_DYNAMIC) + if(option.m_CFODynamic->buttonPressFunc) + option.m_CFODynamic->buttonPressFunc(FEOPTION_ACTION_FOCUSLOSS); - if (option.type == FEOPTION_SELECT && option.onlyApplyOnEnter && option.lastSavedValue != option.displayedValue) - option.displayedValue = *option.value = option.lastSavedValue; - } - } + if (option.m_Action == MENUACTION_CFO_SELECT && option.m_CFOSelect->onlyApplyOnEnter && option.m_CFOSelect->lastSavedValue != option.m_CFOSelect->displayedValue) + option.m_CFOSelect->displayedValue = *option.m_CFO->value = option.m_CFOSelect->lastSavedValue; - if (m_nCurrScreen > lastOgScreen) { - for (int i = 0; i < numCustomFrontendScreens; i++) { - FrontendScreen& screen = customFrontendScreens[i]; - if (m_nCurrScreen == screen.id && screen.returnPrevPageFunc) { - screen.returnPrevPageFunc(); - break; - } - } + if (aScreens[m_nCurrScreen].returnPrevPageFunc) { + aScreens[m_nCurrScreen].returnPrevPageFunc(); } #endif } @@ -476,18 +464,15 @@ CMenuManager::GetPreviousPageOption() prevPage = prevPage == MENUPAGE_NONE ? (!m_bGameNotLoaded ? MENUPAGE_PAUSE_MENU : MENUPAGE_START_MENU) : prevPage; for (int i = 0; i < NUM_MENUROWS; i++) { - if (aScreens[prevPage].m_aEntries[i].m_SaveSlot == SAVESLOT_CFO) { - FrontendOption &option = customFrontendOptions[aScreens[prevPage].m_aEntries[i].m_TargetMenu]; - if(option.type == FEOPTION_REDIRECT && option.to == m_nCurrScreen) { + if (aScreens[prevPage].m_aEntries[i].m_Action >= MENUACTION_NOTHING) { // CFO check + if (aScreens[prevPage].m_aEntries[i].m_TargetMenu == m_nCurrScreen) { return i; } - } else if (aScreens[prevPage].m_aEntries[i].m_TargetMenu == m_nCurrScreen) { - return i; } } - - // Couldn't find current screen option on previous page, use default behaviour (maybe save-related screen?) - return !m_bGameNotLoaded ? aScreens[m_nCurrScreen].m_ParentEntry[1] : aScreens[m_nCurrScreen].m_ParentEntry[0]; + + // This shouldn't happen + return 0; #endif } @@ -854,13 +839,6 @@ CMenuManager::Draw() str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); break; default: -#ifdef CUSTOM_FRONTEND_OPTIONS - if (aScreens[m_nCurrScreen].m_aEntries[0].m_SaveSlot == SAVESLOT_CFO) { - FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[0].m_TargetMenu]; - str = (wchar*)option.leftText; - } - else -#endif str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName); break; } @@ -959,30 +937,22 @@ CMenuManager::Draw() #endif default: #ifdef CUSTOM_FRONTEND_OPTIONS - bool custom = m_nCurrScreen > lastOgScreen; + CCustomScreenLayout *custom = aScreens[m_nCurrScreen].layout; if (custom) { - for (int i = 0; i < numCustomFrontendScreens; i++) { - FrontendScreen& screen = customFrontendScreens[i]; - if (m_nCurrScreen == screen.id) { - columnWidth = screen.columnWidth; - headerHeight = screen.headerHeight; - lineHeight = screen.lineHeight; - CFont::SetFontStyle(FONT_LOCALE(screen.font)); - CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = screen.fontScaleX), MENU_Y(MENU_TEXT_SIZE_Y = screen.fontScaleY)); - if (screen.alignment == FESCREEN_LEFT_ALIGN) { - CFont::SetCentreOff(); - CFont::SetRightJustifyOff(); - } else if (screen.alignment == FESCREEN_RIGHT_ALIGN) { - CFont::SetCentreOff(); - CFont::SetRightJustifyOn(); - } else { - CFont::SetRightJustifyOff(); - CFont::SetCentreOn(); - } - break; - } - if (i == numCustomFrontendScreens - 1) - custom = false; + columnWidth = custom->columnWidth; + headerHeight = custom->headerHeight; + lineHeight = custom->lineHeight; + CFont::SetFontStyle(FONT_LOCALE(custom->font)); + CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X = custom->fontScaleX), MENU_Y(MENU_TEXT_SIZE_Y = custom->fontScaleY)); + if (custom->alignment == FESCREEN_LEFT_ALIGN) { + CFont::SetCentreOff(); + CFont::SetRightJustifyOff(); + } else if (custom->alignment == FESCREEN_RIGHT_ALIGN) { + CFont::SetCentreOff(); + CFont::SetRightJustifyOn(); + } else { + CFont::SetRightJustifyOff(); + CFont::SetCentreOn(); } } if (!custom) @@ -1066,28 +1036,22 @@ CMenuManager::Draw() leftText = TheText.Get(gString); } } else { -#ifdef CUSTOM_FRONTEND_OPTIONS - if (aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot == SAVESLOT_CFO){ - FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[i].m_TargetMenu]; - leftText = (wchar*)option.leftText; - } else -#endif leftText = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName); } #ifdef CUSTOM_FRONTEND_OPTIONS - if (aScreens[m_nCurrScreen].m_aEntries[i].m_SaveSlot == SAVESLOT_CFO) { - FrontendOption &option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[i].m_TargetMenu]; - if (option.type == FEOPTION_SELECT) { - if (option.onlyApplyOnEnter){ + if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action < MENUACTION_NOTHING) { // CFO check + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[i]; + if (option.m_Action == MENUACTION_CFO_SELECT) { + if (option.m_CFOSelect->onlyApplyOnEnter){ if (m_nCurrOption != i) { - if (option.displayedValue != option.lastSavedValue) + if (option.m_CFOSelect->displayedValue != option.m_CFOSelect->lastSavedValue) SetHelperText(3); // Restored original value -// option.displayedValue = option.lastSavedValue = *option.value; +// option.displayedValue = option.lastSavedValue = *option.m_CFO->value; } else { - if (option.displayedValue != *option.value) + if (option.m_CFOSelect->displayedValue != *option.m_CFO->value) SetHelperText(1); // Enter to apply else if (m_nHelperTextMsgId == 1) ResetHelperText(); // Applied @@ -1096,13 +1060,13 @@ CMenuManager::Draw() } if (m_nCurrOption != lastOption && lastOption == i) { - FrontendOption &oldOption = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[lastOption].m_TargetMenu]; - if (oldOption.type == FEOPTION_DYNAMIC || oldOption.type == FEOPTION_BUILTIN_ACTION) - if(oldOption.buttonPressFunc) - oldOption.buttonPressFunc(FEOPTION_ACTION_FOCUSLOSS); + CMenuScreenCustom::CMenuEntry &oldOption = aScreens[m_nCurrScreen].m_aEntries[lastOption]; + if (oldOption.m_Action == MENUACTION_CFO_DYNAMIC) + if(oldOption.m_CFODynamic->buttonPressFunc) + oldOption.m_CFODynamic->buttonPressFunc(FEOPTION_ACTION_FOCUSLOSS); - if (oldOption.onlyApplyOnEnter && oldOption.type == FEOPTION_SELECT) - oldOption.displayedValue = oldOption.lastSavedValue = *oldOption.value; + if (oldOption.m_Action == MENUACTION_CFO_SELECT && oldOption.m_CFOSelect->onlyApplyOnEnter) + oldOption.m_CFOSelect->displayedValue = oldOption.m_CFOSelect->lastSavedValue = *oldOption.m_CFO->value; } } #endif @@ -1336,29 +1300,24 @@ CMenuManager::Draw() rightText = TheText.Get(CVehicle::m_bDisableMouseSteering ? "FEM_OFF" : "FEM_ON"); break; #ifdef CUSTOM_FRONTEND_OPTIONS - case MENUACTION_TRIGGERFUNC: - FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[i].m_TargetMenu]; - if (m_nCurrScreen == option.screen && i == option.screenOptionOrder) { - if (option.type == FEOPTION_SELECT) { - // To whom manipulate option.value of static options externally (like RestoreDef functions) - if (*option.value != option.lastSavedValue) - option.displayedValue = option.lastSavedValue = *option.value; + case MENUACTION_CFO_DYNAMIC: + case MENUACTION_CFO_SELECT: + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[i]; + if (option.m_Action == MENUACTION_CFO_SELECT) { + // To whom manipulate option.m_CFO->value of static options externally (like RestoreDef functions) + if (*option.m_CFO->value != option.m_CFOSelect->lastSavedValue) + option.m_CFOSelect->displayedValue = option.m_CFOSelect->lastSavedValue = *option.m_CFO->value; - if (option.displayedValue >= option.numRightTexts || option.displayedValue < 0) - option.displayedValue = 0; + if (option.m_CFOSelect->displayedValue >= option.m_CFOSelect->numRightTexts || option.m_CFOSelect->displayedValue < 0) + option.m_CFOSelect->displayedValue = 0; - rightText = (wchar*)option.rightTexts[option.displayedValue]; + rightText = TheText.Get(option.m_CFOSelect->rightTexts[option.m_CFOSelect->displayedValue]); - } else if (option.type == FEOPTION_DYNAMIC) { - if (option.drawFunc) { - rightText = option.drawFunc(&isOptionDisabled, m_nCurrOption == i); - } + } else if (option.m_Action == MENUACTION_CFO_DYNAMIC) { + if (option.m_CFODynamic->drawFunc) { + rightText = option.m_CFODynamic->drawFunc(&isOptionDisabled, m_nCurrOption == i); } - } else { - debug("A- screen:%d option:%d - totalCo: %d, coId: %d, coScreen:%d, coOption:%d\n", m_nCurrScreen, i, numCustomFrontendOptions, aScreens[m_nCurrScreen].m_aEntries[i].m_TargetMenu, option.screen, option.screenOptionOrder); - assert(0 && "Custom frontend options is borked"); } - break; #endif } @@ -1573,13 +1532,9 @@ CMenuManager::Draw() break; #ifdef CUSTOM_FRONTEND_OPTIONS default: - if (m_nCurrScreen > lastOgScreen) { - for (int i = 0; i < numCustomFrontendScreens; i++) { - FrontendScreen& screen = customFrontendScreens[i]; - if (m_nCurrScreen == screen.id && screen.showLeftRightHelper) { - DisplayHelperText(); - break; - } + if (aScreens[m_nCurrScreen].layout) { + if (aScreens[m_nCurrScreen].layout->showLeftRightHelper) { + DisplayHelperText(); } } break; @@ -2612,17 +2567,10 @@ CMenuManager::DrawFrontEndNormal() break; default: #ifdef CUSTOM_FRONTEND_OPTIONS - bool custom = m_nPrevScreen > lastOgScreen; + CCustomScreenLayout *custom = aScreens[m_nPrevScreen].layout; if (custom) { - for (int i = 0; i < numCustomFrontendScreens; i++) { - FrontendScreen& screen = customFrontendScreens[i]; - if (m_nPrevScreen == screen.id) { - previousSprite = screen.sprite; - break; - } - if (i == numCustomFrontendScreens - 1) - custom = false; - } + previousSprite = custom->sprite; + break; } if (!custom) #endif @@ -2678,15 +2626,9 @@ CMenuManager::DrawFrontEndNormal() break; #ifdef CUSTOM_FRONTEND_OPTIONS default: - bool custom = m_nCurrScreen > lastOgScreen; + CCustomScreenLayout *custom = aScreens[m_nCurrScreen].layout; if (custom) { - for (int i = 0; i < numCustomFrontendScreens; i++) { - FrontendScreen& screen = customFrontendScreens[i]; - if (m_nCurrScreen == screen.id) { - currentSprite = screen.sprite; - break; - } - } + previousSprite = custom->sprite; } break; #endif @@ -3301,10 +3243,6 @@ CMenuManager::InitialiseChangedLanguageSettings() default: break; } - -#ifdef CUSTOM_FRONTEND_OPTIONS - CustomFrontendOptionsPopulate(); -#endif } } @@ -3494,6 +3432,9 @@ CMenuManager::LoadSettings() strcpy(m_PrefsSkinFile, DEFAULT_SKIN_NAME); strcpy(m_aSkinName, DEFAULT_SKIN_NAME); } +#ifdef LOAD_INI_SETTINGS + LoadINISettings(); // needs frontend options to be loaded +#endif } void @@ -5086,29 +5027,28 @@ CMenuManager::ProcessButtonPresses(void) return; #endif #ifdef CUSTOM_FRONTEND_OPTIONS - case MENUACTION_TRIGGERFUNC: - FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu]; - if (m_nCurrScreen == option.screen && m_nCurrOption == option.screenOptionOrder) { - if (option.type == FEOPTION_SELECT) { - if (!option.onlyApplyOnEnter) { - option.displayedValue++; - if (option.displayedValue >= option.numRightTexts || option.displayedValue < 0) - option.displayedValue = 0; - } - option.changeFunc(option.displayedValue); - *option.value = option.lastSavedValue = option.displayedValue; - - } else if (option.type == FEOPTION_DYNAMIC) { - if (option.buttonPressFunc) - option.buttonPressFunc(FEOPTION_ACTION_SELECT); - } else if (option.type == FEOPTION_REDIRECT) { - ChangeScreen(option.to, option.option, true, option.fadeIn); - } else if (option.type == FEOPTION_GOBACK) { - goBack = true; + case MENUACTION_CFO_SELECT: + case MENUACTION_CFO_DYNAMIC: + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; + if (option.m_Action == MENUACTION_CFO_SELECT) { + if (!option.m_CFOSelect->onlyApplyOnEnter) { + option.m_CFOSelect->displayedValue++; + if (option.m_CFOSelect->displayedValue >= option.m_CFOSelect->numRightTexts || option.m_CFOSelect->displayedValue < 0) + option.m_CFOSelect->displayedValue = 0; } - } else { - debug("B- screen:%d option:%d - totalCo: %d, coId: %d, coScreen:%d, coOption:%d\n", m_nCurrScreen, m_nCurrOption, numCustomFrontendOptions, aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu, option.screen, option.screenOptionOrder); - assert(0 && "Custom frontend options are borked"); + int8 oldValue = *option.m_CFO->value; + + *option.m_CFO->value = option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue; + + if (option.m_CFOSelect->save) + SaveSettings(); + + if (option.m_CFOSelect->displayedValue != oldValue && option.m_CFOSelect->changeFunc) + option.m_CFOSelect->changeFunc(oldValue, option.m_CFOSelect->displayedValue); + + } else if (option.m_Action == MENUACTION_CFO_DYNAMIC) { + if (option.m_CFODynamic->buttonPressFunc) + option.m_CFODynamic->buttonPressFunc(FEOPTION_ACTION_SELECT); } break; @@ -5116,14 +5056,6 @@ CMenuManager::ProcessButtonPresses(void) } } ProcessOnOffMenuOptions(); -#ifdef CUSTOM_FRONTEND_OPTIONS - if (aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_SaveSlot == SAVESLOT_CFO) { - FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu]; - if (option.type == FEOPTION_BUILTIN_ACTION && option.buttonPressFunc) { - option.buttonPressFunc(FEOPTION_ACTION_SELECT); - } - } -#endif } if (goBack) { @@ -5326,32 +5258,34 @@ CMenuManager::ProcessButtonPresses(void) SaveSettings(); break; #ifdef CUSTOM_FRONTEND_OPTIONS - case MENUACTION_TRIGGERFUNC: - FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu]; - if (m_nCurrScreen == option.screen && m_nCurrOption == option.screenOptionOrder) { - if (option.type == FEOPTION_SELECT) { - if (changeValueBy > 0) { - option.displayedValue++; - if (option.displayedValue >= option.numRightTexts) - option.displayedValue = 0; - } else { - option.displayedValue--; - if (option.displayedValue < 0) - option.displayedValue = option.numRightTexts - 1; - } - if (!option.onlyApplyOnEnter) { - option.changeFunc(option.displayedValue); - *option.value = option.lastSavedValue = option.displayedValue; - } - } else if (option.type == FEOPTION_DYNAMIC && option.buttonPressFunc) { - option.buttonPressFunc(changeValueBy > 0 ? FEOPTION_ACTION_RIGHT : FEOPTION_ACTION_LEFT); + case MENUACTION_CFO_SELECT: + case MENUACTION_CFO_DYNAMIC: + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; + if (option.m_Action == MENUACTION_CFO_SELECT) { + if (changeValueBy > 0) { + option.m_CFOSelect->displayedValue++; + if (option.m_CFOSelect->displayedValue >= option.m_CFOSelect->numRightTexts) + option.m_CFOSelect->displayedValue = 0; + } else { + option.m_CFOSelect->displayedValue--; + if (option.m_CFOSelect->displayedValue < 0) + option.m_CFOSelect->displayedValue = option.m_CFOSelect->numRightTexts - 1; } - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); - } - else { - debug("C- screen:%d option:%d - totalCo: %d, coId: %d, coScreen:%d, coOption:%d\n", m_nCurrScreen, m_nCurrOption, numCustomFrontendOptions, aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_TargetMenu, option.screen, option.screenOptionOrder); - assert(0 && "Custom frontend options are borked"); + if (!option.m_CFOSelect->onlyApplyOnEnter) { + int8 oldValue = *option.m_CFO->value; + + *option.m_CFO->value = option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue; + + if (option.m_CFOSelect->save) + SaveSettings(); + + if (option.m_CFOSelect->displayedValue != oldValue && option.m_CFOSelect->changeFunc) + option.m_CFOSelect->changeFunc(oldValue, option.m_CFOSelect->displayedValue); + } + } else if (option.m_Action == MENUACTION_CFO_DYNAMIC && option.m_CFODynamic->buttonPressFunc) { + option.m_CFODynamic->buttonPressFunc(changeValueBy > 0 ? FEOPTION_ACTION_RIGHT : FEOPTION_ACTION_LEFT); } + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); break; #endif diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 848148e7..70b4cd31 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -156,9 +156,6 @@ enum eSaveSlot SAVESLOT_7, SAVESLOT_8, SAVESLOT_LABEL = 36, -#ifdef CUSTOM_FRONTEND_OPTIONS - SAVESLOT_CFO -#endif }; #ifdef MENU_MAP @@ -238,19 +235,32 @@ enum eMenuScreen MENUPAGE_KEYBOARD_CONTROLS = 55, MENUPAGE_MOUSE_CONTROLS = 56, MENUPAGE_MISSION_RETRY = 57, +#ifdef CUSTOM_FRONTEND_OPTIONS + #ifdef MENU_MAP MENUPAGE_MAP, #endif - MENUPAGE_UNK, // 58 in game. Map page is added above, because last screen in CMenuScreens should always be empty to make CFO work -#ifdef CUSTOM_FRONTEND_OPTIONS - MENUPAGES = 65 // for some room to add more screen +#ifdef GRAPHICS_MENU_OPTIONS + MENUPAGE_GRAPHICS_SETTINGS, #else - MENUPAGES + MENUPAGE_ADVANCED_DISPLAY_SETTINGS, #endif +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + MENUPAGE_DETECT_JOYSTICK, +#endif + +#endif + MENUPAGE_UNK, // originally 58. Custom screens are inserted above, because last screen in CMenuScreens should always be empty to make CFO work + MENUPAGES + }; enum eMenuAction { +#ifdef CUSTOM_FRONTEND_OPTIONS + MENUACTION_CFO_SELECT = -2, + MENUACTION_CFO_DYNAMIC = -1, +#endif MENUACTION_NOTHING, MENUACTION_LABEL, MENUACTION_CHANGEMENU, @@ -373,9 +383,6 @@ enum eMenuAction //#ifdef NO_ISLAND_LOADING // MENUACTION_ISLANDLOADING, //#endif -#ifdef CUSTOM_FRONTEND_OPTIONS - MENUACTION_TRIGGERFUNC -#endif }; enum eCheckHover @@ -458,6 +465,7 @@ struct BottomBarOption int32 screenId; }; +#ifndef CUSTOM_FRONTEND_OPTIONS struct CMenuScreen { char m_ScreenName[8]; @@ -470,9 +478,91 @@ struct CMenuScreen int32 m_Action; // eMenuAction char m_EntryName[8]; int32 m_SaveSlot; // eSaveSlot - int32 m_TargetMenu; // eMenuScreen // FrontendOption ID if it's a custom option + int32 m_TargetMenu; // eMenuScreen } m_aEntries[NUM_MENUROWS]; }; +extern CMenuScreen aScreens[MENUPAGES]; +#else +#include "frontendoption.h" +struct CCustomScreenLayout { + eMenuSprites sprite; + int columnWidth; + int headerHeight; + int lineHeight; + int8 font; + int8 alignment; + bool showLeftRightHelper; + float fontScaleX; + float fontScaleY; +}; + +struct CCFO +{ + int8 *value; + const char *save; +}; + +struct CCFOSelect : CCFO +{ + char** rightTexts; + int8 numRightTexts; + bool onlyApplyOnEnter; + int8 displayedValue; // only if onlyApplyOnEnter enabled for now + int8 lastSavedValue; // only if onlyApplyOnEnter enabled + ChangeFunc changeFunc; + + CCFOSelect() {}; + CCFOSelect(int8* value, const char* save, const char** rightTexts, int8 numRightTexts, bool onlyApplyOnEnter, ChangeFunc changeFunc){ + this->value = value; + if (value) + this->lastSavedValue = this->displayedValue = *value; + + this->save = save; + this->rightTexts = (char**)rightTexts; + this->numRightTexts = numRightTexts; + this->onlyApplyOnEnter = onlyApplyOnEnter; + this->changeFunc = changeFunc; + } +}; + +struct CCFODynamic : CCFO +{ + DrawFunc drawFunc; + ButtonPressFunc buttonPressFunc; + + CCFODynamic() {}; + CCFODynamic(int8* value, const char* save, DrawFunc drawFunc, ButtonPressFunc buttonPressFunc){ + this->value = value; + this->save = save; + this->drawFunc = drawFunc; + this->buttonPressFunc = buttonPressFunc; + } +}; + +struct CMenuScreenCustom +{ + char m_ScreenName[8]; + int32 m_PreviousPage[2]; // eMenuScreen + CCustomScreenLayout *layout; + ReturnPrevPageFunc returnPrevPageFunc; + + struct CMenuEntry + { + int32 m_Action; // eMenuAction - below zero is CFO + char m_EntryName[8]; + struct { + union { + CCFO *m_CFO; // for initializing + CCFOSelect *m_CFOSelect; + CCFODynamic *m_CFODynamic; + }; + int32 m_SaveSlot; // eSaveSlot + int32 m_TargetMenu; // eMenuScreen + }; + } m_aEntries[NUM_MENUROWS]; +}; +extern CMenuScreenCustom aScreens[MENUPAGES]; +#endif class CMenuManager { @@ -703,6 +793,5 @@ VALIDATE_SIZE(CMenuManager, 0x564); #endif extern CMenuManager FrontEndMenuManager; -extern CMenuScreen aScreens[MENUPAGES]; -#endif \ No newline at end of file +#endif diff --git a/src/core/Game.cpp b/src/core/Game.cpp index ef4800c5..83c75d91 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -86,7 +86,6 @@ #include "ZoneCull.h" #include "Zones.h" #include "debugmenu.h" -#include "frontendoption.h" #include "postfx.h" #include "custompipes.h" #include "crossplatform.h" @@ -314,16 +313,6 @@ bool CGame::InitialiseOnceAfterRW(void) DMAudio.SetMusicFadeVol(127); CWorld::Players[0].SetPlayerSkin(CMenuManager::m_PrefsSkinFile); -#ifdef CUSTOM_FRONTEND_OPTIONS - // Apparently this func. can be run multiple times at the start. - if (numCustomFrontendOptions == 0 && numCustomFrontendScreens == 0) { - // needs stored language and TheText to be loaded, and last TheText reload is at the start of here - CustomFrontendOptionsPopulate(); - } -#endif -#ifdef LOAD_INI_SETTINGS - LoadINISettings(); // needs frontend options to be loaded -#endif return true; } diff --git a/src/core/MenuScreens.cpp b/src/core/MenuScreens.cpp index 533fc755..c2eadb3b 100644 --- a/src/core/MenuScreens.cpp +++ b/src/core/MenuScreens.cpp @@ -2,8 +2,10 @@ #include "Frontend.h" #ifdef PC_MENU -// If you want to add new options, please don't do that here and see CustomFrontendOptionsPopulate in re3.cpp. +// Please don't touch this file, except for bug fixing or ports. +// Check MenuScreensCustom.cpp +#ifndef CUSTOM_FRONTEND_OPTIONS CMenuScreen aScreens[MENUPAGES] = { // MENUPAGE_NONE = 0 { "", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, }, @@ -434,14 +436,6 @@ CMenuScreen aScreens[MENUPAGES] = { }, #endif -#ifdef MENU_MAP - // MENUPAGE_MAP - { "FEG_MAP", 1, MENUPAGE_NONE, MENUPAGE_NONE, 5, 2, - MENUACTION_UNK110, "", SAVESLOT_NONE, MENUPAGE_NONE, // to prevent cross/enter to go back - MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, - }, -#endif - // MENUPAGE_UNK { "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0, @@ -449,4 +443,5 @@ CMenuScreen aScreens[MENUPAGES] = { }; -#endif \ No newline at end of file +#endif +#endif diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp new file mode 100644 index 00000000..e2516140 --- /dev/null +++ b/src/core/MenuScreensCustom.cpp @@ -0,0 +1,804 @@ +#include "common.h" +#include "platform.h" +#include "crossplatform.h" +#include "Renderer.h" +#include "Frontend.h" +#include "Font.h" +#include "Camera.h" +#include "main.h" +#include "MBlur.h" +#include "postfx.h" +#include "custompipes.h" +#include "RwHelper.h" + +// Menu screens array is at the bottom of the file. + +#ifdef PC_MENU + +#ifdef CUSTOM_FRONTEND_OPTIONS + +#ifdef IMPROVED_VIDEOMODE + #define VIDEOMODE_SELECTOR MENUACTION_CFO_SELECT, "FEM_SCF", { new CCFOSelect((int8*)&FrontEndMenuManager.m_nPrefsWindowed, nil, screenModes, 2, true, ScreenModeAfterChange) }, +#else + #define VIDEOMODE_SELECTOR +#endif + +#ifdef MULTISAMPLING + #define MULTISAMPLING_SELECTOR MENUACTION_CFO_DYNAMIC, "FED_AAS", { new CCFODynamic((int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, "MultiSampling", MultiSamplingDraw, MultiSamplingButtonPress) }, +#else + #define MULTISAMPLING_SELECTOR +#endif + +#ifdef CUTSCENE_BORDERS_SWITCH + #define CUTSCENE_BORDERS_TOGGLE MENUACTION_CFO_SELECT, "FEM_CSB", { new CCFOSelect((int8 *)&CMenuManager::m_PrefsCutsceneBorders, "CutsceneBorders", off_on, 2, false, nil) }, +#else + #define CUTSCENE_BORDERS_TOGGLE +#endif + +#ifdef FREE_CAM + #define FREE_CAM_TOGGLE MENUACTION_CFO_SELECT, "FEC_FRC", { new CCFOSelect((int8*)&TheCamera.bFreeCam, "FreeCam", off_on, 2, false, nil) }, +#else + #define FREE_CAM_TOGGLE +#endif + +#ifdef PS2_ALPHA_TEST + #define DUALPASS_SELECTOR MENUACTION_CFO_SELECT, "FEM_2PR", { new CCFOSelect((int8*)&gPS2alphaTest, "PS2AlphaTest", off_on, 2, false, nil) }, +#else + #define DUALPASS_SELECTOR +#endif + +#ifdef EXTENDED_COLOURFILTER + #define POSTFX_SELECTORS \ + MENUACTION_CFO_SELECT, "VEHPIPE", { new CCFOSelect((int8*)&CustomPipes::VehiclePipeSwitch, "VehiclePipeline", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), false, nil) }, \ + MENUACTION_CFO_SELECT, "RIM", { new CCFOSelect((int8*)&CustomPipes::RimlightEnable, "NeoRimLight", off_on, 2, false, nil) }, \ + MENUACTION_CFO_SELECT, "LGTMAPS", { new CCFOSelect((int8*)&CustomPipes::LightmapEnable, "NeoLightMaps", off_on, 2, false, nil) }, \ + MENUACTION_CFO_SELECT, "GLOSS", { new CCFOSelect((int8*)&CustomPipes::GlossEnable, "NeoRoadGloss", off_on, 2, false, nil) }, +#else + #define POSTFX_SELECTORS +#endif + +#ifdef EXTENDED_PIPELINES + #define PIPELINES_SELECTOR \ + MENUACTION_CFO_SELECT, "CLRFLTR", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false, nil) }, \ + MENUACTION_CFO_SELECT, "MBLUR", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false, nil) }, +#else + #define PIPELINES_SELECTOR +#endif + +const char *filterNames[] = { "None", "Simple", "Normal", "Mobile" }; +const char *vehPipelineNames[] = { "MatFX", "Neo" }; +const char *off_on[] = { "FEM_OFF", "FEM_ON" }; + +void RestoreDefGraphics(int8 action) { + if (action != FEOPTION_ACTION_SELECT) + return; + + #ifdef PS2_ALPHA_TEST + gPS2alphaTest = false; + #endif + #ifdef MULTISAMPLING + FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel = 0; + #endif + #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those + CMenuManager::m_PrefsFrameLimiter = true; + CMenuManager::m_PrefsVsyncDisp = true; + CMenuManager::m_PrefsVsync = true; + CMenuManager::m_PrefsUseWideScreen = false; + FrontEndMenuManager.m_nDisplayVideoMode = FrontEndMenuManager.m_nPrefsVideoMode; + #ifdef GTA3_1_1_PATCH + if (_dwOperatingSystemVersion == OS_WIN98) { + CMBlur::BlurOn = false; + CMBlur::MotionBlurClose(); + } else { + CMBlur::BlurOn = true; + CMBlur::MotionBlurOpen(Scene.camera); + } + #else + CMBlur::BlurOn = true; + #endif + FrontEndMenuManager.SaveSettings(); + #endif +} + +void RestoreDefDisplay(int8 action) { + if (action != FEOPTION_ACTION_SELECT) + return; + + #ifdef CUTSCENE_BORDERS_SWITCH + CMenuManager::m_PrefsCutsceneBorders = true; + #endif + #ifdef FREE_CAM + TheCamera.bFreeCam = false; + #endif + #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those + CMenuManager::m_PrefsBrightness = 256; + CMenuManager::m_PrefsLOD = 1.2f; + CRenderer::ms_lodDistScale = 1.2f; + CMenuManager::m_PrefsShowSubtitles = true; + FrontEndMenuManager.SaveSettings(); + #endif +} + +#ifdef MORE_LANGUAGES +void LangPolSelect(int8 action) +{ + if (action == FEOPTION_ACTION_SELECT) { + FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_POLISH; + FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; + FrontEndMenuManager.InitialiseChangedLanguageSettings(); + FrontEndMenuManager.SaveSettings(); + } +} + +void LangRusSelect(int8 action) +{ + if (action == FEOPTION_ACTION_SELECT) { + FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_RUSSIAN; + FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; + FrontEndMenuManager.InitialiseChangedLanguageSettings(); + FrontEndMenuManager.SaveSettings(); + } +} + +void LangJapSelect(int8 action) +{ + if (action == FEOPTION_ACTION_SELECT) { + FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_JAPANESE; + FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; + FrontEndMenuManager.InitialiseChangedLanguageSettings(); + FrontEndMenuManager.SaveSettings(); + } +} +#endif + +#ifndef MULTISAMPLING +void GraphicsGoBack() { +} +#else +void GraphicsGoBack() { + FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; +} + +void MultiSamplingButtonPress(int8 action) { + if (action == FEOPTION_ACTION_SELECT) { + if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { + FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel; + _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); + FrontEndMenuManager.SetHelperText(0); + FrontEndMenuManager.SaveSettings(); + } + } else if (action == FEOPTION_ACTION_LEFT || action == FEOPTION_ACTION_RIGHT) { + if (FrontEndMenuManager.m_bGameNotLoaded) { + FrontEndMenuManager.m_nDisplayMSAALevel += (action == FEOPTION_ACTION_RIGHT ? 1 : -1); + + int i = 0; + int maxAA = RwD3D8EngineGetMaxMultiSamplingLevels(); + while (maxAA != 1) { + i++; + maxAA >>= 1; + } + + if (FrontEndMenuManager.m_nDisplayMSAALevel < 0) + FrontEndMenuManager.m_nDisplayMSAALevel = i; + else if (FrontEndMenuManager.m_nDisplayMSAALevel > i) + FrontEndMenuManager.m_nDisplayMSAALevel = 0; + } + } else if (action == FEOPTION_ACTION_FOCUSLOSS) { + if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { + FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; + FrontEndMenuManager.SetHelperText(3); + } + } +} + +wchar* MultiSamplingDraw(bool *disabled, bool userHovering) { + static wchar unicodeTemp[64]; + if (userHovering) { + if (FrontEndMenuManager.m_nDisplayMSAALevel == FrontEndMenuManager.m_nPrefsMSAALevel) { + if (FrontEndMenuManager.m_nHelperTextMsgId == 1) // Press enter to apply + FrontEndMenuManager.ResetHelperText(); + } else { + FrontEndMenuManager.SetHelperText(1); + } + } else { + if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { + FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; + } + } + + if (!FrontEndMenuManager.m_bGameNotLoaded) + *disabled = true; + + switch (FrontEndMenuManager.m_nDisplayMSAALevel) { + case 0: + return TheText.Get("FEM_OFF"); + default: + sprintf(gString, "%iX", 1 << (FrontEndMenuManager.m_nDisplayMSAALevel)); + AsciiToUnicode(gString, unicodeTemp); + return unicodeTemp; + } +} +#endif + +#ifdef IMPROVED_VIDEOMODE +const char* screenModes[] = { "FED_FLS", "FED_WND" }; +void ScreenModeAfterChange(int8 before, int8 after) +{ + _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); // apply same resolution + FrontEndMenuManager.SetHelperText(0); +} + +#endif + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +wchar selectedJoystickUnicode[128]; + +wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { + int numButtons; + int found = -1; + const char *joyname; + if (userHovering) { + for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { + if ((joyname = glfwGetJoystickName(i))) { + const uint8* buttons = glfwGetJoystickButtons(i, &numButtons); + for (int j = 0; j < numButtons; j++) { + if (buttons[j]) { + found = i; + break; + } + } + if (found != -1) + break; + } + } + + if (found != -1 && PSGLOBAL(joy1id) != found) { + if (PSGLOBAL(joy1id) != -1 && PSGLOBAL(joy1id) != found) + PSGLOBAL(joy2id) = PSGLOBAL(joy1id); + else + PSGLOBAL(joy2id) = -1; + + strcpy(gSelectedJoystickName, joyname); + PSGLOBAL(joy1id) = found; + } + } + if (PSGLOBAL(joy1id) == -1) + AsciiToUnicode("Not found", selectedJoystickUnicode); + else + AsciiToUnicode(gSelectedJoystickName, selectedJoystickUnicode); + + return selectedJoystickUnicode; +} +#endif + +CMenuScreenCustom aScreens[MENUPAGES] = { + // MENUPAGE_NONE = 0 + { "", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, }, + + // MENUPAGE_STATS = 1 + { "FET_STA", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_NEW_GAME = 2 + { "FET_SGA", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_CHANGEMENU, "FES_SNG", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD }, + MENUACTION_POPULATESLOTS_CHANGEMENU, "GMLOAD", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT }, + MENUACTION_POPULATESLOTS_CHANGEMENU, "FES_DGA", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_BRIEFS = 3 + { "FET_BRE", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_CONTROLLER_SETTINGS = 4 + { "FET_CON", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil, + MENUACTION_CTRLCONFIG, "FEC_CCF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS }, + MENUACTION_CTRLDISPLAY, "FEC_CDP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS }, + MENUACTION_CTRLVIBRATION, "FEC_VIB", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_SETTINGS }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_SOUND_SETTINGS = 5 + { "FET_AUD", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil, + MENUACTION_MUSICVOLUME, "FEA_MUS", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_SFXVOLUME, "FEA_SFX", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_AUDIOHW, "FEA_3DH", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_SPEAKERCONF, "FEA_SPK", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_DYNAMICACOUSTIC, "FET_DAM", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_RADIO, "FEA_RSS", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_RESTOREDEF, "FET_DEF", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + +#ifndef GRAPHICS_MENU_OPTIONS + // MENUPAGE_DISPLAY_SETTINGS = 6 + { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil, + MENUACTION_BRIGHTNESS, "FED_BRI", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_DRAWDIST, "FEM_LOD", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_FRAMESYNC, "FEM_VSC", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_FRAMELIMIT, "FEM_FRM", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, +#ifndef EXTENDED_COLOURFILTER + MENUACTION_TRAILS, "FED_TRA", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, +#endif + MENUACTION_SUBTITLES, "FED_SUB", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_WIDESCREEN, "FED_WIS", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_SCREENRES, "FED_RES", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + VIDEOMODE_SELECTOR + MULTISAMPLING_SELECTOR + MENUACTION_CHANGEMENU, "FET_ADV", { nil, SAVESLOT_NONE, MENUPAGE_ADVANCED_DISPLAY_SETTINGS }, + MENUACTION_RESTOREDEF, "FET_DEF", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#else + // MENUPAGE_DISPLAY_SETTINGS = 6 + { "FET_DIS", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil, + MENUACTION_BRIGHTNESS, "FED_BRI", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_DRAWDIST, "FEM_LOD", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + CUTSCENE_BORDERS_TOGGLE + FREE_CAM_TOGGLE + MENUACTION_SUBTITLES, "FED_SUB", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_CFO_DYNAMIC, "FET_DEF", { new CCFODynamic(nil, nil, nil, RestoreDefDisplay) }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#endif + + // MENUPAGE_LANGUAGE_SETTINGS = 7 + { "FET_LAN", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil, + MENUACTION_LANG_ENG, "FEL_ENG", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, + MENUACTION_LANG_FRE, "FEL_FRE", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, + MENUACTION_LANG_GER, "FEL_GER", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, + MENUACTION_LANG_ITA, "FEL_ITA", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, + MENUACTION_LANG_SPA, "FEL_SPA", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, +#ifdef MORE_LANGUAGES + MENUACTION_CFO_DYNAMIC, "FEL_POL", { new CCFODynamic(nil, nil, nil, LangPolSelect) }, + MENUACTION_CFO_DYNAMIC, "FEL_RUS", { new CCFODynamic(nil, nil, nil, LangRusSelect) }, + MENUACTION_CFO_DYNAMIC, "FEL_JAP", { new CCFODynamic(nil, nil, nil, LangJapSelect) }, +#endif + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_CHOOSE_LOAD_SLOT = 8 + { "FET_LG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, nil, nil, + MENUACTION_CHANGEMENU, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME }, + MENUACTION_CHECKSAVE, "FEM_SL0", { nil, SAVESLOT_1, MENUPAGE_LOAD_SLOT_CONFIRM }, + MENUACTION_CHECKSAVE, "FEM_SL1", { nil, SAVESLOT_2, MENUPAGE_LOAD_SLOT_CONFIRM }, + MENUACTION_CHECKSAVE, "FEM_SL2", { nil, SAVESLOT_3, MENUPAGE_LOAD_SLOT_CONFIRM }, + MENUACTION_CHECKSAVE, "FEM_SL3", { nil, SAVESLOT_4, MENUPAGE_LOAD_SLOT_CONFIRM }, + MENUACTION_CHECKSAVE, "FEM_SL4", { nil, SAVESLOT_5, MENUPAGE_LOAD_SLOT_CONFIRM }, + MENUACTION_CHECKSAVE, "FEM_SL5", { nil, SAVESLOT_6, MENUPAGE_LOAD_SLOT_CONFIRM }, + MENUACTION_CHECKSAVE, "FEM_SL6", { nil, SAVESLOT_7, MENUPAGE_LOAD_SLOT_CONFIRM }, + MENUACTION_CHECKSAVE, "FEM_SL7", { nil, SAVESLOT_8, MENUPAGE_LOAD_SLOT_CONFIRM }, + }, + + // MENUPAGE_CHOOSE_DELETE_SLOT = 9 + { "FET_DG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, nil, nil, + MENUACTION_CHANGEMENU, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME }, + MENUACTION_CHANGEMENU, "FEM_SL0", { nil, SAVESLOT_1, MENUPAGE_DELETE_SLOT_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL1", { nil, SAVESLOT_2, MENUPAGE_DELETE_SLOT_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL2", { nil, SAVESLOT_3, MENUPAGE_DELETE_SLOT_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL3", { nil, SAVESLOT_4, MENUPAGE_DELETE_SLOT_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL4", { nil, SAVESLOT_5, MENUPAGE_DELETE_SLOT_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL5", { nil, SAVESLOT_6, MENUPAGE_DELETE_SLOT_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL6", { nil, SAVESLOT_7, MENUPAGE_DELETE_SLOT_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL7", { nil, SAVESLOT_8, MENUPAGE_DELETE_SLOT_CONFIRM }, + }, + + // MENUPAGE_NEW_GAME_RELOAD = 10 + { "FET_NG", MENUPAGE_NEW_GAME, MENUPAGE_NEW_GAME, nil, nil, + MENUACTION_LABEL, "FESZ_QR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME }, + MENUACTION_NEWGAME, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME_RELOAD }, + }, + + // MENUPAGE_LOAD_SLOT_CONFIRM = 11 + { "FET_LG", MENUPAGE_CHOOSE_LOAD_SLOT, MENUPAGE_CHOOSE_LOAD_SLOT, nil, nil, + MENUACTION_LABEL, "FESZ_QL", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT }, + MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS }, + }, + + // MENUPAGE_DELETE_SLOT_CONFIRM = 12 + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, nil, nil, + MENUACTION_LABEL, "FESZ_QD", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT }, + MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_DELETING }, + }, + + // MENUPAGE_NO_MEMORY_CARD = 13 + { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + // hud adjustment page in mobile + }, + + // MENUPAGE_LOADING_IN_PROGRESS = 14 + { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_LABEL, "FED_LDW", { nil, SAVESLOT_NONE, MENUPAGE_LOAD_SLOT_CONFIRM }, + }, + + // MENUPAGE_DELETING_IN_PROGRESS = 15 + { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_LABEL, "FEDL_WR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_PS2_LOAD_FAILED = 16 + { "FET_LG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_LABEL, "FES_LOE", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_DELETE_FAILED = 17 + { "FET_DG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_LABEL, "FES_DEE", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT }, + }, + + // MENUPAGE_DEBUG_MENU = 18 + { "FED_DBG", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_RELOADIDE, "FED_RID", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_RELOADIPL, "FED_RIP", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_SETDBGFLAG, "FED_DFL", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_SWITCHBIGWHITEDEBUGLIGHT, "FED_DLS", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_PEDROADGROUPS, "FED_SPR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CARROADGROUPS, "FED_SCR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_COLLISIONPOLYS, "FED_SCP", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_PARSEHEAP, "FED_PAH", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_SHOWCULL, "FED_SCZ", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_DEBUGSTREAM, "FED_DSR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_MEMORY_CARD_DEBUG = 19 + { "FEM_MCM", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_REGMEMCARD1, "FEM_RMC", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_TESTFORMATMEMCARD1, "FEM_TFM", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_TESTUNFORMATMEMCARD1, "FEM_TUM", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CREATEROOTDIR, "FEM_CRD", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CREATELOADICONS, "FEM_CLI", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_FILLWITHGUFF, "FEM_FFF", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_SAVEONLYTHEGAME, "FEM_SOG", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_SAVEGAME, "FEM_STG", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_SAVEGAMEUNDERGTA, "FEM_STS", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CREATECOPYPROTECTED, "FEM_CPD", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_MEMORY_CARD_TEST = 20 + { "FEM_MC2", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_MULTIPLAYER_MAIN = 21 + { "FET_MP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_PS2_SAVE_FAILED = 22 + { "MCDNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_PS2_SAVE_FAILED_2 = 23 + { "MCGNSP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_MEMCARDSAVECONFIRM, "JAILB_U", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // Unused in PC but anyway + // MENUPAGE_SAVE = 24 +#ifdef PS2_SAVE_DIALOG + { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_CHANGEMENU, "FESZ_SA", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT }, + MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#else + { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_LABEL, "FES_SCG", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_POPULATESLOTS_CHANGEMENU, "GMSAVE", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT }, + MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#endif + + // MENUPAGE_NO_MEMORY_CARD_2 = 25 + { "FES_NOC", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_CHANGEMENU, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_CHOOSE_SAVE_SLOT = 26 + { "FET_SG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_RESUME_FROM_SAVEZONE, "FESZ_CA", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEM_SL1", { nil, SAVESLOT_1, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL2", { nil, SAVESLOT_2, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL3", { nil, SAVESLOT_3, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL4", { nil, SAVESLOT_4, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL5", { nil, SAVESLOT_5, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL6", { nil, SAVESLOT_6, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL7", { nil, SAVESLOT_7, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + MENUACTION_CHANGEMENU, "FEM_SL8", { nil, SAVESLOT_8, MENUPAGE_SAVE_OVERWRITE_CONFIRM }, + }, + + // MENUPAGE_SAVE_OVERWRITE_CONFIRM = 27 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil, + MENUACTION_LABEL, "FESZ_QO", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_SAVING_IN_PROGRESS }, + MENUACTION_CHANGEMENU, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT }, + }, + + // MENUPAGE_MULTIPLAYER_MAP = 28 + { "FET_MAP", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_MULTIPLAYER_CONNECTION = 29 + { "FET_CON", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_MULTIPLAYER_FIND_GAME = 30 + { "FET_FG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_MULTIPLAYER_MODE = 31 + { "FET_GT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_MULTIPLAYER_CREATE = 32 + { "FET_HG", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_MULTIPLAYER_START = 33 + { "FEN_STA", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_SKIN_SELECT_OLD = 34 + { "FET_PS", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_CONTROLLER_PC = 35 + { "FET_CTL", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil, + MENUACTION_CTRLMETHOD, "FET_CME", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC }, + MENUACTION_KEYBOARDCTRLS,"FET_RDK", { nil, SAVESLOT_NONE, MENUPAGE_KEYBOARD_CONTROLS }, +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + MENUACTION_CHANGEMENU, "FEC_JOD", { nil, SAVESLOT_NONE, MENUPAGE_DETECT_JOYSTICK }, +#endif + MENUACTION_CHANGEMENU, "FET_AMS", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, + MENUACTION_RESTOREDEF, "FET_DEF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_CONTROLLER_PC_OLD1 = 36 + { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, + MENUACTION_GETKEY, "FEC_PLB", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_CWL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_CWR", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_LKT", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_PJP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_PSP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_TLF", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_TRG", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_GETKEY, "FEC_CCM", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD1 }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_CONTROLLER_PC_OLD2 = 37 + { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, + + }, + + // MENUPAGE_CONTROLLER_PC_OLD3 = 38 + { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, + MENUACTION_GETKEY, "FEC_LUP", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 }, + MENUACTION_GETKEY, "FEC_LDN", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 }, + MENUACTION_GETKEY, "FEC_SMS", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 }, + MENUACTION_SHOWHEADBOB, "FEC_GSL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC_OLD3 }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_CONTROLLER_PC_OLD4 = 39 + { "FET_CTL", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, + + }, + + // MENUPAGE_CONTROLLER_DEBUG = 40 + { "FEC_DBG", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, + MENUACTION_GETKEY, "FEC_TGD", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG }, + MENUACTION_GETKEY, "FEC_TDO", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG }, + MENUACTION_GETKEY, "FEC_TSS", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG }, + MENUACTION_GETKEY, "FEC_SMS", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_DEBUG }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_OPTIONS = 41 + { "FET_OPT", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_CHANGEMENU, "FET_CTL", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC }, + MENUACTION_LOADRADIO, "FET_AUD", { nil, SAVESLOT_NONE, MENUPAGE_SOUND_SETTINGS }, + MENUACTION_CHANGEMENU, "FET_DIS", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, +#ifdef GRAPHICS_MENU_OPTIONS + MENUACTION_CHANGEMENU, "FET_GRA", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS }, +#endif + MENUACTION_CHANGEMENU, "FET_LAN", { nil, SAVESLOT_NONE, MENUPAGE_LANGUAGE_SETTINGS }, + MENUACTION_PLAYERSETUP, "FET_PSU", { nil, SAVESLOT_NONE, MENUPAGE_SKIN_SELECT }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_EXIT = 42 + { "FET_QG", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_LABEL, "FEQ_SRE", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_DONTCANCEL, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CANCELGAME, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_SAVING_IN_PROGRESS = 43 + { "", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil, + MENUACTION_LABEL, "FES_WAR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_SAVE_SUCCESSFUL = 44 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil, + MENUACTION_LABEL, "FES_SSC", { nil, SAVESLOT_LABEL, MENUPAGE_NONE }, + MENUACTION_RESUME_FROM_SAVEZONE, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT }, + }, + + // MENUPAGE_DELETING = 45 + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, nil, nil, + MENUACTION_LABEL, "FED_DLW", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_DELETE_SUCCESS = 46 + { "FET_DG", MENUPAGE_CHOOSE_DELETE_SLOT, MENUPAGE_CHOOSE_DELETE_SLOT, nil, nil, + MENUACTION_LABEL, "DEL_FNM", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_DELETE_SLOT }, + }, + + // MENUPAGE_SAVE_FAILED = 47 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil, + MENUACTION_LABEL, "FEC_SVU", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEC_OKK", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_SAVE_SLOT }, + }, + + // MENUPAGE_LOAD_FAILED = 48 + { "FET_SG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil, + MENUACTION_LABEL, "FEC_SVU", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_LOAD_FAILED_2 = 49 + { "FET_LG", MENUPAGE_CHOOSE_SAVE_SLOT, MENUPAGE_CHOOSE_SAVE_SLOT, nil, nil, + MENUACTION_LABEL, "FEC_LUN", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_CHOOSE_LOAD_SLOT }, + }, + + // MENUPAGE_FILTER_GAME = 50 + { "FIL_FLT", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + + }, + + // MENUPAGE_START_MENU = 51 + { "FEM_MM", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_CHANGEMENU, "FEN_STA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME }, + MENUACTION_CHANGEMENU, "FET_OPT", { nil, SAVESLOT_NONE, MENUPAGE_OPTIONS }, + MENUACTION_CHANGEMENU, "FEM_QT", { nil, SAVESLOT_NONE, MENUPAGE_EXIT }, + }, + + // MENUPAGE_PAUSE_MENU = 52 + { "FET_PAU", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_RESUME, "FEM_RES", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEN_STA", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME }, +#ifdef MENU_MAP + MENUACTION_CHANGEMENU, "FEG_MAP", { nil, SAVESLOT_NONE, MENUPAGE_MAP }, +#endif + MENUACTION_CHANGEMENU, "FEP_STA", { nil, SAVESLOT_NONE, MENUPAGE_STATS }, + MENUACTION_CHANGEMENU, "FEP_BRI", { nil, SAVESLOT_NONE, MENUPAGE_BRIEFS }, + MENUACTION_CHANGEMENU, "FET_OPT", { nil, SAVESLOT_NONE, MENUPAGE_OPTIONS }, + MENUACTION_CHANGEMENU, "FEM_QT", { nil, SAVESLOT_NONE, MENUPAGE_EXIT }, + }, + + // MENUPAGE_CHOOSE_MODE = 53 + { "FEN_STA", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_CHANGEMENU, "FET_SP", { nil, SAVESLOT_NONE, MENUPAGE_NEW_GAME }, + MENUACTION_INITMP, "FET_MP", { nil, SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + + // MENUPAGE_SKIN_SELECT = 54 + { "FET_PSU", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, nil, nil, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_MULTIPLAYER_MAIN }, + }, + + // MENUPAGE_KEYBOARD_CONTROLS = 55 + { "FET_STI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_CONTROLLER_PC }, + }, + + // MENUPAGE_MOUSE_CONTROLS = 56 + { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, + MENUACTION_MOUSESENS, "FEC_MSH", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, + MENUACTION_INVVERT, "FEC_IVV", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, + MENUACTION_MOUSESTEER, "FET_MST", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, + // MENUPAGE_MISSION_RETRY = 57 +#ifdef MISSION_REPLAY + + { "M_FAIL", MENUPAGE_DISABLED, MENUPAGE_DISABLED, nil, nil, + MENUACTION_LABEL, "FESZ_RM", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CHANGEMENU, "FEM_YES", { nil, SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS }, + MENUACTION_REJECT_RETRY, "FEM_NO", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#else + { "", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + // mission failed, wanna restart page in mobile + }, +#endif + +#ifdef MENU_MAP + // MENUPAGE_MAP + { "FEG_MAP", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + MENUACTION_UNK110, "", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, // to prevent cross/enter to go back + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#endif + +#ifdef GRAPHICS_MENU_OPTIONS + // MENUPAGE_GRAPHICS_SETTINGS + { "FET_GRA", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, + new CCustomScreenLayout({MENUSPRITE_MAINMENU, 50, 0, 20, FONT_HEADING, FESCREEN_LEFT_ALIGN, true, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), GraphicsGoBack, + + MENUACTION_SCREENRES, "FED_RES", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS }, + MENUACTION_WIDESCREEN, "FED_WIS", { nil, SAVESLOT_NONE, MENUPAGE_GRAPHICS_SETTINGS }, + VIDEOMODE_SELECTOR + MENUACTION_FRAMESYNC, "FEM_VSC", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MENUACTION_FRAMELIMIT, "FEM_FRM", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, + MULTISAMPLING_SELECTOR +#ifdef EXTENDED_COLOURFILTER + POSTFX_SELECTORS +#else + MENUACTION_TRAILS, "FED_TRA", { nil, SAVESLOT_NONE, MENUPAGE_DISPLAY_SETTINGS }, +#endif +#ifdef EXTENDED_PIPELINES + PIPELINES_SELECTOR +#endif + DUALPASS_SELECTOR + MENUACTION_CFO_DYNAMIC, "FET_DEF", { new CCFODynamic(nil, nil, nil, RestoreDefGraphics) }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#else + // MENUPAGE_ADVANCED_DISPLAY_SETTINGS + { "FET_ADV", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, + new CCustomScreenLayout({MENUSPRITE_MAINMENU, 50, 0, 20, FONT_HEADING, FESCREEN_LEFT_ALIGN, true, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), nil, + + DUALPASS_SELECTOR + CUTSCENE_BORDERS_TOGGLE + FREE_CAM_TOGGLE +#ifdef EXTENDED_COLOURFILTER + POSTFX_SELECTORS +#endif +#ifdef EXTENDED_PIPELINES + PIPELINES_SELECTOR +#endif + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#endif + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + // MENUPAGE_DETECT_JOYSTICK + { "FEC_JOD", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, + new CCustomScreenLayout({MENUSPRITE_MAINMENU, 40, 60, 20, FONT_BANK, FESCREEN_LEFT_ALIGN, false, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), nil, + + MENUACTION_LABEL, "FEC_JPR", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + MENUACTION_CFO_DYNAMIC, "FEC_JDE", { new CCFODynamic(nil, nil, DetectJoystickDraw, nil) }, + MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, + }, +#endif + + // MENUPAGE_UNK + { "", MENUPAGE_NONE, MENUPAGE_NONE, nil, nil, + + }, + +}; + +#endif +#endif diff --git a/src/core/config.h b/src/core/config.h index 171c6be9..efb09222 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -210,8 +210,8 @@ enum Config { #define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU //#define USE_TEXTURE_POOL #define CUTSCENE_BORDERS_SWITCH -//#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) -//#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) +#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) +#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) #define MULTISAMPLING // adds MSAA option #ifdef LIBRW diff --git a/src/core/main.cpp b/src/core/main.cpp index 18ee2dc5..fa82d1e1 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -64,6 +64,7 @@ #include "debugmenu.h" #include "Clock.h" #include "custompipes.h" +#include "frontendoption.h" GlobalScene Scene; @@ -404,6 +405,13 @@ Initialise3D(void *param) DebugMenuInit(); DebugMenuPopulate(); #endif // !DEBUGMENU +#ifdef CUSTOM_FRONTEND_OPTIONS + // Apparently this func. can be run multiple times at the start. + if (numCustomFrontendOptions == 0 && numCustomFrontendScreens == 0) { + // needs stored language and TheText to be loaded, and last TheText reload is at the start of here + CustomFrontendOptionsPopulate(); + } +#endif bool ret = CGame::InitialiseRenderWare(); #ifdef EXTENDED_PIPELINES CustomPipes::CustomPipeInit(); // need Scene.world for this diff --git a/src/core/re3.cpp b/src/core/re3.cpp index a06762f5..aa13ba29 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -1,7 +1,6 @@ #include #define WITHWINDOWS #include "common.h" -#include "platform.h" #include "crossplatform.h" #include "Renderer.h" #include "Credits.h" @@ -16,7 +15,6 @@ #include "Boat.h" #include "Heli.h" #include "Automobile.h" -#include "Ped.h" #include "Console.h" #include "Debug.h" #include "Hud.h" @@ -26,10 +24,8 @@ #include "Radar.h" #include "debugmenu.h" #include "Frontend.h" -#include "Text.h" #include "WaterLevel.h" #include "main.h" -#include "MBlur.h" #include "postfx.h" #include "custompipes.h" @@ -76,388 +72,39 @@ mysrand(unsigned int seed) #ifdef CUSTOM_FRONTEND_OPTIONS #include "frontendoption.h" -#include "Font.h" -void ReloadFrontendOptions(void) -{ - CustomFrontendOptionsPopulate(); -} - -void RestoreDefGraphics(int8 action) { - if (action != FEOPTION_ACTION_SELECT) - return; - - #ifdef PS2_ALPHA_TEST - gPS2alphaTest = false; - #endif - #ifdef MULTISAMPLING - FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel = 0; - #endif - #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those - CMenuManager::m_PrefsFrameLimiter = true; - CMenuManager::m_PrefsVsyncDisp = true; - CMenuManager::m_PrefsVsync = true; - CMenuManager::m_PrefsUseWideScreen = false; - FrontEndMenuManager.m_nDisplayVideoMode = FrontEndMenuManager.m_nPrefsVideoMode; - #ifdef GTA3_1_1_PATCH - if (_dwOperatingSystemVersion == OS_WIN98) { - CMBlur::BlurOn = false; - CMBlur::MotionBlurClose(); - } else { - CMBlur::BlurOn = true; - CMBlur::MotionBlurOpen(Scene.camera); - } - #else - CMBlur::BlurOn = true; - #endif - FrontEndMenuManager.SaveSettings(); - #endif -} - -void RestoreDefDisplay(int8 action) { - if (action != FEOPTION_ACTION_SELECT) - return; - - #ifdef CUTSCENE_BORDERS_SWITCH - CMenuManager::m_PrefsCutsceneBorders = true; - #endif - #ifdef FREE_CAM - TheCamera.bFreeCam = false; - #endif - #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those - CMenuManager::m_PrefsBrightness = 256; - CMenuManager::m_PrefsLOD = 1.2f; - CRenderer::ms_lodDistScale = 1.2f; - CMenuManager::m_PrefsShowSubtitles = true; - FrontEndMenuManager.SaveSettings(); - #endif -} - -#ifdef MULTISAMPLING -void MultiSamplingGoBack() { - FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; -} - -void MultiSamplingButtonPress(int8 action) { - if (action == FEOPTION_ACTION_SELECT) { - if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { - FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel; - _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); - FrontEndMenuManager.SetHelperText(0); - FrontEndMenuManager.SaveSettings(); - } - } else if (action == FEOPTION_ACTION_LEFT || action == FEOPTION_ACTION_RIGHT) { - if (FrontEndMenuManager.m_bGameNotLoaded) { - FrontEndMenuManager.m_nDisplayMSAALevel += (action == FEOPTION_ACTION_RIGHT ? 1 : -1); - - int i = 0; - int maxAA = RwD3D8EngineGetMaxMultiSamplingLevels(); - while (maxAA != 1) { - i++; - maxAA >>= 1; - } - - if (FrontEndMenuManager.m_nDisplayMSAALevel < 0) - FrontEndMenuManager.m_nDisplayMSAALevel = i; - else if (FrontEndMenuManager.m_nDisplayMSAALevel > i) - FrontEndMenuManager.m_nDisplayMSAALevel = 0; - } - } else if (action == FEOPTION_ACTION_FOCUSLOSS) { - if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { - FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; - FrontEndMenuManager.SetHelperText(3); - } - } -} - -wchar* MultiSamplingDraw(bool *disabled, bool userHovering) { - static wchar unicodeTemp[64]; - if (userHovering) { - if (FrontEndMenuManager.m_nDisplayMSAALevel == FrontEndMenuManager.m_nPrefsMSAALevel) { - if (FrontEndMenuManager.m_nHelperTextMsgId == 1) // Press enter to apply - FrontEndMenuManager.ResetHelperText(); - } else { - FrontEndMenuManager.SetHelperText(1); - } - } else { - if (FrontEndMenuManager.m_nDisplayMSAALevel != FrontEndMenuManager.m_nPrefsMSAALevel) { - FrontEndMenuManager.m_nDisplayMSAALevel = FrontEndMenuManager.m_nPrefsMSAALevel; - } - } - - if (!FrontEndMenuManager.m_bGameNotLoaded) - *disabled = true; - - switch (FrontEndMenuManager.m_nDisplayMSAALevel) { - case 0: - return TheText.Get("FEM_OFF"); - default: - sprintf(gString, "%iX", 1 << (FrontEndMenuManager.m_nDisplayMSAALevel)); - AsciiToUnicode(gString, unicodeTemp); - return unicodeTemp; - } -} -const char* multisamplingKey = "MultiSampling"; -#endif - -#ifdef MORE_LANGUAGES -void LangPolSelect(int8 action) -{ - if (action == FEOPTION_ACTION_SELECT) { - FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_POLISH; - FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; - FrontEndMenuManager.InitialiseChangedLanguageSettings(); - FrontEndMenuManager.SaveSettings(); - } -} - -void LangRusSelect(int8 action) -{ - if (action == FEOPTION_ACTION_SELECT) { - FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_RUSSIAN; - FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; - FrontEndMenuManager.InitialiseChangedLanguageSettings(); - FrontEndMenuManager.SaveSettings(); - } -} - -void LangJapSelect(int8 action) -{ - if (action == FEOPTION_ACTION_SELECT) { - FrontEndMenuManager.m_PrefsLanguage = CMenuManager::LANGUAGE_JAPANESE; - FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true; - FrontEndMenuManager.InitialiseChangedLanguageSettings(); - FrontEndMenuManager.SaveSettings(); - } -} -#endif - -#ifdef IMPROVED_VIDEOMODE -void ScreenModeChange(int8 displayedValue) -{ - if (displayedValue != FrontEndMenuManager.m_nPrefsWindowed) { - FrontEndMenuManager.m_nPrefsWindowed = displayedValue; - _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); // apply same resolution - FrontEndMenuManager.SetHelperText(0); - FrontEndMenuManager.SaveSettings(); - } -} -#endif - -#ifdef FREE_CAM -void FreeCamChange(int8 displayedValue) -{ - TheCamera.bFreeCam = !!displayedValue; - FrontEndMenuManager.SaveSettings(); -} -const char* freeCamKey = "FreeCam"; -#endif - -#ifdef CUTSCENE_BORDERS_SWITCH -void BorderModeChange(int8 displayedValue) -{ - CMenuManager::m_PrefsCutsceneBorders = !!displayedValue; - FrontEndMenuManager.SaveSettings(); -} -const char* cutsceneBordersKey = "CutsceneBorders"; -#endif - -#ifdef PS2_ALPHA_TEST -void PS2AlphaTestChange(int8 displayedValue) -{ - gPS2alphaTest = !!displayedValue; - FrontEndMenuManager.SaveSettings(); -} -const char* ps2alphaKey = "PS2AlphaTest"; -#endif - -#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS -wchar selectedJoystickUnicode[128]; - -wchar* DetectJoystickDraw(bool* disabled, bool userHovering) { - int numButtons; - int found = -1; - const char *joyname; - if (userHovering) { - for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { - if ((joyname = glfwGetJoystickName(i))) { - const uint8* buttons = glfwGetJoystickButtons(i, &numButtons); - for (int j = 0; j < numButtons; j++) { - if (buttons[j]) { - found = i; - break; - } - } - if (found != -1) - break; - } - } - - if (found != -1 && PSGLOBAL(joy1id) != found) { - if (PSGLOBAL(joy1id) != -1 && PSGLOBAL(joy1id) != found) - PSGLOBAL(joy2id) = PSGLOBAL(joy1id); - else - PSGLOBAL(joy2id) = -1; - - strcpy(gSelectedJoystickName, joyname); - PSGLOBAL(joy1id) = found; - } - } - if (PSGLOBAL(joy1id) == -1) - AsciiToUnicode("Not found", selectedJoystickUnicode); - else - AsciiToUnicode(gSelectedJoystickName, selectedJoystickUnicode); - - return selectedJoystickUnicode; -} -#endif - -// Important: Make sure to read the warnings/informations in frontendoption.h!! -// If you will hardcode any text, please use AllocUnicode! wchar_t size differs between platforms void CustomFrontendOptionsPopulate(void) { - RemoveCustomFrontendOptions(); // if exist - - // -- Graphics/display seperation preperation starts - don't add options in here! -#ifdef GRAPHICS_MENU_OPTIONS - int graphicsMenu = FrontendScreenAdd("FET_GRA", MENUSPRITE_MAINMENU, MENUPAGE_OPTIONS, 50, 0, 20, - FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true); - - int newDisplayMenu = FrontendScreenAdd("FET_DIS", MENUSPRITE_MAINMENU, MENUPAGE_OPTIONS, 50, 0, 20, - FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true); - - FrontendOptionSetCursor(MENUPAGE_OPTIONS, 2, true); - FrontendOptionAddRedirect(TheText.Get("FET_DIS"), newDisplayMenu, 0); - FrontendOptionSetCursor(MENUPAGE_OPTIONS, 3); - FrontendOptionAddRedirect(TheText.Get("FET_GRA"), graphicsMenu, 0); - -#define SWITCH_TO_GRAPHICS_MENU FrontendOptionSetCursor(graphicsMenu, -1); -#define SWITCH_TO_DISPLAY_MENU FrontendOptionSetCursor(newDisplayMenu, -1); -#define CLONE_OPTION(a, b, c, d) FrontendOptionAddBuiltinAction(a, b, c, d); -#define ADD_BACK FrontendOptionAddBackButton(TheText.Get("FEDS_TB")); -#define ADD_RESTORE_DEFAULTS(a) FrontendOptionAddDynamic(TheText.Get("FET_DEF"), nil, nil, a, nil); -#else - int advancedDisplayMenu = FrontendScreenAdd("FET_ADV", MENUSPRITE_MAINMENU, MENUPAGE_DISPLAY_SETTINGS, 50, 0, 20, - FONT_HEADING, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, true); - bool movedToAdvMenu = false; - -#define SWITCH_TO_GRAPHICS_MENU \ - if (GetNumberOfMenuOptions(MENUPAGE_DISPLAY_SETTINGS) >= 12) { \ - FrontendOptionSetCursor(advancedDisplayMenu, -1); \ - movedToAdvMenu = true; \ - } else { \ - FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3); \ - } - -#define SWITCH_TO_DISPLAY_MENU SWITCH_TO_GRAPHICS_MENU -#define CLONE_OPTION(a, b, c, d) -#define ADD_BACK -#define ADD_RESTORE_DEFAULTS(a) -#endif - // -- Graphics/display seperation preperation end - - const wchar* off_on[] = { TheText.Get("FEM_OFF"), TheText.Get("FEM_ON") }; - -#ifdef MORE_LANGUAGES - FrontendOptionSetCursor(MENUPAGE_LANGUAGE_SETTINGS, -2); - FrontendOptionAddDynamic(TheText.Get("FEL_POL"), nil, nil, LangPolSelect, nil); - FrontendOptionAddDynamic(TheText.Get("FEL_RUS"), nil, nil, LangRusSelect, nil); - FrontendOptionAddDynamic(TheText.Get("FEL_JAP"), nil, nil, LangJapSelect, nil); -#endif - -#ifdef MENU_MAP - FrontendOptionSetCursor(MENUPAGE_PAUSE_MENU, 2); - FrontendOptionAddRedirect(TheText.Get("FEG_MAP"), MENUPAGE_MAP); -#endif - - // -- Start of graphics menu - add options in display order! - - SWITCH_TO_GRAPHICS_MENU - CLONE_OPTION(TheText.Get("FED_RES"), MENUACTION_SCREENRES, nil, nil); - CLONE_OPTION(TheText.Get("FED_WIS"), MENUACTION_WIDESCREEN, nil, nil) - -#ifdef IMPROVED_VIDEOMODE - const wchar* screenModes[] = { TheText.Get("FED_FLS"), TheText.Get("FED_WND") }; - // Storing isn't enabled because it's handled in Frontend - FrontendOptionAddSelect(TheText.Get("FEM_SCF"), screenModes, 2, (int8*)&FrontEndMenuManager.m_nPrefsWindowed, true, ScreenModeChange, nil); -#endif - - CLONE_OPTION(TheText.Get("FEM_VSC"), MENUACTION_FRAMESYNC, nil, nil); - CLONE_OPTION(TheText.Get("FEM_FRM"), MENUACTION_FRAMELIMIT, nil, nil); - -#ifdef MULTISAMPLING - SWITCH_TO_GRAPHICS_MENU - FrontendOptionAddDynamic(TheText.Get("FED_AAS"), MultiSamplingDraw, (int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, MultiSamplingButtonPress, MultiSamplingGoBack, multisamplingKey); -#endif - - CLONE_OPTION(TheText.Get("FED_TRA"), MENUACTION_TRAILS, nil, nil); - -#ifdef PS2_ALPHA_TEST - SWITCH_TO_GRAPHICS_MENU - FrontendOptionAddSelect(TheText.Get("FEM_2PR"), off_on, 2, (int8*)&gPS2alphaTest, false, PS2AlphaTestChange, nil, ps2alphaKey); -#endif - - ADD_RESTORE_DEFAULTS(RestoreDefGraphics) - ADD_BACK - - // ---- End of Graphics Menu ---- - - // -- Start of Display menu - add options in display order! - - SWITCH_TO_DISPLAY_MENU - CLONE_OPTION(TheText.Get("FED_BRI"), MENUACTION_BRIGHTNESS, nil, nil); - CLONE_OPTION(TheText.Get("FEM_LOD"), MENUACTION_DRAWDIST, nil, nil); - -#ifdef CUTSCENE_BORDERS_SWITCH - SWITCH_TO_DISPLAY_MENU - FrontendOptionAddSelect(TheText.Get("FEM_CSB"), off_on, 2, (int8 *)&CMenuManager::m_PrefsCutsceneBorders, false, BorderModeChange, nil, cutsceneBordersKey); -#endif - -#ifdef FREE_CAM - SWITCH_TO_DISPLAY_MENU - FrontendOptionAddSelect(TheText.Get("FEC_FRC"), off_on, 2, (int8*)&TheCamera.bFreeCam, false, FreeCamChange, nil, freeCamKey); -#endif - - CLONE_OPTION(TheText.Get("FED_SUB"), MENUACTION_SUBTITLES, nil, nil); - - // Add link to advanced graphics menu if it's filled. -#ifndef GRAPHICS_MENU_OPTIONS - if (movedToAdvMenu) { - FrontendOptionSetCursor(MENUPAGE_DISPLAY_SETTINGS, -3); - FrontendOptionAddRedirect(TheText.Get("FET_ADV"), advancedDisplayMenu, 0); - - FrontendOptionSetCursor(advancedDisplayMenu, -1); - FrontendOptionAddBackButton(TheText.Get("FEDS_TB")); - } -#endif - - ADD_RESTORE_DEFAULTS(RestoreDefDisplay) - ADD_BACK - -#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS - int detectJoystickMenu = FrontendScreenAdd("FEC_JOD", MENUSPRITE_MAINMENU, MENUPAGE_CONTROLLER_PC, 40, 60, 20, - FONT_BANK, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, false); - - FrontendOptionSetCursor(detectJoystickMenu, 0); - - FrontendOptionAddBuiltinAction(TheText.Get("FEC_JPR"), MENUACTION_LABEL, nil, nil); - FrontendOptionAddDynamic(TheText.Get("FEC_JDE"), DetectJoystickDraw, nil, nil, nil); - FrontendOptionAddBackButton(TheText.Get("FEDS_TB")); - - FrontendOptionSetCursor(MENUPAGE_CONTROLLER_PC, 2); - FrontendOptionAddRedirect(TheText.Get("FEC_JOD"), detectJoystickMenu, 1); -#endif + // Moved to an array in MenuScreensCustom.cpp, but APIs are still available. see frontendoption.h } #endif #ifdef LOAD_INI_SETTINGS #include "ini_parser.hpp" + +linb::ini cfg; +int CheckAndReadIniInt(const char *cat, const char *key, int original) +{ + const char *value = (cfg.get(cat, key, "").c_str()); + if (value && value[0] != '\0') + return atoi(value); + + return original; +} + +float CheckAndReadIniFloat(const char *cat, const char *key, float original) +{ + const char *value = (cfg.get(cat, key, "").c_str()); + if (value && value[0] != '\0') + return atof(value); + + return original; +} + void LoadINISettings() { - linb::ini cfg; cfg.load_file("re3.ini"); - char defaultStr[4]; #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS // Written by assuming the codes below will run after _InputInitialiseJoys(). @@ -491,28 +138,43 @@ void LoadINISettings() #endif #ifdef CUSTOM_FRONTEND_OPTIONS - for (int i = 0; i < numCustomFrontendOptions; i++) { - FrontendOption& option = customFrontendOptions[i]; - if (option.save) { - // CFO only supports saving uint8 right now - sprintf(defaultStr, "%u", *option.value); - option.lastSavedValue = option.displayedValue = *option.value = atoi(cfg.get("FrontendOptions", option.save, defaultStr).c_str()); + for (int i = 0; i < MENUPAGES; i++) { + for (int j = 0; j < NUM_MENUROWS; j++) { + CMenuScreenCustom::CMenuEntry &option = aScreens[i].m_aEntries[j]; + if (option.m_Action == MENUACTION_NOTHING) + break; + + // CFO check + if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) { + // CFO only supports saving uint8 right now + *option.m_CFO->value = CheckAndReadIniInt("FrontendOptions", option.m_CFO->save, *option.m_CFO->value); + if (option.m_Action == MENUACTION_CFO_SELECT) { + option.m_CFOSelect->lastSavedValue = option.m_CFOSelect->displayedValue = *option.m_CFO->value; + } + } } } #endif #ifdef NO_ISLAND_LOADING - sprintf(defaultStr, "%u", CMenuManager::m_PrefsIslandLoading); - CMenuManager::m_PrefsIslandLoading = atoi(cfg.get("FrontendOptions", "NoIslandLoading", defaultStr).c_str()); + CMenuManager::m_PrefsIslandLoading = CheckAndReadIniInt("FrontendOptions", "NoIslandLoading", CMenuManager::m_PrefsIslandLoading); CMenuManager::m_DisplayIslandLoading = CMenuManager::m_PrefsIslandLoading; #endif +#ifdef EXTENDED_COLOURFILTER + CPostFX::Intensity = CheckAndReadIniFloat("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity); +#endif +#ifdef EXTENDED_PIPELINES + CustomPipes::VehicleShininess = CheckAndReadIniFloat("CustomPipesValues", "NeoVehicleShininess", CustomPipes::VehicleShininess); + CustomPipes::VehicleSpecularity = CheckAndReadIniFloat("CustomPipesValues", "NeoVehicleSpecularity", CustomPipes::VehicleSpecularity); + CustomPipes::RimlightMult = CheckAndReadIniFloat("CustomPipesValues", "RimlightMult", CustomPipes::RimlightMult); + CustomPipes::LightmapMult = CheckAndReadIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult); + CustomPipes::GlossMult = CheckAndReadIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult); +#endif } void SaveINISettings() { - linb::ini cfg; - cfg.load_file("re3.ini"); bool changed = false; char temp[4]; @@ -523,13 +185,18 @@ void SaveINISettings() } #endif #ifdef CUSTOM_FRONTEND_OPTIONS - for (int i = 0; i < numCustomFrontendOptions; i++) { - FrontendOption &option = customFrontendOptions[i]; - if (option.save) { - if (atoi(cfg.get("FrontendOptions", option.save, "xxx").c_str()) != *option.value) { // if .ini doesn't have that key compare with xxx, so we can add it - changed = true; - sprintf(temp, "%u", *option.value); - cfg.set("FrontendOptions", option.save, temp); + for (int i = 0; i < MENUPAGES; i++) { + for (int j = 0; j < NUM_MENUROWS; j++) { + CMenuScreenCustom::CMenuEntry &option = aScreens[i].m_aEntries[j]; + if (option.m_Action == MENUACTION_NOTHING) + break; + + if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) { + if (atoi(cfg.get("FrontendOptions", option.m_CFO->save, "xxx").c_str()) != *option.m_CFO->value) { // if .ini doesn't have that key compare with xxx, so we can add it + changed = true; + sprintf(temp, "%u", *option.m_CFO->value); + cfg.set("FrontendOptions", option.m_CFO->save, temp); + } } } } @@ -888,9 +555,6 @@ DebugMenuPopulate(void) DebugMenuAddCmd("Debug", "Catalina Fly Away", CHeli::MakeCatalinaHeliFlyAway); DebugMenuAddVarBool8("Debug", "Script Heli On", &CHeli::ScriptHeliOn, nil); -#ifdef CUSTOM_FRONTEND_OPTIONS - DebugMenuAddCmd("Debug", "Reload custom frontend options", ReloadFrontendOptions); -#endif DebugMenuAddVarBool8("Debug", "Toggle popping heads on headshot", &CPed::bPopHeadsOnHeadshot, nil); DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start); DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop); diff --git a/src/extras/frontendoption.cpp b/src/extras/frontendoption.cpp index 88a930a9..a3c4b9e3 100644 --- a/src/extras/frontendoption.cpp +++ b/src/extras/frontendoption.cpp @@ -1,20 +1,14 @@ #include "common.h" #ifdef CUSTOM_FRONTEND_OPTIONS -#include "frontendoption.h" +#include "Frontend.h" #include "Text.h" -int numCustomFrontendOptions = 0; -FrontendOption *customFrontendOptions; - -int numCustomFrontendScreens = 0; -FrontendScreen* customFrontendScreens; - -int numFrontendOptionReplacements = 0; -CMenuScreen::CMenuEntry* frontendOptionReplacements; - int lastOgScreen = MENUPAGES; // means no new pages +int numCustomFrontendOptions = 0; +int numCustomFrontendScreens = 0; + int optionCursor = -2; int currentMenu; bool optionOverwrite = false; @@ -32,8 +26,7 @@ void GoBack(bool fadeIn) { int screen = !FrontEndMenuManager.m_bGameNotLoaded ? aScreens[FrontEndMenuManager.m_nCurrScreen].m_PreviousPage[1] : aScreens[FrontEndMenuManager.m_nCurrScreen].m_PreviousPage[0]; - int option = !FrontEndMenuManager.m_bGameNotLoaded ? - aScreens[FrontEndMenuManager.m_nCurrScreen].m_ParentEntry[1] : aScreens[FrontEndMenuManager.m_nCurrScreen].m_ParentEntry[0]; + int option = FrontEndMenuManager.GetPreviousPageOption(); FrontEndMenuManager.ThingsToDoBeforeGoingBack(); @@ -58,7 +51,7 @@ GetLastMenuScreen() { int8 page = -1; for (int i = 0; i < MENUPAGES; i++) { - if (strcmp(aScreens[i].m_ScreenName, "") == 0 && aScreens[i].unk == 0) + if (strcmp(aScreens[i].m_ScreenName, "") == 0 && aScreens[i].m_PreviousPage[0] == MENUPAGE_NONE) break; ++page; @@ -66,89 +59,23 @@ GetLastMenuScreen() return page; } -// Used before populating options, but effective in InitialiseChangedLanguageSettings and debugmenu -void -RemoveCustomFrontendOptions() -{ - if (numCustomFrontendOptions != 0) { - - for (int i = 0; i < MENUPAGES; i++) { - for (int j = 0; j < NUM_MENUROWS; j++) { - if (aScreens[i].m_aEntries[j].m_SaveSlot == SAVESLOT_CFO) { - int ogOptionId = customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].ogOptionId; - - if (customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].type == FEOPTION_SELECT) - free(customFrontendOptions[aScreens[i].m_aEntries[j].m_TargetMenu].rightTexts); - - if (ogOptionId == -1) { - int k; - for (k = j; k < NUM_MENUROWS - 1; k++) { - memcpy(&aScreens[i].m_aEntries[k], &aScreens[i].m_aEntries[k + 1], sizeof(CMenuScreen::CMenuEntry)); - } - aScreens[i].m_aEntries[k].m_Action = MENUACTION_NOTHING; - aScreens[i].m_aEntries[k].m_SaveSlot = SAVESLOT_NONE; - aScreens[i].m_aEntries[k].m_EntryName[0] = '\0'; - j--; - } else { - memcpy(&aScreens[i].m_aEntries[j], &frontendOptionReplacements[ogOptionId], sizeof(CMenuScreen::CMenuEntry)); - } - } - } - } - free(customFrontendOptions); - numCustomFrontendOptions = 0; - - if (numFrontendOptionReplacements != 0) { - free(frontendOptionReplacements); - numFrontendOptionReplacements = 0; - } - } - - if (numCustomFrontendScreens == 0) - return; - - for (int i = 0; i < MENUPAGES; i++) { - if (i > lastOgScreen) { - aScreens[i].m_ScreenName[0] = '\0'; - aScreens[i].unk = 0; - } - } - free(customFrontendScreens); - numCustomFrontendScreens = 0; - lastOgScreen = MENUPAGES; -} - -int8 RegisterNewScreen(const char *name, int prevPage) +int8 RegisterNewScreen(const char *name, int prevPage, ReturnPrevPageFunc returnPrevPageFunc) { if (lastOgScreen == MENUPAGES) lastOgScreen = GetLastMenuScreen(); numCustomFrontendScreens++; - if (numCustomFrontendScreens == 1) - customFrontendScreens = (FrontendScreen*)malloc(5 * sizeof(FrontendScreen)); - else if (numCustomFrontendScreens % 5 == 1) - customFrontendScreens = (FrontendScreen*)realloc(customFrontendScreens, (numCustomFrontendScreens + 4) * sizeof(FrontendScreen)); - - assert(customFrontendScreens != nil && "Custom frontend screens can't be allocated"); - int id = lastOgScreen + numCustomFrontendScreens; assert(id < MENUPAGES && "No room for new custom frontend screens! Increase MENUPAGES"); strncpy(aScreens[id].m_ScreenName, name, 8); aScreens[id].m_PreviousPage[0] = aScreens[id].m_PreviousPage[1] = prevPage; - aScreens[id].unk = 1; + aScreens[id].returnPrevPageFunc = returnPrevPageFunc; return id; } int8 RegisterNewOption() { numCustomFrontendOptions++; - if (numCustomFrontendOptions == 1) - customFrontendOptions = (FrontendOption*)malloc(5 * sizeof(FrontendOption)); - else if (numCustomFrontendOptions % 5 == 1) - customFrontendOptions = (FrontendOption*)realloc(customFrontendOptions, (numCustomFrontendOptions + 4) * sizeof(FrontendOption)); - - assert(customFrontendOptions != nil && "Custom frontend options can't be allocated"); - uint8 numOptions = GetNumberOfMenuOptions(currentMenu); uint8 curIdx; if (optionCursor < 0) { @@ -159,30 +86,11 @@ int8 RegisterNewOption() if (!optionOverwrite) { if (aScreens[currentMenu].m_aEntries[curIdx].m_Action != MENUACTION_NOTHING) { for (int i = numOptions - 1; i >= curIdx; i--) { - memcpy(&aScreens[currentMenu].m_aEntries[i + 1], &aScreens[currentMenu].m_aEntries[i], sizeof(CMenuScreen::CMenuEntry)); + memcpy(&aScreens[currentMenu].m_aEntries[i + 1], &aScreens[currentMenu].m_aEntries[i], sizeof(CMenuScreenCustom::CMenuEntry)); } } } optionCursor++; - - if (optionOverwrite) { - numFrontendOptionReplacements++; - if (numFrontendOptionReplacements == 1) - frontendOptionReplacements = (CMenuScreen::CMenuEntry*)malloc(5 * sizeof(CMenuScreen::CMenuEntry)); - else if (numFrontendOptionReplacements % 5 == 1) - frontendOptionReplacements = (CMenuScreen::CMenuEntry*)realloc(frontendOptionReplacements, (numFrontendOptionReplacements + 4) * sizeof(CMenuScreen::CMenuEntry)); - - memcpy(&frontendOptionReplacements[numFrontendOptionReplacements - 1], &aScreens[currentMenu].m_aEntries[curIdx], sizeof(CMenuScreen::CMenuEntry)); - customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = numFrontendOptionReplacements - 1; - } else { - customFrontendOptions[numCustomFrontendOptions - 1].ogOptionId = -1; - } - customFrontendOptions[numCustomFrontendOptions - 1].screen = currentMenu; - - aScreens[currentMenu].m_aEntries[curIdx].m_Action = MENUACTION_TRIGGERFUNC; - aScreens[currentMenu].m_aEntries[curIdx].m_SaveSlot = SAVESLOT_CFO; - aScreens[currentMenu].m_aEntries[curIdx].m_TargetMenu = numCustomFrontendOptions - 1; - aScreens[currentMenu].m_aEntries[curIdx].m_EntryName[0] = 1; // just something to fool it return curIdx; } @@ -193,110 +101,78 @@ void FrontendOptionSetCursor(int screen, int8 option, bool overwrite) optionOverwrite = overwrite; } -void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc) { +void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMenu, int saveSlot) { int8 screenOptionOrder = RegisterNewOption(); - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; + CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder]; - // To fool the Frontend, we will still display the text passed via first param. + // We can't use custom text on those :shrug: switch (action) { case MENUACTION_SCREENRES: - strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FED_RES"); + strcpy(option.m_EntryName, "FED_RES"); break; case MENUACTION_AUDIOHW: - strcpy(aScreens[currentMenu].m_aEntries[screenOptionOrder].m_EntryName, "FEA_3DH"); + strcpy(option.m_EntryName, "FEA_3DH"); + break; + default: + strncpy(option.m_EntryName, gxtKey, 8); break; } - aScreens[currentMenu].m_aEntries[screenOptionOrder].m_Action = action; - option.type = FEOPTION_BUILTIN_ACTION; - option.buttonPressFunc = buttonPressFunc; - TextCopy(option.leftText, leftText); - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = returnPrevPageFunc; - option.save = nil; + option.m_Action = action; + option.m_SaveSlot = saveSlot; + option.m_TargetMenu = targetMenu; } -void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName) +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName) +{ + int8 screenOptionOrder = RegisterNewOption(); + + CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder]; + option.m_Action = MENUACTION_CFO_SELECT; + strncpy(option.m_EntryName, gxtKey, 8); + option.m_CFOSelect = new CCFOSelect(); + option.m_CFOSelect->rightTexts = (char**)malloc(numRightTexts * sizeof(char*)); + memcpy(option.m_CFOSelect->rightTexts, rightTexts, numRightTexts * sizeof(char*)); + option.m_CFOSelect->numRightTexts = numRightTexts; + option.m_CFOSelect->value = var; + if (var) { + option.m_CFOSelect->displayedValue = *var; + option.m_CFOSelect->lastSavedValue = *var; + } + option.m_CFOSelect->save = saveName; + option.m_CFOSelect->onlyApplyOnEnter = onlyApplyOnEnter; + option.m_CFOSelect->changeFunc = changeFunc; +} + +void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName) { int8 screenOptionOrder = RegisterNewOption(); - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_SELECT; - TextCopy(option.leftText, leftText); - option.rightTexts = (wchar**)malloc(numRightTexts * sizeof(wchar*)); - memcpy(option.rightTexts, rightTexts, numRightTexts * sizeof(wchar*)); - option.numRightTexts = numRightTexts; - option.value = var; - option.displayedValue = *var; - option.lastSavedValue = *var; - option.save = saveName; - option.onlyApplyOnEnter = onlyApplyOnEnter; - option.changeFunc = changeFunc; - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = returnPrevPageFunc; -} - -void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName) -{ - int8 screenOptionOrder = RegisterNewOption(); - - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_DYNAMIC; - option.drawFunc = drawFunc; - option.buttonPressFunc = buttonPressFunc; - TextCopy(option.leftText, leftText); - option.value = var; - option.save = saveName; - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = returnPrevPageFunc; -} - -void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption, bool fadeIn) -{ - int8 screenOptionOrder = RegisterNewOption(); - - FrontendOption &option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_REDIRECT; - option.to = to; - option.option = selectedOption; - option.fadeIn = fadeIn; - TextCopy(option.leftText, text); - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = nil; - option.save = nil; -} - -void FrontendOptionAddBackButton(const wchar* text, bool fadeIn) -{ - int8 screenOptionOrder = RegisterNewOption(); - - FrontendOption& option = customFrontendOptions[numCustomFrontendOptions - 1]; - option.type = FEOPTION_GOBACK; - option.fadeIn = fadeIn; - TextCopy(option.leftText, text); - option.screenOptionOrder = screenOptionOrder; - option.returnPrevPageFunc = nil; - option.save = nil; + CMenuScreenCustom::CMenuEntry &option = aScreens[currentMenu].m_aEntries[screenOptionOrder]; + option.m_Action = MENUACTION_CFO_DYNAMIC; + strncpy(option.m_EntryName, gxtKey, 8); + option.m_CFODynamic = new CCFODynamic(); + option.m_CFODynamic->drawFunc = drawFunc; + option.m_CFODynamic->buttonPressFunc = buttonPressFunc; + option.m_CFODynamic->value = var; + option.m_CFODynamic->save = saveName; } uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc) { - uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage); + uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage, returnPrevPageFunc); - FrontendScreen &screen = customFrontendScreens[numCustomFrontendScreens - 1]; - screen.id = screenOrder; - screen.sprite = sprite; - screen.prevPage = prevPage; - strncpy(screen.name, gxtKey, 8); - screen.columnWidth = columnWidth; - screen.headerHeight = headerHeight; - screen.lineHeight = lineHeight; - screen.font = font; - screen.fontScaleX = fontScaleX; - screen.fontScaleY = fontScaleY; - screen.alignment = alignment; - screen.returnPrevPageFunc = returnPrevPageFunc; + CCustomScreenLayout *screen = new CCustomScreenLayout(); + aScreens[screenOrder].layout = screen; + screen->sprite = sprite; + screen->columnWidth = columnWidth; + screen->headerHeight = headerHeight; + screen->lineHeight = lineHeight; + screen->font = font; + screen->fontScaleX = fontScaleX; + screen->fontScaleY = fontScaleY; + screen->alignment = alignment; return screenOrder; } diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h index dac6be62..19340b20 100644 --- a/src/extras/frontendoption.h +++ b/src/extras/frontendoption.h @@ -2,47 +2,23 @@ #include "common.h" #ifdef CUSTOM_FRONTEND_OPTIONS -#include "Frontend.h" - -// Warning: -// All of the code relies on that you won't use more then NUM_MENUROWS(18) options on one page. -// Also congrats if you can make 18 options visible at once. - -// About texts: -// All text parameters accept wchar(including hardcoded wchar* and TheText.Get) -// except FrontendScreenAdd(it's char[8] GXT key by the design of Frontend). -// All texts reload if custom options reloaded too, which includes language changes and via live reload feature in debug menu! - -// Execute direction: -// All of the calls below eventually manipulate the aScreens array, so keep in mind to add/replace options in order, -// i.e. don't set cursor to 8 first and then 3. - -// Live reload: -// You can add/change/undo the new options in-game if you use VS. Change what you want, build the changed bits via "Edit and Continue", -// and hit the "Reload custom frontend options" from debug menu. Or call CustomFrontendOptionsPopulate() from somewhere else. +// ! There are 2 ways to use CFO, +// 1st; by adding a new option to the array in MenuScreensCustom.cpp and passing attributes/CBs to it +// 2nd; by calling the functions listed at the bottom of this file. // -- Option types // // Static/select: You allocate the variable, pass it to function and game sets it from user input among the strings given to function, -// then you can handle ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately) -// and ReturnPrevPageFunc optionally. You can store the option in an INI file if you pass the key(as a char array) to corresponding parameter. +// optionally you can add post-change event via ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately) +// You can store the option in an INI file if you pass the key(as a char array) to corresponding parameter. // // Dynamic: Passing variable to function is only needed if you want to store it, otherwise you should do // all the operations with ButtonPressFunc, this includes allocating the variable. // Left-side text is passed while creating and static, but ofc right-side text is dynamic - -// you should return it in DrawFunc, which is called on every draw. ReturnPrevPageFunc is also here if needed. -// -// Redirect: Redirection to another screen. selectedOption parameter is the highlighted option user will see after the redirection. +// you should return it in DrawFunc, which is called on every draw. // // Built-in action: As the name suggests, any action that game has built-in. But as an extra you can set the option text, -// and can be informed on button press/focus loss via buttonPressFunc. ReturnPrevPageFunc is also here. - -#define FEOPTION_SELECT 0 -#define FEOPTION_DYNAMIC 1 -#define FEOPTION_REDIRECT 2 -#define FEOPTION_GOBACK 3 -#define FEOPTION_BUILTIN_ACTION 4 // -- Returned via ButtonPressFunc() action param. #define FEOPTION_ACTION_LEFT 0 @@ -61,7 +37,7 @@ typedef void (*ReturnPrevPageFunc)(); // for static options -typedef void (*ChangeFunc)(int8 displayedValue); // called before updating the value. +typedef void (*ChangeFunc)(int8 before, int8 after); // called after updating the value. // only called on enter if onlyApplyOnEnter set, otherwise called on every value change // for dynamic options @@ -69,71 +45,11 @@ typedef wchar* (*DrawFunc)(bool* disabled, bool userHovering); // you must retur // you can also set *disabled if you want to gray it out. typedef void (*ButtonPressFunc)(int8 action); // see FEOPTION_ACTIONs above -struct FrontendScreen -{ - int id; - char name[8]; - eMenuSprites sprite; - int prevPage; - int columnWidth; - int headerHeight; - int lineHeight; - int8 font; - float fontScaleX; - float fontScaleY; - int8 alignment; - bool showLeftRightHelper; - ReturnPrevPageFunc returnPrevPageFunc; -}; - -struct FrontendOption -{ - int8 type; - int8 screenOptionOrder; - int32 screen; - wchar leftText[128]; - ReturnPrevPageFunc returnPrevPageFunc; - int8* value; - int8 displayedValue; // only if onlyApplyOnEnter enabled for now - const char* save; - int32 ogOptionId; // for replacements, see overwrite parameter of SetCursor - - union { - // Only for dynamic / built-in action - struct { - DrawFunc drawFunc; - ButtonPressFunc buttonPressFunc; - }; - - // Only for static/select - struct { - wchar** rightTexts; - int8 numRightTexts; - bool onlyApplyOnEnter; - ChangeFunc changeFunc; - int8 lastSavedValue; // only if onlyApplyOnEnter enabled - }; - - // Only for redirect - struct { - int to; - int8 option; - bool fadeIn; - }; - }; -}; - // -- Internal things -void RemoveCustomFrontendOptions(); void CustomFrontendOptionsPopulate(); - extern int lastOgScreen; // for reloading - extern int numCustomFrontendOptions; -extern FrontendOption* customFrontendOptions; - extern int numCustomFrontendScreens; -extern FrontendScreen* customFrontendScreens; // -- To be used in ButtonPressFunc / ChangeFunc(this one would be weird): void ChangeScreen(int screen, int option = 0, bool fadeIn = true); @@ -141,6 +57,21 @@ void GoBack(bool fadeIn = true); uint8 GetNumberOfMenuOptions(int screen); +// !!! We're now moved to MenuScreensCustom.cpp, which houses an array that keeps all original+custom options. +// But you can still use the APIs below, and manipulate aScreens while in game. + +// Limits: +// The code relies on that you won't use more then NUM_MENUROWS(18) options on one page, and won't exceed the MENUPAGES of pages. +// Also congrats if you can make 18 options visible at once. + +// Texts: +// All text parameters accept char[8] GXT key. + +// Execute direction: +// All of the calls below eventually manipulate the aScreens array, so keep in mind to add/replace options in order, +// i.e. don't set cursor to 8 first and then 3. + + // -- Placing the cursor to append/overwrite option // // Done via FrontendOptionSetCursor(screen, position, overwrite = false), parameters explained below: @@ -152,11 +83,9 @@ uint8 GetNumberOfMenuOptions(int screen); void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false); // var is optional in AddDynamic, enables you to save them in an INI file(also needs passing char array to saveName param. obv), otherwise pass nil/0 -void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc); -void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil); -void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil); -void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption = 0, bool fadeIn = true); -void FrontendOptionAddBackButton(const wchar* text, bool fadeIn = true); +void FrontendOptionAddBuiltinAction(const char* gxtKey, int action, int targetMenu = MENUPAGE_NONE, int saveSlot = SAVESLOT_NONE); +void FrontendOptionAddSelect(const char* gxtKey, const char** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, const char* saveName = nil); +void FrontendOptionAddDynamic(const char* gxtKey, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, const char* saveName = nil); uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc = nil); #endif From e95516032f4e44ea35b7358f60c464c0faa1df91 Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 29 Oct 2020 19:01:09 +0100 Subject: [PATCH 009/129] fix FINAL build, add DEBUGMENU and other simple qol defines to FINAL, add extra defines for menu and game version text --- src/core/Frontend.cpp | 2 ++ src/core/config.h | 24 ++++++++++++++++++++---- src/core/main.cpp | 3 +++ src/rw/RwHelper.cpp | 6 ++++-- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 89b5ba3d..5c65aed5 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -789,9 +789,11 @@ CMenuManager::Draw() CFont::SetScale(MENU_X(0.7f), MENU_Y(0.5f)); CFont::SetWrapx(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); CFont::SetRightJustifyWrap(0.0f); +#ifdef DRAW_MENU_VERSION_TEXT strcpy(gString, "V1.1"); AsciiToUnicode(gString, gUString); CFont::PrintString(SCREEN_WIDTH / 10, SCREEN_HEIGHT / 45, gUString); +#endif #endif CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN)); CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH)); diff --git a/src/core/config.h b/src/core/config.h index 171c6be9..92c0511f 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -156,6 +156,25 @@ enum Config { // any debug stuff that is only left in mobile, is not in MASTER //#define MASTER +// once and for all: +// pc: FINAL & MASTER +// mobile: FINAL + +// MASTER builds must be FINAL +#ifdef MASTER +#define FINAL +#endif + +// quality of life fixes that should also be in FINAL +#define NASTY_GAME // nasty game for all languages +#define NO_MOVIES // disable intro videos +#define NO_CDCHECK +#define DEBUGMENU + +// those infamous texts +#define DRAW_GAME_VERSION_TEXT +#define DRAW_MENU_VERSION_TEXT + #if defined GTA_PS2 # define GTA_PS2_STUFF # define RANDOMSPLASH @@ -177,6 +196,7 @@ enum Config { #ifdef MASTER // only in master builds + #undef DRAW_GAME_VERSION_TEXT #else // not in master builds #define VALIDATE_SAVE_SIZE @@ -187,11 +207,7 @@ enum Config { # define USE_MY_DOCUMENTS // use my documents directory for user files #else // not in any game -# define NASTY_GAME // nasty game for all languages -# define NO_MOVIES // disable intro videos -# define NO_CDCHECK # define CHATTYSPLASH // print what the game is loading -# define DEBUGMENU # define TIMEBARS // print debug timers #endif diff --git a/src/core/main.cpp b/src/core/main.cpp index 18ee2dc5..1aa0a953 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -768,6 +768,8 @@ DisplayGameDebugText() char str[200]; wchar ustr[200]; + +#ifdef DRAW_GAME_VERSION_TEXT wchar ver[200]; AsciiToUnicode(version_name, ver); @@ -783,6 +785,7 @@ DisplayGameDebugText() CFont::SetBackGroundOnlyTextOff(); CFont::SetColor(CRGBA(255, 108, 0, 255)); CFont::PrintString(SCREEN_SCALE_X(10.0f), SCREEN_SCALE_Y(10.0f), ver); +#endif FrameSamples++; FramesPerSecondCounter += 1000.0f / (CTimer::GetTimeStepNonClippedInSeconds() * 1000.0f); diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index 4b598e9b..dbadae6a 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -6,8 +6,10 @@ #include "Timecycle.h" #include "skeleton.h" #include "Debug.h" -#ifndef FINAL +#if !defined(FINAL) || defined(DEBUGMENU) #include "rtcharse.h" +#endif +#ifndef FINAL RtCharset *debugCharset; #endif @@ -17,7 +19,7 @@ bool gPS2alphaTest = true; bool gPS2alphaTest = false; #endif -#ifndef FINAL +#if !defined(FINAL) || defined(DEBUGMENU) static bool charsetOpen; void OpenCharsetSafe() { From 57b01ac4769b0ac83150f2284f5bad87f2f166a3 Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 29 Oct 2020 19:23:59 +0100 Subject: [PATCH 010/129] NO_MOVIES and DEBUGMENU not for MASTER --- src/core/config.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/config.h b/src/core/config.h index 92c0511f..019ff659 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -167,9 +167,7 @@ enum Config { // quality of life fixes that should also be in FINAL #define NASTY_GAME // nasty game for all languages -#define NO_MOVIES // disable intro videos #define NO_CDCHECK -#define DEBUGMENU // those infamous texts #define DRAW_GAME_VERSION_TEXT @@ -200,6 +198,9 @@ enum Config { #else // not in master builds #define VALIDATE_SAVE_SIZE + + #define NO_MOVIES // disable intro videos + #define DEBUGMENU #endif #ifdef FINAL From d34d591ed36557d88d2d0485965e7f7337ed25de Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 29 Oct 2020 19:53:23 +0100 Subject: [PATCH 011/129] fix draw menu version text ifdef location --- src/core/Frontend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 5c65aed5..dca9685e 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -783,13 +783,13 @@ CMenuManager::Draw() CFont::SetJustifyOn(); CFont::SetBackGroundOnlyTextOn(); #ifdef GTA3_1_1_PATCH +#ifdef DRAW_MENU_VERSION_TEXT CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); CFont::SetRightJustifyOn(); CFont::SetFontStyle(FONT_HEADING); CFont::SetScale(MENU_X(0.7f), MENU_Y(0.5f)); CFont::SetWrapx(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); CFont::SetRightJustifyWrap(0.0f); -#ifdef DRAW_MENU_VERSION_TEXT strcpy(gString, "V1.1"); AsciiToUnicode(gString, gUString); CFont::PrintString(SCREEN_WIDTH / 10, SCREEN_HEIGHT / 45, gUString); From 7784ba052e3c5ea4aced693695e38caab825e053 Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 30 Oct 2020 17:24:20 +0300 Subject: [PATCH 012/129] Update config.h --- src/core/config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/config.h b/src/core/config.h index efb09222..171c6be9 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -210,8 +210,8 @@ enum Config { #define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU //#define USE_TEXTURE_POOL #define CUTSCENE_BORDERS_SWITCH -#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) -#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) +//#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) +//#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) #define MULTISAMPLING // adds MSAA option #ifdef LIBRW From ded7c8960201b3df2a5682a5347fefa9af851f49 Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 30 Oct 2020 17:36:13 +0300 Subject: [PATCH 013/129] Update MenuScreensCustom.cpp --- src/core/MenuScreensCustom.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index e2516140..25831486 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -49,24 +49,24 @@ #ifdef EXTENDED_COLOURFILTER #define POSTFX_SELECTORS \ - MENUACTION_CFO_SELECT, "VEHPIPE", { new CCFOSelect((int8*)&CustomPipes::VehiclePipeSwitch, "VehiclePipeline", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), false, nil) }, \ - MENUACTION_CFO_SELECT, "RIM", { new CCFOSelect((int8*)&CustomPipes::RimlightEnable, "NeoRimLight", off_on, 2, false, nil) }, \ - MENUACTION_CFO_SELECT, "LGTMAPS", { new CCFOSelect((int8*)&CustomPipes::LightmapEnable, "NeoLightMaps", off_on, 2, false, nil) }, \ - MENUACTION_CFO_SELECT, "GLOSS", { new CCFOSelect((int8*)&CustomPipes::GlossEnable, "NeoRoadGloss", off_on, 2, false, nil) }, + MENUACTION_CFO_SELECT, "FED_VPL", { new CCFOSelect((int8*)&CustomPipes::VehiclePipeSwitch, "VehiclePipeline", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_PRM", { new CCFOSelect((int8*)&CustomPipes::RimlightEnable, "NeoRimLight", off_on, 2, false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_WLM", { new CCFOSelect((int8*)&CustomPipes::LightmapEnable, "NeoLightMaps", off_on, 2, false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_RGL", { new CCFOSelect((int8*)&CustomPipes::GlossEnable, "NeoRoadGloss", off_on, 2, false, nil) }, #else #define POSTFX_SELECTORS #endif #ifdef EXTENDED_PIPELINES #define PIPELINES_SELECTOR \ - MENUACTION_CFO_SELECT, "CLRFLTR", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false, nil) }, \ - MENUACTION_CFO_SELECT, "MBLUR", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false, nil) }, + MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_MBL", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false, nil) }, #else #define PIPELINES_SELECTOR #endif -const char *filterNames[] = { "None", "Simple", "Normal", "Mobile" }; -const char *vehPipelineNames[] = { "MatFX", "Neo" }; +const char *filterNames[] = { "FEM_NON", "FEM_SIM", "FEM_NRM", "FEM_MOB" }; +const char *vehPipelineNames[] = { "FED_MFX", "FED_NEO" }; const char *off_on[] = { "FEM_OFF", "FEM_ON" }; void RestoreDefGraphics(int8 action) { From 30c0f26f171b96443b9f897c816450a281cf216c Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 31 Oct 2020 22:09:43 +0100 Subject: [PATCH 014/129] fix sniper crosshair --- src/render/Hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 83c493bb..3d6e59f6 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -247,7 +247,7 @@ void CHud::Draw() rect.right = SCREEN_WIDTH/2 + SCREEN_SCALE_X(210.0f); rect.bottom = SCREEN_HEIGHT/2 + SCREEN_SCALE_Y(210.0f); Sprites[HUD_SITESNIPER].Draw(CRect(rect), CRGBA(255, 255, 255, 255), - 0.99f, 0.99f, 0.01f, 0.99f, 0.99f, 0.01f, 0.1f, 0.01f); + 0.99f, 0.99f, 0.01f, 0.99f, 0.99f, 0.01f, 0.01f, 0.01f); } } RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void *)rwFILTERLINEAR); From f73450f5418714ffdaf219ab43e159187e10adac Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 1 Nov 2020 00:49:42 +0100 Subject: [PATCH 015/129] enable static runtime for all windows builds; fast floating point for x86/x64 builds; no sized dealloc for windows builds --- premake5.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/premake5.lua b/premake5.lua index b5b885b3..6bdb6f32 100644 --- a/premake5.lua +++ b/premake5.lua @@ -122,9 +122,11 @@ workspace "re3" filter { "platforms:*x86*" } architecture "x86" + floatingpoint "Fast" filter { "platforms:*amd64*" } architecture "amd64" + floatingpoint "Fast" filter { "platforms:*arm*" } architecture "ARM" @@ -143,6 +145,7 @@ workspace "re3" filter "platforms:*librw_gl3_glfw*" defines { "RW_GL3" } + staticruntime "Off" includedirs { path.join(_OPTIONS["glewdir"], "include") } if(not _OPTIONS["with-librw"]) then libdirs { path.join(Librw, "lib/%{getsys(cfg.system)}-%{getarch(cfg.architecture)}-gl3/%{cfg.buildcfg}") } @@ -184,6 +187,18 @@ project "librw" files { path.join(Librw, "src/*.*") } files { path.join(Librw, "src/*/*.*") } + filter { "platforms:*x86*" } + architecture "x86" + floatingpoint "Fast" + + filter { "platforms:*amd64*" } + architecture "amd64" + floatingpoint "Fast" + + filter "platforms:win*" + staticruntime "on" + buildoptions { "/Zc:sizedDealloc-" } + filter "platforms:bsd*" includedirs { "/usr/local/include" } libdirs { "/usr/local/lib" } @@ -194,6 +209,9 @@ project "librw" includedirs {"/usr/local/include" } libdirs { "/opt/local/lib" } libdirs { "/usr/local/lib" } + + filter "platforms:*librw_gl3_glfw*" + staticruntime "Off" filter "platforms:*RW33*" flags { "ExcludeFromBuild" } @@ -284,9 +302,11 @@ project "re3" filter "platforms:win*" files { addSrcFiles("src/skel/win") } includedirs { "src/skel/win" } + buildoptions { "/Zc:sizedDealloc-" } linkoptions "/SAFESEH:NO" characterset ("MBCS") targetextension ".exe" + staticruntime "on" filter "platforms:win*oal" includedirs { "vendor/openal-soft/include" } @@ -322,7 +342,6 @@ project "re3" end filter "platforms:*RW33*" - staticruntime "on" includedirs { "sdk/rwsdk/include/d3d8" } libdirs { "sdk/rwsdk/lib/d3d8/release" } links { "rwcore", "rpworld", "rpmatfx", "rpskin", "rphanim", "rtbmp", "rtquat", "rtcharse" } From e9735f928f2c7c0675ef8ac2881da380f390576e Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 1 Nov 2020 01:09:46 +0100 Subject: [PATCH 016/129] add ifdef LIBRW guard for pipelines and colourfilter --- src/core/config.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/config.h b/src/core/config.h index 019ff659..7022fcc9 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -227,8 +227,10 @@ enum Config { #define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU //#define USE_TEXTURE_POOL #define CUTSCENE_BORDERS_SWITCH +#ifdef LIBRW //#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) //#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) +#endif #define MULTISAMPLING // adds MSAA option #ifdef LIBRW From db7c3bda7d13a01a3bee48b6a195a772d06e3c82 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 1 Nov 2020 01:17:14 +0100 Subject: [PATCH 017/129] disable static runtime for glfw --- premake5.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/premake5.lua b/premake5.lua index 6bdb6f32..b8ab1491 100644 --- a/premake5.lua +++ b/premake5.lua @@ -145,7 +145,6 @@ workspace "re3" filter "platforms:*librw_gl3_glfw*" defines { "RW_GL3" } - staticruntime "Off" includedirs { path.join(_OPTIONS["glewdir"], "include") } if(not _OPTIONS["with-librw"]) then libdirs { path.join(Librw, "lib/%{getsys(cfg.system)}-%{getarch(cfg.architecture)}-gl3/%{cfg.buildcfg}") } @@ -210,8 +209,8 @@ project "librw" libdirs { "/opt/local/lib" } libdirs { "/usr/local/lib" } - filter "platforms:*librw_gl3_glfw*" - staticruntime "Off" + filter "platforms:*gl3_glfw*" + staticruntime "off" filter "platforms:*RW33*" flags { "ExcludeFromBuild" } @@ -307,6 +306,9 @@ project "re3" characterset ("MBCS") targetextension ".exe" staticruntime "on" + + filter "platforms:win*glfw*" + staticruntime "off" filter "platforms:win*oal" includedirs { "vendor/openal-soft/include" } From 3c4f166a82d5760849e0f8a02c28a46d734a6c6d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 09:20:37 +0200 Subject: [PATCH 018/129] Fix virtual SetModelIndex call in CBoat ctor --- src/vehicles/Boat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index dfe9d1d9..a33b9770 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -48,7 +48,7 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner) m_fSteeringLeftRight = 0.0f; m_nPadID = 0; m_fMovingRotation = 0.0f; - SetModelIndex(mi); + CBoat::SetModelIndex(mi); pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)minfo->m_handlingId); minfo->ChooseVehicleColour(m_currentColour1, m_currentColour2); From 5711251b0fcf3333c2f96b48dd784fe4c6e1ba25 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 09:46:02 +0200 Subject: [PATCH 019/129] Also fix SetModelIndex in CAutomobile and CTrain ctors --- src/vehicles/Automobile.cpp | 2 +- src/vehicles/Train.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 95a68769..a1c38d21 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -73,7 +73,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) bBigWheels = false; bWaterTight = false; - SetModelIndex(id); + CAutomobile::SetModelIndex(id); pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp index 26d0dee7..98d522a7 100644 --- a/src/vehicles/Train.cpp +++ b/src/vehicles/Train.cpp @@ -44,7 +44,7 @@ CTrain::CTrain(int32 id, uint8 CreatedBy) CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id); m_vehType = VEHICLE_TYPE_TRAIN; pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); - SetModelIndex(id); + CTrain::SetModelIndex(id); Doors[0].Init(0.8f, 0.0f, 1, 0); Doors[1].Init(-0.8f, 0.0f, 0, 0); From f21cfef8fb92a0923c6ddfa26124cf6da1fa883c Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sun, 1 Nov 2020 12:33:16 +0300 Subject: [PATCH 020/129] remove autosave at end of mission under MISSION_REPLAY --- src/control/Script.cpp | 2 ++ vendor/ogg | 2 +- vendor/opusfile | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 6bde6b87..86595bbd 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -2696,8 +2696,10 @@ int8 CRunningScript::ProcessCommands0To99(int32 command) #ifdef MISSION_REPLAY if (m_bMissionFlag) { CPlayerInfo* pPlayerInfo = &CWorld::Players[CWorld::PlayerInFocus]; +#if 0 // makeing autosave is pointless and is a bit buggy if (pPlayerInfo->m_pPed->GetPedState() != PED_DEAD && pPlayerInfo->m_WBState == WBSTATE_PLAYING && !m_bDeatharrestExecuted) SaveGameForPause(1); +#endif oldTargetX = oldTargetY = 0.0f; if (AllowMissionReplay == 1) AllowMissionReplay = 2; diff --git a/vendor/ogg b/vendor/ogg index 684c7377..36f969bb 160000 --- a/vendor/ogg +++ b/vendor/ogg @@ -1 +1 @@ -Subproject commit 684c73773e7e2683245ffd6aa75f04115b51123a +Subproject commit 36f969bb37559345ee03796ed625a9abd42c6db9 diff --git a/vendor/opusfile b/vendor/opusfile index f94a1764..4174c26e 160000 --- a/vendor/opusfile +++ b/vendor/opusfile @@ -1 +1 @@ -Subproject commit f94a1764b0dcdd84ee8c13c040de9f4c1a67e4df +Subproject commit 4174c26e0aaab19d01afdea0a46f7f95fdc6b3e6 From 1f5a6dab67d37af7e3686e29fc81d0f8e5bb5597 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 12:30:23 +0200 Subject: [PATCH 021/129] Revert --- src/vehicles/Automobile.cpp | 2 +- src/vehicles/Boat.cpp | 2 +- src/vehicles/Train.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index a1c38d21..95a68769 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -73,7 +73,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) bBigWheels = false; bWaterTight = false; - CAutomobile::SetModelIndex(id); + SetModelIndex(id); pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index a33b9770..dfe9d1d9 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -48,7 +48,7 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner) m_fSteeringLeftRight = 0.0f; m_nPadID = 0; m_fMovingRotation = 0.0f; - CBoat::SetModelIndex(mi); + SetModelIndex(mi); pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)minfo->m_handlingId); minfo->ChooseVehicleColour(m_currentColour1, m_currentColour2); diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp index 98d522a7..26d0dee7 100644 --- a/src/vehicles/Train.cpp +++ b/src/vehicles/Train.cpp @@ -44,7 +44,7 @@ CTrain::CTrain(int32 id, uint8 CreatedBy) CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id); m_vehType = VEHICLE_TYPE_TRAIN; pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); - CTrain::SetModelIndex(id); + SetModelIndex(id); Doors[0].Init(0.8f, 0.0f, 1, 0); Doors[1].Init(-0.8f, 0.0f, 0, 0); From 37943a87cbafcc0a0ad0a4a5b05a20e48ddf72de Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 13:42:02 +0200 Subject: [PATCH 022/129] Show Xbox buttons when playing with a controller --- src/core/ControllerConfig.cpp | 408 ++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index 576a58b1..1af29a85 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2316,8 +2316,416 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act return num; } +const char *XboxButtons[][MAX_CONTROLLERACTIONS] = +{ + { + "B", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "X", // PED_SNIPER_ZOOM_IN + "A", // PED_SNIPER_ZOOM_OUT + "Y", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "A", // PED_SPRINT + "RS", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + "B", // VEHICLE_FIREWEAPON +#endif + "A", // VEHICLE_ACCELERATE + "X", // VEHICLE_BRAKE + "LB", // VEHICLE_CHANGE_RADIO_STATION + "LS", // VEHICLE_HORN + "RS", // TOGGLE_SUBMISSIONS + "RB", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "LT", // VEHICLE_LOOKLEFT + "RT", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "LT", // PED_CYCLE_TARGET_LEFT + "RT", // PED_CYCLE_TARGET_RIGHT + "LB", // PED_CENTER_CAMERA_BEHIND_PLAYER + "RB", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + }, + { + "B", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "X", // PED_SNIPER_ZOOM_IN + "A", // PED_SNIPER_ZOOM_OUT + "Y", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "A", // PED_SPRINT + "RS", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + "B", // VEHICLE_FIREWEAPON +#endif + "A", // VEHICLE_ACCELERATE + "X", // VEHICLE_BRAKE + "BACK", // VEHICLE_CHANGE_RADIO_STATION + "LB", // VEHICLE_HORN + "RS", // TOGGLE_SUBMISSIONS + "RB", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "LT", // VEHICLE_LOOKLEFT + "RT", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "LT", // PED_CYCLE_TARGET_LEFT + "RT", // PED_CYCLE_TARGET_RIGHT + "LB", // PED_CENTER_CAMERA_BEHIND_PLAYER + "RB", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + }, + { + "A", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "Y", // PED_SNIPER_ZOOM_IN + "X", // PED_SNIPER_ZOOM_OUT + "LB", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "B", // PED_SPRINT + "RS", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + "B", // VEHICLE_FIREWEAPON +#endif + "A", // VEHICLE_ACCELERATE + "X", // VEHICLE_BRAKE + "LS", // VEHICLE_CHANGE_RADIO_STATION + "RB", // VEHICLE_HORN + "RS", // TOGGLE_SUBMISSIONS + "Y", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "LT", // VEHICLE_LOOKLEFT + "RT", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "LT", // PED_CYCLE_TARGET_LEFT + "RT", // PED_CYCLE_TARGET_RIGHT + "Y", // PED_CENTER_CAMERA_BEHIND_PLAYER + "RB", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + }, + { + "RB", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "X", // PED_SNIPER_ZOOM_IN + "A", // PED_SNIPER_ZOOM_OUT + "Y", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "A", // PED_SPRINT + "RS", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + "RB", // VEHICLE_FIREWEAPON +#endif + nil, // VEHICLE_ACCELERATE + nil, // VEHICLE_BRAKE + "B", // VEHICLE_CHANGE_RADIO_STATION + "LS", // VEHICLE_HORN + "X", // TOGGLE_SUBMISSIONS + "LB", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "LT", // VEHICLE_LOOKLEFT + "RT", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "LT", // PED_CYCLE_TARGET_LEFT + "RT", // PED_CYCLE_TARGET_RIGHT + "B", // PED_CENTER_CAMERA_BEHIND_PLAYER + "LB", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + } +}; + +#if 0 // set 1 for ps2 fonts +#define PS2_TRIANGLE "\"" +#define PS2_CIRCLE "|" +#define PS2_CROSS "/" +#define PS2_SQUARE "^" +#else +#define PS2_TRIANGLE "TRIANGLE" +#define PS2_CIRCLE "CIRCLE" +#define PS2_CROSS "CROSS" +#define PS2_SQUARE "SQUARE" +#endif + +const char *PlayStationButtons[][MAX_CONTROLLERACTIONS] = +{ + { + PS2_CIRCLE, // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_SQUARE, // PED_SNIPER_ZOOM_IN + PS2_CROSS, // PED_SNIPER_ZOOM_OUT + PS2_TRIANGLE, // VEHICLE_ENTER_EXIT + "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CROSS, // PED_SPRINT + "R3", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + PS2_CIRCLE, // VEHICLE_FIREWEAPON +#endif + PS2_CROSS, // VEHICLE_ACCELERATE + PS2_SQUARE, // VEHICLE_BRAKE + "L1", // VEHICLE_CHANGE_RADIO_STATION + "L3", // VEHICLE_HORN + "R3", // TOGGLE_SUBMISSIONS + "R1", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "L2", // VEHICLE_LOOKLEFT + "R2", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "L2", // PED_CYCLE_TARGET_LEFT + "R2", // PED_CYCLE_TARGET_RIGHT + "L1", // PED_CENTER_CAMERA_BEHIND_PLAYER + "R1", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + }, + { + PS2_CIRCLE, // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_SQUARE, // PED_SNIPER_ZOOM_IN + PS2_CROSS, // PED_SNIPER_ZOOM_OUT + PS2_TRIANGLE, // VEHICLE_ENTER_EXIT + "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CROSS, // PED_SPRINT + "R3", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + PS2_CIRCLE, // VEHICLE_FIREWEAPON +#endif + PS2_CROSS, // VEHICLE_ACCELERATE + PS2_SQUARE, // VEHICLE_BRAKE + "BACK", // VEHICLE_CHANGE_RADIO_STATION + "L1", // VEHICLE_HORN + "R3", // TOGGLE_SUBMISSIONS + "R1", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "L2", // VEHICLE_LOOKLEFT + "R2", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "L2", // PED_CYCLE_TARGET_LEFT + "R2", // PED_CYCLE_TARGET_RIGHT + "L1", // PED_CENTER_CAMERA_BEHIND_PLAYER + "R1", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + }, + { + PS2_CROSS, // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_TRIANGLE, // PED_SNIPER_ZOOM_IN + PS2_SQUARE, // PED_SNIPER_ZOOM_OUT + "L1", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CIRCLE, // PED_SPRINT + "R3", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + PS2_CIRCLE, // VEHICLE_FIREWEAPON +#endif + PS2_CROSS, // VEHICLE_ACCELERATE + PS2_SQUARE, // VEHICLE_BRAKE + "L3", // VEHICLE_CHANGE_RADIO_STATION + "R1", // VEHICLE_HORN + "R3", // TOGGLE_SUBMISSIONS + PS2_TRIANGLE, // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "L2", // VEHICLE_LOOKLEFT + "R2", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "L2", // PED_CYCLE_TARGET_LEFT + "R2", // PED_CYCLE_TARGET_RIGHT + PS2_TRIANGLE, // PED_CENTER_CAMERA_BEHIND_PLAYER + "R1", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + }, + { + "R1", // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_SQUARE, // PED_SNIPER_ZOOM_IN + PS2_CROSS, // PED_SNIPER_ZOOM_OUT + PS2_TRIANGLE, // VEHICLE_ENTER_EXIT + "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CROSS, // PED_SPRINT + "R3", // PED_LOOKBEHIND +#ifdef BIND_VEHICLE_FIREWEAPON + "R1", // VEHICLE_FIREWEAPON +#endif + nil, // VEHICLE_ACCELERATE + nil, // VEHICLE_BRAKE + PS2_CIRCLE, // VEHICLE_CHANGE_RADIO_STATION + "L3", // VEHICLE_HORN + PS2_SQUARE, // TOGGLE_SUBMISSIONS + "L1", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "L2", // VEHICLE_LOOKLEFT + "R2", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "L2", // PED_CYCLE_TARGET_LEFT + "R2", // PED_CYCLE_TARGET_RIGHT + PS2_CIRCLE, // PED_CENTER_CAMERA_BEHIND_PLAYER + "L1", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE + } +}; + +#undef PS2_TRIANGLE +#undef PS2_CIRCLE +#undef PS2_CROSS +#undef PS2_SQUARE + void CControllerConfigManager::GetWideStringOfCommandKeys(uint16 action, wchar *text, uint16 leight) { +#ifdef DETECT_PAD_INPUT_SWITCH + if (CPad::GetPad(0)->IsAffectedByController) { + wchar wstr[16]; + + // TODO: INI and/or menu setting for Xbox/PS switch + const char *(*Buttons)[MAX_CONTROLLERACTIONS] = XboxButtons; + + assert(Buttons[CPad::GetPad(0)->Mode][action] != nil); // we cannot use these + AsciiToUnicode(Buttons[CPad::GetPad(0)->Mode][action], wstr); + + CMessages::WideStringCopy(text, wstr, leight); + return; + } +#endif + int32 nums = GetNumOfSettingsForAction((e_ControllerAction)action); int32 sets = 0; From 30d1cbfecd6e9fb477a0b5672d830b871be9722d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 13:46:12 +0200 Subject: [PATCH 023/129] Fix the goddamn spaces for tabs master race --- src/core/ControllerConfig.cpp | 568 +++++++++++++++++----------------- 1 file changed, 284 insertions(+), 284 deletions(-) diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index 1af29a85..dcc294c8 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2318,161 +2318,161 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act const char *XboxButtons[][MAX_CONTROLLERACTIONS] = { - { - "B", // PED_FIREWEAPON - "RT", // PED_CYCLE_WEAPON_RIGHT - "LT", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - "X", // PED_SNIPER_ZOOM_IN - "A", // PED_SNIPER_ZOOM_OUT - "Y", // VEHICLE_ENTER_EXIT - "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - "X", // PED_JUMPING - "A", // PED_SPRINT - "RS", // PED_LOOKBEHIND + { + "B", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "X", // PED_SNIPER_ZOOM_IN + "A", // PED_SNIPER_ZOOM_OUT + "Y", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "A", // PED_SPRINT + "RS", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - "B", // VEHICLE_FIREWEAPON + "B", // VEHICLE_FIREWEAPON #endif - "A", // VEHICLE_ACCELERATE - "X", // VEHICLE_BRAKE - "LB", // VEHICLE_CHANGE_RADIO_STATION - "LS", // VEHICLE_HORN - "RS", // TOGGLE_SUBMISSIONS - "RB", // VEHICLE_HANDBRAKE - nil, // PED_1RST_PERSON_LOOK_LEFT - nil, // PED_1RST_PERSON_LOOK_RIGHT - "LT", // VEHICLE_LOOKLEFT - "RT", // VEHICLE_LOOKRIGHT - nil, // VEHICLE_LOOKBEHIND - nil, // VEHICLE_TURRETLEFT - nil, // VEHICLE_TURRETRIGHT - nil, // VEHICLE_TURRETUP - nil, // VEHICLE_TURRETDOWN - "LT", // PED_CYCLE_TARGET_LEFT - "RT", // PED_CYCLE_TARGET_RIGHT - "LB", // PED_CENTER_CAMERA_BEHIND_PLAYER - "RB", // PED_LOCK_TARGET - nil, // NETWORK_TALK - nil, // PED_1RST_PERSON_LOOK_UP - nil, // PED_1RST_PERSON_LOOK_DOWN - nil, // _CONTROLLERACTION_36 - nil, // TOGGLE_DPAD - nil, // SWITCH_DEBUG_CAM_ON - nil, // TAKE_SCREEN_SHOT - nil, // SHOW_MOUSE_POINTER_TOGGLE + "A", // VEHICLE_ACCELERATE + "X", // VEHICLE_BRAKE + "LB", // VEHICLE_CHANGE_RADIO_STATION + "LS", // VEHICLE_HORN + "RS", // TOGGLE_SUBMISSIONS + "RB", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "LT", // VEHICLE_LOOKLEFT + "RT", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "LT", // PED_CYCLE_TARGET_LEFT + "RT", // PED_CYCLE_TARGET_RIGHT + "LB", // PED_CENTER_CAMERA_BEHIND_PLAYER + "RB", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE }, { - "B", // PED_FIREWEAPON - "RT", // PED_CYCLE_WEAPON_RIGHT - "LT", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - "X", // PED_SNIPER_ZOOM_IN - "A", // PED_SNIPER_ZOOM_OUT - "Y", // VEHICLE_ENTER_EXIT - "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - "X", // PED_JUMPING - "A", // PED_SPRINT - "RS", // PED_LOOKBEHIND + "B", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "X", // PED_SNIPER_ZOOM_IN + "A", // PED_SNIPER_ZOOM_OUT + "Y", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "A", // PED_SPRINT + "RS", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - "B", // VEHICLE_FIREWEAPON + "B", // VEHICLE_FIREWEAPON #endif - "A", // VEHICLE_ACCELERATE - "X", // VEHICLE_BRAKE - "BACK", // VEHICLE_CHANGE_RADIO_STATION - "LB", // VEHICLE_HORN - "RS", // TOGGLE_SUBMISSIONS - "RB", // VEHICLE_HANDBRAKE - nil, // PED_1RST_PERSON_LOOK_LEFT - nil, // PED_1RST_PERSON_LOOK_RIGHT - "LT", // VEHICLE_LOOKLEFT - "RT", // VEHICLE_LOOKRIGHT - nil, // VEHICLE_LOOKBEHIND - nil, // VEHICLE_TURRETLEFT - nil, // VEHICLE_TURRETRIGHT - nil, // VEHICLE_TURRETUP - nil, // VEHICLE_TURRETDOWN - "LT", // PED_CYCLE_TARGET_LEFT - "RT", // PED_CYCLE_TARGET_RIGHT - "LB", // PED_CENTER_CAMERA_BEHIND_PLAYER - "RB", // PED_LOCK_TARGET - nil, // NETWORK_TALK - nil, // PED_1RST_PERSON_LOOK_UP - nil, // PED_1RST_PERSON_LOOK_DOWN - nil, // _CONTROLLERACTION_36 - nil, // TOGGLE_DPAD - nil, // SWITCH_DEBUG_CAM_ON - nil, // TAKE_SCREEN_SHOT - nil, // SHOW_MOUSE_POINTER_TOGGLE + "A", // VEHICLE_ACCELERATE + "X", // VEHICLE_BRAKE + "BACK", // VEHICLE_CHANGE_RADIO_STATION + "LB", // VEHICLE_HORN + "RS", // TOGGLE_SUBMISSIONS + "RB", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "LT", // VEHICLE_LOOKLEFT + "RT", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "LT", // PED_CYCLE_TARGET_LEFT + "RT", // PED_CYCLE_TARGET_RIGHT + "LB", // PED_CENTER_CAMERA_BEHIND_PLAYER + "RB", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE }, { - "A", // PED_FIREWEAPON - "RT", // PED_CYCLE_WEAPON_RIGHT - "LT", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - "Y", // PED_SNIPER_ZOOM_IN - "X", // PED_SNIPER_ZOOM_OUT - "LB", // VEHICLE_ENTER_EXIT - "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - "X", // PED_JUMPING - "B", // PED_SPRINT - "RS", // PED_LOOKBEHIND + "A", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "Y", // PED_SNIPER_ZOOM_IN + "X", // PED_SNIPER_ZOOM_OUT + "LB", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "B", // PED_SPRINT + "RS", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - "B", // VEHICLE_FIREWEAPON + "B", // VEHICLE_FIREWEAPON #endif - "A", // VEHICLE_ACCELERATE - "X", // VEHICLE_BRAKE - "LS", // VEHICLE_CHANGE_RADIO_STATION - "RB", // VEHICLE_HORN - "RS", // TOGGLE_SUBMISSIONS - "Y", // VEHICLE_HANDBRAKE - nil, // PED_1RST_PERSON_LOOK_LEFT - nil, // PED_1RST_PERSON_LOOK_RIGHT - "LT", // VEHICLE_LOOKLEFT - "RT", // VEHICLE_LOOKRIGHT - nil, // VEHICLE_LOOKBEHIND - nil, // VEHICLE_TURRETLEFT - nil, // VEHICLE_TURRETRIGHT - nil, // VEHICLE_TURRETUP - nil, // VEHICLE_TURRETDOWN - "LT", // PED_CYCLE_TARGET_LEFT - "RT", // PED_CYCLE_TARGET_RIGHT - "Y", // PED_CENTER_CAMERA_BEHIND_PLAYER - "RB", // PED_LOCK_TARGET - nil, // NETWORK_TALK - nil, // PED_1RST_PERSON_LOOK_UP - nil, // PED_1RST_PERSON_LOOK_DOWN - nil, // _CONTROLLERACTION_36 - nil, // TOGGLE_DPAD - nil, // SWITCH_DEBUG_CAM_ON - nil, // TAKE_SCREEN_SHOT - nil, // SHOW_MOUSE_POINTER_TOGGLE + "A", // VEHICLE_ACCELERATE + "X", // VEHICLE_BRAKE + "LS", // VEHICLE_CHANGE_RADIO_STATION + "RB", // VEHICLE_HORN + "RS", // TOGGLE_SUBMISSIONS + "Y", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "LT", // VEHICLE_LOOKLEFT + "RT", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "LT", // PED_CYCLE_TARGET_LEFT + "RT", // PED_CYCLE_TARGET_RIGHT + "Y", // PED_CENTER_CAMERA_BEHIND_PLAYER + "RB", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE }, { - "RB", // PED_FIREWEAPON - "RT", // PED_CYCLE_WEAPON_RIGHT - "LT", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - "X", // PED_SNIPER_ZOOM_IN - "A", // PED_SNIPER_ZOOM_OUT - "Y", // VEHICLE_ENTER_EXIT - "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - "X", // PED_JUMPING - "A", // PED_SPRINT - "RS", // PED_LOOKBEHIND + "RB", // PED_FIREWEAPON + "RT", // PED_CYCLE_WEAPON_RIGHT + "LT", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + "X", // PED_SNIPER_ZOOM_IN + "A", // PED_SNIPER_ZOOM_OUT + "Y", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + "X", // PED_JUMPING + "A", // PED_SPRINT + "RS", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - "RB", // VEHICLE_FIREWEAPON + "RB", // VEHICLE_FIREWEAPON #endif nil, // VEHICLE_ACCELERATE nil, // VEHICLE_BRAKE @@ -2518,161 +2518,161 @@ const char *XboxButtons[][MAX_CONTROLLERACTIONS] = const char *PlayStationButtons[][MAX_CONTROLLERACTIONS] = { - { - PS2_CIRCLE, // PED_FIREWEAPON - "R2", // PED_CYCLE_WEAPON_RIGHT - "L2", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - PS2_SQUARE, // PED_SNIPER_ZOOM_IN - PS2_CROSS, // PED_SNIPER_ZOOM_OUT - PS2_TRIANGLE, // VEHICLE_ENTER_EXIT - "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - PS2_SQUARE, // PED_JUMPING - PS2_CROSS, // PED_SPRINT - "R3", // PED_LOOKBEHIND + { + PS2_CIRCLE, // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_SQUARE, // PED_SNIPER_ZOOM_IN + PS2_CROSS, // PED_SNIPER_ZOOM_OUT + PS2_TRIANGLE, // VEHICLE_ENTER_EXIT + "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CROSS, // PED_SPRINT + "R3", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - PS2_CIRCLE, // VEHICLE_FIREWEAPON + PS2_CIRCLE, // VEHICLE_FIREWEAPON #endif - PS2_CROSS, // VEHICLE_ACCELERATE - PS2_SQUARE, // VEHICLE_BRAKE - "L1", // VEHICLE_CHANGE_RADIO_STATION - "L3", // VEHICLE_HORN - "R3", // TOGGLE_SUBMISSIONS - "R1", // VEHICLE_HANDBRAKE - nil, // PED_1RST_PERSON_LOOK_LEFT - nil, // PED_1RST_PERSON_LOOK_RIGHT - "L2", // VEHICLE_LOOKLEFT - "R2", // VEHICLE_LOOKRIGHT - nil, // VEHICLE_LOOKBEHIND - nil, // VEHICLE_TURRETLEFT - nil, // VEHICLE_TURRETRIGHT - nil, // VEHICLE_TURRETUP - nil, // VEHICLE_TURRETDOWN - "L2", // PED_CYCLE_TARGET_LEFT - "R2", // PED_CYCLE_TARGET_RIGHT - "L1", // PED_CENTER_CAMERA_BEHIND_PLAYER - "R1", // PED_LOCK_TARGET - nil, // NETWORK_TALK - nil, // PED_1RST_PERSON_LOOK_UP - nil, // PED_1RST_PERSON_LOOK_DOWN - nil, // _CONTROLLERACTION_36 - nil, // TOGGLE_DPAD - nil, // SWITCH_DEBUG_CAM_ON - nil, // TAKE_SCREEN_SHOT - nil, // SHOW_MOUSE_POINTER_TOGGLE + PS2_CROSS, // VEHICLE_ACCELERATE + PS2_SQUARE, // VEHICLE_BRAKE + "L1", // VEHICLE_CHANGE_RADIO_STATION + "L3", // VEHICLE_HORN + "R3", // TOGGLE_SUBMISSIONS + "R1", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "L2", // VEHICLE_LOOKLEFT + "R2", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "L2", // PED_CYCLE_TARGET_LEFT + "R2", // PED_CYCLE_TARGET_RIGHT + "L1", // PED_CENTER_CAMERA_BEHIND_PLAYER + "R1", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE }, { - PS2_CIRCLE, // PED_FIREWEAPON - "R2", // PED_CYCLE_WEAPON_RIGHT - "L2", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - PS2_SQUARE, // PED_SNIPER_ZOOM_IN - PS2_CROSS, // PED_SNIPER_ZOOM_OUT - PS2_TRIANGLE, // VEHICLE_ENTER_EXIT - "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - PS2_SQUARE, // PED_JUMPING - PS2_CROSS, // PED_SPRINT - "R3", // PED_LOOKBEHIND + PS2_CIRCLE, // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_SQUARE, // PED_SNIPER_ZOOM_IN + PS2_CROSS, // PED_SNIPER_ZOOM_OUT + PS2_TRIANGLE, // VEHICLE_ENTER_EXIT + "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CROSS, // PED_SPRINT + "R3", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - PS2_CIRCLE, // VEHICLE_FIREWEAPON + PS2_CIRCLE, // VEHICLE_FIREWEAPON #endif - PS2_CROSS, // VEHICLE_ACCELERATE - PS2_SQUARE, // VEHICLE_BRAKE - "BACK", // VEHICLE_CHANGE_RADIO_STATION - "L1", // VEHICLE_HORN - "R3", // TOGGLE_SUBMISSIONS - "R1", // VEHICLE_HANDBRAKE - nil, // PED_1RST_PERSON_LOOK_LEFT - nil, // PED_1RST_PERSON_LOOK_RIGHT - "L2", // VEHICLE_LOOKLEFT - "R2", // VEHICLE_LOOKRIGHT - nil, // VEHICLE_LOOKBEHIND - nil, // VEHICLE_TURRETLEFT - nil, // VEHICLE_TURRETRIGHT - nil, // VEHICLE_TURRETUP - nil, // VEHICLE_TURRETDOWN - "L2", // PED_CYCLE_TARGET_LEFT - "R2", // PED_CYCLE_TARGET_RIGHT - "L1", // PED_CENTER_CAMERA_BEHIND_PLAYER - "R1", // PED_LOCK_TARGET - nil, // NETWORK_TALK - nil, // PED_1RST_PERSON_LOOK_UP - nil, // PED_1RST_PERSON_LOOK_DOWN - nil, // _CONTROLLERACTION_36 - nil, // TOGGLE_DPAD - nil, // SWITCH_DEBUG_CAM_ON - nil, // TAKE_SCREEN_SHOT - nil, // SHOW_MOUSE_POINTER_TOGGLE + PS2_CROSS, // VEHICLE_ACCELERATE + PS2_SQUARE, // VEHICLE_BRAKE + "BACK", // VEHICLE_CHANGE_RADIO_STATION + "L1", // VEHICLE_HORN + "R3", // TOGGLE_SUBMISSIONS + "R1", // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "L2", // VEHICLE_LOOKLEFT + "R2", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "L2", // PED_CYCLE_TARGET_LEFT + "R2", // PED_CYCLE_TARGET_RIGHT + "L1", // PED_CENTER_CAMERA_BEHIND_PLAYER + "R1", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE }, { - PS2_CROSS, // PED_FIREWEAPON - "R2", // PED_CYCLE_WEAPON_RIGHT - "L2", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - PS2_TRIANGLE, // PED_SNIPER_ZOOM_IN - PS2_SQUARE, // PED_SNIPER_ZOOM_OUT - "L1", // VEHICLE_ENTER_EXIT - "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - PS2_SQUARE, // PED_JUMPING - PS2_CIRCLE, // PED_SPRINT - "R3", // PED_LOOKBEHIND + PS2_CROSS, // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_TRIANGLE, // PED_SNIPER_ZOOM_IN + PS2_SQUARE, // PED_SNIPER_ZOOM_OUT + "L1", // VEHICLE_ENTER_EXIT + "BACK", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CIRCLE, // PED_SPRINT + "R3", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - PS2_CIRCLE, // VEHICLE_FIREWEAPON + PS2_CIRCLE, // VEHICLE_FIREWEAPON #endif - PS2_CROSS, // VEHICLE_ACCELERATE - PS2_SQUARE, // VEHICLE_BRAKE - "L3", // VEHICLE_CHANGE_RADIO_STATION - "R1", // VEHICLE_HORN - "R3", // TOGGLE_SUBMISSIONS - PS2_TRIANGLE, // VEHICLE_HANDBRAKE - nil, // PED_1RST_PERSON_LOOK_LEFT - nil, // PED_1RST_PERSON_LOOK_RIGHT - "L2", // VEHICLE_LOOKLEFT - "R2", // VEHICLE_LOOKRIGHT - nil, // VEHICLE_LOOKBEHIND - nil, // VEHICLE_TURRETLEFT - nil, // VEHICLE_TURRETRIGHT - nil, // VEHICLE_TURRETUP - nil, // VEHICLE_TURRETDOWN - "L2", // PED_CYCLE_TARGET_LEFT - "R2", // PED_CYCLE_TARGET_RIGHT - PS2_TRIANGLE, // PED_CENTER_CAMERA_BEHIND_PLAYER - "R1", // PED_LOCK_TARGET - nil, // NETWORK_TALK - nil, // PED_1RST_PERSON_LOOK_UP - nil, // PED_1RST_PERSON_LOOK_DOWN - nil, // _CONTROLLERACTION_36 - nil, // TOGGLE_DPAD - nil, // SWITCH_DEBUG_CAM_ON - nil, // TAKE_SCREEN_SHOT - nil, // SHOW_MOUSE_POINTER_TOGGLE + PS2_CROSS, // VEHICLE_ACCELERATE + PS2_SQUARE, // VEHICLE_BRAKE + "L3", // VEHICLE_CHANGE_RADIO_STATION + "R1", // VEHICLE_HORN + "R3", // TOGGLE_SUBMISSIONS + PS2_TRIANGLE, // VEHICLE_HANDBRAKE + nil, // PED_1RST_PERSON_LOOK_LEFT + nil, // PED_1RST_PERSON_LOOK_RIGHT + "L2", // VEHICLE_LOOKLEFT + "R2", // VEHICLE_LOOKRIGHT + nil, // VEHICLE_LOOKBEHIND + nil, // VEHICLE_TURRETLEFT + nil, // VEHICLE_TURRETRIGHT + nil, // VEHICLE_TURRETUP + nil, // VEHICLE_TURRETDOWN + "L2", // PED_CYCLE_TARGET_LEFT + "R2", // PED_CYCLE_TARGET_RIGHT + PS2_TRIANGLE, // PED_CENTER_CAMERA_BEHIND_PLAYER + "R1", // PED_LOCK_TARGET + nil, // NETWORK_TALK + nil, // PED_1RST_PERSON_LOOK_UP + nil, // PED_1RST_PERSON_LOOK_DOWN + nil, // _CONTROLLERACTION_36 + nil, // TOGGLE_DPAD + nil, // SWITCH_DEBUG_CAM_ON + nil, // TAKE_SCREEN_SHOT + nil, // SHOW_MOUSE_POINTER_TOGGLE }, { - "R1", // PED_FIREWEAPON - "R2", // PED_CYCLE_WEAPON_RIGHT - "L2", // PED_CYCLE_WEAPON_LEFT - nil, // GO_FORWARD - nil, // GO_BACK - nil, // GO_LEFT - nil, // GO_RIGHT - PS2_SQUARE, // PED_SNIPER_ZOOM_IN - PS2_CROSS, // PED_SNIPER_ZOOM_OUT - PS2_TRIANGLE, // VEHICLE_ENTER_EXIT - "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS - PS2_SQUARE, // PED_JUMPING - PS2_CROSS, // PED_SPRINT - "R3", // PED_LOOKBEHIND + "R1", // PED_FIREWEAPON + "R2", // PED_CYCLE_WEAPON_RIGHT + "L2", // PED_CYCLE_WEAPON_LEFT + nil, // GO_FORWARD + nil, // GO_BACK + nil, // GO_LEFT + nil, // GO_RIGHT + PS2_SQUARE, // PED_SNIPER_ZOOM_IN + PS2_CROSS, // PED_SNIPER_ZOOM_OUT + PS2_TRIANGLE, // VEHICLE_ENTER_EXIT + "SELECT", // CAMERA_CHANGE_VIEW_ALL_SITUATIONS + PS2_SQUARE, // PED_JUMPING + PS2_CROSS, // PED_SPRINT + "R3", // PED_LOOKBEHIND #ifdef BIND_VEHICLE_FIREWEAPON - "R1", // VEHICLE_FIREWEAPON + "R1", // VEHICLE_FIREWEAPON #endif nil, // VEHICLE_ACCELERATE nil, // VEHICLE_BRAKE From fad0a9507d4a4eb63fc5a658c2886fe07f7dadee Mon Sep 17 00:00:00 2001 From: Roman Masanin <36927roma@gmail.com> Date: Sun, 1 Nov 2020 23:48:03 +0300 Subject: [PATCH 024/129] some "optimizations". same like I did in VC --- src/audio/AudioLogic.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 3fc9334f..1e8a8194 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -1930,7 +1930,6 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) m_sQueueSample.m_nSampleIndex = SFX_OLD_CAR_DOOR_CLOSE; break; case NEW_DOOR: - default: m_sQueueSample.m_nSampleIndex = SFX_NEW_CAR_DOOR_CLOSE; break; case TRUCK_DOOR: @@ -1939,9 +1938,12 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) case BUS_DOOR: m_sQueueSample.m_nSampleIndex = SFX_AIR_BRAKES; break; + default: + m_sQueueSample.m_nSampleIndex = SFX_NEW_CAR_DOOR_CLOSE; + break; } m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 22; + m_sQueueSample.m_nCounter = event + 22; //originaly used m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i], which is same m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -1975,7 +1977,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) break; } m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 10; + m_sQueueSample.m_nCounter = event + 10; //also used m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; From e587974759bd98a1f56dd752537b8ffe184b747b Mon Sep 17 00:00:00 2001 From: shfil Date: Mon, 2 Nov 2020 13:31:25 +0100 Subject: [PATCH 025/129] Fix include in Frontend_PS2.cpp --- src/core/Frontend_PS2.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/Frontend_PS2.cpp b/src/core/Frontend_PS2.cpp index d474ee65..a1d802f2 100644 --- a/src/core/Frontend_PS2.cpp +++ b/src/core/Frontend_PS2.cpp @@ -22,7 +22,7 @@ #include "Game.h" #include "World.h" #include "PlayerInfo.h" -#include "FrontendControls.h" +#include "FrontEndControls.h" #include "MemoryCard.h" #define CRect_SZ(x, y, w, h) CRect(x, y, x+w, y+h) @@ -3044,4 +3044,4 @@ CMenuManager::FilterOutColorMarkersFromString(wchar *string, CRGBA &color) *dst = '\0'; } -#endif \ No newline at end of file +#endif From 1df6dda546aa658d456846900880ac380d0ab677 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Sat, 31 Oct 2020 23:14:28 +0100 Subject: [PATCH 026/129] Add basic support for cmake on linux --- CMakeLists.txt | 44 ++++++++++++++++ cmake/FindMPG123.cmake | 28 ++++++++++ cmake/FindSndFile.cmake | 67 ++++++++++++++++++++++++ src/CMakeLists.txt | 112 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/FindMPG123.cmake create mode 100644 cmake/FindSndFile.cmake create mode 100644 src/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..5daf1d15 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.8) + +project(re3 C CXX) +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") + +if(WIN32) + set(RE3_AUDIOS "NULL" "OAL" "MSS") +else() + set(RE3_AUDIOS "NULL" "OAL") +endif() + +set(RE3_AUDIO "OAL" CACHE STRING "Audio") + +set_property(CACHE RE3_AUDIO PROPERTY STRINGS ${RE3_AUDIOS}) +message(STATUS "RE3_AUDIO = ${RE3_AUDIO} (choices=${RE3_AUDIOS})") +set("RE3_AUDIO_${RE3_AUDIO}" ON) +if(NOT RE3_AUDIO IN_LIST RE3_AUDIOS) + message(FATAL_ERROR "Illegal RE3_AUDIO=${RE3_AUDIO}") +endif() + +if(RE3_INSTALL) + include(GNUInstallDirs) + set(RE3_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}/re3") +endif() + +add_subdirectory("vendor/librw") +add_subdirectory(src) + +if(RE3_INSTALL) + include(CMakePackageConfigHelpers) + configure_package_config_file(re3-config.cmake.in re3-config.cmake + INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}" + ) + install( + FILES "${CMAKE_CURRENT_BINARY_DIR}/re3-config.cmake" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" + ) + install( + EXPORT re3-targets + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" + ) + + include(CMakeCPack.cmake) +endif() diff --git a/cmake/FindMPG123.cmake b/cmake/FindMPG123.cmake new file mode 100644 index 00000000..a9b6dd8b --- /dev/null +++ b/cmake/FindMPG123.cmake @@ -0,0 +1,28 @@ +# - Find mpg123 +# Find the native mpg123 includes and library +# +# MPG123_INCLUDE_DIR - where to find mpg123.h +# MPG123_LIBRARIES - List of libraries when using mpg123. +# MPG123_FOUND - True if mpg123 found. + +IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) + # Already in cache, be silent + SET(MPG123_FIND_QUIETLY TRUE) +ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) + +FIND_PATH(MPG123_INCLUDE_DIR mpg123.h + PATHS "${MPG123_DIR}" + PATH_SUFFIXES include + ) + +FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0 + PATHS "${MPG123_DIR}" + PATH_SUFFIXES lib + ) + +# MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR) + +# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR) diff --git a/cmake/FindSndFile.cmake b/cmake/FindSndFile.cmake new file mode 100644 index 00000000..8ae47b70 --- /dev/null +++ b/cmake/FindSndFile.cmake @@ -0,0 +1,67 @@ +# Found on http://hg.kvats.net +# +# - Try to find libsndfile +# +# Once done this will define +# +# SNDFILE_FOUND - system has libsndfile +# SNDFILE_INCLUDE_DIRS - the libsndfile include directory +# SNDFILE_LIBRARIES - Link these to use libsndfile +# +# Copyright (C) 2006 Wengo +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +if (SNDFILE_LIBRARIES AND SNDFILE_INCLUDE_DIRS) + # in cache already + set(SNDFILE_FOUND TRUE) +else (SNDFILE_LIBRARIES AND SNDFILE_INCLUDE_DIRS) + + find_path(SNDFILE_INCLUDE_DIR + NAMES + sndfile.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /sw/include + ) + + find_library(SNDFILE_LIBRARY + NAMES + sndfile + PATHS + /usr/lib + /usr/local/lib + /opt/local/lib + /sw/lib + ) + + set(SNDFILE_INCLUDE_DIRS + ${SNDFILE_INCLUDE_DIR} + ) + set(SNDFILE_LIBRARIES + ${SNDFILE_LIBRARY} + ) + + if (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) + set(SNDFILE_FOUND TRUE) + endif (SNDFILE_INCLUDE_DIRS AND SNDFILE_LIBRARIES) + + if (SNDFILE_FOUND) + if (NOT SndFile_FIND_QUIETLY) + message(STATUS "Found libsndfile: ${SNDFILE_LIBRARIES}") + endif (NOT SndFile_FIND_QUIETLY) + else (SNDFILE_FOUND) + if (SndFile_FIND_REQUIRED) + message(FATAL_ERROR "Could not find libsndfile") + endif (SndFile_FIND_REQUIRED) + endif (SNDFILE_FOUND) + + # show the SNDFILE_INCLUDE_DIRS and SNDFILE_LIBRARIES variables only in the advanced view + mark_as_advanced(SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES) + +endif (SNDFILE_LIBRARIES AND SNDFILE_INCLUDE_DIRS) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..eca69d30 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,112 @@ +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) + +if(${RE3_AUDIO} STREQUAL "OAL") + find_package(OpenAL REQUIRED) + find_package(MPG123 REQUIRED) + find_package(SndFile REQUIRED) +endif() + +file(GLOB_RECURSE Sources "*.cpp" "*.h") + +MACRO(HEADER_DIRECTORIES return_list) + FILE(GLOB_RECURSE new_list *.cpp) + SET(dir_list "animation" + "audio" + "control" + "core" + "entities" + "extras" + "fakerw" + "math" + "modelinfo" + "objects" + "peds" + "render" + "rw" + "save" + "skel" + "text" + "vehicles" + "weapons") + FOREACH(file_path ${new_list}) + GET_FILENAME_COMPONENT(dir_path ${file_path} PATH) + SET(dir_list ${dir_list} ${dir_path}) + ENDFOREACH() + LIST(REMOVE_DUPLICATES dir_list) + SET(${return_list} ${dir_list}) +ENDMACRO() + +HEADER_DIRECTORIES(header_list) +include_directories(${header_list}) + + +add_executable(re3 ${Sources}) +target_link_libraries(re3 librw) +target_link_libraries(re3 Threads::Threads) + +if(${RE3_AUDIO} STREQUAL "OAL") + target_link_libraries(re3 ${OPENAL_LIBRARY}) + target_link_libraries(re3 ${MPG123_LIBRARIES}) + target_link_libraries(re3 ${SNDFILE_LIBRARIES}) +endif() + +target_include_directories(re3 + INTERFACE + $ + ) + +target_compile_definitions(re3 + PRIVATE + "$,DEBUG,NDEBUG>" + PUBLIC + "RW_${RE3_PLATFORM}" + ) + +target_compile_definitions(re3 PRIVATE LIBRW=1 AUDIO_OAL=1) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + target_compile_options(re3 + PRIVATE + "-Wall" + ) + if (NOT RE3_PLATFORM_PS2) + target_compile_options(re3 + PRIVATE + "-Wextra" + "-Wdouble-promotion" + "-Wpedantic" + ) + endif() +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + target_compile_options(re3 + PUBLIC + /wd4996 /wd4244 + ) +endif() + +set_target_properties(re3 + PROPERTIES + C_STANDARD 11 + C_EXTENSIONS OFF + C_STANDARD_REQUIRED ON + CXX_STANDARD 11 + CXX_EXTENSIONS OFF + CXX_STANDARD_REQUIRED ON + PREFIX "" + ) + +if(RE3_INSTALL) + target_include_directories(re3 + INTERFACE + $ + ) + + install( + TARGETS re3 + EXPORT re3-targets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + ) +endif() From d4c26396c7c447de00470a0ba2153ee43bc00532 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 2 Nov 2020 18:17:37 +0200 Subject: [PATCH 027/129] Fix MemoryCard.cpp --- src/save/MemoryCard.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/save/MemoryCard.cpp b/src/save/MemoryCard.cpp index a24b754c..c8ebcd86 100644 --- a/src/save/MemoryCard.cpp +++ b/src/save/MemoryCard.cpp @@ -11,6 +11,7 @@ #include "Clock.h" #include "MBlur.h" #include "Date.h" +#include "Font.h" #include "FileMgr.h" #include "Game.h" #include "GameLogic.h" From f08b9cf0338c448d182c7561cacb4a755153834d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 3 Nov 2020 15:00:48 +0200 Subject: [PATCH 028/129] fix build --- src/core/MenuScreensCustom.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index 25831486..abb93a3c 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -10,6 +10,7 @@ #include "postfx.h" #include "custompipes.h" #include "RwHelper.h" +#include "Text.h" // Menu screens array is at the bottom of the file. From ebddb7956c44d6d5862b6bddfc0be54d55f4a813 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 3 Nov 2020 14:37:00 +0100 Subject: [PATCH 029/129] fix mistake in custom menu; update librw --- src/core/MenuScreensCustom.cpp | 12 ++++++------ vendor/librw | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index abb93a3c..fb0888fc 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -50,18 +50,18 @@ #ifdef EXTENDED_COLOURFILTER #define POSTFX_SELECTORS \ - MENUACTION_CFO_SELECT, "FED_VPL", { new CCFOSelect((int8*)&CustomPipes::VehiclePipeSwitch, "VehiclePipeline", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), false, nil) }, \ - MENUACTION_CFO_SELECT, "FED_PRM", { new CCFOSelect((int8*)&CustomPipes::RimlightEnable, "NeoRimLight", off_on, 2, false, nil) }, \ - MENUACTION_CFO_SELECT, "FED_WLM", { new CCFOSelect((int8*)&CustomPipes::LightmapEnable, "NeoLightMaps", off_on, 2, false, nil) }, \ - MENUACTION_CFO_SELECT, "FED_RGL", { new CCFOSelect((int8*)&CustomPipes::GlossEnable, "NeoRoadGloss", off_on, 2, false, nil) }, + MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_MBL", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false, nil) }, #else #define POSTFX_SELECTORS #endif #ifdef EXTENDED_PIPELINES #define PIPELINES_SELECTOR \ - MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false, nil) }, \ - MENUACTION_CFO_SELECT, "FED_MBL", { new CCFOSelect((int8*)&CPostFX::MotionBlurOn, "MotionBlur", off_on, 2, false, nil) }, + MENUACTION_CFO_SELECT, "FED_VPL", { new CCFOSelect((int8*)&CustomPipes::VehiclePipeSwitch, "VehiclePipeline", vehPipelineNames, ARRAY_SIZE(vehPipelineNames), false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_PRM", { new CCFOSelect((int8*)&CustomPipes::RimlightEnable, "NeoRimLight", off_on, 2, false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_WLM", { new CCFOSelect((int8*)&CustomPipes::LightmapEnable, "NeoLightMaps", off_on, 2, false, nil) }, \ + MENUACTION_CFO_SELECT, "FED_RGL", { new CCFOSelect((int8*)&CustomPipes::GlossEnable, "NeoRoadGloss", off_on, 2, false, nil) }, #else #define PIPELINES_SELECTOR #endif diff --git a/vendor/librw b/vendor/librw index e68ef137..8c00f787 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit e68ef1374d20071887348e9031f5fa38a2e4f7ed +Subproject commit 8c00f787cb8f53781c4335ecbc9d28fb9c664ba7 From b3da518ae02eb9c9a9cc3e0343438f07d6d28251 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 3 Nov 2020 16:59:37 +0100 Subject: [PATCH 030/129] only do backface culling on buildings --- src/render/Renderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 4ad1d3b9..92bbdd45 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -111,7 +111,7 @@ CRenderer::RenderOneRoad(CEntity *e) CustomPipes::AttachGlossPipe(e->GetAtomic()); #endif #ifdef EXTRA_MODEL_FLAGS - if(CModelInfo::GetModelInfo(e->GetModelIndex())->RenderDoubleSided()){ + if(!e->IsBuilding() || CModelInfo::GetModelInfo(e->GetModelIndex())->RenderDoubleSided()){ BACKFACE_CULLING_OFF; e->Render(); BACKFACE_CULLING_ON; @@ -181,7 +181,7 @@ CRenderer::RenderOneNonRoad(CEntity *e) BACKFACE_CULLING_OFF; } #ifdef EXTRA_MODEL_FLAGS - if(CModelInfo::GetModelInfo(e->GetModelIndex())->RenderDoubleSided()){ + if(!e->IsBuilding() || CModelInfo::GetModelInfo(e->GetModelIndex())->RenderDoubleSided()){ BACKFACE_CULLING_OFF; e->Render(); BACKFACE_CULLING_ON; From 8224a6a38156ccba7c69b66fab3388463fc727b1 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 5 Nov 2020 17:05:16 +0200 Subject: [PATCH 031/129] Button icons --- gamefiles/models/x360btns.txd | Bin 0 -> 126760 bytes src/core/ControllerConfig.cpp | 569 ++++++++++++---------------------- src/core/config.h | 1 + src/render/Font.cpp | 172 +++++++++- src/render/Font.h | 33 ++ 5 files changed, 403 insertions(+), 372 deletions(-) create mode 100644 gamefiles/models/x360btns.txd diff --git a/gamefiles/models/x360btns.txd b/gamefiles/models/x360btns.txd new file mode 100644 index 0000000000000000000000000000000000000000..27837c2fd71f7f86ab653b5b42358598b3285178 GIT binary patch literal 126760 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 SCREEN_WIDTH || y <= 0.0f || y > SCREEN_HEIGHT) + return; + + if (PS2Symbol != BUTTON_NONE) { + CRect rect; + rect.left = x; + rect.top = Details.scaleY + Details.scaleY + y; + rect.right = Details.scaleY * 17.0f + x; + rect.bottom = Details.scaleY * 19.0f + y; + + int vertexAlphaState; + RwRenderStateGet(rwRENDERSTATEVERTEXALPHAENABLE, &vertexAlphaState); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); + ButtonSprite[PS2Symbol].Draw(rect, CRGBA(255, 255, 255, Details.color.a)); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)vertexAlphaState); + } +} +#endif + void CFont::PrintChar(float x, float y, wchar c) { @@ -822,6 +883,15 @@ CFont::PrintString(float x, float y, wchar *start, wchar *&end, float spwidth, f c = *s - ' '; if (Details.slant != 0.0f && !IsJapanese()) y = (Details.slantRefX - x) * Details.slant + Details.slantRefY; + +#ifdef BUTTON_ICONS + if (PS2Symbol != BUTTON_NONE) { + DrawButton(x, y); + x += Details.scaleY * 17.0f; + PS2Symbol = BUTTON_NONE; + } +#endif + PrintChar(x, y, c); x += GetCharacterSize(c); if (c == 0 && (!NewLine || !IsJapanese())) // space @@ -953,6 +1023,30 @@ CFont::GetStringWidth(wchar *s, bool spaces) do { while (*s == '~' || *s == JAP_TERMINATION) { s++; +#ifdef BUTTON_ICONS + switch (*s) { +#if 0 // unused + case 'U': + case 'D': + case '<': + case '>': +#endif + case 'X': + case 'O': + case 'Q': + case 'T': + case 'K': + case 'M': + case 'A': + case 'J': + case 'V': + case 'C': + w += 17.0f * Details.scaleY; + break; + default: + break; + } +#endif while (!(*s == '~' || *s == JAP_TERMINATION)) s++; s++; } @@ -967,12 +1061,40 @@ CFont::GetStringWidth(wchar *s, bool spaces) for (; (*s != ' ' || spaces) && *s != '\0'; s++) { if (*s == '~') { s++; +#ifdef BUTTON_ICONS + switch (*s) { +#if 0 // unused + case 'U': + case 'D': + case '<': + case '>': +#endif + case 'X': + case 'O': + case 'Q': + case 'T': + case 'K': + case 'M': + case 'A': + case 'J': + case 'V': + case 'C': + w += 17.0f * Details.scaleY; + break; + default: + break; + } +#endif while (*s != '~') s++; +#ifndef FIX_BUGS s++; if (*s == ' ' && !spaces) break; - } - w += GetCharacterSize(*s - ' '); + } +#else + } else +#endif + w += GetCharacterSize(*s - ' '); } } return w; @@ -1026,9 +1148,11 @@ CFont::GetNextSpace(wchar *s) if(*s == '~'){ s++; while(*s != '~') s++; +#ifndef FIX_BUGS s++; if(*s == ' ') break; +#endif } } return s; @@ -1036,7 +1160,7 @@ CFont::GetNextSpace(wchar *s) #ifdef MORE_LANGUAGES wchar* -CFont::ParseToken(wchar *s, wchar*, bool japShit) +CFont::ParseToken(wchar *s, wchar* ss, bool japShit) { s++; if ((Details.color.r || Details.color.g || Details.color.b) && !japShit) { @@ -1056,13 +1180,37 @@ CFont::ParseToken(wchar *s, wchar*, bool japShit) case 'r': SetColor(CRGBA(113, 43, 73, 255)); break; case 'w': SetColor(CRGBA(175, 175, 175, 255)); break; case 'y': SetColor(CRGBA(210, 196, 106, 255)); break; +#ifdef BUTTON_ICONS +#if 0 // unused + case 'U': PS2Symbol = BUTTON_UP; break; + case 'D': PS2Symbol = BUTTON_DOWN; break; + case '<': PS2Symbol = BUTTON_LEFT; break; + case '>': PS2Symbol = BUTTON_RIGHT; break; +#endif + case 'X': PS2Symbol = BUTTON_CROSS; break; + case 'O': PS2Symbol = BUTTON_CIRCLE; break; + case 'Q': PS2Symbol = BUTTON_SQUARE; break; + case 'T': PS2Symbol = BUTTON_TRIANGLE; break; + case 'K': PS2Symbol = BUTTON_L1; break; + case 'M': PS2Symbol = BUTTON_L2; break; + case 'A': PS2Symbol = BUTTON_L3; break; + case 'J': PS2Symbol = BUTTON_R1; break; + case 'V': PS2Symbol = BUTTON_R2; break; + case 'C': PS2Symbol = BUTTON_R3; break; +#endif } } else if (IsJapanese()) { if ((*s & 0x7FFF) == 'N' || (*s & 0x7FFF) == 'n') NewLine = true; } while ((!IsJapanese() || (*s != JAP_TERMINATION)) && *s != '~') s++; +#ifdef FIX_BUGS + if (*(++s) == '~') + s = ParseToken(s, ss, japShit); + return s; +#else return s + 1; +#endif } #else wchar* @@ -1083,6 +1231,24 @@ CFont::ParseToken(wchar *s, wchar*) case 'r': SetColor(CRGBA(0x71, 0x2B, 0x49, 0xFF)); break; case 'w': SetColor(CRGBA(0xAF, 0xAF, 0xAF, 0xFF)); break; case 'y': SetColor(CRGBA(0xD2, 0xC4, 0x6A, 0xFF)); break; +#ifdef BUTTON_ICONS +#if 0 // unused + case 'U': PS2Symbol = BUTTON_UP; break; + case 'D': PS2Symbol = BUTTON_DOWN; break; + case '<': PS2Symbol = BUTTON_LEFT; break; + case '>': PS2Symbol = BUTTON_RIGHT; break; +#endif + case 'X': PS2Symbol = BUTTON_CROSS; break; + case 'O': PS2Symbol = BUTTON_CIRCLE; break; + case 'Q': PS2Symbol = BUTTON_SQUARE; break; + case 'T': PS2Symbol = BUTTON_TRIANGLE; break; + case 'K': PS2Symbol = BUTTON_L1; break; + case 'M': PS2Symbol = BUTTON_L2; break; + case 'A': PS2Symbol = BUTTON_L3; break; + case 'J': PS2Symbol = BUTTON_R1; break; + case 'V': PS2Symbol = BUTTON_R2; break; + case 'C': PS2Symbol = BUTTON_R3; break; +#endif } while(*s != '~') s++; return s+1; diff --git a/src/render/Font.h b/src/render/Font.h index 51035601..be1eabed 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -63,6 +63,31 @@ enum #define FONT_LOCALE(style) (style) #endif +#ifdef BUTTON_ICONS +enum +{ + BUTTON_NONE = -1, +#if 0 // unused + BUTTON_UP, + BUTTON_DOWN, + BUTTON_LEFT, + BUTTON_RIGHT, +#endif + BUTTON_CROSS, + BUTTON_CIRCLE, + BUTTON_SQUARE, + BUTTON_TRIANGLE, + BUTTON_L1, + BUTTON_L2, + BUTTON_L3, + BUTTON_R1, + BUTTON_R2, + BUTTON_R3, + MAX_BUTTON_ICONS +}; +#endif // BUTTON_ICONS + + class CFont { #ifdef MORE_LANGUAGES @@ -77,6 +102,14 @@ public: static CSprite2d Sprite[MAX_FONTS]; static CFontDetails Details; +#ifdef BUTTON_ICONS + static CSprite2d ButtonSprite[MAX_BUTTON_ICONS]; + static int PS2Symbol; + + static void DrawButton(float x, float y); +#endif // BUTTON_ICONS + + static void Initialise(void); static void Shutdown(void); static void InitPerFrame(void); From 8614f6862050d5e13c7a351cb4fafb4b983a8390 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 5 Nov 2020 16:42:42 +0100 Subject: [PATCH 032/129] RwRenderStateGet --- src/fakerw/fake.cpp | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index b9ff0144..58b3277a 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -462,6 +462,53 @@ RwBool RwIm3DRenderPrimitive(RwPrimitiveType primType); +RwBool RwRenderStateGet(RwRenderState state, void *value) +{ + uint32 *uival = (uint32*)value; + uint32 fog; + switch(state){ + case rwRENDERSTATETEXTURERASTER: *(void**)value = GetRenderStatePtr(TEXTURERASTER); return true; + case rwRENDERSTATETEXTUREADDRESS: *uival = GetRenderState(TEXTUREADDRESS); return true; + case rwRENDERSTATETEXTUREADDRESSU: *uival = GetRenderState(TEXTUREADDRESSU); return true; + case rwRENDERSTATETEXTUREADDRESSV: *uival = GetRenderState(TEXTUREADDRESSV); return true; + case rwRENDERSTATETEXTUREPERSPECTIVE: *uival = 1; return true; + case rwRENDERSTATEZTESTENABLE: *uival = GetRenderState(ZTESTENABLE); return true; + case rwRENDERSTATESHADEMODE: *uival = rwSHADEMODEGOURAUD; return true; + case rwRENDERSTATEZWRITEENABLE: *uival = GetRenderState(ZWRITEENABLE); return true; + case rwRENDERSTATETEXTUREFILTER: *uival = GetRenderState(TEXTUREFILTER); return true; + case rwRENDERSTATESRCBLEND: *uival = GetRenderState(SRCBLEND); return true; + case rwRENDERSTATEDESTBLEND: *uival = GetRenderState(DESTBLEND); return true; + case rwRENDERSTATEVERTEXALPHAENABLE: *uival = GetRenderState(VERTEXALPHA); return true; + case rwRENDERSTATEBORDERCOLOR: *uival = 0; return true; + case rwRENDERSTATEFOGENABLE: *uival = GetRenderState(FOGENABLE); return true; + case rwRENDERSTATEFOGCOLOR: + // have to swap R and B here + fog = GetRenderState(FOGCOLOR); + *uival = (fog>>16)&0xFF; + *uival |= (fog&0xFF)<<16; + *uival |= fog&0xFF00; + *uival |= fog&0xFF000000; + return true; + case rwRENDERSTATEFOGTYPE: *uival = rwFOGTYPELINEAR; return true; + case rwRENDERSTATEFOGDENSITY: *(float*)value = 1.0f; return true; + case rwRENDERSTATECULLMODE: *uival = GetRenderState(CULLMODE); return true; + + // all unsupported + case rwRENDERSTATEFOGTABLE: + case rwRENDERSTATEALPHAPRIMITIVEBUFFER: + + case rwRENDERSTATESTENCILENABLE: + case rwRENDERSTATESTENCILFAIL: + case rwRENDERSTATESTENCILZFAIL: + case rwRENDERSTATESTENCILPASS: + case rwRENDERSTATESTENCILFUNCTION: + case rwRENDERSTATESTENCILFUNCTIONREF: + case rwRENDERSTATESTENCILFUNCTIONMASK: + case rwRENDERSTATESTENCILFUNCTIONWRITEMASK: + default: + return false; + } +} RwBool RwRenderStateSet(RwRenderState state, void *value) { uint32 uival = (uintptr)value; From bd78b5ff4e4d909c7d290b2a1bc823397ca3f930 Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 5 Nov 2020 19:57:13 +0100 Subject: [PATCH 033/129] add bInvertLook4Pad from VC (doesn't get saved yet) --- src/core/Frontend.cpp | 5 +++++ src/core/Frontend.h | 3 +++ src/core/Pad.cpp | 19 ++++++++++++++++++- src/core/Pad.h | 3 +++ src/core/config.h | 1 + 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index cf25e1b9..879bcb29 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -5404,6 +5404,11 @@ CMenuManager::ProcessOnOffMenuOptions() DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); SaveSettings(); break; +#ifdef INVERT_LOOK_FOR_PAD + case MENUACTION_INVERTPADY: + CPad::bInvertLook4Pad = !CPad::bInvertLook4Pad; + break; +#endif } } diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 70b4cd31..947311b6 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -383,6 +383,9 @@ enum eMenuAction //#ifdef NO_ISLAND_LOADING // MENUACTION_ISLANDLOADING, //#endif +#ifdef INVERT_LOOK_FOR_PAD + MENUACTION_INVERTPADY, +#endif }; enum eCheckHover diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 0e2f06a6..104c8b40 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -59,6 +59,9 @@ bool CPad::bDisplayNoControllerMessage; bool CPad::bObsoleteControllerMessage; bool CPad::bOldDisplayNoControllerMessage; bool CPad::m_bMapPadOneToPadTwo; +#ifdef INVERT_LOOK_FOR_PAD +bool CPad::bInvertLook4Pad; +#endif #ifdef GTA_PS2 unsigned char act_direct[6]; unsigned char act_align[6]; @@ -2534,10 +2537,20 @@ int16 CPad::SniperModeLookLeftRight(void) int16 CPad::SniperModeLookUpDown(void) { int16 axis = NewState.LeftStickY; + int16 dpad; #ifdef FIX_BUGS axis = -axis; #endif - int16 dpad = (NewState.DPadUp - NewState.DPadDown) / 2; +#ifndef INVERT_LOOK_FOR_PAD + dpad = (NewState.DPadUp - NewState.DPadDown) / 2; +#else + if (CPad::bInvertLook4Pad) { + axis = -axis; + dpad = (NewState.DPadDown - NewState.DPadUp) / 2; + } else { + dpad = (NewState.DPadUp - NewState.DPadDown) / 2; + } +#endif if ( Abs(axis) > Abs(dpad) ) return axis; @@ -2567,6 +2580,10 @@ int16 CPad::LookAroundUpDown(void) #ifdef FIX_BUGS axis = -axis; #endif +#ifdef INVERT_LOOK_FOR_PAD + if (CPad::bInvertLook4Pad) + axis = -axis; +#endif if ( Abs(axis) > 85 && !GetLookBehindForPed() ) return (int16) ( (axis + ( ( axis > 0 ) ? -85 : 85) ) diff --git a/src/core/Pad.h b/src/core/Pad.h index 8c5d7ba3..20a676ef 100644 --- a/src/core/Pad.h +++ b/src/core/Pad.h @@ -170,6 +170,9 @@ public: static bool bObsoleteControllerMessage; static bool bOldDisplayNoControllerMessage; static bool m_bMapPadOneToPadTwo; +#ifdef INVERT_LOOK_FOR_PAD + static bool bInvertLook4Pad; +#endif static CKeyboardState OldKeyState; static CKeyboardState NewKeyState; diff --git a/src/core/config.h b/src/core/config.h index bdc5cd54..e604699d 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -259,6 +259,7 @@ enum Config { #define REGISTER_START_BUTTON //#define BIND_VEHICLE_FIREWEAPON // Adds ability to rebind fire key for 'in vehicle' controls #define BUTTON_ICONS // use textures to show controller buttons +#define INVERT_LOOK_FOR_PAD // add bInvertLook4Pad from VC // Hud, frontend and radar #define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better. From f442793d201bd905c38c4861c564ba2896b8cd88 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Tue, 3 Nov 2020 18:00:10 +0100 Subject: [PATCH 034/129] Allow to handle larger files via 64bit variables --- src/core/CdStream.cpp | 9 ++++++++- src/core/CdStreamPosix.cpp | 2 +- src/core/config.h | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index c11fb72a..1d39aa52 100644 --- a/src/core/CdStream.cpp +++ b/src/core/CdStream.cpp @@ -242,8 +242,15 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) else return STREAM_SUCCESS; } - + +#ifdef BIG_IMG + LARGE_INTEGER liDistanceToMove; + liDistanceToMove.QuadPart = _GET_OFFSET(offset); + liDistanceToMove.QuadPart *= CDSTREAM_SECTOR_SIZE; + SetFilePointerEx(hImage, liDistanceToMove, nil, FILE_BEGIN); +#else SetFilePointer(hImage, _GET_OFFSET(offset) * CDSTREAM_SECTOR_SIZE, nil, FILE_BEGIN); +#endif DWORD NumberOfBytesRead; diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index 5c8d1b16..35a90a74 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -429,7 +429,7 @@ void *CdStreamThread(void *param) ASSERT(pChannel->hFile >= 0); ASSERT(pChannel->pBuffer != nil ); - lseek(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, SEEK_SET); + lseek(pChannel->hFile, (size_t)pChannel->nSectorOffset * (size_t)CDSTREAM_SECTOR_SIZE, SEEK_SET); if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) { // pChannel->nSectorsToRead == 0 at this point means we wanted to flush channel // STREAM_WAITING is a little hack to make CStreaming not process this data diff --git a/src/core/config.h b/src/core/config.h index bdc5cd54..48e616bd 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -326,6 +326,8 @@ enum Config { #endif //#define PS2_AUDIO // changes audio paths for cutscenes and radio to PS2 paths, needs vbdec to support VB with MSS +// IMG +#define BIG_IMG // allows to read larger img files //#define SQUEEZE_PERFORMANCE #ifdef SQUEEZE_PERFORMANCE From 3b81eaa2d74b6f820f2651b6e468588b514ea5c9 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 7 Nov 2020 12:59:53 +0200 Subject: [PATCH 035/129] Fix cAudioManager::GetPhrase --- src/audio/AudioLogic.cpp | 796 +++++++++++++++++++-------------------- src/audio/AudioManager.h | 2 +- 2 files changed, 399 insertions(+), 399 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 3fc9334f..6bfe3cde 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -3992,15 +3992,15 @@ cAudioManager::GetPedCommentSfx(CPed *ped, int32 sound) } void -cAudioManager::GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint32 maxOffset) const +cAudioManager::GetPhrase(uint32 &phrase, uint32 &prevPhrase, uint32 sample, uint32 maxOffset) const { - *phrase = sample + m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % maxOffset; + phrase = sample + m_anRandomTable[m_sQueueSample.m_nEntityIndex & 3] % maxOffset; // check if the same sfx like last time, if yes, then try use next one, // if exceeded range, then choose first available sample - if (*phrase == *prevPhrase && ++*phrase >= sample + maxOffset) - *phrase = sample; - *prevPhrase = *phrase; + if (phrase == prevPhrase && ++phrase >= sample + maxOffset) + phrase = sample; + prevPhrase = phrase; } #pragma region PED_COMMENTS @@ -4013,13 +4013,13 @@ cAudioManager::GetPlayerTalkSfx(int16 sound) switch (sound) { case SOUND_PED_DAMAGE: - GetPhrase(&sfx, &lastSfx, SFX_CLAUDE_HIGH_DAMAGE_GRUNT_1, 11); + GetPhrase(sfx, lastSfx, SFX_CLAUDE_HIGH_DAMAGE_GRUNT_1, 11); break; case SOUND_PED_HIT: - GetPhrase(&sfx, &lastSfx, SFX_CLAUDE_LOW_DAMAGE_GRUNT_1, 10); + GetPhrase(sfx, lastSfx, SFX_CLAUDE_LOW_DAMAGE_GRUNT_1, 10); break; case SOUND_PED_LAND: - GetPhrase(&sfx, &lastSfx, SFX_CLAUDE_HIT_GROUND_GRUNT_1, 6); + GetPhrase(sfx, lastSfx, SFX_CLAUDE_HIT_GROUND_GRUNT_1, 6); break; default: sfx = NO_SAMPLE; @@ -4037,13 +4037,13 @@ cAudioManager::GetCopTalkSfx(int16 sound) switch (sound) { case SOUND_PED_ARREST_COP: - GetPhrase(&sfx, &lastSfx, SFX_COP_VOICE_1_ARREST_1, 6); + GetPhrase(sfx, lastSfx, SFX_COP_VOICE_1_ARREST_1, 6); break; case SOUND_PED_PURSUIT_COP: pedState = FindPlayerPed()->m_nPedState; if (pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE; - GetPhrase(&sfx, &lastSfx, SFX_COP_VOICE_1_CHASE_1, 7); + GetPhrase(sfx, lastSfx, SFX_COP_VOICE_1_CHASE_1, 7); break; default: return GetGenericMaleTalkSfx(sound); @@ -4061,13 +4061,13 @@ cAudioManager::GetSwatTalkSfx(int16 sound) switch (sound) { case SOUND_PED_ARREST_SWAT: - GetPhrase(&sfx, &lastSfx, SFX_SWAT_VOICE_1_CHASE_1, 6); + GetPhrase(sfx, lastSfx, SFX_SWAT_VOICE_1_CHASE_1, 6); break; case SOUND_PED_PURSUIT_SWAT: pedState = FindPlayerPed()->m_nPedState; if (pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE; - GetPhrase(&sfx, &lastSfx, SFX_SWAT_VOICE_1_CHASE_1, 6); + GetPhrase(sfx, lastSfx, SFX_SWAT_VOICE_1_CHASE_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -4085,13 +4085,13 @@ cAudioManager::GetFBITalkSfx(int16 sound) switch (sound) { case SOUND_PED_ARREST_FBI: - GetPhrase(&sfx, &lastSfx, SFX_FBI_VOICE_1_CHASE_1, 6); + GetPhrase(sfx, lastSfx, SFX_FBI_VOICE_1_CHASE_1, 6); break; case SOUND_PED_PURSUIT_FBI: pedState = FindPlayerPed()->m_nPedState; if (pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE; - GetPhrase(&sfx, &lastSfx, SFX_FBI_VOICE_1_CHASE_1, 6); + GetPhrase(sfx, lastSfx, SFX_FBI_VOICE_1_CHASE_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -4111,7 +4111,7 @@ cAudioManager::GetArmyTalkSfx(int16 sound) case SOUND_PED_PURSUIT_ARMY: pedState = FindPlayerPed()->m_nPedState; if(pedState == PED_ARRESTED || pedState == PED_DEAD || pedState == PED_DIE) return NO_SAMPLE; - GetPhrase(&sfx, &lastSfx, SFX_ARMY_VOICE_1_CHASE_1, 15); + GetPhrase(sfx, lastSfx, SFX_ARMY_VOICE_1_CHASE_1, 15); break; default: return GetGenericMaleTalkSfx(sound); } @@ -4127,19 +4127,19 @@ cAudioManager::GetMedicTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_GUN_PANIC_1, 5); + GetPhrase(sfx, lastSfx, SFX_MEDIC_VOICE_1_GUN_PANIC_1, 5); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_CARJACKED_1, 5); + GetPhrase(sfx, lastSfx, SFX_MEDIC_VOICE_1_CARJACKED_1, 5); break; case SOUND_PED_HEALING: - GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_AT_VICTIM_1, 12); + GetPhrase(sfx, lastSfx, SFX_MEDIC_VOICE_1_AT_VICTIM_1, 12); break; case SOUND_PED_LEAVE_VEHICLE: - GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_GET_OUT_VAN_CHAT_1, 9); + GetPhrase(sfx, lastSfx, SFX_MEDIC_VOICE_1_GET_OUT_VAN_CHAT_1, 9); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_MEDIC_VOICE_1_RUN_FROM_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_MEDIC_VOICE_1_RUN_FROM_FIGHT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -4161,28 +4161,28 @@ cAudioManager::GetNormalMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_GUN_PANIC_1, 7); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_GUN_PANIC_1, 7); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_CARJACKED_1, 7); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_CARJACKED_1, 7); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_DODGE_1, 9); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_DODGE_1, 9); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_RUN_FROM_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_RUN_FROM_FIGHT_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_DRIVER_ABUSE_1, 12); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_DRIVER_ABUSE_1, 12); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_EYING_1, 8); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_EYING_1, 8); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_SHOCKED_1, 10); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_SHOCKED_1, 10); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_NORMAL_MALE_CHAT_1, 25); + GetPhrase(sfx, lastSfx, SFX_NORMAL_MALE_CHAT_1, 25); break; default: return GetGenericMaleTalkSfx(sound); @@ -4198,10 +4198,10 @@ cAudioManager::GetTaxiDriverTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_ASIAN_TAXI_DRIVER_VOICE_1_CARJACKED_1, 7); + GetPhrase(sfx, lastSfx, SFX_ASIAN_TAXI_DRIVER_VOICE_1_CARJACKED_1, 7); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_ASIAN_TAXI_DRIVER_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_ASIAN_TAXI_DRIVER_VOICE_1_DRIVER_ABUSE_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -4218,25 +4218,25 @@ cAudioManager::GetPimpTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_PIMP_GUN_COOL_1, 7); + GetPhrase(sfx, lastSfx, SFX_PIMP_GUN_COOL_1, 7); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_PIMP_CARJACKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_PIMP_CARJACKED_1, 4); break; case SOUND_PED_DEFEND: - GetPhrase(&sfx, &lastSfx, SFX_PIMP_FIGHT_1, 9); + GetPhrase(sfx, lastSfx, SFX_PIMP_FIGHT_1, 9); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_PIMP_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_PIMP_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_PIMP_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_PIMP_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_PIMP_SHOCKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_PIMP_SHOCKED_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_PIMP_CHAT_1, 17); + GetPhrase(sfx, lastSfx, SFX_PIMP_CHAT_1, 17); break; default: return GetGenericMaleTalkSfx(sound); @@ -4252,25 +4252,25 @@ cAudioManager::GetMafiaTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKING: - GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKING_1, 2); + GetPhrase(sfx, lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKING_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_MAFIA_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_MAFIA_MALE_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_MAFIA_MALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_MAFIA_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_MAFIA_MALE_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_MAFIA_MALE_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_MAFIA_MALE_VOICE_1_CHAT_1, 7); break; default: return GetGenericMaleTalkSfx(sound); @@ -4286,28 +4286,28 @@ cAudioManager::GetTriadTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_GUN_COOL_1, 3); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_GUN_COOL_1, 3); break; case SOUND_PED_CAR_JACKING: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKING_1, 2); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKING_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_TRIAD_MALE_VOICE_1_CHAT_1, 8); + GetPhrase(sfx, lastSfx, SFX_TRIAD_MALE_VOICE_1_CHAT_1, 8); break; default: return GetGenericMaleTalkSfx(sound); @@ -4323,32 +4323,32 @@ cAudioManager::GetDiabloTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_GUN_COOL_1, 4); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_GUN_COOL_1, 4); break; case SOUND_PED_HANDS_COWER: sound = SOUND_PED_FLEE_SPRINT; return GetGenericMaleTalkSfx(sound); break; case SOUND_PED_CAR_JACKING: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKING_1, 2); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKING_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_EYING_1, 4); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_EYING_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_DIABLO_MALE_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_DIABLO_MALE_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -4364,22 +4364,22 @@ cAudioManager::GetYakuzaTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKING: - GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKING_1, 2); + GetPhrase(sfx, lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKING_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_YAKUZA_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_YAKUZA_MALE_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_YAKUZA_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_YAKUZA_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_YAKUZA_MALE_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_YAKUZA_MALE_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -4398,25 +4398,25 @@ cAudioManager::GetYardieTalkSfx(int16 sound) sfx = SFX_YARDIE_MALE_VOICE_1_GUN_COOL_1; break; case SOUND_PED_CAR_JACKING: - GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_CARJACKING_1, 2); + GetPhrase(sfx, lastSfx, SFX_YARDIE_MALE_VOICE_1_CARJACKING_1, 2); break; case SOUND_PED_CAR_JACKED: sfx = SFX_YARDIE_MALE_VOICE_1_CARJACKED_1; break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_YARDIE_MALE_VOICE_1_FIGHT_1, 6); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_YARDIE_MALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_YARDIE_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_EYING_1, 2); + GetPhrase(sfx, lastSfx, SFX_YARDIE_MALE_VOICE_1_EYING_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_YARDIE_MALE_VOICE_1_CHAT_1, 8); + GetPhrase(sfx, lastSfx, SFX_YARDIE_MALE_VOICE_1_CHAT_1, 8); break; default: return GetGenericMaleTalkSfx(sound); @@ -4432,25 +4432,25 @@ cAudioManager::GetColumbianTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKING: - GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKING_1, 2); + GetPhrase(sfx, lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKING_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_EYING_1, 2); + GetPhrase(sfx, lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_EYING_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_COLUMBIAN_MALE_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -4466,28 +4466,28 @@ cAudioManager::GetHoodTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_GUN_COOL_1, 5); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_GUN_COOL_1, 5); break; case SOUND_PED_CAR_JACKING: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKING_1, 2); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKING_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_FIGHT_1, 6); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_EYING_1, 2); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_EYING_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_HOOD_MALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_HOOD_MALE_VOICE_1_CHAT_1, 6); break; default: @@ -4505,22 +4505,22 @@ cAudioManager::GetBlackCriminalTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_GUN_COOL_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_GUN_COOL_1, 4); break; case SOUND_PED_CAR_JACKING: sfx = SFX_BLACK_CRIMINAL_VOICE_1_CARJACKING_1; break; case SOUND_PED_MUGGING: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_MUGGING_1, 2); + GetPhrase(sfx, lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_MUGGING_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_CRIMINAL_VOICE_1_DRIVER_ABUSE_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -4537,22 +4537,22 @@ cAudioManager::GetWhiteCriminalTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_GUN_COOL_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_GUN_COOL_1, 3); break; case SOUND_PED_CAR_JACKING: sfx = SFX_WHITE_CRIMINAL_VOICE_1_CARJACKING_1; break; case SOUND_PED_MUGGING: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_MUGGING_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_MUGGING_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_CRIMINAL_VOICE_1_DRIVER_ABUSE_1, 4); break; default: return GetGenericMaleTalkSfx(sound); @@ -4569,25 +4569,25 @@ cAudioManager::GetMaleNo2TalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CARJACKED_1, 3); + GetPhrase(sfx, lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CARJACKED_1, 3); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_MUGGED_1, 4); + GetPhrase(sfx, lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_MUGGED_1, 4); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_EYING_1, 5); + GetPhrase(sfx, lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_EYING_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_CASUAL_MALE_OLD_VOICE_1_CHAT_1, 7); break; default: return GetGenericMaleTalkSfx(sound); @@ -4602,14 +4602,14 @@ cAudioManager::GetBlackProjectMaleTalkSfx(int16 sound, int32 model) static uint32 lastSfx = NO_SAMPLE; switch(sound) { - case SOUND_PED_HANDS_UP: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_GUN_COOL_1, 3); break; - case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_CARJACKED_1, 2); break; - case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_MUGGED_1, 2); break; - case SOUND_PED_ATTACK: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_FIGHT_1, 6); break; - case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_DODGE_1, 5); break; - case SOUND_PED_ANNOYED_DRIVER: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_DRIVER_ABUSE_1, 7); break; - case SOUND_PED_CHAT_SEXY: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_EYING_1, 3); break; - case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_CHAT_1, 6); break; + case SOUND_PED_HANDS_UP: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_GUN_COOL_1, 3); break; + case SOUND_PED_CAR_JACKED: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_CARJACKED_1, 2); break; + case SOUND_PED_ROBBED: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_MUGGED_1, 2); break; + case SOUND_PED_ATTACK: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_FIGHT_1, 6); break; + case SOUND_PED_EVADE: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_DODGE_1, 5); break; + case SOUND_PED_ANNOYED_DRIVER: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_DRIVER_ABUSE_1, 7); break; + case SOUND_PED_CHAT_SEXY: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_EYING_1, 3); break; + case SOUND_PED_CHAT: GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_MALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); } @@ -4625,12 +4625,12 @@ cAudioManager::GetWhiteFatMaleTalkSfx(int16 sound) static uint32 lastSfx = NO_SAMPLE; switch(sound) { - case SOUND_PED_CAR_JACKED: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_CARJACKED_1, 3); break; - case SOUND_PED_ROBBED: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_MUGGED_1, 3); break; - case SOUND_PED_EVADE: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_DODGE_1, 9); break; - case SOUND_PED_ANNOYED_DRIVER: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_DRIVER_ABUSE_1, 9); break; - case SOUND_PED_WAIT_DOUBLEBACK: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_LOST_1, 2); break; - case SOUND_PED_CHAT: GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_CHAT_1, 9); break; + case SOUND_PED_CAR_JACKED: GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_CARJACKED_1, 3); break; + case SOUND_PED_ROBBED: GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_MUGGED_1, 3); break; + case SOUND_PED_EVADE: GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_DODGE_1, 9); break; + case SOUND_PED_ANNOYED_DRIVER: GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_DRIVER_ABUSE_1, 9); break; + case SOUND_PED_WAIT_DOUBLEBACK: GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_LOST_1, 2); break; + case SOUND_PED_CHAT: GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_MALE_VOICE_1_CHAT_1, 9); break; default: return GetGenericMaleTalkSfx(sound); } return sfx; @@ -4644,22 +4644,22 @@ cAudioManager::GetBlackFatMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_CARJACKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_CARJACKED_1, 4); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_MUGGED_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_MUGGED_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_DODGE_1, 7); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_DODGE_1, 7); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_WAIT_DOUBLEBACK: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_LOST_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_LOST_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_CHAT_1, 8); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_MALE_VOICE_1_CHAT_1, 8); break; default: return GetGenericMaleTalkSfx(sound); @@ -4675,28 +4675,28 @@ cAudioManager::GetBlackCasualFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_GUN_PANIC_1, 2); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_GUN_PANIC_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_MUGGED_1, 3); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_MUGGED_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_DODGE_1, 6); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_RUN_FROM_FIGHT_1, 2); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_RUN_FROM_FIGHT_1, 2); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_1_VOICE_1_CHAT_1, 8); + GetPhrase(sfx, lastSfx, SFX_FEMALE_1_VOICE_1_CHAT_1, 8); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4712,28 +4712,28 @@ cAudioManager::GetWhiteCasualFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_GUN_PANIC_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_GUN_PANIC_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: sfx = SFX_WHITE_CASUAL_FEMALE_VOICE_1_MUGGED_1; break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_DODGE_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_DODGE_1, 3); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 2); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 8); + GetPhrase(sfx, lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 8); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_SHOCKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_SHOCKED_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_CHAT_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_CASUAL_FEMALE_VOICE_1_CHAT_1, 4); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4749,28 +4749,28 @@ cAudioManager::GetFemaleNo3TalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_GUN_PANIC_1, 5); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_GUN_PANIC_1, 5); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_CARJACKED_1, 3); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_CARJACKED_1, 3); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_MUGGED_1, 3); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_MUGGED_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_DODGE_1, 6); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_RUN_FROM_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_RUN_FROM_FIGHT_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_FEMALE_3_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_FEMALE_3_VOICE_1_CHAT_1, 5); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4786,25 +4786,25 @@ cAudioManager::GetBlackFatFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_SHOCKED_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_SHOCKED_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_BLACK_FAT_FEMALE_VOICE_1_CHAT_1, 7); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4820,25 +4820,25 @@ cAudioManager::GetWhiteFatFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 8); + GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 8); break; case SOUND_PED_WAIT_DOUBLEBACK: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_LOST_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_LOST_1, 2); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_CHAT_1, 8); + GetPhrase(sfx, lastSfx, SFX_WHITE_FAT_FEMALE_VOICE_1_CHAT_1, 8); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4854,25 +4854,25 @@ cAudioManager::GetBlackFemaleProstituteTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_GUN_COOL_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_GUN_COOL_1, 4); break; case SOUND_PED_ROBBED: sfx = SFX_BLACK_PROSTITUTE_VOICE_1_MUGGED_1; break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_DODGE_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_DODGE_1, 3); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_DRIVER_ABUSE_1, 4); break; case SOUND_PED_SOLICIT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_SOLICIT_1, 8); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_SOLICIT_1, 8); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_CHAT_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROSTITUTE_VOICE_1_CHAT_1, 4); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4888,22 +4888,22 @@ cAudioManager::GetWhiteFemaleProstituteTalkSfx(int16 sound) switch (sound) { case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_DODGE_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_DODGE_1, 3); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_DRIVER_ABUSE_1, 4); break; case SOUND_PED_SOLICIT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_SOLICIT_1, 8); + GetPhrase(sfx, lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_SOLICIT_1, 8); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_CHAT_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_PROSTITUTE_VOICE_1_CHAT_1, 4); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4919,25 +4919,25 @@ cAudioManager::GetBlackProjectFemaleOldTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_CARJACKED_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_CARJACKED_1, 6); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_DODGE_1, 10); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_DODGE_1, 10); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_RUN_FROM_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_RUN_FROM_FIGHT_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_SHOCKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_SHOCKED_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_CHAT_1, 10); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_OLD_VOICE_1_CHAT_1, 10); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4953,25 +4953,25 @@ cAudioManager::GetBlackProjectFemaleYoungTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_CAR_JACKED: sfx = SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_CARJACKED_1; break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_SHOCKED_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_SHOCKED_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_BLACK_PROJECT_FEMALE_YOUNG_VOICE_1_CHAT_1, 7); break; default: return GetGenericFemaleTalkSfx(sound); @@ -4987,25 +4987,25 @@ cAudioManager::GetChinatownMaleOldTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_OLD_VOICE_1_CHAT_1, 7); break; default: return GetGenericMaleTalkSfx(sound); @@ -5021,25 +5021,25 @@ cAudioManager::GetChinatownMaleYoungTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_GUN_PANIC_1, 2); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_GUN_PANIC_1, 2); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_FIGHT_1, 6); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_MALE_YOUNG_VOICE_1_CHAT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -5055,22 +5055,22 @@ cAudioManager::GetChinatownFemaleOldTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT_EVENT: sfx = SFX_CHINATOWN_OLD_FEMALE_VOICE_1_SHOCKED_1; break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_OLD_FEMALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5086,22 +5086,22 @@ cAudioManager::GetChinatownFemaleYoungTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_CHINATOWN_YOUNG_FEMALE_VOICE_1_CHAT_1, 7); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5117,25 +5117,25 @@ cAudioManager::GetLittleItalyMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_MALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -5151,22 +5151,22 @@ cAudioManager::GetLittleItalyFemaleOldTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_OLD_FEMALE_VOICE_1_CHAT_1, 7); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5182,22 +5182,22 @@ cAudioManager::GetLittleItalyFemaleYoungTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_DODGE_1, 7); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_DODGE_1, 7); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_LITTLE_ITALY_YOUNG_FEMALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5213,22 +5213,22 @@ cAudioManager::GetWhiteDockerMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_GUN_PANIC_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_GUN_PANIC_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_FIGHT_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_FIGHT_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_DRIVER_ABUSE_1, 4); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_WHITE_DOCKER_MALE_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -5244,22 +5244,22 @@ cAudioManager::GetBlackDockerMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_DOCKER_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_DOCKER_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_DOCKER_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_DOCKER_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_DOCKER_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_DOCKER_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_DOCKER_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -5275,28 +5275,28 @@ cAudioManager::GetScumMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_GUN_PANIC_1, 5); + GetPhrase(sfx, lastSfx, SFX_SCUM_MALE_VOICE_1_GUN_PANIC_1, 5); break; case SOUND_PED_ROBBED: sfx = SFX_SCUM_MALE_VOICE_1_MUGGED_1; break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_FIGHT_1, 10); + GetPhrase(sfx, lastSfx, SFX_SCUM_MALE_VOICE_1_FIGHT_1, 10); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_SCUM_MALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_SCUM_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_WAIT_DOUBLEBACK: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_LOST_1, 3); + GetPhrase(sfx, lastSfx, SFX_SCUM_MALE_VOICE_1_LOST_1, 3); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_EYING_1, 5); + GetPhrase(sfx, lastSfx, SFX_SCUM_MALE_VOICE_1_EYING_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_MALE_VOICE_1_CHAT_1, 9); + GetPhrase(sfx, lastSfx, SFX_SCUM_MALE_VOICE_1_CHAT_1, 9); break; default: return GetGenericMaleTalkSfx(sound); @@ -5312,22 +5312,22 @@ cAudioManager::GetScumFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_SCUM_FEMALE_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_SCUM_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_SCUM_FEMALE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_DODGE_1, 8); + GetPhrase(sfx, lastSfx, SFX_SCUM_FEMALE_VOICE_1_DODGE_1, 8); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_SCUM_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_SCUM_FEMALE_VOICE_1_CHAT_1, 13); + GetPhrase(sfx, lastSfx, SFX_SCUM_FEMALE_VOICE_1_CHAT_1, 13); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5343,22 +5343,22 @@ cAudioManager::GetWhiteWorkerMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_FIGHT_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_FIGHT_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_EYING_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_EYING_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_WHITE_WORKER_MALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -5374,22 +5374,22 @@ cAudioManager::GetBlackWorkerMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_FIGHT_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_FIGHT_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_DODGE_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_DODGE_1, 3); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_DRIVER_ABUSE_1, 4); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_CHAT_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_WORKER_MALE_VOICE_1_CHAT_1, 4); break; default: return GetGenericMaleTalkSfx(sound); @@ -5405,28 +5405,28 @@ cAudioManager::GetBusinessMaleYoungTalkSfx(int16 sound, int32 model) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_DODGE_1, 4); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_RUN_FROM_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_RUN_FROM_FIGHT_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_YOUNG_VOICE_1_CHAT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -5445,28 +5445,28 @@ cAudioManager::GetBusinessMaleOldTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_DODGE_1, 4); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MRUN_FROM_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_MRUN_FROM_FIGHT_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BUSINESS_MALE_OLD_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -5482,28 +5482,28 @@ cAudioManager::GetWhiteBusinessFemaleTalkSfx(int16 sound, int32 model) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_WHITE_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5522,28 +5522,28 @@ cAudioManager::GetBlackBusinessFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_GUN_PANIC_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_GUN_PANIC_1, 5); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_CARAJACKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_CARAJACKED_1, 4); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_MUGGED_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_DODGE_1, 6); break; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_RUN_FROM_FIGHT_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_BLACK_BUSINESS_FEMALE_VOICE_1_CHAT_1, 7); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5559,25 +5559,25 @@ cAudioManager::GetSupermodelMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_MODEL_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_MODEL_MALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_MODEL_MALE_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_MODEL_MALE_VOICE_1_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_MODEL_MALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_MODEL_MALE_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_MALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_MODEL_MALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -5593,22 +5593,22 @@ cAudioManager::GetSupermodelFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_MODEL_FEMALE_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_MUGGED_1, 3); + GetPhrase(sfx, lastSfx, SFX_MODEL_FEMALE_VOICE_1_MUGGED_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_MODEL_FEMALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_MODEL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_SHOCKED_1, 5); + GetPhrase(sfx, lastSfx, SFX_MODEL_FEMALE_VOICE_1_SHOCKED_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_MODEL_FEMALE_VOICE_1_CHAT_1, 8); + GetPhrase(sfx, lastSfx, SFX_MODEL_FEMALE_VOICE_1_CHAT_1, 8); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5624,19 +5624,19 @@ cAudioManager::GetStewardMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_STEWARD_MALE_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_STEWARD_MALE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_DODGE_1, 3); + GetPhrase(sfx, lastSfx, SFX_STEWARD_MALE_VOICE_1_DODGE_1, 3); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_STEWARD_MALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_MALE_VOICE_1_CHAT_1, 4); + GetPhrase(sfx, lastSfx, SFX_STEWARD_MALE_VOICE_1_CHAT_1, 4); break; default: return GetGenericMaleTalkSfx(sound); @@ -5652,16 +5652,16 @@ cAudioManager::GetStewardFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_STEWARD_FEMALE_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_STEWARD_FEMALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_STEWARD_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_STEWARD_FEMALE_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_STEWARD_FEMALE_VOICE_1_CHAT_1, 5); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5677,19 +5677,19 @@ cAudioManager::GetFanMaleTalkSfx(int16 sound, int32 model) switch (sound) { case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_FIGHT_1, 3); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_MALE_VOICE_1_FIGHT_1, 3); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_MALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_SHOCKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_MALE_VOICE_1_SHOCKED_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_MALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_MALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericMaleTalkSfx(sound); @@ -5711,16 +5711,16 @@ cAudioManager::GetFanFemaleTalkSfx(int16 sound) sfx = SFX_FOOTBALL_FEMALE_VOICE_1_MUGGED_1; break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_SHOCKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_SHOCKED_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_FOOTBALL_FEMALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5736,19 +5736,19 @@ cAudioManager::GetHospitalMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_MALE_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_MALE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_MALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_MALE_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_MALE_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -5764,13 +5764,13 @@ cAudioManager::GetHospitalFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_CHAT_1, 6); + GetPhrase(sfx, lastSfx, SFX_HOSPITAL_FEMALE_VOICE_1_CHAT_1, 6); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5786,25 +5786,25 @@ cAudioManager::GetWhiteConstructionWorkerTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_CAR_JACKED: sfx = SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_CARJACKED_1; break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_DRIVER_ABUSE_1, 4); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_EYING_1, 3); + GetPhrase(sfx, lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_EYING_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_WHITE_MALE_CONSTRUCTION_VOICE_1_CHAT_1, 7); break; default: return GetGenericMaleTalkSfx(sound); @@ -5820,25 +5820,25 @@ cAudioManager::GetBlackConstructionWorkerTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_GUN_PANIC_1, 3); + GetPhrase(sfx, lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_GUN_PANIC_1, 3); break; case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_FIGHT_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_FIGHT_1, 5); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_DODGE_1, 5); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_DRIVER_ABUSE_1, 5); + GetPhrase(sfx, lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_DRIVER_ABUSE_1, 5); break; case SOUND_PED_CHAT_SEXY: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_EYING_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_EYING_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_CHAT_1, 4); + GetPhrase(sfx, lastSfx, SFX_BLACK_CONSTRUCTION_MALE_VOICE_1_CHAT_1, 4); break; default: return GetGenericMaleTalkSfx(sound); @@ -5854,22 +5854,22 @@ cAudioManager::GetShopperFemaleTalkSfx(int16 sound, int32 model) switch (sound) { case SOUND_PED_CAR_JACKED: - GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_CARJACKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_SHOPPER_VOICE_1_CARJACKED_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_SHOPPER_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_DODGE_1, 6); + GetPhrase(sfx, lastSfx, SFX_SHOPPER_VOICE_1_DODGE_1, 6); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_DRIVER_ABUSE_1, 7); + GetPhrase(sfx, lastSfx, SFX_SHOPPER_VOICE_1_DRIVER_ABUSE_1, 7); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_SHOCKED_1, 4); + GetPhrase(sfx, lastSfx, SFX_SHOPPER_VOICE_1_SHOCKED_1, 4); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_SHOPPER_VOICE_1_CHAT_1, 7); + GetPhrase(sfx, lastSfx, SFX_SHOPPER_VOICE_1_CHAT_1, 7); break; default: return GetGenericFemaleTalkSfx(sound); @@ -5891,25 +5891,25 @@ cAudioManager::GetStudentMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_GUN_PANIC_1, 2); + GetPhrase(sfx, lastSfx, SFX_STUDENT_MALE_VOICE_1_GUN_PANIC_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_STUDENT_MALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_MALE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_MALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_MALE_VOICE_1_DRIVER_ABUSE_1, 4); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_SHOCKED_1, 3); + GetPhrase(sfx, lastSfx, SFX_STUDENT_MALE_VOICE_1_SHOCKED_1, 3); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_MALE_VOICE_1_CHAT_1, 5); + GetPhrase(sfx, lastSfx, SFX_STUDENT_MALE_VOICE_1_CHAT_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -5925,25 +5925,25 @@ cAudioManager::GetStudentFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_COWER: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_GUN_PANIC_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_FEMALE_VOICE_1_GUN_PANIC_1, 4); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_STUDENT_FEMALE_VOICE_1_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_FEMALE_VOICE_1_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_DODGE_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_FEMALE_VOICE_1_DODGE_1, 4); break; case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_FEMALE_VOICE_1_DRIVER_ABUSE_1, 4); break; case SOUND_PED_CHAT_EVENT: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_SHOCKED_1, 2); + GetPhrase(sfx, lastSfx, SFX_STUDENT_FEMALE_VOICE_1_SHOCKED_1, 2); break; case SOUND_PED_CHAT: - GetPhrase(&sfx, &lastSfx, SFX_STUDENT_FEMALE_VOICE_1_CHAT_1, 4); + GetPhrase(sfx, lastSfx, SFX_STUDENT_FEMALE_VOICE_1_CHAT_1, 4); break; default: return GetGenericFemaleTalkSfx(sound); @@ -6002,16 +6002,16 @@ cAudioManager::GetEightTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_8BALL_GUN_COOL_1, 2); + GetPhrase(sfx, lastSfx, SFX_8BALL_GUN_COOL_1, 2); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_8BALL_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_8BALL_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_8BALL_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_8BALL_FIGHT_1, 6); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_8BALL_DODGE_1, 7); + GetPhrase(sfx, lastSfx, SFX_8BALL_DODGE_1, 7); break; default: return GetGenericMaleTalkSfx(sound); @@ -6027,16 +6027,16 @@ cAudioManager::GetFrankieTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_SALVATORE_GUN_COOL_1, 4); + GetPhrase(sfx, lastSfx, SFX_SALVATORE_GUN_COOL_1, 4); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_SALVATORE_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_SALVATORE_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_SALVATORE_FIGHT_1, 6); + GetPhrase(sfx, lastSfx, SFX_SALVATORE_FIGHT_1, 6); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_SALVATORE_DODGE_1, 3); + GetPhrase(sfx, lastSfx, SFX_SALVATORE_DODGE_1, 3); break; default: return GetGenericMaleTalkSfx(sound); @@ -6052,19 +6052,19 @@ cAudioManager::GetMistyTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_MISTY_GUN_COOL_1, 5); + GetPhrase(sfx, lastSfx, SFX_MISTY_GUN_COOL_1, 5); break; case SOUND_PED_ROBBED: - GetPhrase(&sfx, &lastSfx, SFX_MISTY_MUGGED_1, 2); + GetPhrase(sfx, lastSfx, SFX_MISTY_MUGGED_1, 2); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_MISTY_FIGHT_1, 4); + GetPhrase(sfx, lastSfx, SFX_MISTY_FIGHT_1, 4); break; case SOUND_PED_EVADE: - GetPhrase(&sfx, &lastSfx, SFX_MISTY_DODGE_1, 5); + GetPhrase(sfx, lastSfx, SFX_MISTY_DODGE_1, 5); break; case SOUND_PED_TAXI_CALL: - GetPhrase(&sfx, &lastSfx, SFX_MISTY_HERE_1, 4); + GetPhrase(sfx, lastSfx, SFX_MISTY_HERE_1, 4); break; default: return GetGenericFemaleTalkSfx(sound); @@ -6094,7 +6094,7 @@ cAudioManager::GetBomberTalkSfx(int16 sound) switch (sound) { case SOUND_PED_BOMBER: - GetPhrase(&sfx, &lastSfx, SFX_BOMBERMAN_1, 7); + GetPhrase(sfx, lastSfx, SFX_BOMBERMAN_1, 7); break; default: return GetGenericMaleTalkSfx(sound); @@ -6110,23 +6110,23 @@ cAudioManager::GetSecurityGuardTalkSfx(int16 sound) switch (sound) { case SOUND_PED_HANDS_UP: - GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_GUN_COOL_1, 2); + GetPhrase(sfx, lastSfx, SFX_SECURITY_GUARD_VOICE_1_GUN_COOL_1, 2); break; case SOUND_PED_HANDS_COWER: sfx = SFX_SECURITY_GUARD_VOICE_1_GUN_PANIC_1; break; case SOUND_PED_CAR_JACKED: case SOUND_PED_ANNOYED_DRIVER: - GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 6); + GetPhrase(sfx, lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 6); break; case SOUND_PED_ATTACK: - GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_FIGHT_1, 2); + GetPhrase(sfx, lastSfx, SFX_SECURITY_GUARD_VOICE_1_FIGHT_1, 2); break; case SOUND_PED_FLEE_RUN: #ifdef FIX_BUGS sfx = SFX_SECURITY_GUARD_VOICE_1_RUN_FROM_FIGHT_1; #else - GetPhrase(&sfx, &lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 12); + GetPhrase(sfx, lastSfx, SFX_SECURITY_GUARD_VOICE_1_DRIVER_ABUSE_1, 12); #endif break; default: @@ -6146,7 +6146,7 @@ cAudioManager::GetChunkyTalkSfx(int16 sound) case SOUND_PED_DEATH: return SFX_CHUNKY_DEATH; case SOUND_PED_FLEE_RUN: - GetPhrase(&sfx, &lastSfx, SFX_CHUNKY_RUN_1, 5); + GetPhrase(sfx, lastSfx, SFX_CHUNKY_RUN_1, 5); break; default: return GetGenericMaleTalkSfx(sound); @@ -6163,17 +6163,17 @@ cAudioManager::GetGenericMaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_DEATH: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_MALE_DEATH_1, 8); + GetPhrase(sfx, lastSfx, SFX_GENERIC_MALE_DEATH_1, 8); break; case SOUND_PED_BULLET_HIT: case SOUND_PED_DEFEND: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_MALE_GRUNT_1, 15); + GetPhrase(sfx, lastSfx, SFX_GENERIC_MALE_GRUNT_1, 15); break; case SOUND_PED_BURNING: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_MALE_FIRE_1, 8); + GetPhrase(sfx, lastSfx, SFX_GENERIC_MALE_FIRE_1, 8); break; case SOUND_PED_FLEE_SPRINT: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_MALE_PANIC_1, 6); + GetPhrase(sfx, lastSfx, SFX_GENERIC_MALE_PANIC_1, 6); break; default: return NO_SAMPLE; @@ -6189,17 +6189,17 @@ cAudioManager::GetGenericFemaleTalkSfx(int16 sound) switch (sound) { case SOUND_PED_DEATH: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_FEMALE_DEATH_1, 10); + GetPhrase(sfx, lastSfx, SFX_GENERIC_FEMALE_DEATH_1, 10); break; case SOUND_PED_BULLET_HIT: case SOUND_PED_DEFEND: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_FEMALE_GRUNT_1, 11); + GetPhrase(sfx, lastSfx, SFX_GENERIC_FEMALE_GRUNT_1, 11); break; case SOUND_PED_BURNING: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_FEMALE_FIRE_1, 9); + GetPhrase(sfx, lastSfx, SFX_GENERIC_FEMALE_FIRE_1, 9); break; case SOUND_PED_FLEE_SPRINT: - GetPhrase(&sfx, &lastSfx, SFX_GENERIC_FEMALE_PANIC_1, 8); + GetPhrase(sfx, lastSfx, SFX_GENERIC_FEMALE_PANIC_1, 8); break; default: return NO_SAMPLE; diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 40a2d056..cf6363bc 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -332,7 +332,7 @@ public: int8 GetMissionScriptPoliceAudioPlayingStatus() const; uint8 GetNum3DProvidersAvailable() const; int32 GetPedCommentSfx(CPed *ped, int32 sound); - void GetPhrase(uint32 *phrase, uint32 *prevPhrase, uint32 sample, uint32 maxOffset) const; + void GetPhrase(uint32 &phrase, uint32 &prevPhrase, uint32 sample, uint32 maxOffset) const; float GetVehicleDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile, cTransmission *transmission, float velocityChange); float GetVehicleNonDriveWheelSkidValue(uint8 wheel, CAutomobile *automobile, From 7f4498e0f09a51bce527760c8f3ec1b94dde1e77 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 7 Nov 2020 20:54:38 +0200 Subject: [PATCH 036/129] Check if buttons txd exsist --- src/core/ControllerConfig.cpp | 17 +++++++---- src/render/Font.cpp | 55 ++++++++++++++++++++--------------- src/render/Font.h | 1 + 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index 504b832c..cadba7f2 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2500,10 +2500,11 @@ int32 CControllerConfigManager::GetNumOfSettingsForAction(e_ControllerAction act nil, /* SHOW_MOUSE_POINTER_TOGGLE */ \ }} + +const char *XboxButtons_noIcons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("Y", "B", "A", "X", "LB", "LT", "LS", "RB", "RT", "RS", "BACK"); + #ifdef BUTTON_ICONS const char *XboxButtons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("~T~", "~O~", "~X~", "~Q~", "~K~", "~M~", "~A~", "~J~", "~V~", "~C~", "BACK"); -#else -const char *XboxButtons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("Y", "B", "A", "X", "LB", "LT", "LS", "RB", "RT", "RS", "BACK"); #endif @@ -2524,12 +2525,12 @@ const char *XboxButtons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS("Y", "B", #define PS2_SQUARE "SQUARE" #endif +const char *PlayStationButtons_noIcons[][MAX_CONTROLLERACTIONS] = + CONTROLLER_BUTTONS(PS2_TRIANGLE, PS2_CIRCLE, PS2_CROSS, PS2_SQUARE, "L1", "L2", "L3", "R1", "R2", "R3", "SELECT"); + #ifdef BUTTON_ICONS const char *PlayStationButtons[][MAX_CONTROLLERACTIONS] = CONTROLLER_BUTTONS(PS2_TRIANGLE, PS2_CIRCLE, PS2_CROSS, PS2_SQUARE, "~K~", "~M~", "~A~", "~J~", "~V~", "~C~", "SELECT"); -#else -const char *PlayStationButtons[][MAX_CONTROLLERACTIONS] = - CONTROLLER_BUTTONS(PS2_TRIANGLE, PS2_CIRCLE, PS2_CROSS, PS2_SQUARE, "L1", "L2", "L3", "R1", "R2", "R3", "SELECT"); #endif #undef PS2_TRIANGLE @@ -2547,7 +2548,11 @@ void CControllerConfigManager::GetWideStringOfCommandKeys(uint16 action, wchar * wchar wstr[16]; // TODO: INI and/or menu setting for Xbox/PS switch - const char *(*Buttons)[MAX_CONTROLLERACTIONS] = XboxButtons; +#ifdef BUTTON_ICONS + const char *(*Buttons)[MAX_CONTROLLERACTIONS] = CFont::ButtonsSlot != -1 ? XboxButtons : XboxButtons_noIcons; +#else + const char *(*Buttons)[MAX_CONTROLLERACTIONS] = XboxButtons_noIcons; +#endif assert(Buttons[CPad::GetPad(0)->Mode][action] != nil); // we cannot use these AsciiToUnicode(Buttons[CPad::GetPad(0)->Mode][action], wstr); diff --git a/src/render/Font.cpp b/src/render/Font.cpp index 6aceaf4b..719dffce 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -3,6 +3,9 @@ #include "Sprite2d.h" #include "TxdStore.h" #include "Font.h" +#ifdef BUTTON_ICONS +#include "FileMgr.h" +#endif void AsciiToUnicode(const char *src, wchar *dst) @@ -227,6 +230,7 @@ wchar foreign_table[128] = { #ifdef BUTTON_ICONS CSprite2d CFont::ButtonSprite[MAX_BUTTON_ICONS]; int CFont::PS2Symbol = BUTTON_NONE; +int CFont::ButtonsSlot = -1; #endif // BUTTON_ICONS void @@ -288,28 +292,31 @@ CFont::Initialise(void) CTxdStore::PopCurrentTxd(); #ifdef BUTTON_ICONS - slot = CTxdStore::AddTxdSlot("buttons"); - CTxdStore::LoadTxd(slot, "MODELS/X360BTNS.TXD"); - CTxdStore::AddRef(slot); - CTxdStore::PushCurrentTxd(); - CTxdStore::SetCurrentTxd(slot); + if (int file = CFileMgr::OpenFile("MODELS/X360BTNS.TXD")) { + CFileMgr::CloseFile(file); + ButtonsSlot = CTxdStore::AddTxdSlot("buttons"); + CTxdStore::LoadTxd(ButtonsSlot, "MODELS/X360BTNS.TXD"); + CTxdStore::AddRef(ButtonsSlot); + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(ButtonsSlot); #if 0 // unused - ButtonSprite[BUTTON_UP].SetTexture("up"); - ButtonSprite[BUTTON_DOWN].SetTexture("down"); - ButtonSprite[BUTTON_LEFT].SetTexture("left"); - ButtonSprite[BUTTON_RIGHT].SetTexture("right"); + ButtonSprite[BUTTON_UP].SetTexture("up"); + ButtonSprite[BUTTON_DOWN].SetTexture("down"); + ButtonSprite[BUTTON_LEFT].SetTexture("left"); + ButtonSprite[BUTTON_RIGHT].SetTexture("right"); #endif - ButtonSprite[BUTTON_CROSS].SetTexture("cross"); - ButtonSprite[BUTTON_CIRCLE].SetTexture("circle"); - ButtonSprite[BUTTON_SQUARE].SetTexture("square"); - ButtonSprite[BUTTON_TRIANGLE].SetTexture("triangle"); - ButtonSprite[BUTTON_L1].SetTexture("l1"); - ButtonSprite[BUTTON_L2].SetTexture("l2"); - ButtonSprite[BUTTON_L3].SetTexture("l3"); - ButtonSprite[BUTTON_R1].SetTexture("r1"); - ButtonSprite[BUTTON_R2].SetTexture("r2"); - ButtonSprite[BUTTON_R3].SetTexture("r3"); - CTxdStore::PopCurrentTxd(); + ButtonSprite[BUTTON_CROSS].SetTexture("cross"); + ButtonSprite[BUTTON_CIRCLE].SetTexture("circle"); + ButtonSprite[BUTTON_SQUARE].SetTexture("square"); + ButtonSprite[BUTTON_TRIANGLE].SetTexture("triangle"); + ButtonSprite[BUTTON_L1].SetTexture("l1"); + ButtonSprite[BUTTON_L2].SetTexture("l2"); + ButtonSprite[BUTTON_L3].SetTexture("l3"); + ButtonSprite[BUTTON_R1].SetTexture("r1"); + ButtonSprite[BUTTON_R2].SetTexture("r2"); + ButtonSprite[BUTTON_R3].SetTexture("r3"); + CTxdStore::PopCurrentTxd(); + } #endif // BUTTON_ICONS } @@ -360,9 +367,11 @@ void CFont::Shutdown(void) { #ifdef BUTTON_ICONS - for (int i = 0; i < MAX_BUTTON_ICONS; i++) - ButtonSprite[i].Delete(); - CTxdStore::RemoveTxdSlot(CTxdStore::FindTxdSlot("buttons")); + if (ButtonsSlot != -1) { + for (int i = 0; i < MAX_BUTTON_ICONS; i++) + ButtonSprite[i].Delete(); + CTxdStore::RemoveTxdSlot(ButtonsSlot); + } #endif Sprite[0].Delete(); Sprite[1].Delete(); diff --git a/src/render/Font.h b/src/render/Font.h index be1eabed..bf747859 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -103,6 +103,7 @@ public: static CFontDetails Details; #ifdef BUTTON_ICONS + static int32 ButtonsSlot; static CSprite2d ButtonSprite[MAX_BUTTON_ICONS]; static int PS2Symbol; From 163c12608fa972e6bed225ac6cb56d0a68279f06 Mon Sep 17 00:00:00 2001 From: erorcun Date: Sat, 7 Nov 2020 18:04:01 +0300 Subject: [PATCH 037/129] Fix build without CFO, NO_ISLAND_LOADING, save postfx/pipeline mults --- src/core/Frontend.cpp | 110 --------------------------------- src/core/Frontend.h | 10 +-- src/core/Frontend_PS2.cpp | 14 ----- src/core/Frontend_PS2.h | 22 ------- src/core/MenuScreens.cpp | 11 ++++ src/core/MenuScreensCustom.cpp | 65 +++++++++++++++++++ src/core/config.h | 25 ++++---- src/core/re3.cpp | 48 +++++++++----- 8 files changed, 125 insertions(+), 180 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index cf25e1b9..8221ad4f 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -122,7 +122,6 @@ int8 CMenuManager::m_nDisplayMSAALevel = 0; #endif #ifdef NO_ISLAND_LOADING -int8 CMenuManager::m_DisplayIslandLoading = ISLAND_LOADING_LOW; int8 CMenuManager::m_PrefsIslandLoading = ISLAND_LOADING_LOW; #endif @@ -1236,21 +1235,6 @@ CMenuManager::Draw() AsciiToUnicode(_psGetVideoModeList()[m_nDisplayVideoMode], unicodeTemp); rightText = unicodeTemp; break; -//#ifdef NO_ISLAND_LOADING -// case MENUACTION_ISLANDLOADING: -// switch (m_DisplayIslandLoading) { -// case ISLAND_LOADING_LOW: -// rightText = TheText.Get("FEM_LOW"); -// break; -// case ISLAND_LOADING_MEDIUM: -// rightText = TheText.Get("FEM_MED"); -// break; -// case ISLAND_LOADING_HIGH: -// rightText = TheText.Get("FEM_HIG"); -// break; -// } -// break; -//#endif case MENUACTION_AUDIOHW: if (m_nPrefsAudio3DProviderIndex == -1) rightText = TheText.Get("FEA_NAH"); @@ -1430,12 +1414,6 @@ CMenuManager::Draw() if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FED_RES") && m_nHelperTextMsgId == 1) ResetHelperText(); } -//#ifdef NO_ISLAND_LOADING -// if (m_DisplayIslandLoading == m_PrefsIslandLoading) { -// if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEM_ISL") && m_nHelperTextMsgId == 1) -// ResetHelperText(); -// } -//#endif if (m_nPrefsAudio3DProviderIndex != DMAudio.GetCurrent3DProviderIndex()) { if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEA_3DH")) SetHelperText(1); @@ -1444,12 +1422,6 @@ CMenuManager::Draw() if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FED_RES")) SetHelperText(1); } -//#ifdef NO_ISLAND_LOADING -// if (m_DisplayIslandLoading != m_PrefsIslandLoading) { -// if (!strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEM_ISL")) -// SetHelperText(1); -// } -//#endif if (m_nPrefsAudio3DProviderIndex != DMAudio.GetCurrent3DProviderIndex()) { if (strcmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEA_3DH") != 0 // To make assigning built-in actions to new custom options possible. @@ -4822,45 +4794,6 @@ CMenuManager::ProcessButtonPresses(void) SaveSettings(); } break; -//#ifdef NO_ISLAND_LOADING -// case MENUACTION_ISLANDLOADING: -// if (m_DisplayIslandLoading != m_PrefsIslandLoading) { -// if (!m_bGameNotLoaded) { -// if (m_DisplayIslandLoading > ISLAND_LOADING_LOW) { -// if (m_DisplayIslandLoading == ISLAND_LOADING_HIGH) -// CStreaming::RemoveIslandsNotUsed(LEVEL_GENERIC); -// if (m_PrefsIslandLoading == ISLAND_LOADING_LOW) { -// if (CGame::currLevel != LEVEL_INDUSTRIAL) -// CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL); -// if (CGame::currLevel != LEVEL_COMMERCIAL) -// CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL); -// if (CGame::currLevel != LEVEL_SUBURBAN) -// CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN); -// CCollision::bAlreadyLoaded = true; -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// CStreaming::RequestBigBuildings(CGame::currLevel); -// } else if (m_PrefsIslandLoading == ISLAND_LOADING_HIGH) { -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// CStreaming::RequestIslands(CGame::currLevel); -// } else -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// } else { // low -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// CCollision::bAlreadyLoaded = false; -// CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); -// CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); -// CStreaming::RemoveUnusedBuildings(CGame::currLevel); -// CStreaming::RequestIslands(CGame::currLevel); -// } -// -// CStreaming::LoadAllRequestedModels(true); -// } else -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// SetHelperText(0); -// SaveSettings(); -// } -// break; -//#endif case MENUACTION_AUDIOHW: { int selectedProvider = m_nPrefsAudio3DProviderIndex; @@ -4935,40 +4868,6 @@ CMenuManager::ProcessButtonPresses(void) RestoreDefGraphics(FEOPTION_ACTION_SELECT); RestoreDefDisplay(FEOPTION_ACTION_SELECT); #endif -//#ifdef NO_ISLAND_LOADING -// m_DisplayIslandLoading = ISLAND_LOADING_LOW; -// if (!m_bGameNotLoaded) { -// if (m_DisplayIslandLoading > ISLAND_LOADING_LOW) { -// if (m_DisplayIslandLoading == ISLAND_LOADING_HIGH) -// CStreaming::RemoveIslandsNotUsed(LEVEL_GENERIC); -// if (m_PrefsIslandLoading == ISLAND_LOADING_LOW) { -// if (CGame::currLevel != LEVEL_INDUSTRIAL) -// CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL); -// if (CGame::currLevel != LEVEL_COMMERCIAL) -// CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL); -// if (CGame::currLevel != LEVEL_SUBURBAN) -// CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN); -// CCollision::bAlreadyLoaded = true; -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// CStreaming::RequestBigBuildings(CGame::currLevel); -// } else if (m_PrefsIslandLoading == ISLAND_LOADING_HIGH) { -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// CStreaming::RequestIslands(CGame::currLevel); -// } else -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// } else { // low -// m_PrefsIslandLoading = m_DisplayIslandLoading; -// CCollision::bAlreadyLoaded = false; -// CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); -// CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); -// CStreaming::RemoveUnusedBuildings(CGame::currLevel); -// CStreaming::RequestIslands(CGame::currLevel); -// } -// -// CStreaming::LoadAllRequestedModels(true); -// } else -// m_PrefsIslandLoading = m_DisplayIslandLoading; -//#endif // NO_ISLAND_LOADING SaveSettings(); } else if ((m_nCurrScreen != MENUPAGE_SKIN_SELECT_OLD) && (m_nCurrScreen == MENUPAGE_CONTROLLER_PC)) { ControlsManager.MakeControllerActionsBlank(); @@ -5228,15 +5127,6 @@ CMenuManager::ProcessButtonPresses(void) } } break; -//#ifdef NO_ISLAND_LOADING -// case MENUACTION_ISLANDLOADING: -// m_DisplayIslandLoading += changeValueBy; -// if (m_DisplayIslandLoading > ISLAND_LOADING_HIGH) -// m_DisplayIslandLoading = ISLAND_LOADING_LOW; -// else if (m_DisplayIslandLoading < ISLAND_LOADING_LOW) -// m_DisplayIslandLoading = ISLAND_LOADING_HIGH; -// break; -//#endif case MENUACTION_AUDIOHW: if (m_nPrefsAudio3DProviderIndex != -1) { m_nPrefsAudio3DProviderIndex += changeValueBy; diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 70b4cd31..fba98690 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -235,11 +235,11 @@ enum eMenuScreen MENUPAGE_KEYBOARD_CONTROLS = 55, MENUPAGE_MOUSE_CONTROLS = 56, MENUPAGE_MISSION_RETRY = 57, +#ifdef MENU_MAP + MENUPAGE_MAP = 58, +#endif #ifdef CUSTOM_FRONTEND_OPTIONS -#ifdef MENU_MAP - MENUPAGE_MAP, -#endif #ifdef GRAPHICS_MENU_OPTIONS MENUPAGE_GRAPHICS_SETTINGS, #else @@ -380,9 +380,6 @@ enum eMenuAction // MENUACTION_MIPMAPS, // MENUACTION_TEXTURE_FILTERING, //#endif -//#ifdef NO_ISLAND_LOADING -// MENUACTION_ISLANDLOADING, -//#endif }; enum eCheckHover @@ -718,7 +715,6 @@ public: ISLAND_LOADING_HIGH }; - static int8 m_DisplayIslandLoading; static int8 m_PrefsIslandLoading; #define ISLAND_LOADING_IS(p) if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_##p) diff --git a/src/core/Frontend_PS2.cpp b/src/core/Frontend_PS2.cpp index a1d802f2..824f342b 100644 --- a/src/core/Frontend_PS2.cpp +++ b/src/core/Frontend_PS2.cpp @@ -203,20 +203,6 @@ static const char* FrontendFilenames[][2] = {"fe_radio9", "" }, }; -#ifdef CUTSCENE_BORDERS_SWITCH -bool CMenuManager::m_PrefsCutsceneBorders = true; -#endif - -#ifdef MULTISAMPLING -int8 CMenuManager::m_nPrefsMSAALevel = 0; -int8 CMenuManager::m_nDisplayMSAALevel = 0; -#endif - -#ifdef NO_ISLAND_LOADING -int8 CMenuManager::m_DisplayIslandLoading = ISLAND_LOADING_LOW; -int8 CMenuManager::m_PrefsIslandLoading = ISLAND_LOADING_LOW; -#endif - int32 CMenuManager::m_PrefsSfxVolume = 102; int32 CMenuManager::m_PrefsMusicVolume = 102; int32 CMenuManager::m_PrefsBrightness = 256; diff --git a/src/core/Frontend_PS2.h b/src/core/Frontend_PS2.h index c1e42291..4bab7df9 100644 --- a/src/core/Frontend_PS2.h +++ b/src/core/Frontend_PS2.h @@ -160,31 +160,9 @@ public: static int32 m_PrefsLanguage; static CONTRCONFIG m_PrefsControllerConfig; static bool m_PrefsUseVibration; -#ifdef NO_ISLAND_LOADING - enum - { - ISLAND_LOADING_LOW = 0, - ISLAND_LOADING_MEDIUM, - ISLAND_LOADING_HIGH - }; - static int8 m_DisplayIslandLoading; - static int8 m_PrefsIslandLoading; - -#define ISLAND_LOADING_IS(p) if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_##p) -#define ISLAND_LOADING_ISNT(p) if (CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_##p) -#else #define ISLAND_LOADING_IS(p) #define ISLAND_LOADING_ISNT(p) -#endif -#ifdef CUTSCENE_BORDERS_SWITCH - static bool m_PrefsCutsceneBorders; -#endif -#ifdef MULTISAMPLING - static int8 m_nPrefsMSAALevel; - static int8 m_nDisplayMSAALevel; -#endif - #ifdef GTA_PC bool m_bQuitGameNoCD; diff --git a/src/core/MenuScreens.cpp b/src/core/MenuScreens.cpp index c2eadb3b..9eff09e6 100644 --- a/src/core/MenuScreens.cpp +++ b/src/core/MenuScreens.cpp @@ -392,6 +392,9 @@ CMenuScreen aScreens[MENUPAGES] = { { "FET_PAU", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, MENUACTION_RESUME, "FEM_RES", SAVESLOT_NONE, MENUPAGE_NONE, MENUACTION_CHANGEMENU, "FEN_STA", SAVESLOT_NONE, MENUPAGE_NEW_GAME, +#ifdef MENU_MAP + MENUACTION_CHANGEMENU, "FEG_MAP", SAVESLOT_NONE, MENUPAGE_MAP, +#endif MENUACTION_CHANGEMENU, "FEP_STA", SAVESLOT_NONE, MENUPAGE_STATS, MENUACTION_CHANGEMENU, "FEP_BRI", SAVESLOT_NONE, MENUPAGE_BRIEFS, MENUACTION_CHANGEMENU, "FET_OPT", SAVESLOT_NONE, MENUPAGE_OPTIONS, @@ -436,6 +439,14 @@ CMenuScreen aScreens[MENUPAGES] = { }, #endif +#ifdef MENU_MAP + // MENUPAGE_MAP + { "FEG_MAP", 1, MENUPAGE_NONE, MENUPAGE_NONE, 2, 2, + MENUACTION_UNK110, "", SAVESLOT_NONE, MENUPAGE_NONE, // to prevent cross/enter to go back + MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, + }, +#endif + // MENUPAGE_UNK { "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0, diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index fb0888fc..b92d5325 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -11,6 +11,10 @@ #include "custompipes.h" #include "RwHelper.h" #include "Text.h" +#include "Streaming.h" +#include "FileLoader.h" +#include "Collision.h" +#include "ModelInfo.h" // Menu screens array is at the bottom of the file. @@ -48,6 +52,12 @@ #define DUALPASS_SELECTOR #endif +#ifdef NO_ISLAND_LOADING + #define ISLAND_LOADING_SELECTOR MENUACTION_CFO_SELECT, "FEM_ISL", { new CCFOSelect((int8*)&CMenuManager::m_PrefsIslandLoading, "IslandLoading", islandLoadingOpts, ARRAY_SIZE(islandLoadingOpts), true, IslandLoadingAfterChange) }, +#else + #define ISLAND_LOADING_SELECTOR +#endif + #ifdef EXTENDED_COLOURFILTER #define POSTFX_SELECTORS \ MENUACTION_CFO_SELECT, "FED_CLF", { new CCFOSelect((int8*)&CPostFX::EffectSwitch, "ColourFilter", filterNames, ARRAY_SIZE(filterNames), false, nil) }, \ @@ -80,6 +90,18 @@ void RestoreDefGraphics(int8 action) { #ifdef MULTISAMPLING FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel = 0; #endif + #ifdef NO_ISLAND_LOADING + if (FrontEndMenuManager.m_bGameNotLoaded) { + FrontEndMenuManager.m_PrefsIslandLoading = FrontEndMenuManager.ISLAND_LOADING_LOW; + CCollision::bAlreadyLoaded = false; + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + CStreaming::RequestIslands(CGame::currLevel); + CStreaming::LoadAllRequestedModels(true); + } else + FrontEndMenuManager.m_PrefsIslandLoading = FrontEndMenuManager.ISLAND_LOADING_LOW; + #endif #ifdef GRAPHICS_MENU_OPTIONS // otherwise Frontend will handle those CMenuManager::m_PrefsFrameLimiter = true; CMenuManager::m_PrefsVsyncDisp = true; @@ -120,6 +142,47 @@ void RestoreDefDisplay(int8 action) { #endif } +#ifdef NO_ISLAND_LOADING +const char *islandLoadingOpts[] = { "FEM_LOW", "FEM_MED", "FEM_HIG" }; +void IslandLoadingAfterChange(int8 before, int8 after) { + if (!FrontEndMenuManager.m_bGameNotLoaded) { + if (after > FrontEndMenuManager.ISLAND_LOADING_LOW) { + FrontEndMenuManager.m_PrefsIslandLoading = before; // calls below needs previous mode :shrug: + + if (after == FrontEndMenuManager.ISLAND_LOADING_HIGH) + CStreaming::RemoveIslandsNotUsed(LEVEL_GENERIC); + if (before == FrontEndMenuManager.ISLAND_LOADING_LOW) { + if (CGame::currLevel != LEVEL_INDUSTRIAL) + CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL); + if (CGame::currLevel != LEVEL_COMMERCIAL) + CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL); + if (CGame::currLevel != LEVEL_SUBURBAN) + CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN); + CCollision::bAlreadyLoaded = true; + FrontEndMenuManager.m_PrefsIslandLoading = after; + CStreaming::RequestBigBuildings(CGame::currLevel); + + } else if (before == FrontEndMenuManager.ISLAND_LOADING_HIGH) { + FrontEndMenuManager.m_PrefsIslandLoading = after; + CStreaming::RequestIslands(CGame::currLevel); + } else + FrontEndMenuManager.m_PrefsIslandLoading = after; + + } else { // low + CCollision::bAlreadyLoaded = false; + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + CStreaming::RequestIslands(CGame::currLevel); + } + + CStreaming::LoadAllRequestedModels(true); + } + + FrontEndMenuManager.SetHelperText(0); +} +#endif + #ifdef MORE_LANGUAGES void LangPolSelect(int8 action) { @@ -761,6 +824,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { #ifdef EXTENDED_PIPELINES PIPELINES_SELECTOR #endif + ISLAND_LOADING_SELECTOR DUALPASS_SELECTOR MENUACTION_CFO_DYNAMIC, "FET_DEF", { new CCFODynamic(nil, nil, nil, RestoreDefGraphics) }, MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, @@ -770,6 +834,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { { "FET_ADV", MENUPAGE_OPTIONS, MENUPAGE_OPTIONS, new CCustomScreenLayout({MENUSPRITE_MAINMENU, 50, 0, 20, FONT_HEADING, FESCREEN_LEFT_ALIGN, true, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE}), nil, + ISLAND_LOADING_SELECTOR DUALPASS_SELECTOR CUTSCENE_BORDERS_TOGGLE FREE_CAM_TOGGLE diff --git a/src/core/config.h b/src/core/config.h index 48e616bd..a55b018e 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -212,10 +212,10 @@ enum Config { # define TIMEBARS // print debug timers #endif -#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more +#define FIX_BUGS // fixes bugs that we've came across during reversing #define MORE_LANGUAGES // Add more translations to the game #define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible -#define LOAD_INI_SETTINGS +#define LOAD_INI_SETTINGS // as the name suggests. fundamental for CUSTOM_FRONTEND_OPTIONS // Rendering/display //#define EXTRA_MODEL_FLAGS // from mobile to optimize rendering @@ -227,19 +227,11 @@ enum Config { #define PS2_ALPHA_TEST // emulate ps2 alpha test #define IMPROVED_VIDEOMODE // save and load videomode parameters instead of a magic number #define DISABLE_LOADING_SCREEN // disable the loading screen which vastly improves the loading time -#define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU //#define USE_TEXTURE_POOL -#define CUTSCENE_BORDERS_SWITCH #ifdef LIBRW //#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) //#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) #endif -#define MULTISAMPLING // adds MSAA option - -#ifdef LIBRW -// these are not supported with librw yet -# undef MULTISAMPLING -#endif // Particle //#define PC_PARTICLE @@ -277,7 +269,13 @@ enum Config { //# define PS2_LIKE_MENU // An effort to recreate PS2 menu, cycling through tabs, different bg etc. //# define PS2_SAVE_DIALOG // PS2 style save dialog with transparent black box # define CUSTOM_FRONTEND_OPTIONS -# define GRAPHICS_MENU_OPTIONS // otherwise Advanced Options menu will appear if Display is full + +# ifdef CUSTOM_FRONTEND_OPTIONS +# define GRAPHICS_MENU_OPTIONS // otherwise Advanced Options menu will appear if Display is full +# define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU +# define CUTSCENE_BORDERS_SWITCH +# define MULTISAMPLING // adds MSAA option +# endif #endif // Script @@ -336,3 +334,8 @@ enum Config { #define PC_PARTICLE #define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial #endif + +#ifdef LIBRW +// these are not supported with librw yet +# undef MULTISAMPLING +#endif diff --git a/src/core/re3.cpp b/src/core/re3.cpp index aa13ba29..6bf5573e 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -102,6 +102,26 @@ float CheckAndReadIniFloat(const char *cat, const char *key, float original) return original; } +void CheckAndSaveIniInt(const char *cat, const char *key, int val, bool &changed) +{ + char temp[10]; + if (atoi(cfg.get(cat, key, "xxx").c_str()) != val) { // if .ini doesn't have our key, compare with xxx and forcefully add it + changed = true; + sprintf(temp, "%u", val); + cfg.set(cat, key, temp); + } +} + +void CheckAndSaveIniFloat(const char *cat, const char *key, float val, bool &changed) +{ + char temp[10]; + if (atof(cfg.get(cat, key, "xxx").c_str()) != val) { // if .ini doesn't have our key, compare with xxx and forcefully add it + changed = true; + sprintf(temp, "%f", val); + cfg.set(cat, key, temp); + } +} + void LoadINISettings() { cfg.load_file("re3.ini"); @@ -156,11 +176,6 @@ void LoadINISettings() } #endif -#ifdef NO_ISLAND_LOADING - CMenuManager::m_PrefsIslandLoading = CheckAndReadIniInt("FrontendOptions", "NoIslandLoading", CMenuManager::m_PrefsIslandLoading); - CMenuManager::m_DisplayIslandLoading = CMenuManager::m_PrefsIslandLoading; -#endif - #ifdef EXTENDED_COLOURFILTER CPostFX::Intensity = CheckAndReadIniFloat("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity); #endif @@ -192,21 +207,22 @@ void SaveINISettings() break; if (option.m_Action < MENUACTION_NOTHING && option.m_CFO->save) { - if (atoi(cfg.get("FrontendOptions", option.m_CFO->save, "xxx").c_str()) != *option.m_CFO->value) { // if .ini doesn't have that key compare with xxx, so we can add it - changed = true; - sprintf(temp, "%u", *option.m_CFO->value); - cfg.set("FrontendOptions", option.m_CFO->save, temp); - } + // Beware: CFO only supports saving uint8 right now + CheckAndSaveIniInt("FrontendOptions", option.m_CFO->save, *option.m_CFO->value, changed); } } } #endif -#ifdef NO_ISLAND_LOADING - if (atoi(cfg.get("FrontendOptions", "NoIslandLoading", "xxx").c_str()) != CMenuManager::m_PrefsIslandLoading) { - changed = true; - sprintf(temp, "%u", CMenuManager::m_PrefsIslandLoading); - cfg.set("FrontendOptions", "NoIslandLoading", temp); - } + +#ifdef EXTENDED_COLOURFILTER + CheckAndSaveIniFloat("CustomPipesValues", "PostFXIntensity", CPostFX::Intensity, changed); +#endif +#ifdef EXTENDED_PIPELINES + CheckAndSaveIniFloat("CustomPipesValues", "NeoVehicleShininess", CustomPipes::VehicleShininess, changed); + CheckAndSaveIniFloat("CustomPipesValues", "NeoVehicleSpecularity", CustomPipes::VehicleSpecularity, changed); + CheckAndSaveIniFloat("CustomPipesValues", "RimlightMult", CustomPipes::RimlightMult, changed); + CheckAndSaveIniFloat("CustomPipesValues", "LightmapMult", CustomPipes::LightmapMult, changed); + CheckAndSaveIniFloat("CustomPipesValues", "GlossMult", CustomPipes::GlossMult, changed); #endif if (changed) From 279acfae593dae000cf7aacd27c8e21a6c60415b Mon Sep 17 00:00:00 2001 From: Roman Masanin <36927roma@gmail.com> Date: Sun, 8 Nov 2020 20:50:46 +0300 Subject: [PATCH 038/129] pointers to referencies too --- src/audio/AudioLogic.cpp | 390 +++++++++++++++++++-------------------- src/audio/AudioManager.h | 46 ++--- 2 files changed, 218 insertions(+), 218 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index b0827885..95e6094f 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -599,78 +599,78 @@ cAudioManager::ProcessVehicle(CVehicle *veh) case VEHICLE_TYPE_CAR: UpdateGasPedalAudio((CAutomobile *)veh); if (params.m_nIndex == RCBANDIT) { - ProcessModelCarEngine(¶ms); - ProcessVehicleOneShots(¶ms); + ProcessModelCarEngine(params); + ProcessVehicleOneShots(params); ((CAutomobile *)veh)->m_fVelocityChangeForAudio = params.m_fVelocityChange; break; } if (params.m_nIndex == DODO) { - if (!ProcessVehicleRoadNoise(¶ms)) { - ProcessVehicleOneShots(¶ms); + if (!ProcessVehicleRoadNoise(params)) { + ProcessVehicleOneShots(params); ((CAutomobile *)veh)->m_fVelocityChangeForAudio = params.m_fVelocityChange; break; } if (CWeather::WetRoads > 0.f) - ProcessWetRoadNoise(¶ms); - ProcessVehicleSkidding(¶ms); + ProcessWetRoadNoise(params); + ProcessVehicleSkidding(params); } else { - if (!ProcessVehicleRoadNoise(¶ms)) { - ProcessVehicleOneShots(¶ms); + if (!ProcessVehicleRoadNoise(params)) { + ProcessVehicleOneShots(params); ((CAutomobile *)veh)->m_fVelocityChangeForAudio = params.m_fVelocityChange; break; } - ProcessReverseGear(¶ms); + ProcessReverseGear(params); if (CWeather::WetRoads > 0.f) - ProcessWetRoadNoise(¶ms); - ProcessVehicleSkidding(¶ms); - ProcessVehicleHorn(¶ms); - ProcessVehicleSirenOrAlarm(¶ms); + ProcessWetRoadNoise(params); + ProcessVehicleSkidding(params); + ProcessVehicleHorn(params); + ProcessVehicleSirenOrAlarm(params); if (UsesReverseWarning(params.m_nIndex)) - ProcessVehicleReverseWarning(¶ms); + ProcessVehicleReverseWarning(params); if (HasAirBrakes(params.m_nIndex)) - ProcessAirBrakes(¶ms); + ProcessAirBrakes(params); } - ProcessCarBombTick(¶ms); - ProcessVehicleEngine(¶ms); - ProcessEngineDamage(¶ms); - ProcessVehicleDoors(¶ms); + ProcessCarBombTick(params); + ProcessVehicleEngine(params); + ProcessEngineDamage(params); + ProcessVehicleDoors(params); - ProcessVehicleOneShots(¶ms); + ProcessVehicleOneShots(params); ((CAutomobile *)veh)->m_fVelocityChangeForAudio = params.m_fVelocityChange; break; case VEHICLE_TYPE_BOAT: - ProcessBoatEngine(¶ms); - ProcessBoatMovingOverWater(¶ms); - ProcessVehicleOneShots(¶ms); + ProcessBoatEngine(params); + ProcessBoatMovingOverWater(params); + ProcessVehicleOneShots(params); break; case VEHICLE_TYPE_TRAIN: - ProcessTrainNoise(¶ms); - ProcessVehicleOneShots(¶ms); + ProcessTrainNoise(params); + ProcessVehicleOneShots(params); break; case VEHICLE_TYPE_HELI: - ProcessHelicopter(¶ms); - ProcessVehicleOneShots(¶ms); + ProcessHelicopter(params); + ProcessVehicleOneShots(params); break; case VEHICLE_TYPE_PLANE: - ProcessPlane(¶ms); - ProcessVehicleOneShots(¶ms); + ProcessPlane(params); + ProcessVehicleOneShots(params); break; default: break; } - ProcessRainOnVehicle(¶ms); + ProcessRainOnVehicle(params); } void -cAudioManager::ProcessRainOnVehicle(cVehicleParams *params) +cAudioManager::ProcessRainOnVehicle(cVehicleParams& params) { const int rainOnVehicleIntensity = 22; - if (params->m_fDistance < SQR(rainOnVehicleIntensity) && CWeather::Rain > 0.01f && (!CCullZones::CamNoRain() || !CCullZones::PlayerNoRain())) { - CVehicle *veh = params->m_pVehicle; + if (params.m_fDistance < SQR(rainOnVehicleIntensity) && CWeather::Rain > 0.01f && (!CCullZones::CamNoRain() || !CCullZones::PlayerNoRain())) { + CVehicle *veh = params.m_pVehicle; ++veh->m_bRainAudioCounter; if (veh->m_bRainAudioCounter >= 2) { veh->m_bRainAudioCounter = 0; - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); float emittingVol = 30.f * CWeather::Rain; m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, rainOnVehicleIntensity, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { @@ -698,7 +698,7 @@ cAudioManager::ProcessRainOnVehicle(cVehicleParams *params) } bool -cAudioManager::ProcessReverseGear(cVehicleParams *params) +cAudioManager::ProcessReverseGear(cVehicleParams& params) { const int reverseGearIntensity = 30; @@ -707,14 +707,14 @@ cAudioManager::ProcessReverseGear(cVehicleParams *params) int32 emittingVol; float modificator; - if (params->m_fDistance >= SQR(reverseGearIntensity)) + if (params.m_fDistance >= SQR(reverseGearIntensity)) return false; - veh = params->m_pVehicle; + veh = params.m_pVehicle; if (veh->bEngineOn && (veh->m_fGasPedal < 0.0f || veh->m_nCurrentGear == 0)) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); - automobile = (CAutomobile *)params->m_pVehicle; + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); + automobile = (CAutomobile *)params.m_pVehicle; if (automobile->m_nWheelsOnGround != 0) { - modificator = params->m_fVelocityChange / params->m_pTransmission->fMaxReverseVelocity; + modificator = params.m_fVelocityChange / params.m_pTransmission->fMaxReverseVelocity; } else { if (automobile->m_nDriveWheelsOnGround != 0) automobile->m_fGasPedalAudio *= 0.4f; @@ -724,7 +724,7 @@ cAudioManager::ProcessReverseGear(cVehicleParams *params) emittingVol = (24.f * modificator); m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, reverseGearIntensity, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { - if (params->m_pVehicle->m_fGasPedal >= 0.0f) { + if (params.m_pVehicle->m_fGasPedal >= 0.0f) { m_sQueueSample.m_nCounter = 62; m_sQueueSample.m_nSampleIndex = SFX_REVERSE_GEAR_2; } else { @@ -752,7 +752,7 @@ cAudioManager::ProcessReverseGear(cVehicleParams *params) } void -cAudioManager::ProcessModelCarEngine(cVehicleParams *params) +cAudioManager::ProcessModelCarEngine(cVehicleParams& params) { const float SOUND_INTENSITY = 30.0f; CAutomobile *automobile; @@ -760,24 +760,24 @@ cAudioManager::ProcessModelCarEngine(cVehicleParams *params) int32 emittingVol; float velocityChange; - if (params->m_fDistance < SQR(SOUND_INTENSITY)) { - automobile = (CAutomobile *)params->m_pVehicle; + if (params.m_fDistance < SQR(SOUND_INTENSITY)) { + automobile = (CAutomobile *)params.m_pVehicle; if (automobile->bEngineOn) { if (automobile->m_nWheelsOnGround == 0) { if (automobile->m_nDriveWheelsOnGround != 0) automobile->m_fGasPedalAudio *= 0.4f; - velocityChange = automobile->m_fGasPedalAudio * params->m_pTransmission->fMaxVelocity; + velocityChange = automobile->m_fGasPedalAudio * params.m_pTransmission->fMaxVelocity; } else { - velocityChange = Abs(params->m_fVelocityChange); + velocityChange = Abs(params.m_fVelocityChange); } if (velocityChange > 0.001f) { - allowedVelocity = 0.5f * params->m_pTransmission->fMaxVelocity; + allowedVelocity = 0.5f * params.m_pTransmission->fMaxVelocity; if (velocityChange < allowedVelocity) emittingVol = (90.f * velocityChange / allowedVelocity); else emittingVol = 90; if (emittingVol) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, 30.f, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 2; @@ -785,7 +785,7 @@ cAudioManager::ProcessModelCarEngine(cVehicleParams *params) m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_bIs2D = false; m_sQueueSample.m_nReleasingVolumeModificator = 1; - m_sQueueSample.m_nFrequency = (11025.f * velocityChange / params->m_pTransmission->fMaxVelocity + 11025.f); + m_sQueueSample.m_nFrequency = (11025.f * velocityChange / params.m_pTransmission->fMaxVelocity + 11025.f); m_sQueueSample.m_nLoopCount = 0; m_sQueueSample.m_nEmittingVolume = emittingVol; m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); @@ -807,7 +807,7 @@ cAudioManager::ProcessModelCarEngine(cVehicleParams *params) bool -cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params) +cAudioManager::ProcessVehicleRoadNoise(cVehicleParams& params) { const float SOUND_INTENSITY = 95.0f; @@ -817,21 +817,21 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params) int sampleFreq; float velocity; - if (params->m_fDistance >= SQR(SOUND_INTENSITY)) + if (params.m_fDistance >= SQR(SOUND_INTENSITY)) return false; - if (params->m_pTransmission != nil) { - if (((CAutomobile*)params->m_pVehicle)->m_nDriveWheelsOnGround != 0) { - velocity = Abs(params->m_fVelocityChange); + if (params.m_pTransmission != nil) { + if (((CAutomobile*)params.m_pVehicle)->m_nDriveWheelsOnGround != 0) { + velocity = Abs(params.m_fVelocityChange); if (velocity > 0.0f) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); - emittingVol = 30.f * Min(1.f, velocity / (0.5f * params->m_pTransmission->fMaxVelocity)); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); + emittingVol = 30.f * Min(1.f, velocity / (0.5f * params.m_pTransmission->fMaxVelocity)); m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 0; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_bIs2D = false; m_sQueueSample.m_nReleasingVolumeModificator = 3; - if (params->m_pVehicle->m_nSurfaceTouched == SURFACE_WATER) { + if (params.m_pVehicle->m_nSurfaceTouched == SURFACE_WATER) { m_sQueueSample.m_nSampleIndex = SFX_BOAT_WATER_LOOP; freq = 6050 * emittingVol / 30 + 16000; } else { @@ -860,7 +860,7 @@ cAudioManager::ProcessVehicleRoadNoise(cVehicleParams *params) } bool -cAudioManager::ProcessWetRoadNoise(cVehicleParams *params) +cAudioManager::ProcessWetRoadNoise(cVehicleParams& params) { const float SOUND_INTENSITY = 30.0f; @@ -870,14 +870,14 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params) int freq; float velChange; - if (params->m_fDistance >= SQR(SOUND_INTENSITY)) + if (params.m_fDistance >= SQR(SOUND_INTENSITY)) return false; - if (params->m_pTransmission != nil) { - if (((CAutomobile *)params->m_pVehicle)->m_nDriveWheelsOnGround != 0) { - velChange = Abs(params->m_fVelocityChange); + if (params.m_pTransmission != nil) { + if (((CAutomobile *)params.m_pVehicle)->m_nDriveWheelsOnGround != 0) { + velChange = Abs(params.m_fVelocityChange); if (velChange > 0.f) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); - relativeVelocity = Min(1.0f, velChange / (0.5f * params->m_pTransmission->fMaxVelocity)); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); + relativeVelocity = Min(1.0f, velChange / (0.5f * params.m_pTransmission->fMaxVelocity)); emittingVol = 23.0f * relativeVelocity * CWeather::WetRoads; m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { @@ -912,7 +912,7 @@ cAudioManager::ProcessWetRoadNoise(cVehicleParams *params) } void -cAudioManager::ProcessVehicleEngine(cVehicleParams *params) +cAudioManager::ProcessVehicleEngine(cVehicleParams& params) { const float SOUND_INTENSITY = 50.0f; @@ -929,17 +929,17 @@ cAudioManager::ProcessVehicleEngine(cVehicleParams *params) float modificator; float traction = 0.f; - if (params->m_fDistance < SQR(SOUND_INTENSITY)) { + if (params.m_fDistance < SQR(SOUND_INTENSITY)) { playerVeh = FindPlayerVehicle(); - veh = params->m_pVehicle; + veh = params.m_pVehicle; if (playerVeh == veh && veh->GetStatus() == STATUS_WRECKED) { SampleManager.StopChannel(m_nActiveSamples); return; } if (veh->bEngineOn) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); - automobile = (CAutomobile *)params->m_pVehicle; - if (params->m_nIndex == DODO) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); + automobile = (CAutomobile *)params.m_pVehicle; + if (params.m_nIndex == DODO) { ProcessCesna(params); return; } @@ -947,14 +947,14 @@ cAudioManager::ProcessVehicleEngine(cVehicleParams *params) ProcessPlayersVehicleEngine(params, automobile); return; } - transmission = params->m_pTransmission; + transmission = params.m_pTransmission; if (transmission != nil) { - currentGear = params->m_pVehicle->m_nCurrentGear; + currentGear = params.m_pVehicle->m_nCurrentGear; if (automobile->m_nWheelsOnGround != 0) { if (automobile->bIsHandbrakeOn) { - if (params->m_fVelocityChange == 0.0f) + if (params.m_fVelocityChange == 0.0f) traction = 0.9f; - } else if (params->m_pVehicle->GetStatus() == STATUS_SIMPLE) { + } else if (params.m_pVehicle->GetStatus() == STATUS_SIMPLE) { traction = 0.0f; } else { switch (transmission->nDriveType) { @@ -982,15 +982,15 @@ cAudioManager::ProcessVehicleEngine(cVehicleParams *params) relativeChange = 0.f; } else if (currentGear != 0) { relativeGearChange = - Min(1.0f, (params->m_fVelocityChange - transmission->Gears[currentGear].fShiftDownVelocity) / transmission->fMaxVelocity * 2.5f); + Min(1.0f, (params.m_fVelocityChange - transmission->Gears[currentGear].fShiftDownVelocity) / transmission->fMaxVelocity * 2.5f); if (traction == 0.0f && automobile->GetStatus() != STATUS_SIMPLE && - params->m_fVelocityChange < transmission->Gears[1].fShiftUpVelocity) { + params.m_fVelocityChange < transmission->Gears[1].fShiftUpVelocity) { traction = 0.7f; } relativeChange = traction * automobile->m_fGasPedalAudio * 0.95f + (1.0f - traction) * relativeGearChange; } else relativeChange = - Min(1.0f, 1.0f - Abs((params->m_fVelocityChange - transmission->Gears[0].fShiftDownVelocity) / transmission->fMaxReverseVelocity)); + Min(1.0f, 1.0f - Abs((params.m_fVelocityChange - transmission->Gears[0].fShiftDownVelocity) / transmission->fMaxReverseVelocity)); } else { if (automobile->m_nDriveWheelsOnGround != 0) automobile->m_fGasPedalAudio *= 0.4f; @@ -1017,20 +1017,20 @@ cAudioManager::ProcessVehicleEngine(cVehicleParams *params) if (m_sQueueSample.m_nVolume != 0) { if (automobile->GetStatus() == STATUS_SIMPLE) { if (modificator < 0.02f) { - m_sQueueSample.m_nSampleIndex = aVehicleSettings[params->m_nIndex].m_nBank - CAR_SFX_BANKS_OFFSET + SFX_CAR_IDLE_1; + m_sQueueSample.m_nSampleIndex = aVehicleSettings[params.m_nIndex].m_nBank - CAR_SFX_BANKS_OFFSET + SFX_CAR_IDLE_1; freq = modificator * 10000 + 22050; m_sQueueSample.m_nCounter = 52; } else { - m_sQueueSample.m_nSampleIndex = aVehicleSettings[params->m_nIndex].m_nAccelerationSampleIndex; + m_sQueueSample.m_nSampleIndex = aVehicleSettings[params.m_nIndex].m_nAccelerationSampleIndex; m_sQueueSample.m_nCounter = 2; } } else { if (automobile->m_fGasPedal < 0.05f) { - m_sQueueSample.m_nSampleIndex = aVehicleSettings[params->m_nIndex].m_nBank - CAR_SFX_BANKS_OFFSET + SFX_CAR_IDLE_1; + m_sQueueSample.m_nSampleIndex = aVehicleSettings[params.m_nIndex].m_nBank - CAR_SFX_BANKS_OFFSET + SFX_CAR_IDLE_1; freq = modificator * 10000 + 22050; m_sQueueSample.m_nCounter = 52; } else { - m_sQueueSample.m_nSampleIndex = aVehicleSettings[params->m_nIndex].m_nAccelerationSampleIndex; + m_sQueueSample.m_nSampleIndex = aVehicleSettings[params.m_nIndex].m_nAccelerationSampleIndex; m_sQueueSample.m_nCounter = 2; } } @@ -1115,14 +1115,14 @@ cAudioManager::AddPlayerCarSample(uint8 emittingVolume, int32 freq, uint32 sampl } void -cAudioManager::ProcessCesna(cVehicleParams *params) +cAudioManager::ProcessCesna(cVehicleParams& params) { static uint8 nAccel = 0; - //((CAutomobile *)params->m_pVehicle)->Damage.GetEngineStatus(); + //((CAutomobile *)params.m_pVehicle)->Damage.GetEngineStatus(); - if (FindPlayerVehicle() == params->m_pVehicle) { - if (params->m_nIndex == DODO) { + if (FindPlayerVehicle() == params.m_pVehicle) { + if (params.m_nIndex == DODO) { if (Pads[0].GetAccelerate() <= 0) { if (nAccel != 0) --nAccel; @@ -1132,10 +1132,10 @@ cAudioManager::ProcessCesna(cVehicleParams *params) AddPlayerCarSample(85 * (60 - nAccel) / 60 + 20, 8500 * nAccel / 60 + 17000, SFX_CESNA_IDLE, SFX_BANK_0, 52, true); AddPlayerCarSample(85 * nAccel / 60 + 20, 8500 * nAccel / 60 + 17000, SFX_CESNA_REV, SFX_BANK_0, 2, true); } - } else if (params->m_nIndex == DODO) { + } else if (params.m_nIndex == DODO) { AddPlayerCarSample(105, 17000, SFX_CESNA_IDLE, SFX_BANK_0, 52, true); - } else if (params->m_fDistance < SQR(200)) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + } else if (params.m_fDistance < SQR(200)) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(80, 200.f, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 52; @@ -1156,7 +1156,7 @@ cAudioManager::ProcessCesna(cVehicleParams *params) m_sQueueSample.m_bRequireReflection = false; AddSampleToRequestedQueue(); } - if (params->m_fDistance < SQR(90)) { + if (params.m_fDistance < SQR(90)) { m_sQueueSample.m_nVolume = ComputeVolume(80, 90.f, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 2; @@ -1182,7 +1182,7 @@ cAudioManager::ProcessCesna(cVehicleParams *params) } void -cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *automobile) +cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams& params, CAutomobile *automobile) { static int32 GearFreqAdj[] = {6000, 6000, 3400, 1200, 0, -1000}; @@ -1234,13 +1234,13 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * accelerateState = Pads[0].GetAccelerate(); channelUsed = SampleManager.GetChannelUsedFlag(m_nActiveSamples); - transmission = params->m_pTransmission; - velocityChange = params->m_fVelocityChange; + transmission = params.m_pTransmission; + velocityChange = params.m_fVelocityChange; relativeVelocityChange = 2.0f * velocityChange / transmission->fMaxVelocity; accelerationMultipler = clamp(relativeVelocityChange, 0.0f, 1.0f); gasPedalAudio = accelerationMultipler; - currentGear = params->m_pVehicle->m_nCurrentGear; + currentGear = params.m_pVehicle->m_nCurrentGear; switch (transmission->nDriveType) { @@ -1265,20 +1265,20 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * } if (velocityChange != 0.0f) { - time = params->m_pVehicle->m_vecMoveSpeed.z / velocityChange; + time = params.m_pVehicle->m_vecMoveSpeed.z / velocityChange; if (time > 0.0f) freqModifier = -(Min(0.2f, time) * 3000.0f * 5.0f); else freqModifier = -(Max(-0.2f, time) * 3000.0f * 5.0f); - if (params->m_fVelocityChange < -0.001f) + if (params.m_fVelocityChange < -0.001f) freqModifier = -freqModifier; } else freqModifier = 0; - engineSoundType = aVehicleSettings[params->m_nIndex].m_nBank; + engineSoundType = aVehicleSettings[params.m_nIndex].m_nBank; soundOffset = 3 * (engineSoundType - CAR_SFX_BANKS_OFFSET); if (accelerateState <= 0) { - if (params->m_fVelocityChange < -0.001f) { + if (params.m_fVelocityChange < -0.001f) { if (channelUsed) { SampleManager.StopChannel(m_nActiveSamples); bAccelSampleStopped = true; @@ -1286,7 +1286,7 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * if (automobile->m_nWheelsOnGround == 0 || automobile->bIsHandbrakeOn || lostTraction) gasPedalAudio = automobile->m_fGasPedalAudio; else - gasPedalAudio = Min(1.0f, params->m_fVelocityChange / params->m_pTransmission->fMaxReverseVelocity); + gasPedalAudio = Min(1.0f, params.m_fVelocityChange / params.m_pTransmission->fMaxReverseVelocity); gasPedalAudio = Max(0.0f, gasPedalAudio); automobile->m_fGasPedalAudio = gasPedalAudio; @@ -1297,7 +1297,7 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * } nCruising = 0; if (automobile->m_nWheelsOnGround == 0 || automobile->bIsHandbrakeOn || lostTraction || - params->m_fVelocityChange < 0.01f && automobile->m_fGasPedalAudio > 0.2f) { + params.m_fVelocityChange < 0.01f && automobile->m_fGasPedalAudio > 0.2f) { automobile->m_fGasPedalAudio *= 0.6f; gasPedalAudio = automobile->m_fGasPedalAudio; } @@ -1355,7 +1355,7 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * if (!channelUsed) { if (!processedAccelSampleStopped) { - if (CurrentPretendGear < params->m_pTransmission->nNumberOfGears - 1) + if (CurrentPretendGear < params.m_pTransmission->nNumberOfGears - 1) ++CurrentPretendGear; else { nCruising = 1; @@ -1386,10 +1386,10 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * if (nCruising != 0) { bAccelSampleStopped = true; if (accelerateState < 150 || automobile->m_nWheelsOnGround == 0 || automobile->bIsHandbrakeOn || lostTraction || - currentGear < params->m_pTransmission->nNumberOfGears - 1) { + currentGear < params.m_pTransmission->nNumberOfGears - 1) { nCruising = 0; } else { - if (accelerateState >= 220 && params->m_fVelocityChange + 0.001f < automobile->m_fVelocityChangeForAudio) { + if (accelerateState >= 220 && params.m_fVelocityChange + 0.001f < automobile->m_fVelocityChangeForAudio) { if (nCruising < 800) ++nCruising; } else if (nCruising > 3) { @@ -1409,7 +1409,7 @@ cAudioManager::ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile * } bool -cAudioManager::ProcessVehicleSkidding(cVehicleParams *params) +cAudioManager::ProcessVehicleSkidding(cVehicleParams& params) { const float SOUND_INTENSITY = 40.0f; @@ -1419,31 +1419,31 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params) float newSkidVal = 0.0f; float skidVal = 0.0f; - if (params->m_fDistance >= SQR(SOUND_INTENSITY)) + if (params.m_fDistance >= SQR(SOUND_INTENSITY)) return false; - automobile = (CAutomobile *)params->m_pVehicle; + automobile = (CAutomobile *)params.m_pVehicle; if (automobile->m_nWheelsOnGround == 0) return true; - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); for (int32 i = 0; i < ARRAY_SIZE(automobile->m_aWheelState); i++) { if (automobile->m_aWheelState[i] == WHEEL_STATE_NORMAL || automobile->Damage.GetWheelStatus(i) == WHEEL_STATUS_MISSING) continue; - transmission = params->m_pTransmission; + transmission = params.m_pTransmission; switch (transmission->nDriveType) { case '4': - newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange); + newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission, params.m_fVelocityChange); break; case 'F': if (i == CARWHEEL_FRONT_LEFT || i == CARWHEEL_FRONT_RIGHT) - newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange); + newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission, params.m_fVelocityChange); else - newSkidVal = GetVehicleNonDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange); + newSkidVal = GetVehicleNonDriveWheelSkidValue(i, automobile, transmission, params.m_fVelocityChange); break; case 'R': if (i == CARWHEEL_REAR_LEFT || i == CARWHEEL_REAR_RIGHT) - newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange); + newSkidVal = GetVehicleDriveWheelSkidValue(i, automobile, transmission, params.m_fVelocityChange); else - newSkidVal = GetVehicleNonDriveWheelSkidValue(i, automobile, transmission, params->m_fVelocityChange); + newSkidVal = GetVehicleNonDriveWheelSkidValue(i, automobile, transmission, params.m_fVelocityChange); break; default: break; @@ -1456,7 +1456,7 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params) m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 3; - switch (params->m_pVehicle->m_nSurfaceTouched) { + switch (params.m_pVehicle->m_nSurfaceTouched) { case SURFACE_GRASS: case SURFACE_HEDGE: m_sQueueSample.m_nSampleIndex = SFX_RAIN; @@ -1547,17 +1547,17 @@ cAudioManager::GetVehicleNonDriveWheelSkidValue(uint8 wheel, CAutomobile *automo } void -cAudioManager::ProcessVehicleHorn(cVehicleParams *params) +cAudioManager::ProcessVehicleHorn(cVehicleParams& params) { const float SOUND_INTENSITY = 40.0f; CAutomobile *automobile; - if (params->m_fDistance < SQR(SOUND_INTENSITY)) { - automobile = (CAutomobile *)params->m_pVehicle; - if ((!automobile->m_bSirenOrAlarm || !UsesSirenSwitching(params->m_nIndex)) && automobile->GetModelIndex() != MI_MRWHOOP) { + if (params.m_fDistance < SQR(SOUND_INTENSITY)) { + automobile = (CAutomobile *)params.m_pVehicle; + if ((!automobile->m_bSirenOrAlarm || !UsesSirenSwitching(params.m_nIndex)) && automobile->GetModelIndex() != MI_MRWHOOP) { if (automobile->m_nCarHornTimer) { - if (params->m_pVehicle->GetStatus() != STATUS_PLAYER) { + if (params.m_pVehicle->GetStatus() != STATUS_PLAYER) { automobile->m_nCarHornTimer = Min(44, automobile->m_nCarHornTimer); if (automobile->m_nCarHornTimer == 44) automobile->m_nCarHornPattern = (m_FrameCounter + m_sQueueSample.m_nEntityIndex) & 7; @@ -1565,15 +1565,15 @@ cAudioManager::ProcessVehicleHorn(cVehicleParams *params) return; } - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(80, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 4; - m_sQueueSample.m_nSampleIndex = aVehicleSettings[params->m_nIndex].m_nHornSample; + m_sQueueSample.m_nSampleIndex = aVehicleSettings[params.m_nIndex].m_nHornSample; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_bIs2D = false; m_sQueueSample.m_nReleasingVolumeModificator = 2; - m_sQueueSample.m_nFrequency = aVehicleSettings[params->m_nIndex].m_nHornFrequency; + m_sQueueSample.m_nFrequency = aVehicleSettings[params.m_nIndex].m_nHornFrequency; m_sQueueSample.m_nLoopCount = 0; m_sQueueSample.m_nEmittingVolume = 80; m_sQueueSample.m_nLoopStart = SampleManager.GetSampleLoopStartOffset(m_sQueueSample.m_nSampleIndex); @@ -1622,36 +1622,36 @@ cAudioManager::UsesSirenSwitching(int32 model) const } bool -cAudioManager::ProcessVehicleSirenOrAlarm(cVehicleParams *params) +cAudioManager::ProcessVehicleSirenOrAlarm(cVehicleParams& params) { const float SOUND_INTENSITY = 110.0f; - if (params->m_fDistance < SQR(SOUND_INTENSITY)) { - CVehicle *veh = params->m_pVehicle; + if (params.m_fDistance < SQR(SOUND_INTENSITY)) { + CVehicle *veh = params.m_pVehicle; if (veh->m_bSirenOrAlarm == false && !veh->IsAlarmOn()) return true; - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(80, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 5; - if (UsesSiren(params->m_nIndex)) { - if (params->m_pVehicle->GetStatus() == STATUS_ABANDONED) + if (UsesSiren(params.m_nIndex)) { + if (params.m_pVehicle->GetStatus() == STATUS_ABANDONED) return true; - if (veh->m_nCarHornTimer && params->m_nIndex != FIRETRUK) { + if (veh->m_nCarHornTimer && params.m_nIndex != FIRETRUK) { m_sQueueSample.m_nSampleIndex = SFX_SIREN_FAST; - if (params->m_nIndex == FBICAR) + if (params.m_nIndex == FBICAR) m_sQueueSample.m_nFrequency = 16113; else m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_SIREN_FAST); m_sQueueSample.m_nCounter = 60; } else { - m_sQueueSample.m_nSampleIndex = aVehicleSettings[params->m_nIndex].m_nSirenOrAlarmSample; - m_sQueueSample.m_nFrequency = aVehicleSettings[params->m_nIndex].m_nSirenOrAlarmFrequency; + m_sQueueSample.m_nSampleIndex = aVehicleSettings[params.m_nIndex].m_nSirenOrAlarmSample; + m_sQueueSample.m_nFrequency = aVehicleSettings[params.m_nIndex].m_nSirenOrAlarmFrequency; } } else { - m_sQueueSample.m_nSampleIndex = aVehicleSettings[params->m_nIndex].m_nSirenOrAlarmSample; - m_sQueueSample.m_nFrequency = aVehicleSettings[params->m_nIndex].m_nSirenOrAlarmFrequency; + m_sQueueSample.m_nSampleIndex = aVehicleSettings[params.m_nIndex].m_nSirenOrAlarmSample; + m_sQueueSample.m_nFrequency = aVehicleSettings[params.m_nIndex].m_nSirenOrAlarmFrequency; } m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_bIs2D = false; @@ -1681,17 +1681,17 @@ cAudioManager::UsesReverseWarning(int32 model) const } bool -cAudioManager::ProcessVehicleReverseWarning(cVehicleParams *params) +cAudioManager::ProcessVehicleReverseWarning(cVehicleParams& params) { const float SOUND_INTENSITY = 50.0f; - CVehicle *veh = params->m_pVehicle; + CVehicle *veh = params.m_pVehicle; - if (params->m_fDistance >= SQR(SOUND_INTENSITY)) + if (params.m_fDistance >= SQR(SOUND_INTENSITY)) return false; if (veh->bEngineOn && veh->m_fGasPedal < 0.0f) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(60, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 12; @@ -1717,7 +1717,7 @@ cAudioManager::ProcessVehicleReverseWarning(cVehicleParams *params) } bool -cAudioManager::ProcessVehicleDoors(cVehicleParams *params) +cAudioManager::ProcessVehicleDoors(cVehicleParams& params) { const float SOUND_INTENSITY = 40.0f; @@ -1726,11 +1726,11 @@ cAudioManager::ProcessVehicleDoors(cVehicleParams *params) int32 emittingVol; float velocity; - if (params->m_fDistance >= SQR(SOUND_INTENSITY)) + if (params.m_fDistance >= SQR(SOUND_INTENSITY)) return false; - automobile = (CAutomobile *)params->m_pVehicle; - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + automobile = (CAutomobile *)params.m_pVehicle; + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); for (int32 i = 0; i < ARRAY_SIZE(automobile->Doors); i++) { if (automobile->Damage.GetDoorStatus(i) == DOOR_STATUS_SWINGING) { doorState = automobile->Doors[i].m_nDoorState; @@ -1765,22 +1765,22 @@ cAudioManager::ProcessVehicleDoors(cVehicleParams *params) } bool -cAudioManager::ProcessAirBrakes(cVehicleParams *params) +cAudioManager::ProcessAirBrakes(cVehicleParams& params) { CAutomobile *automobile; uint8 rand; - if (params->m_fDistance > SQR(30)) + if (params.m_fDistance > SQR(30)) return false; - automobile = (CAutomobile *)params->m_pVehicle; + automobile = (CAutomobile *)params.m_pVehicle; if (!automobile->bEngineOn) return true; - if ((automobile->m_fVelocityChangeForAudio < 0.025f || params->m_fVelocityChange >= 0.025f) && - (automobile->m_fVelocityChangeForAudio > -0.025f || params->m_fVelocityChange <= 0.025f)) + if ((automobile->m_fVelocityChangeForAudio < 0.025f || params.m_fVelocityChange >= 0.025f) && + (automobile->m_fVelocityChangeForAudio > -0.025f || params.m_fVelocityChange <= 0.025f)) return true; - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); rand = m_anRandomTable[0] % 10 + 70; m_sQueueSample.m_nVolume = ComputeVolume(rand, 30.0f, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { @@ -1813,7 +1813,7 @@ cAudioManager::HasAirBrakes(int32 model) const } bool -cAudioManager::ProcessEngineDamage(cVehicleParams *params) +cAudioManager::ProcessEngineDamage(cVehicleParams& params) { const int engineDamageIntensity = 40; @@ -1821,9 +1821,9 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params) uint8 engineStatus; uint8 emittingVolume; - if (params->m_fDistance >= SQR(engineDamageIntensity)) + if (params.m_fDistance >= SQR(engineDamageIntensity)) return false; - veh = (CAutomobile *)params->m_pVehicle; + veh = (CAutomobile *)params.m_pVehicle; if (veh->bEngineOn) { engineStatus = veh->Damage.GetEngineStatus(); if (engineStatus > 250 || engineStatus < 100) @@ -1839,7 +1839,7 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params) m_sQueueSample.m_nReleasingVolumeModificator = 7; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_CAR_ON_FIRE); } - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(emittingVolume, engineDamageIntensity, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 28; @@ -1862,15 +1862,15 @@ cAudioManager::ProcessEngineDamage(cVehicleParams *params) } bool -cAudioManager::ProcessCarBombTick(cVehicleParams *params) +cAudioManager::ProcessCarBombTick(cVehicleParams& params) { CAutomobile *automobile; - if (params->m_fDistance >= SQR(40.f)) + if (params.m_fDistance >= SQR(40.f)) return false; - automobile = (CAutomobile *)params->m_pVehicle; + automobile = (CAutomobile *)params.m_pVehicle; if (automobile->bEngineOn && automobile->m_bombType == CARBOMB_TIMEDACTIVE) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(60, 40.f, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 35; @@ -1896,7 +1896,7 @@ cAudioManager::ProcessCarBombTick(cVehicleParams *params) } void -cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) +cAudioManager::ProcessVehicleOneShots(cVehicleParams& params) { int16 event; uint8 emittingVol; @@ -1925,7 +1925,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) const float SOUND_INTENSITY = 50.0f; maxDist = SQR(SOUND_INTENSITY); emittingVol = m_anRandomTable[2] % 5 + 122; - switch (aVehicleSettings[params->m_nIndex].m_bDoorType) { + switch (aVehicleSettings[params.m_nIndex].m_bDoorType) { case OLD_DOOR: m_sQueueSample.m_nSampleIndex = SFX_OLD_CAR_DOOR_CLOSE; break; @@ -1961,7 +1961,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) const float SOUND_INTENSITY = 50.0f; maxDist = SQR(SOUND_INTENSITY); emittingVol = m_anRandomTable[1] % 10 + 117; - switch (aVehicleSettings[params->m_nIndex].m_bDoorType) { + switch (aVehicleSettings[params.m_nIndex].m_bDoorType) { case OLD_DOOR: m_sQueueSample.m_nSampleIndex = SFX_OLD_CAR_DOOR_OPEN; break; @@ -2009,7 +2009,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) iWheelIndex = 82; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_TYRE_BUMP); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 16); - if (params->m_nIndex == RCBANDIT) { + if (params.m_nIndex == RCBANDIT) { m_sQueueSample.m_nFrequency *= 2; emittingVol /= 2; } @@ -2238,16 +2238,16 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) pedParams.m_pPed = nil; pedParams.m_bDistanceCalculated = false; pedParams.m_fDistance = 0.0f; - pedParams.m_bDistanceCalculated = params->m_bDistanceCalculated; - pedParams.m_fDistance = params->m_fDistance; + pedParams.m_bDistanceCalculated = params.m_bDistanceCalculated; + pedParams.m_fDistance = params.m_fDistance; SetupPedComments(&pedParams, SOUND_PED_HELI_PLAYER_FOUND); continue; case SOUND_PED_BODYCAST_HIT: pedParams.m_pPed = nil; pedParams.m_bDistanceCalculated = false; pedParams.m_fDistance = 0.0f; - pedParams.m_bDistanceCalculated = params->m_bDistanceCalculated; - pedParams.m_fDistance = params->m_fDistance; + pedParams.m_bDistanceCalculated = params.m_bDistanceCalculated; + pedParams.m_fDistance = params.m_fDistance; SetupPedComments(&pedParams, SOUND_PED_BODYCAST_HIT); continue; case SOUND_WATER_FALL: { @@ -2300,8 +2300,8 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) default: continue; } - if (params->m_fDistance < maxDist) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + if (params.m_fDistance < maxDist) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { if (noReflections) { @@ -2323,7 +2323,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams *params) } bool -cAudioManager::ProcessTrainNoise(cVehicleParams *params) +cAudioManager::ProcessTrainNoise(cVehicleParams& params) { const float SOUND_INTENSITY = 300.0f; @@ -2331,12 +2331,12 @@ cAudioManager::ProcessTrainNoise(cVehicleParams *params) uint8 emittingVol; float speedMultipler; - if (params->m_fDistance >= SQR(SOUND_INTENSITY)) + if (params.m_fDistance >= SQR(SOUND_INTENSITY)) return false; - if (params->m_fVelocityChange > 0.0f) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); - train = (CTrain *)params->m_pVehicle; + if (params.m_fVelocityChange > 0.0f) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); + train = (CTrain *)params.m_pVehicle; speedMultipler = Min(1.0f, train->m_fSpeed * 250.f / 51.f); emittingVol = (75.f * speedMultipler); if (train->m_fWagonPosition == 0.0f) { @@ -2362,7 +2362,7 @@ cAudioManager::ProcessTrainNoise(cVehicleParams *params) } } const float SOUND_INTENSITY = 70.0f; - if (params->m_fDistance < SQR(SOUND_INTENSITY)) { + if (params.m_fDistance < SQR(SOUND_INTENSITY)) { m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, SOUND_INTENSITY, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 33; @@ -2389,7 +2389,7 @@ cAudioManager::ProcessTrainNoise(cVehicleParams *params) } bool -cAudioManager::ProcessBoatEngine(cVehicleParams *params) +cAudioManager::ProcessBoatEngine(cVehicleParams& params) { CBoat *boat; float padRelativeAccerate; @@ -2403,10 +2403,10 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params) static const int intensity = 50; - if (params->m_fDistance < SQR(intensity)) { - boat = (CBoat *)params->m_pVehicle; - if (params->m_nIndex == REEFER) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + if (params.m_fDistance < SQR(intensity)) { + boat = (CBoat *)params.m_pVehicle; + if (params.m_nIndex == REEFER) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(80, 50.f, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { m_sQueueSample.m_nCounter = 39; @@ -2428,7 +2428,7 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params) m_sQueueSample.m_bRequireReflection = false; AddSampleToRequestedQueue(); } - if (FindPlayerVehicle() == params->m_pVehicle) { + if (FindPlayerVehicle() == params.m_pVehicle) { padAccelerate = Max(Pads[0].GetAccelerate(), Pads[0].GetBrake()); padRelativeAccerate = padAccelerate / 255; emittingVol = (100.f * padRelativeAccerate) + 15; @@ -2467,7 +2467,7 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params) m_sQueueSample.m_bReverbFlag = true; m_sQueueSample.m_bRequireReflection = false; } else { - if (FindPlayerVehicle() == params->m_pVehicle) { + if (FindPlayerVehicle() == params.m_pVehicle) { padAccelerate = Max(Pads[0].GetAccelerate(), Pads[0].GetBrake()); if (padAccelerate <= 20) { emittingVol = 45 - 45 * padAccelerate / 40; @@ -2504,7 +2504,7 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params) m_sQueueSample.m_nSampleIndex = SFX_POLICE_BOAT_ACCEL; } } - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, 50.f, m_sQueueSample.m_fDistance); if (!m_sQueueSample.m_nVolume) return true; @@ -2530,22 +2530,22 @@ cAudioManager::ProcessBoatEngine(cVehicleParams *params) } bool -cAudioManager::ProcessBoatMovingOverWater(cVehicleParams *params) +cAudioManager::ProcessBoatMovingOverWater(cVehicleParams& params) { float velocityChange; int32 vol; float multiplier; - if (params->m_fDistance > SQR(50)) + if (params.m_fDistance > SQR(50)) return false; - velocityChange = Abs(params->m_fVelocityChange); - if (velocityChange <= 0.0005f && ((CBoat*)params->m_pVehicle)->bBoatInWater) + velocityChange = Abs(params.m_fVelocityChange); + if (velocityChange <= 0.0005f && ((CBoat*)params.m_pVehicle)->bBoatInWater) return true; velocityChange = Min(0.75f, velocityChange); multiplier = (velocityChange - 0.0005f) / (1499.0f / 2000.0f); - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); vol = (30.f * multiplier); m_sQueueSample.m_nVolume = ComputeVolume(vol, 50.f, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { @@ -2578,7 +2578,7 @@ struct tHelicopterSampleData { }; bool -cAudioManager::ProcessHelicopter(cVehicleParams *params) +cAudioManager::ProcessHelicopter(cVehicleParams& params) { CHeli *heli; float MaxDist; @@ -2587,11 +2587,11 @@ cAudioManager::ProcessHelicopter(cVehicleParams *params) int32 emittingVol; static const tHelicopterSampleData gHeliSfxRanges[3] = {{400.f, 380.f, 100}, {100.f, 70.f, MAX_VOLUME}, {60.f, 30.f, MAX_VOLUME}}; - if (SQR(gHeliSfxRanges[0].m_fMaxDistance) <= params->m_fDistance) + if (SQR(gHeliSfxRanges[0].m_fMaxDistance) <= params.m_fDistance) return false; - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); - heli = (CHeli *)params->m_pVehicle; + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); + heli = (CHeli *)params.m_pVehicle; for (uint32 i = 0; i < ARRAY_SIZE(gHeliSfxRanges); i++) { MaxDist = gHeliSfxRanges[i].m_fMaxDistance; dist = m_sQueueSample.m_fDistance; @@ -2628,9 +2628,9 @@ cAudioManager::ProcessHelicopter(cVehicleParams *params) } void -cAudioManager::ProcessPlane(cVehicleParams *params) +cAudioManager::ProcessPlane(cVehicleParams& params) { - switch (params->m_nIndex) { + switch (params.m_nIndex) { case AIRTRAIN: ProcessJumbo(params); break; @@ -2638,7 +2638,7 @@ cAudioManager::ProcessPlane(cVehicleParams *params) ProcessCesna(params); break; default: - debug("Plane Model Id is %d\n, ", params->m_pVehicle->GetModelIndex()); + debug("Plane Model Id is %d\n, ", params.m_pVehicle->GetModelIndex()); break; } } @@ -2654,14 +2654,14 @@ DoJumboVolOffset() } void -cAudioManager::ProcessJumbo(cVehicleParams *params) +cAudioManager::ProcessJumbo(cVehicleParams& params) { CPlane *plane; float position; - if (params->m_fDistance < SQR(440)) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); - plane = (CPlane *)params->m_pVehicle; + if (params.m_fDistance < SQR(440)) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); + plane = (CPlane *)params.m_pVehicle; DoJumboVolOffset(); position = PlanePathPosition[plane->m_nPlaneId]; if (position <= TakeOffPoint) { diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index cf6363bc..2d971ac9 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -362,29 +362,29 @@ public: void PreTerminateGameSpecificShutdown(); /// processX - main logic of adding new sounds void ProcessActiveQueues(); - bool ProcessAirBrakes(cVehicleParams *params); + bool ProcessAirBrakes(cVehicleParams& params); void ProcessAirportScriptObject(uint8 sound); - bool ProcessBoatEngine(cVehicleParams *params); - bool ProcessBoatMovingOverWater(cVehicleParams *params); + bool ProcessBoatEngine(cVehicleParams& params); + bool ProcessBoatMovingOverWater(cVehicleParams& params); void ProcessBridge(); void ProcessBridgeMotor(); void ProcessBridgeOneShots(); void ProcessBridgeWarning(); - bool ProcessCarBombTick(cVehicleParams *params); - void ProcessCesna(cVehicleParams *params); + bool ProcessCarBombTick(cVehicleParams& params); + void ProcessCesna(cVehicleParams& params); void ProcessCinemaScriptObject(uint8 sound); void ProcessCrane(); void ProcessDocksScriptObject(uint8 sound); - bool ProcessEngineDamage(cVehicleParams *params); + bool ProcessEngineDamage(cVehicleParams& params); void ProcessEntity(int32 sound); void ProcessExplosions(int32 explosion); void ProcessFireHydrant(); void ProcessFires(int32 entity); void ProcessFrontEnd(); void ProcessGarages(); - bool ProcessHelicopter(cVehicleParams *params); + bool ProcessHelicopter(cVehicleParams& params); void ProcessHomeScriptObject(uint8 sound); - void ProcessJumbo(cVehicleParams *); + void ProcessJumbo(cVehicleParams& params); void ProcessJumboAccel(CPlane *plane); void ProcessJumboDecel(CPlane *plane); void ProcessJumboFlying(); @@ -394,37 +394,37 @@ public: void ProcessLaunderetteScriptObject(uint8 sound); void ProcessLoopingScriptObject(uint8 sound); void ProcessMissionAudio(); - void ProcessModelCarEngine(cVehicleParams *params); + void ProcessModelCarEngine(cVehicleParams& params); void ProcessOneShotScriptObject(uint8 sound); void ProcessPed(CPhysical *ped); void ProcessPedHeadphones(cPedParams *params); void ProcessPedOneShots(cPedParams *params); void ProcessPhysical(int32 id); - void ProcessPlane(cVehicleParams *params); - void ProcessPlayersVehicleEngine(cVehicleParams *params, CAutomobile *automobile); + void ProcessPlane(cVehicleParams& params); + void ProcessPlayersVehicleEngine(cVehicleParams& params, CAutomobile *automobile); void ProcessPoliceCellBeatingScriptObject(uint8 sound); void ProcessPornCinema(uint8 sound); void ProcessProjectiles(); - void ProcessRainOnVehicle(cVehicleParams *params); + void ProcessRainOnVehicle(cVehicleParams& params); void ProcessReverb() const; - bool ProcessReverseGear(cVehicleParams *params); + bool ProcessReverseGear(cVehicleParams& params); void ProcessSawMillScriptObject(uint8 sound); void ProcessScriptObject(int32 id); void ProcessShopScriptObject(uint8 sound); void ProcessSpecial(); - bool ProcessTrainNoise(cVehicleParams *params); + bool ProcessTrainNoise(cVehicleParams& params); void ProcessVehicle(CVehicle *vehicle); - bool ProcessVehicleDoors(cVehicleParams *params); - void ProcessVehicleEngine(cVehicleParams *params); - void ProcessVehicleHorn(cVehicleParams *params); - void ProcessVehicleOneShots(cVehicleParams *params); - bool ProcessVehicleReverseWarning(cVehicleParams *params); - bool ProcessVehicleRoadNoise(cVehicleParams *params); - bool ProcessVehicleSirenOrAlarm(cVehicleParams *params); - bool ProcessVehicleSkidding(cVehicleParams *params); + bool ProcessVehicleDoors(cVehicleParams& params); + void ProcessVehicleEngine(cVehicleParams& params); + void ProcessVehicleHorn(cVehicleParams& params); + void ProcessVehicleOneShots(cVehicleParams& params); + bool ProcessVehicleReverseWarning(cVehicleParams& params); + bool ProcessVehicleRoadNoise(cVehicleParams& params); + bool ProcessVehicleSirenOrAlarm(cVehicleParams& params); + bool ProcessVehicleSkidding(cVehicleParams& params); void ProcessWaterCannon(int32); void ProcessWeather(int32 id); - bool ProcessWetRoadNoise(cVehicleParams *params); + bool ProcessWetRoadNoise(cVehicleParams& params); void ProcessWorkShopScriptObject(uint8 sound); int32 RandomDisplacement(uint32 seed) const; From f8367ebdef6d15d1b1892a3418ea8a1ed4df46b2 Mon Sep 17 00:00:00 2001 From: erorcun Date: Sun, 8 Nov 2020 21:11:55 +0300 Subject: [PATCH 039/129] Revert "Font: Fix text dimensions" This reverts commit 6729de49b16da9a1be3c95b146ba053bf214c91c. --- src/audio/MusicManager.cpp | 2 +- src/control/Darkel.cpp | 4 ++-- src/control/Garages.cpp | 2 +- src/core/Frontend.cpp | 10 +++++----- src/core/Game.cpp | 8 ++++---- src/core/Pad.cpp | 4 ++-- src/core/main.cpp | 2 +- src/render/Credits.cpp | 4 ++-- src/render/Hud.cpp | 24 ++++++++++++------------ src/render/SpecialFX.cpp | 2 +- 10 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index 10862cdc..5519d899 100644 --- a/src/audio/MusicManager.cpp +++ b/src/audio/MusicManager.cpp @@ -161,7 +161,7 @@ cMusicManager::DisplayRadioStationName() CFont::SetPropOn(); CFont::SetFontStyle(FONT_HEADING); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetCentreSize(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(22.0f) + SCREEN_SCALE_Y(2.0f), pCurrentStation); diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp index afdfcb82..793bec36 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -72,7 +72,7 @@ CDarkel::DrawMessages() { CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_X(610.0f)); + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(30.0f)); CFont::SetCentreOn(); CFont::SetPropOn(); uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart; @@ -132,7 +132,7 @@ CDarkel::DrawMessages() uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart; if (CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart < 5000) { CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_X(620.0f)); + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f)); CFont::SetCentreOn(); CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f)); CFont::SetJustifyOff(); diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 5a04285f..61c1a850 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -1400,7 +1400,7 @@ void CGarages::PrintMessages() CFont::SetPropOn(); CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_X(590.0f)); + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(50.0f)); CFont::SetCentreOn(); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); CFont::SetColor(CRGBA(0, 0, 0, 255)); diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 8221ad4f..1718218d 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -772,7 +772,7 @@ CMenuManager::Draw() CFont::SetRightJustifyOn(); CFont::SetFontStyle(FONT_HEADING); CFont::SetScale(MENU_X(0.7f), MENU_Y(0.5f)); - CFont::SetWrapx(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetWrapx(SCREEN_WIDTH); CFont::SetRightJustifyWrap(0.0f); strcpy(gString, "V1.1"); AsciiToUnicode(gString, gUString); @@ -852,7 +852,7 @@ CMenuManager::Draw() #endif } - CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetCentreSize(SCREEN_WIDTH); #ifdef PS2_LIKE_MENU bool itemsAreSelectable = !bottomBarActive; @@ -3490,11 +3490,11 @@ CMenuManager::MessageScreen(const char *text) CFont::SetPropOn(); CFont::SetJustifyOn(); CFont::SetBackGroundOnlyTextOn(); - CFont::SetWrapx(SCREEN_WIDTH - StretchX(170.0f)); // not used - CFont::SetRightJustifyWrap(SCREEN_WIDTH - StretchX(170.0f)); // not used + CFont::SetWrapx(SCREEN_WIDTH - StretchX(170.0f)); + CFont::SetRightJustifyWrap(SCREEN_WIDTH - StretchX(170.0f)); CSprite2d::DrawRect(CRect(StretchX(120.0f), StretchY(150.0f), SCREEN_WIDTH - StretchX(120.0f), SCREEN_HEIGHT - StretchY(220.0f)), CRGBA(50, 50, 50, 210)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); - CFont::SetCentreSize(SCREEN_SCALE_X(380.0f)); + CFont::SetCentreSize(SCREEN_STRETCH_X(380.0f)); CFont::SetCentreOn(); CFont::SetColor(CRGBA(255, 217, 106, 255)); CFont::SetScale(SCREEN_SCALE_X(SMALLTEXT_X_SCALE), SCREEN_SCALE_Y(SMALLTEXT_Y_SCALE)); diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 83c75d91..3507b3b3 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -128,10 +128,10 @@ void MessageScreen(char *msg) CFont::SetFontStyle(FONT_BANK); CFont::SetBackgroundOff(); - CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(190.0f)); // 450.0f // unused + CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(190.0f)); // 450.0f CFont::SetScale(SCREEN_SCALE_X(1.0f), SCREEN_SCALE_Y(1.0f)); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(450.0f)); // 450.0f + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(190.0f)); // 450.0f CFont::SetJustifyOff(); CFont::SetColor(CRGBA(255, 255, 255, 255)); CFont::SetDropColor(CRGBA(32, 32, 32, 255)); @@ -734,10 +734,10 @@ void CGame::InitialiseWhenRestarting(void) //CFont::SetFontStyle(?); CFont::SetBackgroundOff(); - CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(160.0f)); // 480.0f // unused + CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(160.0f)); // 480.0f CFont::SetScale(SCREEN_SCALE_X(1.0f), SCREEN_SCALE_Y(1.0f)); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(480.0f)); // 480.0f + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(160.0f)); // 480.0f CFont::SetJustifyOff(); CFont::SetColor(CRGBA(255, 255, 255, 255)); CFont::SetBackGroundOnlyTextOff(); diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 0e2f06a6..e2f90a7c 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -2593,7 +2593,7 @@ void CPad::PrintErrorMessage(void) CFont::SetScale(0.85f, 1.0f); CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 20)); + CFont::SetCentreSize(SCREEN_WIDTH - 20); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(255, 255, 200, 200)); @@ -2610,7 +2610,7 @@ void CPad::PrintErrorMessage(void) CFont::SetScale(0.85f, 1.0f); CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 20)); + CFont::SetCentreSize(SCREEN_WIDTH - 20); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(255, 255, 200, 200)); diff --git a/src/core/main.cpp b/src/core/main.cpp index 36c94043..80feddb7 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -852,7 +852,7 @@ DisplayGameDebugText() CFont::SetRightJustifyOff(); CFont::SetJustifyOff(); CFont::SetBackGroundOnlyTextOff(); - CFont::SetWrapx(SCREEN_WIDTH); + CFont::SetWrapx(640.0f); CFont::SetFontStyle(FONT_HEADING); CFont::SetColor(CRGBA(0, 0, 0, 255)); diff --git a/src/render/Credits.cpp b/src/render/Credits.cpp index 2c8a9952..6b28ff04 100644 --- a/src/render/Credits.cpp +++ b/src/render/Credits.cpp @@ -62,7 +62,7 @@ CCredits::Render(void) scrolloffset = (CTimer::GetTimeInMilliseconds() - CreditsStartTime) / 24.0f; CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 20)); + CFont::SetCentreSize(SCALE_AND_CENTER_X(DEFAULT_SCREEN_WIDTH - 20)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(220, 220, 220, 220)); @@ -496,4 +496,4 @@ CCredits::Render(void) bool CCredits::AreCreditsDone(void) { return !bCreditsGoing; -} +} \ No newline at end of file diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 3d6e59f6..4c8b6657 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -336,7 +336,7 @@ void CHud::Draw() CFont::SetScale(SCREEN_SCALE_X(0.4f), SCREEN_SCALE_Y(0.6f)); CFont::SetJustifyOff(); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetCentreSize(SCREEN_WIDTH); CFont::SetPropOn(); CFont::SetFontStyle(FONT_BANK); @@ -740,7 +740,7 @@ void CHud::Draw() CFont::SetRightJustifyWrap(0.0f); CFont::SetFontStyle(FONT_LOCALE(FONT_HEADING)); CFont::SetColor(CRGBA(244, 20, 20, 255)); - CFont::SetWrapx(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); CFont::SetPropOff(); CFont::SetBackGroundOnlyTextOn(); @@ -869,8 +869,8 @@ void CHud::Draw() else CFont::SetCentreOff(); - CFont::SetWrapx(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fWrapX)); - CFont::SetCentreSize(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fCenterSize)); + CFont::SetWrapx(SCALE_AND_CENTER_X(CTheScripts::IntroTextLines[i].m_fWrapX)); + CFont::SetCentreSize(SCALE_AND_CENTER_X(CTheScripts::IntroTextLines[i].m_fCenterSize)); if (CTheScripts::IntroTextLines[i].m_bBackground) CFont::SetBackgroundOn(); @@ -957,12 +957,12 @@ void CHud::Draw() CFont::SetScale(SCREEN_SCALE_X(1.8f), SCREEN_SCALE_Y(1.8f)); CFont::SetPropOn(); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(590.0f)); + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(25.0f)); CFont::SetFontStyle(FONT_HEADING); // Appearently sliding text in here was abandoned very early, since this text is centered now. - if (BigMessageX[0] >= SCALE_AND_CENTER_X(620.0f)) { + if (BigMessageX[0] >= SCREEN_SCALE_FROM_RIGHT(20.0f)) { BigMessageInUse[0] += CTimer::GetTimeStep(); if (BigMessageInUse[0] >= 120.0f) { @@ -997,7 +997,7 @@ void CHud::Draw() } else { BigMessageAlpha[0] = 0.0f; - BigMessageX[0] = SCALE_AND_CENTER_X(-60.0f); + BigMessageX[0] = SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 60.0f); BigMessageInUse[0] = 1.0f; } } @@ -1166,8 +1166,8 @@ void CHud::DrawAfterFade() else CFont::SetCentreOff(); - CFont::SetWrapx(SCREEN_SCALE_X(line.m_fWrapX)); - CFont::SetCentreSize(SCREEN_SCALE_X(line.m_fCenterSize)); + CFont::SetWrapx(SCALE_AND_CENTER_X(line.m_fWrapX)); + CFont::SetCentreSize(SCALE_AND_CENTER_X(line.m_fCenterSize)); if (line.m_bBackground) CFont::SetBackgroundOn(); else @@ -1213,7 +1213,7 @@ void CHud::DrawAfterFade() CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.5f)); CFont::SetCentreOn(); CFont::SetPropOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(600.0f)); + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(40.0f)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); CFont::SetColor(CRGBA(0, 0, 0, 255)); @@ -1229,7 +1229,7 @@ void CHud::DrawAfterFade() CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.5f)); CFont::SetCentreOn(); CFont::SetPropOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(620.0f)); + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f)); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); @@ -1286,7 +1286,7 @@ void CHud::DrawAfterFade() CFont::SetScale(SCREEN_SCALE_X(1.0f), SCREEN_SCALE_Y(1.2f)); CFont::SetCentreOn(); CFont::SetPropOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(620.0f)); + CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f)); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index 89043752..34423d83 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -1058,7 +1058,7 @@ CMoneyMessage::Render() CFont::SetScale(fScaleX, fScaleY); // maybe use SCREEN_SCALE_X and SCREEN_SCALE_Y here? CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetCentreSize(SCREEN_WIDTH); CFont::SetJustifyOff(); CFont::SetColor(CRGBA(m_Colour.r, m_Colour.g, m_Colour.b, (255.0f - 255.0f * fLifeTime) * m_fOpacity)); CFont::SetBackGroundOnlyTextOff(); From 612bd98039fe1516951994721298e05f34fb13b5 Mon Sep 17 00:00:00 2001 From: Roman Masanin <36927roma@gmail.com> Date: Sun, 8 Nov 2020 21:30:03 +0300 Subject: [PATCH 040/129] return bad code, becouse no one knows what to do with it --- src/audio/AudioLogic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index 95e6094f..a27d3351 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -1943,7 +1943,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams& params) break; } m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = event + 22; //originaly used m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i], which is same + m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 22; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -1977,7 +1977,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams& params) break; } m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = event + 10; //also used m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 10; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; From c91d5a90a1d796ad18f438e7f980fe773762631c Mon Sep 17 00:00:00 2001 From: Roman Masanin <36927roma@gmail.com> Date: Sun, 8 Nov 2020 23:29:57 +0300 Subject: [PATCH 041/129] easy way to safe few petaseconds --- src/audio/AudioLogic.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index a27d3351..fc828042 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -1943,7 +1943,11 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams& params) break; } m_sQueueSample.m_nBankIndex = SFX_BANK_0; +#ifdef THIS_IS_STUPID m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 22; +#else + m_sQueueSample.m_nCounter = event + 22; +#endif m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -1977,7 +1981,11 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams& params) break; } m_sQueueSample.m_nBankIndex = SFX_BANK_0; +#ifdef THIS_IS_STUPID m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] + 10; +#else + m_sQueueSample.m_nCounter = event + 10; +#endif m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; From 59f9c009efd3e149b83621c61716fa8da1ee1309 Mon Sep 17 00:00:00 2001 From: erorcun Date: Tue, 10 Nov 2020 01:41:21 +0300 Subject: [PATCH 042/129] Font: Hud: Use orig. text dimensions, fix right-align calculations --- src/control/Darkel.cpp | 4 ++-- src/control/Garages.cpp | 2 +- src/core/Frontend.cpp | 26 ++++++++++++++++++-------- src/core/Frontend.h | 1 - src/core/Game.cpp | 4 ++-- src/core/Pad.cpp | 4 ++-- src/core/main.cpp | 12 ++++++------ src/render/Credits.cpp | 4 ++-- src/render/Font.cpp | 20 +++++++++++++++++--- src/render/Hud.cpp | 26 +++++++++++++------------- 10 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp index 793bec36..afdfcb82 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -72,7 +72,7 @@ CDarkel::DrawMessages() { CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(30.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(610.0f)); CFont::SetCentreOn(); CFont::SetPropOn(); uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart; @@ -132,7 +132,7 @@ CDarkel::DrawMessages() uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart; if (CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart < 5000) { CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(620.0f)); CFont::SetCentreOn(); CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f)); CFont::SetJustifyOff(); diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 61c1a850..5a04285f 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -1400,7 +1400,7 @@ void CGarages::PrintMessages() CFont::SetPropOn(); CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(50.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(590.0f)); CFont::SetCentreOn(); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); CFont::SetColor(CRGBA(0, 0, 0, 255)); diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 1718218d..0831cc79 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -780,7 +780,7 @@ CMenuManager::Draw() #endif #endif CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN)); - CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH)); + CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(MENU_X_MARGIN - 2.0f)); switch (m_nCurrScreen) { case MENUPAGE_STATS: @@ -852,7 +852,11 @@ CMenuManager::Draw() #endif } +#ifdef ASPECT_RATIO_SCALE + CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH)); +#else CFont::SetCentreSize(SCREEN_WIDTH); +#endif #ifdef PS2_LIKE_MENU bool itemsAreSelectable = !bottomBarActive; @@ -1468,6 +1472,12 @@ CMenuManager::Draw() break; } + // Needed after the bug fix in Font.cpp +#ifdef FIX_BUGS + if (!CFont::Details.centre) + CFont::SetRightJustifyOff(); +#endif + // 60.0 is silly nextYToUse += lineHeight * CFont::GetNumberLines(MENU_X_LEFT_ALIGNED(60.0f), MENU_Y(nextYToUse), leftText); @@ -1976,7 +1986,7 @@ CMenuManager::DrawControllerSetupScreen() CFont::SetRightJustifyOff(); CFont::SetBackGroundOnlyTextOn(); CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN)); - CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH)); + CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(MENU_X_MARGIN - 2.0f)); PREPARE_MENU_HEADER @@ -2392,7 +2402,7 @@ CMenuManager::DrawFrontEndNormal() CFont::SetJustifyOn(); CFont::SetRightJustifyOff(); CFont::SetBackGroundOnlyTextOn(); - CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(40.0f)); // 600.0f + CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN)); // 600.0f CFont::SetColor(CRGBA(16, 16, 16, 255)); switch (m_nCurrScreen) { @@ -2710,7 +2720,7 @@ CMenuManager::DrawPlayerSetupScreen() CFont::SetRightJustifyOff(); CFont::SetBackGroundOnlyTextOn(); CFont::SetWrapx(MENU_X_RIGHT_ALIGNED(MENU_X_MARGIN)); - CFont::SetRightJustifyWrap(SCREEN_SCALE_X(MENUACTION_WIDTH)); + CFont::SetRightJustifyWrap(MENU_X_LEFT_ALIGNED(MENU_X_MARGIN - 2.0f)); PREPARE_MENU_HEADER @@ -3490,11 +3500,11 @@ CMenuManager::MessageScreen(const char *text) CFont::SetPropOn(); CFont::SetJustifyOn(); CFont::SetBackGroundOnlyTextOn(); - CFont::SetWrapx(SCREEN_WIDTH - StretchX(170.0f)); - CFont::SetRightJustifyWrap(SCREEN_WIDTH - StretchX(170.0f)); + CFont::SetWrapx(SCREEN_WIDTH - StretchX(170.0f)); // unused + CFont::SetRightJustifyWrap(SCREEN_WIDTH - StretchX(170.0f)); // unused CSprite2d::DrawRect(CRect(StretchX(120.0f), StretchY(150.0f), SCREEN_WIDTH - StretchX(120.0f), SCREEN_HEIGHT - StretchY(220.0f)), CRGBA(50, 50, 50, 210)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); - CFont::SetCentreSize(SCREEN_STRETCH_X(380.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(380.0f)); CFont::SetCentreOn(); CFont::SetColor(CRGBA(255, 217, 106, 255)); CFont::SetScale(SCREEN_SCALE_X(SMALLTEXT_X_SCALE), SCREEN_SCALE_Y(SMALLTEXT_Y_SCALE)); @@ -3585,7 +3595,7 @@ CMenuManager::PrintErrorMessage() CFont::SetJustifyOn(); CFont::SetRightJustifyOff(); CFont::SetBackGroundOnlyTextOn(); - CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(40.0f)); + CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(MENU_X_MARGIN)); #ifdef FIX_BUGS CFont::PrintString(SCREEN_SCALE_X(50.0f), SCREEN_SCALE_Y(180.0f), TheText.Get(CPad::bDisplayNoControllerMessage ? "NOCONT" : "WRCONT")); #else diff --git a/src/core/Frontend.h b/src/core/Frontend.h index fba98690..72288f98 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -18,7 +18,6 @@ #define MENU_X_MARGIN 40.0f #define MENUACTION_POS_Y 60.0f -#define MENUACTION_WIDTH 38.0f #define MENUACTION_SCALE_MULT 0.9f #define MENURADIO_ICON_SCALE 60.0f diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 3507b3b3..f7589d2b 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -131,7 +131,7 @@ void MessageScreen(char *msg) CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(190.0f)); // 450.0f CFont::SetScale(SCREEN_SCALE_X(1.0f), SCREEN_SCALE_Y(1.0f)); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(190.0f)); // 450.0f + CFont::SetCentreSize(SCREEN_SCALE_X(450.0f)); // 450.0f CFont::SetJustifyOff(); CFont::SetColor(CRGBA(255, 255, 255, 255)); CFont::SetDropColor(CRGBA(32, 32, 32, 255)); @@ -737,7 +737,7 @@ void CGame::InitialiseWhenRestarting(void) CFont::SetWrapx(SCREEN_SCALE_FROM_RIGHT(160.0f)); // 480.0f CFont::SetScale(SCREEN_SCALE_X(1.0f), SCREEN_SCALE_Y(1.0f)); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(160.0f)); // 480.0f + CFont::SetCentreSize(SCREEN_SCALE_X(480.0f)); CFont::SetJustifyOff(); CFont::SetColor(CRGBA(255, 255, 255, 255)); CFont::SetBackGroundOnlyTextOff(); diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index e2f90a7c..928ae826 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -2593,7 +2593,7 @@ void CPad::PrintErrorMessage(void) CFont::SetScale(0.85f, 1.0f); CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_WIDTH - 20); + CFont::SetCentreSize(SCREEN_SCALE_X(SCREEN_WIDTH - 20)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(255, 255, 200, 200)); @@ -2610,7 +2610,7 @@ void CPad::PrintErrorMessage(void) CFont::SetScale(0.85f, 1.0f); CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCREEN_WIDTH - 20); + CFont::SetCentreSize(SCREEN_SCALE_X(SCREEN_WIDTH - 20)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(255, 255, 200, 200)); diff --git a/src/core/main.cpp b/src/core/main.cpp index 80feddb7..2e4b839a 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -625,20 +625,20 @@ LoadingIslandScreen(const char *levelName) CFont::SetScale(1.5f, 1.5f); CFont::SetPropOn(); CFont::SetRightJustifyOn(); - CFont::SetRightJustifyWrap(150.0f); + CFont::SetRightJustifyWrap(SCREEN_SCALE_X(150.0f)); CFont::SetFontStyle(FONT_HEADING); sprintf(str, "WELCOME TO"); AsciiToUnicode(str, wstr); CFont::SetDropColor(CRGBA(0, 0, 0, 255)); CFont::SetDropShadowPosition(3); CFont::SetColor(CRGBA(243, 237, 71, 255)); - CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); - CFont::PrintString(SCREEN_WIDTH - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); + CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); TextCopy(wstr, name); TheText.UpperCase(wstr); CFont::SetColor(CRGBA(243, 237, 71, 255)); - CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); - CFont::PrintString(SCREEN_WIDTH-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr); + CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.2f)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr); CFont::DrawFonts(); DoRWStuffEndOfFrame(); } @@ -852,7 +852,7 @@ DisplayGameDebugText() CFont::SetRightJustifyOff(); CFont::SetJustifyOff(); CFont::SetBackGroundOnlyTextOff(); - CFont::SetWrapx(640.0f); + CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); CFont::SetFontStyle(FONT_HEADING); CFont::SetColor(CRGBA(0, 0, 0, 255)); diff --git a/src/render/Credits.cpp b/src/render/Credits.cpp index 6b28ff04..2c8a9952 100644 --- a/src/render/Credits.cpp +++ b/src/render/Credits.cpp @@ -62,7 +62,7 @@ CCredits::Render(void) scrolloffset = (CTimer::GetTimeInMilliseconds() - CreditsStartTime) / 24.0f; CFont::SetJustifyOff(); CFont::SetBackgroundOff(); - CFont::SetCentreSize(SCALE_AND_CENTER_X(DEFAULT_SCREEN_WIDTH - 20)); + CFont::SetCentreSize(SCREEN_SCALE_X(DEFAULT_SCREEN_WIDTH - 20)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetColor(CRGBA(220, 220, 220, 220)); @@ -496,4 +496,4 @@ CCredits::Render(void) bool CCredits::AreCreditsDone(void) { return !bCreditsGoing; -} \ No newline at end of file +} diff --git a/src/render/Font.cpp b/src/render/Font.cpp index 719dffce..fbcc38e4 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -279,8 +279,8 @@ CFont::Initialise(void) SetColor(CRGBA(0xFF, 0xFF, 0xFF, 0)); SetJustifyOff(); SetCentreOff(); - SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); - SetCentreSize(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); + SetWrapx(SCREEN_WIDTH); + SetCentreSize(SCREEN_WIDTH); SetBackgroundOff(); SetBackgroundColor(CRGBA(0x80, 0x80, 0x80, 0x80)); SetBackGroundOnlyTextOff(); @@ -701,7 +701,14 @@ CFont::GetNumberLines(float xstart, float ystart, wchar *s) y = ystart; while(*s){ +#ifdef FIX_BUGS + float f = Details.centre ? Details.centreSize : + Details.rightJustify ? xstart - Details.rightJustifyWrap : + Details.wrapX; +#else float f = (Details.centre ? Details.centreSize : Details.wrapX); +#endif + #ifdef MORE_LANGUAGES if (IsJapaneseFont()) f -= SCREEN_SCALE_X(21.0f * 2.0f); @@ -781,8 +788,15 @@ CFont::GetTextRect(CRect *rect, float xstart, float ystart, wchar *s) x = xstart; y = ystart; +#ifdef FIX_BUGS + float xEnd = Details.centre ? Details.centreSize : + Details.rightJustify ? xstart - Details.rightJustifyWrap : + Details.wrapX; +#else + float xEnd = (Details.centre ? Details.centreSize : Details.wrapX); +#endif while(*s){ - if(x + GetStringWidth(s) > (Details.centre ? Details.centreSize : Details.wrapX)){ + if(x + GetStringWidth(s) > xEnd){ // reached end of line if(x > maxlength) maxlength = x; diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 4c8b6657..de3128ce 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -870,7 +870,7 @@ void CHud::Draw() CFont::SetCentreOff(); CFont::SetWrapx(SCALE_AND_CENTER_X(CTheScripts::IntroTextLines[i].m_fWrapX)); - CFont::SetCentreSize(SCALE_AND_CENTER_X(CTheScripts::IntroTextLines[i].m_fCenterSize)); + CFont::SetCentreSize(SCREEN_SCALE_X(CTheScripts::IntroTextLines[i].m_fCenterSize)); if (CTheScripts::IntroTextLines[i].m_bBackground) CFont::SetBackgroundOn(); @@ -931,9 +931,9 @@ void CHud::Draw() CFont::SetPropOn(); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); - float offsetX = SCREEN_SCALE_X(40.0f) + SCREEN_SCALE_X(8.0f); - float center = SCREEN_SCALE_FROM_RIGHT(50.0f) - SCREEN_SCALE_X(8.0f) - offsetX; - CFont::SetCentreSize(center); + float radarBulge = SCREEN_SCALE_X(40.0f) + SCREEN_SCALE_X(8.0f); + float rectWidth = SCREEN_WIDTH - SCREEN_SCALE_X(50.0f) - SCREEN_SCALE_X(8.0f) - radarBulge; + CFont::SetCentreSize(rectWidth); const int16 shadow = 1; CFont::SetDropShadowPosition(shadow); @@ -941,7 +941,7 @@ void CHud::Draw() CFont::SetColor(CRGBA(235, 235, 235, 255)); // I'm not sure shadow substaction was intentional here, might be a leftover if CFont::PrintString was used for a shadow draw call - CFont::PrintString(center / 2.0f + offsetX - SCREEN_SCALE_X(shadow), SCREEN_SCALE_Y(4.0f) + SCREEN_SCALE_FROM_BOTTOM(68.0f) - SCREEN_SCALE_Y(shadow), m_Message); + CFont::PrintString(rectWidth / 2.0f + radarBulge - SCREEN_SCALE_X(shadow), SCREEN_SCALE_Y(4.0f) + SCREEN_SCALE_FROM_BOTTOM(68.0f) - SCREEN_SCALE_Y(shadow), m_Message); CFont::SetDropShadowPosition(0); } @@ -957,12 +957,12 @@ void CHud::Draw() CFont::SetScale(SCREEN_SCALE_X(1.8f), SCREEN_SCALE_Y(1.8f)); CFont::SetPropOn(); CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(25.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(615.0f)); CFont::SetFontStyle(FONT_HEADING); // Appearently sliding text in here was abandoned very early, since this text is centered now. - if (BigMessageX[0] >= SCREEN_SCALE_FROM_RIGHT(20.0f)) { + if (BigMessageX[0] >= SCALE_AND_CENTER_X(620.0f)) { BigMessageInUse[0] += CTimer::GetTimeStep(); if (BigMessageInUse[0] >= 120.0f) { @@ -997,7 +997,7 @@ void CHud::Draw() } else { BigMessageAlpha[0] = 0.0f; - BigMessageX[0] = SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 60.0f); + BigMessageX[0] = SCALE_AND_CENTER_X(-60.0f); BigMessageInUse[0] = 1.0f; } } @@ -1167,7 +1167,7 @@ void CHud::DrawAfterFade() CFont::SetCentreOff(); CFont::SetWrapx(SCALE_AND_CENTER_X(line.m_fWrapX)); - CFont::SetCentreSize(SCALE_AND_CENTER_X(line.m_fCenterSize)); + CFont::SetCentreSize(SCREEN_SCALE_X(line.m_fCenterSize)); if (line.m_bBackground) CFont::SetBackgroundOn(); else @@ -1213,7 +1213,7 @@ void CHud::DrawAfterFade() CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.5f)); CFont::SetCentreOn(); CFont::SetPropOn(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(40.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(600.0f)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); CFont::SetColor(CRGBA(0, 0, 0, 255)); @@ -1229,7 +1229,7 @@ void CHud::DrawAfterFade() CFont::SetScale(SCREEN_SCALE_X(1.2f), SCREEN_SCALE_Y(1.5f)); CFont::SetCentreOn(); CFont::SetPropOn(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(620.0f)); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); @@ -1286,7 +1286,7 @@ void CHud::DrawAfterFade() CFont::SetScale(SCREEN_SCALE_X(1.0f), SCREEN_SCALE_Y(1.2f)); CFont::SetCentreOn(); CFont::SetPropOn(); - CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f)); + CFont::SetCentreSize(SCREEN_SCALE_X(620.0f)); CFont::SetColor(CRGBA(0, 0, 0, 255)); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); @@ -1318,7 +1318,7 @@ void CHud::DrawAfterFade() CFont::SetScale(SCREEN_SCALE_X(1.04f), SCREEN_SCALE_Y(1.6f)); CFont::SetPropOn(); - CFont::SetRightJustifyWrap(SCREEN_SCALE_X(-500.0f)); + CFont::SetRightJustifyWrap(SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 500.0f)); CFont::SetRightJustifyOn(); CFont::SetFontStyle(FONT_HEADING); if (BigMessageX[1] >= SCREEN_SCALE_FROM_RIGHT(20.0f)) { From 460f3cea447296cb5757c04108b9ac6becd6c968 Mon Sep 17 00:00:00 2001 From: erorcun Date: Tue, 10 Nov 2020 02:06:59 +0300 Subject: [PATCH 043/129] Frontend: Scroll for All, some care for PS2-like menu Don't show Back button on PS2-like menu Removed PS2-style reversed fade-in, because it was a hack and taking too much space --- src/core/Frontend.cpp | 800 +++++++++++++++++++++++------------------- src/core/Frontend.h | 1 + 2 files changed, 436 insertions(+), 365 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 0831cc79..4be23b77 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -41,14 +41,7 @@ #define TIDY_UP_PBP // ProcessButtonPresses #define MAX_VISIBLE_LIST_ROW 30 #define SCROLLBAR_MAX_HEIGHT 263.0f // not in end result - -#ifdef USE_PRECISE_MEASUREMENT_CONVERTION -#define MILES_IN_METER 0.000621371192f -#define FEET_IN_METER 3.28084f -#else -#define MILES_IN_METER 0.00059880241f -#define FEET_IN_METER 3.33f -#endif +#define SCROLLABLE_PAGES #ifdef SCROLLABLE_STATS_PAGE #define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS) @@ -56,6 +49,34 @@ #define isPlainTextScreen(screen) (screen == MENUPAGE_BRIEFS || screen == MENUPAGE_STATS) #endif +#define hasNativeList(screen) (screen == MENUPAGE_MULTIPLAYER_FIND_GAME || screen == MENUPAGE_SKIN_SELECT \ + || screen == MENUPAGE_KEYBOARD_CONTROLS) + +#ifdef SCROLLABLE_PAGES +#define MAX_VISIBLE_OPTION 12 +#define MAX_VISIBLE_OPTION_ON_SCREEN (hasNativeList(m_nCurrScreen) ? MAX_VISIBLE_LIST_ROW : MAX_VISIBLE_OPTION) + +int GetOptionCount(int screen) +{ + int i = 0; + for (; i < NUM_MENUROWS && aScreens[screen].m_aEntries[i].m_Action != MENUACTION_NOTHING; i++); + return i; +} + +#define SETUP_SCROLLING(screen) \ + if (!hasNativeList(screen)) { \ + m_nTotalListRow = GetOptionCount(screen); \ + if (m_nTotalListRow > MAX_VISIBLE_OPTION) { \ + m_nSelectedListRow = 0; \ + m_nFirstVisibleRowOnList = 0; \ + m_nScrollbarTopMargin = 0; \ + } \ + } +#else +#define MAX_VISIBLE_OPTION_ON_SCREEN MAX_VISIBLE_LIST_ROW +#define SETUP_SCROLLING(screen) +#endif + #ifdef TRIANGLE_BACK_BUTTON #define GetBackJustUp GetTriangleJustUp #define GetBackJustDown GetTriangleJustDown @@ -80,13 +101,40 @@ float CMenuManager::fMapCenterX; BottomBarOption bbNames[8]; int bbTabCount = 0; bool bottomBarActive = false; -bool reverseAlpha = false; int pendingScreen = -1; int pendingOption = -1; int curBottomBarOption = -1; int hoveredBottomBarOption = -1; #endif +#ifdef CUTSCENE_BORDERS_SWITCH +bool CMenuManager::m_PrefsCutsceneBorders = true; +#endif + +#ifdef MULTISAMPLING +int8 CMenuManager::m_nPrefsMSAALevel = 0; +int8 CMenuManager::m_nDisplayMSAALevel = 0; +#endif + +#ifdef NO_ISLAND_LOADING +int8 CMenuManager::m_PrefsIslandLoading = ISLAND_LOADING_LOW; +#endif + +// Originally that was PS2 option color, they forget it here and used in PrintBriefs once(but didn't use the output anyway) +#ifdef PS2_LIKE_MENU +const CRGBA TEXT_COLOR = CRGBA(150, 110, 30, 255); +#else +const CRGBA TEXT_COLOR = CRGBA(235, 170, 50, 255); // PC briefs text color +#endif + +#ifdef USE_PRECISE_MEASUREMENT_CONVERTION +#define MILES_IN_METER 0.000621371192f +#define FEET_IN_METER 3.28084f +#else +#define MILES_IN_METER 0.00059880241f +#define FEET_IN_METER 3.33f +#endif + int32 CMenuManager::OS_Language = LANG_ENGLISH; int8 CMenuManager::m_PrefsUseVibration; int8 CMenuManager::m_DisplayControllerOnFoot; @@ -112,30 +160,11 @@ int8 CMenuManager::m_bFrontEnd_ReloadObrTxtGxt; int32 CMenuManager::m_PrefsMusicVolume = 102; int32 CMenuManager::m_PrefsSfxVolume = 102; -#ifdef CUTSCENE_BORDERS_SWITCH -bool CMenuManager::m_PrefsCutsceneBorders = true; -#endif - -#ifdef MULTISAMPLING -int8 CMenuManager::m_nPrefsMSAALevel = 0; -int8 CMenuManager::m_nDisplayMSAALevel = 0; -#endif - -#ifdef NO_ISLAND_LOADING -int8 CMenuManager::m_PrefsIslandLoading = ISLAND_LOADING_LOW; -#endif char CMenuManager::m_PrefsSkinFile[256] = DEFAULT_SKIN_NAME; int32 CMenuManager::m_KeyPressedCode = -1; -// Originally that was PS2 option color, they forget it here and used in PrintBriefs once(but didn't use the output anyway) -#ifdef PS2_LIKE_MENU -const CRGBA TEXT_COLOR = CRGBA(150, 110, 30, 255); -#else -const CRGBA TEXT_COLOR = CRGBA(235, 170, 50, 255); // PC briefs text color -#endif - float MENU_TEXT_SIZE_X = SMALLTEXT_X_SCALE; float MENU_TEXT_SIZE_Y = SMALLTEXT_Y_SCALE; @@ -253,35 +282,12 @@ const char* MenuFilenames[][2] = { #define PAGE_NAME_X SCREEN_SCALE_FROM_RIGHT #endif -#ifdef PS2_LIKE_MENU -#define ChangeScreen(screen, option, updateDelay, withReverseAlpha) \ - do { \ - if (reverseAlpha) { \ - m_nPrevScreen = m_nCurrScreen; \ - m_nCurrScreen = pendingScreen; \ - m_nCurrOption = pendingOption; \ - reverseAlpha = false; \ - if (updateDelay) \ - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); \ - } \ - if (withReverseAlpha && !m_bRenderGameInMenu) { \ - pendingOption = option; \ - pendingScreen = screen; \ - reverseAlpha = true; \ - } else { \ - m_nPrevScreen = m_nCurrScreen; \ - m_nCurrScreen = screen; \ - m_nCurrOption = option; \ - if (updateDelay) \ - m_nScreenChangeDelayTimer = CTimer::GetTimeInMillisecondsPauseMode(); \ - } \ - m_nMenuFadeAlpha = 255; \ - } while(0) -#else +// Seperate func. in VC #define ChangeScreen(screen, option, updateDelay, clearAlpha) \ do { \ m_nPrevScreen = m_nCurrScreen; \ int newOpt = option; \ + SETUP_SCROLLING(screen) \ m_nCurrScreen = screen; \ m_nCurrOption = newOpt; \ if(updateDelay) \ @@ -289,7 +295,6 @@ const char* MenuFilenames[][2] = { if(clearAlpha) \ m_nMenuFadeAlpha = 0; \ } while(0) -#endif #define PREPARE_MENU_HEADER \ CFont::SetColor(CRGBA(0, 0, 0, FadeIn(255))); \ @@ -340,8 +345,8 @@ CMenuManager::ScrollUpListByOne() void CMenuManager::ScrollDownListByOne() { - if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1) { - if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { + if (m_nSelectedListRow == m_nFirstVisibleRowOnList + MAX_VISIBLE_OPTION_ON_SCREEN - 1) { + if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_OPTION_ON_SCREEN) { m_nSelectedListRow++; m_nFirstVisibleRowOnList++; m_nScrollbarTopMargin += SCROLLBAR_MAX_HEIGHT / m_nTotalListRow; @@ -356,13 +361,13 @@ CMenuManager::ScrollDownListByOne() void CMenuManager::PageUpList(bool playSoundOnSuccess) { - if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { + if (m_nTotalListRow > MAX_VISIBLE_OPTION_ON_SCREEN) { if (m_nFirstVisibleRowOnList > 0) { if(playSoundOnSuccess) DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - m_nFirstVisibleRowOnList = Max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_LIST_ROW); - m_nSelectedListRow = Min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW - 1); + m_nFirstVisibleRowOnList = Max(0, m_nFirstVisibleRowOnList - MAX_VISIBLE_OPTION_ON_SCREEN); + m_nSelectedListRow = Min(m_nSelectedListRow, m_nFirstVisibleRowOnList + MAX_VISIBLE_OPTION_ON_SCREEN - 1); } else { m_nFirstVisibleRowOnList = 0; m_nSelectedListRow = 0; @@ -374,15 +379,15 @@ CMenuManager::PageUpList(bool playSoundOnSuccess) void CMenuManager::PageDownList(bool playSoundOnSuccess) { - if (m_nTotalListRow > MAX_VISIBLE_LIST_ROW) { - if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_LIST_ROW) { + if (m_nTotalListRow > MAX_VISIBLE_OPTION_ON_SCREEN) { + if (m_nFirstVisibleRowOnList < m_nTotalListRow - MAX_VISIBLE_OPTION_ON_SCREEN) { if(playSoundOnSuccess) DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - m_nFirstVisibleRowOnList = Min(m_nFirstVisibleRowOnList + MAX_VISIBLE_LIST_ROW, m_nTotalListRow - MAX_VISIBLE_LIST_ROW); + m_nFirstVisibleRowOnList = Min(m_nFirstVisibleRowOnList + MAX_VISIBLE_OPTION_ON_SCREEN, m_nTotalListRow - MAX_VISIBLE_OPTION_ON_SCREEN); m_nSelectedListRow = Max(m_nSelectedListRow, m_nFirstVisibleRowOnList); } else { - m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; + m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_OPTION_ON_SCREEN; m_nSelectedListRow = m_nTotalListRow - 1; } m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; @@ -433,6 +438,14 @@ CMenuManager::ThingsToDoBeforeGoingBack() m_nTotalListRow = 0; } +#ifdef SCROLLABLE_PAGES + if (m_nTotalListRow > MAX_VISIBLE_OPTION && !hasNativeList(m_nCurrScreen)) { + m_nSelectedListRow = 0; + m_nFirstVisibleRowOnList = 0; + m_nScrollbarTopMargin = 0; + } +#endif + #ifdef CUSTOM_FRONTEND_OPTIONS CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; @@ -475,6 +488,236 @@ CMenuManager::GetPreviousPageOption() #endif } +void +CMenuManager::ProcessList(bool &goBack, bool &optionSelected) +{ + if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { + m_nTotalListRow = m_nSkinsTotal; + } + if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { + m_nTotalListRow = m_ControlMethod == CONTROL_CLASSIC ? 30 : 25; + if (m_nSelectedListRow > m_nTotalListRow) + m_nSelectedListRow = m_nTotalListRow - 1; + } + +#ifndef TIDY_UP_PBP + if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) { + m_bShowMouse = 0; + optionSelected = true; + } +#endif + if (CPad::GetPad(0)->GetBackspaceJustDown() && m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS && !field_535) { + if (m_nCurrExLayer == HOVEROPTION_LIST) { + m_nHoverOption = HOVEROPTION_NOT_HOVERING; + m_bWaitingForNewKeyBind = true; + m_bStartWaitingForKeyBind = true; + m_bKeyChangeNotProcessed = true; + pControlEdit = &m_KeyPressedCode; + } + } else { + field_535 = false; + } + + static uint32 lastTimeClickedScrollButton = 0; + + if (CTimer::GetTimeInMillisecondsPauseMode() - lastTimeClickedScrollButton >= 200) { + m_bPressedPgUpOnList = false; + m_bPressedPgDnOnList = false; + m_bPressedUpOnList = false; + m_bPressedDownOnList = false; + m_bPressedScrollButton = false; + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); + } + + if (CPad::GetPad(0)->GetTabJustDown()) { + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); + m_bShowMouse = false; + switch (m_nCurrExLayer) { + case HOVEROPTION_BACK: + default: + m_nCurrExLayer = HOVEROPTION_LIST; + break; + case HOVEROPTION_LIST: + m_nCurrExLayer = HOVEROPTION_USESKIN; + break; + case HOVEROPTION_USESKIN: + m_nCurrExLayer = HOVEROPTION_BACK; + } + if (((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) && strcmp(m_aSkinName, m_PrefsSkinFile) == 0) { + m_nCurrExLayer = HOVEROPTION_BACK; + } + if ((m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) { + m_nCurrExLayer = HOVEROPTION_BACK; + } + } + + bool pressed = false; + if (CPad::GetPad(0)->GetUp() || CPad::GetPad(0)->GetAnaloguePadUp() || CPad::GetPad(0)->GetDPadUpJustDown()) { + m_bShowMouse = false; + pressed = true; + } else if (CPad::GetPad(0)->GetMouseWheelUpJustUp()) { + m_bShowMouse = true; + pressed = true; + } + + // Up + if (pressed) { + m_nCurrExLayer = HOVEROPTION_LIST; + if (!m_bPressedUpOnList) { + m_bPressedUpOnList = true; + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); + ScrollUpListByOne(); + } + } else { + m_bPressedUpOnList = false; + } + + pressed = false; + if (CPad::GetPad(0)->GetDown() || CPad::GetPad(0)->GetAnaloguePadDown() || CPad::GetPad(0)->GetDPadDownJustDown()) { + m_bShowMouse = false; + pressed = true; + } else if (CPad::GetPad(0)->GetMouseWheelDownJustDown()) { + m_bShowMouse = true; + pressed = true; + } + + // Down + if (pressed) { + m_nCurrExLayer = HOVEROPTION_LIST; + if (!m_bPressedDownOnList) { + m_bPressedDownOnList = true; + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); + ScrollDownListByOne(); + } + } else { + m_bPressedDownOnList = false; + } + + if (m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) { + if (!CPad::GetPad(0)->GetPageUp()) { + m_bPressedPgUpOnList = false; + } else { + m_nCurrExLayer = HOVEROPTION_LIST; + if (!m_bPressedPgUpOnList) { + m_bPressedPgUpOnList = true; + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); + m_bShowMouse = false; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); + PageUpList(false); + } + } + if (!CPad::GetPad(0)->GetPageDown()) { + m_bPressedPgDnOnList = false; + } else { + m_nCurrExLayer = HOVEROPTION_LIST; + if (!m_bPressedPgDnOnList) { + m_bPressedPgDnOnList = true; + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); + m_bShowMouse = false; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); + PageDownList(false); + } + } + if (CPad::GetPad(0)->GetHome()) { + m_nCurrExLayer = HOVEROPTION_LIST; + m_bShowMouse = false; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); + if (m_nTotalListRow >= MAX_VISIBLE_OPTION_ON_SCREEN) { + m_nFirstVisibleRowOnList = 0; + } + m_nSelectedListRow = 0; + m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; + } + if (CPad::GetPad(0)->GetEnd()) { + m_nCurrExLayer = HOVEROPTION_LIST; + m_bShowMouse = false; + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); + if (m_nTotalListRow >= MAX_VISIBLE_OPTION_ON_SCREEN) { + m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_OPTION_ON_SCREEN; + } + m_nSelectedListRow = m_nTotalListRow - 1; + m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; + } + } + +#ifndef TIDY_UP_PBP + if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetBackJustDown()) { + m_bShowMouse = false; + goBack = true; + } +#endif + + if (CPad::GetPad(0)->GetLeftMouseJustDown()) { + switch (m_nHoverOption) { + case HOVEROPTION_BACK: + goBack = true; + break; + case HOVEROPTION_PAGEUP: + PageUpList(true); + break; + case HOVEROPTION_PAGEDOWN: + PageDownList(true); + break; + case HOVEROPTION_USESKIN: + if (m_nSkinsTotal > 0) { + DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); + m_pSelectedSkin = m_pSkinListHead.nextSkin; + strcpy(m_PrefsSkinFile, m_aSkinName); + CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile); + SaveSettings(); + } + } + } + + if (CPad::GetPad(0)->GetLeftMouseJustDown()) { + switch (m_nHoverOption) { + case HOVEROPTION_OVER_SCROLL_UP: + m_nHoverOption = HOVEROPTION_CLICKED_SCROLL_UP; + break; + case HOVEROPTION_OVER_SCROLL_DOWN: + m_nHoverOption = HOVEROPTION_CLICKED_SCROLL_DOWN; + break; + case HOVEROPTION_LIST: + m_nHoverOption = HOVEROPTION_SKIN; + } + } else if ((CPad::GetPad(0)->GetLeftMouseJustUp()) + && ((m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_UP || (m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_DOWN)))) { + m_nHoverOption = HOVEROPTION_NOT_HOVERING; + } + + if (!CPad::GetPad(0)->GetLeftMouse()) { + holdingScrollBar = false; + } else { + if ((m_nHoverOption == HOVEROPTION_HOLDING_SCROLLBAR) || holdingScrollBar) { + holdingScrollBar = true; + // TODO: This part is a bit hard to reverse. Not much code tho + assert(0 && "Holding scrollbar isn't done yet"); + } else { + switch (m_nHoverOption) { + case HOVEROPTION_OVER_SCROLL_UP: + case HOVEROPTION_CLICKED_SCROLL_UP: + if (!m_bPressedScrollButton) { + m_bPressedScrollButton = true; + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); + ScrollUpListByOne(); + } + break; + case HOVEROPTION_OVER_SCROLL_DOWN: + case HOVEROPTION_CLICKED_SCROLL_DOWN: + if (!m_bPressedScrollButton) { + m_bPressedScrollButton = true; + lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); + ScrollDownListByOne(); + } + break; + default: + m_bPressedScrollButton = false; + } + } + } +} // ------ Functions not in the game/inlined ends void @@ -1018,12 +1261,23 @@ CMenuManager::Draw() #endif #ifdef CUSTOM_FRONTEND_OPTIONS - static int lastOption = m_nCurrOption; + static int lastSelectedOpt = m_nCurrOption; #endif +#ifdef SCROLLABLE_PAGES + int firstOption = m_nTotalListRow > MAX_VISIBLE_OPTION && !hasNativeList(m_nCurrScreen) ? m_nFirstVisibleRowOnList : 0; + for (int i = firstOption; i < firstOption + MAX_VISIBLE_OPTION && i < NUM_MENUROWS; ++i) { +#else for (int i = 0; i < NUM_MENUROWS; ++i) { +#endif + #ifdef CUSTOM_FRONTEND_OPTIONS bool isOptionDisabled = false; +#endif + // Hide back button +#ifdef PS2_LIKE_MENU + if ((i == NUM_MENUROWS - 1 || aScreens[m_nCurrScreen].m_aEntries[i+1].m_EntryName[0] == '\0') && strncmp(aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName, "FEDS_TB", 8) == 0) + break; #endif if (aScreens[m_nCurrScreen].m_aEntries[i].m_Action != MENUACTION_LABEL && aScreens[m_nCurrScreen].m_aEntries[i].m_EntryName[0] != '\0') { wchar *rightText = nil; @@ -1064,8 +1318,8 @@ CMenuManager::Draw() } } - if (m_nCurrOption != lastOption && lastOption == i) { - CMenuScreenCustom::CMenuEntry &oldOption = aScreens[m_nCurrScreen].m_aEntries[lastOption]; + if (m_nCurrOption != lastSelectedOpt && lastSelectedOpt == i) { + CMenuScreenCustom::CMenuEntry &oldOption = aScreens[m_nCurrScreen].m_aEntries[lastSelectedOpt]; if (oldOption.m_Action == MENUACTION_CFO_DYNAMIC) if(oldOption.m_CFODynamic->buttonPressFunc) oldOption.m_CFODynamic->buttonPressFunc(FEOPTION_ACTION_FOCUSLOSS); @@ -1317,9 +1571,20 @@ CMenuManager::Draw() int nextYToCheck = bitAboveNextItemY; if (!foundTheHoveringItem) { +#ifdef SCROLLABLE_PAGES + for (int rowToCheck = firstOption + (aScreens[m_nCurrScreen].m_aEntries[firstOption].m_Action == MENUACTION_LABEL); rowToCheck < firstOption + MAX_VISIBLE_OPTION && rowToCheck < NUM_MENUROWS; ++rowToCheck) { +#else for (int rowToCheck = aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL; rowToCheck < NUM_MENUROWS; ++rowToCheck) { +#endif if(aScreens[m_nCurrScreen].m_aEntries[rowToCheck].m_Action == MENUACTION_NOTHING) break; + + // Hide back button +#ifdef PS2_LIKE_MENU + if ((rowToCheck == NUM_MENUROWS - 1 || aScreens[m_nCurrScreen].m_aEntries[rowToCheck+1].m_EntryName[0] == '\0') && + strncmp(aScreens[m_nCurrScreen].m_aEntries[rowToCheck].m_EntryName, "FEDS_TB", 8) == 0) + break; +#endif int extraOffset = 0; if (aScreens[m_nCurrScreen].m_aEntries[rowToCheck].m_Action == MENUACTION_RADIO) @@ -1502,7 +1767,36 @@ CMenuManager::Draw() } #ifdef CUSTOM_FRONTEND_OPTIONS - lastOption = m_nCurrOption; + lastSelectedOpt = m_nCurrOption; +#endif + +#ifdef SCROLLABLE_PAGES + #define SCROLLBAR_BOTTOM_X 125.0f // only for background, scrollbar's itself is calculated + #define SCROLLBAR_RIGHT_X 36.0f + #define SCROLLBAR_WIDTH 9.5f + #define SCROLLBAR_TOP_X 64 + + if (m_nTotalListRow > MAX_VISIBLE_OPTION && !hasNativeList(m_nCurrScreen)) { + // Scrollbar background + CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(SCROLLBAR_RIGHT_X - 2), MENU_Y(SCROLLBAR_TOP_X), + MENU_X_RIGHT_ALIGNED(SCROLLBAR_RIGHT_X - 2 - SCROLLBAR_WIDTH), SCREEN_SCALE_FROM_BOTTOM(SCROLLBAR_BOTTOM_X)), CRGBA(100, 100, 66, FadeIn(205))); + + float scrollbarHeight = SCROLLBAR_MAX_HEIGHT / (m_nTotalListRow / (float) MAX_VISIBLE_OPTION); + float scrollbarBottom, scrollbarTop; + + scrollbarBottom = MENU_Y(SCROLLBAR_TOP_X - 8 + m_nScrollbarTopMargin + scrollbarHeight); + scrollbarTop = MENU_Y(SCROLLBAR_TOP_X + m_nScrollbarTopMargin); + // Scrollbar shadow + CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(SCROLLBAR_RIGHT_X - 4), scrollbarTop, + MENU_X_RIGHT_ALIGNED(SCROLLBAR_RIGHT_X - 1 - SCROLLBAR_WIDTH), scrollbarBottom + MENU_Y(1.0f)), + CRGBA(50, 50, 50, FadeIn(255))); + + // Scrollbar + CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(SCROLLBAR_RIGHT_X - 4), scrollbarTop, + MENU_X_RIGHT_ALIGNED(SCROLLBAR_RIGHT_X - SCROLLBAR_WIDTH), scrollbarBottom), + CRGBA(235, 170, 50, FadeIn(255))); + + } #endif switch (m_nCurrScreen) { @@ -2175,27 +2469,28 @@ CMenuManager::DrawFrontEnd() CFont::SetAlphaFade(255.0f); #ifdef PS2_LIKE_MENU + #define setBbItem(a, b, c) strcpy(a.name, b); a.screenId = c; if (m_nCurrScreen == MENUPAGE_NONE) { if (m_bGameNotLoaded) { if (bbTabCount != 6) { - bbNames[0] = { "FEB_SAV",MENUPAGE_NEW_GAME }; - bbNames[1] = { "FEB_CON",MENUPAGE_CONTROLLER_PC }; - bbNames[2] = { "FEB_AUD",MENUPAGE_SOUND_SETTINGS }; - bbNames[3] = { "FEB_DIS",MENUPAGE_DISPLAY_SETTINGS }; - bbNames[4] = { "FEB_LAN",MENUPAGE_LANGUAGE_SETTINGS }; - bbNames[5] = { "FESZ_QU",MENUPAGE_EXIT }; + setBbItem(bbNames[0], "FEB_SAV",MENUPAGE_NEW_GAME) + setBbItem(bbNames[1], "FEB_CON",MENUPAGE_CONTROLLER_PC) + setBbItem(bbNames[2], "FEB_AUD",MENUPAGE_SOUND_SETTINGS) + setBbItem(bbNames[3], "FEB_DIS",MENUPAGE_DISPLAY_SETTINGS) + setBbItem(bbNames[4], "FEB_LAN",MENUPAGE_LANGUAGE_SETTINGS) + setBbItem(bbNames[5], "FESZ_QU",MENUPAGE_EXIT) bbTabCount = 6; } } else { if (bbTabCount != 8) { - bbNames[0] = { "FEB_STA",MENUPAGE_STATS }; - bbNames[1] = { "FEB_SAV",MENUPAGE_NEW_GAME }; - bbNames[2] = { "FEB_BRI",MENUPAGE_BRIEFS }; - bbNames[3] = { "FEB_CON",MENUPAGE_CONTROLLER_PC }; - bbNames[4] = { "FEB_AUD",MENUPAGE_SOUND_SETTINGS }; - bbNames[5] = { "FEB_DIS",MENUPAGE_DISPLAY_SETTINGS }; - bbNames[6] = { "FEB_LAN",MENUPAGE_LANGUAGE_SETTINGS }; - bbNames[7] = { "FESZ_QU",MENUPAGE_EXIT }; + setBbItem(bbNames[0], "FEB_STA",MENUPAGE_STATS) + setBbItem(bbNames[1], "FEB_SAV",MENUPAGE_NEW_GAME) + setBbItem(bbNames[2], "FEB_BRI",MENUPAGE_BRIEFS) + setBbItem(bbNames[3], "FEB_CON",MENUPAGE_CONTROLLER_PC) + setBbItem(bbNames[4], "FEB_AUD",MENUPAGE_SOUND_SETTINGS) + setBbItem(bbNames[5], "FEB_DIS",MENUPAGE_DISPLAY_SETTINGS) + setBbItem(bbNames[6], "FEB_LAN",MENUPAGE_LANGUAGE_SETTINGS) + setBbItem(bbNames[7], "FESZ_QU",MENUPAGE_EXIT) bbTabCount = 8; } } @@ -2203,6 +2498,7 @@ CMenuManager::DrawFrontEnd() bottomBarActive = true; curBottomBarOption = 0; } + #undef setBbItem #else if (m_nCurrScreen == MENUPAGE_NONE) { if (m_bGameNotLoaded) { @@ -2293,7 +2589,7 @@ CMenuManager::DrawFrontEndNormal() m_aFrontEndSprites[FE2_MAINPANEL_UR].Draw(CRect(SCREEN_WIDTH / 2, 0.0f, MENU_X_RIGHT_ALIGNED(0.0f), SCREEN_HEIGHT / 2), CRGBA(255, 255, 255, 255)); m_aFrontEndSprites[FE2_MAINPANEL_DL].Draw(CRect(MENU_X_LEFT_ALIGNED(0.0f), SCREEN_HEIGHT / 2, SCREEN_WIDTH / 2, SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); m_aFrontEndSprites[FE2_MAINPANEL_DR].Draw(CRect(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, MENU_X_RIGHT_ALIGNED(0.0f), SCREEN_HEIGHT), CRGBA(255, 255, 255, 255)); - + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); eFrontendSprites currentSprite; switch (m_nCurrScreen) { @@ -2333,39 +2629,15 @@ CMenuManager::DrawFrontEndNormal() break; } - m_aFrontEndSprites[currentSprite].Draw(CRect(MENU_X_LEFT_ALIGNED(50.0f), MENU_Y(50.0f), MENU_X_RIGHT_ALIGNED(50.0f), SCREEN_SCALE_FROM_BOTTOM(95.0f)), CRGBA(255, 255, 255, m_nMenuFadeAlpha > 255 ? 255 : m_nMenuFadeAlpha)); - static float fadeAlpha = 0.0f; - static int lastState = 0; - // reverseAlpha = PS2 fading (wait for 255->0, then change screen) if (m_nMenuFadeAlpha < 255) { - if (lastState == 1 && !reverseAlpha) - fadeAlpha = 0.f; - - if (m_nMenuFadeAlpha <= 0 && reverseAlpha) { - reverseAlpha = false; - ChangeScreen(pendingScreen, pendingOption, true, false); - } else { - // +20 per every 33 ms (1000.f/30.f - original frame limiter fps) - if (!reverseAlpha) - fadeAlpha += (frameTime) * 20.f / 33.f; - else - fadeAlpha = max(0.0f, fadeAlpha - (frameTime) * 30.f / 33.f); - - m_nMenuFadeAlpha = fadeAlpha; - } - lastState = 0; + if (m_nMenuFadeAlpha == 0 && fadeAlpha > 1.0f) fadeAlpha = 0.0f; + + // +20 per every 33 ms (1000.f/30.f - original frame limiter fps) + fadeAlpha += (frameTime) * 20.f / 33.f; + m_nMenuFadeAlpha = fadeAlpha; } else { - if (lastState == 0) fadeAlpha = 255.f; - - if (reverseAlpha) { - fadeAlpha -= (frameTime) * 30.f / 33.f; - - m_nMenuFadeAlpha = fadeAlpha; - } - lastState = 1; - // TODO: what is this? waiting mouse? if(field_518 == 4){ if(m_nHoverOption == HOVEROPTION_3 || m_nHoverOption == HOVEROPTION_4 || @@ -2377,6 +2649,8 @@ CMenuManager::DrawFrontEndNormal() } } + m_aFrontEndSprites[currentSprite].Draw(CRect(MENU_X_LEFT_ALIGNED(50.0f), MENU_Y(50.0f), MENU_X_RIGHT_ALIGNED(50.0f), SCREEN_SCALE_FROM_BOTTOM(95.0f)), CRGBA(255, 255, 255, m_nMenuFadeAlpha > 255 ? 255 : m_nMenuFadeAlpha)); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST); RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void*)rwTEXTUREADDRESSCLAMP); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); @@ -2912,14 +3186,13 @@ CMenuManager::DrawPlayerSetupScreen() CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2), MENU_Y(PLAYERSETUP_LIST_TOP), MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 2 - PLAYERSETUP_SCROLLBAR_WIDTH), SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM)), CRGBA(100, 100, 66, FadeIn(205))); - // Scrollbar - float scrollbarHeight = SCROLLBAR_MAX_HEIGHT / m_nSkinsTotal * (float) MAX_VISIBLE_LIST_ROW; + float scrollbarHeight = SCROLLBAR_MAX_HEIGHT / (m_nSkinsTotal / (float) MAX_VISIBLE_LIST_ROW); float scrollbarBottom, scrollbarTop; if (m_nSkinsTotal <= MAX_VISIBLE_LIST_ROW) { scrollbarBottom = SCREEN_SCALE_FROM_BOTTOM(PLAYERSETUP_LIST_BOTTOM + PLAYERSETUP_SCROLLBUTTON_HEIGHT + 4.0f); scrollbarTop = MENU_Y(PLAYERSETUP_LIST_BODY_TOP); - // Shadow + // Scrollbar shadow CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 4), scrollbarTop, MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 1 - PLAYERSETUP_SCROLLBAR_WIDTH), scrollbarBottom + MENU_Y(1.0f)), CRGBA(50, 50, 50, FadeIn(255))); } else { @@ -2930,12 +3203,13 @@ CMenuManager::DrawPlayerSetupScreen() scrollbarBottom = MENU_Y(PLAYERSETUP_LIST_BODY_TOP - 4 + m_nScrollbarTopMargin + scrollbarHeight - SCROLLBAR_MAX_HEIGHT / m_nSkinsTotal); scrollbarTop = MENU_Y(SCROLLBAR_MAX_HEIGHT / m_nSkinsTotal + PLAYERSETUP_LIST_BODY_TOP - 3 + m_nScrollbarTopMargin); #endif - // Shadow + // Scrollbar shadow CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 4), scrollbarTop, MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 1 - PLAYERSETUP_SCROLLBAR_WIDTH), scrollbarBottom + MENU_Y(1.0f)), CRGBA(50, 50, 50, FadeIn(255))); } + // Scrollbar CSprite2d::DrawRect(CRect(MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - 4), scrollbarTop, MENU_X_RIGHT_ALIGNED(PLAYERSETUP_LIST_RIGHT - PLAYERSETUP_SCROLLBAR_WIDTH), scrollbarBottom), CRGBA(235, 170, 50, FadeIn(255))); @@ -3907,235 +4181,10 @@ CMenuManager::ProcessButtonPresses(void) if (m_nMousePosY < 0) m_nMousePosY = 0; if (m_nMousePosY > SCREEN_HEIGHT) m_nMousePosY = SCREEN_HEIGHT; - if (m_nCurrScreen == MENUPAGE_MULTIPLAYER_FIND_GAME || m_nCurrScreen == MENUPAGE_SKIN_SELECT - || m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { + if (hasNativeList(m_nCurrScreen)) { + // Not split to seperate function in III as in VC, but we need it for scrollable pages :) + ProcessList(goBack, optionSelected); - if (m_nCurrScreen == MENUPAGE_SKIN_SELECT) { - m_nTotalListRow = m_nSkinsTotal; - } - if (m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) { - m_nTotalListRow = m_ControlMethod == CONTROL_CLASSIC ? 30 : 25; - if (m_nSelectedListRow > m_nTotalListRow) - m_nSelectedListRow = m_nTotalListRow - 1; - } - -#ifndef TIDY_UP_PBP - if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown()) { - m_bShowMouse = 0; - optionSelected = true; - } -#endif - if (CPad::GetPad(0)->GetBackspaceJustDown() && m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS && !field_535) { - if (m_nCurrExLayer == HOVEROPTION_LIST) { - m_nHoverOption = HOVEROPTION_NOT_HOVERING; - m_bWaitingForNewKeyBind = true; - m_bStartWaitingForKeyBind = true; - m_bKeyChangeNotProcessed = true; - pControlEdit = &m_KeyPressedCode; - } - } else { - field_535 = false; - } - - static uint32 lastTimeClickedScrollButton = 0; - - if (CTimer::GetTimeInMillisecondsPauseMode() - lastTimeClickedScrollButton >= 200) { - m_bPressedPgUpOnList = false; - m_bPressedPgDnOnList = false; - m_bPressedUpOnList = false; - m_bPressedDownOnList = false; - m_bPressedScrollButton = false; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - } - - if (CPad::GetPad(0)->GetTabJustDown()) { - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - m_bShowMouse = false; - switch (m_nCurrExLayer) { - case HOVEROPTION_BACK: - default: - m_nCurrExLayer = HOVEROPTION_LIST; - break; - case HOVEROPTION_LIST: - m_nCurrExLayer = HOVEROPTION_USESKIN; - break; - case HOVEROPTION_USESKIN: - m_nCurrExLayer = HOVEROPTION_BACK; - } - if (((m_nCurrScreen == MENUPAGE_SKIN_SELECT) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) && strcmp(m_aSkinName, m_PrefsSkinFile) == 0) { - m_nCurrExLayer = HOVEROPTION_BACK; - } - if ((m_nCurrScreen == MENUPAGE_KEYBOARD_CONTROLS) && (m_nCurrExLayer == HOVEROPTION_USESKIN)) { - m_nCurrExLayer = HOVEROPTION_BACK; - } - } - - bool pressed = false; - if (CPad::GetPad(0)->GetUp() || CPad::GetPad(0)->GetAnaloguePadUp() || CPad::GetPad(0)->GetDPadUpJustDown()) { - m_bShowMouse = false; - pressed = true; - } else if (CPad::GetPad(0)->GetMouseWheelUpJustUp()) { - m_bShowMouse = true; - pressed = true; - } - - // Up - if (pressed) { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedUpOnList) { - m_bPressedUpOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - ScrollUpListByOne(); - } - } else { - m_bPressedUpOnList = false; - } - - pressed = false; - if (CPad::GetPad(0)->GetDown() || CPad::GetPad(0)->GetAnaloguePadDown() || CPad::GetPad(0)->GetDPadDownJustDown()) { - m_bShowMouse = false; - pressed = true; - } else if (CPad::GetPad(0)->GetMouseWheelDownJustDown()) { - m_bShowMouse = true; - pressed = true; - } - - // Down - if (pressed) { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedDownOnList) { - m_bPressedDownOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - ScrollDownListByOne(); - } - } else { - m_bPressedDownOnList = false; - } - - if (m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) { - if (!CPad::GetPad(0)->GetPageUp()) { - m_bPressedPgUpOnList = false; - } else { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedPgUpOnList) { - m_bPressedPgUpOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - PageUpList(false); - } - } - if (!CPad::GetPad(0)->GetPageDown()) { - m_bPressedPgDnOnList = false; - } else { - m_nCurrExLayer = HOVEROPTION_LIST; - if (!m_bPressedPgDnOnList) { - m_bPressedPgDnOnList = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - PageDownList(false); - } - } - if (CPad::GetPad(0)->GetHome()) { - m_nCurrExLayer = HOVEROPTION_LIST; - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - if (m_nTotalListRow >= MAX_VISIBLE_LIST_ROW) { - m_nFirstVisibleRowOnList = 0; - } - m_nSelectedListRow = 0; - m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; - } - if (CPad::GetPad(0)->GetEnd()) { - m_nCurrExLayer = HOVEROPTION_LIST; - m_bShowMouse = false; - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); - if (m_nTotalListRow >= MAX_VISIBLE_LIST_ROW) { - m_nFirstVisibleRowOnList = m_nTotalListRow - MAX_VISIBLE_LIST_ROW; - } - m_nSelectedListRow = m_nTotalListRow - 1; - m_nScrollbarTopMargin = (SCROLLBAR_MAX_HEIGHT / m_nTotalListRow) * m_nFirstVisibleRowOnList; - } - } - -#ifndef TIDY_UP_PBP - if (CPad::GetPad(0)->GetEscapeJustDown() || CPad::GetPad(0)->GetBackJustDown()) { - m_bShowMouse = false; - goBack = true; - } -#endif - - if (CPad::GetPad(0)->GetLeftMouseJustDown()) { - switch (m_nHoverOption) { - case HOVEROPTION_BACK: - goBack = true; - break; - case HOVEROPTION_PAGEUP: - PageUpList(true); - break; - case HOVEROPTION_PAGEDOWN: - PageDownList(true); - break; - case HOVEROPTION_USESKIN: - if (m_nSkinsTotal > 0) { - DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); - m_pSelectedSkin = m_pSkinListHead.nextSkin; - strcpy(m_PrefsSkinFile, m_aSkinName); - CWorld::Players[0].SetPlayerSkin(m_PrefsSkinFile); - SaveSettings(); - } - } - } - - if (CPad::GetPad(0)->GetLeftMouseJustDown()) { - switch (m_nHoverOption) { - case HOVEROPTION_OVER_SCROLL_UP: - m_nHoverOption = HOVEROPTION_CLICKED_SCROLL_UP; - break; - case HOVEROPTION_OVER_SCROLL_DOWN: - m_nHoverOption = HOVEROPTION_CLICKED_SCROLL_DOWN; - break; - case HOVEROPTION_LIST: - m_nHoverOption = HOVEROPTION_SKIN; - } - } else if ((CPad::GetPad(0)->GetLeftMouseJustUp()) - && ((m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_UP || (m_nHoverOption == HOVEROPTION_CLICKED_SCROLL_DOWN)))) { - m_nHoverOption = HOVEROPTION_NOT_HOVERING; - } - - if (!CPad::GetPad(0)->GetLeftMouse()) { - holdingScrollBar = false; - } else { - if ((m_nHoverOption == HOVEROPTION_HOLDING_SCROLLBAR) || holdingScrollBar) { - holdingScrollBar = true; - // TODO: This part is a bit hard to reverse. Not much code tho - assert(0 && "Holding scrollbar isn't done yet"); - } else { - switch (m_nHoverOption) { - case HOVEROPTION_OVER_SCROLL_UP: - case HOVEROPTION_CLICKED_SCROLL_UP: - if (!m_bPressedScrollButton) { - m_bPressedScrollButton = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - ScrollUpListByOne(); - } - break; - case HOVEROPTION_OVER_SCROLL_DOWN: - case HOVEROPTION_CLICKED_SCROLL_DOWN: - if (!m_bPressedScrollButton) { - m_bPressedScrollButton = true; - lastTimeClickedScrollButton = CTimer::GetTimeInMillisecondsPauseMode(); - ScrollDownListByOne(); - } - break; - default: - m_bPressedScrollButton = false; - } - } - } } else if (isPlainTextScreen(m_nCurrScreen)) { #ifndef TIDY_UP_PBP if (CPad::GetPad(0)->GetEnterJustDown() || CPad::GetPad(0)->GetCrossJustDown() || CPad::GetPad(0)->GetLeftMouseJustDown()) { @@ -4374,7 +4423,7 @@ CMenuManager::ProcessButtonPresses(void) TheCamera.m_fMouseAccelVertical = TheCamera.m_fMouseAccelHorzntl; SaveSettings(); break; - } + } #else switch (m_nHoverOption) { case HOVEROPTION_INCREASE_BRIGHTNESS: @@ -4393,7 +4442,26 @@ CMenuManager::ProcessButtonPresses(void) break; } #endif - } + } + +#ifdef SCROLLABLE_PAGES + if (m_nTotalListRow > MAX_VISIBLE_OPTION) { + bool temp = false; + + m_nSelectedListRow = m_nCurrOption; + + // ignore detected back/select states, it's our screen's job + ProcessList(temp, temp); + + // and ignore our screen's goUp/Down, now it's ProcessList's job + goUp = false; + goDown = false; + m_nCurrOption = m_nSelectedListRow; + } + + // Prevent sound on scroll. Mouse wheel is now belongs to us! + if (!(m_nTotalListRow > MAX_VISIBLE_OPTION && (CPad::GetPad(0)->GetMouseWheelUpJustDown() || CPad::GetPad(0)->GetMouseWheelDownJustDown()))) +#endif if (CPad::GetPad(0)->GetLeftMouseJustUp() || CPad::GetPad(0)->GetLeftJustUp() || CPad::GetPad(0)->GetRightJustUp() || CPad::GetPad(0)->GetDPadLeftJustUp() || CPad::GetPad(0)->GetDPadRightJustUp() @@ -4408,6 +4476,7 @@ CMenuManager::ProcessButtonPresses(void) DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); } + #ifndef TIDY_UP_PBP if (CPad::GetPad(0)->GetBackJustDown()) { if (m_nCurrScreen != MENUPAGE_START_MENU && m_nCurrScreen != MENUPAGE_PAUSE_MENU) { @@ -4427,7 +4496,7 @@ CMenuManager::ProcessButtonPresses(void) goBack = false; } #endif - } + } // Centralized enter/back (except some conditions) #ifdef TIDY_UP_PBP @@ -4480,16 +4549,10 @@ CMenuManager::ProcessButtonPresses(void) if (bbNames[curBottomBarOption].screenId == MENUPAGE_SOUND_SETTINGS) DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1); - // If there's a menu change with fade ongoing, finish it now - if (reverseAlpha) - m_nMenuFadeAlpha = 0; return; } else if (CPad::GetPad(0)->GetLeftJustDown() || CPad::GetPad(0)->GetAnaloguePadLeft() || CPad::GetPad(0)->GetDPadLeftJustDown() || CPad::GetPad(0)->GetUpJustDown() || CPad::GetPad(0)->GetAnaloguePadUp() || CPad::GetPad(0)->GetDPadUpJustDown()) { - if (reverseAlpha && m_nMenuFadeAlpha > 30) - return; - m_bShowMouse = false; DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); curBottomBarOption = ((curBottomBarOption + bbTabCount) - 1) % bbTabCount; @@ -4498,9 +4561,6 @@ CMenuManager::ProcessButtonPresses(void) } else if (CPad::GetPad(0)->GetRightJustDown() || CPad::GetPad(0)->GetAnaloguePadRight() || CPad::GetPad(0)->GetDPadRightJustDown() || CPad::GetPad(0)->GetDownJustDown() || CPad::GetPad(0)->GetAnaloguePadDown() || CPad::GetPad(0)->GetDPadDownJustDown()) { - if (reverseAlpha && m_nMenuFadeAlpha > 30) - return; - m_bShowMouse = false; DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_NAVIGATION, 0); curBottomBarOption = ((curBottomBarOption + bbTabCount) + 1) % bbTabCount; @@ -4531,6 +4591,12 @@ CMenuManager::ProcessButtonPresses(void) } } + // Hide back button +#ifdef PS2_LIKE_MENU + if ((goUp || goDown) && m_nCurrScreen != MENUPAGE_MULTIPLAYER_FIND_GAME && strncmp(aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_EntryName, "FEDS_TB", 8) == 0) + m_nCurrOption = goUp ? m_nCurrOption - 1 : (aScreens[m_nCurrScreen].m_aEntries[0].m_Action == MENUACTION_LABEL); +#endif + if (optionSelected) { int option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption].m_Action; if ((option == MENUACTION_CHANGEMENU) || (option == MENUACTION_POPULATESLOTS_CHANGEMENU)) { @@ -5056,23 +5122,27 @@ CMenuManager::ProcessButtonPresses(void) if (CPad::GetPad(0)->GetRightJustDown() || CPad::GetPad(0)->GetAnaloguePadRight() || CPad::GetPad(0)->GetDPadRightJustDown()) { m_bShowMouse = false; increase = true; - } else if (CPad::GetPad(0)->GetMouseWheelUpJustDown() && m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) { + } else if ( +#ifdef SCROLLABLE_PAGES + !(m_nTotalListRow > MAX_VISIBLE_OPTION && !hasNativeList(m_nCurrScreen)) && +#endif + CPad::GetPad(0)->GetMouseWheelUpJustDown() && m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) { increase = true; CheckSliderMovement(1); m_bShowMouse = true; } - if (!CPad::GetPad(0)->GetLeftJustDown() && !CPad::GetPad(0)->GetAnaloguePadLeft() && !CPad::GetPad(0)->GetDPadLeftJustDown()) { - if (CPad::GetPad(0)->GetMouseWheelDownJustDown()) { - if (m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) { - decrease = true; - CheckSliderMovement(-1); - m_bShowMouse = true; - } - } - } else { + if (CPad::GetPad(0)->GetLeftJustDown() || CPad::GetPad(0)->GetAnaloguePadLeft() || CPad::GetPad(0)->GetDPadLeftJustDown()) { m_bShowMouse = false; decrease = true; + } else if ( +#ifdef SCROLLABLE_PAGES + !(m_nTotalListRow > MAX_VISIBLE_OPTION && !hasNativeList(m_nCurrScreen)) && +#endif + CPad::GetPad(0)->GetMouseWheelDownJustDown() && m_nCurrScreen != MENUPAGE_KEYBOARD_CONTROLS) { + decrease = true; + CheckSliderMovement(-1); + m_bShowMouse = true; } if (increase) diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 72288f98..21124fdb 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -781,6 +781,7 @@ public: void PageUpList(bool); void PageDownList(bool); int8 GetPreviousPageOption(); + void ProcessList(bool &goBack, bool &optionSelected); }; #ifndef IMPROVED_VIDEOMODE From 546ed0ff07cad63cb07612d8aff8d63213f71ecd Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 11 Nov 2020 09:42:30 +0100 Subject: [PATCH 044/129] changes to RW layer so loading foreign files works --- src/core/FileLoader.cpp | 17 ++++++++ src/core/Streaming.cpp | 1 + src/core/main.cpp | 4 ++ src/fakerw/fake.cpp | 25 ++---------- src/objects/CutsceneHead.cpp | 37 +++++++++++++++++ src/rw/RwHelper.cpp | 77 ++++++++++++++++++++++++++++++++++++ src/rw/RwHelper.h | 2 + vendor/librw | 2 +- 8 files changed, 143 insertions(+), 22 deletions(-) diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index aadafc29..3f731658 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -332,6 +332,16 @@ CFileLoader::FindRelatedModelInfoCB(RpAtomic *atomic, void *data) return atomic; } +#ifdef LIBRW +void +InitClump(RpClump *clump) +{ + RpClumpForAllAtomics(clump, ConvertPlatformAtomic, nil); +} +#else +#define InitClump(clump) +#endif + void CFileLoader::LoadModelFile(const char *filename) { @@ -343,6 +353,7 @@ CFileLoader::LoadModelFile(const char *filename) if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)){ clump = RpClumpStreamRead(stream); if(clump){ + InitClump(clump); RpClumpForAllAtomics(clump, FindRelatedModelInfoCB, clump); RpClumpDestroy(clump); } @@ -368,6 +379,7 @@ CFileLoader::LoadClumpFile(const char *filename) GetNameAndLOD(nodename, name, &n); mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(name, nil); if(mi){ + InitClump(clump); assert(mi->IsClump()); mi->SetClump(clump); }else @@ -393,6 +405,7 @@ CFileLoader::LoadClumpFile(RwStream *stream, uint32 id) if (mi->GetModelType() == MITYPE_PED && id != 0 && RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) { // Read LOD ped clump = RpClumpStreamRead(stream); + InitClump(clump); if(clump){ ((CPedModelInfo*)mi)->SetLowDetailClump(clump); RpClumpDestroy(clump); @@ -423,6 +436,7 @@ CFileLoader::FinishLoadClumpFile(RwStream *stream, uint32 id) clump = RpClumpGtaStreamRead2(stream); if(clump){ + InitClump(clump); mi = (CClumpModelInfo*)CModelInfo::GetModelInfo(id); mi->SetClump(clump); return true; @@ -443,6 +457,7 @@ CFileLoader::LoadAtomicFile(RwStream *stream, uint32 id) clump = RpClumpStreamRead(stream); if(clump == nil) return false; + InitClump(clump); gpRelatedModelInfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(id); RpClumpForAllAtomics(clump, SetRelatedModelInfoCB, clump); RpClumpDestroy(clump); @@ -806,6 +821,8 @@ CFileLoader::LoadAtomicFile2Return(const char *filename) stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, filename); if(RwStreamFindChunk(stream, rwID_CLUMP, nil, nil)) clump = RpClumpStreamRead(stream); + if(clump) + InitClump(clump); RwStreamClose(stream, nil); return clump; } diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index 3c5689fd..4f721f17 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -390,6 +390,7 @@ CStreaming::LoadCdDirectory(const char *dirname, int n) assert(sizeof(direntry) == 32); while(CFileMgr::Read(fd, (char*)&direntry, sizeof(direntry))){ dot = strchr(direntry.name, '.'); + assert(dot); if(dot) *dot = '\0'; if(direntry.size > (uint32)ms_streamingBufferSize) ms_streamingBufferSize = direntry.size; diff --git a/src/core/main.cpp b/src/core/main.cpp index 2e4b839a..cd234588 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -89,7 +89,11 @@ RwRGBA gColourTop; bool gameAlreadyInitialised; float NumberOfChunksLoaded; +#ifdef GTA_PS2 +#define TOTALNUMCHUNKS 48.0f +#else #define TOTALNUMCHUNKS 73.0f +#endif bool g_SlowMode = false; char version_name[64]; diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 58b3277a..64e59375 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -294,32 +294,12 @@ RwTextureAddressMode RwTextureGetAddressingV(const RwTexture *texture); // TODO void _rwD3D8TexDictionaryEnableRasterFormatConversion(bool enable) { } -static rw::Raster* -ConvertTexRaster(rw::Raster *ras) -{ - using namespace rw; - - if(ras->platform == rw::platform) - return ras; - // compatible platforms - if(ras->platform == PLATFORM_D3D8 && rw::platform == PLATFORM_D3D9 || - ras->platform == PLATFORM_D3D9 && rw::platform == PLATFORM_D3D8) - return ras; - - Image *img = ras->toImage(); - ras->destroy(); - img->unpalettize(); - ras = Raster::createFromImage(img); - img->destroy(); - return ras; -} - // hack for reading native textures RwBool rwNativeTextureHackRead(RwStream *stream, RwTexture **tex, RwInt32 size) { *tex = Texture::streamReadNative(stream); #ifdef LIBRW - (*tex)->raster = ConvertTexRaster((*tex)->raster); + (*tex)->raster = rw::Raster::convertTexToCurrentPlatform((*tex)->raster); #endif return *tex != nil; } @@ -796,6 +776,9 @@ RwBool RpWorldPluginAttach(void) { registerNativeDataPlugin(); registerAtomicRightsPlugin(); registerMaterialRightsPlugin(); + + // not sure if this goes here + rw::xbox::registerVertexFormatPlugin(); return true; } diff --git a/src/objects/CutsceneHead.cpp b/src/objects/CutsceneHead.cpp index 55e75807..15611c29 100644 --- a/src/objects/CutsceneHead.cpp +++ b/src/objects/CutsceneHead.cpp @@ -12,6 +12,10 @@ #include "CutsceneHead.h" #include "CdStream.h" +#ifdef GTA_PS2_STUFF +// this is a total hack to switch between PC and PS2 code +static bool lastLoadedSKA; +#endif CCutsceneHead::CCutsceneHead(CObject *obj) { @@ -87,6 +91,10 @@ CCutsceneHead::ProcessControl(void) assert(RwObjectGetType(m_rwObject) == rpCLUMP); atm = GetFirstAtomic((RpClump*)m_rwObject); hier = RpSkinAtomicGetHAnimHierarchy(atm); +#ifdef GTA_PS2_STUFF + // PS2 only plays anims in cutscene, PC always plays anims + if(!lastLoadedSKA || CCutsceneMgr::IsRunning()) +#endif RpHAnimHierarchyAddAnimTime(hier, CTimer::GetTimeStepNonClipped()/50.0f); } @@ -168,6 +176,10 @@ CCutsceneHead::PlayAnimation(const char *animName) uint32 offset, size; RwStream *stream; +#ifdef GTA_PS2_STUFF + lastLoadedSKA = false; +#endif + assert(RwObjectGetType(m_rwObject) == rpCLUMP); atm = GetFirstAtomic((RpClump*)m_rwObject); hier = RpSkinAtomicGetHAnimHierarchy(atm); @@ -191,4 +203,29 @@ CCutsceneHead::PlayAnimation(const char *animName) RwStreamClose(stream, nil); } +#ifdef GTA_PS2_STUFF +#ifdef LIBRW + else{ + sprintf(gString, "%s.ska", animName); + + if(CCutsceneMgr::ms_pCutsceneDir->FindItem(gString, offset, size)){ + stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, "ANIM\\CUTS.IMG"); + assert(stream); + + CStreaming::MakeSpaceFor(size * CDSTREAM_SECTOR_SIZE); + CStreaming::ImGonnaUseStreamingMemory(); + + RwStreamSkip(stream, offset*2048); + anim = rw::Animation::streamReadLegacy(stream); + RpHAnimHierarchySetCurrentAnim(hier, anim); + + CStreaming::IHaveUsedStreamingMemory(); + + RwStreamClose(stream, nil); + + lastLoadedSKA = true; + } + } +#endif +#endif } diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index 35af1ebd..0069934f 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -649,6 +649,83 @@ WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); } WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); } #endif +#ifdef LIBRW +#include +#include "VehicleModelInfo.h" + +int32 +findPlatform(rw::Atomic *a) +{ + rw::Geometry *g = a->geometry; + if(g->instData) + return g->instData->platform; + return 0; +} + +// in CVehicleModelInfo in VC +static RpMaterial* +GetMatFXEffectMaterialCB(RpMaterial *material, void *data) +{ + if(RpMatFXMaterialGetEffects(material) == rpMATFXEFFECTNULL) + return material; + *(int*)data = RpMatFXMaterialGetEffects(material); + return nil; +} + +// Game doesn't read atomic extensions so we never get any other than the default pipe, +// but we need it for uninstancing +void +attachPipe(rw::Atomic *atomic) +{ + if(RpSkinGeometryGetSkin(RpAtomicGetGeometry(atomic))) + atomic->pipeline = rw::skinGlobals.pipelines[rw::platform]; + else{ + int fx = rpMATFXEFFECTNULL; + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), GetMatFXEffectMaterialCB, &fx); + if(fx != rpMATFXEFFECTNULL) + RpMatFXAtomicEnableEffects(atomic); + } +} + +// Attach pipes for the platform we have native data for so we can uninstance +void +switchPipes(rw::Atomic *a, int32 platform) +{ + if(a->pipeline && a->pipeline->platform != platform){ + uint32 plgid = a->pipeline->pluginID; + switch(plgid){ + // assume default pipe won't be attached explicitly + case rw::ID_SKIN: + a->pipeline = rw::skinGlobals.pipelines[platform]; + break; + case rw::ID_MATFX: + a->pipeline = rw::matFXGlobals.pipelines[platform]; + break; + } + } +} + +RpAtomic* +ConvertPlatformAtomic(RpAtomic *atomic, void *data) +{ + int32 driver = rw::platform; + int32 platform = findPlatform(atomic); + if(platform != 0 && platform != driver){ + attachPipe(atomic); // kludge + rw::ObjPipeline *origPipe = atomic->pipeline; + rw::platform = platform; + switchPipes(atomic, rw::platform); + if(atomic->geometry->flags & rw::Geometry::NATIVE) + atomic->uninstance(); + // no ADC in this game + //rw::ps2::unconvertADC(atomic->geometry); + rw::platform = driver; + atomic->pipeline = origPipe; + } + return atomic; +} +#endif + #if defined(FIX_BUGS) && defined(GTA_PC) RwUInt32 saved_alphafunc, saved_alpharef; diff --git a/src/rw/RwHelper.h b/src/rw/RwHelper.h index 130eb636..523a7732 100644 --- a/src/rw/RwHelper.h +++ b/src/rw/RwHelper.h @@ -56,6 +56,8 @@ RwCamera *CameraCreate(RwInt32 width, void _TexturePoolsInitialise(); void _TexturePoolsShutdown(); +RpAtomic *ConvertPlatformAtomic(RpAtomic *atomic, void *data); + #if defined(FIX_BUGS) && defined (GTA_PC) void SetAlphaTest(RwUInt32 alpharef); void RestoreAlphaTest(); diff --git a/vendor/librw b/vendor/librw index 8c00f787..7e80d45c 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit 8c00f787cb8f53781c4335ecbc9d28fb9c664ba7 +Subproject commit 7e80d45cdb6663f97d89ed443198ce6e37c4435e From 67e57d136862ea7823ca3c7b256214b92d738af6 Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 11 Nov 2020 13:08:22 +0300 Subject: [PATCH 045/129] Fix RestoreDef crash --- src/core/MenuScreensCustom.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index b92d5325..d3d7474d 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -91,7 +91,7 @@ void RestoreDefGraphics(int8 action) { FrontEndMenuManager.m_nPrefsMSAALevel = FrontEndMenuManager.m_nDisplayMSAALevel = 0; #endif #ifdef NO_ISLAND_LOADING - if (FrontEndMenuManager.m_bGameNotLoaded) { + if (!FrontEndMenuManager.m_bGameNotLoaded) { FrontEndMenuManager.m_PrefsIslandLoading = FrontEndMenuManager.ISLAND_LOADING_LOW; CCollision::bAlreadyLoaded = false; CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); From feeab0b74afa63376e51b1869f6e4a17fec9a420 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Wed, 11 Nov 2020 20:57:44 +0200 Subject: [PATCH 046/129] Fix ini reader --- src/core/re3.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 6bf5573e..4783e513 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -86,7 +86,8 @@ CustomFrontendOptionsPopulate(void) linb::ini cfg; int CheckAndReadIniInt(const char *cat, const char *key, int original) { - const char *value = (cfg.get(cat, key, "").c_str()); + std::string strval = cfg.get(cat, key, ""); + const char *value = strval.c_str(); if (value && value[0] != '\0') return atoi(value); @@ -95,7 +96,8 @@ int CheckAndReadIniInt(const char *cat, const char *key, int original) float CheckAndReadIniFloat(const char *cat, const char *key, float original) { - const char *value = (cfg.get(cat, key, "").c_str()); + std::string strval = cfg.get(cat, key, ""); + const char *value = strval.c_str(); if (value && value[0] != '\0') return atof(value); From 8374a346e52b99552228e80726305376c1853952 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Fri, 13 Nov 2020 18:28:15 +0200 Subject: [PATCH 047/129] Fix loading island LODs with big buildings --- src/core/Streaming.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index 4f721f17..e9a7af88 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -742,7 +742,9 @@ CStreaming::RequestBigBuildings(eLevelName level) b = CPools::GetBuildingPool()->GetSlot(i); if(b && b->bIsBIGBuilding #ifdef NO_ISLAND_LOADING - && ((CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_LOW) || (b->m_level == level)) + && (((CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_LOW) && (b != pIslandLODindustEntity) && (b != pIslandLODcomIndEntity) && + (b != pIslandLODcomSubEntity) && (b != pIslandLODsubIndEntity) && (b != pIslandLODsubComEntity) + ) || (b->m_level == level)) #else && b->m_level == level #endif From a6f5f4634c63a515196a0f650682953356cb8e18 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 14 Nov 2020 22:13:32 +0200 Subject: [PATCH 048/129] Make collision code placement more like original (+ small fixes) --- premake5.lua | 2 + src/CMakeLists.txt | 1 + src/collision/ColBox.cpp | 21 + src/collision/ColBox.h | 16 + src/collision/ColLine.cpp | 9 + src/collision/ColLine.h | 14 + src/collision/ColModel.cpp | 184 +++++++ src/collision/ColModel.h | 37 ++ src/collision/ColPoint.cpp | 16 + src/collision/ColPoint.h | 34 ++ src/collision/ColSphere.cpp | 11 + src/collision/ColSphere.h | 13 + src/collision/ColTriangle.cpp | 41 ++ src/collision/ColTriangle.h | 68 +++ src/{core => collision}/Collision.cpp | 568 +--------------------- src/collision/Collision.h | 70 +++ src/collision/CompressedVector.h | 36 ++ src/{core => collision}/TempColModels.cpp | 53 +- src/{core => collision}/TempColModels.h | 0 src/collision/VuCollision.cpp | 282 +++++++++++ src/collision/VuCollision.h | 32 ++ src/{core => collision}/vu0Collision.dsm | 0 src/{core => collision}/vu0Collision_1.s | 0 src/{core => collision}/vu0Collision_2.s | 0 src/core/Collision.h | 254 ---------- src/entities/Physical.cpp | 24 +- 26 files changed, 932 insertions(+), 854 deletions(-) create mode 100644 src/collision/ColBox.cpp create mode 100644 src/collision/ColBox.h create mode 100644 src/collision/ColLine.cpp create mode 100644 src/collision/ColLine.h create mode 100644 src/collision/ColModel.cpp create mode 100644 src/collision/ColModel.h create mode 100644 src/collision/ColPoint.cpp create mode 100644 src/collision/ColPoint.h create mode 100644 src/collision/ColSphere.cpp create mode 100644 src/collision/ColSphere.h create mode 100644 src/collision/ColTriangle.cpp create mode 100644 src/collision/ColTriangle.h rename src/{core => collision}/Collision.cpp (86%) create mode 100644 src/collision/Collision.h create mode 100644 src/collision/CompressedVector.h rename src/{core => collision}/TempColModels.cpp (89%) rename src/{core => collision}/TempColModels.h (100%) create mode 100644 src/collision/VuCollision.cpp create mode 100644 src/collision/VuCollision.h rename src/{core => collision}/vu0Collision.dsm (100%) rename src/{core => collision}/vu0Collision_1.s (100%) rename src/{core => collision}/vu0Collision_2.s (100%) delete mode 100644 src/core/Collision.h diff --git a/premake5.lua b/premake5.lua index b8ab1491..4e4417bf 100644 --- a/premake5.lua +++ b/premake5.lua @@ -231,6 +231,7 @@ project "re3" files { addSrcFiles("src/audio") } files { addSrcFiles("src/audio/eax") } files { addSrcFiles("src/audio/oal") } + files { addSrcFiles("src/collision") } files { addSrcFiles("src/control") } files { addSrcFiles("src/core") } files { addSrcFiles("src/entities") } @@ -253,6 +254,7 @@ project "re3" includedirs { "src/audio" } includedirs { "src/audio/eax" } includedirs { "src/audio/oal" } + includedirs { "src/collision" } includedirs { "src/control" } includedirs { "src/core" } includedirs { "src/entities" } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eca69d30..ef322a9a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,6 +13,7 @@ MACRO(HEADER_DIRECTORIES return_list) FILE(GLOB_RECURSE new_list *.cpp) SET(dir_list "animation" "audio" + "collision" "control" "core" "entities" diff --git a/src/collision/ColBox.cpp b/src/collision/ColBox.cpp new file mode 100644 index 00000000..53cba88b --- /dev/null +++ b/src/collision/ColBox.cpp @@ -0,0 +1,21 @@ +#include "common.h" +#include "ColBox.h" + +void +CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) +{ + this->min = min; + this->max = max; + this->surface = surf; + this->piece = piece; +} + +CColBox& +CColBox::operator=(const CColBox& other) +{ + min = other.min; + max = other.max; + surface = other.surface; + piece = other.piece; + return *this; +} \ No newline at end of file diff --git a/src/collision/ColBox.h b/src/collision/ColBox.h new file mode 100644 index 00000000..ac2cd675 --- /dev/null +++ b/src/collision/ColBox.h @@ -0,0 +1,16 @@ +#pragma once + +#include "SurfaceTable.h" + +struct CColBox +{ + CVector min; + CVector max; + uint8 surface; + uint8 piece; + + void Set(const CVector &min, const CVector &max, uint8 surf = SURFACE_DEFAULT, uint8 piece = 0); + CVector GetSize(void) { return max - min; } + + CColBox& operator=(const CColBox &other); +}; \ No newline at end of file diff --git a/src/collision/ColLine.cpp b/src/collision/ColLine.cpp new file mode 100644 index 00000000..c6247449 --- /dev/null +++ b/src/collision/ColLine.cpp @@ -0,0 +1,9 @@ +#include "common.h" +#include "ColLine.h" + +void +CColLine::Set(const CVector &p0, const CVector &p1) +{ + this->p0 = p0; + this->p1 = p1; +} \ No newline at end of file diff --git a/src/collision/ColLine.h b/src/collision/ColLine.h new file mode 100644 index 00000000..21587a06 --- /dev/null +++ b/src/collision/ColLine.h @@ -0,0 +1,14 @@ +#pragma once + +struct CColLine +{ + // NB: this has to be compatible with two CVuVectors + CVector p0; + int pad0; + CVector p1; + int pad1; + + CColLine(void) { }; + CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; }; + void Set(const CVector &p0, const CVector &p1); +}; \ No newline at end of file diff --git a/src/collision/ColModel.cpp b/src/collision/ColModel.cpp new file mode 100644 index 00000000..650e6958 --- /dev/null +++ b/src/collision/ColModel.cpp @@ -0,0 +1,184 @@ +#include "common.h" +#include "ColModel.h" +#include "Game.h" + +CColModel::CColModel(void) +{ + numSpheres = 0; + spheres = nil; + numLines = 0; + lines = nil; + numBoxes = 0; + boxes = nil; + numTriangles = 0; + vertices = nil; + triangles = nil; + trianglePlanes = nil; + level = CGame::currLevel; + ownsCollisionVolumes = true; +} + +CColModel::~CColModel(void) +{ + RemoveCollisionVolumes(); + RemoveTrianglePlanes(); +} + +void +CColModel::RemoveCollisionVolumes(void) +{ + if(ownsCollisionVolumes){ + RwFree(spheres); + RwFree(lines); + RwFree(boxes); + RwFree(vertices); + RwFree(triangles); + } + numSpheres = 0; + numLines = 0; + numBoxes = 0; + numTriangles = 0; + spheres = nil; + lines = nil; + boxes = nil; + vertices = nil; + triangles = nil; +} + +void +CColModel::CalculateTrianglePlanes(void) +{ + // HACK: allocate space for one more element to stuff the link pointer into + trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); + for(int i = 0; i < numTriangles; i++) + trianglePlanes[i].Set(vertices, triangles[i]); +} + +void +CColModel::RemoveTrianglePlanes(void) +{ + RwFree(trianglePlanes); + trianglePlanes = nil; +} + +void +CColModel::SetLinkPtr(CLink *lptr) +{ + assert(trianglePlanes); + *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; +} + +CLink* +CColModel::GetLinkPtr(void) +{ + assert(trianglePlanes); + return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); +} + +void +CColModel::GetTrianglePoint(CVector &v, int i) const +{ + v = vertices[i].Get(); +} + +CColModel& +CColModel::operator=(const CColModel &other) +{ + int i; + int numVerts; + + boundingSphere = other.boundingSphere; + boundingBox = other.boundingBox; + + // copy spheres + if(other.numSpheres){ + if(numSpheres != other.numSpheres){ + numSpheres = other.numSpheres; + if(spheres) + RwFree(spheres); + spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); + } + for(i = 0; i < numSpheres; i++) + spheres[i] = other.spheres[i]; + }else{ + numSpheres = 0; + if(spheres) + RwFree(spheres); + spheres = nil; + } + + // copy lines + if(other.numLines){ + if(numLines != other.numLines){ + numLines = other.numLines; + if(lines) + RwFree(lines); + lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); + } + for(i = 0; i < numLines; i++) + lines[i] = other.lines[i]; + }else{ + numLines = 0; + if(lines) + RwFree(lines); + lines = nil; + } + + // copy boxes + if(other.numBoxes){ + if(numBoxes != other.numBoxes){ + numBoxes = other.numBoxes; + if(boxes) + RwFree(boxes); + boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); + } + for(i = 0; i < numBoxes; i++) + boxes[i] = other.boxes[i]; + }else{ + numBoxes = 0; + if(boxes) + RwFree(boxes); + boxes = nil; + } + + // copy mesh + if(other.numTriangles){ + // copy vertices + numVerts = 0; + for(i = 0; i < other.numTriangles; i++){ + if(other.triangles[i].a > numVerts) + numVerts = other.triangles[i].a; + if(other.triangles[i].b > numVerts) + numVerts = other.triangles[i].b; + if(other.triangles[i].c > numVerts) + numVerts = other.triangles[i].c; + } + numVerts++; + if(vertices) + RwFree(vertices); + if(numVerts){ + vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector)); + for(i = 0; i < numVerts; i++) + vertices[i] = other.vertices[i]; + } + + // copy triangles + if(numTriangles != other.numTriangles){ + numTriangles = other.numTriangles; + if(triangles) + RwFree(triangles); + triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); + } + for(i = 0; i < numTriangles; i++) + triangles[i] = other.triangles[i]; + }else{ + numTriangles = 0; + if(triangles) + RwFree(triangles); + triangles = nil; + if(vertices) + RwFree(vertices); + vertices = nil; + } + return *this; +} diff --git a/src/collision/ColModel.h b/src/collision/ColModel.h new file mode 100644 index 00000000..7dcdfa4d --- /dev/null +++ b/src/collision/ColModel.h @@ -0,0 +1,37 @@ +#pragma once + +#include "templates.h" +#include "ColBox.h" +#include "ColSphere.h" +#include "ColLine.h" +#include "ColPoint.h" +#include "ColTriangle.h" + +struct CColModel +{ + CColSphere boundingSphere; + CColBox boundingBox; + int16 numSpheres; + int16 numLines; + int16 numBoxes; + int16 numTriangles; + int32 level; + bool ownsCollisionVolumes; // missing on PS2 + CColSphere *spheres; + CColLine *lines; + CColBox *boxes; + CompressedVector *vertices; + CColTriangle *triangles; + CColTrianglePlane *trianglePlanes; + + CColModel(void); + ~CColModel(void); + void RemoveCollisionVolumes(void); + void CalculateTrianglePlanes(void); + void RemoveTrianglePlanes(void); + CLink *GetLinkPtr(void); + void SetLinkPtr(CLink*); + void GetTrianglePoint(CVector &v, int i) const; + + CColModel& operator=(const CColModel& other); +}; \ No newline at end of file diff --git a/src/collision/ColPoint.cpp b/src/collision/ColPoint.cpp new file mode 100644 index 00000000..fbf9e8c3 --- /dev/null +++ b/src/collision/ColPoint.cpp @@ -0,0 +1,16 @@ +#include "common.h" +#include "ColPoint.h" + +CColPoint& +CColPoint::operator=(const CColPoint &other) +{ + point = other.point; + normal = other.normal; + surfaceA = other.surfaceA; + pieceA = other.pieceA; + surfaceB = other.surfaceB; + pieceB = other.pieceB; + + // no depth? + return *this; +} diff --git a/src/collision/ColPoint.h b/src/collision/ColPoint.h new file mode 100644 index 00000000..a15b2345 --- /dev/null +++ b/src/collision/ColPoint.h @@ -0,0 +1,34 @@ +#pragma once + +struct CColPoint +{ + CVector point; + int pad1; + // the surface normal on the surface of point + CVector normal; + int pad2; + uint8 surfaceA; + uint8 pieceA; + uint8 surfaceB; + uint8 pieceB; + float depth; + + const CVector &GetNormal() { return normal; } + float GetDepth() { return depth; } + void Set(float depth, uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { + this->depth = depth; + this->surfaceA = surfA; + this->pieceA = pieceA; + this->surfaceB = surfB; + this->pieceB = pieceB; + } + void Set(uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { + this->surfaceA = surfA; + this->pieceA = pieceA; + this->surfaceB = surfB; + this->pieceB = pieceB; + } + + CColPoint &operator=(const CColPoint &other); +}; + diff --git a/src/collision/ColSphere.cpp b/src/collision/ColSphere.cpp new file mode 100644 index 00000000..9aac01e0 --- /dev/null +++ b/src/collision/ColSphere.cpp @@ -0,0 +1,11 @@ +#include "common.h" +#include "ColSphere.h" + +void +CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) +{ + this->radius = radius; + this->center = center; + this->surface = surf; + this->piece = piece; +} \ No newline at end of file diff --git a/src/collision/ColSphere.h b/src/collision/ColSphere.h new file mode 100644 index 00000000..70e29763 --- /dev/null +++ b/src/collision/ColSphere.h @@ -0,0 +1,13 @@ +#pragma once + +#include "SurfaceTable.h" + +struct CColSphere +{ + // NB: this has to be compatible with a CVuVector + CVector center; + float radius; + uint8 surface; + uint8 piece; + void Set(float radius, const CVector ¢er, uint8 surf = SURFACE_DEFAULT, uint8 piece = 0); +}; \ No newline at end of file diff --git a/src/collision/ColTriangle.cpp b/src/collision/ColTriangle.cpp new file mode 100644 index 00000000..9120fcff --- /dev/null +++ b/src/collision/ColTriangle.cpp @@ -0,0 +1,41 @@ +#include "common.h" +#include "ColTriangle.h" + +void +CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece) +{ + this->a = a; + this->b = b; + this->c = c; + this->surface = surf; +} + +#ifdef VU_COLLISION +void +CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) +{ + CVector norm = CrossProduct(vc-va, vb-va); + norm.Normalise(); + float d = DotProduct(norm, va); + normal.x = norm.x*4096.0f; + normal.y = norm.y*4096.0f; + normal.z = norm.z*4096.0f; + dist = d*128.0f; +} +#else +void +CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) +{ + normal = CrossProduct(vc-va, vb-va); + normal.Normalise(); + dist = DotProduct(normal, va); + CVector an(Abs(normal.x), Abs(normal.y), Abs(normal.z)); + // find out largest component and its direction + if(an.x > an.y && an.x > an.z) + dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; + else if(an.y > an.z) + dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; + else + dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; +} +#endif \ No newline at end of file diff --git a/src/collision/ColTriangle.h b/src/collision/ColTriangle.h new file mode 100644 index 00000000..9e918e38 --- /dev/null +++ b/src/collision/ColTriangle.h @@ -0,0 +1,68 @@ +#pragma once + +#include "CompressedVector.h" + +enum Direction { + DIR_X_POS, + DIR_X_NEG, + DIR_Y_POS, + DIR_Y_NEG, + DIR_Z_POS, + DIR_Z_NEG, +}; + +struct CColTriangle +{ + uint16 a; + uint16 b; + uint16 c; + uint8 surface; + + void Set(const CompressedVector *v, int a, int b, int c, uint8 surf, uint8 piece); +}; + +struct CColTrianglePlane +{ +#ifdef VU_COLLISION + CompressedVector normal; + int16 dist; + + void Set(const CVector &va, const CVector &vb, const CVector &vc); + void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } + void GetNormal(CVector &n) const { n.x = normal.x/4096.0f; n.y = normal.y/4096.0f; n.z = normal.z/4096.0f; } + float CalcPoint(const CVector &v) const { CVector n; GetNormal(n); return DotProduct(n, v) - dist/128.0f; }; +#ifdef GTA_PS2 + void Unpack(uint128 &qword) const { + __asm__ volatile ( + "lh $8, 0(%1)\n" + "lh $9, 2(%1)\n" + "lh $10, 4(%1)\n" + "lh $11, 6(%1)\n" + "pextlw $10, $8\n" + "pextlw $11, $9\n" + "pextlw $2, $11, $10\n" + "sq $2, %0\n" + : "=m" (qword) + : "r" (this) + : "$8", "$9", "$10", "$11", "$2" + ); + } +#else + void Unpack(int32 *qword) const { + qword[0] = normal.x; + qword[1] = normal.y; + qword[2] = normal.z; + qword[3] = dist; + } +#endif +#else + CVector normal; + float dist; + uint8 dir; + + void Set(const CVector &va, const CVector &vb, const CVector &vc); + void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } + void GetNormal(CVector &n) const { n = normal; } + float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; +#endif +}; \ No newline at end of file diff --git a/src/core/Collision.cpp b/src/collision/Collision.cpp similarity index 86% rename from src/core/Collision.cpp rename to src/collision/Collision.cpp index d8603cd8..41997e32 100644 --- a/src/core/Collision.cpp +++ b/src/collision/Collision.cpp @@ -23,303 +23,8 @@ #include "Collision.h" #include "Frontend.h" - -// TODO: where do these go? - #ifdef VU_COLLISION - -struct VuTriangle -{ - // Compressed int16 but unpacked -#ifdef GTA_PS2 - uint128 v0; - uint128 v1; - uint128 v2; - uint128 plane; -#else - int32 v0[4]; - int32 v1[4]; - int32 v2[4]; - int32 plane[4]; -#endif -}; - -#ifndef GTA_PS2 -static int16 vi01; -static CVuVector vf01; -static CVuVector vf02; -static CVuVector vf03; - -CVuVector -DistanceBetweenSphereAndLine(const CVuVector ¢er, const CVuVector &p0, const CVuVector &line) -{ - // center VF12 - // p0 VF14 - // line VF15 - CVuVector ret; // VF16 - CVuVector p1 = p0+line; - CVuVector dist0 = center - p0; // VF20 - CVuVector dist1 = center - p1; // VF25 - float lenSq = line.MagnitudeSqr(); // VF21 - float distSq0 = dist0.MagnitudeSqr(); // VF22 - float distSq1 = dist1.MagnitudeSqr(); - float dot = DotProduct(dist0, line); // VF23 - if(dot < 0.0f){ - // not above line, closest to p0 - ret = p0; - ret.w = distSq0; - return ret; - } - float t = dot/lenSq; // param of nearest point on infinite line - if(t > 1.0f){ - // not above line, closest to p1 - ret = p1; - ret.w = distSq1; - return ret; - } - // closest to line - ret = p0 + line*t; - ret.w = (ret - center).MagnitudeSqr(); - return ret; -} -inline int SignFlags(const CVector &v) -{ - int f = 0; - if(v.x < 0.0f) f |= 1; - if(v.y < 0.0f) f |= 2; - if(v.z < 0.0f) f |= 4; - return f; -} -#endif - -extern "C" void -LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, - const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, - const CVuVector &plane) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf13, 0x0(%1)\n" - "lqc2 vf14, 0x0(%2)\n" - "lqc2 vf15, 0x0(%3)\n" - "lqc2 vf16, 0x0(%4)\n" - "lqc2 vf17, 0x0(%5)\n" - "vcallms Vu0LineToTriangleCollisionStart\n" - ".set reorder\n" - : - : "r" (&p0), "r" (&p1), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) - ); -#else - float dot0 = DotProduct(plane, p0); - float dot1 = DotProduct(plane, p1); - float dist0 = plane.w - dot0; - float dist1 = plane.w - dot1; - - // if points are on the same side, no collision - if(dist0 * dist1 > 0.0f){ - vi01 = 0; - return; - } - - CVuVector diff = p1 - p0; - float t = dist0/(dot1 - dot0); - CVuVector p = p0 + diff*t; - p.w = 0.0f; - vf01 = p; - vf03.x = t; - - // Check if point is inside - CVector cross1 = CrossProduct(p-v0, v1-v0); - CVector cross2 = CrossProduct(p-v1, v2-v1); - CVector cross3 = CrossProduct(p-v2, v0-v2); - // Only check relevant directions - int flagmask = 0; - if(Abs(plane.x) > 0.5f) flagmask |= 1; - if(Abs(plane.y) > 0.5f) flagmask |= 2; - if(Abs(plane.z) > 0.5f) flagmask |= 4; - int flags1 = SignFlags(cross1) & flagmask; - int flags2 = SignFlags(cross2) & flagmask; - int flags3 = SignFlags(cross3) & flagmask; - // inside if on the same side of all edges - if(flags1 != flags2 || flags1 != flags3){ - vi01 = 0; - return; - } - vi01 = 1; - vf02 = plane; - return; -#endif -} - -extern "C" void -LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf13, 0x0(%1)\n" - "lqc2 vf14, 0x0(%2)\n" - "lqc2 vf15, 0x10(%2)\n" - "lqc2 vf16, 0x20(%2)\n" - "lqc2 vf17, 0x30(%2)\n" - "vcallms Vu0LineToTriangleCollisionCompressedStart\n" - ".set reorder\n" - : - : "r" (&p0), "r" (&p1), "r" (&tri) - ); -#else - CVuVector v0, v1, v2, plane; - v0.x = tri.v0[0]/128.0f; - v0.y = tri.v0[1]/128.0f; - v0.z = tri.v0[2]/128.0f; - v0.w = tri.v0[3]/128.0f; - v1.x = tri.v1[0]/128.0f; - v1.y = tri.v1[1]/128.0f; - v1.z = tri.v1[2]/128.0f; - v1.w = tri.v1[3]/128.0f; - v2.x = tri.v2[0]/128.0f; - v2.y = tri.v2[1]/128.0f; - v2.z = tri.v2[2]/128.0f; - v2.w = tri.v2[3]/128.0f; - plane.x = tri.plane[0]/4096.0f; - plane.y = tri.plane[1]/4096.0f; - plane.z = tri.plane[2]/4096.0f; - plane.w = tri.plane[3]/128.0f; - LineToTriangleCollision(p0, p1, v0, v1, v2, plane); -#endif -} - -extern "C" void -SphereToTriangleCollision(const CVuVector &sph, - const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, - const CVuVector &plane) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf14, 0x0(%1)\n" - "lqc2 vf15, 0x0(%2)\n" - "lqc2 vf16, 0x0(%3)\n" - "lqc2 vf17, 0x0(%4)\n" - "vcallms Vu0SphereToTriangleCollisionStart\n" - ".set reorder\n" - : - : "r" (&sph), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) - ); -#else - float planedist = DotProduct(plane, sph) - plane.w; // VF02 - if(Abs(planedist) > sph.w){ - vi01 = 0; - return; - } - // point on plane - CVuVector p = sph - planedist*plane; - p.w = 0.0f; - vf01 = p; - planedist = Abs(planedist); - // edges - CVuVector v01 = v1 - v0; - CVuVector v12 = v2 - v1; - CVuVector v20 = v0 - v2; - // VU code calculates normal again for some weird reason... - // Check sides of point - CVector cross1 = CrossProduct(p-v0, v01); - CVector cross2 = CrossProduct(p-v1, v12); - CVector cross3 = CrossProduct(p-v2, v20); - // Only check relevant directions - int flagmask = 0; - if(Abs(plane.x) > 0.1f) flagmask |= 1; - if(Abs(plane.y) > 0.1f) flagmask |= 2; - if(Abs(plane.z) > 0.1f) flagmask |= 4; - int nflags = SignFlags(plane) & flagmask; - int flags1 = SignFlags(cross1) & flagmask; - int flags2 = SignFlags(cross2) & flagmask; - int flags3 = SignFlags(cross3) & flagmask; - int testcase = 0; - CVuVector closest(0.0f, 0.0f, 0.0f); // VF04 - if(flags1 == nflags){ - closest += v2; - testcase++; - } - if(flags2 == nflags){ - closest += v0; - testcase++; - } - if(flags3 == nflags){ - closest += v1; - testcase++; - } - if(testcase == 3){ - // inside triangle - dist to plane already checked - vf02 = plane; - vf02.w = vf03.x = planedist; - vi01 = 1; - }else if(testcase == 1){ - // outside two sides - closest to point opposide inside edge - vf01 = closest; - vf02 = sph - closest; - float distSq = vf02.MagnitudeSqr(); - vi01 = sph.w*sph.w > distSq; - vf03.x = Sqrt(distSq); - vf02 *= 1.0f/vf03.x; - }else{ - // inside two sides - closest to third edge - if(flags1 != nflags) - closest = DistanceBetweenSphereAndLine(sph, v0, v01); - else if(flags2 != nflags) - closest = DistanceBetweenSphereAndLine(sph, v1, v12); - else - closest = DistanceBetweenSphereAndLine(sph, v2, v20); - vi01 = sph.w*sph.w > closest.w; - vf01 = closest; - vf02 = sph - closest; - vf03.x = Sqrt(closest.w); - vf02 *= 1.0f/vf03.x; - } -#endif -} - -extern "C" void -SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri) -{ -#ifdef GTA_PS2 - __asm__ volatile ( - ".set noreorder\n" - "lqc2 vf12, 0x0(%0)\n" - "lqc2 vf14, 0x0(%1)\n" - "lqc2 vf15, 0x10(%1)\n" - "lqc2 vf16, 0x20(%1)\n" - "lqc2 vf17, 0x30(%1)\n" - "vcallms Vu0SphereToTriangleCollisionCompressedStart\n" - ".set reorder\n" - : - : "r" (&sph), "r" (&tri) - ); -#else - CVuVector v0, v1, v2, plane; - v0.x = tri.v0[0]/128.0f; - v0.y = tri.v0[1]/128.0f; - v0.z = tri.v0[2]/128.0f; - v0.w = tri.v0[3]/128.0f; - v1.x = tri.v1[0]/128.0f; - v1.y = tri.v1[1]/128.0f; - v1.z = tri.v1[2]/128.0f; - v1.w = tri.v1[3]/128.0f; - v2.x = tri.v2[0]/128.0f; - v2.y = tri.v2[1]/128.0f; - v2.z = tri.v2[2]/128.0f; - v2.w = tri.v2[3]/128.0f; - plane.x = tri.plane[0]/4096.0f; - plane.y = tri.plane[1]/4096.0f; - plane.z = tri.plane[2]/4096.0f; - plane.w = tri.plane[3]/128.0f; - SphereToTriangleCollision(sph, v0, v1, v2, plane); -#endif -} +#include "VuCollision.h" inline int GetVUresult(void) @@ -362,17 +67,6 @@ GetVUresult(CVuVector &point, CVuVector &normal, float &dist) #endif - -enum Direction -{ - DIR_X_POS, - DIR_X_NEG, - DIR_Y_POS, - DIR_Y_NEG, - DIR_Z_POS, - DIR_Z_NEG, -}; - eLevelName CCollision::ms_collisionInMemory; CLinkList CCollision::ms_colModelCache; @@ -2412,11 +2106,12 @@ CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, assert(modelA.numLines <= MAXNUMLINES); // From model A space to model B space - Invert(matrixB, matAB); + matAB = Invert(matrixB, matAB); matAB *= matrixA; CColSphere bsphereAB; // bounding sphere of A in B space - bsphereAB.Set(modelA.boundingSphere.radius, matAB * modelA.boundingSphere.center); + bsphereAB.radius = modelA.boundingSphere.radius; + bsphereAB.center = matAB * modelA.boundingSphere.center; if(!TestSphereBox(bsphereAB, modelB.boundingBox)) return 0; // B to A space @@ -2449,7 +2144,8 @@ CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, int numBoxesB = 0; int numTrianglesB = 0; for(i = 0; i < modelB.numSpheres; i++){ - s.Set(modelB.spheres[i].radius, matBA * modelB.spheres[i].center); + s.radius = modelB.spheres[i].radius; + s.center = matBA * modelB.spheres[i].center; if(TestSphereBox(s, modelA.boundingBox)) aSphereIndicesB[numSpheresB++] = i; } @@ -3037,254 +2733,4 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); -} - - -/* - * ColModel code - */ - -void -CColSphere::Set(float radius, const CVector ¢er, uint8 surf, uint8 piece) -{ - this->radius = radius; - this->center = center; - this->surface = surf; - this->piece = piece; -} - -void -CColBox::Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece) -{ - this->min = min; - this->max = max; - this->surface = surf; - this->piece = piece; -} - -void -CColLine::Set(const CVector &p0, const CVector &p1) -{ - this->p0 = p0; - this->p1 = p1; -} - -void -CColTriangle::Set(const CompressedVector *, int a, int b, int c, uint8 surf, uint8 piece) -{ - this->a = a; - this->b = b; - this->c = c; - this->surface = surf; -} - -#ifdef VU_COLLISION -void -CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) -{ - CVector norm = CrossProduct(vc-va, vb-va); - norm.Normalise(); - float d = DotProduct(norm, va); - normal.x = norm.x*4096.0f; - normal.y = norm.y*4096.0f; - normal.z = norm.z*4096.0f; - dist = d*128.0f; -} -#else -void -CColTrianglePlane::Set(const CVector &va, const CVector &vb, const CVector &vc) -{ - normal = CrossProduct(vc-va, vb-va); - normal.Normalise(); - dist = DotProduct(normal, va); - CVector an(Abs(normal.x), Abs(normal.y), Abs(normal.z)); - // find out largest component and its direction - if(an.x > an.y && an.x > an.z) - dir = normal.x < 0.0f ? DIR_X_NEG : DIR_X_POS; - else if(an.y > an.z) - dir = normal.y < 0.0f ? DIR_Y_NEG : DIR_Y_POS; - else - dir = normal.z < 0.0f ? DIR_Z_NEG : DIR_Z_POS; -} -#endif - -CColModel::CColModel(void) -{ - numSpheres = 0; - spheres = nil; - numLines = 0; - lines = nil; - numBoxes = 0; - boxes = nil; - numTriangles = 0; - vertices = nil; - triangles = nil; - trianglePlanes = nil; - level = CGame::currLevel; - ownsCollisionVolumes = true; -} - -CColModel::~CColModel(void) -{ - RemoveCollisionVolumes(); - RemoveTrianglePlanes(); -} - -void -CColModel::RemoveCollisionVolumes(void) -{ - if(ownsCollisionVolumes){ - RwFree(spheres); - RwFree(lines); - RwFree(boxes); - RwFree(vertices); - RwFree(triangles); - } - numSpheres = 0; - numLines = 0; - numBoxes = 0; - numTriangles = 0; - spheres = nil; - lines = nil; - boxes = nil; - vertices = nil; - triangles = nil; -} - -void -CColModel::CalculateTrianglePlanes(void) -{ - // HACK: allocate space for one more element to stuff the link pointer into - trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); - for(int i = 0; i < numTriangles; i++) - trianglePlanes[i].Set(vertices, triangles[i]); -} - -void -CColModel::RemoveTrianglePlanes(void) -{ - RwFree(trianglePlanes); - trianglePlanes = nil; -} - -void -CColModel::SetLinkPtr(CLink *lptr) -{ - assert(trianglePlanes); - *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]) = lptr; -} - -CLink* -CColModel::GetLinkPtr(void) -{ - assert(trianglePlanes); - return *(CLink**)ALIGNPTR(&trianglePlanes[numTriangles]); -} - -void -CColModel::GetTrianglePoint(CVector &v, int i) const -{ - v = vertices[i].Get(); -} - -CColModel& -CColModel::operator=(const CColModel &other) -{ - int i; - int numVerts; - - boundingSphere = other.boundingSphere; - boundingBox = other.boundingBox; - - // copy spheres - if(other.numSpheres){ - if(numSpheres != other.numSpheres){ - numSpheres = other.numSpheres; - if(spheres) - RwFree(spheres); - spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); - } - for(i = 0; i < numSpheres; i++) - spheres[i] = other.spheres[i]; - }else{ - numSpheres = 0; - if(spheres) - RwFree(spheres); - spheres = nil; - } - - // copy lines - if(other.numLines){ - if(numLines != other.numLines){ - numLines = other.numLines; - if(lines) - RwFree(lines); - lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); - } - for(i = 0; i < numLines; i++) - lines[i] = other.lines[i]; - }else{ - numLines = 0; - if(lines) - RwFree(lines); - lines = nil; - } - - // copy boxes - if(other.numBoxes){ - if(numBoxes != other.numBoxes){ - numBoxes = other.numBoxes; - if(boxes) - RwFree(boxes); - boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); - } - for(i = 0; i < numBoxes; i++) - boxes[i] = other.boxes[i]; - }else{ - numBoxes = 0; - if(boxes) - RwFree(boxes); - boxes = nil; - } - - // copy mesh - if(other.numTriangles){ - // copy vertices - numVerts = 0; - for(i = 0; i < other.numTriangles; i++){ - if(other.triangles[i].a > numVerts) - numVerts = other.triangles[i].a; - if(other.triangles[i].b > numVerts) - numVerts = other.triangles[i].b; - if(other.triangles[i].c > numVerts) - numVerts = other.triangles[i].c; - } - numVerts++; - if(vertices) - RwFree(vertices); - if(numVerts){ - vertices = (CompressedVector*)RwMalloc(numVerts*sizeof(CompressedVector)); - for(i = 0; i < numVerts; i++) - vertices[i] = other.vertices[i]; - } - - // copy triangles - if(numTriangles != other.numTriangles){ - numTriangles = other.numTriangles; - if(triangles) - RwFree(triangles); - triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); - } - for(i = 0; i < numTriangles; i++) - triangles[i] = other.triangles[i]; - }else{ - numTriangles = 0; - if(triangles) - RwFree(triangles); - triangles = nil; - if(vertices) - RwFree(vertices); - vertices = nil; - } - return *this; -} +} \ No newline at end of file diff --git a/src/collision/Collision.h b/src/collision/Collision.h new file mode 100644 index 00000000..f4270bc5 --- /dev/null +++ b/src/collision/Collision.h @@ -0,0 +1,70 @@ +#pragma once + +#include "ColModel.h" +#include "Game.h" // for eLevelName +#ifdef VU_COLLISION +#include "VuVector.h" +#endif + +struct CStoredCollPoly +{ +#ifdef VU_COLLISION + CVuVector verts[3]; +#else + CVector verts[3]; +#endif + bool valid; +}; + +// If you spawn many tanks at once, you will see that collisions of two entity exceeds 32. +#if defined(FIX_BUGS) && !defined(SQUEEZE_PERFORMANCE) +#define MAX_COLLISION_POINTS 64 +#else +#define MAX_COLLISION_POINTS 32 +#endif + +class CCollision +{ +public: + static eLevelName ms_collisionInMemory; + static CLinkList ms_colModelCache; +#ifdef NO_ISLAND_LOADING + static bool bAlreadyLoaded; +#endif + + static void Init(void); + static void Shutdown(void); + static void Update(void); + static void LoadCollisionWhenINeedIt(bool changeLevel); + static void SortOutCollisionAfterLoad(void); + static void LoadCollisionScreen(eLevelName level); + static void DrawColModel(const CMatrix &mat, const CColModel &colModel); + static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); + + static void CalculateTrianglePlanes(CColModel *model); + + // all these return true if there's a collision + static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); + static bool TestSphereBox(const CColSphere &sph, const CColBox &box); + static bool TestLineBox(const CColLine &line, const CColBox &box); + static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); + static bool TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineSphere(const CColLine &line, const CColSphere &sph); + static bool TestSphereTriangle(const CColSphere &sphere, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); + static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough); + + static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); + static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); + static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); + static bool ProcessVerticalLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); + static bool ProcessLineTriangle(const CColLine &line , const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); + static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); + static bool ProcessSphereTriangle(const CColSphere &sph, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); + static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); + static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); + static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); + static bool IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly); + + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); + static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); +}; diff --git a/src/collision/CompressedVector.h b/src/collision/CompressedVector.h new file mode 100644 index 00000000..d54e49b1 --- /dev/null +++ b/src/collision/CompressedVector.h @@ -0,0 +1,36 @@ +#pragma once + +struct CompressedVector +{ +#ifdef COMPRESSED_COL_VECTORS + int16 x, y, z; + CVector Get(void) const { return CVector(x, y, z)/128.0f; }; + void Set(float x, float y, float z) { this->x = x*128.0f; this->y = y*128.0f; this->z = z*128.0f; }; +#ifdef GTA_PS2 + void Unpack(uint128 &qword) const { + __asm__ volatile ( + "lh $8, 0(%1)\n" + "lh $9, 2(%1)\n" + "lh $10, 4(%1)\n" + "pextlw $10, $8\n" + "pextlw $2, $9, $10\n" + "sq $2, %0\n" + : "=m" (qword) + : "r" (this) + : "$8", "$9", "$10", "$2" + ); + } +#else + void Unpack(int32 *qword) const { + qword[0] = x; + qword[1] = y; + qword[2] = z; + qword[3] = 0; // junk + } +#endif +#else + float x, y, z; + CVector Get(void) const { return CVector(x, y, z); }; + void Set(float x, float y, float z) { this->x = x; this->y = y; this->z = z; }; +#endif +}; \ No newline at end of file diff --git a/src/core/TempColModels.cpp b/src/collision/TempColModels.cpp similarity index 89% rename from src/core/TempColModels.cpp rename to src/collision/TempColModels.cpp index f6796909..849eb01e 100644 --- a/src/core/TempColModels.cpp +++ b/src/collision/TempColModels.cpp @@ -1,7 +1,6 @@ #include "common.h" #include "TempColModels.h" -#include "SurfaceTable.h" CColModel CTempColModels::ms_colModelPed1; CColModel CTempColModels::ms_colModelPed2; @@ -45,13 +44,13 @@ CTempColModels::Initialise(void) int i; - ms_colModelBBox.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBBox.boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f), SURFACE_DEFAULT, 0); + ms_colModelBBox.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelBBox.boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f)); ms_colModelBBox.level = LEVEL_GENERIC; for (i = 0; i < ARRAY_SIZE(ms_colModelCutObj); i++) { - ms_colModelCutObj[i].boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelCutObj[i].boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f), SURFACE_DEFAULT, 0); + ms_colModelCutObj[i].boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelCutObj[i].boundingBox.Set(CVector(-2.0f, -2.0f, -2.0f), CVector(2.0f, 2.0f, 2.0f)); ms_colModelCutObj[i].level = LEVEL_GENERIC; } @@ -73,8 +72,8 @@ CTempColModels::Initialise(void) s_aPedSpheres[i].piece = 0; } - ms_colModelPed1.boundingSphere.Set(1.25f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPed1.boundingBox.Set(CVector(-0.35f, -0.35f, -1.0f), CVector(0.35f, 0.35f, 0.9f), SURFACE_DEFAULT, 0); + ms_colModelPed1.boundingSphere.Set(1.25f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPed1.boundingBox.Set(CVector(-0.35f, -0.35f, -1.0f), CVector(0.35f, 0.35f, 0.9f)); SET_COLMODEL_SPHERES(ms_colModelPed1, s_aPedSpheres); // Ped 2 Spheres @@ -92,8 +91,8 @@ CTempColModels::Initialise(void) s_aPed2Spheres[i].piece = 0; } - ms_colModelPed2.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPed2.boundingBox.Set(CVector(-0.7f, -0.7f, -1.2f), CVector(0.7f, 0.7f, 0.0f), SURFACE_DEFAULT, 0); + ms_colModelPed2.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPed2.boundingBox.Set(CVector(-0.7f, -0.7f, -1.2f), CVector(0.7f, 0.7f, 0.0f)); SET_COLMODEL_SPHERES(ms_colModelPed2, s_aPed2Spheres); @@ -118,8 +117,8 @@ CTempColModels::Initialise(void) s_aPedGSpheres[2].piece = 0; s_aPedGSpheres[3].piece = 6; - ms_colModelPedGroundHit.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPedGroundHit.boundingBox.Set(CVector(-0.4f, -1.0f, -1.25f), CVector(0.4f, 1.2f, -0.5f), SURFACE_DEFAULT, 0); + ms_colModelPedGroundHit.boundingSphere.Set(2.0f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPedGroundHit.boundingBox.Set(CVector(-0.4f, -1.0f, -1.25f), CVector(0.4f, 1.2f, -0.5f)); SET_COLMODEL_SPHERES(ms_colModelPedGroundHit, s_aPedGSpheres); @@ -142,8 +141,8 @@ CTempColModels::Initialise(void) s_aDoorSpheres[i].piece = 0; } - ms_colModelDoor1.boundingSphere.Set(1.5f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelDoor1.boundingBox.Set(CVector(-0.3f, 0.0f, -0.6f), CVector(0.3f, -1.2f, 0.6f), SURFACE_DEFAULT, 0); + ms_colModelDoor1.boundingSphere.Set(1.5f, CVector(0.0f, -0.6f, 0.0f)); + ms_colModelDoor1.boundingBox.Set(CVector(-0.3f, 0.0f, -0.6f), CVector(0.3f, -1.2f, 0.6f)); SET_COLMODEL_SPHERES(ms_colModelDoor1, s_aDoorSpheres); @@ -162,8 +161,8 @@ CTempColModels::Initialise(void) s_aBumperSpheres[i].piece = 0; } - ms_colModelBumper1.boundingSphere.Set(2.2f, CVector(0.0f, -0.6f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBumper1.boundingBox.Set(CVector(-1.2f, -0.3f, -0.2f), CVector(1.2f, 0.3f, 0.2f), SURFACE_DEFAULT, 0); + ms_colModelBumper1.boundingSphere.Set(2.2f, CVector(0.0f, -0.6f, 0.0f)); + ms_colModelBumper1.boundingBox.Set(CVector(-1.2f, -0.3f, -0.2f), CVector(1.2f, 0.3f, 0.2f)); SET_COLMODEL_SPHERES(ms_colModelBumper1, s_aBumperSpheres); @@ -182,8 +181,8 @@ CTempColModels::Initialise(void) s_aPanelSpheres[i].piece = 0; } - ms_colModelPanel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelPanel1.boundingBox.Set(CVector(-0.3f, -0.6f, -0.15f), CVector(0.3f, 0.6f, 0.15f), SURFACE_DEFAULT, 0); + ms_colModelPanel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelPanel1.boundingBox.Set(CVector(-0.3f, -0.6f, -0.15f), CVector(0.3f, 0.6f, 0.15f)); SET_COLMODEL_SPHERES(ms_colModelPanel1, s_aPanelSpheres); @@ -202,8 +201,8 @@ CTempColModels::Initialise(void) s_aBonnetSpheres[i].piece = 0; } - ms_colModelBonnet1.boundingSphere.Set(1.7f, CVector(0.0f, 0.5f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBonnet1.boundingBox.Set(CVector(-0.7f, -0.2f, -0.3f), CVector(0.7f, 1.2f, 0.3f), SURFACE_DEFAULT, 0); + ms_colModelBonnet1.boundingSphere.Set(1.7f, CVector(0.0f, 0.5f, 0.0f)); + ms_colModelBonnet1.boundingBox.Set(CVector(-0.7f, -0.2f, -0.3f), CVector(0.7f, 1.2f, 0.3f)); SET_COLMODEL_SPHERES(ms_colModelBonnet1, s_aBonnetSpheres); @@ -222,8 +221,8 @@ CTempColModels::Initialise(void) s_aBootSpheres[i].piece = 0; } - ms_colModelBoot1.boundingSphere.Set(1.4f, CVector(0.0f, -0.4f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBoot1.boundingBox.Set(CVector(-0.7f, -0.9f, -0.3f), CVector(0.7f, 0.2f, 0.3f), SURFACE_DEFAULT, 0); + ms_colModelBoot1.boundingSphere.Set(1.4f, CVector(0.0f, -0.4f, 0.0f)); + ms_colModelBoot1.boundingBox.Set(CVector(-0.7f, -0.9f, -0.3f), CVector(0.7f, 0.2f, 0.3f)); SET_COLMODEL_SPHERES(ms_colModelBoot1, s_aBootSpheres); @@ -244,8 +243,8 @@ CTempColModels::Initialise(void) s_aWheelSpheres[i].piece = 0; } - ms_colModelWheel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelWheel1.boundingBox.Set(CVector(-0.7f, -0.4f, -0.4f), CVector(0.7f, 0.4f, 0.4f), SURFACE_DEFAULT, 0); + ms_colModelWheel1.boundingSphere.Set(1.4f, CVector(0.0f, 0.0f, 0.0f)); + ms_colModelWheel1.boundingBox.Set(CVector(-0.7f, -0.4f, -0.4f), CVector(0.7f, 0.4f, 0.4f)); SET_COLMODEL_SPHERES(ms_colModelWheel1, s_aWheelSpheres); @@ -266,8 +265,8 @@ CTempColModels::Initialise(void) s_aBodyPartSpheres1[i].piece = 0; } - ms_colModelBodyPart1.boundingSphere.Set(0.7f, CVector(0.4f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBodyPart1.boundingBox.Set(CVector(-0.3f, -0.3f, -0.3f), CVector(1.1f, 0.3f, 0.3f), SURFACE_DEFAULT, 0); + ms_colModelBodyPart1.boundingSphere.Set(0.7f, CVector(0.4f, 0.0f, 0.0f)); + ms_colModelBodyPart1.boundingBox.Set(CVector(-0.3f, -0.3f, -0.3f), CVector(1.1f, 0.3f, 0.3f)); SET_COLMODEL_SPHERES(ms_colModelBodyPart1, s_aBodyPartSpheres1); @@ -288,8 +287,8 @@ CTempColModels::Initialise(void) s_aBodyPartSpheres2[i].piece = 0; } - ms_colModelBodyPart2.boundingSphere.Set(0.5f, CVector(0.25f, 0.0f, 0.0f), SURFACE_DEFAULT, 0); - ms_colModelBodyPart2.boundingBox.Set(CVector(-0.2f, -0.2f, -0.2f), CVector(0.7f, 0.2f, 0.2f), SURFACE_DEFAULT, 0); + ms_colModelBodyPart2.boundingSphere.Set(0.5f, CVector(0.25f, 0.0f, 0.0f)); + ms_colModelBodyPart2.boundingBox.Set(CVector(-0.2f, -0.2f, -0.2f), CVector(0.7f, 0.2f, 0.2f)); SET_COLMODEL_SPHERES(ms_colModelBodyPart2, s_aBodyPartSpheres2); diff --git a/src/core/TempColModels.h b/src/collision/TempColModels.h similarity index 100% rename from src/core/TempColModels.h rename to src/collision/TempColModels.h diff --git a/src/collision/VuCollision.cpp b/src/collision/VuCollision.cpp new file mode 100644 index 00000000..8828d2e1 --- /dev/null +++ b/src/collision/VuCollision.cpp @@ -0,0 +1,282 @@ +#include "common.h" +#ifdef VU_COLLISION +#include "VuVector.h" +#include "VuCollision.h" + +#ifndef GTA_PS2 +int16 vi01; +CVuVector vf01; +CVuVector vf02; +CVuVector vf03; + +CVuVector +DistanceBetweenSphereAndLine(const CVuVector ¢er, const CVuVector &p0, const CVuVector &line) +{ + // center VF12 + // p0 VF14 + // line VF15 + CVuVector ret; // VF16 + CVuVector p1 = p0+line; + CVuVector dist0 = center - p0; // VF20 + CVuVector dist1 = center - p1; // VF25 + float lenSq = line.MagnitudeSqr(); // VF21 + float distSq0 = dist0.MagnitudeSqr(); // VF22 + float distSq1 = dist1.MagnitudeSqr(); + float dot = DotProduct(dist0, line); // VF23 + if(dot < 0.0f){ + // not above line, closest to p0 + ret = p0; + ret.w = distSq0; + return ret; + } + float t = dot/lenSq; // param of nearest point on infinite line + if(t > 1.0f){ + // not above line, closest to p1 + ret = p1; + ret.w = distSq1; + return ret; + } + // closest to line + ret = p0 + line*t; + ret.w = (ret - center).MagnitudeSqr(); + return ret; +} +inline int SignFlags(const CVector &v) +{ + int f = 0; + if(v.x < 0.0f) f |= 1; + if(v.y < 0.0f) f |= 2; + if(v.z < 0.0f) f |= 4; + return f; +} +#endif + +extern "C" void +LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, + const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, + const CVuVector &plane) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf13, 0x0(%1)\n" + "lqc2 vf14, 0x0(%2)\n" + "lqc2 vf15, 0x0(%3)\n" + "lqc2 vf16, 0x0(%4)\n" + "lqc2 vf17, 0x0(%5)\n" + "vcallms Vu0LineToTriangleCollisionStart\n" + ".set reorder\n" + : + : "r" (&p0), "r" (&p1), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) + ); +#else + float dot0 = DotProduct(plane, p0); + float dot1 = DotProduct(plane, p1); + float dist0 = plane.w - dot0; + float dist1 = plane.w - dot1; + + // if points are on the same side, no collision + if(dist0 * dist1 > 0.0f){ + vi01 = 0; + return; + } + + CVuVector diff = p1 - p0; + float t = dist0/(dot1 - dot0); + CVuVector p = p0 + diff*t; + p.w = 0.0f; + vf01 = p; + vf03.x = t; + + // Check if point is inside + CVector cross1 = CrossProduct(p-v0, v1-v0); + CVector cross2 = CrossProduct(p-v1, v2-v1); + CVector cross3 = CrossProduct(p-v2, v0-v2); + // Only check relevant directions + int flagmask = 0; + if(Abs(plane.x) > 0.5f) flagmask |= 1; + if(Abs(plane.y) > 0.5f) flagmask |= 2; + if(Abs(plane.z) > 0.5f) flagmask |= 4; + int flags1 = SignFlags(cross1) & flagmask; + int flags2 = SignFlags(cross2) & flagmask; + int flags3 = SignFlags(cross3) & flagmask; + // inside if on the same side of all edges + if(flags1 != flags2 || flags1 != flags3){ + vi01 = 0; + return; + } + vi01 = 1; + vf02 = plane; + return; +#endif +} + +extern "C" void +LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf13, 0x0(%1)\n" + "lqc2 vf14, 0x0(%2)\n" + "lqc2 vf15, 0x10(%2)\n" + "lqc2 vf16, 0x20(%2)\n" + "lqc2 vf17, 0x30(%2)\n" + "vcallms Vu0LineToTriangleCollisionCompressedStart\n" + ".set reorder\n" + : + : "r" (&p0), "r" (&p1), "r" (&tri) + ); +#else + CVuVector v0, v1, v2, plane; + v0.x = tri.v0[0]/128.0f; + v0.y = tri.v0[1]/128.0f; + v0.z = tri.v0[2]/128.0f; + v0.w = tri.v0[3]/128.0f; + v1.x = tri.v1[0]/128.0f; + v1.y = tri.v1[1]/128.0f; + v1.z = tri.v1[2]/128.0f; + v1.w = tri.v1[3]/128.0f; + v2.x = tri.v2[0]/128.0f; + v2.y = tri.v2[1]/128.0f; + v2.z = tri.v2[2]/128.0f; + v2.w = tri.v2[3]/128.0f; + plane.x = tri.plane[0]/4096.0f; + plane.y = tri.plane[1]/4096.0f; + plane.z = tri.plane[2]/4096.0f; + plane.w = tri.plane[3]/128.0f; + LineToTriangleCollision(p0, p1, v0, v1, v2, plane); +#endif +} + +extern "C" void +SphereToTriangleCollision(const CVuVector &sph, + const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, + const CVuVector &plane) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf14, 0x0(%1)\n" + "lqc2 vf15, 0x0(%2)\n" + "lqc2 vf16, 0x0(%3)\n" + "lqc2 vf17, 0x0(%4)\n" + "vcallms Vu0SphereToTriangleCollisionStart\n" + ".set reorder\n" + : + : "r" (&sph), "r" (&v0), "r" (&v1), "r" (&v2), "r" (&plane) + ); +#else + float planedist = DotProduct(plane, sph) - plane.w; // VF02 + if(Abs(planedist) > sph.w){ + vi01 = 0; + return; + } + // point on plane + CVuVector p = sph - planedist*plane; + p.w = 0.0f; + vf01 = p; + planedist = Abs(planedist); + // edges + CVuVector v01 = v1 - v0; + CVuVector v12 = v2 - v1; + CVuVector v20 = v0 - v2; + // VU code calculates normal again for some weird reason... + // Check sides of point + CVector cross1 = CrossProduct(p-v0, v01); + CVector cross2 = CrossProduct(p-v1, v12); + CVector cross3 = CrossProduct(p-v2, v20); + // Only check relevant directions + int flagmask = 0; + if(Abs(plane.x) > 0.1f) flagmask |= 1; + if(Abs(plane.y) > 0.1f) flagmask |= 2; + if(Abs(plane.z) > 0.1f) flagmask |= 4; + int nflags = SignFlags(plane) & flagmask; + int flags1 = SignFlags(cross1) & flagmask; + int flags2 = SignFlags(cross2) & flagmask; + int flags3 = SignFlags(cross3) & flagmask; + int testcase = 0; + CVuVector closest(0.0f, 0.0f, 0.0f); // VF04 + if(flags1 == nflags){ + closest += v2; + testcase++; + } + if(flags2 == nflags){ + closest += v0; + testcase++; + } + if(flags3 == nflags){ + closest += v1; + testcase++; + } + if(testcase == 3){ + // inside triangle - dist to plane already checked + vf02 = plane; + vf02.w = vf03.x = planedist; + vi01 = 1; + }else if(testcase == 1){ + // outside two sides - closest to point opposide inside edge + vf01 = closest; + vf02 = sph - closest; + float distSq = vf02.MagnitudeSqr(); + vi01 = sph.w*sph.w > distSq; + vf03.x = Sqrt(distSq); + vf02 *= 1.0f/vf03.x; + }else{ + // inside two sides - closest to third edge + if(flags1 != nflags) + closest = DistanceBetweenSphereAndLine(sph, v0, v01); + else if(flags2 != nflags) + closest = DistanceBetweenSphereAndLine(sph, v1, v12); + else + closest = DistanceBetweenSphereAndLine(sph, v2, v20); + vi01 = sph.w*sph.w > closest.w; + vf01 = closest; + vf02 = sph - closest; + vf03.x = Sqrt(closest.w); + vf02 *= 1.0f/vf03.x; + } +#endif +} + +extern "C" void +SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri) +{ +#ifdef GTA_PS2 + __asm__ volatile ( + ".set noreorder\n" + "lqc2 vf12, 0x0(%0)\n" + "lqc2 vf14, 0x0(%1)\n" + "lqc2 vf15, 0x10(%1)\n" + "lqc2 vf16, 0x20(%1)\n" + "lqc2 vf17, 0x30(%1)\n" + "vcallms Vu0SphereToTriangleCollisionCompressedStart\n" + ".set reorder\n" + : + : "r" (&sph), "r" (&tri) + ); +#else + CVuVector v0, v1, v2, plane; + v0.x = tri.v0[0]/128.0f; + v0.y = tri.v0[1]/128.0f; + v0.z = tri.v0[2]/128.0f; + v0.w = tri.v0[3]/128.0f; + v1.x = tri.v1[0]/128.0f; + v1.y = tri.v1[1]/128.0f; + v1.z = tri.v1[2]/128.0f; + v1.w = tri.v1[3]/128.0f; + v2.x = tri.v2[0]/128.0f; + v2.y = tri.v2[1]/128.0f; + v2.z = tri.v2[2]/128.0f; + v2.w = tri.v2[3]/128.0f; + plane.x = tri.plane[0]/4096.0f; + plane.y = tri.plane[1]/4096.0f; + plane.z = tri.plane[2]/4096.0f; + plane.w = tri.plane[3]/128.0f; + SphereToTriangleCollision(sph, v0, v1, v2, plane); +#endif +} +#endif \ No newline at end of file diff --git a/src/collision/VuCollision.h b/src/collision/VuCollision.h new file mode 100644 index 00000000..29ca4cbf --- /dev/null +++ b/src/collision/VuCollision.h @@ -0,0 +1,32 @@ +#pragma once + + +struct VuTriangle +{ + // Compressed int16 but unpacked +#ifdef GTA_PS2 + uint128 v0; + uint128 v1; + uint128 v2; + uint128 plane; +#else + int32 v0[4]; + int32 v1[4]; + int32 v2[4]; + int32 plane[4]; +#endif +}; + +#ifndef GTA_PS2 +extern int16 vi01; +extern CVuVector vf01; +extern CVuVector vf02; +extern CVuVector vf03; +#endif + +extern "C" { +void LineToTriangleCollision(const CVuVector &p0, const CVuVector &p1, const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, const CVuVector &plane); +void LineToTriangleCollisionCompressed(const CVuVector &p0, const CVuVector &p1, VuTriangle &tri); +void SphereToTriangleCollision(const CVuVector &sph, const CVuVector &v0, const CVuVector &v1, const CVuVector &v2, const CVuVector &plane); +void SphereToTriangleCollisionCompressed(const CVuVector &sph, VuTriangle &tri); +} diff --git a/src/core/vu0Collision.dsm b/src/collision/vu0Collision.dsm similarity index 100% rename from src/core/vu0Collision.dsm rename to src/collision/vu0Collision.dsm diff --git a/src/core/vu0Collision_1.s b/src/collision/vu0Collision_1.s similarity index 100% rename from src/core/vu0Collision_1.s rename to src/collision/vu0Collision_1.s diff --git a/src/core/vu0Collision_2.s b/src/collision/vu0Collision_2.s similarity index 100% rename from src/core/vu0Collision_2.s rename to src/collision/vu0Collision_2.s diff --git a/src/core/Collision.h b/src/core/Collision.h deleted file mode 100644 index da94dd34..00000000 --- a/src/core/Collision.h +++ /dev/null @@ -1,254 +0,0 @@ -#pragma once - -#include "templates.h" -#include "Game.h" // for eLevelName -#ifdef VU_COLLISION -#include "VuVector.h" -#endif - -// If you spawn many tanks at once, you will see that collisions of two entity exceeds 32. -#if defined(FIX_BUGS) && !defined(SQUEEZE_PERFORMANCE) -#define MAX_COLLISION_POINTS 64 -#else -#define MAX_COLLISION_POINTS 32 -#endif - -struct CompressedVector -{ -#ifdef COMPRESSED_COL_VECTORS - int16 x, y, z; - CVector Get(void) const { return CVector(x, y, z)/128.0f; }; - void Set(float x, float y, float z) { this->x = x*128.0f; this->y = y*128.0f; this->z = z*128.0f; }; -#ifdef GTA_PS2 - void Unpack(uint128 &qword) const { - __asm__ volatile ( - "lh $8, 0(%1)\n" - "lh $9, 2(%1)\n" - "lh $10, 4(%1)\n" - "pextlw $10, $8\n" - "pextlw $2, $9, $10\n" - "sq $2, %0\n" - : "=m" (qword) - : "r" (this) - : "$8", "$9", "$10", "$2" - ); - } -#else - void Unpack(int32 *qword) const { - qword[0] = x; - qword[1] = y; - qword[2] = z; - qword[3] = 0; // junk - } -#endif -#else - float x, y, z; - CVector Get(void) const { return CVector(x, y, z); }; - void Set(float x, float y, float z) { this->x = x; this->y = y; this->z = z; }; -#endif -}; - -struct CColSphere -{ - // NB: this has to be compatible with a CVuVector - CVector center; - float radius; - uint8 surface; - uint8 piece; - - void Set(float radius, const CVector ¢er, uint8 surf, uint8 piece); - void Set(float radius, const CVector ¢er) { this->center = center; this->radius = radius; } -}; - -struct CColBox -{ - CVector min; - CVector max; - uint8 surface; - uint8 piece; - - void Set(const CVector &min, const CVector &max, uint8 surf, uint8 piece); - CVector GetSize(void) { return max - min; } -}; - -struct CColLine -{ - // NB: this has to be compatible with two CVuVectors - CVector p0; - int pad0; - CVector p1; - int pad1; - - CColLine(void) { }; - CColLine(const CVector &p0, const CVector &p1) { this->p0 = p0; this->p1 = p1; }; - void Set(const CVector &p0, const CVector &p1); -}; - -struct CColTriangle -{ - uint16 a; - uint16 b; - uint16 c; - uint8 surface; - - void Set(const CompressedVector *v, int a, int b, int c, uint8 surf, uint8 piece); -}; - -struct CColTrianglePlane -{ -#ifdef VU_COLLISION - CompressedVector normal; - int16 dist; - - void Set(const CVector &va, const CVector &vb, const CVector &vc); - void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } - void GetNormal(CVector &n) const { n.x = normal.x/4096.0f; n.y = normal.y/4096.0f; n.z = normal.z/4096.0f; } - float CalcPoint(const CVector &v) const { CVector n; GetNormal(n); return DotProduct(n, v) - dist/128.0f; }; -#ifdef GTA_PS2 - void Unpack(uint128 &qword) const { - __asm__ volatile ( - "lh $8, 0(%1)\n" - "lh $9, 2(%1)\n" - "lh $10, 4(%1)\n" - "lh $11, 6(%1)\n" - "pextlw $10, $8\n" - "pextlw $11, $9\n" - "pextlw $2, $11, $10\n" - "sq $2, %0\n" - : "=m" (qword) - : "r" (this) - : "$8", "$9", "$10", "$11", "$2" - ); - } -#else - void Unpack(int32 *qword) const { - qword[0] = normal.x; - qword[1] = normal.y; - qword[2] = normal.z; - qword[3] = dist; - } -#endif -#else - CVector normal; - float dist; - uint8 dir; - - void Set(const CVector &va, const CVector &vb, const CVector &vc); - void Set(const CompressedVector *v, CColTriangle &tri) { Set(v[tri.a].Get(), v[tri.b].Get(), v[tri.c].Get()); } - void GetNormal(CVector &n) const { n = normal; } - float CalcPoint(const CVector &v) const { return DotProduct(normal, v) - dist; }; -#endif -}; - -struct CColPoint -{ - CVector point; - int pad1; - // the surface normal on the surface of point - CVector normal; - int pad2; - uint8 surfaceA; - uint8 pieceA; - uint8 surfaceB; - uint8 pieceB; - float depth; - - void Set(float depth, uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { - this->depth = depth; - this->surfaceA = surfA; - this->pieceA = pieceA; - this->surfaceB = surfB; - this->pieceB = pieceB; - } - void Set(uint8 surfA, uint8 pieceA, uint8 surfB, uint8 pieceB) { - this->surfaceA = surfA; - this->pieceA = pieceA; - this->surfaceB = surfB; - this->pieceB = pieceB; - } -}; - -struct CStoredCollPoly -{ -#ifdef VU_COLLISION - CVuVector verts[3]; -#else - CVector verts[3]; -#endif - bool valid; -}; - -struct CColModel -{ - CColSphere boundingSphere; - CColBox boundingBox; - int16 numSpheres; - int16 numLines; - int16 numBoxes; - int16 numTriangles; - int32 level; - bool ownsCollisionVolumes; // missing on PS2 - CColSphere *spheres; - CColLine *lines; - CColBox *boxes; - CompressedVector *vertices; - CColTriangle *triangles; - CColTrianglePlane *trianglePlanes; - - CColModel(void); - ~CColModel(void); - void RemoveCollisionVolumes(void); - void CalculateTrianglePlanes(void); - void RemoveTrianglePlanes(void); - CLink *GetLinkPtr(void); - void SetLinkPtr(CLink*); - void GetTrianglePoint(CVector &v, int i) const; - - CColModel& operator=(const CColModel& other); -}; - -class CCollision -{ -public: - static eLevelName ms_collisionInMemory; - static CLinkList ms_colModelCache; -#ifdef NO_ISLAND_LOADING - static bool bAlreadyLoaded; -#endif - - static void Init(void); - static void Shutdown(void); - static void Update(void); - static void LoadCollisionWhenINeedIt(bool changeLevel); - static void SortOutCollisionAfterLoad(void); - static void LoadCollisionScreen(eLevelName level); - static void DrawColModel(const CMatrix &mat, const CColModel &colModel); - static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); - - static void CalculateTrianglePlanes(CColModel *model); - - // all these return true if there's a collision - static bool TestSphereSphere(const CColSphere &s1, const CColSphere &s2); - static bool TestSphereBox(const CColSphere &sph, const CColBox &box); - static bool TestLineBox(const CColLine &line, const CColBox &box); - static bool TestVerticalLineBox(const CColLine &line, const CColBox &box); - static bool TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); - static bool TestLineSphere(const CColLine &line, const CColSphere &sph); - static bool TestSphereTriangle(const CColSphere &sphere, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane); - static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough); - - static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq); - static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq); - static bool ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist); - static bool ProcessVerticalLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist, CStoredCollPoly *poly); - static bool ProcessLineTriangle(const CColLine &line , const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist); - static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist); - static bool ProcessSphereTriangle(const CColSphere &sph, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq); - static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); - static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); - static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); - static bool IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly); - - static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); - static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); -}; diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index a08e68f8..172bae3f 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -572,7 +572,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToSoftCollision(B, impulseA); if(!A->bInfiniteMass) - A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA); + A->ApplyMoveForce(colpoint.GetNormal() * (1.0f + A->m_fElasticity) * impulseA); return true; } }else if(!B->bInfiniteMass) @@ -624,7 +624,7 @@ CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, fl }else{ if(IsGlass(B->GetModelIndex())) CGlass::WindowRespondsToSoftCollision(B, impulseA); - CVector f = colpoint.normal * impulseA; + CVector f = colpoint.GetNormal() * impulseA; if(A->IsVehicle() && colpoint.normal.z < 0.7f) f.z *= 0.3f; if(!A->bInfiniteMass){ @@ -1146,43 +1146,43 @@ CPhysical::ProcessShiftSectorList(CPtrList *lists) mostColliding = 0; for(j = 1; j < numCollisions; j++) - if(colpoints[j].depth > colpoints[mostColliding].depth) + if (colpoints[j].GetDepth() > colpoints[mostColliding].GetDepth()) mostColliding = j; if(CWorld::bSecondShift) for(j = 0; j < numCollisions; j++) - shift += colpoints[j].normal * colpoints[j].depth * 1.5f/numCollisions; + shift += colpoints[j].GetNormal() * colpoints[j].GetDepth() * 1.5f / numCollisions; else for(j = 0; j < numCollisions; j++) - shift += colpoints[j].normal * colpoints[j].depth * 1.2f/numCollisions; + shift += colpoints[j].GetNormal() * colpoints[j].GetDepth() * 1.2f / numCollisions; if(A->IsVehicle() && B->IsVehicle()){ CVector dir = A->GetPosition() - B->GetPosition(); dir.Normalise(); if(dir.z < 0.0f && dir.z < A->GetForward().z && dir.z < A->GetRight().z) dir.z = Min(0.0f, Min(A->GetForward().z, A->GetRight().z)); - shift += dir * colpoints[mostColliding].depth * 0.5f; + shift += dir * colpoints[mostColliding].GetDepth() * 0.5f; }else if(A->IsPed() && B->IsVehicle() && ((CVehicle*)B)->IsBoat()){ - CVector dir = colpoints[mostColliding].normal; + CVector dir = colpoints[mostColliding].GetNormal(); float f = Min(Abs(dir.z), 0.9f); dir.z = 0.0f; dir.Normalise(); - shift += dir * colpoints[mostColliding].depth / (1.0f - f); + shift += dir * colpoints[mostColliding].GetDepth() / (1.0f - f); boat = B; }else if(B->IsPed() && A->IsVehicle() && ((CVehicle*)A)->IsBoat()){ - CVector dir = colpoints[mostColliding].normal * -1.0f; + CVector dir = colpoints[mostColliding].GetNormal() * -1.0f; float f = Min(Abs(dir.z), 0.9f); dir.z = 0.0f; dir.Normalise(); - B->GetMatrix().Translate(dir * colpoints[mostColliding].depth / (1.0f - f)); + B->GetMatrix().Translate(dir * colpoints[mostColliding].GetDepth() / (1.0f - f)); // BUG? how can that ever happen? A is a Ped if(B->IsVehicle()) B->ProcessEntityCollision(A, colpoints); }else{ if(CWorld::bSecondShift) - shift += colpoints[mostColliding].normal * colpoints[mostColliding].depth * 0.4f; + shift += colpoints[mostColliding].GetNormal() * colpoints[mostColliding].GetDepth() * 0.4f; else - shift += colpoints[mostColliding].normal * colpoints[mostColliding].depth * 0.2f; + shift += colpoints[mostColliding].GetNormal() * colpoints[mostColliding].GetDepth() * 0.2f; } doShift = true; From ad10d3e64e317a60c4c7c481354ef9c2b39922f2 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 15 Nov 2020 22:07:44 +0100 Subject: [PATCH 049/129] revert frontend changes for invertlook4pad --- src/core/Frontend.cpp | 5 ----- src/core/Frontend.h | 3 --- 2 files changed, 8 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 879bcb29..cf25e1b9 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -5404,11 +5404,6 @@ CMenuManager::ProcessOnOffMenuOptions() DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0); SaveSettings(); break; -#ifdef INVERT_LOOK_FOR_PAD - case MENUACTION_INVERTPADY: - CPad::bInvertLook4Pad = !CPad::bInvertLook4Pad; - break; -#endif } } diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 947311b6..70b4cd31 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -383,9 +383,6 @@ enum eMenuAction //#ifdef NO_ISLAND_LOADING // MENUACTION_ISLANDLOADING, //#endif -#ifdef INVERT_LOOK_FOR_PAD - MENUACTION_INVERTPADY, -#endif }; enum eCheckHover From ac29ae6e23ac174adf03acb85749533e601ec5d0 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 15 Nov 2020 23:06:09 +0100 Subject: [PATCH 050/129] add CFO for invertlook4pad; update american.gxt --- gamefiles/TEXT/american.gxt | Bin 220024 -> 220080 bytes src/core/MenuScreensCustom.cpp | 10 ++++++++++ utils/gxt/american.txt | 3 +++ 3 files changed, 13 insertions(+) diff --git a/gamefiles/TEXT/american.gxt b/gamefiles/TEXT/american.gxt index e7f714b27978eb83ebbc88fa46da4c58abf74b74..1054ca126d8d797e0405afb6ecd0cb36126fdbbe 100644 GIT binary patch delta 73 zcmV-P0Ji`5whgei4Fyz7MOpN*1z#u&fZYNBMnywkNmfv^V$RTZB7Fj39}f& delta 36 scmdn6o%hE!Ue*wA*T@$eS>rV}7idffWo&3>tZQeiW8BVI$JBfm01jUb=>Px# diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index d3d7474d..5fc44661 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -15,6 +15,7 @@ #include "FileLoader.h" #include "Collision.h" #include "ModelInfo.h" +#include "Pad.h" // Menu screens array is at the bottom of the file. @@ -76,6 +77,12 @@ #define PIPELINES_SELECTOR #endif +#ifdef INVERT_LOOK_FOR_PAD + #define INVERT_PAD_SELECTOR MENUACTION_CFO_SELECT, "FEC_IVP", { new CCFOSelect((int8*)&CPad::bInvertLook4Pad, "InvertPad", off_on, 2, false, nil) }, +#else + #define INVERT_PAD_SELECTOR +#endif + const char *filterNames[] = { "FEM_NON", "FEM_SIM", "FEM_NRM", "FEM_MOB" }; const char *vehPipelineNames[] = { "FED_MFX", "FED_NEO" }; const char *off_on[] = { "FEM_OFF", "FEM_ON" }; @@ -780,6 +787,9 @@ CMenuScreenCustom aScreens[MENUPAGES] = { { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, MENUACTION_MOUSESENS, "FEC_MSH", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, MENUACTION_INVVERT, "FEC_IVV", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, +#ifdef INVERT_LOOK_FOR_PAD + INVERT_PAD_SELECTOR +#endif MENUACTION_MOUSESTEER, "FET_MST", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, }, diff --git a/utils/gxt/american.txt b/utils/gxt/american.txt index c428a570..cdee16f9 100644 --- a/utils/gxt/american.txt +++ b/utils/gxt/american.txt @@ -8061,6 +8061,9 @@ PS2 [FEM_XBX] XBOX +[FEC_IVP] +INVERT PAD VERTICALLY + { end of file } [DUMMY] From f0071c094aeacdd5fc8dd4f45911ebbc719811e0 Mon Sep 17 00:00:00 2001 From: withmorten Date: Mon, 16 Nov 2020 00:07:27 +0100 Subject: [PATCH 051/129] remove unneeded ifdef --- src/core/MenuScreensCustom.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index 5fc44661..f8ff3acf 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -787,9 +787,7 @@ CMenuScreenCustom aScreens[MENUPAGES] = { { "FET_MTI", MENUPAGE_CONTROLLER_PC, MENUPAGE_CONTROLLER_PC, nil, nil, MENUACTION_MOUSESENS, "FEC_MSH", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, MENUACTION_INVVERT, "FEC_IVV", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, -#ifdef INVERT_LOOK_FOR_PAD INVERT_PAD_SELECTOR -#endif MENUACTION_MOUSESTEER, "FET_MST", { nil, SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS }, MENUACTION_CHANGEMENU, "FEDS_TB", { nil, SAVESLOT_NONE, MENUPAGE_NONE }, }, From 207f8576d83c54d80a05a983798ce1d4bcb34f91 Mon Sep 17 00:00:00 2001 From: withmorten Date: Mon, 16 Nov 2020 00:21:04 +0100 Subject: [PATCH 052/129] move config.h define to CUSTOM_FRONTEND_OPTIONS --- src/core/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/config.h b/src/core/config.h index 39c5d782..1d321175 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -251,7 +251,6 @@ enum Config { #define REGISTER_START_BUTTON //#define BIND_VEHICLE_FIREWEAPON // Adds ability to rebind fire key for 'in vehicle' controls #define BUTTON_ICONS // use textures to show controller buttons -#define INVERT_LOOK_FOR_PAD // add bInvertLook4Pad from VC // Hud, frontend and radar #define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better. @@ -276,6 +275,7 @@ enum Config { # define NO_ISLAND_LOADING // disable loadscreen between islands via loading all island data at once, consumes more memory and CPU # define CUTSCENE_BORDERS_SWITCH # define MULTISAMPLING // adds MSAA option +# define INVERT_LOOK_FOR_PAD // add bInvertLook4Pad from VC # endif #endif From abcda2ce29877cdd60fad383ec098b174fbcc11f Mon Sep 17 00:00:00 2001 From: withmorten Date: Mon, 16 Nov 2020 00:41:03 +0100 Subject: [PATCH 053/129] add mission switcher from miami --- src/control/Script.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ src/control/Script.h | 7 +++++++ src/core/config.h | 5 +++++ src/core/re3.cpp | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 86595bbd..646bc3f7 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -13337,3 +13337,44 @@ void RetryMission(int type, int unk) } #endif + +#ifdef MISSION_SWITCHER +void +CTheScripts::SwitchToMission(int32 mission) +{ + for (CRunningScript* pScript = CTheScripts::pActiveScripts; pScript != nil; pScript = pScript->GetNext()) { + if (!pScript->m_bIsMissionScript || !pScript->m_bDeatharrestEnabled) { + continue; + } + while (pScript->m_nStackPointer > 0) + --pScript->m_nStackPointer; + + pScript->m_nIp = pScript->m_anStack[pScript->m_nStackPointer]; + *(int32*)&CTheScripts::ScriptSpace[CTheScripts::OnAMissionFlag] = 0; + pScript->m_nWakeTime = 0; + pScript->m_bDeatharrestExecuted = true; + + while (!pScript->ProcessOneCommand()); + + CMessages::ClearMessages(); + } + +#ifdef MISSION_REPLAY + missionRetryScriptIndex = mission; + if (missionRetryScriptIndex == 19) + CStats::LastMissionPassedName[0] = '\0'; +#endif + CTimer::Suspend(); + int offset = CTheScripts::MultiScriptArray[mission]; + CFileMgr::ChangeDir("\\"); + int handle = CFileMgr::OpenFile("data\\main.scm", "rb"); + CFileMgr::Seek(handle, offset, 0); + CFileMgr::Read(handle, (const char*)&CTheScripts::ScriptSpace[SIZE_MAIN_SCRIPT], SIZE_MISSION_SCRIPT); + CFileMgr::CloseFile(handle); + CRunningScript* pMissionScript = CTheScripts::StartNewScript(SIZE_MAIN_SCRIPT); + CTimer::Resume(); + pMissionScript->m_bIsMissionScript = true; + pMissionScript->m_bMissionFlag = true; + CTheScripts::bAlreadyRunningAMissionScript = true; +} +#endif diff --git a/src/control/Script.h b/src/control/Script.h index e0ed314e..c9e92129 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -376,6 +376,11 @@ private: #ifdef FIX_BUGS friend void RetryMission(int, int); #endif + +#ifdef MISSION_SWITCHER +public: + static void SwitchToMission(int32 mission); +#endif }; @@ -514,6 +519,8 @@ private: return false; } } + + friend class CTheScripts; }; #ifdef MISSION_REPLAY diff --git a/src/core/config.h b/src/core/config.h index a55b018e..ddbac185 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -217,6 +217,11 @@ enum Config { #define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible #define LOAD_INI_SETTINGS // as the name suggests. fundamental for CUSTOM_FRONTEND_OPTIONS +// Just debug menu entries +#ifdef DEBUGMENU +#define MISSION_SWITCHER // from debug menu +#endif + // Rendering/display //#define EXTRA_MODEL_FLAGS // from mobile to optimize rendering //# define HARDCODED_MODEL_FLAGS // sets the flags enabled above from hardcoded model names. diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 4783e513..194f75fa 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -26,6 +26,7 @@ #include "Frontend.h" #include "WaterLevel.h" #include "main.h" +#include "Script.h" #include "postfx.h" #include "custompipes.h" @@ -373,6 +374,15 @@ ResetCamStatics(void) TheCamera.Cams[TheCamera.ActiveCam].ResetStatics = true; } +#ifdef MISSION_SWITCHER +int8 nextMissionToSwitch = 0; +static void +SwitchToMission(void) +{ + CTheScripts::SwitchToMission(nextMissionToSwitch); +} +#endif + static const char *carnames[] = { "landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony", "mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer", @@ -581,6 +591,29 @@ DebugMenuPopulate(void) #ifdef TIMEBARS DebugMenuAddVarBool8("Debug", "Show Timebars", &gbShowTimebars, nil); #endif +#ifdef MISSION_SWITCHER + DebugMenuEntry *missionEntry; + static const char* missions[] = { + "Intro Movie", "Hospital Info Scene", "Police Station Info Scene", + "RC Diablo Destruction", "RC Mafia Massacre", "RC Rumpo Rampage", "RC Casino Calamity", + "Patriot Playground", "A Ride In The Park", "Gripped!", "Multistorey Mayhem", + "Paramedic", "Firefighter", "Vigilante", "Taxi Driver", + "The Crook", "The Thieves", "The Wife", "Her Lover", + "Give Me Liberty and Luigi's Girls", "Don't Spank My Bitch Up", "Drive Misty For Me", "Pump-Action Pimp", "The Fuzz Ball", + "Mike Lips Last Lunch", "Farewell 'Chunky' Lee Chong", "Van Heist", "Cipriani's Chauffeur", "Dead Skunk In The Trunk", "The Getaway", + "Taking Out The Laundry", "The Pick-Up", "Salvatore's Called A Meeting", "Triads And Tribulations", "Blow Fish", "Chaperone", "Cutting The Grass", + "Bomb Da Base: Act I", "Bomb Da Base: Act II", "Last Requests", "Turismo", "I Scream, You Scream", "Trial By Fire", "Big'N'Veiny", "Sayonara Salvatore", + "Under Surveillance", "Paparazzi Purge", "Payday For Ray", "Two-Faced Tanner", "Kanbu Bust-Out", "Grand Theft Auto", "Deal Steal", "Shima", "Smack Down", + "Silence The Sneak", "Arms Shortage", "Evidence Dash", "Gone Fishing", "Plaster Blaster", "Marked Man", + "Liberator", "Waka-Gashira Wipeout!", "A Drop In The Ocean", "Bling-Bling Scramble", "Uzi Rider", "Gangcar Round-Up", "Kingdom Come", + "Grand Theft Aero", "Escort Service", "Decoy", "Love's Disappearance", "Bait", "Espresso-2-Go!", "S.A.M.", + "Uzi Money", "Toyminator", "Rigged To Blow", "Bullion Run", "Rumble", "The Exchange" + }; + + missionEntry = DebugMenuAddVar("Debug", "Select mission", &nextMissionToSwitch, nil, 1, 0, 79, missions); + DebugMenuEntrySetWrap(missionEntry, true); + DebugMenuAddCmd("Debug", "Start selected mission ", SwitchToMission); +#endif extern bool PrintDebugCode; extern int16 DebugCamMode; From 2f9a905c613aacf12a3bc059eb1c8876d8c3bc86 Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 09:41:39 +0100 Subject: [PATCH 054/129] change gl caps.dat constants --- src/fakerw/fake.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 64e59375..460b8211 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -942,7 +942,9 @@ RwBool RtCharsetDestroy(RtCharset * charSet) { charSet->destroy(); return RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags) { #ifdef RW_GL3 - return '3LGO'; + if(flags & (rwRASTERFORMATPAL8 | rwRASTERFORMAT8888)) + return 'NOPE'; + return 'YUP'; #endif return flags & 0xF00; } From 5335b46cbb83e80e88d99f6963670050920e5f3e Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 09:48:02 +0100 Subject: [PATCH 055/129] little fix to ps2 CPad --- src/core/Pad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 44a347bd..9c6bdc98 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -1284,7 +1284,7 @@ void CPad::Update(int16 pad) { if ( ShakeDur ) { - ShakeDur = Max(ShakeDur - CTimer::GetTimeStepInMilliseconds(), 0); + ShakeDur = Max(ShakeDur - (int32)CTimer::GetTimeStepInMilliseconds(), 0); if ( ShakeDur == 0 ) { From b508458f372ba125c0d40d3f2aed27701b2cf7be Mon Sep 17 00:00:00 2001 From: Nikolay Date: Mon, 16 Nov 2020 15:13:30 +0300 Subject: [PATCH 056/129] small fix --- src/control/CarCtrl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index 76ee47b0..627d7bad 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -2692,7 +2692,7 @@ void CCarCtrl::GenerateEmergencyServicesCar(void) float distance = 30.0f; CFire* pNearestFire = gFireManager.FindNearestFire(FindPlayerCoors(), &distance); if (pNearestFire) { - if (CountCarsOfType(MI_FIRETRUCK) < 2 && CTimer::GetTimeInMilliseconds() > LastTimeFireTruckCreated + 30000){ + if (CountCarsOfType(MI_FIRETRUCK) < 2 && CTimer::GetTimeInMilliseconds() > LastTimeFireTruckCreated + 35000){ CStreaming::RequestModel(MI_FIRETRUCK, STREAMFLAGS_DEPENDENCY); CStreaming::RequestModel(MI_FIREMAN, STREAMFLAGS_DONT_REMOVE); if (CStreaming::HasModelLoaded(MI_FIRETRUCK) && CStreaming::HasModelLoaded(MI_FIREMAN)){ From 3b1debaa0d5341bdb954654503424fb12b529894 Mon Sep 17 00:00:00 2001 From: erorcun Date: Mon, 16 Nov 2020 15:28:10 +0300 Subject: [PATCH 057/129] Fix mouse lock/high-dpi --- src/core/Frontend.cpp | 9 ++++++++- src/core/main.cpp | 4 ++-- src/skel/glfw/glfw.cpp | 20 +++++++++++++------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 4be23b77..ffcd8b30 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -5529,8 +5529,15 @@ CMenuManager::SwitchMenuOnAndOff() gMusicPlaying = 0; } */ - if (m_bMenuActive != menuWasActive) + if (m_bMenuActive != menuWasActive) { m_bMenuStateChanged = true; + + // Keep mouse centered while in game. Done in main.cpp in other conditions. + // IMPROVED_VIDEOMODE because otherwise there is no way for windowed mode. +#if defined(RW_GL3) && defined(IMPROVED_VIDEOMODE) + glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, m_bMenuActive && m_nPrefsWindowed ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_DISABLED); +#endif + } m_bStartUpFrontEndRequested = false; m_bShutDownFrontEndRequested = false; diff --git a/src/core/main.cpp b/src/core/main.cpp index cd234588..157776e0 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -1090,9 +1090,9 @@ Idle(void *arg) if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu) && TheCamera.GetScreenFadeStatus() != FADE_2) { -#ifdef GTA_PC + // This is from SA, but it's nice for windowed mode +#if defined(GTA_PC) && !defined(RW_GL3) if (!FrontEndMenuManager.m_bRenderGameInMenu) { - // This is from SA, but it's nice for windowed mode RwV2d pos; pos.x = SCREEN_WIDTH / 2.0f; pos.y = SCREEN_HEIGHT / 2.0f; diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index d8d168c5..86abca64 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -885,7 +885,13 @@ void _InputInitialiseJoys() long _InputInitialiseMouse() { +#ifdef IMPROVED_VIDEOMODE + // May be windowed, transition will be handled in CMenuManager::SwitchMenuOnAndOff() glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, GLFW_CURSOR_HIDDEN); +#else + // Always fullscreen, disable mouse + glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif return 0; } @@ -1416,11 +1422,13 @@ _InputTranslateShiftKeyUpDown(RsKeyCodes *rs) { // TODO this only works in frontend(and luckily only frontend use this). Fun fact: if I get pos manually in game, glfw reports that it's > 32000 void cursorCB(GLFWwindow* window, double xpos, double ypos) { - int bufw, bufh, winw, winh; - glfwGetWindowSize(window, &winw, &winh); - glfwGetFramebufferSize(window, &bufw, &bufh); - FrontEndMenuManager.m_nMouseTempPosX = xpos * (bufw / winw); - FrontEndMenuManager.m_nMouseTempPosY = ypos * (bufh / winh); + if (!FrontEndMenuManager.m_bMenuActive) + return; + + int winw, winh; + glfwGetWindowSize(PSGLOBAL(window), &winw, &winh); + FrontEndMenuManager.m_nMouseTempPosX = xpos * (RsGlobal.maximumWidth / winw); + FrontEndMenuManager.m_nMouseTempPosY = ypos * (RsGlobal.maximumHeight / winh); } void @@ -1648,8 +1656,6 @@ main(int argc, char *argv[]) #endif { glfwPollEvents(); - glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, - (FrontEndMenuManager.m_bMenuActive && !PSGLOBAL(fullScreen)) ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_DISABLED); if( ForegroundApp ) { switch ( gGameState ) From f33ed2892a7a083d10c89b93b0122c6b4100a9a2 Mon Sep 17 00:00:00 2001 From: erorcun Date: Mon, 16 Nov 2020 15:49:00 +0300 Subject: [PATCH 058/129] Fix mouse lock/high-dpi 2 --- src/core/Frontend.cpp | 7 +++++-- src/skel/glfw/glfw.cpp | 6 ------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index ffcd8b30..b84b691d 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -5433,6 +5433,10 @@ CMenuManager::SetHelperText(int text) void CMenuManager::ShutdownJustMenu() { + // In case we're windowed, keep mouse centered while in game. Done in main.cpp in other conditions. +#if defined(RW_GL3) && defined(IMPROVED_VIDEOMODE) + glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif m_bMenuActive = false; CTimer::EndUserPause(); } @@ -5532,8 +5536,7 @@ CMenuManager::SwitchMenuOnAndOff() if (m_bMenuActive != menuWasActive) { m_bMenuStateChanged = true; - // Keep mouse centered while in game. Done in main.cpp in other conditions. - // IMPROVED_VIDEOMODE because otherwise there is no way for windowed mode. + // In case we're windowed, keep mouse centered while in game. Done in main.cpp in other conditions. #if defined(RW_GL3) && defined(IMPROVED_VIDEOMODE) glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, m_bMenuActive && m_nPrefsWindowed ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_DISABLED); #endif diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 86abca64..982e8641 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -885,13 +885,7 @@ void _InputInitialiseJoys() long _InputInitialiseMouse() { -#ifdef IMPROVED_VIDEOMODE - // May be windowed, transition will be handled in CMenuManager::SwitchMenuOnAndOff() glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, GLFW_CURSOR_HIDDEN); -#else - // Always fullscreen, disable mouse - glfwSetInputMode(PSGLOBAL(window), GLFW_CURSOR, GLFW_CURSOR_DISABLED); -#endif return 0; } From 6bc2ed74fec6e60d1d379dc36f271c457448d3e7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 16 Nov 2020 14:56:07 +0200 Subject: [PATCH 059/129] Add debug code to CPathFind::PreparePathDataForType --- src/control/PathFind.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index fb60250c..ecd2d0cb 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -542,6 +542,22 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor int done, cont; int tileStart; +#ifndef MASTER + for (i = 0; i < m_numMapObjects-1; i++) + for (j = i+1; j < m_numMapObjects; j++) { + CTreadable *obj1 = m_mapObjects[i]; + CTreadable *obj2 = m_mapObjects[j]; + if (obj1->GetModelIndex() == obj2->GetModelIndex() && + obj1->GetPosition().x == obj2->GetPosition().x && obj1->GetPosition().y == obj2->GetPosition().y && obj1->GetPosition().z == obj2->GetPosition().z && + obj1->GetRight().x == obj2->GetRight().x && obj1->GetForward().x == obj2->GetForward().x && obj1->GetUp().x == obj2->GetUp().x && + obj1->GetRight().y == obj2->GetRight().y && obj1->GetForward().y == obj2->GetForward().y && obj1->GetUp().y == obj2->GetUp().y && + obj1->GetRight().z == obj2->GetRight().z && obj1->GetForward().z == obj2->GetForward().z && obj1->GetUp().z == obj2->GetUp().z) { + printf("THIS IS VERY BAD INDEED. FIX IMMEDIATELY!!!\n"); + printf("Double road objects at the following coors: %f %f %f\n", obj1->GetPosition().x, obj1->GetPosition().y, obj1->GetPosition().z); + } + } +#endif // !MASTER + oldNumPathNodes = m_numPathNodes; oldNumLinks = m_numConnections; From a802ad5c271f15fc9acaacdfa55fb6a318c1c893 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 16 Nov 2020 15:05:02 +0200 Subject: [PATCH 060/129] pragma twice --- src/objects/Projectile.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/objects/Projectile.h b/src/objects/Projectile.h index 2f2b541c..4b3eb4b8 100644 --- a/src/objects/Projectile.h +++ b/src/objects/Projectile.h @@ -1,7 +1,5 @@ #pragma once -#pragma once - #include "Object.h" class CProjectile : public CObject From 3564b85b4e354272cea8a8217f9e27827a043d7a Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 22:43:15 +0100 Subject: [PATCH 061/129] animation compression from PS2 --- src/animation/AnimBlendAssociation.h | 2 +- src/animation/AnimBlendHierarchy.cpp | 18 +++-- src/animation/AnimBlendSequence.cpp | 104 +++++++++++++++++++++++++++ src/animation/AnimBlendSequence.h | 16 +++-- src/animation/AnimManager.cpp | 2 +- src/core/config.h | 1 + 6 files changed, 133 insertions(+), 10 deletions(-) diff --git a/src/animation/AnimBlendAssociation.h b/src/animation/AnimBlendAssociation.h index 2dff4391..80927da2 100644 --- a/src/animation/AnimBlendAssociation.h +++ b/src/animation/AnimBlendAssociation.h @@ -13,7 +13,7 @@ enum { ASSOC_MOVEMENT = 0x20, // ??? ASSOC_HAS_TRANSLATION = 0x40, ASSOC_WALK = 0x80, // for CPed::PlayFootSteps(void) - ASSOC_FLAG_XPRESS = 0x100, // only used by xpress scratch, see CPed::Chat(void) + ASSOC_IDLE = 0x100, // only used by xpress scratch, see CPed::Chat(void) ASSOC_NOWALK = 0x200, // see CPed::PlayFootSteps(void) ASSOC_BLOCK = 0x400, // unused in assoc description, blocks other anims from being played ASSOC_FRONTAL = 0x800, // anims that we fall to front diff --git a/src/animation/AnimBlendHierarchy.cpp b/src/animation/AnimBlendHierarchy.cpp index feeaca3d..67b19019 100644 --- a/src/animation/AnimBlendHierarchy.cpp +++ b/src/animation/AnimBlendHierarchy.cpp @@ -30,15 +30,14 @@ void CAnimBlendHierarchy::CalcTotalTime(void) { int i, j; - float totalTime = 0.0f; + totalLength = 0.0f; for(i = 0; i < numSequences; i++){ float seqTime = 0.0f; for(j = 0; j < sequences[i].numFrames; j++) seqTime += sequences[i].GetKeyFrame(j)->deltaTime; - totalTime = Max(totalTime, seqTime); + totalLength = Max(totalLength, seqTime); } - totalLength = totalTime; } void @@ -61,6 +60,12 @@ CAnimBlendHierarchy::RemoveAnimSequences(void) void CAnimBlendHierarchy::Uncompress(void) { +#ifdef ANIM_COMPRESSION + int i; + assert(compressed); + for(i = 0; i < numSequences; i++) + sequences[i].Uncompress(); +#endif if(totalLength == 0.0f) CalcTotalTime(); compressed = 0; @@ -69,6 +74,11 @@ CAnimBlendHierarchy::Uncompress(void) void CAnimBlendHierarchy::RemoveUncompressedData(void) { - // useless +#ifdef ANIM_COMPRESSION + int i; + assert(!compressed); + for(i = 0; i < numSequences; i++) + sequences[i].RemoveUncompressedData(); +#endif compressed = 1; } diff --git a/src/animation/AnimBlendSequence.cpp b/src/animation/AnimBlendSequence.cpp index 4578ec50..d35fbc46 100644 --- a/src/animation/AnimBlendSequence.cpp +++ b/src/animation/AnimBlendSequence.cpp @@ -15,6 +15,7 @@ CAnimBlendSequence::CAnimBlendSequence(void) CAnimBlendSequence::~CAnimBlendSequence(void) { + assert(keyFramesCompressed == nil); if(keyFrames) RwFree(keyFrames); } @@ -60,3 +61,106 @@ CAnimBlendSequence::RemoveQuaternionFlips(void) last = frame->rotation; } } + +void +CAnimBlendSequence::Uncompress(void) +{ + int i; + + if(numFrames == 0) + return; + + float rotScale = 1.0f/4096.0f; + float timeScale = 1.0f/60.0f; + float transScale = 1.0f/128.0f; + if(type & KF_TRANS){ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameTrans)); + KeyFrameTransCompressed *ckf = (KeyFrameTransCompressed*)keyFramesCompressed; + KeyFrameTrans *kf = (KeyFrameTrans*)newKfs; + for(i = 0; i < numFrames; i++){ + kf->rotation.x = ckf->rot[0]*rotScale; + kf->rotation.y = ckf->rot[1]*rotScale; + kf->rotation.z = ckf->rot[2]*rotScale; + kf->rotation.w = ckf->rot[3]*rotScale; + kf->deltaTime = ckf->deltaTime*timeScale; + kf->translation.x = ckf->trans[0]*transScale; + kf->translation.y = ckf->trans[1]*transScale; + kf->translation.z = ckf->trans[2]*transScale; + kf++; + ckf++; + } + keyFrames = newKfs; + }else{ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrame)); + KeyFrameCompressed *ckf = (KeyFrameCompressed*)keyFramesCompressed; + KeyFrame *kf = (KeyFrame*)newKfs; + for(i = 0; i < numFrames; i++){ + kf->rotation.x = ckf->rot[0]*rotScale; + kf->rotation.y = ckf->rot[1]*rotScale; + kf->rotation.z = ckf->rot[2]*rotScale; + kf->rotation.w = ckf->rot[3]*rotScale; + kf->deltaTime = ckf->deltaTime*timeScale; + kf++; + ckf++; + } + keyFrames = newKfs; + } + RwFree(keyFramesCompressed); + keyFramesCompressed = nil; +} + +void +CAnimBlendSequence::CompressKeyframes(void) +{ + int i; + + if(numFrames == 0) + return; + + float rotScale = 4096.0f; + float timeScale = 60.0f; + float transScale = 128.0f; + if(type & KF_TRANS){ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameTransCompressed)); + KeyFrameTransCompressed *ckf = (KeyFrameTransCompressed*)newKfs; + KeyFrameTrans *kf = (KeyFrameTrans*)keyFrames; + for(i = 0; i < numFrames; i++){ + ckf->rot[0] = kf->rotation.x*rotScale; + ckf->rot[1] = kf->rotation.y*rotScale; + ckf->rot[2] = kf->rotation.z*rotScale; + ckf->rot[3] = kf->rotation.w*rotScale; + ckf->deltaTime = kf->deltaTime*timeScale + 0.5f; + ckf->trans[0] = kf->translation.x*transScale; + ckf->trans[1] = kf->translation.y*transScale; + ckf->trans[2] = kf->translation.z*transScale; + kf++; + ckf++; + } + keyFramesCompressed = newKfs; + }else{ + void *newKfs = RwMalloc(numFrames * sizeof(KeyFrameCompressed)); + KeyFrameCompressed *ckf = (KeyFrameCompressed*)newKfs; + KeyFrame *kf = (KeyFrame*)keyFrames; + for(i = 0; i < numFrames; i++){ + ckf->rot[0] = kf->rotation.x*rotScale; + ckf->rot[1] = kf->rotation.y*rotScale; + ckf->rot[2] = kf->rotation.z*rotScale; + ckf->rot[3] = kf->rotation.w*rotScale; + ckf->deltaTime = kf->deltaTime*timeScale + 0.5f; + kf++; + ckf++; + } + keyFramesCompressed = newKfs; + } +} + +void +CAnimBlendSequence::RemoveUncompressedData(void) +{ + if(numFrames == 0) + return; + CompressKeyframes(); + RwFree(keyFrames); + keyFrames = nil; +} + diff --git a/src/animation/AnimBlendSequence.h b/src/animation/AnimBlendSequence.h index 44ac8886..e51e5aaa 100644 --- a/src/animation/AnimBlendSequence.h +++ b/src/animation/AnimBlendSequence.h @@ -12,6 +12,15 @@ struct KeyFrameTrans : KeyFrame { CVector translation; }; +struct KeyFrameCompressed { + int16 rot[4]; // 4096 + int16 deltaTime; // 60 +}; + +struct KeyFrameTransCompressed : KeyFrameCompressed { + int16 trans[3]; // 128 +}; + // The sequence of key frames of one animated node class CAnimBlendSequence @@ -41,10 +50,9 @@ public: &((KeyFrame*)keyFrames)[n]; } bool HasTranslation(void) { return !!(type & KF_TRANS); } - // TODO? these are unused -// void Uncompress(void); -// void CompressKeyframes(void); -// void RemoveUncompressedData(void); + void Uncompress(void); + void CompressKeyframes(void); + void RemoveUncompressedData(void); #ifdef PED_SKIN void SetBoneTag(int tag) { boneTag = tag; } diff --git a/src/animation/AnimManager.cpp b/src/animation/AnimManager.cpp index 444b6d45..877dcd76 100644 --- a/src/animation/AnimManager.cpp +++ b/src/animation/AnimManager.cpp @@ -176,7 +176,7 @@ AnimAssocDesc aStdAnimDescs[] = { { ANIM_FALL_COLLAPSE, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION }, { ANIM_EV_STEP, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION }, { ANIM_EV_DIVE, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION | ASSOC_FRONTAL }, - { ANIM_XPRESS_SCRATCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_FLAG_XPRESS }, + { ANIM_XPRESS_SCRATCH, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL | ASSOC_IDLE }, { ANIM_ROAD_CROSS, ASSOC_REPEAT | ASSOC_PARTIAL }, { ANIM_TURN_180, ASSOC_FADEOUTWHENDONE | ASSOC_PARTIAL }, { ANIM_ARREST_GUN, ASSOC_PARTIAL | ASSOC_HAS_TRANSLATION }, diff --git a/src/core/config.h b/src/core/config.h index 1d321175..11168039 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -177,6 +177,7 @@ enum Config { # define GTA_PS2_STUFF # define RANDOMSPLASH # define VU_COLLISION +# define ANIM_COMPRESSION #elif defined GTA_PC # define GTA3_1_1_PATCH //# define GTA3_STEAM_PATCH From 19d943031481f83d662c74ee3202a8fbaed22fa2 Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 22:57:37 +0100 Subject: [PATCH 062/129] fix flag --- src/peds/Ped.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index fcfd9bce..b3c5c57b 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -3023,7 +3023,7 @@ CPed::Chat(void) } else Say(SOUND_PED_CHAT); - } else if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FLAG_XPRESS)) { + } else if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { if (CGeneral::GetRandomNumber() < 20) { CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); From 82b0103c6789041b721b1de30746ce21a556ab4d Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 10:27:55 +0100 Subject: [PATCH 063/129] changes to librw layer, GLES now runtime choice --- src/extras/custompipes_gl.cpp | 47 +++------- src/extras/postfx.cpp | 18 +--- src/extras/shaders/Makefile | 58 ++++++------ src/extras/shaders/colourfilterIII.frag | 11 +-- src/extras/shaders/colourfilterIII_fs_gl.inc | 26 ++++++ src/extras/shaders/contrast.frag | 11 +-- src/extras/shaders/contrast_fs_gl.inc | 21 +++++ src/extras/shaders/default_UV2.vert | 14 ++- src/extras/shaders/default_UV2_gl.inc | 27 ++++++ src/extras/shaders/im2d.vert | 10 +-- src/extras/shaders/im2d_gl.inc | 21 +++++ src/extras/shaders/neoGloss.frag | 14 +-- src/extras/shaders/neoGloss.vert | 14 ++- src/extras/shaders/neoGloss_fs_gl.inc | 28 ++++++ src/extras/shaders/neoGloss_vs_gl.inc | 27 ++++++ src/extras/shaders/neoRim.vert | 11 +-- src/extras/shaders/neoRimSkin.vert | 13 +-- src/extras/shaders/neoRimSkin_gl.inc | 45 ++++++++++ src/extras/shaders/neoRim_gl.inc | 36 ++++++++ src/extras/shaders/neoVehicle.frag | 15 ++-- src/extras/shaders/neoVehicle.vert | 15 ++-- src/extras/shaders/neoVehicle_fs_gl.inc | 31 +++++++ src/extras/shaders/neoVehicle_vs_gl.inc | 53 +++++++++++ src/extras/shaders/neoWorldIII.frag | 14 +-- src/extras/shaders/neoWorldIII_fs_gl.inc | 27 ++++++ src/extras/shaders/simple.frag | 11 +-- src/extras/shaders/simple_fs_gl.inc | 19 ++++ src/fakerw/fake.cpp | 13 --- src/rw/TexRead.cpp | 92 +++++++++++++++++++- vendor/librw | 2 +- 30 files changed, 563 insertions(+), 181 deletions(-) create mode 100644 src/extras/shaders/colourfilterIII_fs_gl.inc create mode 100644 src/extras/shaders/contrast_fs_gl.inc create mode 100644 src/extras/shaders/default_UV2_gl.inc create mode 100644 src/extras/shaders/im2d_gl.inc create mode 100644 src/extras/shaders/neoGloss_fs_gl.inc create mode 100644 src/extras/shaders/neoGloss_vs_gl.inc create mode 100644 src/extras/shaders/neoRimSkin_gl.inc create mode 100644 src/extras/shaders/neoRim_gl.inc create mode 100644 src/extras/shaders/neoVehicle_fs_gl.inc create mode 100644 src/extras/shaders/neoVehicle_vs_gl.inc create mode 100644 src/extras/shaders/neoWorldIII_fs_gl.inc create mode 100644 src/extras/shaders/simple_fs_gl.inc diff --git a/src/extras/custompipes_gl.cpp b/src/extras/custompipes_gl.cpp index 01663df5..861a831e 100644 --- a/src/extras/custompipes_gl.cpp +++ b/src/extras/custompipes_gl.cpp @@ -134,6 +134,7 @@ vehicleRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header) } SetRenderState(SRCBLEND, BLENDSRCALPHA); + setTexture(1, nil); #ifndef RW_GL_USE_VAOS disableAttribPointers(header->attribDesc, header->numAttribs); @@ -158,13 +159,8 @@ CreateVehiclePipe(void) { -#ifdef RW_GLES2 -#include "gl2_shaders/neoVehicle_fs_gl2.inc" -#include "gl2_shaders/neoVehicle_vs_gl2.inc" -#else -#include "shaders/neoVehicle_fs_gl3.inc" -#include "shaders/neoVehicle_vs_gl3.inc" -#endif +#include "shaders/neoVehicle_fs_gl.inc" +#include "shaders/neoVehicle_vs_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, neoVehicle_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, neoVehicle_frag_src, nil }; neoVehicleShader = Shader::create(vs, fs); @@ -256,6 +252,7 @@ worldRenderCB(rw::Atomic *atomic, rw::gl3::InstanceDataHeader *header) drawInst(header, inst); inst++; } + setTexture(1, nil); #ifndef RW_GL_USE_VAOS disableAttribPointers(header->attribDesc, header->numAttribs); #endif @@ -273,13 +270,8 @@ CreateWorldPipe(void) ReadTweakValueTable((char*)work_buff, WorldLightmapBlend); { -#ifdef RW_GLES2 -#include "gl2_shaders/neoWorldIII_fs_gl2.inc" -#include "gl2_shaders/default_UV2_gl2.inc" -#else -#include "shaders/neoWorldIII_fs_gl3.inc" -#include "shaders/default_UV2_gl3.inc" -#endif +#include "shaders/neoWorldIII_fs_gl.inc" +#include "shaders/default_UV2_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, default_UV2_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, neoWorldIII_frag_src, nil }; neoWorldShader = Shader::create(vs, fs); @@ -381,13 +373,8 @@ CreateGlossPipe(void) using namespace rw::gl3; { -#ifdef RW_GLES2 -#include "gl2_shaders/neoGloss_fs_gl2.inc" -#include "gl2_shaders/neoGloss_vs_gl2.inc" -#else -#include "shaders/neoGloss_fs_gl3.inc" -#include "shaders/neoGloss_vs_gl3.inc" -#endif +#include "shaders/neoGloss_fs_gl.inc" +#include "shaders/neoGloss_vs_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, neoGloss_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, neoGloss_frag_src, nil }; neoGlossShader = Shader::create(vs, fs); @@ -558,13 +545,8 @@ CreateRimLightPipes(void) } { -#ifdef RW_GLES2 -#include "gl2_shaders/simple_fs_gl2.inc" -#include "gl2_shaders/neoRimSkin_gl2.inc" -#else -#include "shaders/simple_fs_gl3.inc" -#include "shaders/neoRimSkin_gl3.inc" -#endif +#include "shaders/simple_fs_gl.inc" +#include "shaders/neoRimSkin_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, neoRimSkin_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, simple_frag_src, nil }; neoRimSkinShader = Shader::create(vs, fs); @@ -572,13 +554,8 @@ CreateRimLightPipes(void) } { -#ifdef RW_GLES2 -#include "gl2_shaders/simple_fs_gl2.inc" -#include "gl2_shaders/neoRim_gl2.inc" -#else -#include "shaders/simple_fs_gl3.inc" -#include "shaders/neoRim_gl3.inc" -#endif +#include "shaders/simple_fs_gl.inc" +#include "shaders/neoRim_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, neoRim_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, simple_frag_src, nil }; neoRimShader = Shader::create(vs, fs); diff --git a/src/extras/postfx.cpp b/src/extras/postfx.cpp index 6355dfb1..fe481658 100644 --- a/src/extras/postfx.cpp +++ b/src/extras/postfx.cpp @@ -150,13 +150,8 @@ CPostFX::Open(RwCamera *cam) #ifdef RW_OPENGL using namespace rw::gl3; { -#ifdef RW_GLES2 -#include "gl2_shaders/im2d_gl2.inc" -#include "gl2_shaders/colourfilterIII_fs_gl2.inc" -#else -#include "shaders/im2d_gl3.inc" -#include "shaders/colourfilterIII_fs_gl3.inc" -#endif +#include "shaders/im2d_gl.inc" +#include "shaders/colourfilterIII_fs_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, colourfilterIII_frag_src, nil }; colourFilterIII = Shader::create(vs, fs); @@ -164,17 +159,12 @@ CPostFX::Open(RwCamera *cam) } { -#ifdef RW_GLES2 -#include "gl2_shaders/im2d_gl2.inc" -#include "gl2_shaders/contrast_fs_gl2.inc" -#else -#include "shaders/im2d_gl3.inc" -#include "shaders/contrast_fs_gl3.inc" +#include "shaders/im2d_gl.inc" +#include "shaders/contrast_fs_gl.inc" const char *vs[] = { shaderDecl, header_vert_src, im2d_vert_src, nil }; const char *fs[] = { shaderDecl, header_frag_src, contrast_frag_src, nil }; contrast = Shader::create(vs, fs); assert(contrast); -#endif } #endif diff --git a/src/extras/shaders/Makefile b/src/extras/shaders/Makefile index 6cbbf237..4b6027e2 100644 --- a/src/extras/shaders/Makefile +++ b/src/extras/shaders/Makefile @@ -1,68 +1,68 @@ -all: im2d_gl3.inc simple_fs_gl3.inc default_UV2_gl3.inc \ - colourfilterIII_fs_gl3.inc contrast_fs_gl3.inc \ - neoRim_gl3.inc neoRimSkin_gl3.inc \ - neoWorldIII_fs_gl3.inc neoGloss_vs_gl3.inc neoGloss_fs_gl3.inc \ - neoVehicle_vs_gl3.inc neoVehicle_fs_gl3.inc +all: im2d_gl.inc simple_fs_gl.inc default_UV2_gl.inc \ + colourfilterIII_fs_gl.inc contrast_fs_gl.inc \ + neoRim_gl.inc neoRimSkin_gl.inc \ + neoWorldIII_fs_gl.inc neoGloss_vs_gl.inc neoGloss_fs_gl.inc \ + neoVehicle_vs_gl.inc neoVehicle_fs_gl.inc -im2d_gl3.inc: im2d.vert +im2d_gl.inc: im2d.vert (echo 'const char *im2d_vert_src =';\ sed 's/..*/"&\\n"/' im2d.vert;\ - echo ';') >im2d_gl3.inc + echo ';') >im2d_gl.inc -simple_fs_gl3.inc: simple.frag +simple_fs_gl.inc: simple.frag (echo 'const char *simple_frag_src =';\ sed 's/..*/"&\\n"/' simple.frag;\ - echo ';') >simple_fs_gl3.inc + echo ';') >simple_fs_gl.inc -default_UV2_gl3.inc: default_UV2.vert +default_UV2_gl.inc: default_UV2.vert (echo 'const char *default_UV2_vert_src =';\ sed 's/..*/"&\\n"/' default_UV2.vert;\ - echo ';') >default_UV2_gl3.inc + echo ';') >default_UV2_gl.inc -colourfilterIII_fs_gl3.inc: colourfilterIII.frag +colourfilterIII_fs_gl.inc: colourfilterIII.frag (echo 'const char *colourfilterIII_frag_src =';\ sed 's/..*/"&\\n"/' colourfilterIII.frag;\ - echo ';') >colourfilterIII_fs_gl3.inc + echo ';') >colourfilterIII_fs_gl.inc -contrast_fs_gl3.inc: contrast.frag +contrast_fs_gl.inc: contrast.frag (echo 'const char *contrast_frag_src =';\ sed 's/..*/"&\\n"/' contrast.frag;\ - echo ';') >contrast_fs_gl3.inc + echo ';') >contrast_fs_gl.inc -neoRim_gl3.inc: neoRim.vert +neoRim_gl.inc: neoRim.vert (echo 'const char *neoRim_vert_src =';\ sed 's/..*/"&\\n"/' neoRim.vert;\ - echo ';') >neoRim_gl3.inc + echo ';') >neoRim_gl.inc -neoRimSkin_gl3.inc: neoRimSkin.vert +neoRimSkin_gl.inc: neoRimSkin.vert (echo 'const char *neoRimSkin_vert_src =';\ sed 's/..*/"&\\n"/' neoRimSkin.vert;\ - echo ';') >neoRimSkin_gl3.inc + echo ';') >neoRimSkin_gl.inc -neoWorldIII_fs_gl3.inc: neoWorldIII.frag +neoWorldIII_fs_gl.inc: neoWorldIII.frag (echo 'const char *neoWorldIII_frag_src =';\ sed 's/..*/"&\\n"/' neoWorldIII.frag;\ - echo ';') >neoWorldIII_fs_gl3.inc + echo ';') >neoWorldIII_fs_gl.inc -neoGloss_fs_gl3.inc: neoGloss.frag +neoGloss_fs_gl.inc: neoGloss.frag (echo 'const char *neoGloss_frag_src =';\ sed 's/..*/"&\\n"/' neoGloss.frag;\ - echo ';') >neoGloss_fs_gl3.inc + echo ';') >neoGloss_fs_gl.inc -neoGloss_vs_gl3.inc: neoGloss.vert +neoGloss_vs_gl.inc: neoGloss.vert (echo 'const char *neoGloss_vert_src =';\ sed 's/..*/"&\\n"/' neoGloss.vert;\ - echo ';') >neoGloss_vs_gl3.inc + echo ';') >neoGloss_vs_gl.inc -neoVehicle_vs_gl3.inc: neoVehicle.vert +neoVehicle_vs_gl.inc: neoVehicle.vert (echo 'const char *neoVehicle_vert_src =';\ sed 's/..*/"&\\n"/' neoVehicle.vert;\ - echo ';') >neoVehicle_vs_gl3.inc + echo ';') >neoVehicle_vs_gl.inc -neoVehicle_fs_gl3.inc: neoVehicle.frag +neoVehicle_fs_gl.inc: neoVehicle.frag (echo 'const char *neoVehicle_frag_src =';\ sed 's/..*/"&\\n"/' neoVehicle.frag;\ - echo ';') >neoVehicle_fs_gl3.inc + echo ';') >neoVehicle_fs_gl.inc diff --git a/src/extras/shaders/colourfilterIII.frag b/src/extras/shaders/colourfilterIII.frag index 4c9a8400..b41cb94a 100644 --- a/src/extras/shaders/colourfilterIII.frag +++ b/src/extras/shaders/colourfilterIII.frag @@ -1,11 +1,9 @@ uniform sampler2D tex0; uniform vec4 u_blurcolor; -in vec4 v_color; -in vec2 v_tex0; -in float v_fog; - -out vec4 color; +FSIN vec4 v_color; +FSIN vec2 v_tex0; +FSIN float v_fog; void main(void) @@ -17,7 +15,10 @@ main(void) vec4 tmp = dst*(1.0-a) + prev*u_blurcolor*a; prev = clamp(tmp, 0.0, 1.0); } + vec4 color; color.rgb = prev.rgb; color.a = 1.0f; + + FRAGCOLOR(color); } diff --git a/src/extras/shaders/colourfilterIII_fs_gl.inc b/src/extras/shaders/colourfilterIII_fs_gl.inc new file mode 100644 index 00000000..6fd1935b --- /dev/null +++ b/src/extras/shaders/colourfilterIII_fs_gl.inc @@ -0,0 +1,26 @@ +const char *colourfilterIII_frag_src = +"uniform sampler2D tex0;\n" +"uniform vec4 u_blurcolor;\n" + +"FSIN vec4 v_color;\n" +"FSIN vec2 v_tex0;\n" +"FSIN float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" float a = u_blurcolor.a;\n" +" vec4 dst = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" +" vec4 prev = dst;\n" +" for(int i = 0; i < 5; i++){\n" +" vec4 tmp = dst*(1.0-a) + prev*u_blurcolor*a;\n" +" prev = clamp(tmp, 0.0, 1.0);\n" +" }\n" +" vec4 color;\n" +" color.rgb = prev.rgb;\n" +" color.a = 1.0f;\n" + +" FRAGCOLOR(color);\n" +"}\n" + +; diff --git a/src/extras/shaders/contrast.frag b/src/extras/shaders/contrast.frag index d6dec478..1b93f6fe 100644 --- a/src/extras/shaders/contrast.frag +++ b/src/extras/shaders/contrast.frag @@ -2,17 +2,18 @@ uniform sampler2D tex0; uniform vec3 u_contrastAdd; uniform vec3 u_contrastMult; -in vec4 v_color; -in vec2 v_tex0; -in float v_fog; - -out vec4 color; +FSIN vec4 v_color; +FSIN vec2 v_tex0; +FSIN float v_fog; void main(void) { vec4 dst = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y)); + vec4 color; color.rgb = dst.rgb*u_contrastMult + u_contrastAdd; color.a = 1.0f; + + FRAGCOLOR(color); } diff --git a/src/extras/shaders/contrast_fs_gl.inc b/src/extras/shaders/contrast_fs_gl.inc new file mode 100644 index 00000000..97f78194 --- /dev/null +++ b/src/extras/shaders/contrast_fs_gl.inc @@ -0,0 +1,21 @@ +const char *contrast_frag_src = +"uniform sampler2D tex0;\n" +"uniform vec3 u_contrastAdd;\n" +"uniform vec3 u_contrastMult;\n" + +"FSIN vec4 v_color;\n" +"FSIN vec2 v_tex0;\n" +"FSIN float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 dst = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" +" vec4 color;\n" +" color.rgb = dst.rgb*u_contrastMult + u_contrastAdd;\n" +" color.a = 1.0f;\n" + +" FRAGCOLOR(color);\n" +"}\n" + +; diff --git a/src/extras/shaders/default_UV2.vert b/src/extras/shaders/default_UV2.vert index 3dbad20f..694c012b 100644 --- a/src/extras/shaders/default_UV2.vert +++ b/src/extras/shaders/default_UV2.vert @@ -1,13 +1,9 @@ -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; -layout(location = 4) in vec2 in_tex1; +VSIN(ATTRIB_POS) vec3 in_pos; -out vec4 v_color; -out vec2 v_tex0; -out vec2 v_tex1; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec2 v_tex0; +VSOUT vec2 v_tex1; +VSOUT float v_fog; void main(void) diff --git a/src/extras/shaders/default_UV2_gl.inc b/src/extras/shaders/default_UV2_gl.inc new file mode 100644 index 00000000..450f3d9a --- /dev/null +++ b/src/extras/shaders/default_UV2_gl.inc @@ -0,0 +1,27 @@ +const char *default_UV2_vert_src = +"VSIN(ATTRIB_POS) vec3 in_pos;\n" + +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT vec2 v_tex1;\n" +"VSOUT float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" +" gl_Position = u_proj * u_view * Vertex;\n" +" vec3 Normal = mat3(u_world) * in_normal;\n" + +" v_tex0 = in_tex0;\n" +" v_tex1 = in_tex1;\n" + +" v_color = in_color;\n" +" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" +" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n" +" v_color = clamp(v_color, 0.0, 1.0);\n" +" v_color *= u_matColor;\n" + +" v_fog = DoFog(gl_Position.w);\n" +"}\n" +; diff --git a/src/extras/shaders/im2d.vert b/src/extras/shaders/im2d.vert index 241593b1..fcd81c2c 100644 --- a/src/extras/shaders/im2d.vert +++ b/src/extras/shaders/im2d.vert @@ -1,12 +1,10 @@ uniform vec4 u_xform; -layout(location = 0) in vec4 in_pos; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; +VSIN(ATTRIB_POS) vec4 in_pos; -out vec4 v_color; -out vec2 v_tex0; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec2 v_tex0; +VSOUT float v_fog; void main(void) diff --git a/src/extras/shaders/im2d_gl.inc b/src/extras/shaders/im2d_gl.inc new file mode 100644 index 00000000..d11f5d33 --- /dev/null +++ b/src/extras/shaders/im2d_gl.inc @@ -0,0 +1,21 @@ +const char *im2d_vert_src = +"uniform vec4 u_xform;\n" + +"VSIN(ATTRIB_POS) vec4 in_pos;\n" + +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" gl_Position = in_pos;\n" +" gl_Position.w = 1.0;\n" +" gl_Position.xy = gl_Position.xy * u_xform.xy + u_xform.zw;\n" +" v_fog = DoFog(gl_Position.z);\n" +" gl_Position.xyz *= gl_Position.w;\n" +" v_color = in_color;\n" +" v_tex0 = in_tex0;\n" +"}\n" +; diff --git a/src/extras/shaders/neoGloss.frag b/src/extras/shaders/neoGloss.frag index 14ef0e15..4f097b0b 100644 --- a/src/extras/shaders/neoGloss.frag +++ b/src/extras/shaders/neoGloss.frag @@ -4,17 +4,15 @@ uniform vec4 u_reflProps; #define glossMult (u_reflProps.x) -in vec3 v_normal; -in vec3 v_light; -in vec2 v_tex0; -in float v_fog; - -out vec4 color; +FSIN vec3 v_normal; +FSIN vec3 v_light; +FSIN vec2 v_tex0; +FSIN float v_fog; void main(void) { - color = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y)); + vec4 color = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y)); vec3 n = 2.0*v_normal-1.0; // unpack vec3 v = 2.0*v_light-1.0; // @@ -22,5 +20,7 @@ main(void) color = s*s*s*s*s*s*s*s*color*v_fog*glossMult; DoAlphaTest(color.a); + + FRAGCOLOR(color); } diff --git a/src/extras/shaders/neoGloss.vert b/src/extras/shaders/neoGloss.vert index 78dd1b33..41102f3f 100644 --- a/src/extras/shaders/neoGloss.vert +++ b/src/extras/shaders/neoGloss.vert @@ -1,15 +1,11 @@ uniform vec3 u_eye; +VSIN(ATTRIB_POS) vec3 in_pos; -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; - -out vec3 v_normal; -out vec3 v_light; -out vec2 v_tex0; -out float v_fog; +VSOUT vec3 v_normal; +VSOUT vec3 v_light; +VSOUT vec2 v_tex0; +VSOUT float v_fog; void main(void) diff --git a/src/extras/shaders/neoGloss_fs_gl.inc b/src/extras/shaders/neoGloss_fs_gl.inc new file mode 100644 index 00000000..67e9724e --- /dev/null +++ b/src/extras/shaders/neoGloss_fs_gl.inc @@ -0,0 +1,28 @@ +const char *neoGloss_frag_src = +"uniform sampler2D tex0;\n" + +"uniform vec4 u_reflProps;\n" + +"#define glossMult (u_reflProps.x)\n" + +"FSIN vec3 v_normal;\n" +"FSIN vec3 v_light;\n" +"FSIN vec2 v_tex0;\n" +"FSIN float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 color = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" +" vec3 n = 2.0*v_normal-1.0; // unpack\n" +" vec3 v = 2.0*v_light-1.0; //\n" + +" float s = dot(n, v);\n" +" color = s*s*s*s*s*s*s*s*color*v_fog*glossMult;\n" + +" DoAlphaTest(color.a);\n" + +" FRAGCOLOR(color);\n" +"}\n" + +; diff --git a/src/extras/shaders/neoGloss_vs_gl.inc b/src/extras/shaders/neoGloss_vs_gl.inc new file mode 100644 index 00000000..dffb423f --- /dev/null +++ b/src/extras/shaders/neoGloss_vs_gl.inc @@ -0,0 +1,27 @@ +const char *neoGloss_vert_src = +"uniform vec3 u_eye;\n" + +"VSIN(ATTRIB_POS) vec3 in_pos;\n" + +"VSOUT vec3 v_normal;\n" +"VSOUT vec3 v_light;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" +" gl_Position = u_proj * u_view * Vertex;\n" +" vec3 Normal = mat3(u_world) * in_normal;\n" + +" v_tex0 = in_tex0;\n" + +" vec3 viewVec = normalize(u_eye - Vertex.xyz);\n" +" vec3 Light = normalize(viewVec - u_lightDirection[0].xyz);\n" +" v_normal = 0.5*(1.0 + vec3(0.0, 0.0, 1.0)); // compress\n" +" v_light = 0.5*(1.0 + Light); //\n" + +" v_fog = DoFog(gl_Position.w);\n" +"}\n" +; diff --git a/src/extras/shaders/neoRim.vert b/src/extras/shaders/neoRim.vert index 4a2b545f..81ee1090 100644 --- a/src/extras/shaders/neoRim.vert +++ b/src/extras/shaders/neoRim.vert @@ -3,14 +3,11 @@ uniform vec4 u_rampStart; uniform vec4 u_rampEnd; uniform vec3 u_rimData; -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; +VSIN(ATTRIB_POS) vec3 in_pos; -out vec4 v_color; -out vec2 v_tex0; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec2 v_tex0; +VSOUT float v_fog; void main(void) diff --git a/src/extras/shaders/neoRimSkin.vert b/src/extras/shaders/neoRimSkin.vert index f16f2310..1515ad71 100644 --- a/src/extras/shaders/neoRimSkin.vert +++ b/src/extras/shaders/neoRimSkin.vert @@ -5,16 +5,11 @@ uniform vec4 u_rampStart; uniform vec4 u_rampEnd; uniform vec3 u_rimData; -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; -layout(location = 11) in vec4 in_weights; -layout(location = 12) in vec4 in_indices; +VSIN(ATTRIB_POS) vec3 in_pos; -out vec4 v_color; -out vec2 v_tex0; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec2 v_tex0; +VSOUT float v_fog; void main(void) diff --git a/src/extras/shaders/neoRimSkin_gl.inc b/src/extras/shaders/neoRimSkin_gl.inc new file mode 100644 index 00000000..01b739b2 --- /dev/null +++ b/src/extras/shaders/neoRimSkin_gl.inc @@ -0,0 +1,45 @@ +const char *neoRimSkin_vert_src = +"uniform mat4 u_boneMatrices[64];\n" + +"uniform vec3 u_viewVec;\n" +"uniform vec4 u_rampStart;\n" +"uniform vec4 u_rampEnd;\n" +"uniform vec3 u_rimData;\n" + +"VSIN(ATTRIB_POS) vec3 in_pos;\n" + +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec3 SkinVertex = vec3(0.0, 0.0, 0.0);\n" +" vec3 SkinNormal = vec3(0.0, 0.0, 0.0);\n" +" for(int i = 0; i < 4; i++){\n" +" SkinVertex += (u_boneMatrices[int(in_indices[i])] * vec4(in_pos, 1.0)).xyz * in_weights[i];\n" +" SkinNormal += (mat3(u_boneMatrices[int(in_indices[i])]) * in_normal) * in_weights[i];\n" +" }\n" + +" vec4 Vertex = u_world * vec4(SkinVertex, 1.0);\n" +" gl_Position = u_proj * u_view * Vertex;\n" +" vec3 Normal = mat3(u_world) * SkinNormal;\n" + +" v_tex0 = in_tex0;\n" + +" v_color = in_color;\n" +" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" +" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n" + +" // rim light\n" +" float f = u_rimData.x - u_rimData.y*dot(Normal, u_viewVec);\n" +" vec4 rimlight = clamp(mix(u_rampEnd, u_rampStart, f)*u_rimData.z, 0.0, 1.0);\n" +" v_color.rgb += rimlight.rgb;\n" + +" v_color = clamp(v_color, 0.0, 1.0);\n" +" v_color *= u_matColor;\n" + +" v_fog = DoFog(gl_Position.z);\n" +"}\n" +; diff --git a/src/extras/shaders/neoRim_gl.inc b/src/extras/shaders/neoRim_gl.inc new file mode 100644 index 00000000..7cd199d0 --- /dev/null +++ b/src/extras/shaders/neoRim_gl.inc @@ -0,0 +1,36 @@ +const char *neoRim_vert_src = +"uniform vec3 u_viewVec;\n" +"uniform vec4 u_rampStart;\n" +"uniform vec4 u_rampEnd;\n" +"uniform vec3 u_rimData;\n" + +"VSIN(ATTRIB_POS) vec3 in_pos;\n" + +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" +" gl_Position = u_proj * u_view * Vertex;\n" +" vec3 Normal = mat3(u_world) * in_normal;\n" + +" v_tex0 = in_tex0;\n" + +" v_color = in_color;\n" +" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" +" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n" + +" // rim light\n" +" float f = u_rimData.x - u_rimData.y*dot(Normal, u_viewVec);\n" +" vec4 rimlight = clamp(mix(u_rampEnd, u_rampStart, f)*u_rimData.z, 0.0, 1.0);\n" +" v_color.rgb += rimlight.rgb;\n" + +" v_color = clamp(v_color, 0.0, 1.0);\n" +" v_color *= u_matColor;\n" + +" v_fog = DoFog(gl_Position.w);\n" +"}\n" +; diff --git a/src/extras/shaders/neoVehicle.frag b/src/extras/shaders/neoVehicle.frag index 96d4a632..2ac24f70 100644 --- a/src/extras/shaders/neoVehicle.frag +++ b/src/extras/shaders/neoVehicle.frag @@ -1,13 +1,11 @@ uniform sampler2D tex0; uniform sampler2D tex1; -in vec4 v_color; -in vec4 v_reflcolor; -in vec2 v_tex0; -in vec2 v_tex1; -in float v_fog; - -out vec4 color; +FSIN vec4 v_color; +FSIN vec4 v_reflcolor; +FSIN vec2 v_tex0; +FSIN vec2 v_tex1; +FSIN float v_fog; void main(void) @@ -20,9 +18,12 @@ main(void) vec3 pass2 = v_reflcolor.rgb * v_fog; + vec4 color; color.rgb = pass1.rgb*pass1.a + pass2; color.a = pass1.a; // color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog); DoAlphaTest(color.a); + + FRAGCOLOR(color); } diff --git a/src/extras/shaders/neoVehicle.vert b/src/extras/shaders/neoVehicle.vert index f2f54d6d..f0224ddb 100644 --- a/src/extras/shaders/neoVehicle.vert +++ b/src/extras/shaders/neoVehicle.vert @@ -8,16 +8,13 @@ uniform vec4 u_specColor[5]; #define shininess (u_reflProps.z) #define specularity (u_reflProps.w) -layout(location = 0) in vec3 in_pos; -layout(location = 1) in vec3 in_normal; -layout(location = 2) in vec4 in_color; -layout(location = 3) in vec2 in_tex0; +VSIN(ATTRIB_POS) vec3 in_pos; -out vec4 v_color; -out vec4 v_reflcolor; -out vec2 v_tex0; -out vec2 v_tex1; -out float v_fog; +VSOUT vec4 v_color; +VSOUT vec4 v_reflcolor; +VSOUT vec2 v_tex0; +VSOUT vec2 v_tex1; +VSOUT float v_fog; vec3 DoDirLightSpec(vec3 Ldir, vec3 Lcol, vec3 N, vec3 V, float power) { diff --git a/src/extras/shaders/neoVehicle_fs_gl.inc b/src/extras/shaders/neoVehicle_fs_gl.inc new file mode 100644 index 00000000..20537440 --- /dev/null +++ b/src/extras/shaders/neoVehicle_fs_gl.inc @@ -0,0 +1,31 @@ +const char *neoVehicle_frag_src = +"uniform sampler2D tex0;\n" +"uniform sampler2D tex1;\n" + +"FSIN vec4 v_color;\n" +"FSIN vec4 v_reflcolor;\n" +"FSIN vec2 v_tex0;\n" +"FSIN vec2 v_tex1;\n" +"FSIN float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" +" vec3 envmap = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y)).rgb;\n" +" pass1.rgb = mix(pass1.rgb, envmap, v_reflcolor.a);\n" +" pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);\n" +"// pass1.rgb += v_reflcolor.rgb * v_fog;\n" + +" vec3 pass2 = v_reflcolor.rgb * v_fog;\n" + +" vec4 color;\n" +" color.rgb = pass1.rgb*pass1.a + pass2;\n" +" color.a = pass1.a;\n" + +"// color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n" +" DoAlphaTest(color.a);\n" + +" FRAGCOLOR(color);\n" +"}\n" +; diff --git a/src/extras/shaders/neoVehicle_vs_gl.inc b/src/extras/shaders/neoVehicle_vs_gl.inc new file mode 100644 index 00000000..b7b42622 --- /dev/null +++ b/src/extras/shaders/neoVehicle_vs_gl.inc @@ -0,0 +1,53 @@ +const char *neoVehicle_vert_src = +"uniform vec3 u_eye;\n" +"uniform vec4 u_reflProps;\n" +"uniform vec4 u_specDir[5];\n" +"uniform vec4 u_specColor[5];\n" + +"#define fresnel (u_reflProps.x)\n" +"#define lightStrength (u_reflProps.y) // speclight alpha\n" +"#define shininess (u_reflProps.z)\n" +"#define specularity (u_reflProps.w)\n" + +"VSIN(ATTRIB_POS) vec3 in_pos;\n" + +"VSOUT vec4 v_color;\n" +"VSOUT vec4 v_reflcolor;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT vec2 v_tex1;\n" +"VSOUT float v_fog;\n" + +"vec3 DoDirLightSpec(vec3 Ldir, vec3 Lcol, vec3 N, vec3 V, float power)\n" +"{\n" +" return pow(clamp(dot(N, normalize(V + -Ldir)), 0.0, 1.0), power)*Lcol;\n" +"}\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" +" gl_Position = u_proj * u_view * Vertex;\n" +" vec3 Normal = mat3(u_world) * in_normal;\n" +" vec3 viewVec = normalize(u_eye - Vertex.xyz);\n" + +" v_tex0 = in_tex0;\n" + +" v_color = in_color;\n" +" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" +" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse*lightStrength;\n" +" v_color = clamp(v_color, 0.0, 1.0);\n" +" v_color *= u_matColor;\n" + +" // reflect V along Normal\n" +" vec3 uv2 = Normal*dot(viewVec, Normal)*2.0 - viewVec;\n" +" v_tex1 = uv2.xy*0.5 + 0.5;\n" +" float b = 1.0 - clamp(dot(viewVec, Normal), 0.0, 1.0);\n" +" v_reflcolor = vec4(0.0, 0.0, 0.0, 1.0);\n" +" v_reflcolor.a = mix(b*b*b*b*b, 1.0f, fresnel)*shininess;\n" + +" for(int i = 0; i < 5; i++)\n" +" v_reflcolor.rgb += DoDirLightSpec(u_specDir[i].xyz, u_specColor[i].rgb, Normal, viewVec, u_specDir[i].w)*specularity*lightStrength;\n" + +" v_fog = DoFog(gl_Position.w);\n" +"}\n" +; diff --git a/src/extras/shaders/neoWorldIII.frag b/src/extras/shaders/neoWorldIII.frag index 4c5571ee..d8bb7159 100644 --- a/src/extras/shaders/neoWorldIII.frag +++ b/src/extras/shaders/neoWorldIII.frag @@ -3,12 +3,10 @@ uniform sampler2D tex1; uniform vec4 u_lightMap; -in vec4 v_color; -in vec2 v_tex0; -in vec2 v_tex1; -in float v_fog; - -out vec4 color; +FSIN vec4 v_color; +FSIN vec2 v_tex0; +FSIN vec2 v_tex1; +FSIN float v_fog; void main(void) @@ -16,10 +14,12 @@ main(void) vec4 t0 = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y)); vec4 t1 = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y)); - color = t0*v_color*(1 + u_lightMap*(2*t1-1)); + vec4 color = t0*v_color*(1.0 + u_lightMap*(2.0*t1-1.0)); color.a = v_color.a*t0.a*u_lightMap.a; color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog); DoAlphaTest(color.a); + + FRAGCOLOR(color); } diff --git a/src/extras/shaders/neoWorldIII_fs_gl.inc b/src/extras/shaders/neoWorldIII_fs_gl.inc new file mode 100644 index 00000000..afd75f57 --- /dev/null +++ b/src/extras/shaders/neoWorldIII_fs_gl.inc @@ -0,0 +1,27 @@ +const char *neoWorldIII_frag_src = +"uniform sampler2D tex0;\n" +"uniform sampler2D tex1;\n" + +"uniform vec4 u_lightMap;\n" + +"FSIN vec4 v_color;\n" +"FSIN vec2 v_tex0;\n" +"FSIN vec2 v_tex1;\n" +"FSIN float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 t0 = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" +" vec4 t1 = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y));\n" + +" vec4 color = t0*v_color*(1.0 + u_lightMap*(2.0*t1-1.0));\n" +" color.a = v_color.a*t0.a*u_lightMap.a;\n" + +" color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n" +" DoAlphaTest(color.a);\n" + +" FRAGCOLOR(color);\n" +"}\n" + +; diff --git a/src/extras/shaders/simple.frag b/src/extras/shaders/simple.frag index 87157beb..c85bf089 100644 --- a/src/extras/shaders/simple.frag +++ b/src/extras/shaders/simple.frag @@ -1,16 +1,17 @@ uniform sampler2D tex0; -in vec4 v_color; -in vec2 v_tex0; -in float v_fog; - -out vec4 color; +FSIN vec4 v_color; +FSIN vec2 v_tex0; +FSIN float v_fog; void main(void) { + vec4 color; color = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y)); color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog); DoAlphaTest(color.a); + + FRAGCOLOR(color); } diff --git a/src/extras/shaders/simple_fs_gl.inc b/src/extras/shaders/simple_fs_gl.inc new file mode 100644 index 00000000..614d79a0 --- /dev/null +++ b/src/extras/shaders/simple_fs_gl.inc @@ -0,0 +1,19 @@ +const char *simple_frag_src = +"uniform sampler2D tex0;\n" + +"FSIN vec4 v_color;\n" +"FSIN vec2 v_tex0;\n" +"FSIN float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" vec4 color;\n" +" color = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" +" color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n" +" DoAlphaTest(color.a);\n" + +" FRAGCOLOR(color);\n" +"}\n" + +; diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 460b8211..64a37421 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -935,16 +935,3 @@ RtCharset *RtCharsetSetColors(RtCharset * charSet, const RwRGBA * foreGround, RtCharset *RtCharsetGetDesc(RtCharset * charset, RtCharsetDesc * desc) { *desc = charset->desc; return charset; } RtCharset *RtCharsetCreate(const RwRGBA * foreGround, const RwRGBA * backGround) { return Charset::create(foreGround, backGround); } RwBool RtCharsetDestroy(RtCharset * charSet) { charSet->destroy(); return true; } - - - -// fake shit -RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags) -{ -#ifdef RW_GL3 - if(flags & (rwRASTERFORMATPAL8 | rwRASTERFORMAT8888)) - return 'NOPE'; - return 'YUP'; -#endif - return flags & 0xF00; -} diff --git a/src/rw/TexRead.cpp b/src/rw/TexRead.cpp index 33d9a4cb..0a0ed04b 100644 --- a/src/rw/TexRead.cpp +++ b/src/rw/TexRead.cpp @@ -150,11 +150,80 @@ RwTexDictionaryGtaStreamRead2(RwStream *stream, RwTexDictionary *texDict) } #ifdef GTA_PC -#ifdef RWLIBS -extern "C" RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags); -#else -RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags); + +#ifdef LIBRW + +#define CAPSVERSION 0 + +struct GPUcaps +{ + uint32 version; // so we can force regeneration easily + uint32 platform; + uint32 subplatform; + uint32 dxtSupport; +}; + +static void +GetGPUcaps(GPUcaps *caps) +{ + caps->version = CAPSVERSION; + caps->platform = rw::platform; + caps->subplatform = 0; + caps->dxtSupport = 0; + // TODO: more later +#ifdef RW_GL3 + caps->subplatform = rw::gl3::gl3Caps.gles; + caps->dxtSupport = rw::gl3::gl3Caps.dxtSupported; #endif +#ifdef RW_D3D9 + caps->dxtSupport = 1; // TODO, probably +#endif +} + +void +ReadVideoCardCapsFile(GPUcaps *caps) +{ + memset(caps, 0, sizeof(GPUcaps)); + + int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "rb"); + if (file != 0) { + CFileMgr::Read(file, (char*)&caps->version, 4); + CFileMgr::Read(file, (char*)&caps->platform, 4); + CFileMgr::Read(file, (char*)&caps->subplatform, 4); + CFileMgr::Read(file, (char*)&caps->dxtSupport, 4); + CFileMgr::CloseFile(file); + } +} + +bool +CheckVideoCardCaps(void) +{ + GPUcaps caps, fcaps; + GetGPUcaps(&caps); + ReadVideoCardCapsFile(&fcaps); + return caps.version != fcaps.version || + caps.platform != fcaps.platform || + caps.subplatform != fcaps.subplatform || + caps.dxtSupport != fcaps.dxtSupport; +} + +void +WriteVideoCardCapsFile(void) +{ + GPUcaps caps; + GetGPUcaps(&caps); + int32 file = CFileMgr::OpenFile("DATA\\CAPS.DAT", "wb"); + if (file != 0) { + CFileMgr::Write(file, (char*)&caps.version, 4); + CFileMgr::Write(file, (char*)&caps.platform, 4); + CFileMgr::Write(file, (char*)&caps.subplatform, 4); + CFileMgr::Write(file, (char*)&caps.dxtSupport, 4); + CFileMgr::CloseFile(file); + } +} + +#else +extern "C" RwInt32 _rwD3D8FindCorrectRasterFormat(RwRasterType type, RwInt32 flags); void ReadVideoCardCapsFile(uint32 &cap32, uint32 &cap24, uint32 &cap16, uint32 &cap8) { @@ -201,6 +270,7 @@ WriteVideoCardCapsFile(void) CFileMgr::CloseFile(file); } } +#endif void ConvertingTexturesScreen(uint32 num, uint32 count, const char *text) @@ -281,6 +351,13 @@ CreateTxdImageForVideoCard() return false; } +#ifdef LIBRW + // so we can read back DXT with GLES + // only works for textures that are not yet loaded + // so let's hope that is the case for all + rw::gl3::needToReadBackTextures = true; +#endif + int32 i; for (i = 0; i < TXDSTORESIZE; i++) { ConvertingTexturesScreen(i, TXDSTORESIZE, "CVT_MSG"); @@ -308,6 +385,9 @@ CreateTxdImageForVideoCard() delete []buf; delete pDir; CStreaming::RemoveTxd(i); +#ifdef LIBRW + rw::gl3::needToReadBackTextures = false; +#endif return false; } @@ -334,6 +414,10 @@ CreateTxdImageForVideoCard() RwStreamClose(img, nil); delete []buf; +#ifdef LIBRW + rw::gl3::needToReadBackTextures = false; +#endif + if (!pDir->WriteDirFile("models\\txd.dir")) { DealWithTxdWriteError(i, TXDSTORESIZE, "CVT_ERR"); delete pDir; diff --git a/vendor/librw b/vendor/librw index 7e80d45c..4ac67e5d 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit 7e80d45cdb6663f97d89ed443198ce6e37c4435e +Subproject commit 4ac67e5df87da7d94725789cedad2b69e8687007 From 498a2795d9a2c42e7321d5c711bdc7e851e27ea1 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Wed, 18 Nov 2020 10:38:31 +0100 Subject: [PATCH 064/129] Fix CI --- .github/workflows/re3_msvc_amd64.yml | 2 +- .github/workflows/re3_msvc_x86.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/re3_msvc_amd64.yml b/.github/workflows/re3_msvc_amd64.yml index 07b793ba..8f22af56 100644 --- a/.github/workflows/re3_msvc_amd64.yml +++ b/.github/workflows/re3_msvc_amd64.yml @@ -23,7 +23,7 @@ jobs: buildtype: [Debug, Release] steps: - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.0.1 + uses: microsoft/setup-msbuild@v1.0.2 - uses: actions/checkout@v2 with: submodules: 'true' diff --git a/.github/workflows/re3_msvc_x86.yml b/.github/workflows/re3_msvc_x86.yml index 34e892cf..c0432280 100644 --- a/.github/workflows/re3_msvc_x86.yml +++ b/.github/workflows/re3_msvc_x86.yml @@ -23,7 +23,7 @@ jobs: buildtype: [Debug, Release] steps: - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1.0.1 + uses: microsoft/setup-msbuild@v1.0.2 - uses: actions/checkout@v2 with: submodules: 'true' From 9826fdf6d5a324b316e59a34feeb0da9ffca56cc Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 11:16:02 +0100 Subject: [PATCH 065/129] more fixes to librw stuff --- src/extras/shaders/colourfilterIII_fs_gl3.inc | 25 --------- src/extras/shaders/contrast_fs_gl3.inc | 20 ------- src/extras/shaders/default_UV2_gl3.inc | 31 ---------- src/extras/shaders/im2d_gl3.inc | 23 -------- src/extras/shaders/neoGloss_fs_gl3.inc | 28 ---------- src/extras/shaders/neoGloss_vs_gl3.inc | 31 ---------- src/extras/shaders/neoRimSkin_gl3.inc | 50 ----------------- src/extras/shaders/neoRim_gl3.inc | 39 ------------- src/extras/shaders/neoVehicle_fs_gl3.inc | 30 ---------- src/extras/shaders/neoVehicle_vs_gl3.inc | 56 ------------------- src/extras/shaders/neoWorldIII_fs_gl3.inc | 27 --------- src/extras/shaders/simple_fs_gl3.inc | 18 ------ src/rw/TexRead.cpp | 6 +- vendor/librw | 2 +- 14 files changed, 4 insertions(+), 382 deletions(-) delete mode 100644 src/extras/shaders/colourfilterIII_fs_gl3.inc delete mode 100644 src/extras/shaders/contrast_fs_gl3.inc delete mode 100644 src/extras/shaders/default_UV2_gl3.inc delete mode 100644 src/extras/shaders/im2d_gl3.inc delete mode 100644 src/extras/shaders/neoGloss_fs_gl3.inc delete mode 100644 src/extras/shaders/neoGloss_vs_gl3.inc delete mode 100644 src/extras/shaders/neoRimSkin_gl3.inc delete mode 100644 src/extras/shaders/neoRim_gl3.inc delete mode 100644 src/extras/shaders/neoVehicle_fs_gl3.inc delete mode 100644 src/extras/shaders/neoVehicle_vs_gl3.inc delete mode 100644 src/extras/shaders/neoWorldIII_fs_gl3.inc delete mode 100644 src/extras/shaders/simple_fs_gl3.inc diff --git a/src/extras/shaders/colourfilterIII_fs_gl3.inc b/src/extras/shaders/colourfilterIII_fs_gl3.inc deleted file mode 100644 index 5530a4fa..00000000 --- a/src/extras/shaders/colourfilterIII_fs_gl3.inc +++ /dev/null @@ -1,25 +0,0 @@ -const char *colourfilterIII_frag_src = -"uniform sampler2D tex0;\n" -"uniform vec4 u_blurcolor;\n" - -"in vec4 v_color;\n" -"in vec2 v_tex0;\n" -"in float v_fog;\n" - -"out vec4 color;\n" - -"void\n" -"main(void)\n" -"{\n" -" float a = u_blurcolor.a;\n" -" vec4 dst = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" -" vec4 prev = dst;\n" -" for(int i = 0; i < 5; i++){\n" -" vec4 tmp = dst*(1.0-a) + prev*u_blurcolor*a;\n" -" prev = clamp(tmp, 0.0, 1.0);\n" -" }\n" -" color.rgb = prev.rgb;\n" -" color.a = 1.0f;\n" -"}\n" - -; diff --git a/src/extras/shaders/contrast_fs_gl3.inc b/src/extras/shaders/contrast_fs_gl3.inc deleted file mode 100644 index 58aaf079..00000000 --- a/src/extras/shaders/contrast_fs_gl3.inc +++ /dev/null @@ -1,20 +0,0 @@ -const char *contrast_frag_src = -"uniform sampler2D tex0;\n" -"uniform vec3 u_contrastAdd;\n" -"uniform vec3 u_contrastMult;\n" - -"in vec4 v_color;\n" -"in vec2 v_tex0;\n" -"in float v_fog;\n" - -"out vec4 color;\n" - -"void\n" -"main(void)\n" -"{\n" -" vec4 dst = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" -" color.rgb = dst.rgb*u_contrastMult + u_contrastAdd;\n" -" color.a = 1.0f;\n" -"}\n" - -; diff --git a/src/extras/shaders/default_UV2_gl3.inc b/src/extras/shaders/default_UV2_gl3.inc deleted file mode 100644 index 14106b29..00000000 --- a/src/extras/shaders/default_UV2_gl3.inc +++ /dev/null @@ -1,31 +0,0 @@ -const char *default_UV2_vert_src = -"layout(location = 0) in vec3 in_pos;\n" -"layout(location = 1) in vec3 in_normal;\n" -"layout(location = 2) in vec4 in_color;\n" -"layout(location = 3) in vec2 in_tex0;\n" -"layout(location = 4) in vec2 in_tex1;\n" - -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out vec2 v_tex1;\n" -"out float v_fog;\n" - -"void\n" -"main(void)\n" -"{\n" -" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" -" gl_Position = u_proj * u_view * Vertex;\n" -" vec3 Normal = mat3(u_world) * in_normal;\n" - -" v_tex0 = in_tex0;\n" -" v_tex1 = in_tex1;\n" - -" v_color = in_color;\n" -" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" -" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n" -" v_color = clamp(v_color, 0.0, 1.0);\n" -" v_color *= u_matColor;\n" - -" v_fog = DoFog(gl_Position.w);\n" -"}\n" -; diff --git a/src/extras/shaders/im2d_gl3.inc b/src/extras/shaders/im2d_gl3.inc deleted file mode 100644 index 68341b39..00000000 --- a/src/extras/shaders/im2d_gl3.inc +++ /dev/null @@ -1,23 +0,0 @@ -const char *im2d_vert_src = -"uniform vec4 u_xform;\n" - -"layout(location = 0) in vec4 in_pos;\n" -"layout(location = 2) in vec4 in_color;\n" -"layout(location = 3) in vec2 in_tex0;\n" - -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out float v_fog;\n" - -"void\n" -"main(void)\n" -"{\n" -" gl_Position = in_pos;\n" -" gl_Position.w = 1.0;\n" -" gl_Position.xy = gl_Position.xy * u_xform.xy + u_xform.zw;\n" -" v_fog = DoFog(gl_Position.z);\n" -" gl_Position.xyz *= gl_Position.w;\n" -" v_color = in_color;\n" -" v_tex0 = in_tex0;\n" -"}\n" -; diff --git a/src/extras/shaders/neoGloss_fs_gl3.inc b/src/extras/shaders/neoGloss_fs_gl3.inc deleted file mode 100644 index 736b0c5d..00000000 --- a/src/extras/shaders/neoGloss_fs_gl3.inc +++ /dev/null @@ -1,28 +0,0 @@ -const char *neoGloss_frag_src = -"uniform sampler2D tex0;\n" - -"uniform vec4 u_reflProps;\n" - -"#define glossMult (u_reflProps.x)\n" - -"in vec3 v_normal;\n" -"in vec3 v_light;\n" -"in vec2 v_tex0;\n" -"in float v_fog;\n" - -"out vec4 color;\n" - -"void\n" -"main(void)\n" -"{\n" -" color = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" -" vec3 n = 2.0*v_normal-1.0; // unpack\n" -" vec3 v = 2.0*v_light-1.0; //\n" - -" float s = dot(n, v);\n" -" color = s*s*s*s*s*s*s*s*color*v_fog*glossMult;\n" - -" DoAlphaTest(color.a);\n" -"}\n" - -; diff --git a/src/extras/shaders/neoGloss_vs_gl3.inc b/src/extras/shaders/neoGloss_vs_gl3.inc deleted file mode 100644 index 4adc9cb2..00000000 --- a/src/extras/shaders/neoGloss_vs_gl3.inc +++ /dev/null @@ -1,31 +0,0 @@ -const char *neoGloss_vert_src = -"uniform vec3 u_eye;\n" - - -"layout(location = 0) in vec3 in_pos;\n" -"layout(location = 1) in vec3 in_normal;\n" -"layout(location = 2) in vec4 in_color;\n" -"layout(location = 3) in vec2 in_tex0;\n" - -"out vec3 v_normal;\n" -"out vec3 v_light;\n" -"out vec2 v_tex0;\n" -"out float v_fog;\n" - -"void\n" -"main(void)\n" -"{\n" -" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" -" gl_Position = u_proj * u_view * Vertex;\n" -" vec3 Normal = mat3(u_world) * in_normal;\n" - -" v_tex0 = in_tex0;\n" - -" vec3 viewVec = normalize(u_eye - Vertex.xyz);\n" -" vec3 Light = normalize(viewVec - u_lightDirection[0].xyz);\n" -" v_normal = 0.5*(1.0 + vec3(0.0, 0.0, 1.0)); // compress\n" -" v_light = 0.5*(1.0 + Light); //\n" - -" v_fog = DoFog(gl_Position.w);\n" -"}\n" -; diff --git a/src/extras/shaders/neoRimSkin_gl3.inc b/src/extras/shaders/neoRimSkin_gl3.inc deleted file mode 100644 index 70948e1f..00000000 --- a/src/extras/shaders/neoRimSkin_gl3.inc +++ /dev/null @@ -1,50 +0,0 @@ -const char *neoRimSkin_vert_src = -"uniform mat4 u_boneMatrices[64];\n" - -"uniform vec3 u_viewVec;\n" -"uniform vec4 u_rampStart;\n" -"uniform vec4 u_rampEnd;\n" -"uniform vec3 u_rimData;\n" - -"layout(location = 0) in vec3 in_pos;\n" -"layout(location = 1) in vec3 in_normal;\n" -"layout(location = 2) in vec4 in_color;\n" -"layout(location = 3) in vec2 in_tex0;\n" -"layout(location = 11) in vec4 in_weights;\n" -"layout(location = 12) in vec4 in_indices;\n" - -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out float v_fog;\n" - -"void\n" -"main(void)\n" -"{\n" -" vec3 SkinVertex = vec3(0.0, 0.0, 0.0);\n" -" vec3 SkinNormal = vec3(0.0, 0.0, 0.0);\n" -" for(int i = 0; i < 4; i++){\n" -" SkinVertex += (u_boneMatrices[int(in_indices[i])] * vec4(in_pos, 1.0)).xyz * in_weights[i];\n" -" SkinNormal += (mat3(u_boneMatrices[int(in_indices[i])]) * in_normal) * in_weights[i];\n" -" }\n" - -" vec4 Vertex = u_world * vec4(SkinVertex, 1.0);\n" -" gl_Position = u_proj * u_view * Vertex;\n" -" vec3 Normal = mat3(u_world) * SkinNormal;\n" - -" v_tex0 = in_tex0;\n" - -" v_color = in_color;\n" -" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" -" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n" - -" // rim light\n" -" float f = u_rimData.x - u_rimData.y*dot(Normal, u_viewVec);\n" -" vec4 rimlight = clamp(mix(u_rampEnd, u_rampStart, f)*u_rimData.z, 0.0, 1.0);\n" -" v_color.rgb += rimlight.rgb;\n" - -" v_color = clamp(v_color, 0.0, 1.0);\n" -" v_color *= u_matColor;\n" - -" v_fog = DoFog(gl_Position.z);\n" -"}\n" -; diff --git a/src/extras/shaders/neoRim_gl3.inc b/src/extras/shaders/neoRim_gl3.inc deleted file mode 100644 index 7e36e95a..00000000 --- a/src/extras/shaders/neoRim_gl3.inc +++ /dev/null @@ -1,39 +0,0 @@ -const char *neoRim_vert_src = -"uniform vec3 u_viewVec;\n" -"uniform vec4 u_rampStart;\n" -"uniform vec4 u_rampEnd;\n" -"uniform vec3 u_rimData;\n" - -"layout(location = 0) in vec3 in_pos;\n" -"layout(location = 1) in vec3 in_normal;\n" -"layout(location = 2) in vec4 in_color;\n" -"layout(location = 3) in vec2 in_tex0;\n" - -"out vec4 v_color;\n" -"out vec2 v_tex0;\n" -"out float v_fog;\n" - -"void\n" -"main(void)\n" -"{\n" -" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" -" gl_Position = u_proj * u_view * Vertex;\n" -" vec3 Normal = mat3(u_world) * in_normal;\n" - -" v_tex0 = in_tex0;\n" - -" v_color = in_color;\n" -" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" -" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse;\n" - -" // rim light\n" -" float f = u_rimData.x - u_rimData.y*dot(Normal, u_viewVec);\n" -" vec4 rimlight = clamp(mix(u_rampEnd, u_rampStart, f)*u_rimData.z, 0.0, 1.0);\n" -" v_color.rgb += rimlight.rgb;\n" - -" v_color = clamp(v_color, 0.0, 1.0);\n" -" v_color *= u_matColor;\n" - -" v_fog = DoFog(gl_Position.w);\n" -"}\n" -; diff --git a/src/extras/shaders/neoVehicle_fs_gl3.inc b/src/extras/shaders/neoVehicle_fs_gl3.inc deleted file mode 100644 index c75ba717..00000000 --- a/src/extras/shaders/neoVehicle_fs_gl3.inc +++ /dev/null @@ -1,30 +0,0 @@ -const char *neoVehicle_frag_src = -"uniform sampler2D tex0;\n" -"uniform sampler2D tex1;\n" - -"in vec4 v_color;\n" -"in vec4 v_reflcolor;\n" -"in vec2 v_tex0;\n" -"in vec2 v_tex1;\n" -"in float v_fog;\n" - -"out vec4 color;\n" - -"void\n" -"main(void)\n" -"{\n" -" vec4 pass1 = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" -" vec3 envmap = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y)).rgb;\n" -" pass1.rgb = mix(pass1.rgb, envmap, v_reflcolor.a);\n" -" pass1.rgb = mix(u_fogColor.rgb, pass1.rgb, v_fog);\n" -"// pass1.rgb += v_reflcolor.rgb * v_fog;\n" - -" vec3 pass2 = v_reflcolor.rgb * v_fog;\n" - -" color.rgb = pass1.rgb*pass1.a + pass2;\n" -" color.a = pass1.a;\n" - -"// color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n" -" DoAlphaTest(color.a);\n" -"}\n" -; diff --git a/src/extras/shaders/neoVehicle_vs_gl3.inc b/src/extras/shaders/neoVehicle_vs_gl3.inc deleted file mode 100644 index 268180e1..00000000 --- a/src/extras/shaders/neoVehicle_vs_gl3.inc +++ /dev/null @@ -1,56 +0,0 @@ -const char *neoVehicle_vert_src = -"uniform vec3 u_eye;\n" -"uniform vec4 u_reflProps;\n" -"uniform vec4 u_specDir[5];\n" -"uniform vec4 u_specColor[5];\n" - -"#define fresnel (u_reflProps.x)\n" -"#define lightStrength (u_reflProps.y) // speclight alpha\n" -"#define shininess (u_reflProps.z)\n" -"#define specularity (u_reflProps.w)\n" - -"layout(location = 0) in vec3 in_pos;\n" -"layout(location = 1) in vec3 in_normal;\n" -"layout(location = 2) in vec4 in_color;\n" -"layout(location = 3) in vec2 in_tex0;\n" - -"out vec4 v_color;\n" -"out vec4 v_reflcolor;\n" -"out vec2 v_tex0;\n" -"out vec2 v_tex1;\n" -"out float v_fog;\n" - -"vec3 DoDirLightSpec(vec3 Ldir, vec3 Lcol, vec3 N, vec3 V, float power)\n" -"{\n" -" return pow(clamp(dot(N, normalize(V + -Ldir)), 0.0, 1.0), power)*Lcol;\n" -"}\n" - -"void\n" -"main(void)\n" -"{\n" -" vec4 Vertex = u_world * vec4(in_pos, 1.0);\n" -" gl_Position = u_proj * u_view * Vertex;\n" -" vec3 Normal = mat3(u_world) * in_normal;\n" -" vec3 viewVec = normalize(u_eye - Vertex.xyz);\n" - -" v_tex0 = in_tex0;\n" - -" v_color = in_color;\n" -" v_color.rgb += u_ambLight.rgb*surfAmbient;\n" -" v_color.rgb += DoDynamicLight(Vertex.xyz, Normal)*surfDiffuse*lightStrength;\n" -" v_color = clamp(v_color, 0.0, 1.0);\n" -" v_color *= u_matColor;\n" - -" // reflect V along Normal\n" -" vec3 uv2 = Normal*dot(viewVec, Normal)*2.0 - viewVec;\n" -" v_tex1 = uv2.xy*0.5 + 0.5;\n" -" float b = 1.0 - clamp(dot(viewVec, Normal), 0.0, 1.0);\n" -" v_reflcolor = vec4(0.0, 0.0, 0.0, 1.0);\n" -" v_reflcolor.a = mix(b*b*b*b*b, 1.0f, fresnel)*shininess;\n" - -" for(int i = 0; i < 5; i++)\n" -" v_reflcolor.rgb += DoDirLightSpec(u_specDir[i].xyz, u_specColor[i].rgb, Normal, viewVec, u_specDir[i].w)*specularity*lightStrength;\n" - -" v_fog = DoFog(gl_Position.w);\n" -"}\n" -; diff --git a/src/extras/shaders/neoWorldIII_fs_gl3.inc b/src/extras/shaders/neoWorldIII_fs_gl3.inc deleted file mode 100644 index 5145f9cd..00000000 --- a/src/extras/shaders/neoWorldIII_fs_gl3.inc +++ /dev/null @@ -1,27 +0,0 @@ -const char *neoWorldIII_frag_src = -"uniform sampler2D tex0;\n" -"uniform sampler2D tex1;\n" - -"uniform vec4 u_lightMap;\n" - -"in vec4 v_color;\n" -"in vec2 v_tex0;\n" -"in vec2 v_tex1;\n" -"in float v_fog;\n" - -"out vec4 color;\n" - -"void\n" -"main(void)\n" -"{\n" -" vec4 t0 = texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" -" vec4 t1 = texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y));\n" - -" color = t0*v_color*(1 + u_lightMap*(2*t1-1));\n" -" color.a = v_color.a*t0.a*u_lightMap.a;\n" - -" color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n" -" DoAlphaTest(color.a);\n" -"}\n" - -; diff --git a/src/extras/shaders/simple_fs_gl3.inc b/src/extras/shaders/simple_fs_gl3.inc deleted file mode 100644 index 47d89971..00000000 --- a/src/extras/shaders/simple_fs_gl3.inc +++ /dev/null @@ -1,18 +0,0 @@ -const char *simple_frag_src = -"uniform sampler2D tex0;\n" - -"in vec4 v_color;\n" -"in vec2 v_tex0;\n" -"in float v_fog;\n" - -"out vec4 color;\n" - -"void\n" -"main(void)\n" -"{\n" -" color = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" -" color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n" -" DoAlphaTest(color.a);\n" -"}\n" - -; diff --git a/src/rw/TexRead.cpp b/src/rw/TexRead.cpp index 0a0ed04b..72d2ae17 100644 --- a/src/rw/TexRead.cpp +++ b/src/rw/TexRead.cpp @@ -351,7 +351,7 @@ CreateTxdImageForVideoCard() return false; } -#ifdef LIBRW +#ifdef RW_GL3 // so we can read back DXT with GLES // only works for textures that are not yet loaded // so let's hope that is the case for all @@ -385,7 +385,7 @@ CreateTxdImageForVideoCard() delete []buf; delete pDir; CStreaming::RemoveTxd(i); -#ifdef LIBRW +#ifdef RW_GL3 rw::gl3::needToReadBackTextures = false; #endif return false; @@ -414,7 +414,7 @@ CreateTxdImageForVideoCard() RwStreamClose(img, nil); delete []buf; -#ifdef LIBRW +#ifdef RW_GL3 rw::gl3::needToReadBackTextures = false; #endif diff --git a/vendor/librw b/vendor/librw index 4ac67e5d..d9def88c 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit 4ac67e5df87da7d94725789cedad2b69e8687007 +Subproject commit d9def88c46a742c6bc74bf79021c0f8838480df4 From 91f9c7938ee3d2f68002cfc9ab9733f7e358c503 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 12:38:47 +0100 Subject: [PATCH 066/129] CPed review part1,2 re3 --- src/peds/Ped.cpp | 620 ++++++++++++++++++++----------------------- src/peds/PedChat.cpp | 53 ++-- 2 files changed, 314 insertions(+), 359 deletions(-) diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index b3c5c57b..05e00ec2 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -591,13 +591,11 @@ CPed::AddWeaponModel(int id) void CPed::AimGun(void) { - RwV3d pos; CVector vector; if (m_pSeekTarget) { if (m_pSeekTarget->IsPed()) { - ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(&pos, PED_MID); - vector = pos; + ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(vector, PED_MID); } else { vector = m_pSeekTarget->GetPosition(); } @@ -1987,8 +1985,8 @@ CPed::SortPeds(CPed **list, int min, int max) float middleDist = middleDiff.Magnitude(); int left = max; - int right; - for(right = min; right <= left; ){ + int right = min; + while(right <= left){ float rightDist, leftDist; do { rightDiff = GetPosition() - list[right]->GetPosition(); @@ -2015,31 +2013,7 @@ CPed::SortPeds(CPed **list, int min, int max) void CPed::BuildPedLists(void) { - if ((CTimer::GetFrameCounter() + m_randomSeed) % 16) { - - for(int i = 0; i < ARRAY_SIZE(m_nearPeds); ) { - bool removePed = false; - if (m_nearPeds[i]) { - if (m_nearPeds[i]->IsPointerValid()) { - float distSqr = (GetPosition() - m_nearPeds[i]->GetPosition()).MagnitudeSqr2D(); - if (distSqr > 900.0f) - removePed = true; - } else - removePed = true; - } - if (removePed) { - // If we arrive here, the ped we're checking isn't "near", so we should remove it. - for (int j = i; j < ARRAY_SIZE(m_nearPeds) - 1; j++) { - m_nearPeds[j] = m_nearPeds[j + 1]; - m_nearPeds[j + 1] = nil; - } - // Above loop won't work when it's 9, so we need to empty slot 9. - m_nearPeds[9] = nil; - m_numNearPeds--; - } else - i++; - } - } else { + if (((CTimer::GetFrameCounter() + m_randomSeed) % 16) == 0) { CVector centre = CEntity::GetBoundCentre(); CRect rect(centre.x - 20.0f, centre.y - 20.0f, @@ -2077,6 +2051,29 @@ CPed::BuildPedLists(void) } for (int pedToClear = m_numNearPeds; pedToClear < ARRAY_SIZE(m_nearPeds); pedToClear++) m_nearPeds[pedToClear] = nil; + } else { + for(int i = 0; i < ARRAY_SIZE(m_nearPeds); ) { + bool removePed = false; + if (m_nearPeds[i]) { + if (m_nearPeds[i]->IsPointerValid()) { + float distSqr = (GetPosition() - m_nearPeds[i]->GetPosition()).MagnitudeSqr2D(); + if (distSqr > 900.0f) + removePed = true; + } else + removePed = true; + } + if (removePed) { + // If we arrive here, the ped we're checking isn't "near", so we should remove it. + for (int j = i; j < ARRAY_SIZE(m_nearPeds) - 1; j++) { + m_nearPeds[j] = m_nearPeds[j + 1]; + m_nearPeds[j + 1] = nil; + } + // Above loop won't work on last slot, so we need to empty it. + m_nearPeds[ARRAY_SIZE(m_nearPeds) - 1] = nil; + m_numNearPeds--; + } else + i++; + } } } @@ -2337,13 +2334,13 @@ CPed::CanPedJumpThis(CEntity *unused, CVector *damageNormal = nil) pos.z = ourCol->spheres->center.z - ourCol->spheres->radius * damageNormal->z + pos.z; pos.z = pos.z + 0.05f; float collPower = damageNormal->Magnitude2D(); - if (damageNormal->z <= 0.5f) { - forwardOffset += collPower * ourCol->spheres->radius * forwardOffset; - } else { + if (damageNormal->z > 0.5f) { CVector invDamageNormal(-damageNormal->x, -damageNormal->y, 0.0f); invDamageNormal *= 1.0f / collPower; CVector estimatedJumpDist = invDamageNormal + collPower * invDamageNormal * ourCol->spheres->radius; forwardOffset = estimatedJumpDist * Min(2.0f / collPower, 4.0f); + } else { + forwardOffset += collPower * ourCol->spheres->radius * forwardOffset; } } else { pos.z -= 0.15f; @@ -2574,7 +2571,9 @@ CPed::SetObjective(eObjective newObj, void *entity) ClearPointGunAt(); #endif bObjectiveCompleted = false; - if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) { + if (IsTemporaryObjective(m_objective) && !IsTemporaryObjective(newObj)) { + m_prevObjective = newObj; + } else { if (m_objective != newObj) { if (IsTemporaryObjective(newObj)) ForceStoredObjective(newObj); @@ -2582,8 +2581,6 @@ CPed::SetObjective(eObjective newObj, void *entity) SetStoredObjective(); } m_objective = newObj; - } else { - m_prevObjective = newObj; } switch (newObj) { @@ -2623,13 +2620,12 @@ CPed::SetObjective(eObjective newObj, void *entity) case OBJECTIVE_FLEE_CAR: m_carInObjective = (CVehicle*)entity; m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); - if (!m_carInObjective->bIsBus || m_leaveCarTimer) - break; - - for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) { - if (m_carInObjective->pPassengers[i] == this) { - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; - break; + if (m_carInObjective->bIsBus && m_leaveCarTimer == 0) { + for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) { + if (m_carInObjective->pPassengers[i] == this) { + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; + break; + } } } @@ -2836,10 +2832,9 @@ CPed::InformMyGangOfAttack(CEntity *attacker) void CPed::QuitEnteringCar(void) { - CAnimBlendAssociation *animAssoc = m_pVehicleAnim; CVehicle *veh = m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; + if (m_pVehicleAnim) + m_pVehicleAnim->blendDelta = -1000.0f; RestartNonPartialAnims(); @@ -2866,11 +2861,10 @@ CPed::QuitEnteringCar(void) ReplaceWeaponWhenExitingVehicle(); if (DyingOrDead()) { - animAssoc = m_pVehicleAnim; - if (animAssoc) { - animAssoc->blendDelta = -4.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->flags &= ~ASSOC_RUNNING; + if (m_pVehicleAnim) { + m_pVehicleAnim->blendDelta = -4.0f; + m_pVehicleAnim->flags |= ASSOC_DELETEFADEDOUT; + m_pVehicleAnim->flags &= ~ASSOC_RUNNING; } } else SetIdle(); @@ -2954,21 +2948,16 @@ CPed::ReactToAttack(CEntity *attacker) bool CPed::TurnBody(void) { - float lookDir; bool turnDone = true; - if (m_pLookTarget) { - const CVector &lookPos = m_pLookTarget->GetPosition(); - - lookDir = CGeneral::GetRadianAngleBetweenPoints( - lookPos.x, - lookPos.y, + if (m_pLookTarget) + m_fLookDirection = CGeneral::GetRadianAngleBetweenPoints( + m_pLookTarget->GetPosition().x, + m_pLookTarget->GetPosition().y, GetPosition().x, GetPosition().y); - } else - lookDir = m_fLookDirection; - float limitedLookDir = CGeneral::LimitRadianAngle(lookDir); + float limitedLookDir = CGeneral::LimitRadianAngle(m_fLookDirection); float currentRot = m_fRotationCur; if (currentRot - PI > limitedLookDir) @@ -3023,12 +3012,12 @@ CPed::Chat(void) } else Say(SOUND_PED_CHAT); - } else if (!RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { + } else { - if (CGeneral::GetRandomNumber() < 20) { + if (CGeneral::GetRandomNumber() < 20 && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); } - if (!bIsTalking) { + if (!bIsTalking && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f); float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f); chatAssoc->SetCurrentTime(chatTime); @@ -4465,10 +4454,10 @@ CPed::SetEvasiveStep(CEntity *reason, uint8 animType) dangerZone = CGeneral::LimitRadianAngle(dangerZone); // So, add or subtract 90deg (jump to left/right) according to that - if (dangerZone <= 0.0f) - angleToFace = HALFPI + vehDirection; - else + if (dangerZone > 0.0f) angleToFace = vehDirection - HALFPI; + else + angleToFace = vehDirection + HALFPI; stepAnim = NUM_ANIMS; if (animType == 0 || animType == 1) @@ -4851,9 +4840,9 @@ CPed::LoadFightData(void) line[linelen] = '\0'; // skip white space - for (lp = 0; line[lp] <= ' '; lp++); + for (lp = 0; line[lp] <= ' ' && line[lp] != '\0'; lp++); - if (lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines + if (line[lp] == '\0' || line[lp] == '#') continue; @@ -4914,11 +4903,12 @@ CPed::LoadFightData(void) int CPed::GetLocalDirection(const CVector2D &posOffset) { - float direction; + int direction; + float angle; - for (direction = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); direction < 0.0f; direction += TWOPI); + for (angle = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); angle < 0.0f; angle += TWOPI); - for (direction = (int)RADTODEG(direction) / 90; direction > 3; direction -= 4); + for (direction = RADTODEG(angle)/90.0f; direction > 3; direction -= 4); // 0-forward, 1-left, 2-backward, 3-right. return direction; @@ -5636,8 +5626,9 @@ CPed::CreateDeadPedMoney(void) if (!CGame::nastyGame) return; - int skin = GetModelIndex(); - if ((skin >= MI_COP && skin <= MI_FIREMAN) || CharCreatedBy == MISSION_CHAR || bInVehicle) + int mi = GetModelIndex(); + + if ((mi >= MI_COP && mi <= MI_FIREMAN) || CharCreatedBy == MISSION_CHAR || bInVehicle) return; int money = CGeneral::GetRandomNumber() % 60; @@ -6103,10 +6094,8 @@ CPed::EnterCar(void) // CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehEnterType); if (veh->CanPedOpenLocks(this)) { - if (m_vehEnterType) { - CAnimBlendAssociation *enterAssoc = m_pVehicleAnim; - if (enterAssoc) - veh->ProcessOpenDoor(m_vehEnterType, enterAssoc->animId, enterAssoc->currentTime); + if (m_vehEnterType && m_pVehicleAnim) { + veh->ProcessOpenDoor(m_vehEnterType, m_pVehicleAnim->animId, m_pVehicleAnim->currentTime); } } bIsInTheAir = false; @@ -6258,10 +6247,10 @@ CPed::ExitCar(void) if (m_pSeekTarget) { // Car is upside down if (m_pMyVehicle->GetUp().z > -0.8f) { - if (exitAnim != ANIM_CAR_CLOSE_RHS && exitAnim != ANIM_CAR_CLOSE_LHS && animTime <= 0.3f) - LineUpPedWithCar((m_pMyVehicle->GetModelIndex() == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START)); - else + if (exitAnim == ANIM_CAR_CLOSE_RHS || exitAnim == ANIM_CAR_CLOSE_LHS || animTime > 0.3f) LineUpPedWithCar(LINE_UP_TO_CAR_END); + else + LineUpPedWithCar((m_pMyVehicle->GetModelIndex() == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START)); } else { LineUpPedWithCar(LINE_UP_TO_CAR_END); } @@ -6681,7 +6670,7 @@ CPed::FindBestCoordsFromNodes(CVector unused, CVector *bestCoords) CVector ourPos = GetPosition(); - int closestNodeId = ThePaths.FindNodeClosestToCoors(GetPosition(), 1, 999999.9f, false, false); + int closestNodeId = ThePaths.FindNodeClosestToCoors(GetPosition(), 1, 999999.9f); CVector seekObjPos = m_vecSeekPos; seekObjPos.z += 1.0f; @@ -7561,15 +7550,12 @@ CPed::FollowPath(void) CVector CPed::GetFormationPosition(void) { - CPed *referencePed = m_pedInObjective; - - if (referencePed->m_nPedState == PED_DEAD) { - CPed *referencePedOfReference = referencePed->m_pedInObjective; - if (!referencePedOfReference) { + if (m_pedInObjective->m_nPedState == PED_DEAD) { + if (!m_pedInObjective->m_pedInObjective) { m_pedInObjective = nil; return GetPosition(); } - m_pedInObjective = referencePed = referencePedOfReference; + m_pedInObjective = m_pedInObjective->m_pedInObjective; } CVector formationOffset; @@ -7602,7 +7588,7 @@ CPed::GetFormationPosition(void) formationOffset = CVector(0.0f, 0.0f, 0.0f); break; } - return formationOffset + referencePed->GetPosition(); + return formationOffset + m_pedInObjective->GetPosition(); } void @@ -7620,41 +7606,36 @@ CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen) CVector lfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LF); CVector rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); - // Right front door is closer - if ((lfPos - GetPosition()).MagnitudeSqr2D() >= (rfPos - GetPosition()).MagnitudeSqr2D()) { + // Left front door is closer + if ((lfPos - GetPosition()).MagnitudeSqr2D() < (rfPos - GetPosition()).MagnitudeSqr2D()) { + + if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { + m_vehEnterType = CAR_DOOR_RF; + posToOpen = rfPos; + } + } else { if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { CPed *rfPassenger = veh->pPassengers[0]; - if (!rfPassenger - || rfPassenger->m_leader != this && !rfPassenger->bDontDragMeOutCar && (veh->VehicleCreatedBy != MISSION_VEHICLE || m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) - || veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) == 0) { + if (rfPassenger && (rfPassenger->m_leader == this || rfPassenger->bDontDragMeOutCar || + veh->VehicleCreatedBy == MISSION_VEHICLE && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) + || (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - if ((veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) == 0 - || veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) == 0) { - m_vehEnterType = CAR_DOOR_RF; - posToOpen = rfPos; - return; - } + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } else { + m_vehEnterType = CAR_DOOR_RF; + posToOpen = rfPos; } - } else { - if (!veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) - return; + } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; } - m_vehEnterType = CAR_DOOR_LF; - posToOpen = lfPos; - return; - } - - if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - m_vehEnterType = CAR_DOOR_LF; - posToOpen = lfPos; - return; - } - - if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { - m_vehEnterType = CAR_DOOR_RF; - posToOpen = rfPos; } } @@ -8951,18 +8932,11 @@ CPed::MoveHeadToLook(void) } bShakeFist = false; return; - } - - if (999999.0f == m_fLookDirection) { + } else if (999999.0f == m_fLookDirection) { ClearLookFlag(); - return; - } - - if (!m_pedIK.LookInDirection(m_fLookDirection, 0.0f)) { - if (!bKeepTryingToLook) { + } else if (!m_pedIK.LookInDirection(m_fLookDirection, 0.0f)) { + if (!bKeepTryingToLook) ClearLookFlag(); - return; - } } } @@ -10525,7 +10499,7 @@ CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *animAssoc, void *arg) default: assert(0); } - if (veh->Damage.GetDoorStatus(door) == DOOR_STATUS_SMASHED) + if (veh->Damage.GetDoorStatus(door) == DOOR_STATUS_SWINGING) veh->Damage.SetDoorStatus(door, DOOR_STATUS_OK); if (door == DOOR_FRONT_LEFT || ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || veh->bIsBus) { @@ -11125,9 +11099,7 @@ CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) default: break; } - bool closeDoor = false; - if (!veh->IsDoorMissing(door)) - closeDoor = true; + bool closeDoor = !veh->IsDoorMissing(door); int padNo; if (ped->IsPlayer()) { @@ -11148,10 +11120,7 @@ CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) break; } CPad* pad = CPad::GetPad(padNo); - bool engineIsIntact = false; - if (veh->IsCar() && ((CAutomobile*)veh)->Damage.GetEngineStatus() >= 225) { - engineIsIntact = true; - } + bool engineIsIntact = veh->IsCar() && ((CAutomobile*)veh)->Damage.GetEngineStatus() >= 225; if (!pad->ArePlayerControlsDisabled() && veh->m_nDoorLock != CARLOCK_FORCE_SHUT_DOORS && (pad->GetTarget() || pad->NewState.LeftStickX @@ -11215,10 +11184,9 @@ CPed::PedEvadeCB(CAnimBlendAssociation* animAssoc, void* arg) if (!animAssoc) { ped->ClearLookFlag(); - if (ped->m_nPedState != PED_DIVE_AWAY && ped->m_nPedState != PED_STEP_AWAY) - return; - - ped->RestorePreviousState(); + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) + ped->RestorePreviousState(); + } else if (animAssoc->animId == ANIM_EV_DIVE) { ped->bUpdateAnimHeading = true; ped->ClearLookFlag(); @@ -11229,12 +11197,12 @@ CPed::PedEvadeCB(CAnimBlendAssociation* animAssoc, void* arg) } animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } else if (animAssoc->flags & ASSOC_FADEOUTWHENDONE) { ped->ClearLookFlag(); - if (ped->m_nPedState != PED_DIVE_AWAY && ped->m_nPedState != PED_STEP_AWAY) - return; + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) + ped->RestorePreviousState(); - ped->RestorePreviousState(); } else if (ped->m_nPedState != PED_ARRESTED) { animAssoc->flags |= ASSOC_DELETEFADEDOUT; if (animAssoc->blendDelta >= 0.0f) @@ -11798,12 +11766,14 @@ CPed::ReactToPointGun(CEntity *entWithGun) if (m_nPedType == PEDTYPE_COP) { if (pedWithGun->IsPlayer()) { ((CPlayerPed*)pedWithGun)->m_pWanted->SetWantedLevelNoDrop(2); + if (bCrouchWhenShooting || bKindaStayInSamePlace) { + SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); + return; + } } - if (bCrouchWhenShooting || bKindaStayInSamePlace) { - SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); - } + } - } else if (m_nPedType != PEDTYPE_COP + if (m_nPedType != PEDTYPE_COP && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) && (m_nPedState != PED_FLEE_ENTITY || pedWithGun->IsPlayer() && m_fleeFrom != pedWithGun) && m_nPedState != PED_AIM_GUN && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { @@ -11825,9 +11795,8 @@ CPed::ReactToPointGun(CEntity *entWithGun) int moneyPerPickup = money / pickupCount; for (int i = 0; i < pickupCount; i++) { - // (CGeneral::GetRandomNumber() % 256) * PI / 128 gives a float up to something TWOPI-ish. - float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().x; - float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().y; + float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().x; + float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().y; bool found = false; float groundZ = CWorld::FindGroundZFor3DCoord(pickupX, pickupY, GetPosition().z, &found) + 0.5f; if (found) { @@ -12123,7 +12092,6 @@ CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void CVector finalPos; CVector draggedOutOffset; - CVector finalLocalPos; CMatrix pedMat(ped->GetMatrix()); ped->bUsesCollision = true; @@ -12132,8 +12100,7 @@ CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) draggedOutOffset.x = -draggedOutOffset.x; - finalLocalPos = Multiply3x3(pedMat, draggedOutOffset); - finalPos = finalLocalPos + ped->GetPosition(); + finalPos = Multiply3x3(pedMat, draggedOutOffset) + ped->GetPosition(); CPedPlacement::FindZCoorForPed(&finalPos); ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); ped->SetPosition(finalPos); @@ -12178,36 +12145,32 @@ CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void ped->m_pNextPathNode = nil; ped->Say(SOUND_PED_FLEE_RUN); } - } else { - if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear - && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE - && veh->pDriver && veh->pDriver->IsPlayer() - && !CTheScripts::IsPlayerOnAMission()) { + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear + && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE + && veh->pDriver && veh->pDriver->IsPlayer() + && !CTheScripts::IsPlayerOnAMission()) { #ifndef VC_PED_PORTS - if (CGeneral::GetRandomNumber() < MYRAND_MAX / 2) { - ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, veh->pDriver); - } else + if (CGeneral::GetRandomNumber() < MYRAND_MAX / 2) { + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, veh->pDriver); + } else #endif - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); - } else { #ifdef VC_PED_PORTS - if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR - && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && !veh->pDriver - && FindPlayerPed()->m_carInObjective == ped->m_pMyVehicle && !CTheScripts::IsPlayerOnAMission()) - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); - else + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear + && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE + && !veh->pDriver && FindPlayerPed()->m_carInObjective == veh + && !CTheScripts::IsPlayerOnAMission()) { + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); #endif - { - ped->SetFindPathAndFlee(veh->GetPosition(), 10000); - if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { - ped->SetMoveState(PEDMOVE_SPRINT); - ped->Say(SOUND_PED_FLEE_SPRINT); - } else { - ped->Say(SOUND_PED_FLEE_RUN); - } - } + } else { + ped->SetFindPathAndFlee(veh->GetPosition(), 10000); + if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { + ped->SetMoveState(PEDMOVE_SPRINT); + ped->Say(SOUND_PED_FLEE_SPRINT); + } else { + ped->Say(SOUND_PED_FLEE_RUN); } } } @@ -12417,27 +12380,33 @@ CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) void CPed::Render(void) { - if (!bInVehicle || m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR || - bRenderPedInCar && sq(25.0f * TheCamera.LODDistMultiplier) >= (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr()) { - CEntity::Render(); + if (bInVehicle && m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR) { + if (!bRenderPedInCar) + return; + + float camDistSq = (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr(); + if (camDistSq > SQR(25.0f * TheCamera.LODDistMultiplier)) + return; + } + + CEntity::Render(); #ifdef PED_SKIN - if(IsClumpSkinned(GetClump())){ - renderLimb(PED_HEAD); - renderLimb(PED_HANDL); - renderLimb(PED_HANDR); - } - if(m_pWeaponModel && IsClumpSkinned(GetClump())){ - RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); - int idx = RpHAnimIDGetIndex(hier, m_pFrames[PED_HANDR]->nodeID); - RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; - RwFrame *frame = RpAtomicGetFrame(m_pWeaponModel); - *RwFrameGetMatrix(frame) = *mat; - RwFrameUpdateObjects(frame); - RpAtomicRender(m_pWeaponModel); - } -#endif + if(IsClumpSkinned(GetClump())){ + renderLimb(PED_HEAD); + renderLimb(PED_HANDL); + renderLimb(PED_HANDR); } + if(m_pWeaponModel && IsClumpSkinned(GetClump())){ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, m_pFrames[PED_HANDR]->nodeID); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + RwFrame *frame = RpAtomicGetFrame(m_pWeaponModel); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + RpAtomicRender(m_pWeaponModel); + } +#endif } #ifdef PED_SKIN @@ -15520,31 +15489,7 @@ CPed::ScanForInterestingStuff(void) return; if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { - if (CGeneral::GetRandomNumber() % 100 >= 10) { - if (m_objective != OBJECTIVE_MUG_CHAR && !(CGeneral::GetRandomNumber() & 7)) { - CPed *charToMug = nil; - for (int i = 0; i < m_numNearPeds; ++i) { - CPed *nearPed = m_nearPeds[i]; - - if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) - break; - - if ((nearPed->m_nPedType == PEDTYPE_CIVFEMALE || nearPed->m_nPedType == PEDTYPE_CIVMALE - || nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->m_nPedType == PEDTYPE_UNUSED1 - || nearPed->m_nPedType == PEDTYPE_PROSTITUTE) - && nearPed->CharCreatedBy != MISSION_CHAR - && nearPed->IsPedShootable() - && nearPed->m_objective != OBJECTIVE_MUG_CHAR) { - charToMug = nearPed; - break; - } - } - if (charToMug) - SetObjective(OBJECTIVE_MUG_CHAR, charToMug); - - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - } - } else { + if (CGeneral::GetRandomNumber() % 100 < 10) { int mostExpensiveVehAround = -1; int bestMonetaryValue = 0; @@ -15570,6 +15515,28 @@ CPed::ScanForInterestingStuff(void) return; } m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + } else if (m_objective != OBJECTIVE_MUG_CHAR && !(CGeneral::GetRandomNumber() & 7)) { + CPed *charToMug = nil; + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + + if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) + break; + + if ((nearPed->m_nPedType == PEDTYPE_CIVFEMALE || nearPed->m_nPedType == PEDTYPE_CIVMALE + || nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->m_nPedType == PEDTYPE_UNUSED1 + || nearPed->m_nPedType == PEDTYPE_PROSTITUTE) + && nearPed->CharCreatedBy != MISSION_CHAR + && nearPed->IsPedShootable() + && nearPed->m_objective != OBJECTIVE_MUG_CHAR) { + charToMug = nearPed; + break; + } + } + if (charToMug) + SetObjective(OBJECTIVE_MUG_CHAR, charToMug); + + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; } } @@ -15596,9 +15563,7 @@ CPed::ScanForInterestingStuff(void) } } #else - if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) >= 0.5f) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 200; - } else { + if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.5f) { if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { for (int i = 0; i < m_numNearPeds; i ++) { if (m_nearPeds[i] && m_nearPeds[i]->m_nPedState == PED_WANDER_PATH) { @@ -15615,6 +15580,8 @@ CPed::ScanForInterestingStuff(void) } } } + } else { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 200; } #endif } @@ -16308,94 +16275,92 @@ CPed::UpdateFromLeader(void) return; } } - if (bInVehicle || !m_leader->bInVehicle || m_leader->m_nPedState != PED_DRIVING) { - if (m_leader->m_objective != OBJECTIVE_NONE && (!m_leader->IsPlayer() || m_leader->m_objective != OBJECTIVE_WAIT_ON_FOOT) - && m_objective != m_leader->m_objective) { + if (!bInVehicle && m_leader->bInVehicle && m_leader->m_nPedState == PED_DRIVING) { + if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (m_leader->m_pMyVehicle->m_nNumPassengers < m_leader->m_pMyVehicle->m_nNumMaxPassengers) + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_pMyVehicle); + } + } else if (m_leader->m_objective == OBJECTIVE_NONE || (m_leader->IsPlayer() && m_leader->m_objective == OBJECTIVE_WAIT_ON_FOOT) + || m_objective == m_leader->m_objective) { - switch (m_leader->m_objective) { - case OBJECTIVE_WAIT_ON_FOOT: - case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: - case OBJECTIVE_WAIT_IN_CAR: - case OBJECTIVE_FOLLOW_ROUTE: - SetObjective(m_leader->m_objective); - m_objectiveTimer = m_leader->m_objectiveTimer; - break; - case OBJECTIVE_GUARD_SPOT: - SetObjective(OBJECTIVE_GUARD_SPOT, m_leader->m_vecSeekPosEx); - m_objectiveTimer = m_leader->m_objectiveTimer; - break; - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - if (m_leader->m_pedInObjective) { - SetObjective(m_leader->m_objective, m_leader->m_pedInObjective); - m_objectiveTimer = m_leader->m_objectiveTimer; - } - break; - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - if (m_leader->m_carInObjective) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_carInObjective); - return; - } - break; - case OBJECTIVE_GUARD_ATTACK: - return; - case OBJECTIVE_HAIL_TAXI: - m_leader = nil; - SetObjective(OBJECTIVE_NONE); - break; - default: - SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); - SetObjectiveTimer(0); - break; + if (m_leader->m_nPedState == PED_ATTACK) { + CEntity *lookTargetOfLeader = m_leader->m_pLookTarget; + if (lookTargetOfLeader && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT + && lookTargetOfLeader->IsPed() && lookTargetOfLeader != this) { + + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, lookTargetOfLeader); + SetObjectiveTimer(8000); + SetLookFlag(m_leader->m_pLookTarget, false); + SetLookTimer(500); } } else { - if (m_leader->m_nPedState == PED_ATTACK) { - CEntity *lookTargetOfLeader = m_leader->m_pLookTarget; - if (lookTargetOfLeader && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT - && lookTargetOfLeader->IsPed() && lookTargetOfLeader != this) { - - SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, lookTargetOfLeader); - SetObjectiveTimer(8000); - SetLookFlag(m_leader->m_pLookTarget, false); - SetLookTimer(500); - } - } else { - if (IsPedInControl() && m_nPedState != PED_ATTACK) { + if (IsPedInControl() && m_nPedState != PED_ATTACK) { #ifndef VC_PED_PORTS + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); +#else + if (m_leader->m_objective == OBJECTIVE_NONE && m_objective == OBJECTIVE_NONE + && m_leader->m_nPedState == PED_CHAT && m_nPedState == PED_CHAT) { + + SetObjective(OBJECTIVE_NONE); + } else { SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); SetObjectiveTimer(0); -#else - if (m_leader->m_objective != OBJECTIVE_NONE || m_objective != OBJECTIVE_NONE - || m_leader->m_nPedState != PED_CHAT || m_nPedState != PED_CHAT) { - - SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); - SetObjectiveTimer(0); - } else { - SetObjective(OBJECTIVE_NONE); - } -#endif } - if (m_nPedState == PED_IDLE && m_leader->IsPlayer()) { - if (ScanForThreats() && m_threatEntity) { - m_pLookTarget = m_threatEntity; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - if (m_attackTimer < CTimer::GetTimeInMilliseconds() && !GetWeapon()->IsTypeMelee()) { - m_pPointGunAt = m_threatEntity; - if (m_threatEntity) - m_threatEntity->RegisterReference((CEntity **) &m_pPointGunAt); - SetAttack(m_threatEntity); - } +#endif + } + if (m_nPedState == PED_IDLE && m_leader->IsPlayer()) { + if (ScanForThreats() && m_threatEntity) { + m_pLookTarget = m_threatEntity; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && !GetWeapon()->IsTypeMelee()) { + m_pPointGunAt = m_threatEntity; + if (m_threatEntity) + m_threatEntity->RegisterReference((CEntity **) &m_pPointGunAt); + SetAttack(m_threatEntity); } } } } } else { - if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (m_leader->m_pMyVehicle->m_nNumPassengers < m_leader->m_pMyVehicle->m_nNumMaxPassengers) - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_pMyVehicle); + switch (m_leader->m_objective) { + case OBJECTIVE_WAIT_ON_FOOT: + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_FOLLOW_ROUTE: + SetObjective(m_leader->m_objective); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_GUARD_SPOT: + SetObjective(OBJECTIVE_GUARD_SPOT, m_leader->m_vecSeekPosEx); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + if (m_leader->m_pedInObjective) { + SetObjective(m_leader->m_objective, m_leader->m_pedInObjective); + m_objectiveTimer = m_leader->m_objectiveTimer; + } + break; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_leader->m_carInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_carInObjective); + return; + } + break; + case OBJECTIVE_GUARD_ATTACK: + return; + case OBJECTIVE_HAIL_TAXI: + m_leader = nil; + SetObjective(OBJECTIVE_NONE); + break; + default: + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); + break; } } } else if (bInVehicle) { @@ -16433,34 +16398,32 @@ CPed::UpdatePosition(void) SetHeading(m_fRotationCur); if (m_pCurrentPhysSurface) { CVector2D velocityOfSurface; - CPhysical *curSurface = m_pCurrentPhysSurface; if (!IsPlayer() && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) { // It seems R* didn't like m_vecOffsetFromPhysSurface for boats - CVector offsetToSurface = GetPosition() - curSurface->GetPosition(); + CVector offsetToSurface = GetPosition() - m_pCurrentPhysSurface->GetPosition(); offsetToSurface.z -= FEET_OFFSET; - CVector surfaceMoveVelocity = curSurface->m_vecMoveSpeed; - CVector surfaceTurnVelocity = CrossProduct(curSurface->m_vecTurnSpeed, offsetToSurface); + CVector surfaceMoveVelocity = m_pCurrentPhysSurface->m_vecMoveSpeed; + CVector surfaceTurnVelocity = CrossProduct(m_pCurrentPhysSurface->m_vecTurnSpeed, offsetToSurface); // Also we use that weird formula instead of friction if it's boat - float slideMult = -curSurface->m_vecTurnSpeed.MagnitudeSqr(); + float slideMult = -m_pCurrentPhysSurface->m_vecTurnSpeed.MagnitudeSqr(); velocityOfSurface = slideMult * offsetToSurface * CTimer::GetTimeStep() + (surfaceTurnVelocity + surfaceMoveVelocity); m_vecMoveSpeed.z = slideMult * offsetToSurface.z * CTimer::GetTimeStep() + (surfaceTurnVelocity.z + surfaceMoveVelocity.z); } else { - velocityOfSurface = curSurface->GetSpeed(m_vecOffsetFromPhysSurface); + velocityOfSurface = m_pCurrentPhysSurface->GetSpeed(m_vecOffsetFromPhysSurface); } // Reminder: m_moved is displacement from walking/running. velocityChange = m_moved + velocityOfSurface - m_vecMoveSpeed; - m_fRotationCur += curSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); - m_fRotationDest += curSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); - } else if (m_nSurfaceTouched != SURFACE_STEEP_CLIFF || m_vecDamageNormal.x == 0.0f && m_vecDamageNormal.y == 0.0f) { - velocityChange = m_moved - m_vecMoveSpeed; - } else { + m_fRotationCur += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + m_fRotationDest += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + } else if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF && (m_vecDamageNormal.x != 0.0f || m_vecDamageNormal.y != 0.0f)) { // Ped got damaged by steep slope m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.001f); // some kind of - CVector2D reactionForce = m_vecDamageNormal * (1.0f / m_vecDamageNormal.Magnitude2D()); + CVector2D reactionForce = m_vecDamageNormal; + reactionForce.Normalise(); velocityChange = 0.02f * reactionForce + m_moved; @@ -16469,17 +16432,18 @@ CPed::UpdatePosition(void) if (reactionAndVelocityDotProd < 0.0f) { velocityChange -= reactionAndVelocityDotProd * reactionForce; } + } else { + velocityChange = m_moved - m_vecMoveSpeed; } // Take time step into account if (m_pCurrentPhysSurface) { float speedChange = velocityChange.Magnitude(); float changeMult = speedChange; - if (m_nPedState != PED_DIE || !m_pCurrentPhysSurface->IsVehicle()) { - if (!m_pCurrentPhysSurface->IsVehicle() || !((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) - changeMult = 0.01f * CTimer::GetTimeStep(); - } else { + if (m_nPedState == PED_DIE && m_pCurrentPhysSurface->IsVehicle()) { changeMult = 0.002f * CTimer::GetTimeStep(); + } else if (!(m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat())) { + changeMult = 0.01f * CTimer::GetTimeStep(); } if (speedChange > changeMult) { @@ -16551,7 +16515,7 @@ CPed::SetPedPositionInCar(void) tempMat.RotateZ(-HALFPI); newMat = newMat * tempMat; } else if (m_pMyVehicle->pPassengers[2] == this) { - m_fRotationCur = HALFPI + m_pMyVehicle->GetForward().Heading(); + m_fRotationCur = m_pMyVehicle->GetForward().Heading() + HALFPI; tempMat.SetTranslate(0.0f, 0.0f, 0.0f); tempMat.RotateZ(HALFPI); newMat = newMat * tempMat; @@ -17202,18 +17166,10 @@ CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) float zDiff = Max(0.0f, carEnterPos.z - GetPosition().z); bUsesCollision = false; - if (zDiff > 4.4f) { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); - - } else { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); - } + if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_LHS : ANIM_CAR_ALIGN_LHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_RHS : ANIM_CAR_ALIGN_RHS, 4.0f); m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); } @@ -17307,11 +17263,11 @@ CPed::SetCarJack(CVehicle* car) if (m_fHealth > 0.0f && (IsPlayer() || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || (car->VehicleCreatedBy != MISSION_VEHICLE && car->GetModelIndex() != MI_DODO))) - if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) - if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) - if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) - if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) - SetCarJack_AllClear(car, m_vehEnterType, doorFlag); + if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) + if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) + if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) + if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) + SetCarJack_AllClear(car, m_vehEnterType, doorFlag); } void diff --git a/src/peds/PedChat.cpp b/src/peds/PedChat.cpp index 65ed67a5..81e295c6 100644 --- a/src/peds/PedChat.cpp +++ b/src/peds/PedChat.cpp @@ -56,26 +56,27 @@ CPed::ServiceTalkingWhenDead(void) void CPed::ServiceTalking(void) { - if (!bBodyPartJustCameOff || m_bodyPartBleeding != PED_HEAD) { - if (!CGeneral::faststricmp(CModelInfo::GetModelInfo(GetModelIndex())->GetName(), "bomber")) - m_queuedSound = SOUND_PED_BOMBER; - else if (m_nPedState == PED_ON_FIRE) - m_queuedSound = SOUND_PED_BURNING; + if (bBodyPartJustCameOff && m_bodyPartBleeding == PED_HEAD) + return; - if (m_queuedSound != SOUND_NO_SOUND) { - if (m_queuedSound == SOUND_PED_DEATH) - m_soundStart = CTimer::GetTimeInMilliseconds() - 1; + if (!CGeneral::faststricmp(CModelInfo::GetModelInfo(GetModelIndex())->GetName(), "bomber")) + m_queuedSound = SOUND_PED_BOMBER; + else if (m_nPedState == PED_ON_FIRE) + m_queuedSound = SOUND_PED_BURNING; - if (CTimer::GetTimeInMilliseconds() > m_soundStart) { - DMAudio.PlayOneShot(m_audioEntityId, m_queuedSound, 1.0f); - m_lastSoundStart = CTimer::GetTimeInMilliseconds(); - m_soundStart = - CommentWaitTime[m_queuedSound - SOUND_PED_DEATH].m_nFixedDelayTime - + CTimer::GetTimeInMilliseconds() - + CGeneral::GetRandomNumberInRange(0, CommentWaitTime[m_queuedSound - SOUND_PED_DEATH].m_nOverrideFixedDelayTime); - m_lastQueuedSound = m_queuedSound; - m_queuedSound = SOUND_NO_SOUND; - } + if (m_queuedSound != SOUND_NO_SOUND) { + if (m_queuedSound == SOUND_PED_DEATH) + m_soundStart = CTimer::GetTimeInMilliseconds() - 1; + + if (CTimer::GetTimeInMilliseconds() > m_soundStart) { + DMAudio.PlayOneShot(m_audioEntityId, m_queuedSound, 1.0f); + m_lastSoundStart = CTimer::GetTimeInMilliseconds(); + m_soundStart = + CommentWaitTime[m_queuedSound - SOUND_PED_DEATH].m_nFixedDelayTime + + CTimer::GetTimeInMilliseconds() + + CGeneral::GetRandomNumberInRange(0, CommentWaitTime[m_queuedSound - SOUND_PED_DEATH].m_nOverrideFixedDelayTime); + m_lastQueuedSound = m_queuedSound; + m_queuedSound = SOUND_NO_SOUND; } } } @@ -83,14 +84,12 @@ CPed::ServiceTalking(void) void CPed::Say(uint16 audio) { - uint16 audioToPlay = audio; - if (IsPlayer()) { // Ofc this part isn't in VC. switch (audio) { case SOUND_PED_DEATH: - audioToPlay = SOUND_PED_DAMAGE; + audio = SOUND_PED_DAMAGE; break; case SOUND_PED_DAMAGE: case SOUND_PED_HIT: @@ -99,7 +98,7 @@ CPed::Say(uint16 audio) case SOUND_PED_BULLET_HIT: case SOUND_PED_CAR_JACKED: case SOUND_PED_DEFEND: - audioToPlay = SOUND_PED_HIT; + audio = SOUND_PED_HIT; break; default: return; @@ -142,12 +141,12 @@ CPed::Say(uint16 audio) } } - if (audioToPlay < m_queuedSound) { - if (audioToPlay != m_lastQueuedSound || audioToPlay == SOUND_PED_DEATH - || CommentWaitTime[audioToPlay - SOUND_PED_DEATH].m_nOverrideMaxRandomDelayTime + if (audio < m_queuedSound) { + if (audio != m_lastQueuedSound || audio == SOUND_PED_DEATH + || CommentWaitTime[audio - SOUND_PED_DEATH].m_nOverrideMaxRandomDelayTime + m_lastSoundStart - + (uint32) CGeneral::GetRandomNumberInRange(0, CommentWaitTime[audioToPlay - SOUND_PED_DEATH].m_nMaxRandomDelayTime) <= CTimer::GetTimeInMilliseconds()) { - m_queuedSound = audioToPlay; + + (uint32) CGeneral::GetRandomNumberInRange(0, CommentWaitTime[audio - SOUND_PED_DEATH].m_nMaxRandomDelayTime) <= CTimer::GetTimeInMilliseconds()) { + m_queuedSound = audio; } } } \ No newline at end of file From cf3308c66e1f4bc881f511b55ac60b3644df7a84 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 13:46:58 +0100 Subject: [PATCH 067/129] no static runtime for external librw --- premake5.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/premake5.lua b/premake5.lua index 51518a98..85f4d082 100644 --- a/premake5.lua +++ b/premake5.lua @@ -310,7 +310,10 @@ project "re3" linkoptions "/SAFESEH:NO" characterset ("MBCS") targetextension ".exe" - staticruntime "on" + if(_OPTIONS["with-librw"]) then + -- external librw is dynamic + staticruntime "on" + end filter "platforms:win*glfw*" staticruntime "off" From 808f7c46f1df9acaf8d00ebde7cb1925e1d27f94 Mon Sep 17 00:00:00 2001 From: erorcun Date: Thu, 19 Nov 2020 02:09:04 +0300 Subject: [PATCH 068/129] Infamous XBOX subtitle outline --- src/core/config.h | 1 + src/render/Font.cpp | 34 ++++++++++++++++++++++++++++++++++ src/render/Font.h | 4 ++++ src/render/Hud.cpp | 12 +++++++++++- 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/core/config.h b/src/core/config.h index 3da9bcb1..db6e5490 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -262,6 +262,7 @@ enum Config { #define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better. // #define BETA_SLIDING_TEXT #define TRIANGULAR_BLIPS // height indicating triangular radar blips, as in VC +// #define XBOX_SUBTITLES // the infamous outlines #define PC_MENU #ifndef PC_MENU diff --git a/src/render/Font.cpp b/src/render/Font.cpp index fbcc38e4..42ddd0fb 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -942,6 +942,40 @@ CFont::PrintString(float x, float y, wchar *start, wchar *end, float spwidth) } #endif +#ifdef XBOX_SUBTITLES +void +CFont::PrintStringFromBottom(float x, float y, wchar *str) +{ +#ifdef MORE_LANGUAGES + if (IsJapaneseFont()) + y -= (32.0f * CFont::Details.scaleY / 2.75f + 2.0f * CFont::Details.scaleY) * GetNumberLines(x, y, str); + else +#endif + y -= (32.0f * CFont::Details.scaleY * 0.5f + 2.0f * CFont::Details.scaleY) * GetNumberLines(x, y, str); + PrintString(x, y, str); +} + +void +CFont::PrintOutlinedString(float x, float y, wchar *str, float outlineStrength, bool fromBottom, CRGBA outlineColor) +{ + CRGBA textColor = Details.color; + SetColor(outlineColor); + CVector2D offsets[] = { {1.f, 1.f}, {1.f, -1.f}, {-1.f, 1.f}, {-1.f, -1.f} }; + for(int i = 0; i < ARRAY_SIZE(offsets); i++){ + if (fromBottom) + PrintStringFromBottom(x + SCREEN_SCALE_X(offsets[i].x * outlineStrength), y + SCREEN_SCALE_Y(offsets[i].y * outlineStrength), str); + else + PrintString(x + SCREEN_SCALE_X(offsets[i].x * outlineStrength), y + SCREEN_SCALE_Y(offsets[i].y * outlineStrength), str); + } + SetColor(textColor); + + if (fromBottom) + PrintStringFromBottom(x, y, str); + else + PrintString(x, y, str); +} +#endif + float CFont::GetCharacterWidth(wchar c) { diff --git a/src/render/Font.h b/src/render/Font.h index bf747859..7b67e310 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -116,6 +116,10 @@ public: static void InitPerFrame(void); static void PrintChar(float x, float y, wchar c); static void PrintString(float x, float y, wchar *s); +#ifdef XBOX_SUBTITLES + static void PrintStringFromBottom(float x, float y, wchar *str); + static void PrintOutlinedString(float x, float y, wchar *str, float outlineStrength, bool fromBottom, CRGBA outlineColor); +#endif static int GetNumberLines(float xstart, float ystart, wchar *s); static void GetTextRect(CRect *rect, float xstart, float ystart, wchar *s); #ifdef MORE_LANGUAGES diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index de3128ce..1a39e1c7 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -926,11 +926,20 @@ void CHud::Draw() CFont::SetJustifyOff(); CFont::SetBackgroundOff(); CFont::SetBackgroundColor(CRGBA(0, 0, 0, 128)); - CFont::SetScale(SCREEN_SCALE_X(0.48f), SCREEN_SCALE_Y(1.120f)); + CFont::SetScale(SCREEN_SCALE_X(0.48f), SCREEN_SCALE_Y(1.12f)); CFont::SetCentreOn(); CFont::SetPropOn(); CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); +#ifdef XBOX_SUBTITLES + float radarBulge = SCREEN_SCALE_X(45.0f) + SCREEN_SCALE_X(16.0f); + float rectWidth = SCREEN_WIDTH - SCREEN_SCALE_X(45.0f) - SCREEN_SCALE_X(16.0f) - radarBulge; + CFont::SetCentreSize(rectWidth); + CFont::SetColor(CRGBA(180, 180, 180, 255)); + + CFont::PrintOutlinedString(rectWidth / 2.0f + radarBulge, SCREEN_SCALE_Y(4.0f) + SCREEN_SCALE_FROM_BOTTOM(48.0f) - SCREEN_SCALE_Y(1), m_Message, + 2.0f, true, CRGBA(0, 0, 0, 255)); +#else float radarBulge = SCREEN_SCALE_X(40.0f) + SCREEN_SCALE_X(8.0f); float rectWidth = SCREEN_WIDTH - SCREEN_SCALE_X(50.0f) - SCREEN_SCALE_X(8.0f) - radarBulge; CFont::SetCentreSize(rectWidth); @@ -943,6 +952,7 @@ void CHud::Draw() // I'm not sure shadow substaction was intentional here, might be a leftover if CFont::PrintString was used for a shadow draw call CFont::PrintString(rectWidth / 2.0f + radarBulge - SCREEN_SCALE_X(shadow), SCREEN_SCALE_Y(4.0f) + SCREEN_SCALE_FROM_BOTTOM(68.0f) - SCREEN_SCALE_Y(shadow), m_Message); CFont::SetDropShadowPosition(0); +#endif } /* From 02c7f8381b81732645ed92fda0c5a66d0f1db265 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 19 Nov 2020 16:23:52 +0100 Subject: [PATCH 069/129] neo screen droplets --- src/control/GameLogic.cpp | 10 + src/core/Game.cpp | 7 + src/core/config.h | 8 + src/core/main.cpp | 17 +- src/extras/custompipes.cpp | 2 +- src/extras/custompipes.h | 1 + src/extras/custompipes_d3d9.cpp | 1 + src/extras/postfx.cpp | 15 +- src/extras/postfx.h | 1 + src/extras/screendroplets.cpp | 791 +++++++++++++++++++++ src/extras/screendroplets.h | 78 ++ src/extras/shaders/Makefile | 13 +- src/extras/shaders/im2d_UV2.vert | 21 + src/extras/shaders/im2d_UV2_gl.inc | 23 + src/extras/shaders/screenDroplet.frag | 18 + src/extras/shaders/screenDroplet_PS.cso | Bin 0 -> 324 bytes src/extras/shaders/screenDroplet_PS.hlsl | 17 + src/extras/shaders/screenDroplet_PS.inc | 29 + src/extras/shaders/screenDroplet_fs_gl.inc | 20 + src/objects/ParticleObject.cpp | 6 + src/objects/ParticleObject.h | 2 + 21 files changed, 1072 insertions(+), 8 deletions(-) create mode 100644 src/extras/screendroplets.cpp create mode 100644 src/extras/screendroplets.h create mode 100644 src/extras/shaders/im2d_UV2.vert create mode 100644 src/extras/shaders/im2d_UV2_gl.inc create mode 100644 src/extras/shaders/screenDroplet.frag create mode 100644 src/extras/shaders/screenDroplet_PS.cso create mode 100644 src/extras/shaders/screenDroplet_PS.hlsl create mode 100644 src/extras/shaders/screenDroplet_PS.inc create mode 100644 src/extras/shaders/screenDroplet_fs_gl.inc diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp index 47b4586b..59c75dd4 100644 --- a/src/control/GameLogic.cpp +++ b/src/control/GameLogic.cpp @@ -19,6 +19,7 @@ #include "Fire.h" #include "Script.h" #include "Garages.h" +#include "screendroplets.h" uint8 CGameLogic::ActivePlayers; @@ -117,6 +118,9 @@ CGameLogic::Update() } } CEventList::Initialise(); +#ifdef SCREEN_DROPLETS + ScreenDroplets::Initialise(); +#endif CMessages::ClearMessages(); CCarCtrl::ClearInterestingVehicleList(); CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1); @@ -196,6 +200,9 @@ CGameLogic::Update() } } CEventList::Initialise(); +#ifdef SCREEN_DROPLETS + ScreenDroplets::Initialise(); +#endif CMessages::ClearMessages(); CCarCtrl::ClearInterestingVehicleList(); CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1); @@ -245,6 +252,9 @@ CGameLogic::Update() } } CEventList::Initialise(); +#ifdef SCREEN_DROPLETS + ScreenDroplets::Initialise(); +#endif CMessages::ClearMessages(); CCarCtrl::ClearInterestingVehicleList(); CWorld::ClearExcitingStuffFromArea(pPlayerInfo.GetPos(), 4000.0f, 1); diff --git a/src/core/Game.cpp b/src/core/Game.cpp index f7589d2b..1283ecd1 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -88,6 +88,7 @@ #include "debugmenu.h" #include "postfx.h" #include "custompipes.h" +#include "screendroplets.h" #include "crossplatform.h" eLevelName CGame::currLevel; @@ -408,6 +409,9 @@ bool CGame::Initialise(const char* datFile) CPed::Initialise(); CRouteNode::Initialise(); CEventList::Initialise(); +#ifdef SCREEN_DROPLETS + ScreenDroplets::Initialise(); +#endif LoadingScreen("Loading the Game", "Find big buildings", nil); CRenderer::Init(); LoadingScreen("Loading the Game", "Setup game variables", nil); @@ -559,6 +563,9 @@ void CGame::ReInitGameObjectVariables(void) CStreaming::LoadAllRequestedModels(false); CPed::Initialise(); CEventList::Initialise(); +#ifdef SCREEN_DROPLETS + ScreenDroplets::Initialise(); +#endif CWeapon::InitialiseWeapons(); CPopulation::Initialise(); diff --git a/src/core/config.h b/src/core/config.h index db6e5490..8b4356ce 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -237,6 +237,14 @@ enum Config { #ifdef LIBRW //#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) //#define EXTENDED_PIPELINES // custom render pipelines (includes Neo) +//#define SCREEN_DROPLETS // neo water droplets +#endif + +#ifndef EXTENDED_COLOURFILTER +#undef SCREEN_DROPLETS // we need the frontbuffer for this effect +#endif +#ifndef EXTENDED_PIPELINES +#undef SCREEN_DROPLETS // we need neo.txd #endif // Particle diff --git a/src/core/main.cpp b/src/core/main.cpp index 157776e0..843f0671 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -63,7 +63,9 @@ #include "SceneEdit.h" #include "debugmenu.h" #include "Clock.h" +#include "postfx.h" #include "custompipes.h" +#include "screendroplets.h" #include "frontendoption.h" GlobalScene Scene; @@ -419,6 +421,9 @@ Initialise3D(void *param) bool ret = CGame::InitialiseRenderWare(); #ifdef EXTENDED_PIPELINES CustomPipes::CustomPipeInit(); // need Scene.world for this +#endif +#ifdef SCREEN_DROPLETS + ScreenDroplets::InitDraw(); #endif return ret; } @@ -429,6 +434,9 @@ Initialise3D(void *param) static void Terminate3D(void) { +#ifdef SCREEN_DROPLETS + ScreenDroplets::Shutdown(); +#endif #ifdef EXTENDED_PIPELINES CustomPipes::CustomPipeShutdown(); #endif @@ -1142,10 +1150,17 @@ Idle(void *arg) RenderDebugShit(); RenderEffects(); - tbStartTimer(0, "RenderMotionBlur"); if((TheCamera.m_BlurType == MOTION_BLUR_NONE || TheCamera.m_BlurType == MOTION_BLUR_LIGHT_SCENE) && TheCamera.m_ScreenReductionPercentage > 0.0f) TheCamera.SetMotionBlurAlpha(150); + +#ifdef SCREEN_DROPLETS + CPostFX::GetBackBuffer(Scene.camera); + ScreenDroplets::Process(); + ScreenDroplets::Render(); +#endif + + tbStartTimer(0, "RenderMotionBlur"); TheCamera.RenderMotionBlur(); tbEndTimer("RenderMotionBlur"); diff --git a/src/extras/custompipes.cpp b/src/extras/custompipes.cpp index 8c2b6916..bb3ebd2e 100644 --- a/src/extras/custompipes.cpp +++ b/src/extras/custompipes.cpp @@ -44,7 +44,7 @@ CustomMatCopy(void *dst, void *src, int32, int32) -static rw::TexDictionary *neoTxd; +rw::TexDictionary *neoTxd; bool bRenderingEnvMap; int32 EnvMapSize = 128; diff --git a/src/extras/custompipes.h b/src/extras/custompipes.h index 6e9c6517..ca3f0fb4 100644 --- a/src/extras/custompipes.h +++ b/src/extras/custompipes.h @@ -6,6 +6,7 @@ namespace CustomPipes { +extern rw::TexDictionary *neoTxd; struct CustomMatExt { diff --git a/src/extras/custompipes_d3d9.cpp b/src/extras/custompipes_d3d9.cpp index 93973fec..b39efd47 100644 --- a/src/extras/custompipes_d3d9.cpp +++ b/src/extras/custompipes_d3d9.cpp @@ -131,6 +131,7 @@ vehicleRenderCB(rw::Atomic *atomic, rw::d3d9::InstanceDataHeader *header) drawInst(header, inst); inst++; } + d3d::setTexture(1, nil); SetRenderState(SRCBLEND, BLENDSRCALPHA); } diff --git a/src/extras/postfx.cpp b/src/extras/postfx.cpp index fe481658..d3b8b8ac 100644 --- a/src/extras/postfx.cpp +++ b/src/extras/postfx.cpp @@ -363,6 +363,14 @@ CPostFX::NeedFrontBuffer(int32 type) return false; } +void +CPostFX::GetBackBuffer(RwCamera *cam) +{ + RwRasterPushContext(pBackBuffer); + RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0); + RwRasterPopContext(); +} + void CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha) { @@ -405,11 +413,8 @@ CPostFX::Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blu assert(pFrontBuffer); assert(pBackBuffer); - if(NeedBackBuffer()){ - RwRasterPushContext(pBackBuffer); - RwRasterRenderFast(RwCameraGetRaster(cam), 0, 0); - RwRasterPopContext(); - } + if(NeedBackBuffer()) + GetBackBuffer(cam); DefinedState(); diff --git a/src/extras/postfx.h b/src/extras/postfx.h index 658c2d88..f8779a6d 100644 --- a/src/extras/postfx.h +++ b/src/extras/postfx.h @@ -29,6 +29,7 @@ public: static void Render(RwCamera *cam, uint32 red, uint32 green, uint32 blue, uint32 blur, int32 type, uint32 bluralpha); static bool NeedBackBuffer(void); static bool NeedFrontBuffer(int32 type); + static void GetBackBuffer(RwCamera *cam); static bool UseBlurColours(void) { return EffectSwitch != POSTFX_SIMPLE; } }; diff --git a/src/extras/screendroplets.cpp b/src/extras/screendroplets.cpp new file mode 100644 index 00000000..2d34cdcb --- /dev/null +++ b/src/extras/screendroplets.cpp @@ -0,0 +1,791 @@ +#define WITH_D3D +#include "common.h" + +#ifdef SCREEN_DROPLETS + +#ifndef LIBRW +#error "Need librw for SCREEN_DROPLETS" +#endif + +#include "General.h" +#include "Main.h" +#include "RwHelper.h" +#include "Main.h" +#include "Timer.h" +#include "Camera.h" +#include "ZoneCull.h" +#include "Weather.h" +#include "ParticleObject.h" + #include "Pad.h" +#include "RenderBuffer.h" +#include "custompipes.h" +#include "postfx.h" +#include "screendroplets.h" + +// for 640 +#define MAXSIZE 15 +#define MINSIZE 4 + +int ScreenDroplets::ms_initialised; +RwTexture *ScreenDroplets::ms_maskTex; +RwTexture *ScreenDroplets::ms_screenTex; + +bool ScreenDroplets::ms_enabled = true; +bool ScreenDroplets::ms_movingEnabled = true; + +ScreenDroplets::ScreenDrop ScreenDroplets::ms_drops[ScreenDroplets::MAXDROPS]; +int ScreenDroplets::ms_numDrops; +ScreenDroplets::ScreenDropMoving ScreenDroplets::ms_dropsMoving[ScreenDroplets::MAXDROPSMOVING]; +int ScreenDroplets::ms_numDropsMoving; + +CVector ScreenDroplets::ms_prevCamUp; +CVector ScreenDroplets::ms_prevCamPos; +CVector ScreenDroplets::ms_camMoveDelta; +float ScreenDroplets::ms_camMoveDist; +CVector ScreenDroplets::ms_screenMoveDelta; +float ScreenDroplets::ms_screenMoveDist; +float ScreenDroplets::ms_camUpAngle; + +int ScreenDroplets::ms_splashDuration; +CParticleObject *ScreenDroplets::ms_splashObject; + +struct Im2DVertexUV2 : rw::RWDEVICE::Im2DVertex +{ + rw::float32 u2, v2; +}; + +#ifdef RW_D3D9 +static void *screenDroplet_PS; +#endif +#ifdef RW_GL3 +static rw::gl3::Shader *screenDroplet; +#endif + +// platform specific +static void openim2d_uv2(void); +static void closeim2d_uv2(void); +static void RenderIndexedPrimitive_UV2(RwPrimitiveType primType, Im2DVertexUV2 *vertices, RwInt32 numVertices, RwImVertexIndex *indices, RwInt32 numIndices); + +static Im2DVertexUV2 VertexBuffer[TEMPBUFFERVERTSIZE]; + +void +ScreenDroplets::Initialise(void) +{ + Clear(); + ms_splashDuration = -1; + ms_splashObject = nil; +} + +void +ScreenDroplets::InitDraw(void) +{ + if(CustomPipes::neoTxd) + ms_maskTex = CustomPipes::neoTxd->find("dropmask"); + + ms_screenTex = RwTextureCreate(nil); + RwTextureSetFilterMode(ms_screenTex, rwFILTERLINEAR); + + openim2d_uv2(); +#ifdef RW_D3D9 +#include "shaders/screenDroplet_PS.inc" + screenDroplet_PS = rw::d3d::createPixelShader(screenDroplet_PS_cso); +#endif +#ifdef RW_GL3 + using namespace rw::gl3; + { +#include "shaders/im2d_UV2_gl.inc" +#include "shaders/screenDroplet_fs_gl.inc" + const char *vs[] = { shaderDecl, header_vert_src, im2d_UV2_vert_src, nil }; + const char *fs[] = { shaderDecl, header_frag_src, screenDroplet_frag_src, nil }; + screenDroplet = Shader::create(vs, fs); + assert(screenDroplet); + } +#endif + + ms_initialised = 1; +} + +void +ScreenDroplets::Shutdown(void) +{ + if(ms_maskTex){ + RwTextureDestroy(ms_maskTex); + ms_maskTex = nil; + } + if(ms_screenTex){ + RwTextureSetRaster(ms_screenTex, nil); + RwTextureDestroy(ms_screenTex); + ms_screenTex = nil; + } +#ifdef RW_D3D9 + if(screenDroplet_PS){ + rw::d3d::destroyPixelShader(screenDroplet_PS); + screenDroplet_PS = nil; + } +#endif +#ifdef RW_GL3 + if(screenDroplet){ + screenDroplet->destroy(); + screenDroplet = nil; + } +#endif + + closeim2d_uv2(); +} + +void +ScreenDroplets::Process(void) +{ + ProcessCameraMovement(); + SprayDrops(); + ProcessMoving(); + Fade(); +} + +static void +FlushBuffer(void) +{ + if(TempBufferIndicesStored){ + RenderIndexedPrimitive_UV2(rwPRIMTYPETRILIST, + VertexBuffer, TempBufferVerticesStored, + TempBufferRenderIndexList, TempBufferIndicesStored); + TempBufferVerticesStored = 0; + TempBufferIndicesStored = 0; + } +} + +static int +StartStoring(int numIndices, int numVertices, RwImVertexIndex **indexStart, Im2DVertexUV2 **vertexStart) +{ + if(TempBufferIndicesStored + numIndices >= TEMPBUFFERINDEXSIZE || + TempBufferVerticesStored + numVertices >= TEMPBUFFERVERTSIZE) + FlushBuffer(); + *indexStart = &TempBufferRenderIndexList[TempBufferIndicesStored]; + *vertexStart = &VertexBuffer[TempBufferVerticesStored]; + int vertOffset = TempBufferVerticesStored; + TempBufferIndicesStored += numIndices; + TempBufferVerticesStored += numVertices; + return vertOffset; +} + +void +ScreenDroplets::Render(void) +{ + ScreenDrop *drop; + + DefinedState(); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(ms_maskTex)); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + + RwTextureSetRaster(ms_screenTex, CPostFX::pBackBuffer); +#ifdef RW_D3D9 + rw::d3d::im2dOverridePS = screenDroplet_PS; + rw::d3d::setTexture(1, ms_screenTex); +#endif +#ifdef RW_GL3 + rw::gl3::im2dOverrideShader = screenDroplet; + rw::gl3::setTexture(1, ms_screenTex); +#endif + + RenderBuffer::ClearRenderBuffer(); + for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++) + if(drop->active) + AddToRenderList(drop); + FlushBuffer(); + +#ifdef RW_D3D9 + rw::d3d::im2dOverridePS = nil; + rw::d3d::setTexture(1, nil); +#endif +#ifdef RW_GL3 + rw::gl3::im2dOverrideShader = nil; + rw::gl3::setTexture(1, nil); +#endif + + RwRenderStateSet(rwRENDERSTATEFOGENABLE, FALSE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, FALSE); +} + +void +ScreenDroplets::AddToRenderList(ScreenDroplets::ScreenDrop *drop) +{ + static float xy[] = { + -1.0f, -1.0f, + -1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f + }; + static float uv[] = { + 0.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, 0.0f + }; + + int i; + RwImVertexIndex *indices; + Im2DVertexUV2 *verts; + int first = StartStoring(6, 4, &indices, &verts); + + float scale = 0.5f*SCREEN_SCALE_X(drop->size); + + float screenz = RwIm2DGetNearScreenZ(); + float z = RwCameraGetNearClipPlane(Scene.camera); + float recipz = 1.0f/z; + + float magSize = SCREEN_SCALE_Y(drop->magnification*(300.0f-40.0f) + 40.0f); + float ul = drop->x - magSize; + float vt = drop->y - magSize; + float ur = drop->x + magSize; + float vb = drop->y + magSize; + ul = Max(ul, 0.0f)/RwRasterGetWidth(CPostFX::pBackBuffer); + vt = Max(vt, 0.0f)/RwRasterGetHeight(CPostFX::pBackBuffer); + ur = Min(ur, SCREEN_WIDTH)/RwRasterGetWidth(CPostFX::pBackBuffer); + vb = Min(vb, SCREEN_HEIGHT)/RwRasterGetHeight(CPostFX::pBackBuffer); + + for(i = 0; i < 4; i++){ + RwIm2DVertexSetScreenX(&verts[i], drop->x + xy[i*2]*scale); + RwIm2DVertexSetScreenY(&verts[i], drop->y + xy[i*2+1]*scale); + RwIm2DVertexSetScreenZ(&verts[i], screenz); + RwIm2DVertexSetCameraZ(&verts[i], z); + RwIm2DVertexSetRecipCameraZ(&verts[i], recipz); + RwIm2DVertexSetIntRGBA(&verts[i], drop->color.r, drop->color.g, drop->color.b, drop->color.a); + RwIm2DVertexSetU(&verts[i], uv[i*2], recipz); + RwIm2DVertexSetV(&verts[i], uv[i*2+1], recipz); + + verts[i].u2 = i < 2 ? ul : ur; + verts[i].v2 = i % 3 ? vt : vb; + } + indices[0] = first + 0; + indices[1] = first + 1; + indices[2] = first + 2; + indices[3] = first + 2; + indices[4] = first + 3; + indices[5] = first + 0; +} + +void +ScreenDroplets::Clear(void) +{ + ScreenDrop *drop; + for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++) + drop->active = false; + ms_numDrops = 0; +} + +ScreenDroplets::ScreenDrop* +ScreenDroplets::NewDrop(float x, float y, float size, float lifetime, bool fades, int r, int g, int b) +{ + ScreenDrop *drop; + int i; + + for(i = 0, drop = ms_drops; i < MAXDROPS; i++, drop++) + if(!ms_drops[i].active) + goto found; + return nil; +found: + ms_numDrops++; + drop->x = x; + drop->y = y; + drop->size = size; + drop->magnification = (MAXSIZE - size + 1.0f) / (MAXSIZE - MINSIZE + 1.0f); + drop->fades = fades; + drop->active = true; + drop->color.r = r; + drop->color.g = g; + drop->color.b = b; + drop->color.a = 255; + drop->time = 0.0f; + drop->lifetime = lifetime; + return drop; +} + +void +ScreenDroplets::SetMoving(ScreenDroplets::ScreenDrop *drop) +{ + ScreenDropMoving *moving; + for(moving = ms_dropsMoving; moving < &ms_dropsMoving[MAXDROPSMOVING]; moving++) + if(moving->drop == nil) + goto found; + return; +found: + ms_numDropsMoving++; + moving->drop = drop; + moving->dist = 0.0f; +} + +void +ScreenDroplets::FillScreen(int n) +{ + float x, y, size; + ScreenDrop *drop; + + if(!ms_initialised) + return; + ms_numDrops = 0; + for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++){ + drop->active = false; + if(drop < &ms_drops[n]){ + x = CGeneral::GetRandomNumber() % (int)SCREEN_WIDTH; + y = CGeneral::GetRandomNumber() % (int)SCREEN_HEIGHT; + size = CGeneral::GetRandomNumberInRange(MINSIZE, MAXSIZE); + NewDrop(x, y, size, 2000.0f, true); + } + } +} + +void +ScreenDroplets::FillScreenMoving(float amount, bool isBlood) +{ + int n = (ms_screenMoveDelta.z > 5.0f ? 1.5f : 1.0f)*amount*20.0f; + float x, y, size; + ScreenDrop *drop; + + while(n--) + if(ms_numDrops < MAXDROPS && ms_numDropsMoving < MAXDROPSMOVING){ + x = CGeneral::GetRandomNumber() % (int)SCREEN_WIDTH; + y = CGeneral::GetRandomNumber() % (int)SCREEN_HEIGHT; + size = CGeneral::GetRandomNumberInRange(MINSIZE, MAXSIZE); + drop = nil; + if(isBlood) + drop = NewDrop(x, y, size, 2000.0f, true, 255, 0, 0); + else + drop = NewDrop(x, y, size, 2000.0f, true); + if(drop) + SetMoving(drop); + } +} + +void +ScreenDroplets::RegisterSplash(CParticleObject *pobj) +{ + CVector dist = pobj->GetPosition() - ms_prevCamPos; + if(dist.MagnitudeSqr() < 20.0f){ + ms_splashDuration = 14; + ms_splashObject = pobj; + } +} + +void +ScreenDroplets::ProcessCameraMovement(void) +{ + RwMatrix *camMat = RwFrameGetMatrix(RwCameraGetFrame(Scene.camera)); + CVector camPos = camMat->pos; + CVector camUp = camMat->at; + ms_camMoveDelta = camPos - ms_prevCamPos; + ms_camMoveDist = ms_camMoveDelta.Magnitude(); + + ms_prevCamUp = camUp; + ms_prevCamPos = camPos; + + ms_screenMoveDelta.x = -RwV3dDotProduct(&camMat->right, (RwV3d*)&ms_camMoveDelta); + ms_screenMoveDelta.y = RwV3dDotProduct(&camMat->up, (RwV3d*)&ms_camMoveDelta); + ms_screenMoveDelta.z = RwV3dDotProduct(&camMat->at, (RwV3d*)&ms_camMoveDelta); + ms_screenMoveDelta *= 10.0f; + ms_screenMoveDist = ms_screenMoveDelta.Magnitude2D(); + + uint16 mode = TheCamera.Cams[TheCamera.ActiveCam].Mode; + bool isTopDown = mode == CCam::MODE_TOPDOWN || mode == CCam::MODE_GTACLASSIC || mode == CCam::MODE_TOP_DOWN_PED; + bool isLookingInDirection = CPad::GetPad(0)->GetLookBehindForCar() || CPad::GetPad(0)->GetLookLeft() || CPad::GetPad(0)->GetLookRight(); + ms_enabled = !isTopDown && !isLookingInDirection; + ms_movingEnabled = !isTopDown && !isLookingInDirection; + + // 0 when looking stright up, 180 when looking up or down + ms_camUpAngle = RADTODEG(Acos(clamp(camUp.z, -1.0f, 1.0f))); +} + +void +ScreenDroplets::SprayDrops(void) +{ + bool noRain = CCullZones::PlayerNoRain() || CCullZones::CamNoRain(); + if(!noRain && CWeather::Rain > 0.0f && ms_enabled){ + // 180 when looking stright up, 0 when looking up or down + float angle = 180.0f - ms_camUpAngle; + angle = Max(angle, 40.0f); // want at least some rain + FillScreenMoving((angle - 40.0f) / 150.0f * CWeather::Rain * 0.5f); + } + + int i; + for(i = 0; i < MAX_AUDIOHYDRANTS; i++){ + CAudioHydrant *hyd = CAudioHydrant::Get(i); + if (hyd->pParticleObject){ + CVector dist = hyd->pParticleObject->GetPosition() - ms_prevCamPos; + if(dist.MagnitudeSqr() > 40.0f || + DotProduct(dist, ms_prevCamUp) < 0.0f) continue; + + FillScreenMoving(1.0f); + } + } + + static int ndrops[] = { + 125, 250, 500, 1000, 1000, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if(ms_splashDuration >= 0){ + if(ms_numDrops < MAXDROPS) { + float numDropMult = 1.0f; + if(ms_splashObject){ + float dist = (ms_splashObject->GetPosition() - ms_prevCamPos).Magnitude(); + numDropMult = 1.0f - (dist - 5.0f)/15.0f; + if(numDropMult < 0) numDropMult = 0.0f; // fix + } + int n = ndrops[ms_splashDuration] * numDropMult; + while(n--) + if(ms_numDrops < MAXDROPS){ + float x = CGeneral::GetRandomNumber() % (int)SCREEN_WIDTH; + float y = CGeneral::GetRandomNumber() % (int)SCREEN_HEIGHT; + float size = CGeneral::GetRandomNumberInRange(MINSIZE, MAXSIZE); + NewDrop(x, y, size, 10000.0f, false); + } + } + ms_splashDuration--; + } +} + +void +ScreenDroplets::NewTrace(ScreenDroplets::ScreenDropMoving *moving) +{ + if(ms_numDrops < MAXDROPS){ + moving->dist = 0.0f; + NewDrop(moving->drop->x, moving->drop->y, MINSIZE, 500.0f, true, + moving->drop->color.r, moving->drop->color.g, moving->drop->color.b); + } +} + +void +ScreenDroplets::MoveDrop(ScreenDroplets::ScreenDropMoving *moving) +{ + ScreenDrop *drop = moving->drop; + if(!ms_movingEnabled) + return; + if(!drop->active){ + moving->drop = nil; + ms_numDropsMoving--; + return; + } + if(ms_screenMoveDelta.z > 0.0f && ms_camMoveDist > 0.3f){ + if(ms_screenMoveDist > 0.5f && TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON){ + // movement when camera turns + moving->dist += ms_screenMoveDist; + if(moving->dist > 20.0f && drop->color.a > 100) + NewTrace(moving); + + drop->x -= ms_screenMoveDelta.x; + drop->y += ms_screenMoveDelta.y; + }else{ + // movement out of center + float d = ms_screenMoveDelta.z*0.2f; + float dx, dy, sum; + dx = drop->x - SCREEN_WIDTH*0.5f + ms_screenMoveDelta.x; + if(TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON) + dy = drop->y - SCREEN_HEIGHT*1.2f - ms_screenMoveDelta.y; + else + dy = drop->y - SCREEN_HEIGHT*0.5f - ms_screenMoveDelta.y; + sum = fabs(dx) + fabs(dy); + if(sum > 0.001f){ + dx /= sum; + dy /= sum; + } + moving->dist += d; + if(moving->dist > 20.0f && drop->color.a > 100) + NewTrace(moving); + drop->x += dx * d; + drop->y += dy * d; + } + + if(drop->x < 0.0f || drop->y < 0.0f || + drop->x > SCREEN_WIDTH || drop->y > SCREEN_HEIGHT){ + moving->drop = nil; + ms_numDropsMoving--; + } + } +} + +void +ScreenDroplets::ProcessMoving(void) +{ + ScreenDropMoving *moving; + if(!ms_movingEnabled) + return; + for(moving = ms_dropsMoving; moving < &ms_dropsMoving[MAXDROPSMOVING]; moving++) + if(moving->drop) + MoveDrop(moving); +} + +void +ScreenDroplets::Fade(void) +{ + ScreenDrop *drop; + for(drop = &ms_drops[0]; drop < &ms_drops[MAXDROPS]; drop++) + if(drop->active) + drop->Fade(); +} + +void +ScreenDroplets::ScreenDrop::Fade(void) +{ + int delta = CTimer::GetTimeStepInMilliseconds(); + time += delta; + if(time < lifetime){ + color.a = 255 - time/lifetime*255; + }else if(fades){ + ScreenDroplets::ms_numDrops--; + active = false; + } +} + + +/* + * Im2D with two uv coors + */ + +#ifdef RW_D3D9 +// stolen from RW, not in a public header +namespace rw { +namespace d3d { +void addDynamicVB(uint32 length, uint32 fvf, IDirect3DVertexBuffer9 **buf); // NB: don't share this pointer +void removeDynamicVB(IDirect3DVertexBuffer9 **buf); +void addDynamicIB(uint32 length, IDirect3DIndexBuffer9 **buf); // NB: don't share this pointer +void removeDynamicIB(IDirect3DIndexBuffer9 **buf); +} +} +// different than im2d +#define NUMINDICES 1024 +#define NUMVERTICES 1024 + +static int primTypeMap[] = { + D3DPT_POINTLIST, // invalid + D3DPT_LINELIST, + D3DPT_LINESTRIP, + D3DPT_TRIANGLELIST, + D3DPT_TRIANGLESTRIP, + D3DPT_TRIANGLEFAN, + D3DPT_POINTLIST, // actually not supported! +}; +// end of stolen stuff + + +static IDirect3DVertexDeclaration9 *im2ddecl_uv2; +static IDirect3DVertexBuffer9 *im2dvertbuf_uv2; +static IDirect3DIndexBuffer9 *im2dindbuf_uv2; + +void +openim2d_uv2(void) +{ + using namespace rw; + using namespace d3d; + D3DVERTEXELEMENT9 elements[5] = { + { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 }, + { 0, offsetof(Im2DVertexUV2, color), D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }, + { 0, offsetof(Im2DVertexUV2, u), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, + { 0, offsetof(Im2DVertexUV2, u2), D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, + D3DDECL_END() + }; + assert(im2ddecl_uv2 == nil); + im2ddecl_uv2 = (IDirect3DVertexDeclaration9*)d3d9::createVertexDeclaration((d3d9::VertexElement*)elements); + assert(im2ddecl_uv2); + + assert(im2dvertbuf_uv2 == nil); + im2dvertbuf_uv2 = (IDirect3DVertexBuffer9*)createVertexBuffer(NUMVERTICES*sizeof(Im2DVertexUV2), 0, true); + assert(im2dvertbuf_uv2); + addDynamicVB(NUMVERTICES*sizeof(Im2DVertexUV2), 0, &im2dvertbuf_uv2); + + assert(im2dindbuf_uv2 == nil); + im2dindbuf_uv2 = (IDirect3DIndexBuffer9*)createIndexBuffer(NUMINDICES*sizeof(rw::uint16), true); + assert(im2dindbuf_uv2); + addDynamicIB(NUMINDICES*sizeof(rw::uint16), &im2dindbuf_uv2); +} + +void +closeim2d_uv2(void) +{ + using namespace rw; + using namespace d3d; + + d3d9::destroyVertexDeclaration(im2ddecl_uv2); + im2ddecl_uv2 = nil; + + removeDynamicVB(&im2dvertbuf_uv2); + destroyVertexBuffer(im2dvertbuf_uv2); + im2dvertbuf_uv2 = nil; + + removeDynamicIB(&im2dindbuf_uv2); + destroyIndexBuffer(im2dindbuf_uv2); + im2dindbuf_uv2 = nil; +} + +void +RenderIndexedPrimitive_UV2(RwPrimitiveType primType, Im2DVertexUV2 *vertices, RwInt32 numVertices, RwImVertexIndex *indices, RwInt32 numIndices) +{ + using namespace rw; + using namespace d3d; + + if(numVertices > NUMVERTICES || + numIndices > NUMINDICES){ + // TODO: error + return; + } + rw::uint16 *lockedindices = lockIndices(im2dindbuf_uv2, 0, numIndices*sizeof(rw::uint16), D3DLOCK_DISCARD); + memcpy(lockedindices, indices, numIndices*sizeof(rw::uint16)); + unlockIndices(im2dindbuf_uv2); + + rw::uint8 *lockedvertices = lockVertices(im2dvertbuf_uv2, 0, numVertices*sizeof(Im2DVertexUV2), D3DLOCK_DISCARD); + memcpy(lockedvertices, vertices, numVertices*sizeof(Im2DVertexUV2)); + unlockVertices(im2dvertbuf_uv2); + + setStreamSource(0, im2dvertbuf_uv2, 0, sizeof(Im2DVertexUV2)); + setIndices(im2dindbuf_uv2); + setVertexDeclaration(im2ddecl_uv2); + + if(im2dOverridePS) + setPixelShader(im2dOverridePS); + else if(engine->device.getRenderState(TEXTURERASTER)) + setPixelShader(im2d_tex_PS); + else + setPixelShader(im2d_PS); + + d3d::flushCache(); + + rw::uint32 primCount = 0; + switch(primType){ + case PRIMTYPELINELIST: + primCount = numIndices/2; + break; + case PRIMTYPEPOLYLINE: + primCount = numIndices-1; + break; + case PRIMTYPETRILIST: + primCount = numIndices/3; + break; + case PRIMTYPETRISTRIP: + primCount = numIndices-2; + break; + case PRIMTYPETRIFAN: + primCount = numIndices-2; + break; + case PRIMTYPEPOINTLIST: + primCount = numIndices; + break; + } + d3ddevice->DrawIndexedPrimitive((D3DPRIMITIVETYPE)primTypeMap[primType], 0, + 0, numVertices, + 0, primCount); +} +#endif + +#ifdef RW_GL3 +// different than im2d +#define NUMINDICES 1024 +#define NUMVERTICES 1024 + +static rw::gl3::AttribDesc im2d_UV2_attribDesc[4] = { + { rw::gl3::ATTRIB_POS, GL_FLOAT, GL_FALSE, 4, + sizeof(Im2DVertexUV2), 0 }, + { rw::gl3::ATTRIB_COLOR, GL_UNSIGNED_BYTE, GL_TRUE, 4, + sizeof(Im2DVertexUV2), offsetof(Im2DVertexUV2, r) }, + { rw::gl3::ATTRIB_TEXCOORDS0, GL_FLOAT, GL_FALSE, 2, + sizeof(Im2DVertexUV2), offsetof(Im2DVertexUV2, u) }, + { rw::gl3::ATTRIB_TEXCOORDS1, GL_FLOAT, GL_FALSE, 2, + sizeof(Im2DVertexUV2), offsetof(Im2DVertexUV2, u2) } +}; + +static int primTypeMap[] = { + GL_POINTS, // invalid + GL_LINES, + GL_LINE_STRIP, + GL_TRIANGLES, + GL_TRIANGLE_STRIP, + GL_TRIANGLE_FAN, + GL_POINTS +}; + +static int32 u_xform; + +uint32 im2D_UV2_Vbo, im2D_UV2_Ibo; +#ifdef RW_GL_USE_VAOS +uint32 im2D_UV2_Vao; +#endif + +void +openim2d_uv2(void) +{ + u_xform = rw::gl3::registerUniform("u_xform"); // this doesn't add a new one, so it's safe + + glGenBuffers(1, &im2D_UV2_Ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, im2D_UV2_Ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, NUMINDICES*2, nil, GL_STREAM_DRAW); + + glGenBuffers(1, &im2D_UV2_Vbo); + glBindBuffer(GL_ARRAY_BUFFER, im2D_UV2_Vbo); + glBufferData(GL_ARRAY_BUFFER, NUMVERTICES*sizeof(Im2DVertexUV2), nil, GL_STREAM_DRAW); + +#ifdef RW_GL_USE_VAOS + glGenVertexArrays(1, &im2D_UV2_Vao); + glBindVertexArray(im2D_UV2_Vao); + setAttribPointers(im2d_UV2_attribDesc, 4); +#endif +} + +void +closeim2d_uv2(void) +{ + glDeleteBuffers(1, &im2D_UV2_Ibo); + glDeleteBuffers(1, &im2D_UV2_Vbo); +#ifdef RW_GL_USE_VAOS + glDeleteVertexArrays(1, &im2D_UV2_Vao); +#endif +} + +void +RenderIndexedPrimitive_UV2(RwPrimitiveType primType, Im2DVertexUV2 *vertices, RwInt32 numVertices, RwImVertexIndex *indices, RwInt32 numIndices) +{ + using namespace rw; + using namespace gl3; + + GLfloat xform[4]; + Camera *cam; + cam = (Camera*)engine->currentCamera; + +#ifdef RW_GL_USE_VAOS + glBindVertexArray(im2D_UV2_Vao); +#endif + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, im2D_UV2_Ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, NUMINDICES*2, nil, GL_STREAM_DRAW); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numIndices*2, indices); + + glBindBuffer(GL_ARRAY_BUFFER, im2D_UV2_Vbo); + glBufferData(GL_ARRAY_BUFFER, NUMVERTICES*sizeof(Im2DVertexUV2), nil, GL_STREAM_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices*sizeof(Im2DVertexUV2), vertices); + + xform[0] = 2.0f/cam->frameBuffer->width; + xform[1] = -2.0f/cam->frameBuffer->height; + xform[2] = -1.0f; + xform[3] = 1.0f; + + if(im2dOverrideShader) + im2dOverrideShader->use(); + else + assert(0);//im2dShader->use(); +#ifndef RW_GL_USE_VAOS + setAttribPointers(im2d_UV2_attribDesc, 4); +#endif + + glUniform4fv(currentShader->uniformLocations[u_xform], 1, xform); + + flushCache(); + glDrawElements(primTypeMap[primType], numIndices, + GL_UNSIGNED_SHORT, nil); +#ifndef RW_GL_USE_VAOS + disableAttribPointers(im2d_UV2_attribDesc, 4); +#endif +} +#endif + +#endif diff --git a/src/extras/screendroplets.h b/src/extras/screendroplets.h new file mode 100644 index 00000000..090b1923 --- /dev/null +++ b/src/extras/screendroplets.h @@ -0,0 +1,78 @@ +#pragma once + +#ifdef SCREEN_DROPLETS + +class CParticleObject; + +class ScreenDroplets +{ +public: + enum { + MAXDROPS = 2000, + MAXDROPSMOVING = 700 + }; + + class ScreenDrop + { + public: + float x, y, time; // shorts on xbox (short float?) + float size, magnification, lifetime; // " + CRGBA color; + bool active; + bool fades; + + void Fade(void); + }; + + struct ScreenDropMoving + { + ScreenDrop *drop; + float dist; + }; + + static int ms_initialised; + static RwTexture *ms_maskTex; + static RwTexture *ms_screenTex; + + static bool ms_enabled; + static bool ms_movingEnabled; + + static ScreenDrop ms_drops[MAXDROPS]; + static int ms_numDrops; + static ScreenDropMoving ms_dropsMoving[MAXDROPSMOVING]; + static int ms_numDropsMoving; + + static CVector ms_prevCamUp; + static CVector ms_prevCamPos; + static CVector ms_camMoveDelta; + static float ms_camMoveDist; + static CVector ms_screenMoveDelta; + static float ms_screenMoveDist; + static float ms_camUpAngle; + + static int ms_splashDuration; + static CParticleObject *ms_splashObject; + + static void Initialise(void); + static void InitDraw(void); + static void Shutdown(void); + static void Process(void); + static void Render(void); + static void AddToRenderList(ScreenDrop *drop); + + static void Clear(void); + static ScreenDrop *NewDrop(float x, float y, float size, float lifetime, bool fades, int r = 255, int g = 255, int b = 255); + static void SetMoving(ScreenDroplets::ScreenDrop *drop); + static void FillScreen(int n); + static void FillScreenMoving(float amount, bool isBlood = false); + static void RegisterSplash(CParticleObject *pobj); + + static void ProcessCameraMovement(void); + static void SprayDrops(void); + static void NewTrace(ScreenDroplets::ScreenDropMoving *moving); + static void MoveDrop(ScreenDropMoving *moving); + static void ProcessMoving(void); + static void Fade(void); +}; + +#endif diff --git a/src/extras/shaders/Makefile b/src/extras/shaders/Makefile index 4b6027e2..51e009d6 100644 --- a/src/extras/shaders/Makefile +++ b/src/extras/shaders/Makefile @@ -2,7 +2,8 @@ all: im2d_gl.inc simple_fs_gl.inc default_UV2_gl.inc \ colourfilterIII_fs_gl.inc contrast_fs_gl.inc \ neoRim_gl.inc neoRimSkin_gl.inc \ neoWorldIII_fs_gl.inc neoGloss_vs_gl.inc neoGloss_fs_gl.inc \ - neoVehicle_vs_gl.inc neoVehicle_fs_gl.inc + neoVehicle_vs_gl.inc neoVehicle_fs_gl.inc \ + im2d_UV2_gl.inc screenDroplet_fs_gl.inc im2d_gl.inc: im2d.vert (echo 'const char *im2d_vert_src =';\ @@ -66,3 +67,13 @@ neoVehicle_fs_gl.inc: neoVehicle.frag (echo 'const char *neoVehicle_frag_src =';\ sed 's/..*/"&\\n"/' neoVehicle.frag;\ echo ';') >neoVehicle_fs_gl.inc + +im2d_UV2_gl.inc: im2d_UV2.vert + (echo 'const char *im2d_UV2_vert_src =';\ + sed 's/..*/"&\\n"/' im2d_UV2.vert;\ + echo ';') >im2d_UV2_gl.inc + +screenDroplet_fs_gl.inc: screenDroplet.frag + (echo 'const char *screenDroplet_frag_src =';\ + sed 's/..*/"&\\n"/' screenDroplet.frag;\ + echo ';') >screenDroplet_fs_gl.inc diff --git a/src/extras/shaders/im2d_UV2.vert b/src/extras/shaders/im2d_UV2.vert new file mode 100644 index 00000000..e5fd4d08 --- /dev/null +++ b/src/extras/shaders/im2d_UV2.vert @@ -0,0 +1,21 @@ +uniform vec4 u_xform; + +VSIN(ATTRIB_POS) vec4 in_pos; + +VSOUT vec4 v_color; +VSOUT vec2 v_tex0; +VSOUT vec2 v_tex1; +VSOUT float v_fog; + +void +main(void) +{ + gl_Position = in_pos; + gl_Position.w = 1.0; + gl_Position.xy = gl_Position.xy * u_xform.xy + u_xform.zw; + v_fog = DoFog(gl_Position.z); + gl_Position.xyz *= gl_Position.w; + v_color = in_color; + v_tex0 = in_tex0; + v_tex1 = in_tex1; +} diff --git a/src/extras/shaders/im2d_UV2_gl.inc b/src/extras/shaders/im2d_UV2_gl.inc new file mode 100644 index 00000000..3feb2bc1 --- /dev/null +++ b/src/extras/shaders/im2d_UV2_gl.inc @@ -0,0 +1,23 @@ +const char *im2d_UV2_vert_src = +"uniform vec4 u_xform;\n" + +"VSIN(ATTRIB_POS) vec4 in_pos;\n" + +"VSOUT vec4 v_color;\n" +"VSOUT vec2 v_tex0;\n" +"VSOUT vec2 v_tex1;\n" +"VSOUT float v_fog;\n" + +"void\n" +"main(void)\n" +"{\n" +" gl_Position = in_pos;\n" +" gl_Position.w = 1.0;\n" +" gl_Position.xy = gl_Position.xy * u_xform.xy + u_xform.zw;\n" +" v_fog = DoFog(gl_Position.z);\n" +" gl_Position.xyz *= gl_Position.w;\n" +" v_color = in_color;\n" +" v_tex0 = in_tex0;\n" +" v_tex1 = in_tex1;\n" +"}\n" +; diff --git a/src/extras/shaders/screenDroplet.frag b/src/extras/shaders/screenDroplet.frag new file mode 100644 index 00000000..84d30bd5 --- /dev/null +++ b/src/extras/shaders/screenDroplet.frag @@ -0,0 +1,18 @@ +uniform sampler2D tex0; +uniform sampler2D tex1; + +FSIN vec4 v_color; +FSIN vec2 v_tex0; +FSIN vec2 v_tex1; +FSIN float v_fog; + +void +main(void) +{ + vec4 color; + color = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y)); + color *= texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y)); + + FRAGCOLOR(color); +} + diff --git a/src/extras/shaders/screenDroplet_PS.cso b/src/extras/shaders/screenDroplet_PS.cso new file mode 100644 index 0000000000000000000000000000000000000000..5508096bd68b79407a7b647cf586b9fba5390edd GIT binary patch literal 324 zcmZusI|{;35S$l3q!4le!ITOTOvECkiG@XMjHMvr2L&Z!QV2FVLXKdcCWrDIJ|_=@ z7A`D1GdsI)A2canvJZbT_SyjMOi8gn=0z*4y3H^rQ3Tcp`8u$Fm_nSkipFrames = 3; #endif pobj->m_nCreationChance = 0; +#ifdef SCREEN_DROPLETS + ScreenDroplets::RegisterSplash(pobj); +#endif break; } diff --git a/src/objects/ParticleObject.h b/src/objects/ParticleObject.h index 34a672bb..e4e7fcd2 100644 --- a/src/objects/ParticleObject.h +++ b/src/objects/ParticleObject.h @@ -103,4 +103,6 @@ public: static bool Add (CParticleObject *particleobject); static void Remove(CParticleObject *particleobject); + + static CAudioHydrant *Get(int n); // for neo screen droplets }; \ No newline at end of file From 9e45feb4fa0a841b1d059bcab8507fd80708d6e7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 19 Nov 2020 21:12:20 +0200 Subject: [PATCH 070/129] Reorganize CPed functions into their original cpp files --- src/control/Pickups.cpp | 82 + src/core/FileLoader.cpp | 1 - src/modelinfo/PedModelInfo.h | 1 - src/peds/CivilianPed.cpp | 42 + src/peds/Ped.cpp | 19334 +++++++++------------------------ src/peds/Ped.h | 48 +- src/peds/PedAI.cpp | 5413 +++++++++ src/peds/PedFight.cpp | 3250 ++++++ src/peds/PedStats.cpp | 118 - src/peds/PedStats.h | 80 - src/peds/PedType.cpp | 113 + src/peds/PedType.h | 79 + src/render/Renderer.cpp | 31 + src/vehicles/Automobile.cpp | 87 + src/weapons/Weapon.cpp | 10 + 15 files changed, 14349 insertions(+), 14340 deletions(-) create mode 100644 src/peds/PedAI.cpp create mode 100644 src/peds/PedFight.cpp delete mode 100644 src/peds/PedStats.cpp delete mode 100644 src/peds/PedStats.h diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 6fea43fb..8951ed82 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -1432,3 +1432,85 @@ CPacManPickups::ResetPowerPillsCarriedByPlayer() FindPlayerVehicle()->m_fForceMultiplier = 1.0f; } } + +void +CPed::CreateDeadPedMoney(void) +{ + if (!CGame::nastyGame) + return; + + int mi = GetModelIndex(); + + if ((mi >= MI_COP && mi <= MI_FIREMAN) || CharCreatedBy == MISSION_CHAR || bInVehicle) + return; + + int money = CGeneral::GetRandomNumber() % 60; + if (money < 10) + return; + + if (money == 43) + money = 700; + + int pickupCount = money / 40 + 1; + int moneyPerPickup = money / pickupCount; + + for(int i = 0; i < pickupCount; i++) { + // (CGeneral::GetRandomNumber() % 256) * PI / 128 gives a float up to something TWOPI-ish. + float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().x; + float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().y; + bool found = false; + float groundZ = CWorld::FindGroundZFor3DCoord(pickupX, pickupY, GetPosition().z, &found) + 0.5f; + if (found) { + CPickups::GenerateNewOne(CVector(pickupX, pickupY, groundZ), MI_MONEY, PICKUP_MONEY, moneyPerPickup + (CGeneral::GetRandomNumber() & 7)); + } + } +} + +void +CPed::CreateDeadPedWeaponPickups(void) +{ + bool found = false; + float angleToPed; + CVector pickupPos; + + if (bInVehicle) + return; + + for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { + + eWeaponType weapon = GetWeapon(i).m_eWeaponType; + int weaponAmmo = GetWeapon(i).m_nAmmoTotal; + if (weapon == WEAPONTYPE_UNARMED || weapon == WEAPONTYPE_DETONATOR || weaponAmmo == 0) + continue; + + angleToPed = i * 1.75f; + pickupPos = GetPosition(); + pickupPos.x += 1.5f * Sin(angleToPed); + pickupPos.y += 1.5f * Cos(angleToPed); + pickupPos.z = CWorld::FindGroundZFor3DCoord(pickupPos.x, pickupPos.y, pickupPos.z, &found) + 0.5f; + + CVector pedPos = GetPosition(); + pedPos.z += 0.3f; + + CVector pedToPickup = pickupPos - pedPos; + float distance = pedToPickup.Magnitude(); + + // outer edge of pickup + distance = (distance + 0.3f) / distance; + CVector pickupPos2 = pedPos; + pickupPos2 += distance * pedToPickup; + + // pickup must be on ground and line to its edge must be clear + if (!found || CWorld::GetIsLineOfSightClear(pickupPos2, pedPos, true, false, false, false, false, false, false)) { + // otherwise try another position (but disregard second check apparently) + angleToPed += 3.14f; + pickupPos = GetPosition(); + pickupPos.x += 1.5f * Sin(angleToPed); + pickupPos.y += 1.5f * Cos(angleToPed); + pickupPos.z = CWorld::FindGroundZFor3DCoord(pickupPos.x, pickupPos.y, pickupPos.z, &found) + 0.5f; + } + if (found) + CPickups::GenerateNewOne_WeaponType(pickupPos, weapon, PICKUP_ONCE_TIMEOUT, Min(weaponAmmo, AmmoForWeapon_OnStreet[weapon])); + } + ClearWeapons(); +} \ No newline at end of file diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index 3f731658..f46b6134 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -11,7 +11,6 @@ #include "HandlingMgr.h" #include "CarCtrl.h" #include "PedType.h" -#include "PedStats.h" #include "AnimManager.h" #include "Game.h" #include "RwHelper.h" diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h index d73d3646..f467fe8a 100644 --- a/src/modelinfo/PedModelInfo.h +++ b/src/modelinfo/PedModelInfo.h @@ -2,7 +2,6 @@ #include "ClumpModelInfo.h" #include "PedType.h" -#include "PedStats.h" enum PedNode { PED_TORSO, diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index 2d782a73..401d2e67 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -424,3 +424,45 @@ CCivilianPed::ProcessControl(void) if (m_moved.Magnitude() > 0.0f) Avoid(); } + +// It's "CPhoneInfo::ProcessNearestFreePhone" in PC IDB but that's not true, someone made it up. +bool +CPed::RunToReportCrime(eCrimeType crimeToReport) +{ +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + if (bRunningToPhone) { + if (!isPhoneAvailable(m_phoneId)) { + m_phoneId = -1; + bIsRunning = false; + ClearSeek(); // clears bRunningToPhone + return false; + } + + return true; + } +#else + // They changed true into false to make this function unusable. So running to phone actually starts but first frame after that cancels it. + if (m_nPedState == PED_SEEK_POS) + return false; +#endif + + CVector pos = GetPosition(); + int phoneId = gPhoneInfo.FindNearestFreePhone(&pos); + + if (phoneId == -1) + return false; + + CPhone *phone = &gPhoneInfo.m_aPhones[phoneId]; +#ifndef PEDS_REPORT_CRIMES_ON_PHONE + if (phone->m_nState != PHONE_STATE_FREE) + return false; +#endif + + bRunningToPhone = true; + SetSeek(phone->m_pEntity->GetMatrix() * -phone->m_pEntity->GetForward(), 1.0f); // original: phone.m_vecPos, 0.3f + SetMoveState(PEDMOVE_RUN); + bIsRunning = true; // not there in original + m_phoneId = phoneId; + m_crimeToReportOnPhone = crimeToReport; + return true; +} \ No newline at end of file diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 05e00ec2..c41c1f0c 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -3,111 +3,44 @@ #include "main.h" #include "Pools.h" #include "Particle.h" -#include "Stats.h" -#include "World.h" #include "RpAnimBlend.h" #include "Bones.h" #include "Ped.h" -#include "Wanted.h" -#include "PlayerPed.h" -#include "PedType.h" -#include "AnimBlendClumpData.h" #include "AnimBlendAssociation.h" #include "Fire.h" #include "DMAudio.h" #include "General.h" -#include "SurfaceTable.h" #include "VisibilityPlugins.h" -#include "AudioManager.h" #include "HandlingMgr.h" #include "Replay.h" -#include "Camera.h" #include "Radar.h" #include "PedPlacement.h" #include "Shadows.h" #include "Weather.h" #include "ZoneCull.h" #include "Population.h" -#include "Renderer.h" -#include "Lights.h" -#include "PointLights.h" #include "Pad.h" #include "Phones.h" -#include "Darkel.h" -#include "PathFind.h" -#include "ModelIndices.h" -#include "FileMgr.h" -#include "TempColModels.h" -#include "Pickups.h" -#include "Train.h" #include "TrafficLights.h" -#include "PedRoutes.h" -#include "Sprite.h" -#include "RwHelper.h" -#include "Font.h" -#include "Text.h" #include "CopPed.h" #include "Script.h" #include "CarCtrl.h" #include "Garages.h" #include "WaterLevel.h" -#include "CarAI.h" -#include "Zones.h" -#include "Cranes.h" #include "Timecycle.h" #include "ParticleObject.h" #include "Floater.h" #include "Range2D.h" -#define CAN_SEE_ENTITY_ANGLE_THRESHOLD DEGTORAD(60.0f) - CPed *gapTempPedList[50]; uint16 gnNumTempPedList; static CColPoint aTempPedColPts[MAX_COLLISION_POINTS]; -uint16 nPlayerInComboMove; - -RpClump *flyingClumpTemp; - -// This is beta fistfite.dat array. Not used anymore since they're being fetched from fistfite.dat. -FightMove tFightMoves[NUM_FIGHTMOVES] = { - {NUM_ANIMS, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_PUNCH_R, 0.2f, 8.0f / 30.0f, 0.0f, 0.3f, HITLEVEL_HIGH, 1, 0}, - {ANIM_FIGHT_IDLE, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_FIGHT_SH_F, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_FIGHT_KNEE, 4.0f / 30.0f, 0.2f, 0.0f, 0.6f, HITLEVEL_LOW, 2, 0}, - {ANIM_FIGHT_HEAD, 4.0f / 30.0f, 0.2f, 0.0f, 0.7f, HITLEVEL_HIGH, 3, 0}, - {ANIM_FIGHT_PUNCH, 4.0f / 30.0f, 7.0f / 30.0f, 10.0f / 30.0f, 0.4f, HITLEVEL_HIGH, 1, 0}, - {ANIM_FIGHT_LHOOK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.4f, HITLEVEL_HIGH, 3, 0}, - {ANIM_FIGHT_KICK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.5, HITLEVEL_MEDIUM, 2, 0}, - {ANIM_FIGHT_LONGKICK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.5, HITLEVEL_MEDIUM, 4, 0}, - {ANIM_FIGHT_ROUNDHOUSE, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.6f, HITLEVEL_MEDIUM, 4, 0}, - {ANIM_FIGHT_BODYBLOW, 5.0f / 30.0f, 7.0f / 30.0f, 0.0f, 0.35f, HITLEVEL_LOW, 2, 0}, - {ANIM_KICK_FLOOR, 10.0f / 30.0f, 14.0f / 30.0f, 0.0f, 0.4f, HITLEVEL_GROUND, 1, 0}, - {ANIM_HIT_FRONT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_BACK, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_RIGHT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_LEFT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_BODYBLOW, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_CHEST, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_WALK, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_FLOOR_HIT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_HIT_BEHIND, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, - {ANIM_FIGHT2_IDLE, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, -}; uint16 CPed::nThreatReactionRangeMultiplier = 1; uint16 CPed::nEnterCarRangeMultiplier = 1; -CVector vecPedCarDoorAnimOffset; -CVector vecPedCarDoorLoAnimOffset; -CVector vecPedVanRearDoorAnimOffset; -CVector vecPedQuickDraggedOutCarAnimOffset; -CVector vecPedDraggedOutCarAnimOffset; -CVector vecPedTrainDoorAnimOffset; - bool CPed::bNastyLimbsCheat; bool CPed::bPedCheat2; bool CPed::bPedCheat3; @@ -122,53 +55,6 @@ void CPed::operator delete(void *p, int handle) { CPools::GetPedPool()->Delete(( bool CPed::bPopHeadsOnHeadshot = false; #endif -CPed::~CPed(void) -{ - CWorld::Remove(this); - CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); - if (InVehicle()){ - uint8 door_flag = GetCarDoorFlag(m_vehEnterType); - if (m_pMyVehicle->pDriver == this) - m_pMyVehicle->pDriver = nil; - else { - // FIX: Passenger counter now decreasing after removing ourself from vehicle. - m_pMyVehicle->RemovePassenger(this); - } - if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) - m_pMyVehicle->m_nGettingOutFlags &= ~door_flag; - bInVehicle = false; - m_pMyVehicle = nil; - } else if (EnteringCar()) { - QuitEnteringCar(); - } - if (m_pFire) - m_pFire->Extinguish(); - CPopulation::UpdatePedCount((ePedType)m_nPedType, true); - DMAudio.DestroyEntity(m_audioEntityId); -} - -void -CPed::FlagToDestroyWhenNextProcessed(void) -{ - bRemoveFromWorld = true; - if (!InVehicle()) - return; - if (m_pMyVehicle->pDriver == this){ - m_pMyVehicle->pDriver = nil; - if (IsPlayer() && m_pMyVehicle->GetStatus() != STATUS_WRECKED) - m_pMyVehicle->SetStatus(STATUS_ABANDONED); - }else{ - m_pMyVehicle->RemovePassenger(this); - } - bInVehicle = false; - m_pMyVehicle = nil; - if (CharCreatedBy == MISSION_CHAR) - m_nPedState = PED_DEAD; - else - m_nPedState = PED_NONE; - m_pVehicleAnim = nil; -} - CPed::CPed(uint32 pedType) : m_pedIK(this) { m_type = ENTITY_TYPE_PED; @@ -397,1617 +283,66 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) CPopulation::UpdatePedCount((ePedType)m_nPedType, false); } -uint32 -CPed::GiveWeapon(eWeaponType weaponType, uint32 ammo) +CPed::~CPed(void) { - CWeapon &weapon = GetWeapon(weaponType); - - if (HasWeapon(weaponType)) { - if (weapon.m_nAmmoTotal + ammo > 99999) - weapon.m_nAmmoTotal = 99999; - else - weapon.m_nAmmoTotal += ammo; - - weapon.Reload(); - } else { - weapon.Initialise(weaponType, ammo); - // TODO: It seems game uses this as both weapon count and max WeaponType we have, which is ofcourse erroneous. - m_maxWeaponTypeAllowed++; - } - if (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) - weapon.m_eWeaponState = WEAPONSTATE_READY; - - return weaponType; -} - -static RwObject* -RemoveAllModelCB(RwObject *object, void *data) -{ - RpAtomic *atomic = (RpAtomic*)object; - if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { - RpClumpRemoveAtomic(RpAtomicGetClump(atomic), atomic); - RpAtomicDestroy(atomic); - } - return object; -} - -static PedOnGroundState -CheckForPedsOnGroundToAttack(CPed *attacker, CPed **pedOnGround) -{ - PedOnGroundState stateToReturn; - float angleToFace; - CPed *currentPed = nil; - PedState currentPedState; - CPed *pedOnTheFloor = nil; - CPed *deadPed = nil; - CPed *pedBelow = nil; - bool foundDead = false; - bool foundOnTheFloor = false; - bool foundBelow = false; - float angleDiff; - float distance; - - if (!CGame::nastyGame) - return NO_PED; - - for (int currentPedId = 0; currentPedId < attacker->m_numNearPeds; currentPedId++) { - - currentPed = attacker->m_nearPeds[currentPedId]; - - CVector posDifference = currentPed->GetPosition() - attacker->GetPosition(); - distance = posDifference.Magnitude(); - - if (distance < 2.0f) { - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - currentPed->GetPosition().x, currentPed->GetPosition().y, - attacker->GetPosition().x, attacker->GetPosition().y); - - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - attacker->m_fRotationCur = CGeneral::LimitRadianAngle(attacker->m_fRotationCur); - - angleDiff = Abs(angleToFace - attacker->m_fRotationCur); - - if (angleDiff > PI) - angleDiff = 2 * PI - angleDiff; - - currentPedState = currentPed->m_nPedState; - - if (currentPed->OnGroundOrGettingUp()) { - if (distance < 2.0f && angleDiff < DEGTORAD(65.0f)) { - if (currentPedState == PED_DEAD) { - foundDead = 1; - if (!deadPed) - deadPed = currentPed; - } else if (!currentPed->IsPedHeadAbovePos(-0.6f)) { - foundOnTheFloor = 1; - if (!pedOnTheFloor) - pedOnTheFloor = currentPed; - } - } - } else if ((distance < 0.8f && angleDiff < DEGTORAD(75.0f)) - || (distance < 1.3f && angleDiff < DEGTORAD(55.0f)) - || (distance < 1.7f && angleDiff < DEGTORAD(35.0f)) - || (distance < 2.0f && angleDiff < DEGTORAD(30.0f))) { - - // Either this condition or below one was probably returning 4 early in development. See Fight(). - foundBelow = 1; - pedBelow = currentPed; - break; - } else { - if (angleDiff < DEGTORAD(75.0f)) { - foundBelow = 1; - if (!pedBelow) - pedBelow = currentPed; - } - } + CWorld::Remove(this); + CRadar::ClearBlipForEntity(BLIP_CHAR, CPools::GetPedPool()->GetIndex(this)); + if (InVehicle()){ + uint8 door_flag = GetCarDoorFlag(m_vehEnterType); + if (m_pMyVehicle->pDriver == this) + m_pMyVehicle->pDriver = nil; + else { + // FIX: Passenger counter now decreasing after removing ourself from vehicle. + m_pMyVehicle->RemovePassenger(this); } + if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) + m_pMyVehicle->m_nGettingOutFlags &= ~door_flag; + bInVehicle = false; + m_pMyVehicle = nil; + } else if (EnteringCar()) { + QuitEnteringCar(); } - - if (foundOnTheFloor) { - currentPed = pedOnTheFloor; - stateToReturn = PED_ON_THE_FLOOR; - } else if (foundDead) { - currentPed = deadPed; - stateToReturn = PED_DEAD_ON_THE_FLOOR; - } else if (foundBelow) { - currentPed = pedBelow; - stateToReturn = PED_IN_FRONT_OF_ATTACKER; - } else { - currentPed = nil; - stateToReturn = NO_PED; - } - - if (pedOnGround) - *pedOnGround = currentPed; - - return stateToReturn; -} - -bool -CPed::IsPlayer(void) -{ - return m_nPedType == PEDTYPE_PLAYER1 || m_nPedType == PEDTYPE_PLAYER2 || - m_nPedType == PEDTYPE_PLAYER3 || m_nPedType == PEDTYPE_PLAYER4; -} - -bool -CPed::UseGroundColModel(void) -{ - return m_nPedState == PED_FALL || - m_nPedState == PED_DIVE_AWAY || - m_nPedState == PED_DIE || - m_nPedState == PED_DEAD; -} - -bool -CPed::CanSetPedState(void) -{ - return !DyingOrDead() && m_nPedState != PED_ARRESTED && !EnteringCar() && m_nPedState != PED_STEAL_CAR; -} - -bool -CPed::IsPedInControl(void) -{ - return m_nPedState <= PED_STATES_NO_AI - && !bIsInTheAir && !bIsLanding - && m_fHealth > 0.0f; -} - -bool -CPed::CanStrafeOrMouseControl(void) -{ -#ifdef FREE_CAM - if (CCamera::bFreeCam) - return false; -#endif - return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY || - m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP; + if (m_pFire) + m_pFire->Extinguish(); + CPopulation::UpdatePedCount((ePedType)m_nPedType, true); + DMAudio.DestroyEntity(m_audioEntityId); } void -CPed::AddWeaponModel(int id) +CPed::Initialise(void) { - RpAtomic *atm; + debug("Initialising CPed...\n"); + CPedType::Initialise(); + LoadFightData(); + SetAnimOffsetForEnterOrExitVehicle(); + debug("CPed ready\n"); +} + +void +CPed::SetModelIndex(uint32 mi) +{ + CEntity::SetModelIndex(mi); + RpAnimBlendClumpInit(GetClump()); + RpAnimBlendClumpFillFrameArray(GetClump(), m_pFrames); + CPedModelInfo *modelInfo = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); + SetPedStats(modelInfo->m_pedStatType); + m_headingRate = m_pedStats->m_headingChangeRate; + m_animGroup = (AssocGroupId) modelInfo->m_animGroup; + CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE); + + // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. + (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; - if (id != -1) { #ifdef PED_SKIN - if (IsClumpSkinned(GetClump())) { - if (m_pWeaponModel) - RemoveWeaponModel(-1); - - m_pWeaponModel = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); - } else -#endif - { - atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); - RwFrameDestroy(RpAtomicGetFrame(atm)); - RpAtomicSetFrame(atm, m_pFrames[PED_HANDR]->frame); - RpClumpAddAtomic(GetClump(), atm); - } - m_wepModelID = id; - } -} - -void -CPed::AimGun(void) -{ - CVector vector; - - if (m_pSeekTarget) { - if (m_pSeekTarget->IsPed()) { - ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(vector, PED_MID); - } else { - vector = m_pSeekTarget->GetPosition(); - } - Say(SOUND_PED_ATTACK); - - bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(vector); - if (m_pLookTarget != m_pSeekTarget) { - SetLookFlag(m_pSeekTarget, true); - } - - } else { - if (IsPlayer()) { - bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, ((CPlayerPed*)this)->m_fFPSMoveHeading); - } else { - bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, 0.0f); - } - } -} - -void -CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) -{ - CVector pos2 = CVector( - pos.x, - pos.y, - pos.z + 0.1f - ); - - if (!IsPlayer() || evenOnPlayer) { - ++CStats::HeadsPopped; - - // BUG: This condition will always return true. Even fixing it won't work, because these states are unused. - // if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { - SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - // } - - bBodyPartJustCameOff = true; - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; - - CParticle::AddParticle(PARTICLE_TEST, pos2, - CVector(0.0f, 0.0f, 0.0f), nil, 0.2f, 0, 0, 0, 0); - - if (CEntity::GetIsOnScreen()) { - for(int i=0; i < 32; i++) { - CParticle::AddParticle(PARTICLE_BLOOD_SMALL, - pos2, CVector(0.0f, 0.0f, 0.03f), - nil, 0.0f, 0, 0, 0, 0); - } - - for (int i = 0; i < 16; i++) { - CParticle::AddParticle(PARTICLE_DEBRIS2, - pos2, - CVector(0.0f, 0.0f, 0.01f), - nil, 0.0f, 0, 0, 0, 0); - } - } - } -} - -static RwObject* -SetPedAtomicVisibilityCB(RwObject* object, void* data) -{ - if (data == nil) - RpAtomicSetFlags((RpAtomic*)object, 0); - return object; -} - -static RwFrame* -RecurseFrameChildrenVisibilityCB(RwFrame* frame, void* data) -{ - RwFrameForAllObjects(frame, SetPedAtomicVisibilityCB, data); - RwFrameForAllChildren(frame, RecurseFrameChildrenVisibilityCB, nil); - return frame; -} - -void -CPed::RemoveBodyPart(PedNode nodeId, int8 direction) -{ - RwFrame *frame; - CVector pos; - - frame = m_pFrames[nodeId]->frame; - if (frame) { - if (CGame::nastyGame) { -#ifdef PED_SKIN - if(!IsClumpSkinned(GetClump())) -#endif - { -#ifdef DEBUGMENU - if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) -#else - if (nodeId != PED_HEAD) -#endif - SpawnFlyingComponent(nodeId, direction); - - RecurseFrameChildrenVisibilityCB(frame, nil); - } - pos.x = 0.0f; - pos.y = 0.0f; - pos.z = 0.0f; - TransformToNode(pos, PED_HEAD); - - if (CEntity::GetIsOnScreen()) { - CParticle::AddParticle(PARTICLE_TEST, pos, - CVector(0.0f, 0.0f, 0.0f), - nil, 0.1f, 0, 0, 0, 0); - - for (int i = 0; i < 16; i++) { - CParticle::AddParticle(PARTICLE_BLOOD_SMALL, - pos, - CVector(0.0f, 0.0f, 0.03f), - nil, 0.0f, 0, 0, 0, 0); - } - } - bBodyPartJustCameOff = true; - m_bodyPartBleeding = nodeId; - } - } else { - printf("Trying to remove ped component"); - } -} - -void -CPed::SetLookFlag(CEntity *target, bool keepTryingToLook) -{ - if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { - bIsLooking = true; - bIsRestoringLook = false; - m_pLookTarget = target; - m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); - m_fLookDirection = 999999.0f; - m_lookTimer = 0; - bKeepTryingToLook = keepTryingToLook; - if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - } - } -} - -void -CPed::SetLookFlag(float direction, bool keepTryingToLook) -{ - if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { - bIsLooking = true; - bIsRestoringLook = false; - m_pLookTarget = nil; - m_fLookDirection = direction; - m_lookTimer = 0; - bKeepTryingToLook = keepTryingToLook; - if (m_nPedState != PED_DRIVING) { - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - } - } -} - -void -CPed::SetLookTimer(int time) -{ - if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - m_lookTimer = CTimer::GetTimeInMilliseconds() + time; - } -} - -bool -CPed::OurPedCanSeeThisOne(CEntity *target) -{ - CColPoint colpoint; - CEntity *ent; - - CVector2D dist = CVector2D(target->GetPosition()) - CVector2D(GetPosition()); - - // Check if target is behind ped - if (DotProduct2D(dist, CVector2D(GetForward())) < 0.0f) - return false; - - // Check if target is too far away - if (dist.Magnitude() >= 40.0f) - return false; - - // Check line of sight from head - CVector headPos = this->GetPosition(); - headPos.z += 1.0f; - return !CWorld::ProcessLineOfSight(headPos, target->GetPosition(), colpoint, ent, true, false, false, false, false, false); -} - -void -CPed::Avoid(void) -{ - CPed *nearestPed; - - if(m_pedStats->m_temper > m_pedStats->m_fear && m_pedStats->m_temper > 50) - return; - - if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { - - if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { - nearestPed = m_nearPeds[0]; - - if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) { - - // Check if this ped wants to avoid the nearest one - if (CPedType::GetAvoid(m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) { - - // Further codes checks whether the distance between us and ped will be equal or below 1.0, if we walk up to him by 1.25 meters. - // If so, we want to avoid it, so we turn our body 45 degree and look to somewhere else. - - // Game converts from radians to degress and back again here, doesn't make much sense - CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); - forward.Normalise(); // this is kinda pointless - - // Move forward 1.25 meters - CVector2D testPosition = CVector2D(GetPosition()) + forward*1.25f; - - // Get distance to ped we want to avoid - CVector2D distToPed = CVector2D(nearestPed->GetPosition()) - testPosition; - - if (distToPed.Magnitude() <= 1.0f && OurPedCanSeeThisOne((CEntity*)nearestPed)) { - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() - + 500 + (m_randomSeed + 3 * CTimer::GetFrameCounter()) - % 1000 / 5; - - m_fRotationDest += DEGTORAD(45.0f); - if (!bIsLooking) { - SetLookFlag(nearestPed, false); - SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); - } - } - } - } - } - } -} - -void -CPed::ClearAimFlag(void) -{ - if (bIsAimingGun) { - bIsAimingGun = false; - bIsRestoringGun = true; - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; -#if defined VC_PED_PORTS || defined FIX_BUGS - m_lookTimer = 0; -#endif - } - - if (IsPlayer()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; -} - -void -CPed::ClearLookFlag(void) { - if (bIsLooking) { - bIsLooking = false; - bIsRestoringLook = true; - bShakeFist = false; - - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - if (IsPlayer()) - m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; - else - m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; - - if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { - ClearLook(); - } - } -} - -bool -CPed::IsPedHeadAbovePos(float zOffset) -{ - return zOffset + GetPosition().z < GetNodePosition(PED_HEAD).z; -} - -void -CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) -{ - CWeaponInfo *currentWeapon; - CAnimBlendAssociation *newAnim; - CPed *ped = (CPed*)arg; - - if (attackAssoc) { - switch (attackAssoc->animId) { - case ANIM_WEAPON_START_THROW: - // what?! - if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->m_bHaveTargetSelected) && ped->IsPlayer()) { - attackAssoc->blendDelta = -1000.0f; - newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROWU); - } else { - attackAssoc->blendDelta = -1000.0f; - newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROW); - } - - newAnim->SetFinishCallback(FinishedAttackCB, ped); - return; - - case ANIM_FIGHT_PPUNCH: - attackAssoc->blendDelta = -8.0f; - attackAssoc->flags |= ASSOC_DELETEFADEDOUT; - ped->ClearAttack(); - return; - - case ANIM_WEAPON_THROW: - case ANIM_WEAPON_THROWU: - if (ped->GetWeapon()->m_nAmmoTotal > 0) { - currentWeapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType); - ped->AddWeaponModel(currentWeapon->m_nModelId); - } - break; - default: - break; - } - } - - if (!ped->bIsAttacking) - ped->ClearAttack(); -} - -void -CPed::Attack(void) -{ - CAnimBlendAssociation *weaponAnimAssoc; - int32 weaponAnim; - float animStart; - eWeaponType ourWeaponType; - float weaponAnimTime; - eWeaponFire ourWeaponFire; - float animLoopEnd; - CWeaponInfo *ourWeapon; - bool attackShouldContinue; - AnimationId reloadAnim; - CAnimBlendAssociation *reloadAnimAssoc; - float delayBetweenAnimAndFire; - CVector firePos; - - ourWeaponType = GetWeapon()->m_eWeaponType; - ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType); - ourWeaponFire = ourWeapon->m_eWeaponFire; - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay); - attackShouldContinue = bIsAttacking; - reloadAnimAssoc = nil; - reloadAnim = NUM_ANIMS; - delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire; - weaponAnim = ourWeapon->m_AnimToPlay; - - if (weaponAnim == ANIM_WEAPON_HGUN_BODY) - reloadAnim = ANIM_HGUN_RELOAD; - else if (weaponAnim == ANIM_WEAPON_AK_BODY) - reloadAnim = ANIM_AK_RELOAD; - - if (reloadAnim != NUM_ANIMS) - reloadAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), reloadAnim); - - if (bIsDucking) - return; - - if (reloadAnimAssoc) { - if (!IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) - ClearAttack(); - - return; - } - - if (CTimer::GetTimeInMilliseconds() < m_shootTimer) - attackShouldContinue = true; - - if (!weaponAnimAssoc) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_Anim2ToPlay); - delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; - - // Long throw granade, molotov - if (!weaponAnimAssoc && ourWeapon->m_bThrow) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU); - delayBetweenAnimAndFire = 0.2f; - } - - if (!weaponAnimAssoc) { - if (attackShouldContinue) { - if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) { - if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { - weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } - else { - weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); - } - - weaponAnimAssoc->SetFinishCallback(FinishedAttackCB, this); - weaponAnimAssoc->SetRun(); - - if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) - weaponAnimAssoc->SetCurrentTime(0.0f); - - if (IsPlayer()) { - ((CPlayerPed*)this)->m_fAttackButtonCounter = 0.0f; - ((CPlayerPed*)this)->m_bHaveTargetSelected = false; - } - } - } else - FinishedAttackCB(nil, this); - - return; - } - } - - animStart = ourWeapon->m_fAnimLoopStart; - weaponAnimTime = weaponAnimAssoc->currentTime; - if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { - if (ourWeapon->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; - else - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; - } - - if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { - if (weaponAnimAssoc->speed < 1.0f) - weaponAnimAssoc->speed = 1.0f; - - } else { - firePos = ourWeapon->m_vecFireOffset; - if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { - if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; - - firePos = GetMatrix() * firePos; - } else if (ourWeaponType != WEAPONTYPE_UNARMED) { - TransformToNode(firePos, weaponAnimAssoc->animId == ANIM_KICK_FLOOR ? PED_FOOTR : PED_HANDR); - } else { - firePos = GetMatrix() * firePos; - } - - GetWeapon()->Fire(this, &firePos); - - if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { - RemoveWeaponModel(ourWeapon->m_nModelId); - } - if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { - SelectGunIfArmed(); - } - - if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) { - // If reloading just began, start the animation - // Last condition will always return true, even IDA hides it - if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS /* && !reloadAnimAssoc*/) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, reloadAnim, 8.0f); - ClearLookFlag(); - ClearAimFlag(); - bIsAttacking = false; - bIsPointingGunAt = false; - m_shootTimer = CTimer::GetTimeInMilliseconds(); - return; - } - } else { - if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); - } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { - DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); - } - - weaponAnimAssoc->speed = 0.5f; - - if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) { - weaponAnimAssoc->callbackType = 0; - } - } - - attackShouldContinue = false; - } - - if (ourWeaponType == WEAPONTYPE_SHOTGUN) { - weaponAnimTime = weaponAnimAssoc->currentTime; - firePos = ourWeapon->m_vecFireOffset; - - if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { - TransformToNode(firePos, PED_HANDR); - - CVector gunshellPos( - firePos.x - 0.6f * GetForward().x, - firePos.y - 0.6f * GetForward().y, - firePos.z - 0.15f * GetUp().z - ); - - CVector2D gunshellRot( - GetRight().x, - GetRight().y - ); - - gunshellRot.Normalise(); - GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); - } - } -#ifdef VC_PED_PORTS - if (IsPlayer()) { - if (CPad::GetPad(0)->GetSprint()) { - // animBreakout is a member of WeaponInfo in VC, so it's me that added the below line. - float animBreakOut = ((ourWeaponType == WEAPONTYPE_FLAMETHROWER || ourWeaponType == WEAPONTYPE_UZI || ourWeaponType == WEAPONTYPE_SHOTGUN) ? 25 / 30.0f : 99 / 30.0f); - if (!attackShouldContinue && weaponAnimAssoc->currentTime > animBreakOut) { - weaponAnimAssoc->blendDelta = -4.0f; - FinishedAttackCB(nil, this); - return; - } - } - } -#endif - animLoopEnd = ourWeapon->m_fAnimLoopEnd; - if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - animLoopEnd = 3.4f/6.0f; - - weaponAnimTime = weaponAnimAssoc->currentTime; - - // Anim loop end, either start the loop again or finish the attack - if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { - - if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd - && (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) - && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { - - weaponAnim = weaponAnimAssoc->animId; - if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { - if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { - weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); - } else { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); - } - } else { - if (weaponAnim == ourWeapon->m_Anim2ToPlay) - weaponAnimAssoc->SetCurrentTime(0.1f); - else - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); - } -#ifdef VC_PED_PORTS - } else if (IsPlayer() && m_pPointGunAt && bIsAimingGun && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { - weaponAnimAssoc->SetCurrentTime(ourWeapon->m_fAnimLoopEnd); - weaponAnimAssoc->flags &= ~ASSOC_RUNNING; - SetPointGunAt(m_pPointGunAt); -#endif - } else { - ClearAimFlag(); - - // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) - if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { - switch (ourWeaponType) { - case WEAPONTYPE_UZI: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_AK47: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); - break; - case WEAPONTYPE_M16: - DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); - break; - default: - break; - } - } - - // Fun fact: removing this part leds to reloading flamethrower - if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { - weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; - weaponAnimAssoc->flags &= ~ASSOC_RUNNING; - weaponAnimAssoc->blendDelta = -4.0f; - } - } - } - if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) - attackShouldContinue = false; - - bIsAttacking = attackShouldContinue; -} - -void -CPed::RemoveWeaponModel(int modelId) -{ - // modelId is not used!! This function just removes the current weapon. -#ifdef PED_SKIN - if(IsClumpSkinned(GetClump())){ - if(m_pWeaponModel){ - RwFrame *frm = RpAtomicGetFrame(m_pWeaponModel); - RpAtomicDestroy(m_pWeaponModel); - RwFrameDestroy(frm); - m_pWeaponModel = nil; - } - }else -#endif - RwFrameForAllObjects(m_pFrames[PED_HANDR]->frame,RemoveAllModelCB,nil); - m_wepModelID = -1; -} - -void -CPed::SetCurrentWeapon(uint32 weaponType) -{ - CWeaponInfo *weaponInfo; - if (HasWeapon(weaponType)) { - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(weaponInfo->m_nModelId); - - m_currentWeapon = weaponType; - - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - AddWeaponModel(weaponInfo->m_nModelId); - } -} - -// Only used while deciding which gun ped should switch to, if no ammo left. -bool -CPed::SelectGunIfArmed(void) -{ - for (int i = 0; i < m_maxWeaponTypeAllowed; i++) { - if (GetWeapon(i).m_nAmmoTotal > 0) { - eWeaponType weaponType = GetWeapon(i).m_eWeaponType; - if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { - SetCurrentWeapon(i); - return true; - } - } - } - SetCurrentWeapon(WEAPONTYPE_UNARMED); - return false; -} - -void -CPed::Duck(void) -{ - if (CTimer::GetTimeInMilliseconds() > m_duckTimer) - ClearDuck(); -} - -void -CPed::ClearDuck(void) -{ - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); - - if (!animAssoc) { - bIsDucking = false; - return; - } - } - - if (!bCrouchWhenShooting) - return; - - if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN) - return; - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT); - if (!animAssoc || animAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); - } -} - -void -CPed::ClearPointGunAt(void) -{ - CAnimBlendAssociation *animAssoc; - CWeaponInfo *weaponInfo; - - ClearLookFlag(); - ClearAimFlag(); - bIsPointingGunAt = false; -#ifndef VC_PED_PORTS - if (m_nPedState == PED_AIM_GUN) { - RestorePreviousState(); -#else - if (m_nPedState == PED_AIM_GUN || m_nPedState == PED_ATTACK) { - m_nPedState = PED_IDLE; - RestorePreviousState(); - } -#endif - weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); - if (!animAssoc || animAssoc->blendDelta < 0.0f) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay); - } - if (animAssoc) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->blendDelta = -4.0f; - } -#ifndef VC_PED_PORTS - } + if(modelInfo->GetHitColModel() == nil) + modelInfo->CreateHitColModelSkinned(GetClump()); #endif } void -CPed::BeingDraggedFromCar(void) +CPed::SetPedStats(ePedStats pedStat) { - CAnimBlendAssociation *animAssoc; - AnimationId enterAnim; - bool dontRunAnim = false; - PedLineUpPhase lineUpType; - - if (!m_pVehicleAnim) { - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO); - } - } - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { - if (bWillBeQuickJacked) { - enterAnim = ANIM_CAR_QJACKED; - } else if (m_pMyVehicle->bLowVehicle) { - enterAnim = ANIM_CAR_LJACKED_LHS; - } else { - enterAnim = ANIM_CAR_JACKED_LHS; - } - } else if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { - if (m_pMyVehicle->bLowVehicle) - enterAnim = ANIM_CAR_LJACKED_RHS; - else - enterAnim = ANIM_CAR_JACKED_RHS; - } else - dontRunAnim = true; - - - if (!dontRunAnim) - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), 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); -#ifdef VC_PED_PORTS - if (m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { - if (m_pMyVehicle) { - m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, NUM_ANIMS, m_pVehicleAnim->currentTime * 5.0f); - } - } -#endif -} - -void -CPed::RestartNonPartialAnims(void) -{ - CAnimBlendAssociation *assoc; - - for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (!assoc->IsPartial()) - assoc->SetRun(); - } -} - -void -CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) -{ - CAnimBlendAssociation *quickJackedAssoc; - CVehicle *vehicle; - CPed *ped = (CPed*)arg; - - quickJackedAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_CAR_QJACKED); - if (ped->m_nPedState != PED_ARRESTED) { - ped->m_nLastPedState = PED_NONE; - if (dragAssoc) - dragAssoc->blendDelta = -1000.0f; - } - ped->RestartNonPartialAnims(); - ped->m_pVehicleAnim = nil; - ped->m_pSeekTarget = nil; - vehicle = ped->m_pMyVehicle; - - if (vehicle) { - vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); - - if (vehicle->pDriver == ped) { - vehicle->RemoveDriver(); - if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - vehicle->m_nDoorLock = CARLOCK_UNLOCKED; - - if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) - vehicle->ChangeLawEnforcerState(false); - } else { - vehicle->RemovePassenger(ped); - } - } - ped->bInVehicle = false; - if (ped->IsPlayer()) - AudioManager.PlayerJustLeftCar(); - -#ifdef VC_PED_PORTS - if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { - dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); - ped->m_fHealth = 0.0f; - ped->SetDie(ANIM_FLOOR_HIT, 1000.0f, 0.5f); - return; - } -#endif - - if (quickJackedAssoc) { - dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); - } else { - dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); - if (ped->CanSetPedState()) - CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); - } - - ped->ReplaceWeaponWhenExitingVehicle(); - - ped->m_nStoredMoveState = PEDMOVE_NONE; - ped->bVehExitWillBeInstant = false; -} - -CVector -CPed::GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatPosMult) -{ - CVehicleModelInfo *vehModel; - CVector vehDoorPos; - CVector vehDoorOffset; - float seatOffset; - - vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(veh->GetModelIndex()); - if (veh->bIsVan && (component == CAR_DOOR_LR || component == CAR_DOOR_RR)) { - seatOffset = 0.0f; - vehDoorOffset = vecPedVanRearDoorAnimOffset; - } else { - seatOffset = veh->pHandling->fSeatOffsetDistance * seatPosMult; - if (veh->bLowVehicle) { - vehDoorOffset = vecPedCarDoorLoAnimOffset; - } else { - vehDoorOffset = vecPedCarDoorAnimOffset; - } - } - - switch (component) { - case CAR_DOOR_RF: - vehDoorPos = vehModel->GetFrontSeatPosn(); - vehDoorPos.x += seatOffset; - vehDoorOffset.x = -vehDoorOffset.x; - break; - - case CAR_DOOR_RR: - vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; - vehDoorPos.x += seatOffset; - vehDoorOffset.x = -vehDoorOffset.x; - break; - - case CAR_DOOR_LF: - vehDoorPos = vehModel->GetFrontSeatPosn(); - vehDoorPos.x = -(vehDoorPos.x + seatOffset); - break; - - case CAR_DOOR_LR: - vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; - vehDoorPos.x = -(vehDoorPos.x + seatOffset); - break; - - default: - vehDoorPos = vehModel->GetFrontSeatPosn(); - vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); - } - return vehDoorPos - vehDoorOffset; -} - -// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it. -CVector -CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component) -{ - CVector localPos; - CVector vehDoorPos; - - localPos = GetLocalPositionToOpenCarDoor(veh, component, 1.0f); - vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); - -/* - // Not used. - CVector localVehDoorOffset; - - if (veh->bIsVan && (component == VEHICLE_ENTER_REAR_LEFT || component == VEHICLE_ENTER_REAR_RIGHT)) { - localVehDoorOffset = vecPedVanRearDoorAnimOffset; - } else { - if (veh->bIsLow) { - localVehDoorOffset = vecPedCarDoorLoAnimOffset; - } else { - localVehDoorOffset = vecPedCarDoorAnimOffset; - } - } - - vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); -*/ - return vehDoorPos; -} - -CVector -CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset) -{ - CVector doorPos; - CMatrix vehMat(veh->GetMatrix()); - - doorPos = Multiply3x3(vehMat, GetLocalPositionToOpenCarDoor(veh, component, offset)); - - return 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 (!bChangedSeat && phase != LINE_UP_TO_CAR_2) { - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP)) { - SetPedPositionInCar(); - return; - } - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO)) { - SetPedPositionInCar(); - return; - } - bChangedSeat = true; - } - 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. - if (veh->GetUp().z <= -0.8f) - vehIsUpsideDown = true; - - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { - if (vehIsUpsideDown) { - m_fRotationDest = -PI + veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { - if (vehIsUpsideDown) { - m_fRotationDest = veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = -0.5f * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } else { - // I don't know will this part ever run(maybe boats?), but the game also handles that. I don't know is it intentional. - - if (vehIsUpsideDown) { - m_fRotationDest = veh->GetForward().Heading(); - } else if (veh->bIsBus) { - m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); - } else { - m_fRotationDest = veh->GetForward().Heading(); - } - } - - if (!bInVehicle) - seatPosMult = 1.0f; - -#ifdef VC_PED_PORTS - bool multExtractedFromAnim = false; - bool multExtractedFromAnimBus = false; - float zBlend; -#endif - 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_VAN_GETIN_L: - case ANIM_VAN_GETIN: -#ifdef VC_PED_PORTS - multExtractedFromAnim = true; - zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.3f, 0.0f) / (1.0f - 0.3f); - // fall through -#endif - 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: -#ifdef VC_PED_PORTS - if (!multExtractedFromAnim) { - multExtractedFromAnim = true; - zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.5f, 0.0f) / (1.0f - 0.5f); - } - // fall through -#endif - case ANIM_CAR_CRAWLOUT_RHS: - case ANIM_CAR_CRAWLOUT_RHS2: - case ANIM_VAN_GETOUT_L: - case ANIM_VAN_GETOUT: - seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength; - break; - case ANIM_CAR_GETIN_RHS: - case ANIM_CAR_GETIN_LHS: -#ifdef VC_PED_PORTS - if (veh && veh->IsCar() && veh->bIsBus) { - multExtractedFromAnimBus = true; - zBlend = Min(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength, 0.5f) / 0.5f; - } - // fall through -#endif - case ANIM_CAR_QJACK: - case ANIM_CAR_GETIN_LOW_LHS: - 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 { - neededPos = GetPositionToOpenCarDoor(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 nextZSpeed = m_vecMoveSpeed.z - GRAVITY * CTimer::GetTimeStep(); - - // If we're not in ground at next step, apply animation - if (neededPos.z + nextZSpeed >= autoZPos.z) { - m_vecMoveSpeed.z = nextZSpeed; - 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) { -#ifdef VC_PED_PORTS - if (multExtractedFromAnim) { - neededPos.z += (autoZPos.z - neededPos.z) * zBlend; - } else { -#endif - 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); - } -#ifdef VC_PED_PORTS - } -#endif - } else { - // We may need to raise up the ped - if (phase == LINE_UP_TO_CAR_START) { - currentZ = GetPosition().z; - - if (neededPos.z > currentZ) { -#ifdef VC_PED_PORTS - if (multExtractedFromAnimBus) { - neededPos.z = (neededPos.z - currentZ) * zBlend + currentZ; - } else { -#endif - 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 (EnteringCar()) { - neededPos.z = Max(currentZ, autoZPos.z); - } -#ifdef VC_PED_PORTS - } -#endif - } - } - } - - bool stillGettingInOut = false; - if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) - stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || bOnBoat; - - if (!stillGettingInOut) { - m_fRotationCur = m_fRotationDest; - } else { - float limitedDest = CGeneral::LimitRadianAngle(m_fRotationDest); - float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; - - if (timeUntilStateChange <= 0.0f) { - m_vecOffsetSeek.x = 0.0f; - m_vecOffsetSeek.y = 0.0f; - } - m_vecOffsetSeek.z = 0.0f; - - neededPos -= timeUntilStateChange * m_vecOffsetSeek; - - if (PI + m_fRotationCur < limitedDest) { - limitedDest -= 2 * PI; - } else if (m_fRotationCur - PI > limitedDest) { - limitedDest += 2 * PI; - } - m_fRotationCur -= (m_fRotationCur - limitedDest) * (1.0f - timeUntilStateChange); - } - - if (seatPosMult > 0.2f || vehIsUpsideDown) { - SetPosition(neededPos); - SetHeading(m_fRotationCur); - } else { - CMatrix vehDoorMat(veh->GetMatrix()); - vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehEnterType, 0.0f)); - // VC couch anims are inverted, so they're fixing it here. - GetMatrix() = vehDoorMat; - } - -} - -static void -particleProduceFootDust(CPed *ped, CVector const &pos, float size, int times) -{ - switch (ped->m_nSurfaceTouched) - { - case SURFACE_TARMAC: - case SURFACE_GRAVEL: - case SURFACE_PAVEMENT: - case SURFACE_SAND: - for (int i = 0; i < times; ++i) { - CVector adjustedPos = pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - CParticle::AddParticle(PARTICLE_PEDFOOT_DUST, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, 0, 0); - } - break; - default: - break; - } -} - -static void -particleProduceFootSplash(CPed *ped, CVector const &pos, float size, int times) -{ -#ifdef PC_PARTICLE - for (int i = 0; i < times; i++) { - CVector adjustedPos = pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); - - CVector direction = ped->GetForward() * -0.05f; - CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, direction, nil, size, CRGBA(32, 32, 32, 32), 0, 0, CGeneral::GetRandomNumber() & 1, 200); - } -#else - for ( int32 i = 0; i < times; i++ ) - { - CVector adjustedPos = pos; - adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); - adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); - - CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, CGeneral::GetRandomNumber() & 1, 200); - } -#endif -} - -void -CPed::PlayFootSteps(void) -{ - if (bDoBloodyFootprints) { - if (m_bloodyFootprintCountOrDeathTime > 0 && m_bloodyFootprintCountOrDeathTime < 300) { - m_bloodyFootprintCountOrDeathTime--; - - if (m_bloodyFootprintCountOrDeathTime == 0) - bDoBloodyFootprints = false; - } - } - - if (!bIsStanding) - return; - - CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); - CAnimBlendAssociation *walkRunAssoc = nil; - float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; - - for (; assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (assoc->flags & ASSOC_WALK) { - walkRunAssoc = assoc; - walkRunAssocBlend += assoc->blendAmount; - } else if ((assoc->flags & ASSOC_NOWALK) == 0) { - idleAssocBlend += assoc->blendAmount; - } - } - -#ifdef GTA_PS2_STUFF - CAnimBlendAssociation *runStopAsoc = NULL; - - if ( IsPlayer() ) - { - runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); - - if ( runStopAsoc == NULL ) - runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); - } - - if ( runStopAsoc != NULL && runStopAsoc->blendAmount > 0.1f ) - { - { - CVector pos(0.0f, 0.0f, 0.0f); - TransformToNode(pos, PED_FOOTL); - - pos.z -= 0.1f; - pos += GetForward()*0.2f; - particleProduceFootDust(this, pos, 0.02f, 1); - } - - { - CVector pos(0.0f, 0.0f, 0.0f); - TransformToNode(pos, PED_FOOTR); - - pos.z -= 0.1f; - pos += GetForward()*0.2f; - particleProduceFootDust(this, pos, 0.02f, 1); - } - } -#endif - - - if (walkRunAssoc && walkRunAssocBlend > 0.5f && idleAssocBlend < 1.0f) { - float stepStart = 1 / 15.0f; - float stepEnd = walkRunAssoc->hierarchy->totalLength / 2.0f + stepStart; - float currentTime = walkRunAssoc->currentTime; - int stepPart = 0; - - if (currentTime >= stepStart && currentTime - walkRunAssoc->timeStep < stepStart) - stepPart = 1; - else if (currentTime >= stepEnd && currentTime - walkRunAssoc->timeStep < stepEnd) - stepPart = 2; - - if (stepPart != 0) { - DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); - CVector footPos(0.0f, 0.0f, 0.0f); - TransformToNode(footPos, stepPart == 1 ? PED_FOOTL : PED_FOOTR); - - CVector forward = GetForward(); - - footPos.z -= 0.1f; - footPos += 0.2f * forward; - - if (bDoBloodyFootprints) { - CVector2D top(forward * 0.26f); - CVector2D right(GetRight() * 0.14f); - - CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &footPos, - top.x, top.y, - right.x, right.y, - 255, 255, 0, 0, 4.0f, 3000.0f, 1.0f); - - if (m_bloodyFootprintCountOrDeathTime <= 20) { - m_bloodyFootprintCountOrDeathTime = 0; - bDoBloodyFootprints = false; - } else { - m_bloodyFootprintCountOrDeathTime -= 20; - } - } - if (CWeather::Rain <= 0.1f || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) { - if(IsPlayer()) - particleProduceFootDust(this, footPos, 0.0f, 4); - } -#ifdef PC_PARTICLE - else if(stepPart == 2) -#else - else -#endif - { - particleProduceFootSplash(this, footPos, 0.15f, 4); - } - } - } - - if (m_nSurfaceTouched == SURFACE_WATER) { - float pedSpeed = CVector2D(m_vecMoveSpeed).Magnitude(); - if (pedSpeed > 0.03f && CTimer::GetFrameCounter() % 2 == 0 && pedSpeed > 0.13f) { -#ifdef PC_PARTICLE - float particleSize = pedSpeed * 2.0f; - - if (particleSize < 0.25f) - particleSize = 0.25f; - - if (particleSize > 0.75f) - particleSize = 0.75f; - - CVector particlePos = GetPosition() + GetForward() * 0.3f; - particlePos.z -= 1.2f; - - CVector particleDir = m_vecMoveSpeed * -0.75f; - - particleDir.z = CGeneral::GetRandomNumberInRange(0.01f, 0.03f); - CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos, particleDir, nil, 0.8f * particleSize, CRGBA(155,155,185,128), 0, 0, 0, 0); - - particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); - CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, particlePos, particleDir, nil, particleSize, CRGBA(255,255,255,255), 0, 0, 0, 0); -#else - CVector particlePos = (GetPosition() - 0.3f * GetUp()) + GetForward()*0.3f; - CVector particleDir = m_vecMoveSpeed * 0.45f; - particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); - CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos-CVector(0.0f, 0.0f, 1.2f), particleDir, nil, 0.0f, CRGBA(155, 185, 155, 255)); -#endif - } - } -} - -bool -CPed::IsPointerValid(void) -{ - int pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; - if (pedIndex < 0 || pedIndex >= NUMPEDS) - return false; - - if (m_entryInfoList.first || FindPlayerPed() == this) - return true; - - return false; -} - -// Some kind of binary sort -void -CPed::SortPeds(CPed **list, int min, int max) -{ - if (min >= max) - return; - - CVector leftDiff, rightDiff; - CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); - float middleDist = middleDiff.Magnitude(); - - int left = max; - int right = min; - while(right <= left){ - float rightDist, leftDist; - do { - rightDiff = GetPosition() - list[right]->GetPosition(); - rightDist = rightDiff.Magnitude(); - } while (middleDist > rightDist && ++right); - - do { - leftDiff = GetPosition() - list[left]->GetPosition(); - leftDist = leftDiff.Magnitude(); - } while (middleDist < leftDist && left--); - - if (right <= left) { - CPed *ped = list[right]; - list[right] = list[left]; - list[left] = ped; - right++; - left--; - } - } - SortPeds(list, min, left); - SortPeds(list, right, max); + m_pedStats = CPedStats::ms_apPedStats[pedStat]; } void @@ -2077,333 +412,63 @@ CPed::BuildPedLists(void) } } -void -CPed::SetPedStats(ePedStats pedStat) -{ - m_pedStats = CPedStats::ms_apPedStats[pedStat]; -} - -void -CPed::SetModelIndex(uint32 mi) -{ - CEntity::SetModelIndex(mi); - RpAnimBlendClumpInit(GetClump()); - RpAnimBlendClumpFillFrameArray(GetClump(), m_pFrames); - CPedModelInfo *modelInfo = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); - SetPedStats(modelInfo->m_pedStatType); - m_headingRate = m_pedStats->m_headingChangeRate; - m_animGroup = (AssocGroupId) modelInfo->m_animGroup; - CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE); - - // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. - (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; - -#ifdef PED_SKIN - if(modelInfo->GetHitColModel() == nil) - modelInfo->CreateHitColModelSkinned(GetClump()); -#endif -} - -void -CPed::RemoveLighting(bool reset) -{ - CRenderer::RemoveVehiclePedLights(this, reset); -} - bool -CPed::SetupLighting(void) +CPed::OurPedCanSeeThisOne(CEntity *target) { - ActivateDirectional(); - SetAmbientColoursForPedsCarsAndObjects(); + CColPoint colpoint; + CEntity *ent; -#ifndef MASTER - // Originally this was being called through iteration of Sectors, but putting it here is better. - if (GetDebugDisplay() != 0 && !IsPlayer()) - DebugRenderOnePedText(); -#endif + CVector2D dist = CVector2D(target->GetPosition()) - CVector2D(GetPosition()); - if (bRenderScorched) { - WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); - } else { - // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0. - float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition()); - if (!bHasBlip && lightMult != 1.0f) { - SetAmbientAndDirectionalColours(lightMult); - return true; - } - } - return false; -} - -void -CPed::Teleport(CVector pos) -{ - CWorld::Remove(this); - SetPosition(pos); - bIsStanding = false; - m_nPedStateTimer = 0; - m_actionX = 0.0f; - m_actionY = 0.0f; - m_pDamageEntity = nil; - CWorld::Add(this); -} - -void -CPed::CalculateNewOrientation(void) -{ - if (CReplay::IsPlayingBack() || !IsPedInControl()) - return; - - SetHeading(m_fRotationCur); -} - -float -CPed::WorkOutHeadingForMovingFirstPerson(float offset) -{ - if (!IsPlayer()) - return 0.0f; - - CPad *pad0 = CPad::GetPad(0); - float leftRight = pad0->GetPedWalkLeftRight(); - float upDown = pad0->GetPedWalkUpDown(); - float &angle = ((CPlayerPed*)this)->m_fWalkAngle; - - if (upDown != 0.0f) { - angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); - } else { - if (leftRight < 0.0f) - angle = 0.5f * PI; - else if (leftRight > 0.0f) - angle = -0.5f * PI; - } - - return CGeneral::LimitRadianAngle(offset + angle); -} - -void -CPed::CalculateNewVelocity(void) -{ - if (IsPedInControl()) { - float headAmount = DEGTORAD(m_headingRate) * CTimer::GetTimeStep(); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - float limitedRotDest = CGeneral::LimitRadianAngle(m_fRotationDest); - - if (m_fRotationCur - PI > limitedRotDest) { - limitedRotDest += 2 * PI; - } else if(PI + m_fRotationCur < limitedRotDest) { - limitedRotDest -= 2 * PI; - } - - if (IsPlayer() && m_nPedState == PED_ATTACK) - headAmount /= 4.0f; - - float neededTurn = limitedRotDest - m_fRotationCur; - if (neededTurn <= headAmount) { - if (neededTurn > (-headAmount)) - m_fRotationCur += neededTurn; - else - m_fRotationCur -= headAmount; - } else { - m_fRotationCur += headAmount; - } - } - - CVector2D forward(Sin(m_fRotationCur), Cos(m_fRotationCur)); - - m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * Cos(m_fRotationCur)) + -Sin(m_fRotationCur) * m_vecAnimMoveDelta.y; - m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward); // m_vecAnimMoveDelta.y* Cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * Sin(m_fRotationCur)); - - if (CTimer::GetTimeStep() >= 0.01f) { - m_moved = m_moved * (1 / CTimer::GetTimeStep()); - } else { - m_moved = m_moved * (1 / 100.0f); - } - - if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam()) - || FindPlayerPed() != this || !CanStrafeOrMouseControl()) - return; - - float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur); - float pedSpeed = m_moved.Magnitude(); - float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur); - - if (localWalkAngle < -0.5f * PI) { - localWalkAngle += PI; - } else if (localWalkAngle > 0.5f * PI) { - localWalkAngle -= PI; - } - - // Interestingly this part is responsible for diagonal walking. - if (localWalkAngle > -DEGTORAD(50.0f) && localWalkAngle < DEGTORAD(50.0f)) { - TheCamera.Cams[TheCamera.ActiveCam].m_fPlayerVelocity = pedSpeed; - m_moved = CVector2D(-Sin(walkAngle), Cos(walkAngle)) * pedSpeed; - } - - CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - CAnimBlendAssociation *fightAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); -#ifdef VC_PED_PORTS - if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc && !bIsDucking) { -#else - if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) { -#endif - LimbOrientation newUpperLegs; - newUpperLegs.yaw = localWalkAngle; - - if (newUpperLegs.yaw < -DEGTORAD(100.0f)) { - newUpperLegs.yaw += PI; - } else if (newUpperLegs.yaw > DEGTORAD(100.0f)) { - newUpperLegs.yaw -= PI; - } - - if (newUpperLegs.yaw > -DEGTORAD(50.0f) && newUpperLegs.yaw < DEGTORAD(50.0f)) { -#ifdef PED_SKIN - if(IsClumpSkinned(GetClump())){ -/* - // this looks shit - newUpperLegs.pitch = 0.0f; - RwV3d axis = { -1.0f, 0.0f, 0.0f }; - RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &axis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPRECONCAT); - RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &axis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPRECONCAT); -*/ - newUpperLegs.pitch = 0.1f; - RwV3d Xaxis = { 1.0f, 0.0f, 0.0f }; - RwV3d Zaxis = { 0.0f, 0.0f, 1.0f }; - RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &Zaxis, RADTODEG(newUpperLegs.pitch), rwCOMBINEPOSTCONCAT); - RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &Xaxis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPOSTCONCAT); - RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &Zaxis, RADTODEG(newUpperLegs.pitch), rwCOMBINEPOSTCONCAT); - RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &Xaxis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPOSTCONCAT); - - bDontAcceptIKLookAts = true; - }else -#endif - { - newUpperLegs.pitch = 0.0f; - m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false); - m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false); - } - } - } -} - -bool -CPed::CanBeDeleted(void) -{ - if (bInVehicle) + // Check if target is behind ped + if (DotProduct2D(dist, CVector2D(GetForward())) < 0.0f) return false; - switch (CharCreatedBy) { - case RANDOM_CHAR: - return true; - case MISSION_CHAR: - return false; - default: - return true; - } -} - -bool -CPed::CanPedDriveOff(void) -{ - if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) + // Check if target is too far away + if (dist.Magnitude() >= 40.0f) return false; - for (int i = 0; i < m_numNearPeds; i++) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed->m_nPedType == m_nPedType && nearPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && nearPed->m_carInObjective == m_carInObjective) { - m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000; - return false; + // Check line of sight from head + CVector headPos = this->GetPosition(); + headPos.z += 1.0f; + return !CWorld::ProcessLineOfSight(headPos, target->GetPosition(), colpoint, ent, true, false, false, false, false, false); +} + +// Some kind of binary sort +void +CPed::SortPeds(CPed **list, int min, int max) +{ + if (min >= max) + return; + + CVector leftDiff, rightDiff; + CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); + float middleDist = middleDiff.Magnitude(); + + int left = max; + int right = min; + while(right <= left){ + float rightDist, leftDist; + do { + rightDiff = GetPosition() - list[right]->GetPosition(); + rightDist = rightDiff.Magnitude(); + } while (middleDist > rightDist && ++right); + + do { + leftDiff = GetPosition() - list[left]->GetPosition(); + leftDist = leftDiff.Magnitude(); + } while (middleDist < leftDist && left--); + + if (right <= left) { + CPed *ped = list[right]; + list[right] = list[left]; + list[left] = ped; + right++; + left--; } } - return true; -} - -#ifdef VC_PED_PORTS -bool -CPed::CanPedJumpThis(CEntity *unused, CVector *damageNormal = nil) -{ - if (m_nSurfaceTouched == SURFACE_WATER) - return true; - - CVector pos = GetPosition(); - CVector forwardOffset = GetForward(); - if (damageNormal && damageNormal->z > 0.17f) { - if (damageNormal->z > 0.9f) - return false; - - CColModel *ourCol = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); - pos.z = ourCol->spheres->center.z - ourCol->spheres->radius * damageNormal->z + pos.z; - pos.z = pos.z + 0.05f; - float collPower = damageNormal->Magnitude2D(); - if (damageNormal->z > 0.5f) { - CVector invDamageNormal(-damageNormal->x, -damageNormal->y, 0.0f); - invDamageNormal *= 1.0f / collPower; - CVector estimatedJumpDist = invDamageNormal + collPower * invDamageNormal * ourCol->spheres->radius; - forwardOffset = estimatedJumpDist * Min(2.0f / collPower, 4.0f); - } else { - forwardOffset += collPower * ourCol->spheres->radius * forwardOffset; - } - } else { - pos.z -= 0.15f; - } - - CVector forwardPos = pos + forwardOffset; - return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); -} -#else -bool -CPed::CanPedJumpThis(CEntity *unused) -{ - CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); - CVector pos = GetPosition(); - CVector forwardPos( - forward.x + pos.x, - forward.y + pos.y, - pos.z); - - return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); -} -#endif - -bool -CPed::CanPedReturnToState(void) -{ - return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK && - m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY; -} - -bool -CPed::CanSeeEntity(CEntity *entity, float threshold = CAN_SEE_ENTITY_ANGLE_THRESHOLD) -{ - float neededAngle = CGeneral::GetRadianAngleBetweenPoints( - entity->GetPosition().x, - entity->GetPosition().y, - GetPosition().x, - GetPosition().y); - - if (neededAngle < 0.0f) - neededAngle += TWOPI; - else if (neededAngle > TWOPI) - neededAngle -= TWOPI; - - float ourAngle = m_fRotationCur; - if (ourAngle < 0.0f) - ourAngle += TWOPI; - else if (ourAngle > TWOPI) - ourAngle -= TWOPI; - - float neededTurn = Abs(neededAngle - ourAngle); - - return neededTurn < threshold || TWOPI - threshold < neededTurn; -} - -bool -CPed::IsTemporaryObjective(eObjective objective) -{ - return objective == OBJECTIVE_LEAVE_CAR || objective == OBJECTIVE_SET_LEADER || -#ifdef VC_PED_PORTS - objective == OBJECTIVE_LEAVE_CAR_AND_DIE || -#endif - objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER; + SortPeds(list, min, left); + SortPeds(list, right, max); } void @@ -2413,1056 +478,114 @@ CPed::SetMoveState(eMoveState state) } void -CPed::SetObjectiveTimer(int time) +CPed::SetMoveAnim(void) { - if (time == 0) { - m_objectiveTimer = 0; - } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; - } -} + if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) + return; -void -CPed::ForceStoredObjective(eObjective objective) -{ - if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - m_prevObjective = m_objective; + if (m_nMoveState == PEDMOVE_NONE) { + m_nStoredMoveState = PEDMOVE_NONE; return; } - switch (m_objective) - { - case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: + AssocGroupId animGroupToUse; + if (m_leader && m_leader->IsPlayer()) + animGroupToUse = ASSOCGRP_PLAYER; + else + animGroupToUse = m_animGroup; + + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_BLOCK); + if (!animAssoc) { + CAnimBlendAssociation *fightIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); + animAssoc = fightIdleAssoc; + if (fightIdleAssoc && m_nPedState == PED_FIGHT) return; - default: - m_prevObjective = m_objective; + + if (fightIdleAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 8.0f); + } + } } -} - -void -CPed::SetStoredObjective(void) -{ - if (m_objective == m_prevObjective) - return; - - switch (m_objective) - { - case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - return; - default: - m_prevObjective = m_objective; - } -} - -void -CPed::RestorePreviousObjective(void) -{ - if (m_objective == OBJECTIVE_NONE) - return; - - if (m_objective != OBJECTIVE_LEAVE_CAR && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER -#if defined VC_PED_PORTS || defined FIX_BUGS - && m_nPedState != PED_CARJACK -#endif - ) - m_pedInObjective = nil; - - if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { - m_objective = OBJECTIVE_NONE; - if (m_pMyVehicle) - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - - } else { - m_objective = m_prevObjective; - m_prevObjective = OBJECTIVE_NONE; - } - bObjectiveCompleted = false; -} - -void -CPed::SetLeader(CEntity *leader) -{ - m_leader = (CPed*)leader; - - if(m_leader) - m_leader->RegisterReference((CEntity **)&m_leader); -} - -void -CPed::SetObjective(eObjective newObj, void *entity) -{ - if (DyingOrDead()) - return; - - if (m_prevObjective == newObj) { - // Why? - if (m_prevObjective != OBJECTIVE_NONE) - return; - } - - if (entity == this) - return; - - SetObjectiveTimer(0); - if (m_objective == newObj) { - switch (newObj) { - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - case OBJECTIVE_GUARD_ATTACK: - if (m_pedInObjective == entity) - return; - - break; - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_FLEE_CAR: -#ifdef VC_PED_PORTS - case OBJECTIVE_LEAVE_CAR_AND_DIE: -#endif + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + if (animAssoc) + if (m_nWaitState == WAITSTATE_STUCK || m_nWaitState == WAITSTATE_FINISH_FLEE) return; - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_DESTROY_CAR: - case OBJECTIVE_SOLICIT_VEHICLE: - case OBJECTIVE_BUY_ICE_CREAM: - if (m_carInObjective == entity) - return; - break; - case OBJECTIVE_SET_LEADER: - if (m_leader == entity) - return; - - break; - default: - break; + if (animAssoc) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + } } - } else { - if ((newObj == OBJECTIVE_LEAVE_CAR -#ifdef VC_PED_PORTS - || newObj == OBJECTIVE_LEAVE_CAR_AND_DIE -#endif - ) && !bInVehicle) - return; } + if (!animAssoc) { + m_nStoredMoveState = m_nMoveState; + if (m_nMoveState == PEDMOVE_WALK || m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT) { + for (CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_PARTIAL); + assoc; assoc = RpAnimBlendGetNextAssociation(assoc, ASSOC_PARTIAL)) { -#ifdef VC_PED_PORTS - ClearPointGunAt(); -#endif - bObjectiveCompleted = false; - if (IsTemporaryObjective(m_objective) && !IsTemporaryObjective(newObj)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) { - if (IsTemporaryObjective(newObj)) - ForceStoredObjective(newObj); - else - SetStoredObjective(); - } - m_objective = newObj; - } - - switch (newObj) { - case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: - - // In this special case, entity parameter isn't CEntity, but int. - SetObjectiveTimer((uintptr)entity); - break; - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_MUG_CHAR: - m_pNextPathNode = nil; - bUsePedNodeSeek = false; - m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); - m_pedInObjective = (CPed*)entity; - m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - m_pLookTarget = (CEntity*)entity; - m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); - break; - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_GUARD_ATTACK: - m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); - m_pedInObjective = (CPed*)entity; - m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - break; - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - m_pedInObjective = (CPed*)entity; - m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); - m_pedFormation = FORMATION_REAR; - break; - case OBJECTIVE_LEAVE_CAR: -#ifdef VC_PED_PORTS - case OBJECTIVE_LEAVE_CAR_AND_DIE: -#endif - case OBJECTIVE_FLEE_CAR: - m_carInObjective = (CVehicle*)entity; - m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); - if (m_carInObjective->bIsBus && m_leaveCarTimer == 0) { - for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) { - if (m_carInObjective->pPassengers[i] == this) { - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; - break; - } + if (!(assoc->flags & ASSOC_FADEOUTWHENDONE)) { + assoc->blendDelta = -2.0f; + assoc->flags |= ASSOC_DELETEFADEDOUT; } } - break; - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - if (m_nMoveState == PEDMOVE_STILL) - SetMoveState(PEDMOVE_RUN); + ClearAimFlag(); + ClearLookFlag(); + } - if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { - RestorePreviousObjective(); + switch (m_nMoveState) { + case PEDMOVE_STILL: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); break; - } - // fall through - case OBJECTIVE_DESTROY_CAR: - case OBJECTIVE_SOLICIT_VEHICLE: - case OBJECTIVE_BUY_ICE_CREAM: - m_carInObjective = (CVehicle*)entity; - m_carInObjective->RegisterReference((CEntity**)&m_carInObjective); - m_pSeekTarget = m_carInObjective; - m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); - m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); - if (newObj == OBJECTIVE_SOLICIT_VEHICLE) { - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; - } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR && - (m_carInObjective->GetStatus() == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->ArePlayerControlsDisabled())) { - SetObjectiveTimer(14000); - } else { - m_objectiveTimer = 0; - } - break; - case OBJECTIVE_SET_LEADER: - SetLeader((CEntity*)entity); - RestorePreviousObjective(); - break; - default: - break; - } -} - -void -CPed::SetIdle(void) -{ - if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { -#ifdef VC_PED_PORTS - if (m_nPedState == PED_AIM_GUN) - ClearPointGunAt(); - - m_nLastPedState = PED_NONE; -#endif - m_nPedState = PED_IDLE; - SetMoveState(PEDMOVE_STILL); - } - if (m_nWaitState == WAITSTATE_FALSE) { - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000); - } -} - -void -CPed::SetObjective(eObjective newObj) -{ - if (DyingOrDead()) - return; - - if (newObj == OBJECTIVE_NONE) { - if ((m_objective == OBJECTIVE_LEAVE_CAR || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER -#ifdef VC_PED_PORTS - || m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) - && !IsPlayer() -#else - ) -#endif - && !IsPedInControl()) { - - bStartWanderPathOnFoot = true; - return; - } - // Unused code from assembly... - /* - else if(m_objective == OBJECTIVE_FLEE_CAR) { - - } else { - - } - */ - m_objective = OBJECTIVE_NONE; - m_prevObjective = OBJECTIVE_NONE; - } else if (m_prevObjective != newObj || m_prevObjective == OBJECTIVE_NONE) { - SetObjectiveTimer(0); - - if (m_objective == newObj) - return; - - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - bObjectiveCompleted = false; - - switch (newObj) { - case OBJECTIVE_NONE: - m_prevObjective = OBJECTIVE_NONE; + case PEDMOVE_WALK: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_WALK, 1.0f); break; - case OBJECTIVE_HAIL_TAXI: - m_nWaitTimer = 0; - SetIdle(); - SetMoveState(PEDMOVE_STILL); - break; - default: - break; - } - } -} - -// Only used in 01E1: SET_CHAR_OBJ_FOLLOW_ROUTE opcode -// IDA fails very badly in here, puts a fake loop and ignores SetFollowRoute call... -void -CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType) -{ - if (DyingOrDead()) - return; - - if (m_prevObjective == newObj && m_prevObjective != OBJECTIVE_NONE) - return; - - SetObjectiveTimer(0); - - if (m_objective == newObj && newObj == OBJECTIVE_FOLLOW_ROUTE && m_routeLastPoint == routePoint && m_routeType == routeType) - return; - - bObjectiveCompleted = false; - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - - if (newObj == OBJECTIVE_FOLLOW_ROUTE) { - SetFollowRoute(routePoint, routeType); - } -} - -void -CPed::ClearChat(void) -{ - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - bIsTalking = false; - ClearLookFlag(); - RestorePreviousState(); -} - -bool -CPed::IsGangMember(void) -{ - return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; -} - -void -CPed::InformMyGangOfAttack(CEntity *attacker) -{ - CPed *attackerPed; - - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) - return; - - if (attacker->IsPed()) { - attackerPed = (CPed*)attacker; - } else { - if (!attacker->IsVehicle()) - return; - - attackerPed = ((CVehicle*)attacker)->pDriver; - if (!attackerPed) - return; - } - - if (attackerPed->m_nPedType == PEDTYPE_COP) - return; - - for (int i = 0; i < m_numNearPeds; i++) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed && nearPed != this) { - CPed *leader = nearPed->m_leader; - if (leader && leader == this && nearPed->m_pedStats->m_fear < nearPed->m_pedStats->m_temper) - { - nearPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attackerPed); - nearPed->SetObjectiveTimer(30000); - } - } - } -} - -void -CPed::QuitEnteringCar(void) -{ - CVehicle *veh = m_pMyVehicle; - if (m_pVehicleAnim) - m_pVehicleAnim->blendDelta = -1000.0f; - - RestartNonPartialAnims(); - - if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE)) - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); - - if (veh) { - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_nPedState == PED_CARJACK) - veh->bIsBeingCarJacked = false; - - if (veh->m_nNumGettingIn != 0) - veh->m_nNumGettingIn--; - -#ifdef VC_PED_PORTS - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) - RestorePreviousObjective(); -#endif - - veh->m_nGettingInFlags &= ~GetCarDoorFlag(m_vehEnterType); - } - - bUsesCollision = true; - - ReplaceWeaponWhenExitingVehicle(); - - if (DyingOrDead()) { - if (m_pVehicleAnim) { - m_pVehicleAnim->blendDelta = -4.0f; - m_pVehicleAnim->flags |= ASSOC_DELETEFADEDOUT; - m_pVehicleAnim->flags &= ~ASSOC_RUNNING; - } - } else - SetIdle(); - - m_pVehicleAnim = nil; - - if (veh) { -#ifdef VC_PED_PORTS - if (veh->AutoPilot.m_nCruiseSpeed == 0 && veh->VehicleCreatedBy == RANDOM_VEHICLE) -#else - if (veh->AutoPilot.m_nCruiseSpeed == 0) -#endif - veh->AutoPilot.m_nCruiseSpeed = 17; - } -} - -void -CPed::ReactToAttack(CEntity *attacker) -{ - if (IsPlayer() && attacker->IsPed()) { - InformMyGangOfAttack(attacker); - SetLookFlag(attacker, true); - SetLookTimer(700); - return; - } - -#ifdef VC_PED_PORTS - if (m_nPedState == PED_DRIVING && InVehicle() - && (m_pMyVehicle->pDriver == this || m_pMyVehicle->pDriver && m_pMyVehicle->pDriver->m_nPedState == PED_DRIVING && m_pMyVehicle->pDriver->m_objective != OBJECTIVE_LEAVE_CAR_AND_DIE)) { - - if (m_pMyVehicle->VehicleCreatedBy == RANDOM_VEHICLE - && (m_pMyVehicle->GetStatus() == STATUS_SIMPLE || m_pMyVehicle->GetStatus() == STATUS_PHYSICS) - && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) { - - CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); - m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; - m_pMyVehicle->SetStatus(STATUS_PHYSICS); - } - } else -#endif - if (IsPedInControl() && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats)) { - CPed *ourLeader = m_leader; - if (ourLeader != attacker && (!ourLeader || FindPlayerPed() != ourLeader) - && attacker->IsPed()) { - - CPed *attackerPed = (CPed*)attacker; - if (bNotAllowedToDuck) { - if (!attackerPed->GetWeapon()->IsTypeMelee()) { - m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds(); - return; + case PEDMOVE_RUN: + if (m_nPedState == PED_FLEE_ENTITY) { + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 3.0f); + } else { + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 1.0f); } - } else if (bCrouchWhenShooting || bKindaStayInSamePlace) { - SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); - return; - } - - if (m_pedStats->m_fear <= 100 - attackerPed->m_pedStats->m_temper) { - if (m_pedStats != attackerPed->m_pedStats) { - if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { - RegisterThreatWithGangPeds(attackerPed); - } - if (!attackerPed->GetWeapon()->IsTypeMelee() && GetWeapon()->IsTypeMelee()) { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attacker); - SetMoveState(PEDMOVE_RUN); - } else { - SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attacker); - SetObjectiveTimer(20000); - } - } - } else { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attackerPed); - SetMoveState(PEDMOVE_RUN); - if (attackerPed->GetWeapon()->IsTypeMelee()) - Say(SOUND_PED_FLEE_RUN); - } - } - } -} - -bool -CPed::TurnBody(void) -{ - bool turnDone = true; - - if (m_pLookTarget) - m_fLookDirection = CGeneral::GetRadianAngleBetweenPoints( - m_pLookTarget->GetPosition().x, - m_pLookTarget->GetPosition().y, - GetPosition().x, - GetPosition().y); - - float limitedLookDir = CGeneral::LimitRadianAngle(m_fLookDirection); - float currentRot = m_fRotationCur; - - if (currentRot - PI > limitedLookDir) - limitedLookDir += 2 * PI; - else if (PI + currentRot < limitedLookDir) - limitedLookDir -= 2 * PI; - - float neededTurn = currentRot - limitedLookDir; - m_fRotationDest = limitedLookDir; - - if (Abs(neededTurn) > 0.05f) { - turnDone = false; - currentRot -= neededTurn * 0.2f; - } - - m_fRotationCur = currentRot; - m_fLookDirection = limitedLookDir; - return turnDone; -} - -void -CPed::Chat(void) -{ - // We're already looking to our partner - if (bIsLooking && TurnBody()) - ClearLookFlag(); - - if (!m_pLookTarget || !m_pLookTarget->IsPed()) { - ClearChat(); - return; - } - - CPed *partner = (CPed*) m_pLookTarget; - - if (partner->m_nPedState != PED_CHAT) { - ClearChat(); - if (partner->m_pedInObjective) { - if (partner->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || - partner->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE) - ReactToAttack(partner->m_pedInObjective); - } - return; - } - if (bIsTalking) { - if (CGeneral::GetRandomNumber() < 512) { - CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); - if (chatAssoc) { - chatAssoc->blendDelta = -4.0f; - chatAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - bIsTalking = false; - } else - Say(SOUND_PED_CHAT); - - } else { - - if (CGeneral::GetRandomNumber() < 20 && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); - } - if (!bIsTalking && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { - CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f); - float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f); - chatAssoc->SetCurrentTime(chatTime); - - bIsTalking = true; - Say(SOUND_PED_CHAT); - } - } - if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) { - ClearChat(); - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; - } -} - -void -CPed::CheckAroundForPossibleCollisions(void) -{ - CVector ourCentre, objCentre; - CEntity *objects[8]; - int16 maxObject; - - if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) - return; - - GetBoundCentre(ourCentre); - - CWorld::FindObjectsInRange(ourCentre, 10.0f, true, &maxObject, 6, objects, false, true, false, true, false); - for (int i = 0; i < maxObject; i++) { - CEntity *object = objects[i]; - if (bRunningToPhone) { - if (gPhoneInfo.PhoneAtThisPosition(object->GetPosition())) break; - } - object->GetBoundCentre(objCentre); - float radius = object->GetBoundRadius(); - if (radius > 4.5f || radius < 1.0f) - radius = 1.0f; - - // Developers gave up calculating Z diff. later according to asm. - float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); - - if (sq(radius + 1.0f) > diff) - m_fRotationDest += DEGTORAD(22.5f); - } -} - -#ifdef PEDS_REPORT_CRIMES_ON_PHONE -void -ReportPhonePickUpCB(CAnimBlendAssociation* assoc, void* arg) -{ - CPed* ped = (CPed*)arg; - ped->m_nMoveState = PEDMOVE_STILL; - CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); - - if (assoc->blendAmount > 0.5f && ped) { - CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); - } -} - -void -ReportPhonePutDownCB(CAnimBlendAssociation* assoc, void* arg) -{ - assoc->flags |= ASSOC_DELETEFADEDOUT; - assoc->blendDelta = -1000.0f; - CPed* ped = (CPed*)arg; - - if (ped->m_phoneId != -1 && crimeReporters[ped->m_phoneId] == ped) { - crimeReporters[ped->m_phoneId] = nil; - gPhoneInfo.m_aPhones[ped->m_phoneId].m_nState = PHONE_STATE_FREE; - ped->m_phoneId = -1; - } - - if (assoc->blendAmount > 0.5f) - ped->bUpdateAnimHeading = true; - - ped->SetWanderPath(CGeneral::GetRandomNumber() & 7); -} -#endif - -bool -CPed::MakePhonecall(void) -{ -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - if (!IsPlayer() && CTimer::GetTimeInMilliseconds() > m_phoneTalkTimer - 7000 && bRunningToPhone) { - - FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(m_crimeToReportOnPhone, GetPosition(), - (m_crimeToReportOnPhone == CRIME_POSSESSION_GUN ? (uintptr)m_threatEntity : (uintptr)m_victimOfPlayerCrime), false); - - if (m_crimeToReportOnPhone != CRIME_POSSESSION_GUN) - FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1); - - bRunningToPhone = false; - } -#endif - if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) - return false; - -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - CAnimBlendAssociation* talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_PHONE_TALK); - if (talkAssoc && talkAssoc->blendAmount > 0.5f) { - CAnimBlendAssociation* endAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_OUT, 8.0f); - endAssoc->flags &= ~ASSOC_DELETEFADEDOUT; - endAssoc->SetFinishCallback(ReportPhonePutDownCB, this); - } -#endif - SetIdle(); - - gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; -#ifndef PEDS_REPORT_CRIMES_ON_PHONE - m_phoneId = -1; -#endif - - // Because SetWanderPath is now done async in ReportPhonePutDownCB -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - return false; -#else - return true; -#endif -} - -bool -CPed::FacePhone(void) -{ - // This function was broken since it's left unused early in development. -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - float phoneDir = CGeneral::GetRadianAngleBetweenPoints( - gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, - GetPosition().x, GetPosition().y); - - if (m_facePhoneStart) { - m_lookTimer = 0; - SetLookFlag(phoneDir, true); - m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; - m_facePhoneStart = false; - } - - if (bIsLooking && TurnBody()) { - ClearLookFlag(); - SetIdle(); - m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; - CAnimBlendAssociation* assoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_IN, 4.0f); - assoc->SetFinishCallback(ReportPhonePickUpCB, this); - return true; - } - - return false; -#else - float currentRot = RADTODEG(m_fRotationCur); - float phoneDir = CGeneral::GetRadianAngleBetweenPoints( - gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, - gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, - GetPosition().x, - GetPosition().y); - - SetLookFlag(phoneDir, false); - phoneDir = CGeneral::LimitAngle(phoneDir); - m_moved = CVector2D(0.0f, 0.0f); - - if (currentRot - 180.0f > phoneDir) - phoneDir += 2 * 180.0f; - else if (180.0f + currentRot < phoneDir) - phoneDir -= 2 * 180.0f; - - float neededTurn = currentRot - phoneDir; - - if (Abs(neededTurn) <= 0.75f) { - SetIdle(); - ClearLookFlag(); - m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; - return true; - } else { - m_fRotationCur = DEGTORAD(currentRot - neededTurn * 0.2f); - return false; - } -#endif -} - -CPed * -CPed::CheckForDeadPeds(void) -{ - int event; - if (CEventList::FindClosestEvent(EVENT_DEAD_PED, GetPosition(), &event)) { - int pedHandle = gaEvent[event].entityRef; - if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { - bGonnaInvestigateEvent = true; - return CPools::GetPed(pedHandle); - } - } - bGonnaInvestigateEvent = false; - return nil; -} - -#ifdef PEDS_REPORT_CRIMES_ON_PHONE -// returns event id, parameter is optional -int32 -CPed::CheckForPlayerCrimes(CPed *victim) -{ - int i; - float dist; - float mindist = 60.0f; - CPlayerPed *player = FindPlayerPed(); - int32 victimRef = (victim ? CPools::GetPedRef(victim) : 0); - int event = -1; - - for (i = 0; i < NUMEVENTS; i++) { - if (gaEvent[i].type == EVENT_NULL || gaEvent[i].type > EVENT_CAR_SET_ON_FIRE) - continue; - - // those are already handled in game, also DEAD_PED isn't registered alone, most of the time there is SHOOT_PED etc. - if (gaEvent[i].type == EVENT_DEAD_PED || gaEvent[i].type == EVENT_GUNSHOT || gaEvent[i].type == EVENT_EXPLOSION) - continue; - - if (victim && gaEvent[i].entityRef != victimRef) - continue; - - if (gaEvent[i].criminal != player) - continue; - - dist = (GetPosition() - gaEvent[i].posn).Magnitude(); - if (dist < mindist) { - mindist = dist; - event = i; - } - } - - if (event != -1) { - if (victim) { - m_victimOfPlayerCrime = victim; - } else { - switch (gaEvent[event].entityType) { - case EVENT_ENTITY_PED: - m_victimOfPlayerCrime = CPools::GetPed(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_VEHICLE: - m_victimOfPlayerCrime = CPools::GetVehicle(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_OBJECT: - m_victimOfPlayerCrime = CPools::GetObject(gaEvent[event].entityRef); - break; - default: - break; - } - } - } - - return event; -} -#endif - -bool -CPed::CheckForExplosions(CVector2D &area) -{ - int event = 0; - if (CEventList::FindClosestEvent(EVENT_EXPLOSION, GetPosition(), &event)) { - area.x = gaEvent[event].posn.x; - area.y = gaEvent[event].posn.y; - CEntity *actualEntity = nil; - - switch (gaEvent[event].entityType) { - case EVENT_ENTITY_PED: - actualEntity = CPools::GetPed(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_VEHICLE: - actualEntity = CPools::GetVehicle(gaEvent[event].entityRef); - break; - case EVENT_ENTITY_OBJECT: - actualEntity = CPools::GetObject(gaEvent[event].entityRef); + case PEDMOVE_SPRINT: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_SPRINT, 1.0f); break; default: break; } - if (actualEntity) { - m_pEventEntity = actualEntity; - m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); - bGonnaInvestigateEvent = true; - } else - bGonnaInvestigateEvent = false; + if (animAssoc) { + if (m_leader) { + CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); - CEventList::ClearEvent(event); - return true; - } else if (CEventList::FindClosestEvent(EVENT_FIRE, GetPosition(), &event)) { - area.x = gaEvent[event].posn.x; - area.y = gaEvent[event].posn.y; - CEventList::ClearEvent(event); - bGonnaInvestigateEvent = false; - return true; - } + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_SPRINT); - bGonnaInvestigateEvent = false; - return false; -} - -CPed * -CPed::CheckForGunShots(void) -{ - int event; - if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) { - if (gaEvent[event].entityType == EVENT_ENTITY_PED) { - // Probably due to we don't want peds to go gunshot area? (same on VC) - bGonnaInvestigateEvent = false; - return CPools::GetPed(gaEvent[event].entityRef); - } - } - bGonnaInvestigateEvent = false; - return nil; -} - -PointBlankNecessity -CPed::CheckForPointBlankPeds(CPed *pedToVerify) -{ - float pbDistance = 1.1f; - if (GetWeapon()->IsType2Handed()) - pbDistance = 1.6f; - - for (int i = 0; i < m_numNearPeds; i++) { - CPed *nearPed = m_nearPeds[i]; - - if (!pedToVerify || pedToVerify == nearPed) { - - CVector diff = nearPed->GetPosition() - GetPosition(); - if (diff.Magnitude() < pbDistance) { - - float neededAngle = CGeneral::GetRadianAngleBetweenPoints( - nearPed->GetPosition().x, nearPed->GetPosition().y, - GetPosition().x, GetPosition().y); - neededAngle = CGeneral::LimitRadianAngle(neededAngle); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - - float neededTurn = Abs(neededAngle - m_fRotationCur); - - if (neededTurn > PI) - neededTurn = 2*PI - neededTurn; - - if (nearPed->OnGroundOrGettingUp() || nearPed->m_nPedState == PED_DIVE_AWAY) - return NO_POINT_BLANK_PED; - - if (neededTurn < CAN_SEE_ENTITY_ANGLE_THRESHOLD) { - if (pedToVerify == nearPed) - return POINT_BLANK_FOR_WANTED_PED; + if (walkAssoc) { + animAssoc->speed = walkAssoc->speed; + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; else - return POINT_BLANK_FOR_SOMEONE_ELSE; + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; + } + } else { + if (CharCreatedBy == MISSION_CHAR) + animAssoc->speed = 1.0f; + else + animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; } } } - return NO_POINT_BLANK_PED; -} - -bool -CPed::CheckIfInTheAir(void) -{ - if (bInVehicle) - return false; - - CVector pos = GetPosition(); - CColPoint foundColPoint; - CEntity *foundEntity; - - float startZ = pos.z - 1.54f; - bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, nil); - if (!foundGround && m_nPedState != PED_JUMP) - { - pos.z -= FEET_OFFSET; - if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) - foundGround = true; - } - return !foundGround; -} - -void -CPed::ClearAll(void) -{ - if (!IsPedInControl() && m_nPedState != PED_DEAD) - return; - - m_nPedState = PED_NONE; - m_nMoveState = PEDMOVE_NONE; - m_pSeekTarget = nil; - m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); - m_fleeFromPosX = 0.0f; - m_fleeFromPosY = 0.0f; - m_fleeFrom = nil; - m_fleeTimer = 0; - bUsesCollision = true; -#ifdef VC_PED_PORTS - ClearPointGunAt(); -#else - ClearAimFlag(); - ClearLookFlag(); -#endif - bIsPointingGunAt = false; - bRenderPedInCar = true; - bKnockedUpIntoAir = false; - m_pCollidingEntity = nil; -} - -void -CPed::ClearAttack(void) -{ - if (m_nPedState != PED_ATTACK || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) - return; - -#ifdef VC_PED_PORTS - // VC uses CCamera::Using1stPersonWeaponMode - if (FindPlayerPed() == this && (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_SNIPER || - TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_ROCKETLAUNCHER)) { - SetPointGunAt(nil); - } else -#endif - if (bIsPointingGunAt) { - if (m_pLookTarget) - SetPointGunAt(m_pLookTarget); - else - ClearPointGunAt(); - } else if (m_objective != OBJECTIVE_NONE) { - SetIdle(); - } else { - RestorePreviousState(); - } -} - -void -CPed::ClearAttackByRemovingAnim(void) -{ - if (m_nPedState != PED_ATTACK || bIsDucking) - return; - - CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_AnimToPlay); - if (!weaponAssoc) { - weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_Anim2ToPlay); - - if (!weaponAssoc && weapon->m_bThrow) - weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU); - - if (!weaponAssoc) { - ClearAttack(); - return; - } - } - weaponAssoc->blendDelta = -8.0f; - weaponAssoc->flags &= ~ASSOC_RUNNING; - weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; - weaponAssoc->SetDeleteCallback(FinishedAttackCB, this); } void @@ -3476,6 +599,17 @@ CPed::StopNonPartialAnims(void) } } +void +CPed::RestartNonPartialAnims(void) +{ + CAnimBlendAssociation *assoc; + + for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->SetRun(); + } +} + void CPed::SetStoredState(void) { @@ -3497,775 +631,6 @@ CPed::SetStoredState(void) } } -void -CPed::SetDie(AnimationId animId, float delta, float speed) -{ - CPlayerPed *player = FindPlayerPed(); - if (player == this) { - if (!player->m_bCanBeDamaged) - return; - } - - m_threatEntity = nil; - if (DyingOrDead()) - return; - - if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) - delta *= 0.5f; - - SetStoredState(); - ClearAll(); - m_fHealth = 0.0f; - if (m_nPedState == PED_DRIVING) { - if (!IsPlayer()) - FlagToDestroyWhenNextProcessed(); - } else if (bInVehicle) { - if (m_pVehicleAnim) - m_pVehicleAnim->blendDelta = -1000.0f; - } else if (EnteringCar()) { - QuitEnteringCar(); - } - - m_nPedState = PED_DIE; - if (animId == NUM_ANIMS) { - bIsPedDieAnimPlaying = false; - } else { - CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, delta); - if (speed > 0.0f) - dieAssoc->speed = speed; - - dieAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - if (dieAssoc->IsRunning()) { - dieAssoc->SetFinishCallback(FinishDieAnimCB, this); - bIsPedDieAnimPlaying = true; - } - } - - Say(SOUND_PED_DEATH); - if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK) - QuitEnteringCar(); - if (!bInVehicle) - StopNonPartialAnims(); - - m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); -} - -bool -CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPieceTypes pedPiece, uint8 direction) -{ - CPlayerPed *player = FindPlayerPed(); - float dieDelta = 4.0f; - float dieSpeed = 0.0f; - AnimationId dieAnim = ANIM_KO_SHOT_FRONT1; - bool headShot = false; - bool willLinger = false; - int random; - - if (player == this) { - if (!player->m_bCanBeDamaged) - return false; - - player->AnnoyPlayerPed(false); - } - - if (DyingOrDead()) - return false; - - if (!bUsesCollision && method != WEAPONTYPE_DROWNING) - return false; - - if (bOnlyDamagedByPlayer && damagedBy != player && damagedBy != FindPlayerVehicle() && - method != WEAPONTYPE_DROWNING && method != WEAPONTYPE_EXPLOSION) - return false; - - float healthImpact; - if (IsPlayer()) - healthImpact = damage * 0.33f; - else - healthImpact = damage * m_pedStats->m_defendWeakness; - - bool detectDieAnim = true; - if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) { - if (!IsPedHeadAbovePos(-0.3f)) { - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - dieAnim = ANIM_FLOOR_HIT_F; - else - dieAnim = ANIM_FLOOR_HIT; - dieDelta *= 2.0f; - dieSpeed = 0.5f; - detectDieAnim = false; - } else if (m_nPedState == PED_FALL) { - dieAnim = NUM_ANIMS; - detectDieAnim = false; - } - } - if (detectDieAnim) { - switch (method) { - case WEAPONTYPE_UNARMED: - if (bMeleeProof) - return false; - - if (m_nPedState == PED_FALL) { - if (IsPedHeadAbovePos(-0.3f)) { - dieAnim = NUM_ANIMS; - } else { - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - dieAnim = ANIM_FLOOR_HIT_F; - else - dieAnim = ANIM_FLOOR_HIT; - dieDelta = dieDelta * 2.0f; - dieSpeed = 0.5f; - } - } else { - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - } - break; - case WEAPONTYPE_BASEBALLBAT: - if (bMeleeProof) - return false; - - if (m_nPedState == PED_FALL) { - if (IsPedHeadAbovePos(-0.3f)) { - dieAnim = NUM_ANIMS; - } else { - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - dieAnim = ANIM_FLOOR_HIT_F; - else - dieAnim = ANIM_FLOOR_HIT; - dieDelta = dieDelta * 2.0f; - dieSpeed = 0.5f; - } - } else { - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - } - break; - case WEAPONTYPE_COLT45: - case WEAPONTYPE_UZI: - case WEAPONTYPE_SHOTGUN: - case WEAPONTYPE_AK47: - case WEAPONTYPE_M16: - case WEAPONTYPE_SNIPERRIFLE: - if (bBulletProof) - return false; - - bool dontRemoveLimb; - if (IsPlayer() || bNoCriticalHits) - dontRemoveLimb = true; - else { - switch (method) { - case WEAPONTYPE_SNIPERRIFLE: - dontRemoveLimb = false; - break; - case WEAPONTYPE_M16: - dontRemoveLimb = false; - break; - case WEAPONTYPE_SHOTGUN: - dontRemoveLimb = CGeneral::GetRandomNumber() & 7; - break; - default: - dontRemoveLimb = CGeneral::GetRandomNumber() & 15; - break; - } - } - - if (dontRemoveLimb) { - if (method == WEAPONTYPE_SHOTGUN) { - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - } else - dieAnim = ANIM_KO_SHOT_FRONT1; - - willLinger = false; - } else { - switch (pedPiece) { - case PEDPIECE_TORSO: - willLinger = false; - dieAnim = ANIM_KO_SHOT_FRONT1; - break; - case PEDPIECE_MID: - willLinger = false; - dieAnim = ANIM_KO_SHOT_STOM; - break; - case PEDPIECE_LEFTARM: - dieAnim = ANIM_KO_SHOT_ARML; - RemoveBodyPart(PED_UPPERARML, direction); - willLinger = true; - break; - case PEDPIECE_RIGHTARM: - dieAnim = ANIM_KO_SHOT_ARMR; - RemoveBodyPart(PED_UPPERARMR, direction); - willLinger = true; - break; - case PEDPIECE_LEFTLEG: - dieAnim = ANIM_KO_SHOT_LEGL; - RemoveBodyPart(PED_UPPERLEGL, direction); - willLinger = true; - break; - case PEDPIECE_RIGHTLEG: - dieAnim = ANIM_KO_SHOT_LEGR; - RemoveBodyPart(PED_UPPERLEGR, direction); - willLinger = true; - break; - case PEDPIECE_HEAD: - dieAnim = ANIM_KO_SHOT_FACE; - RemoveBodyPart(PED_HEAD, direction); - headShot = true; - willLinger = true; - break; - default: - break; - } - } - break; - case WEAPONTYPE_ROCKETLAUNCHER: - case WEAPONTYPE_GRENADE: - case WEAPONTYPE_EXPLOSION: - if (bExplosionProof) - return false; - - if (CGame::nastyGame && !IsPlayer() && !bInVehicle && - 1.0f + healthImpact > m_fArmour + m_fHealth) { - - random = CGeneral::GetRandomNumber(); - if (random & 1) - RemoveBodyPart(PED_UPPERARML, direction); - if (random & 2) - RemoveBodyPart(PED_UPPERLEGR, direction); - if (random & 4) - RemoveBodyPart(PED_HEAD, direction); - if (random & 8) - RemoveBodyPart(PED_UPPERARMR, direction); - if (random & 0x10) - RemoveBodyPart(PED_UPPERLEGL, direction); - if (bBodyPartJustCameOff) - willLinger = true; - } - // fall through - case WEAPONTYPE_MOLOTOV: - if (bExplosionProof) - return false; - - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - break; - case WEAPONTYPE_FLAMETHROWER: - if (bFireProof) - return false; - - dieAnim = ANIM_KO_SHOT_FRONT1; - break; - case WEAPONTYPE_RAMMEDBYCAR: - case WEAPONTYPE_RUNOVERBYCAR: - if (bCollisionProof) - return false; - - random = CGeneral::GetRandomNumber() & 3; - switch (random) { - case 0: - if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) - && (pedPiece != PEDPIECE_MID || random != 1)) { - if (pedPiece == PEDPIECE_RIGHTARM && random > 1 - || pedPiece == PEDPIECE_MID && random == 2) - - dieAnim = ANIM_KO_SPIN_L; - else - dieAnim = ANIM_KO_SKID_FRONT; - } else - dieAnim = ANIM_KO_SPIN_R; - - break; - case 1: - if (m_nPedState == PED_DIVE_AWAY) - dieAnim = ANIM_KD_LEFT; - else - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) - && (pedPiece != PEDPIECE_MID || random != 1)) { - if ((pedPiece != PEDPIECE_RIGHTARM || random <= 1) - && (pedPiece != PEDPIECE_MID || random != 2)) { - dieAnim = ANIM_KO_SKID_BACK; - } else { - dieAnim = ANIM_KD_RIGHT; - } - } else - dieAnim = ANIM_KD_LEFT; - break; - case 3: - if (m_nPedState == PED_DIVE_AWAY) - dieAnim = ANIM_KD_RIGHT; - else - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - if (damagedBy) { - CVehicle *vehicle = (CVehicle*)damagedBy; - if (method == WEAPONTYPE_RAMMEDBYCAR) { - float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); - dieDelta = 8.0f * vehSpeed + 4.0f; - } else { - float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); - dieDelta = 12.0f * vehSpeed + 4.0f; - dieSpeed = 16.0f * vehSpeed + 1.0f; - } - } - break; - case WEAPONTYPE_DROWNING: - dieAnim = ANIM_DROWN; - break; - case WEAPONTYPE_FALL: - if (bCollisionProof) - return false; - - switch (direction) { - case 0: - dieAnim = ANIM_KO_SKID_FRONT; - break; - case 1: - dieAnim = ANIM_KO_SPIN_R; - break; - case 2: - dieAnim = ANIM_KO_SKID_BACK; - break; - case 3: - dieAnim = ANIM_KO_SPIN_L; - break; - default: - break; - } - break; - default: - break; - } - } - - if (m_fArmour != 0.0f && method != WEAPONTYPE_DROWNING) { - if (player == this) - CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds(); - - if (healthImpact < m_fArmour) { - m_fArmour = m_fArmour - healthImpact; - healthImpact = 0.0f; - } else { - healthImpact = healthImpact - m_fArmour; - m_fArmour = 0.0f; - } - } - - if (healthImpact != 0.0f) { - if (player == this) - CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss = CTimer::GetTimeInMilliseconds(); - - m_lastWepDam = method; - } - - if (m_fHealth - healthImpact >= 1.0f && !willLinger) { - m_fHealth -= healthImpact; - return false; - } - - if (bInVehicle) { - if (method != WEAPONTYPE_DROWNING) { -#ifdef VC_PED_PORTS - if (m_pMyVehicle) { - if (m_pMyVehicle->IsCar() && m_pMyVehicle->pDriver == this) { - if (m_pMyVehicle->GetStatus() == STATUS_SIMPLE) { - m_pMyVehicle->SetStatus(STATUS_PHYSICS); - CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); - } - m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - m_pMyVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKESTRAIGHT; - m_pMyVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000; - } - if (m_pMyVehicle->CanPedExitCar()) { - SetObjective(OBJECTIVE_LEAVE_CAR_AND_DIE, m_pMyVehicle); - } else { - m_fHealth = 0.0f; - if (m_pMyVehicle && m_pMyVehicle->pDriver == this) { - SetRadioStation(); - m_pMyVehicle->SetStatus(STATUS_ABANDONED); - } - SetDie(dieAnim, dieDelta, dieSpeed); - /* - if (damagedBy == FindPlayerPed() && damagedBy != this) { - // PlayerInfo stuff - } - */ - } - for (int i = 0; i < ARRAY_SIZE(m_pMyVehicle->pPassengers); i++) { - CPed* passenger = m_pMyVehicle->pPassengers[i]; - if (passenger && passenger != this && damagedBy) - passenger->ReactToAttack(damagedBy); - } - - CPed *driverOfVeh = m_pMyVehicle->pDriver; - if (driverOfVeh && driverOfVeh != this && damagedBy) - driverOfVeh->ReactToAttack(damagedBy); - - if (damagedBy == FindPlayerPed() || damagedBy && damagedBy == FindPlayerVehicle()) { - CDarkel::RegisterKillByPlayer(this, method, headShot); - m_threatEntity = FindPlayerPed(); - } else { - CDarkel::RegisterKillNotByPlayer(this, method); - } - } -#endif - m_fHealth = 1.0f; - return false; - } - m_fHealth = 0.0f; - if (player == this) - m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED); - - SetDie(NUM_ANIMS, 4.0f, 0.0f); - return true; - } else { - m_fHealth = 0.0f; - SetDie(dieAnim, dieDelta, dieSpeed); - - if (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) { - - // There are PlayerInfo stuff here in VC - CDarkel::RegisterKillByPlayer(this, method, headShot); - m_threatEntity = player; - } else { - CDarkel::RegisterKillNotByPlayer(this, method); - } - if (method == WEAPONTYPE_DROWNING) - bIsInTheAir = false; - - return true; - } -} - -void -CPed::ClearFlee(void) -{ - RestorePreviousState(); - bUsePedNodeSeek = false; - m_standardTimer = 0; - m_fleeTimer = 0; -} - -void -CPed::ClearFall(void) -{ - SetGetUp(); -} - -void -CPed::SetGetUp(void) -{ - if (m_nPedState == PED_GETUP && bGetUpAnimStarted) - return; - - if (!CanSetPedState()) - return; - - if (m_fHealth >= 1.0f || IsPedHeadAbovePos(-0.3f)) { - if (bUpdateAnimHeading) { - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - m_fRotationCur -= HALFPI; - bUpdateAnimHeading = false; - } - if (m_nPedState != PED_GETUP) { - SetStoredState(); - m_nPedState = PED_GETUP; - } - - CVehicle *collidingVeh = (CVehicle*)m_pCollidingEntity; - CVehicle *veh = (CVehicle*)CPedPlacement::IsPositionClearOfCars(&GetPosition()); - if (veh && veh->m_vehType != VEHICLE_TYPE_BIKE || - collidingVeh && collidingVeh->IsVehicle() && collidingVeh->m_vehType != VEHICLE_TYPE_BIKE - && ((uint8)(CTimer::GetFrameCounter() + m_randomSeed + 5) % 8 || - CCollision::ProcessColModels(GetMatrix(), *GetColModel(), collidingVeh->GetMatrix(), *collidingVeh->GetColModel(), - aTempPedColPts, nil, nil) > 0)) { - - bGetUpAnimStarted = false; - if (IsPlayer()) - InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); - else { - if (!CPad::GetPad(0)->ArePlayerControlsDisabled()) - return; - - InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, 0); - } - return; - } - bGetUpAnimStarted = true; - m_pCollidingEntity = nil; - bKnockedUpIntoAir = false; - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT); - if (animAssoc) { - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN)) { - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_RUN, 8.0f); - } else { - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); - } - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f); - else - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); - - animAssoc->SetFinishCallback(PedGetupCB,this); - } else { - m_fHealth = 0.0f; - SetDie(NUM_ANIMS, 4.0f, 0.0f); - } -} - -void -CPed::ClearInvestigateEvent(void) -{ - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - if (m_eventType > EVENT_EXPLOSION) - m_standardTimer = CTimer::GetTimeInMilliseconds() + 15000; - - bGonnaInvestigateEvent = false; - m_pEventEntity = nil; - ClearLookFlag(); - RestorePreviousState(); - if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) - SetMoveState(PEDMOVE_WALK); -} - -void -CPed::ClearLeader(void) -{ - if (!m_leader) - return; - - m_leader = nil; - if (IsPedInControl()) { - SetObjective(OBJECTIVE_NONE); - if (CharCreatedBy == MISSION_CHAR) { - SetIdle(); - } else { - SetWanderPath(CGeneral::GetRandomNumberInRange(0,8)); - } - } else if (m_objective != OBJECTIVE_NONE) { - bClearObjective = true; - } -} - -void -CPed::ClearLook(void) -{ - RestorePreviousState(); - ClearLookFlag(); -} - -void -CPed::ClearObjective(void) -{ - if (IsPedInControl() || m_nPedState == PED_DRIVING) { - m_objective = OBJECTIVE_NONE; -#ifdef VC_PED_PORTS - m_pedInObjective = nil; - m_carInObjective = nil; -#endif - if (m_nPedState == PED_DRIVING && m_pMyVehicle) { - - if (m_pMyVehicle->pDriver != this) { -#if defined VC_PED_PORTS || defined FIX_BUGS - if(!IsPlayer()) -#endif - bWanderPathAfterExitingCar = true; - - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } -#ifdef VC_PED_PORTS - m_nLastPedState = PED_NONE; -#endif - } else { - SetIdle(); - SetMoveState(PEDMOVE_STILL); - } - } else { - bClearObjective = true; - } -} - -void -CPed::ClearPause(void) -{ - RestorePreviousState(); -} - -void -CPed::ClearSeek(void) -{ - SetIdle(); - bRunningToPhone = false; -} - -bool -CPed::SetWanderPath(int8 pathStateDest) -{ - uint8 nextPathState; - - if (IsPedInControl()) { - if (bKindaStayInSamePlace) { - SetIdle(); - return false; - } else { - m_nPathDir = pathStateDest; - if (pathStateDest == 0) - pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); - - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &nextPathState); - - // Circular loop until we find a node for current m_nPathDir - while (!m_pNextPathNode) { - m_nPathDir = (m_nPathDir+1) % 8; - - // We're at where we started and couldn't find any node - if (m_nPathDir == pathStateDest) { - ClearAll(); - SetIdle(); - return false; - } - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &nextPathState); - } - - // We did it, save next path state and return true - m_nPathDir = nextPathState; - m_nPedState = PED_WANDER_PATH; - SetMoveState(PEDMOVE_WALK); - bIsRunning = false; - return true; - } - } else { - m_nPathDir = pathStateDest; - bStartWanderPathOnFoot = true; - return false; - } -} - -void -CPed::ClearWeapons(void) -{ - CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(currentWeapon->m_nModelId); - - m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT; - m_currentWeapon = WEAPONTYPE_UNARMED; - - currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - AddWeaponModel(currentWeapon->m_nModelId); - for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { - CWeapon &weapon = GetWeapon(i); - weapon.m_eWeaponType = WEAPONTYPE_UNARMED; - weapon.m_eWeaponState = WEAPONSTATE_READY; - weapon.m_nAmmoInClip = 0; - weapon.m_nAmmoTotal = 0; - weapon.m_nTimer = 0; - } -} - -void -CPed::RestoreGunPosition(void) -{ - if (bIsLooking) { - m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; - bIsRestoringGun = false; - } else if (m_pedIK.RestoreGunPosn()) { - bIsRestoringGun = false; - } else { - if (IsPlayer()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; - } -} - -void -CPed::RestoreHeadingRate(void) -{ - m_headingRate = m_pedStats->m_headingChangeRate; -} - -void -CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) -{ - ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate; -} - void CPed::RestorePreviousState(void) { @@ -4315,4522 +680,246 @@ CPed::RestorePreviousState(void) } } -void -CPed::SetAimFlag(CEntity *to) +uint32 +CPed::ScanForThreats(void) { - bIsAimingGun = true; - bIsRestoringGun = false; - m_pLookTarget = to; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - m_pSeekTarget = to; - m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - m_lookTimer = 0; -} - -void -CPed::SetAimFlag(float angle) -{ - bIsAimingGun = true; - bIsRestoringGun = false; - m_fLookDirection = angle; - m_lookTimer = 0; - m_pLookTarget = nil; - m_pSeekTarget = nil; - if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; - else - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; -} - -void -CPed::SetPointGunAt(CEntity *to) -{ - if (to) { - SetLookFlag(to, true); - SetAimFlag(to); -#ifdef VC_PED_PORTS - SetLookTimer(INT32_MAX); -#endif + int fearFlags = m_fearFlags; + CVector ourPos = GetPosition(); + float closestPedDist = 60.0f; + CVector2D explosionPos = GetPosition(); + if (fearFlags & PED_FLAG_EXPLOSION && CheckForExplosions(explosionPos)) { + m_eventOrThreat = explosionPos; + return PED_FLAG_EXPLOSION; } - - if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) - return; - - if (m_nPedState != PED_ATTACK) - SetStoredState(); - - m_nPedState = PED_AIM_GUN; - bIsPointingGunAt = true; - CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - SetMoveState(PEDMOVE_NONE); - - CAnimBlendAssociation *aimAssoc; - - if (bCrouchWhenShooting) - aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_Anim2ToPlay); - else - aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_AnimToPlay); - - if (!aimAssoc || aimAssoc->blendDelta < 0.0f) { - if (bCrouchWhenShooting) - aimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f); - else - aimAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay); - - aimAssoc->blendAmount = 0.0f; - aimAssoc->blendDelta = 8.0f; - } - if (to) - Say(SOUND_PED_ATTACK); -} - -void -CPed::SetAmmo(eWeaponType weaponType, uint32 ammo) -{ - if (HasWeapon(weaponType)) { - GetWeapon(weaponType).m_nAmmoTotal = ammo; - } else { - GetWeapon(weaponType).Initialise(weaponType, ammo); - m_maxWeaponTypeAllowed++; - } -} - -void -CPed::GrantAmmo(eWeaponType weaponType, uint32 ammo) -{ - if (HasWeapon(weaponType)) { - GetWeapon(weaponType).m_nAmmoTotal += ammo; - } else { - GetWeapon(weaponType).Initialise(weaponType, ammo); - m_maxWeaponTypeAllowed++; - } -} - -void -CPed::SetEvasiveStep(CEntity *reason, uint8 animType) -{ - AnimationId stepAnim; - - if (m_nPedState == PED_STEP_AWAY || !IsPedInControl() || ((IsPlayer() || !bRespondsToThreats) && animType == 0)) - return; - - float angleToFace = CGeneral::GetRadianAngleBetweenPoints( - reason->GetPosition().x, reason->GetPosition().y, - GetPosition().x, GetPosition().y); - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - float neededTurn = Abs(angleToFace - m_fRotationCur); - bool vehPressedHorn = false; - - if (neededTurn > PI) - neededTurn = TWOPI - neededTurn; - - CVehicle *veh = (CVehicle*)reason; - if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR) { - if (veh->m_nCarHornTimer != 0) { - vehPressedHorn = true; - if (!IsPlayer()) - animType = 1; - } - } - if (neededTurn <= DEGTORAD(90.0f) || veh->GetModelIndex() == MI_RCBANDIT || vehPressedHorn || animType != 0) { - SetLookFlag(veh, true); - if ((CGeneral::GetRandomNumber() & 1) && veh->GetModelIndex() != MI_RCBANDIT && animType == 0) { - stepAnim = ANIM_IDLE_TAXI; - } else { - - float vehDirection = CGeneral::GetRadianAngleBetweenPoints( - veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, - 0.0f, 0.0f); - - // Let's turn our back to the "reason" - angleToFace += PI; - - if (angleToFace > PI) - angleToFace -= TWOPI; - - // We don't want to run towards car's direction - float dangerZone = angleToFace - vehDirection; - dangerZone = CGeneral::LimitRadianAngle(dangerZone); - - // So, add or subtract 90deg (jump to left/right) according to that - if (dangerZone > 0.0f) - angleToFace = vehDirection - HALFPI; - else - angleToFace = vehDirection + HALFPI; - - stepAnim = NUM_ANIMS; - if (animType == 0 || animType == 1) - stepAnim = ANIM_EV_STEP; - else if (animType == 2) - stepAnim = ANIM_HANDSCOWER; - } - if (!RpAnimBlendClumpGetAssociation(GetClump(), stepAnim)) { - CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, stepAnim, 8.0f); - stepAssoc->flags &= ~ASSOC_DELETEFADEDOUT; - stepAssoc->SetFinishCallback(PedEvadeCB, this); - - if (animType == 0) - Say(SOUND_PED_EVADE); - - m_fRotationCur = CGeneral::LimitRadianAngle(angleToFace); - ClearAimFlag(); - SetStoredState(); - m_nPedState = PED_STEP_AWAY; - } - } -} - -void -CPed::SetEvasiveDive(CPhysical *reason, uint8 onlyRandomJump) -{ - if (!IsPedInControl() || !bRespondsToThreats) - return; - - CAnimBlendAssociation *animAssoc; - float angleToFace, neededTurn; - bool handsUp = false; - - angleToFace = m_fRotationCur; - CVehicle *veh = (CVehicle*) reason; - if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR && veh->m_nCarHornTimer != 0 && !IsPlayer()) { - onlyRandomJump = true; - } - - if (onlyRandomJump) { - if (reason) { - // Simple version of my bug fix below. Doesn't calculate "danger zone", selects jump direction randomly. - // Also doesn't include random hands up, sound etc. Only used on player ped and peds running from gun shots. - - float vehDirection = CGeneral::GetRadianAngleBetweenPoints( - veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, - 0.0f, 0.0f); - angleToFace = (CGeneral::GetRandomNumber() & 1) * PI + (-0.5f*PI) + vehDirection; - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - } - } else { - if (IsPlayer()) { - ((CPlayerPed*)this)->m_nEvadeAmount = 5; - ((CPlayerPed*)this)->m_pEvadingFrom = reason; - reason->RegisterReference((CEntity**) &((CPlayerPed*)this)->m_pEvadingFrom); - return; - } - - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - reason->GetPosition().x, reason->GetPosition().y, - GetPosition().x, GetPosition().y); - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - - // FIX: Peds no more dive into cars. Taken from SetEvasiveStep, last if statement inverted -#ifdef FIX_BUGS - float vehDirection = CGeneral::GetRadianAngleBetweenPoints( - veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, - 0.0f, 0.0f); - - // Let's turn our back to the "reason" - angleToFace += PI; - - if (angleToFace > PI) - angleToFace -= 2 * PI; - - // We don't want to dive towards car's direction - float dangerZone = angleToFace - vehDirection; - dangerZone = CGeneral::LimitRadianAngle(dangerZone); - - // So, add or subtract 90deg (jump to left/right) according to that - if (dangerZone > 0.0f) - angleToFace = 0.5f * PI + vehDirection; - else - angleToFace = vehDirection - 0.5f * PI; -#endif - - neededTurn = Abs(angleToFace - m_fRotationCur); - - if (neededTurn > PI) - neededTurn = 2 * PI - neededTurn; - - if (neededTurn <= 0.5f*PI) { - if (CGeneral::GetRandomNumber() & 1) - handsUp = true; - } else { - if (CGeneral::GetRandomNumber() & 7) - return; - } - Say(SOUND_PED_EVADE); - } - - if (handsUp || !IsPlayer() && m_pedStats->m_flags & STAT_NO_DIVE) { - m_fRotationCur = angleToFace; - ClearLookFlag(); - ClearAimFlag(); - SetLookFlag(reason, true); - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSUP); - if (animAssoc) - return; - - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSUP, 8.0f); - animAssoc->flags &= ~ASSOC_DELETEFADEDOUT; - animAssoc->SetFinishCallback(PedEvadeCB, this); - SetStoredState(); - m_nPedState = PED_STEP_AWAY; - } else { - m_fRotationCur = angleToFace; - ClearLookFlag(); - ClearAimFlag(); - SetStoredState(); - m_nPedState = PED_DIVE_AWAY; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_EV_DIVE, 8.0f); - animAssoc->SetFinishCallback(PedEvadeCB, this); - } - - if (reason->IsVehicle() && m_nPedType == PEDTYPE_COP) { - if (veh->pDriver && veh->pDriver->IsPlayer()) { - CWanted *wanted = FindPlayerPed()->m_pWanted; - wanted->RegisterCrime_Immediately(CRIME_RECKLESS_DRIVING, GetPosition(), (uintptr)this, false); - wanted->RegisterCrime_Immediately(CRIME_SPEEDING, GetPosition(), (uintptr)this, false); - } - } -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - else if (reason->IsVehicle()) { - if (veh->pDriver && veh->pDriver->IsPlayer()) { - CWanted* wanted = FindPlayerPed()->m_pWanted; - wanted->RegisterCrime(CRIME_RECKLESS_DRIVING, GetPosition(), (uintptr)this, false); - } - } -#endif -} - -void -CPed::SetAttack(CEntity *victim) -{ - CPed *victimPed = nil; - if (victim && victim->IsPed()) - victimPed = (CPed*)victim; - - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); - if (animAssoc) { - animAssoc->blendDelta = -1000.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - - if (m_attackTimer > CTimer::GetTimeInMilliseconds() || m_nWaitState == WAITSTATE_SURPRISE) - return; - - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HGUN_RELOAD)) { - bIsAttacking = false; - return; - } - - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD)) { - if (!IsPlayer() || m_nPedState != PED_ATTACK || ((CPlayerPed*)this)->m_bHaveTargetSelected) - bIsAttacking = false; - else - bIsAttacking = true; - - return; - } - - CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - if (curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT && !IsPlayer()) { - if (GetWeapon()->HitsGround(this, nil, victim)) - return; - } - - if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { - if (IsPlayer() || - (m_nPedState != PED_FIGHT && m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL && !(m_pedStats->m_flags & STAT_SHOPPING_BAGS))) { - - if (m_nPedState != PED_ATTACK) { - m_nPedState = PED_ATTACK; - bIsAttacking = false; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, 8.0f); - animAssoc->SetRun(); - if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) - animAssoc->SetCurrentTime(0.0f); - - animAssoc->SetFinishCallback(FinishedAttackCB, this); - } - } else { - StartFightAttack(CGeneral::GetRandomNumber() % 256); - } - return; - } - - m_pSeekTarget = victim; - if (m_pSeekTarget) - m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - - if (curWeapon->m_bCanAim) { - CVector aimPos = GetRight() * 0.1f + GetForward() * 0.2f + GetPosition(); - CEntity *obstacle = CWorld::TestSphereAgainstWorld(aimPos, 0.2f, nil, true, false, false, true, false, false); - if (obstacle) - return; - - m_pLookTarget = victim; - if (victim) { - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - } - if (m_pLookTarget) { - SetAimFlag(m_pLookTarget); - } else { - SetAimFlag(m_fRotationCur); - - if (FindPlayerPed() == this && TheCamera.Cams[0].Using3rdPersonMouseCam()) - ((CPlayerPed*)this)->m_fFPSMoveHeading = TheCamera.Find3rdPersonQuickAimPitch(); - } - } - if (m_nPedState == PED_ATTACK) { - bIsAttacking = true; - return; - } - - if (IsPlayer() || !victimPed || victimPed->IsPedInControl()) { - if (IsPlayer()) - CPad::GetPad(0)->ResetAverageWeapon(); - - PointBlankNecessity pointBlankStatus; - if ((curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER) - && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON - && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON_RUNABOUT - && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER - && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER_RUNABOUT - && (pointBlankStatus = CheckForPointBlankPeds(victimPed)) != NO_POINT_BLANK_PED) { - ClearAimFlag(); - - // This condition is pointless - if (pointBlankStatus == POINT_BLANK_FOR_WANTED_PED || !victimPed) - StartFightAttack(200); - } else { - if (!curWeapon->m_bCanAim) - m_pSeekTarget = nil; - - if (m_nPedState != PED_AIM_GUN) - SetStoredState(); - - m_nPedState = PED_ATTACK; - SetMoveState(PEDMOVE_NONE); - if (bCrouchWhenShooting) { - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); - } else { - float animDelta = 8.0f; - if (curWeapon->m_eWeaponFire == WEAPON_FIRE_MELEE) - animDelta = 1000.0f; - - if (GetWeapon()->m_eWeaponType != WEAPONTYPE_BASEBALLBAT - || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, animDelta); - } else { - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, animDelta); - } - } - - animAssoc->SetRun(); - if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) - animAssoc->SetCurrentTime(0.0f); - - animAssoc->SetFinishCallback(FinishedAttackCB, this); - } - return; - } - - if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && victimPed->m_nPedState == PED_GETUP) - SetWaitState(WAITSTATE_SURPRISE, nil); - - SetLookFlag(victim, false); - SetLookTimer(100); -} - -void -CPed::StartFightAttack(uint8 buttonPressure) -{ - if (!IsPedInControl() || m_attackTimer > CTimer::GetTimeInMilliseconds()) - return; - - if (m_nPedState == PED_FIGHT) { - m_fightButtonPressure = buttonPressure; - return; - } - - if (m_nPedState != PED_AIM_GUN) - SetStoredState(); - - if (m_nWaitState != WAITSTATE_FALSE) { - m_nWaitState = WAITSTATE_FALSE; - RestoreHeadingRate(); - } - - m_nPedState = PED_FIGHT; - m_fightButtonPressure = 0; - RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT); - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START); - - if (animAssoc) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->blendDelta = -1000.0f; - } - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); - - if (animAssoc) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->blendDelta = -1000.0f; - RestoreHeadingRate(); - } - - SetMoveState(PEDMOVE_NONE); - m_nStoredMoveState = PEDMOVE_NONE; - - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f; - - CPed *pedOnGround = nil; - if (IsPlayer() && CheckForPedsOnGroundToAttack(this, &pedOnGround) > PED_IN_FRONT_OF_ATTACKER) { - m_curFightMove = FIGHTMOVE_GROUNDKICK; - } else if (m_pedStats->m_flags & STAT_SHOPPING_BAGS) { - m_curFightMove = FIGHTMOVE_ROUNDHOUSE; - } else { - m_curFightMove = FIGHTMOVE_STDPUNCH; - } - - if (pedOnGround && IsPlayer()) { - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - pedOnGround->GetPosition().x, pedOnGround->GetPosition().y, - GetPosition().x, GetPosition().y); - - m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); - m_fRotationCur = m_fRotationDest; - m_lookTimer = 0; - SetLookFlag(pedOnGround, true); - SetLookTimer(1500); - } - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); - animAssoc->SetFinishCallback(FinishFightMoveCB, this); - m_fightState = FIGHTSTATE_NO_MOVE; - m_takeAStepAfterAttack = false; - bIsAttacking = true; - - if (IsPlayer()) - nPlayerInComboMove = 0; -} - -void -CPed::LoadFightData(void) -{ - float startFireTime, endFireTime, comboFollowOnTime, strikeRadius; - int damage, flags; - char line[256], moveName[32], animName[32], hitLevel; - int moveId = 0; - - CAnimBlendAssociation *animAssoc; - - size_t bp, buflen; - int lp, linelen; - - buflen = CFileMgr::LoadFile("DATA\\fistfite.dat", work_buff, sizeof(work_buff), "r"); - - for (bp = 0; bp < buflen; ) { - // read file line by line - for (linelen = 0; work_buff[bp] != '\n' && bp < buflen; bp++) { - line[linelen++] = work_buff[bp]; - } - bp++; - line[linelen] = '\0'; - - // skip white space - for (lp = 0; line[lp] <= ' ' && line[lp] != '\0'; lp++); - - if (line[lp] == '\0' || - line[lp] == '#') - continue; - - sscanf( - &line[lp], - "%s %f %f %f %f %c %s %d %d", - moveName, - &startFireTime, - &endFireTime, - &comboFollowOnTime, - &strikeRadius, - &hitLevel, - animName, - &damage, - &flags); - - if (strncmp(moveName, "ENDWEAPONDATA", 13) == 0) - return; - - tFightMoves[moveId].startFireTime = startFireTime / 30.0f; - tFightMoves[moveId].endFireTime = endFireTime / 30.0f; - tFightMoves[moveId].comboFollowOnTime = comboFollowOnTime / 30.0f; - tFightMoves[moveId].strikeRadius = strikeRadius; - tFightMoves[moveId].damage = damage; - tFightMoves[moveId].flags = flags; - - switch (hitLevel) { - case 'G': - tFightMoves[moveId].hitLevel = HITLEVEL_GROUND; - break; - case 'H': - tFightMoves[moveId].hitLevel = HITLEVEL_HIGH; - break; - case 'L': - tFightMoves[moveId].hitLevel = HITLEVEL_LOW; - break; - case 'M': - tFightMoves[moveId].hitLevel = HITLEVEL_MEDIUM; - break; - case 'N': - tFightMoves[moveId].hitLevel = HITLEVEL_NULL; - break; - default: - break; - } - - if (strncmp(animName, "null", 4) != 0) { - animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animName); - tFightMoves[moveId].animId = (AnimationId)animAssoc->animId; - } else { - tFightMoves[moveId].animId = ANIM_WALK; - } - moveId++; - } -} - -// Actually GetLocalDirectionTo(Turn/Look) -int -CPed::GetLocalDirection(const CVector2D &posOffset) -{ - int direction; - float angle; - - for (angle = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); angle < 0.0f; angle += TWOPI); - - for (direction = RADTODEG(angle)/90.0f; direction > 3; direction -= 4); - - // 0-forward, 1-left, 2-backward, 3-right. - return direction; -} - -bool -CPed::FightStrike(CVector &touchedNodePos) -{ - CColModel *ourCol; - CVector attackDistance; - ePedPieceTypes closestPedPiece = PEDPIECE_TORSO; - float maxDistanceToBeBeaten; - CPed *nearPed; - int state = m_fightState; - bool pedFound = false; - - if (state == FIGHTSTATE_JUST_ATTACKED) - return false; - - // Pointless code - if (state > FIGHTSTATE_NO_MOVE) - attackDistance = touchedNodePos - m_vecHitLastPos; - - for (int i = 0; i < m_numNearPeds; i++) { - nearPed = m_nearPeds[i]; - if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) - maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_curFightMove].strikeRadius + 0.1f; - else - maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_curFightMove].strikeRadius; - - if (nearPed->bUsesCollision || nearPed->m_nPedState == PED_DEAD) { - CVector nearPedCentre; - nearPed->GetBoundCentre(nearPedCentre); - CVector potentialAttackDistance = nearPedCentre - touchedNodePos; - - // He can beat us - if (sq(maxDistanceToBeBeaten) > potentialAttackDistance.MagnitudeSqr()) { - -#ifdef PED_SKIN - // Have to animate a skinned clump because the initial col model is useless - if(IsClumpSkinned(GetClump())) - ourCol = ((CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()))->AnimatePedColModelSkinned(GetClump()); - else -#endif - if (nearPed->OnGround() || !nearPed->IsPedHeadAbovePos(-0.3f)) { - ourCol = &CTempColModels::ms_colModelPedGroundHit; - } else { -#ifdef ANIMATE_PED_COL_MODEL - ourCol = CPedModelInfo::AnimatePedColModel(((CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()))->GetHitColModel(), - RpClumpGetFrame(GetClump())); -#else - ourCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->GetHitColModel(); -#endif - } - - for (int j = 0; j < ourCol->numSpheres; j++) { - attackDistance = nearPed->GetPosition() + ourCol->spheres[j].center; - attackDistance -= touchedNodePos; - CColSphere *ourPieces = ourCol->spheres; - float maxDistanceToBeat = ourPieces[j].radius + tFightMoves[m_curFightMove].strikeRadius; - - // We can beat him too - if (sq(maxDistanceToBeat) > attackDistance.MagnitudeSqr()) { - pedFound = true; - closestPedPiece = (ePedPieceTypes) ourPieces[j].piece; - break; - } - } - } - } - if (pedFound) - break; - } - - if (pedFound) { - if (nearPed->IsPlayer() && nearPed->m_nPedState == PED_GETUP) - return false; - - float oldVictimHealth = nearPed->m_fHealth; - CVector bloodPos = 0.5f * attackDistance + touchedNodePos; - int damageMult = tFightMoves[m_curFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1; - - CVector2D diff (GetPosition() - nearPed->GetPosition()); - int direction = nearPed->GetLocalDirection(diff); - if (IsPlayer()) { - if (((CPlayerPed*)this)->m_bAdrenalineActive) - damageMult = 20; - } else { - damageMult *= m_pedStats->m_attackStrength; - } - - // Change direction if we used kick. - if (m_curFightMove == FIGHTMOVE_KICK) { - if (CGeneral::GetRandomNumber() & 1) { - direction++; - if (direction > 3) - direction -= 4; - } - } - nearPed->ReactToAttack(this); - - // Mostly unused. if > 5, ANIM_HIT_WALK will be run, that's it. - int unk2; - if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !nearPed->IsPlayer()) - unk2 = 101; - else - unk2 = damageMult; - - nearPed->StartFightDefend(direction, tFightMoves[m_curFightMove].hitLevel, unk2); - PlayHitSound(nearPed); - m_fightState = FIGHTSTATE_JUST_ATTACKED; - RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId)->speed = 0.6f; - if (!nearPed->DyingOrDead()) { - nearPed->InflictDamage(this, WEAPONTYPE_UNARMED, damageMult * 3.0f, closestPedPiece, direction); - } - - if (CGame::nastyGame - && tFightMoves[m_curFightMove].hitLevel > HITLEVEL_MEDIUM - && nearPed->m_nPedState == PED_DIE - && nearPed->GetIsOnScreen()) { - - // Just for blood particle. We will restore it below. - attackDistance /= (10.0f * attackDistance.Magnitude()); - for(int i=0; i<4; i++) { - CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, attackDistance, nil, 0.0f, 0, 0, 0, 0); - } - } - if (!nearPed->OnGround()) { - float curVictimHealth = nearPed->m_fHealth; - if (curVictimHealth > 0.0f - && (curVictimHealth < 40.0f && oldVictimHealth > 40.0f && !nearPed->IsPlayer() - || nearPed->m_fHealth < 20.0f && oldVictimHealth > 20.0f - || GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && IsPlayer() - || nearPed->m_pedStats->m_flags & STAT_ONE_HIT_KNOCKDOWN)) { - - nearPed->SetFall(0, (AnimationId)(direction + ANIM_KO_SKID_FRONT), 0); - if (nearPed->m_nPedState == PED_FALL) - nearPed->bIsStanding = false; - } - } - if (nearPed->m_nPedState == PED_DIE || !nearPed->bIsStanding) { - attackDistance = nearPed->GetPosition() - GetPosition(); - attackDistance.Normalise(); - attackDistance.z = 1.0f; - nearPed->bIsStanding = false; - - float moveMult; - if (m_curFightMove == FIGHTMOVE_GROUNDKICK) { - moveMult = Min(damageMult * 0.6f, 4.0f); - } else { - if (nearPed->m_nPedState != PED_DIE || damageMult >= 20) { - moveMult = damageMult; - } else { - moveMult = Min(damageMult * 2.0f, 14.0f); - } - } - - nearPed->ApplyMoveForce(moveMult * 0.6f * attackDistance); - } - CEventList::RegisterEvent(nearPed->m_nPedType == PEDTYPE_COP ? EVENT_ASSAULT_POLICE : EVENT_ASSAULT, EVENT_ENTITY_PED, nearPed, this, 2000); - } - - if (m_fightState == FIGHTSTATE_NO_MOVE) - m_fightState = FIGHTSTATE_1; - - m_vecHitLastPos = *touchedNodePos; - return false; -} - -void -CPed::SetFall(int extraTime, AnimationId animId, uint8 evenIfNotInControl) -{ - if (!IsPedInControl() && (!evenIfNotInControl || DyingOrDead())) - return; - - ClearLookFlag(); - ClearAimFlag(); - SetStoredState(); - m_nPedState = PED_FALL; - CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), animId); - if (fallAssoc) { - fallAssoc->SetCurrentTime(0.0f); - fallAssoc->blendAmount = 0.0f; - fallAssoc->blendDelta = 8.0f; - fallAssoc->SetRun(); - } else { - fallAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, 8.0f); - } - - if (extraTime == -1) { - m_getUpTimer = UINT32_MAX; - } else if (fallAssoc) { - if (IsPlayer()) { - m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength - + CTimer::GetTimeInMilliseconds() - + 500.0f; - } else { - m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength - + CTimer::GetTimeInMilliseconds() - + extraTime - + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000); + CPed *shooter = nil; + if ((fearFlags & PED_FLAG_GUN) && (shooter = CheckForGunShots()) && (m_nPedType != shooter->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE)) { + if (!IsGangMember()) { + m_threatEntity = shooter; + m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + return PED_FLAG_GUN; } - } else { - m_getUpTimer = extraTime - + CTimer::GetTimeInMilliseconds() - + 1000 - + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000); - } - bFallenDown = true; -} -void -CPed::SetFlee(CEntity *fleeFrom, int time) -{ - if (!IsPedInControl() || bKindaStayInSamePlace || !fleeFrom) - return; - - SetStoredState(); - m_nPedState = PED_FLEE_ENTITY; - bUsePedNodeSeek = true; - SetMoveState(PEDMOVE_RUN); - m_fleeFrom = fleeFrom; - m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); - - if (time <= 0) - m_fleeTimer = 0; - else - m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; - - float angleToFace = CGeneral::GetRadianAngleBetweenPoints( - GetPosition().x, GetPosition().y, - fleeFrom->GetPosition().x, fleeFrom->GetPosition().y); - - m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); - if (m_fRotationCur - PI > m_fRotationDest) { - m_fRotationDest += 2 * PI; - } else if (PI + m_fRotationCur < m_fRotationDest) { - m_fRotationDest -= 2 * PI; - } -} - -void -CPed::SetFlee(CVector2D const &from, int time) -{ - if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer || !IsPedInControl() || bKindaStayInSamePlace) - return; - - if (m_nPedState != PED_FLEE_ENTITY) { - SetStoredState(); - m_nPedState = PED_FLEE_POS; - SetMoveState(PEDMOVE_RUN); - m_fleeFromPosX = from.x; - m_fleeFromPosY = from.y; - } - - bUsePedNodeSeek = true; - m_pNextPathNode = nil; - m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; - - float angleToFace = CGeneral::GetRadianAngleBetweenPoints( - GetPosition().x, GetPosition().y, - from.x, from.y); - - m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); - if (m_fRotationCur - PI > m_fRotationDest) { - m_fRotationDest += 2 * PI; - } else if (PI + m_fRotationCur < m_fRotationDest) { - m_fRotationDest -= 2 * PI; - } -} - -void -CPed::SetWaitState(eWaitState state, void *time) -{ - AnimationId waitAnim = NUM_ANIMS; - CAnimBlendAssociation *animAssoc; - - if (!IsPedInControl()) - return; - - if (state != m_nWaitState) - FinishedWaitCB(nil, this); - - switch (state) { - case WAITSTATE_TRAFFIC_LIGHTS: - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500; - SetMoveState(PEDMOVE_STILL); - break; - case WAITSTATE_CROSS_ROAD: - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 1000; - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); - break; - case WAITSTATE_CROSS_ROAD_LOOK: - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 8.0f); - - if (time) - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; - else - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000,5000); - - break; - case WAITSTATE_LOOK_PED: - case WAITSTATE_LOOK_SHOP: - case WAITSTATE_LOOK_ACCIDENT: - case WAITSTATE_FACEOFF_GANG: - break; - case WAITSTATE_DOUBLEBACK: - m_headingRate = 0.0f; - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3500; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); -#ifdef FIX_BUGS - animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); -#endif - break; - case WAITSTATE_HITWALL: - m_headingRate = 2.0f; - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 16.0f); - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->flags |= ASSOC_FADEOUTWHENDONE; - animAssoc->SetDeleteCallback(FinishedWaitCB, this); - - if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { - ClearObjective(); - RestorePreviousState(); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; - } - break; - case WAITSTATE_TURN180: - m_headingRate = 0.0f; - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TURN_180, 4.0f); - animAssoc->SetFinishCallback(FinishedWaitCB, this); - animAssoc->SetDeleteCallback(RestoreHeadingRateCB, this); - break; - case WAITSTATE_SURPRISE: - m_headingRate = 0.0f; - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 4.0f); - animAssoc->SetFinishCallback(FinishedWaitCB, this); - break; - case WAITSTATE_STUCK: - SetMoveState(PEDMOVE_STILL); - SetMoveAnim(); - m_headingRate = 0.0f; - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f); -#ifdef FIX_BUGS - animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); -#endif - - if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { - ClearObjective(); - RestorePreviousState(); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; - } - break; - case WAITSTATE_LOOK_ABOUT: - SetMoveState(PEDMOVE_STILL); - SetMoveAnim(); - m_headingRate = 0.0f; - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); -#ifdef FIX_BUGS - animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); -#endif - - break; - case WAITSTATE_PLAYANIM_COWER: - waitAnim = ANIM_HANDSCOWER; - case WAITSTATE_PLAYANIM_HANDSUP: - if (waitAnim == NUM_ANIMS) - waitAnim = ANIM_HANDSUP; - case WAITSTATE_PLAYANIM_HANDSCOWER: - if (waitAnim == NUM_ANIMS) - waitAnim = ANIM_HANDSCOWER; - m_headingRate = 0.0f; - if (time) - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; - else - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; - - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 4.0f); - animAssoc->SetDeleteCallback(FinishedWaitCB, this); - break; - case WAITSTATE_PLAYANIM_DUCK: - waitAnim = ANIM_DUCK_DOWN; - case WAITSTATE_PLAYANIM_TAXI: - if (waitAnim == NUM_ANIMS) - waitAnim = ANIM_IDLE_TAXI; - case WAITSTATE_PLAYANIM_CHAT: - if (waitAnim == NUM_ANIMS) - waitAnim = ANIM_IDLE_CHAT; - if (time) - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; - else - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; - - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 4.0f); - animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc->SetDeleteCallback(FinishedWaitCB, this); - break; - case WAITSTATE_FINISH_FLEE: - SetMoveState(PEDMOVE_STILL); - SetMoveAnim(); - m_headingRate = 0.0f; - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2500; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f); -#ifdef FIX_BUGS - animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); -#endif - break; - default: - m_nWaitState = WAITSTATE_FALSE; - RestoreHeadingRate(); - return; - } - m_nWaitState = state; -} - - -void -CPed::PlayHitSound(CPed *hitTo) -{ - // That was very complicated to reverse for me... - // First index is our fight move ID (from 1 to 12, total 12), second is the one of we fight with (from 13 to 22, total 10). - enum { - S33 = SOUND_FIGHT_PUNCH_33, - S34 = SOUND_FIGHT_KICK_34, - S35 = SOUND_FIGHT_HEADBUTT_35, - S36 = SOUND_FIGHT_PUNCH_36, - S37 = SOUND_FIGHT_PUNCH_37, - S38 = SOUND_FIGHT_CLOSE_PUNCH_38, - S39 = SOUND_FIGHT_PUNCH_39, - S40 = SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 , - S41 = SOUND_FIGHT_PUNCH_41, - S42 = SOUND_FIGHT_PUNCH_FROM_BEHIND_42, - S43 = SOUND_FIGHT_KNEE_OR_KICK_43, - S44 = SOUND_FIGHT_KICK_44, - NO_SND = SOUND_NO_SOUND - }; - uint16 hitSoundsByFightMoves[12][10] = { - {S39,S42,S43,S43,S39,S39,S39,S39,S39,S42}, - {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND}, - {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND}, - {S39,S39,S39,S39,S33,S43,S39,S39,S39,S39}, - {S39,S39,S39,S39,S35,S39,S38,S38,S39,S39}, - {S39,S39,S39,S39,S33,S39,S41,S36,S39,S39}, - {S39,S39,S39,S39,S37,S40,S38,S38,S39,S39}, - {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39}, - {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39}, - {S39,S39,S39,S39,S34,S43,S44,S37,S39,S40}, - {S39,S39,S39,S39,S33,S39,S41,S37,S39,S40}, - {S39,S39,S39,S39,S39,S39,S39,S39,S33,S33} - }; - - // This is why first dimension is between FightMove 1 and 12. - if (m_curFightMove == FIGHTMOVE_NULL || m_curFightMove >= FIGHTMOVE_HITFRONT) - return; - - uint16 soundId; - - // And this is why second dimension is between 13 and 22. - if (hitTo->m_curFightMove > FIGHTMOVE_GROUNDKICK && hitTo->m_curFightMove < FIGHTMOVE_IDLE2NORM) { - soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][hitTo->m_curFightMove - FIGHTMOVE_HITFRONT]; - - } else { - if (hitTo->m_nPedState == PED_DEAD || hitTo->UseGroundColModel()) { - soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITONFLOOR - FIGHTMOVE_HITFRONT]; - } else { - soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITFRONT - FIGHTMOVE_HITFRONT]; + if (CPedType::GetFlag(shooter->m_nPedType) & fearFlags) { + m_threatEntity = shooter; + m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + return CPedType::GetFlag(shooter->m_nPedType); } } - if (soundId != NO_SND) - DMAudio.PlayOneShot(m_audioEntityId, soundId, 0.0f); -} + CPed *deadPed = nil; + if (fearFlags & PED_FLAG_DEADPEDS && CharCreatedBy != MISSION_CHAR + && (deadPed = CheckForDeadPeds()) != nil && (deadPed->GetPosition() - ourPos).MagnitudeSqr() < sq(20.0f)) { + m_pEventEntity = deadPed; + m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); + return PED_FLAG_DEADPEDS; + } else { + uint32 flagsOfSomePed = 0; -void -CPed::CollideWithPed(CPed *collideWith) -{ - CAnimBlendAssociation *animAssoc; - AnimationId animToPlay; + CPed *pedToFearFrom = nil; +#ifndef VC_PED_PORTS + for (int i = 0; i < m_numNearPeds; i++) { + if (CharCreatedBy != RANDOM_CHAR || m_nearPeds[i]->CharCreatedBy != MISSION_CHAR || m_nearPeds[i]->IsPlayer()) { + CPed *nearPed = m_nearPeds[i]; - bool weAreMissionChar = CharCreatedBy == MISSION_CHAR; - bool heIsMissionChar = collideWith->CharCreatedBy == MISSION_CHAR; - CVector posDiff = collideWith->GetPosition() - GetPosition(); - int waitTime = 0; + // BUG: WTF Rockstar?! Putting this here will result in returning the flags of farthest ped to us, since m_nearPeds is sorted by distance. + // Fixed at the bottom of the function. + flagsOfSomePed = CPedType::GetFlag(nearPed->m_nPedType); - if (weAreMissionChar || !collideWith->IsPlayer() || collideWith->m_nPedState != PED_MAKE_CALL) { - bool weDontLookToHim = DotProduct(posDiff, GetForward()) > 0.0f; - bool heLooksToUs = DotProduct(posDiff, collideWith->GetForward()) < 0.0f; + if (CPedType::GetFlag(nearPed->m_nPedType) & fearFlags) { + if (nearPed->m_fHealth > 0.0f && OurPedCanSeeThisOne(m_nearPeds[i])) { + // FIX: Taken from VC +#ifdef FIX_BUGS + float nearPedDistSqr = (nearPed->GetPosition() - ourPos).MagnitudeSqr2D(); +#else + float nearPedDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); +#endif + if (sq(closestPedDist) > nearPedDistSqr) { + closestPedDist = Sqrt(nearPedDistSqr); + pedToFearFrom = m_nearPeds[i]; + } + } + } + } + } +#else + bool weSawOurEnemy = false; + bool weMaySeeOurEnemy = false; + float closestEnemyDist = 60.0f; + if ((CTimer::GetFrameCounter() + (uint8)m_randomSeed + 16) & 4) { - if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { + for (int i = 0; i < m_numNearPeds; ++i) { + if (CharCreatedBy == RANDOM_CHAR && m_nearPeds[i]->CharCreatedBy == MISSION_CHAR && !m_nearPeds[i]->IsPlayer()) { + continue; + } - if ((!IsPlayer() || ((CPlayerPed*)this)->m_fMoveSpeed <= 1.8f) - && (IsPlayer() || heIsMissionChar && weAreMissionChar || m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT -#ifdef VC_PED_PORTS - || m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && m_pedInObjective == collideWith - || collideWith->m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && collideWith->m_pedInObjective == this -#endif - )) { + // BUG: Explained at the same occurence of this bug above. Fixed at the bottom of the function. + flagsOfSomePed = CPedType::GetFlag(m_nearPeds[i]->m_nPedType); - if (m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT) { + if (flagsOfSomePed & fearFlags) { + if (m_nearPeds[i]->m_fHealth > 0.0f) { - if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { + // VC also has ability to include objects to line of sight check here (via last bit of flagsL) + if (OurPedCanSeeThisOne(m_nearPeds[i])) { + if (m_nearPeds[i]->m_nPedState == PED_ATTACK) { + if (m_nearPeds[i]->m_pedInObjective == this) { - if (heIsMissionChar || !weAreMissionChar && collideWith->m_nMoveState != PEDMOVE_STILL) { - - if (weAreMissionChar && (m_nPedState == PED_SEEK_POS || m_nPedState == PED_SEEK_ENTITY)) { - - if (collideWith->m_nMoveState != PEDMOVE_STILL - && (!collideWith->IsPlayer() || collideWith->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled())) { - float seekPosDist = (GetPosition() - m_vecSeekPos).MagnitudeSqr2D(); - float heAndSeekPosDist = (collideWith->GetPosition() - m_vecSeekPos).MagnitudeSqr2D(); - - if (seekPosDist <= heAndSeekPosDist) { - waitTime = 1000; - collideWith->SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime); - collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime; - } else { - waitTime = 500; - SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime; + float enemyDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); + if (sq(closestEnemyDist) > enemyDistSqr) { + float enemyDist = Sqrt(enemyDistSqr); + weSawOurEnemy = true; + closestPedDist = enemyDist; + closestEnemyDist = enemyDist; + pedToFearFrom = m_nearPeds[i]; } - } else if (collideWith->m_nMoveState == PEDMOVE_STILL) { - SetDirectionToWalkAroundObject(collideWith); } } else { - if (weAreMissionChar || m_pedStats->m_fear <= 100 - collideWith->m_pedStats->m_temper - || (collideWith->IsPlayer() || collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL) && - (!collideWith->IsPlayer() || ((CPlayerPed*)collideWith)->m_fMoveSpeed <= 1.0f)) { - SetDirectionToWalkAroundObject(collideWith); - if (!weAreMissionChar) - Say(SOUND_PED_CHAT); - } else { - SetEvasiveStep(collideWith, 2); + float nearPedDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); + if (sq(closestPedDist) > nearPedDistSqr && !weSawOurEnemy) { + closestPedDist = Sqrt(nearPedDistSqr); + pedToFearFrom = m_nearPeds[i]; } } - } else { - if (m_pedStats->m_temper <= m_pedStats->m_fear - || GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED - || weAreMissionChar - || collideWith->m_nPedType == PEDTYPE_CIVFEMALE - || collideWith->m_nPedType == m_nPedType - || collideWith->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { - SetDirectionToWalkAroundObject(collideWith); - Say(SOUND_PED_CHAT); - } else { - TurnBody(); - SetAttack(collideWith); -#ifdef VC_PED_PORTS - m_fRotationCur = 0.3f + m_fRotationCur; - m_fRotationDest = m_fRotationCur; -#endif - } - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(250, 450); - } - } - } else { -#ifdef VC_PED_PORTS - if (m_pedInObjective && (collideWith == m_pedInObjective || collideWith->m_pedInObjective == m_pedInObjective) && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { -#else - if (m_pedInObjective && collideWith == m_pedInObjective && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { -#endif - if (heLooksToUs) { - SetEvasiveStep(collideWith, 1); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; - } - } else if (weDontLookToHim && IsPedInControl()) { + } else if (!weSawOurEnemy) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedState == PED_ATTACK) { + CColPoint foundCol; + CEntity *foundEnt; - if (m_pedStats != collideWith->m_pedStats) { + // We don't see him yet but he's behind a ped, vehicle or object + // VC also has ability to include objects to line of sight check here (via last bit of flagsL) + if (!CWorld::ProcessLineOfSight(ourPos, nearPed->GetPosition(), foundCol, foundEnt, + true, false, false, false, false, false, false)) { - if (collideWith->m_pedStats->m_fear <= 100 - m_pedStats->m_temper -#ifdef VC_PED_PORTS - || collideWith->IsPlayer() || CTimer::GetTimeInMilliseconds() < m_nPedStateTimer -#endif - ) { - - if (collideWith->IsPlayer()) { - // He's on our right side - if (DotProduct(posDiff,GetRight()) <= 0.0f) - m_fRotationCur -= m_headingRate; - else - m_fRotationCur += m_headingRate; - } else { - // He's on our right side - if (DotProduct(posDiff, collideWith->GetRight()) <= 0.0f) - collideWith->m_fRotationCur -= collideWith->m_headingRate; - else - collideWith->m_fRotationCur += collideWith->m_headingRate; - } - } else { - SetLookFlag(collideWith, false); - TurnBody(); - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f); - animAssoc->flags |= ASSOC_FADEOUTWHENDONE; -#ifdef VC_PED_PORTS - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000; -#endif - if (!heIsMissionChar) { - CVector2D posDiff2D(posDiff); - int direction = collideWith->GetLocalDirection(posDiff2D); - collideWith->StartFightDefend(direction, HITLEVEL_HIGH, 5); + if (nearPed->m_pedInObjective == this) { + float enemyDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); + if (sq(closestEnemyDist) > enemyDistSqr) { + float enemyDist = Sqrt(enemyDistSqr); + weMaySeeOurEnemy = true; + closestPedDist = enemyDist; + closestEnemyDist = enemyDist; + pedToFearFrom = m_nearPeds[i]; + } + } else if (!nearPed->GetWeapon()->IsTypeMelee() && !weMaySeeOurEnemy) { + float nearPedDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); + if (sq(closestPedDist) > nearPedDistSqr) { + weMaySeeOurEnemy = true; + closestPedDist = Sqrt(nearPedDistSqr); + pedToFearFrom = m_nearPeds[i]; + } + } } } } } } - } else if (collideWith->m_pedStats->m_defendWeakness <= 1.5f || heIsMissionChar -#ifdef VC_PED_PORTS - || m_pedStats->m_defendWeakness <= collideWith->m_pedStats->m_defendWeakness -#endif - ) { - // He looks us and we're not at his right side - if (heLooksToUs && DotProduct(posDiff,collideWith->GetRight()) > 0.0f) { - CVector moveForce = GetRight(); - moveForce.z += 0.1f; - ApplyMoveForce(moveForce); - if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) - animToPlay = ANIM_HIT_LEFT; - else - animToPlay = ANIM_SHOT_LEFT_PARTIAL; - } else if (heLooksToUs) { - CVector moveForce = GetRight() * -1.0f; - moveForce.z += 0.1f; - ApplyMoveForce(moveForce); - if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) - animToPlay = ANIM_HIT_RIGHT; - else - animToPlay = ANIM_SHOT_RIGHT_PARTIAL; - } else { - if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) - animToPlay = ANIM_HIT_BACK; - else - animToPlay = ANIM_SHOT_BACK_PARTIAL; - } - - if (collideWith->IsPedInControl() && CTimer::GetTimeInMilliseconds() > collideWith->m_nPedStateTimer) { - animAssoc = CAnimManager::BlendAnimation(collideWith->GetClump(), ASSOCGRP_STD, animToPlay, 8.0f); - animAssoc->flags |= ASSOC_FADEOUTWHENDONE; - collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 1000; - if (m_nPedState == PED_ATTACK) - DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); - } - } else { - // We're at his right side - if (DotProduct(posDiff, collideWith->GetRight()) <= 0.0f) { - CVector moveForce = GetRight() * -1.0f; - moveForce.z += 0.1f; - ApplyMoveForce(moveForce); - if (heLooksToUs) - animToPlay = ANIM_KO_SPIN_L; - else - animToPlay = ANIM_KD_RIGHT; - } else { - CVector moveForce = GetRight(); - moveForce.z += 0.1f; - ApplyMoveForce(moveForce); - if (heLooksToUs) - animToPlay = ANIM_KO_SPIN_R; - else - animToPlay = ANIM_KD_LEFT; - } - - if (m_nPedState == PED_ATTACK && collideWith->IsPedInControl()) - DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); - - collideWith->SetFall(3000, animToPlay, 0); - } - } else { - if (!IsPedInControl()) - return; - - if (collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL) - return; - - if (m_nPedType != collideWith->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) { - - if (!weAreMissionChar && heLooksToUs && m_pedStats->m_fear > 100 - collideWith->m_pedStats->m_temper) { - - if (CGeneral::GetRandomNumber() & 1 && CTimer::GetTimeInMilliseconds() < m_nPedStateTimer){ - SetEvasiveStep(collideWith, 2); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; - } else if (collideWith->m_nMoveState > PEDMOVE_WALK) { - waitTime = 2000; - SetWaitState(WAITSTATE_PLAYANIM_DUCK, &waitTime); - } - } - } else if (heLooksToUs - && collideWith->m_nPedState != PED_STEP_AWAY - && m_nPedState != PED_STEP_AWAY - && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { - - SetEvasiveStep(collideWith, 1); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; } } - - if (IsPlayer()) { - SetLookFlag(collideWith, true); - SetLookTimer(800); - } - } else { - bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; - SetFindPathAndFlee(collideWith, 5000, !isRunning); - } -} - -void -CPed::CreateDeadPedMoney(void) -{ - if (!CGame::nastyGame) - return; - - int mi = GetModelIndex(); - - if ((mi >= MI_COP && mi <= MI_FIREMAN) || CharCreatedBy == MISSION_CHAR || bInVehicle) - return; - - int money = CGeneral::GetRandomNumber() % 60; - if (money < 10) - return; - - if (money == 43) - money = 700; - - int pickupCount = money / 40 + 1; - int moneyPerPickup = money / pickupCount; - - for(int i = 0; i < pickupCount; i++) { - // (CGeneral::GetRandomNumber() % 256) * PI / 128 gives a float up to something TWOPI-ish. - float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().x; - float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256) * PI / 128) + GetPosition().y; - bool found = false; - float groundZ = CWorld::FindGroundZFor3DCoord(pickupX, pickupY, GetPosition().z, &found) + 0.5f; - if (found) { - CPickups::GenerateNewOne(CVector(pickupX, pickupY, groundZ), MI_MONEY, PICKUP_MONEY, moneyPerPickup + (CGeneral::GetRandomNumber() & 7)); - } - } -} - -void -CPed::CreateDeadPedWeaponPickups(void) -{ - bool found = false; - float angleToPed; - CVector pickupPos; - - if (bInVehicle) - return; - - for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { - - eWeaponType weapon = GetWeapon(i).m_eWeaponType; - int weaponAmmo = GetWeapon(i).m_nAmmoTotal; - if (weapon == WEAPONTYPE_UNARMED || weapon == WEAPONTYPE_DETONATOR || weaponAmmo == 0) - continue; - - angleToPed = i * 1.75f; - pickupPos = GetPosition(); - pickupPos.x += 1.5f * Sin(angleToPed); - pickupPos.y += 1.5f * Cos(angleToPed); - pickupPos.z = CWorld::FindGroundZFor3DCoord(pickupPos.x, pickupPos.y, pickupPos.z, &found) + 0.5f; - - CVector pedPos = GetPosition(); - pedPos.z += 0.3f; - - CVector pedToPickup = pickupPos - pedPos; - float distance = pedToPickup.Magnitude(); - - // outer edge of pickup - distance = (distance + 0.3f) / distance; - CVector pickupPos2 = pedPos; - pickupPos2 += distance * pedToPickup; - - // pickup must be on ground and line to its edge must be clear - if (!found || CWorld::GetIsLineOfSightClear(pickupPos2, pedPos, true, false, false, false, false, false, false)) { - // otherwise try another position (but disregard second check apparently) - angleToPed += 3.14f; - pickupPos = GetPosition(); - pickupPos.x += 1.5f * Sin(angleToPed); - pickupPos.y += 1.5f * Cos(angleToPed); - pickupPos.z = CWorld::FindGroundZFor3DCoord(pickupPos.x, pickupPos.y, pickupPos.z, &found) + 0.5f; - } - if (found) - CPickups::GenerateNewOne_WeaponType(pickupPos, weapon, PICKUP_ONCE_TIMEOUT, Min(weaponAmmo, AmmoForWeapon_OnStreet[weapon])); - } - ClearWeapons(); -} - -void -CPed::SetAttackTimer(uint32 time) -{ - if (CTimer::GetTimeInMilliseconds() > m_attackTimer) - m_attackTimer = Max(m_shootTimer, CTimer::GetTimeInMilliseconds()) + time; -} - -void -CPed::SetBeingDraggedFromCar(CVehicle *veh, uint32 vehEnterType, bool quickJack) -{ - if (m_nPedState == PED_DRAG_FROM_CAR) - return; - - bUsesCollision = false; - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - m_nLastPedState = PED_IDLE; - SetMoveState(PEDMOVE_STILL); - m_pSeekTarget = veh; - m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - m_vehEnterType = vehEnterType; - if (m_vehEnterType == CAR_DOOR_LF) { - if (veh->pDriver && veh->pDriver->IsPlayer()) - veh->SetStatus(STATUS_PLAYER_DISABLED); - else - veh->SetStatus(STATUS_ABANDONED); - } - RemoveInCarAnims(); - SetMoveState(PEDMOVE_NONE); - LineUpPedWithCar(LINE_UP_TO_CAR_START); - m_pVehicleAnim = nil; - m_nPedState = PED_DRAG_FROM_CAR; - bChangedSeat = false; - bWillBeQuickJacked = quickJack; - - SetHeading(m_fRotationCur); - - Say(SOUND_PED_CAR_JACKED); - SetRadioStation(); - veh->m_nGettingOutFlags |= GetCarDoorFlag(m_vehEnterType); -} - -void -CPed::SetBuyIceCream(void) -{ - if (m_nPedState == PED_BUY_ICECREAM || !IsPedInControl()) - return; - - if (!m_carInObjective) - return; - -#ifdef FIX_ICECREAM - - // Simulating BuyIceCream - CPed* driver = m_carInObjective->pDriver; - if (driver) { - m_nPedState = PED_BUY_ICECREAM; - bFindNewNodeAfterStateRestore = true; - SetObjectiveTimer(8000); - SetChat(driver, 8000); - driver->SetChat(this, 8000); - return; - } #endif - - // Side of the Ice Cream van - m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; - - if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 3000; - m_nPedState = PED_BUY_ICECREAM; - } -} - -void -CPed::SetChat(CEntity *chatWith, uint32 time) -{ - if(m_nPedState != PED_CHAT) - SetStoredState(); - - m_nPedState = PED_CHAT; - SetMoveState(PEDMOVE_STILL); -#if defined VC_PED_PORTS || defined FIX_BUGS - m_lookTimer = 0; -#endif - SetLookFlag(chatWith, true); - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; - m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; -} - -void -CPed::SetDead(void) -{ - bUsesCollision = false; - - m_fHealth = 0.0f; - if (m_nPedState == PED_DRIVING) - bIsVisible = false; - - m_nPedState = PED_DEAD; - m_pVehicleAnim = nil; - m_pCollidingEntity = nil; - - CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(weapon->m_nModelId); - - m_currentWeapon = WEAPONTYPE_UNARMED; - CEventList::RegisterEvent(EVENT_INJURED_PED, EVENT_ENTITY_PED, this, nil, 250); - if (this != FindPlayerPed()) { - CreateDeadPedWeaponPickups(); - CreateDeadPedMoney(); - } - - m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); - m_deadBleeding = false; - bDoBloodyFootprints = false; - bVehExitWillBeInstant = false; - CEventList::RegisterEvent(EVENT_DEAD_PED, EVENT_ENTITY_PED, this, nil, 1000); -} - -void -CPed::SetSeek(CEntity *seeking, float distanceToCountDone) -{ - if (!IsPedInControl()) - return; - - if (m_nPedState == PED_SEEK_ENTITY && m_pSeekTarget == seeking) - return; - - if (!seeking) - return; - - if (m_nPedState != PED_SEEK_ENTITY) - SetStoredState(); - - m_nPedState = PED_SEEK_ENTITY; - m_distanceToCountSeekDone = distanceToCountDone; - m_pSeekTarget = seeking; - m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - SetMoveState(PEDMOVE_STILL); -} - -void -CPed::SetSeek(CVector pos, float distanceToCountDone) -{ - if (!IsPedInControl() - || (m_nPedState == PED_SEEK_POS && m_vecSeekPos.x == pos.x && m_vecSeekPos.y == pos.y)) - return; - - if (GetWeapon()->m_eWeaponType == WEAPONTYPE_M16 - || GetWeapon()->m_eWeaponType == WEAPONTYPE_AK47 - || GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE - || GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER - || GetWeapon()->m_eWeaponType == WEAPONTYPE_SHOTGUN) { - ClearPointGunAt(); - } - - if (m_nPedState != PED_SEEK_POS) - SetStoredState(); - - m_nPedState = PED_SEEK_POS; - m_distanceToCountSeekDone = distanceToCountDone; - m_vecSeekPos = pos; -} - -void -CPed::DeadPedMakesTyresBloody(void) -{ - int minX = CWorld::GetSectorIndexX(GetPosition().x - 2.0f); - if (minX < 0) minX = 0; - int minY = CWorld::GetSectorIndexY(GetPosition().y - 2.0f); - if (minY < 0) minY = 0; - int maxX = CWorld::GetSectorIndexX(GetPosition().x + 2.0f); - if (maxX > NUMSECTORS_X-1) maxX = NUMSECTORS_X-1; - int maxY = CWorld::GetSectorIndexY(GetPosition().y + 2.0f); - if (maxY > NUMSECTORS_Y-1) maxY = NUMSECTORS_Y-1; - - CWorld::AdvanceCurrentScanCode(); - - for (int curY = minY; curY <= maxY; curY++) { - for (int curX = minX; curX <= maxX; curX++) { - CSector *sector = CWorld::GetSector(curX, curY); - MakeTyresMuddySectorList(sector->m_lists[ENTITYLIST_VEHICLES]); - MakeTyresMuddySectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP]); - } - } -} - -void -CPed::Die(void) -{ - // UNUSED: This is a perfectly empty function. -} - -uint8 -CPed::DoesLOSBulletHitPed(CColPoint &colPoint) -{ -#ifdef FIX_BUGS - return 1; -#else - uint8 retVal = 2; - - float headZ = GetNodePosition(PED_HEAD).z; - - if (m_nPedState == PED_FALL) - retVal = 1; - - float colZ = colPoint.point.z; - if (colZ < headZ) - retVal = 1; - - if (headZ + 0.2f <= colZ) - retVal = 0; - - return retVal; -#endif -} - -bool -CPed::DuckAndCover(void) -{ - if (!m_pedInObjective || CTimer::GetTimeInMilliseconds() <= m_duckAndCoverTimer) - return false; - - if (bKindaStayInSamePlace){ - - if (CTimer::GetTimeInMilliseconds() <= m_leaveCarTimer) { - if (!m_pLookTarget || m_pLookTarget != m_pedInObjective) { - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - } - if (!bIsAimingGun) - SetAimFlag(m_pedInObjective); - - } else { - bCrouchWhenShooting = false; - bKindaStayInSamePlace = false; - bIsDucking = false; - bDuckAndCover = false; - m_headingRate = 10.0f; - m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(20000,30000); - if (m_pSeekTarget && m_pSeekTarget->IsVehicle()) - ((CVehicle*)m_pSeekTarget)->m_numPedsUseItAsCover--; - } - return false; - } - - bool justDucked = false; - CVehicle *foundVeh = nil; - float maxDist = 225.0f; - bIsDucking = false; - bCrouchWhenShooting = false; - if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - CVector pos = GetPosition(); int16 lastVehicle; - CEntity *vehicles[8]; - CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(ourPos, 20.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + CVehicle* foundVeh = nil; for (int i = 0; i < lastVehicle; i++) { - CVehicle *veh = (CVehicle*) vehicles[i]; - if (veh->m_vecMoveSpeed.Magnitude() <= 0.02f - && !veh->bIsBus - && !veh->bIsVan - && !veh->bIsBig - && veh->m_numPedsUseItAsCover < 3) { - float dist = (GetPosition() - veh->GetPosition()).MagnitudeSqr(); - if (dist < maxDist) { - maxDist = dist; - foundVeh = veh; - } - } - } - if (foundVeh) { - // Unused. - // CVector lfWheelPos, rfWheelPos; - // foundVeh->GetComponentWorldPosition(CAR_WHEEL_RF, rfWheelPos); - // foundVeh->GetComponentWorldPosition(CAR_WHEEL_LF, lfWheelPos); - CVector rightSide, leftSide; + CVehicle* nearVeh = (CVehicle*)vehicles[i]; - // 3 persons can use the car as cover. Found the correct position for us. - if (foundVeh->m_numPedsUseItAsCover == 2) { - rightSide = CVector(1.5f, -0.5f, 0.0f); - leftSide = CVector(-1.5f, -0.5f, 0.0f); - } else if (foundVeh->m_numPedsUseItAsCover == 1) { - rightSide = CVector(1.5f, 0.5f, 0.0f); - leftSide = CVector(-1.5f, 0.5f, 0.0f); - } else if (foundVeh->m_numPedsUseItAsCover == 0) { - rightSide = CVector(1.5f, 0.0f, 0.0f); - leftSide = CVector(-1.5f, 0.0f, 0.0f); - } + CPed *driver = nearVeh->pDriver; + if (driver) { - CMatrix vehMatrix(foundVeh->GetMatrix()); - CVector duckAtRightSide = Multiply3x3(vehMatrix, rightSide) + foundVeh->GetPosition(); - - CVector duckAtLeftSide = Multiply3x3(vehMatrix, leftSide) + foundVeh->GetPosition(); - - CVector distWithPedRightSide = m_pedInObjective->GetPosition() - duckAtRightSide; - CVector distWithPedLeftSide = m_pedInObjective->GetPosition() - duckAtLeftSide; - - CVector duckPos; - if (distWithPedRightSide.MagnitudeSqr() <= distWithPedLeftSide.MagnitudeSqr()) - duckPos = duckAtLeftSide; - else - duckPos = duckAtRightSide; - - if (CWorld::TestSphereAgainstWorld(duckPos, 0.5f, nil, true, true, true, false, false, false) - && CWorld::GetIsLineOfSightClear(GetPosition(), duckPos, 1, 0, 0, 1, 0, 0, 0)) { - SetSeek(duckPos, 1.0f); - m_headingRate = 15.0f; - bIsRunning = true; - bDuckAndCover = true; - justDucked = true; - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 500; - if (foundVeh->bIsLawEnforcer) - m_carInObjective = foundVeh; - - // BUG? Shouldn't we register the reference? - m_pSeekTarget = foundVeh; - ClearPointGunAt(); - } else { - m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(10000, 15000); - bDuckAndCover = false; - } - } else { - bDuckAndCover = false; - } - } - - if (!justDucked && !bDuckAndCover) - return false; - - if (!Seek()) - return true; - - bKindaStayInSamePlace = true; - bDuckAndCover = false; - m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); - if (m_pSeekTarget && m_pSeekTarget->IsVehicle()) - ((CVehicle*)m_pSeekTarget)->m_numPedsUseItAsCover++; - - SetIdle(); - SetMoveState(PEDMOVE_STILL); - SetMoveAnim(); - if (!m_pLookTarget || m_pLookTarget != m_pedInObjective) { - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - } - - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(3000, 6000); - return false; -} - -void -CPed::EndFight(uint8 endType) -{ - if (m_nPedState != PED_FIGHT) - return; - - m_curFightMove = FIGHTMOVE_NULL; - RestorePreviousState(); - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); - if (animAssoc) - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - - switch (endType) { - case ENDFIGHT_NORMAL: - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 8.0f); - break; - case ENDFIGHT_WITH_A_STEP: - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 1.0f); - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_WALK_START, 8.0f); - break; - case ENDFIGHT_FAST: - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 8.0f)->speed = 2.0f; - break; - default: - break; - } - m_nWaitTimer = 0; -} - -void -CPed::EnterCar(void) -{ - if (IsNotInWreckedVehicle() && m_fHealth > 0.0f) { - CVehicle *veh = (CVehicle*)m_pSeekTarget; - - // Not used. - // CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehEnterType); - - if (veh->CanPedOpenLocks(this)) { - if (m_vehEnterType && m_pVehicleAnim) { - veh->ProcessOpenDoor(m_vehEnterType, m_pVehicleAnim->animId, m_pVehicleAnim->currentTime); - } - } - bIsInTheAir = false; - LineUpPedWithCar(LINE_UP_TO_CAR_START); - } else { - QuitEnteringCar(); - SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - } -} - -uint8 -CPed::GetNearestTrainPedPosition(CVehicle *train, CVector &enterPos) -{ - CVector enterStepOffset; - CVehicleModelInfo *trainModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(train->GetModelIndex()); - CMatrix trainMat = CMatrix(train->GetMatrix()); - CVector leftEntryPos, rightEntryPos, midEntryPos; - float distLeftEntry, distRightEntry, distMidEntry; - - // enterStepOffset = vecPedCarDoorAnimOffset; - enterStepOffset = CVector(1.5f, 0.0f, 0.0f); - - if (train->pPassengers[TRAIN_POS_LEFT_ENTRY]) { - distLeftEntry = 999.0f; - } else { - leftEntryPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterStepOffset; - leftEntryPos = Multiply3x3(trainMat, leftEntryPos); - leftEntryPos += train->GetPosition(); - distLeftEntry = (leftEntryPos - GetPosition()).Magnitude(); - } - - if (train->pPassengers[TRAIN_POS_MID_ENTRY]) { - distMidEntry = 999.0f; - } else { - midEntryPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterStepOffset; - midEntryPos = Multiply3x3(trainMat, midEntryPos); - midEntryPos += train->GetPosition(); - distMidEntry = (midEntryPos - GetPosition()).Magnitude(); - } - - if (train->pPassengers[TRAIN_POS_RIGHT_ENTRY]) { - distRightEntry = 999.0f; - } else { - rightEntryPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterStepOffset; - rightEntryPos = Multiply3x3(trainMat, rightEntryPos); - rightEntryPos += train->GetPosition(); - distRightEntry = (rightEntryPos - GetPosition()).Magnitude(); - } - - if (distMidEntry < distLeftEntry) { - if (distMidEntry < distRightEntry) { - enterPos = midEntryPos; - m_vehEnterType = TRAIN_POS_MID_ENTRY; - } else { - enterPos = rightEntryPos; - m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; - } - } else if (distRightEntry < distLeftEntry) { - enterPos = rightEntryPos; - m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; - } else { - enterPos = leftEntryPos; - m_vehEnterType = TRAIN_POS_LEFT_ENTRY; - } - - return 1; -} - -uint8 -CPed::GetNearestTrainDoor(CVehicle *train, CVector &doorPos) -{ - GetNearestTrainPedPosition(train, doorPos); -/* - // Not used. - CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(train->m_modelIndex); - CMatrix trainMat = CMatrix(train->GetMatrix()); - - doorPos = trainModel->m_positions[m_vehEnterType]; - doorPos.x -= 1.5f; - doorPos = Multiply3x3(trainMat, doorPos); - doorPos += train->GetPosition(); -*/ - return 1; -} - -void -CPed::LineUpPedWithTrain(void) -{ - CVector lineUpPos; - CVehicleModelInfo *trainModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(m_pMyVehicle->GetModelIndex()); - CVector enterOffset(1.5f, 0.0f, -0.2f); - - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI; - m_fRotationDest = m_fRotationCur; - - if (!bInVehicle) { - GetNearestTrainDoor(m_pMyVehicle, lineUpPos); - lineUpPos.z += 0.2f; - } else { - if (m_pMyVehicle->pPassengers[TRAIN_POS_LEFT_ENTRY] == this) { - - lineUpPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterOffset; - - } else if (m_pMyVehicle->pPassengers[TRAIN_POS_MID_ENTRY] == this) { - - lineUpPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterOffset; - - } else if (m_pMyVehicle->pPassengers[TRAIN_POS_RIGHT_ENTRY] == this) { - - lineUpPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterOffset; - } - lineUpPos = Multiply3x3(m_pMyVehicle->GetMatrix(), lineUpPos); - lineUpPos += m_pMyVehicle->GetPosition(); - } - - if (m_pVehicleAnim) { - float percentageLeft = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; - lineUpPos += (GetPosition() - lineUpPos) * percentageLeft; - } - - SetPosition(lineUpPos); - SetHeading(m_fRotationCur); -} - -void -CPed::EnterTrain(void) -{ - LineUpPedWithTrain(); -} - -void -CPed::ExitTrain(void) -{ - LineUpPedWithTrain(); -} - -void -CPed::ExitCar(void) -{ - if (!m_pVehicleAnim) - return; - - AnimationId exitAnim = (AnimationId) m_pVehicleAnim->animId; - float animTime = m_pVehicleAnim->currentTime; - - m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, exitAnim, animTime); - - if (m_pSeekTarget) { - // Car is upside down - if (m_pMyVehicle->GetUp().z > -0.8f) { - if (exitAnim == ANIM_CAR_CLOSE_RHS || exitAnim == ANIM_CAR_CLOSE_LHS || animTime > 0.3f) - LineUpPedWithCar(LINE_UP_TO_CAR_END); - else - LineUpPedWithCar((m_pMyVehicle->GetModelIndex() == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START)); - } else { - LineUpPedWithCar(LINE_UP_TO_CAR_END); - } - } - - // If there is someone in front of the door, make him fall while we exit. - if (m_nPedState == PED_EXIT_CAR) { - CPed *foundPed = nil; - for (int i = 0; i < m_numNearPeds; i++) { - if ((m_nearPeds[i]->GetPosition() - GetPosition()).MagnitudeSqr2D() < 0.04f) { - foundPed = m_nearPeds[i]; - break; - } - } - if (foundPed && animTime > 0.4f && foundPed->IsPedInControl()) - foundPed->SetFall(1000, ANIM_KO_SKID_FRONT, 1); - } -} - -void -CPed::Fall(void) -{ - if (m_getUpTimer != UINT32_MAX && CTimer::GetTimeInMilliseconds() > m_getUpTimer -#ifdef VC_PED_PORTS - && bIsStanding -#endif - ) - ClearFall(); - - // VC plays animations ANIM_STD_FALL_ONBACK and ANIM_STD_FALL_ONFRONT in here, which doesn't exist in III. -} - -void -CPed::Fight(void) -{ - CAnimBlendAssociation *currentAssoc, *animAssoc; - bool hasShoppingBags, punchOnly, canKick, canKneeHead, canRoundhouse; - float angleToFace, nextAngle; - bool goForward = false; - int nextFightMove; - - switch (m_curFightMove) { - case FIGHTMOVE_NULL: - return; - case FIGHTMOVE_IDLE2NORM: - m_curFightMove = FIGHTMOVE_NULL; - RestorePreviousState(); - - // FIX: Uninitialized - currentAssoc = nil; - break; - case FIGHTMOVE_IDLE: - currentAssoc = nil; - break; - default: - currentAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId); - break; - } - - if (!bIsAttacking && IsPlayer()) { - if (currentAssoc) { - currentAssoc->blendDelta = -1000.0f; - currentAssoc->flags |= ASSOC_DELETEFADEDOUT; - currentAssoc->flags &= ~ASSOC_RUNNING; - } - if (m_takeAStepAfterAttack) - EndFight(ENDFIGHT_WITH_A_STEP); - else - EndFight(ENDFIGHT_FAST); - - } else if (currentAssoc && m_fightState > FIGHTSTATE_MOVE_FINISHED) { - float animTime = currentAssoc->currentTime; - FightMove &curMove = tFightMoves[m_curFightMove]; - if (curMove.hitLevel != HITLEVEL_NULL && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightState >= FIGHTSTATE_NO_MOVE) { - - CVector touchingNodePos(0.0f, 0.0f, 0.0f); - - switch (m_curFightMove) { - case FIGHTMOVE_STDPUNCH: - case FIGHTMOVE_PUNCHHOOK: - case FIGHTMOVE_BODYBLOW: - TransformToNode(touchingNodePos, PED_HANDR); - break; - case FIGHTMOVE_IDLE: - case FIGHTMOVE_SHUFFLE_F: - break; - case FIGHTMOVE_KNEE: - TransformToNode(touchingNodePos, PED_LOWERLEGR); - break; - case FIGHTMOVE_HEADBUTT: - TransformToNode(touchingNodePos, PED_HEAD); - break; - case FIGHTMOVE_PUNCHJAB: - TransformToNode(touchingNodePos, PED_HANDL); - break; - case FIGHTMOVE_KICK: - case FIGHTMOVE_LONGKICK: - case FIGHTMOVE_ROUNDHOUSE: - case FIGHTMOVE_GROUNDKICK: - TransformToNode(touchingNodePos, PED_FOOTR); - break; - } - - if (m_curFightMove == FIGHTMOVE_PUNCHJAB) { - touchingNodePos += 0.1f * GetForward(); - } else if (m_curFightMove == FIGHTMOVE_PUNCHHOOK) { - touchingNodePos += 0.22f * GetForward(); - } - FightStrike(touchingNodePos); - m_fightButtonPressure = 0; - return; - } - - if (curMove.hitLevel != HITLEVEL_NULL) { - if (animTime > curMove.endFireTime) { - if (IsPlayer()) - currentAssoc->speed = 1.0f; - else - currentAssoc->speed = 0.8f; - } - - if (IsPlayer() && !nPlayerInComboMove) { - if (curMove.comboFollowOnTime > 0.0f && m_fightButtonPressure != 0 && animTime > curMove.comboFollowOnTime) { - - // Notice that it increases fight move index, because we're in combo! - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[++m_curFightMove].animId, 8.0f); - animAssoc->SetFinishCallback(FinishFightMoveCB, this); - animAssoc->SetCurrentTime(0.1f * animAssoc->hierarchy->totalLength); - m_fightButtonPressure = 0; - nPlayerInComboMove = 1; - } - } - } else { - if (curMove.startFireTime > 0.0f && m_curFightMove != FIGHTMOVE_SHUFFLE_F && animTime > curMove.startFireTime) { - if (IsPlayer()) - currentAssoc->speed = 1.3f; - else - currentAssoc->speed = 0.8f; - } - } - } else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { - EndFight(ENDFIGHT_FAST); - - } else if (m_fightButtonPressure != 0) { - bool canAffectMultiplePeople = true; - nextAngle = m_fRotationCur; - bool kickGround = false; - float angleForGroundKick = 0.0f; - CPed *pedOnGround = nil; - - Say(SOUND_PED_ATTACK); - - if (IsPlayer()) { - canRoundhouse = false; - punchOnly = false; - canKick = true; - nextFightMove = (m_fightButtonPressure > 190 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE); - hasShoppingBags = false; - canKneeHead = true; - nPlayerInComboMove = 0; - } else { - nextFightMove = (m_fightButtonPressure > 120 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE); - uint16 pedFeatures = m_pedStats->m_flags; - punchOnly = pedFeatures & STAT_PUNCH_ONLY; - canRoundhouse = pedFeatures & STAT_CAN_ROUNDHOUSE; - canKneeHead = pedFeatures & STAT_CAN_KNEE_HEAD; - canKick = pedFeatures & STAT_CAN_KICK; - hasShoppingBags = pedFeatures & STAT_SHOPPING_BAGS; - } - - // Attack isn't scripted, find the victim - if (IsPlayer() || !m_pedInObjective) { - - for (int i = 0; i < m_numNearPeds; i++) { - - CPed *nearPed = m_nearPeds[i]; - float nearPedDist = (nearPed->GetPosition() - GetPosition()).Magnitude(); - if (nearPedDist < 3.0f) { - float angleToFace = CGeneral::GetRadianAngleBetweenPoints( - nearPed->GetPosition().x, nearPed->GetPosition().y, - GetPosition().x, GetPosition().y); - - nextAngle = CGeneral::LimitRadianAngle(angleToFace); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - - float neededTurn = Abs(nextAngle - m_fRotationCur); - if (neededTurn > PI) - neededTurn = TWOPI - neededTurn; - - if (!nearPed->OnGroundOrGettingUp()) { - - if (nearPedDist < 0.8f && neededTurn < DEGTORAD(75.0f) && canKneeHead) { - canAffectMultiplePeople = false; - } else if (nearPedDist >= 1.3f || neededTurn >= DEGTORAD(55.0f) || hasShoppingBags) { - - if (nearPedDist < 1.7f - && neededTurn < DEGTORAD(35.0f) - && (canKick || hasShoppingBags)) { - - nextFightMove = FIGHTMOVE_KICK; - if (hasShoppingBags) { - nextFightMove = FIGHTMOVE_ROUNDHOUSE; - } else if (canRoundhouse && CGeneral::GetRandomNumber() & 1) { - nextFightMove = FIGHTMOVE_ROUNDHOUSE; - } - canAffectMultiplePeople = false; - } else if (nearPedDist < 2.0f && neededTurn < DEGTORAD(30.0f) && canKick) { - canAffectMultiplePeople = false; - nextFightMove = FIGHTMOVE_LONGKICK; - } else if (neededTurn < DEGTORAD(30.0f)) { - goForward = true; - } - } else { - nextFightMove += 2; // Makes it 6 or 7 - if (punchOnly) - nextFightMove = FIGHTMOVE_PUNCHJAB; - - canAffectMultiplePeople = false; - } - } else if (!CGame::nastyGame - || nearPedDist >= 1.3f - || neededTurn >= DEGTORAD(55.0f) - || punchOnly) { - - if (nearPedDist > 0.8f - && nearPedDist < 3.0f - && neededTurn < DEGTORAD(30.0f)) { - goForward = true; - } - - } else if (nearPed->m_nPedState != PED_DEAD || pedOnGround) { - if (!nearPed->IsPedHeadAbovePos(-0.3f)) { - canAffectMultiplePeople = false; - nextFightMove = FIGHTMOVE_GROUNDKICK; - } - - } else { - pedOnGround = nearPed; - kickGround = true; - angleForGroundKick = nextAngle; - } - } - - if (!canAffectMultiplePeople) { - m_fRotationDest = nextAngle; - if (IsPlayer()) { - m_fRotationCur = m_fRotationDest; - m_lookTimer = 0; - SetLookFlag(nearPed, true); - SetLookTimer(1500); - } - break; - } - } - } else { - // Because we're in a scripted fight with some particular ped. - canAffectMultiplePeople = false; - - float fightingPedDist = (m_pedInObjective->GetPosition() - GetPosition()).Magnitude(); - if (hasShoppingBags) { - if (fightingPedDist >= 1.7f) - nextFightMove = FIGHTMOVE_SHUFFLE_F; - else - nextFightMove = FIGHTMOVE_ROUNDHOUSE; - - } else if (punchOnly) { - if (fightingPedDist >= 1.3f) - nextFightMove = FIGHTMOVE_SHUFFLE_F; - else - nextFightMove = FIGHTMOVE_PUNCHJAB; - - } else if (fightingPedDist >= 3.0f) { - nextFightMove = FIGHTMOVE_STDPUNCH; - - } else { - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - m_pedInObjective->GetPosition().x, - m_pedInObjective->GetPosition().y, - GetPosition().x, - GetPosition().y); - - nextAngle = CGeneral::LimitRadianAngle(angleToFace); - m_fRotationDest = nextAngle; - m_fRotationCur = m_fRotationDest; - if (!m_pedInObjective->OnGroundOrGettingUp()) { - - if (fightingPedDist >= 0.8f || !canKneeHead) { - - if (fightingPedDist >= 1.3f) { - - if (fightingPedDist < 1.7f && canKick) { - nextFightMove = FIGHTMOVE_KICK; - if (canRoundhouse && CGeneral::GetRandomNumber() & 1) - nextFightMove = FIGHTMOVE_ROUNDHOUSE; - - } else if (fightingPedDist < 2.0f && canKick) { - nextFightMove += 5; // Makes it 9 or 10 - - } else { - nextFightMove = FIGHTMOVE_SHUFFLE_F; - - } - } else { - nextFightMove += 2; // Makes it 6 or 7 - } - } - } else if (!CGame::nastyGame - || fightingPedDist >= 1.3f - || m_pedInObjective->IsPlayer() - || m_pedInObjective->m_nPedState != PED_DEAD && m_pedInObjective->IsPedHeadAbovePos(-0.3f)) { - nextFightMove = FIGHTMOVE_IDLE; - } else { - nextFightMove = FIGHTMOVE_GROUNDKICK; - } - } - } - - if (canAffectMultiplePeople) { - if (kickGround && IsPlayer()) { - m_fRotationDest = angleForGroundKick; - nextFightMove = FIGHTMOVE_GROUNDKICK; - m_fRotationCur = m_fRotationDest; - m_lookTimer = 0; - SetLookFlag(pedOnGround, true); - SetLookTimer(1500); - } else if (goForward) { - nextFightMove = FIGHTMOVE_SHUFFLE_F; - } else { - nextFightMove = FIGHTMOVE_STDPUNCH; - } - } - - if (nextFightMove != FIGHTMOVE_IDLE) { - m_curFightMove = nextFightMove; - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); - - animAssoc->SetFinishCallback(FinishFightMoveCB, this); - if (m_fightState == FIGHTSTATE_MOVE_FINISHED && animAssoc->currentTime != 0.0f) { - animAssoc->SetCurrentTime(0.0f); - animAssoc->SetRun(); - } - m_fightButtonPressure = 0; - } - m_fightState = FIGHTSTATE_NO_MOVE; - } else if (m_takeAStepAfterAttack && m_curFightMove != FIGHTMOVE_SHUFFLE_F -#ifndef FIX_BUGS - && CheckForPedsOnGroundToAttack(this, nil) == 4) { -#else - && CheckForPedsOnGroundToAttack(this, nil) == PED_IN_FRONT_OF_ATTACKER) { -#endif - m_curFightMove = FIGHTMOVE_SHUFFLE_F; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId); - - if (animAssoc) { - animAssoc->SetCurrentTime(0.0f); - animAssoc->blendDelta = 4.0f; - animAssoc->SetRun(); - } else { - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 32.0f); - } - animAssoc->SetFinishCallback(FinishFightMoveCB, this); - m_fightState = FIGHTSTATE_NO_MOVE; - m_fightButtonPressure = 0; - m_takeAStepAfterAttack = false; - - } else if (m_takeAStepAfterAttack) { - EndFight(ENDFIGHT_FAST); - - } else if (m_curFightMove == FIGHTMOVE_IDLE) { - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - EndFight(ENDFIGHT_NORMAL); - } - - } else { - m_curFightMove = FIGHTMOVE_IDLE; - if (IsPlayer()) - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500; - else - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; - } -} - -// Some helper function which doesn't exist in og game. -inline void -SelectClosestNodeForSeek(CPed *ped, CPathNode *node, CVector2D closeDist, CVector2D farDist, CPathNode *closeNode, CPathNode *closeNode2, int runCount = 3) -{ - for (int i = 0; i < node->numLinks; i++) { - - CPathNode *testNode = &ThePaths.m_pathNodes[ThePaths.ConnectedNode(i + node->firstLink)]; - - if (testNode && testNode != closeNode && testNode != closeNode2) { - CVector2D posDiff(ped->m_vecSeekPos - testNode->GetPosition()); - float dist = posDiff.MagnitudeSqr(); - - if (farDist.MagnitudeSqr() > dist) { - - if (closeDist.MagnitudeSqr() <= dist) { - ped->m_pNextPathNode = closeNode; - closeDist = posDiff; - } else { - ped->m_pNextPathNode = (closeNode2 ? closeNode2 : testNode); - farDist = posDiff; - } - } - - if (--runCount > 0) - SelectClosestNodeForSeek(ped, testNode, closeDist, farDist, closeNode, (closeNode2 ? closeNode2 : testNode), runCount); - } - } -} - -bool -CPed::FindBestCoordsFromNodes(CVector unused, CVector *bestCoords) -{ - if (m_pNextPathNode || !bUsePedNodeSeek) - return false; - - CVector ourPos = GetPosition(); - - int closestNodeId = ThePaths.FindNodeClosestToCoors(GetPosition(), 1, 999999.9f); - - CVector seekObjPos = m_vecSeekPos; - seekObjPos.z += 1.0f; - - if (CWorld::GetIsLineOfSightClear(ourPos, seekObjPos, true, false, false, true, false, false, false)) - return false; - - m_pNextPathNode = nil; - - CVector2D seekPosDist (m_vecSeekPos - ourPos); - - CPathNode *closestNode = &ThePaths.m_pathNodes[closestNodeId]; - CVector2D closeDist(m_vecSeekPos - closestNode->GetPosition()); - - SelectClosestNodeForSeek(this, closestNode, closeDist, seekPosDist, closestNode, nil); - - // Above function decided that going to the next node is more logical than seeking the object. - if (m_pNextPathNode) { - - CVector pathToNextNode = m_pNextPathNode->GetPosition() - ourPos; - if (pathToNextNode.MagnitudeSqr2D() < seekPosDist.MagnitudeSqr()) { - *bestCoords = m_pNextPathNode->GetPosition(); - return true; - } - m_pNextPathNode = nil; - } - - return false; -} - -void -CPed::FinishDieAnimCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - if (ped->bIsPedDieAnimPlaying) - ped->bIsPedDieAnimPlaying = false; -} - -void -CPed::FinishFightMoveCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - if (tFightMoves[ped->m_curFightMove].animId == animAssoc->animId) { - ped->m_fightState = FIGHTSTATE_MOVE_FINISHED; - animAssoc->blendDelta = -1000.0f; - } -} - -void -CPed::FinishHitHeadCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - if (animAssoc) { - animAssoc->blendDelta = -4.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - - if (ped->m_nPedState == PED_JUMP) - ped->RestorePreviousState(); - - ped->bIsLanding = false; -} - -void -CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - ped->bResetWalkAnims = true; - ped->bIsLanding = false; - - animAssoc->blendDelta = -1000.0f; -} - -void -CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - if (ped->m_nPedState != PED_JUMP) - return; - - CVector forward(0.15f * ped->GetForward() + ped->GetPosition()); - forward.z += CModelInfo::GetModelInfo(ped->GetModelIndex())->GetColModel()->spheres->center.z + 0.25f; - - CEntity *obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); - if (!obstacle) { - // Forward of forward - forward += 0.15f * ped->GetForward(); - forward.z += 0.15f; - obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); - } - - if (obstacle) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - - // ANIM_HIT_WALL in VC (which makes more sense) - CAnimBlendAssociation *handsCoverAssoc = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 8.0f); - handsCoverAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - handsCoverAssoc->SetFinishCallback(FinishHitHeadCB, ped); - ped->bIsLanding = true; - return; - } - - float velocityFromAnim = 0.1f; - CAnimBlendAssociation *sprintAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_SPRINT); - - if (sprintAssoc) { - velocityFromAnim = 0.05f * sprintAssoc->blendAmount + 0.17f; - } else { - CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_RUN); - if (runAssoc) { - velocityFromAnim = 0.07f * runAssoc->blendAmount + 0.1f; - } - } - - if (ped->IsPlayer() -#ifdef VC_PED_PORTS - || ped->m_pedInObjective && ped->m_pedInObjective->IsPlayer() -#endif - ) - ped->ApplyMoveForce(0.0f, 0.0f, 8.5f); - else - ped->ApplyMoveForce(0.0f, 0.0f, 4.5f); - - if (sq(velocityFromAnim) > ped->m_vecMoveSpeed.MagnitudeSqr2D() -#ifdef VC_PED_PORTS - || ped->m_pCurrentPhysSurface -#endif - ) { - -#ifdef FREE_CAM - if (TheCamera.Cams[0].Using3rdPersonMouseCam() && !CCamera::bFreeCam) { -#else - if (TheCamera.Cams[0].Using3rdPersonMouseCam()) { -#endif - float fpsAngle = ped->WorkOutHeadingForMovingFirstPerson(ped->m_fRotationCur); - ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(fpsAngle); - ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(fpsAngle); - } else { - ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(ped->m_fRotationCur); - ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(ped->m_fRotationCur); - } -#ifdef VC_PED_PORTS - if (ped->m_pCurrentPhysSurface) { - ped->m_vecMoveSpeed.x += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.x; - ped->m_vecMoveSpeed.y += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.y; - } -#endif - } - - ped->bIsStanding = false; - ped->bIsInTheAir = true; - animAssoc->blendDelta = -1000.0f; - CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_JUMP_GLIDE); - - if (ped->bDoBloodyFootprints) { - CVector bloodPos(0.0f, 0.0f, 0.0f); - ped->TransformToNode(bloodPos, PED_FOOTL); - - bloodPos.z -= 0.1f; - bloodPos += 0.2f * ped->GetForward(); - - CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, - 0.26f * ped->GetForward().x, - 0.26f * ped->GetForward().y, - 0.14f * ped->GetRight().x, - 0.14f * ped->GetRight().y, - 255, 255, 0, 0, 4.0f, 3000, 1.0f); - - bloodPos = CVector(0.0f, 0.0f, 0.0f); - ped->TransformToNode(bloodPos, PED_FOOTR); - - bloodPos.z -= 0.1f; - bloodPos += 0.2f * ped->GetForward(); - CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, - 0.26f * ped->GetForward().x, - 0.26f * ped->GetForward().y, - 0.14f * ped->GetRight().x, - 0.14f * ped->GetRight().y, - 255, 255, 0, 0, 4.0f, 3000, 1.0f); - - if (ped->m_bloodyFootprintCountOrDeathTime <= 40) { - ped->m_bloodyFootprintCountOrDeathTime = 0; - ped->bDoBloodyFootprints = false; - } else { - ped->m_bloodyFootprintCountOrDeathTime -= 40; - } - } -} - -void -CPed::FinishedWaitCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - ped->m_nWaitTimer = 0; - ped->RestoreHeadingRate(); - ped->Wait(); -} - -void -CPed::Wait(void) -{ - AnimationId mustHaveAnim = NUM_ANIMS; - CAnimBlendAssociation *animAssoc; - CPed *pedWeLook; - - if (DyingOrDead()) { - m_nWaitState = WAITSTATE_FALSE; - RestoreHeadingRate(); - return; - } - - switch (m_nWaitState) { - - case WAITSTATE_TRAFFIC_LIGHTS: - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - if (CTrafficLights::LightForPeds() == PED_LIGHTS_WALK) { - m_nWaitState = WAITSTATE_FALSE; - SetMoveState(PEDMOVE_WALK); - } - } - break; - - case WAITSTATE_CROSS_ROAD: - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - if (CGeneral::GetRandomNumber() & 1 || !m_nWaitTimer) - m_nWaitState = WAITSTATE_FALSE; - else - SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, nil); - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - break; - - case WAITSTATE_CROSS_ROAD_LOOK: - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - m_nWaitState = WAITSTATE_FALSE; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - break; - - case WAITSTATE_DOUBLEBACK: - if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { - uint32 timeLeft = m_nWaitTimer - CTimer::GetTimeInMilliseconds(); - if (timeLeft < 2500 && timeLeft > 2000) { - m_nWaitTimer -= 500; - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); - } - } else { - m_nWaitState = WAITSTATE_FALSE; - SetMoveState(PEDMOVE_WALK); - } - break; - - case WAITSTATE_HITWALL: - if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { - if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) { - m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; - } - } else { - m_nWaitState = WAITSTATE_FALSE; - } - break; - - case WAITSTATE_TURN180: - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - m_nWaitState = WAITSTATE_FALSE; - SetMoveState(PEDMOVE_WALK); - m_fRotationCur = m_fRotationCur + PI; - if (m_nPedState == PED_INVESTIGATE) - ClearInvestigateEvent(); - } - - if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) { - m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; - } - break; - - case WAITSTATE_SURPRISE: - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HIT_WALL)) { - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); - animAssoc->SetFinishCallback(FinishedWaitCB, this); - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; - } else { - m_nWaitState = WAITSTATE_FALSE; - } - } - break; - - case WAITSTATE_STUCK: - if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) - break; - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); - - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_TURN_180); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); - - if (animAssoc) { - if (animAssoc->IsPartial()) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } else { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); - } - - if (animAssoc->animId == ANIM_TURN_180) { - m_fRotationCur = CGeneral::LimitRadianAngle(PI + m_fRotationCur); - m_nWaitState = WAITSTATE_FALSE; - SetMoveState(PEDMOVE_WALK); - m_nStoredMoveState = PEDMOVE_NONE; - m_panicCounter = 0; - return; - } - } - - AnimationId animToPlay; - - switch (CGeneral::GetRandomNumber() & 3) { - case 0: - animToPlay = ANIM_ROAD_CROSS; - break; - case 1: - animToPlay = ANIM_IDLE_TIRED; - break; - case 2: - animToPlay = ANIM_XPRESS_SCRATCH; - break; - case 3: - animToPlay = ANIM_TURN_180; - break; - default: - break; - } - - animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); - - if (animToPlay == ANIM_TURN_180) - animAssoc->SetFinishCallback(FinishedWaitCB, this); - - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(1500, 5000); - break; - - case WAITSTATE_LOOK_ABOUT: - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - m_nWaitState = WAITSTATE_FALSE; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - break; - - case WAITSTATE_PLAYANIM_HANDSUP: - mustHaveAnim = ANIM_HANDSUP; - - case WAITSTATE_PLAYANIM_HANDSCOWER: - if (mustHaveAnim == NUM_ANIMS) - mustHaveAnim = ANIM_HANDSCOWER; - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); - pedWeLook = (CPed*) m_pLookTarget; - - if ((!m_pLookTarget || !m_pLookTarget->IsPed() || pedWeLook->m_pPointGunAt) - && m_nPedState != PED_FLEE_ENTITY - && m_nPedState != PED_ATTACK - && CTimer::GetTimeInMilliseconds() <= m_nWaitTimer - && animAssoc) { - - TurnBody(); - } else { - m_nWaitState = WAITSTATE_FALSE; - m_nWaitTimer = 0; - if (m_pLookTarget && m_pLookTarget->IsPed()) { - - if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_ATTACK) { - - if (m_pedStats->m_fear <= 100 - pedWeLook->m_pedStats->m_temper) { - - if (GetWeapon()->IsTypeMelee()) { -#ifdef VC_PED_PORTS - if(m_pedStats->m_flags & STAT_GUN_PANIC) { -#endif - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget); - if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) { - - bUsePedNodeSeek = true; - m_pNextPathNode = nil; - } - if (m_nMoveState != PEDMOVE_RUN) - SetMoveState(PEDMOVE_WALK); - - if (m_nPedType != PEDTYPE_COP) { - ProcessObjective(); - SetMoveState(PEDMOVE_WALK); - } -#ifdef VC_PED_PORTS - } else { - SetObjective(OBJECTIVE_NONE); - SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - } -#endif - } else { - SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_pLookTarget); - SetObjectiveTimer(20000); - } - } else { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget); - if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) - { - bUsePedNodeSeek = true; - m_pNextPathNode = nil; - } - SetMoveState(PEDMOVE_RUN); - Say(SOUND_PED_FLEE_RUN); - } - } - } - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); - if (animAssoc) { - animAssoc->blendDelta = -4.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - break; - case WAITSTATE_PLAYANIM_COWER: - mustHaveAnim = ANIM_HANDSCOWER; - - case WAITSTATE_PLAYANIM_DUCK: - if (mustHaveAnim == NUM_ANIMS) - mustHaveAnim = ANIM_DUCK_DOWN; - - case WAITSTATE_PLAYANIM_TAXI: - if (mustHaveAnim == NUM_ANIMS) - mustHaveAnim = ANIM_IDLE_TAXI; - - case WAITSTATE_PLAYANIM_CHAT: - if (mustHaveAnim == NUM_ANIMS) - mustHaveAnim = ANIM_IDLE_CHAT; - - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); - if (animAssoc) { - animAssoc->blendDelta = -4.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - m_nWaitState = WAITSTATE_FALSE; - } -#ifdef VC_PED_PORTS - else if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) { - if (m_pedInObjective) { - if (m_objective == OBJECTIVE_GOTO_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT) { - - // VC also calls CleanUpOldReference here for old LookTarget. - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - } - } - } -#endif - break; - - case WAITSTATE_FINISH_FLEE: - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); - if (animAssoc) { - if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); - int timer = 2000; - m_nWaitState = WAITSTATE_FALSE; - SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &timer); - } - } else { - m_nWaitState = WAITSTATE_FALSE; - } - break; - default: - break; - } - - if(!m_nWaitState) - RestoreHeadingRate(); -} - -bool -CPed::Seek(void) -{ - float distanceToCountItDone = m_distanceToCountSeekDone; - eMoveState nextMove = PEDMOVE_NONE; - - if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { - - if (m_nPedState != PED_EXIT_TRAIN && m_nPedState != PED_ENTER_TRAIN && m_nPedState != PED_SEEK_IN_BOAT && - m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_SOLICIT_VEHICLE && !bDuckAndCover) { - - if ((!m_pedInObjective || !m_pedInObjective->bInVehicle) - && !((CTimer::GetFrameCounter() + (m_randomSeed % 256) + 17) & 7)) { - - CEntity *obstacle = CWorld::TestSphereAgainstWorld(m_vecSeekPos, 0.4f, nil, - false, true, false, false, false, false); - - if (obstacle) { - if (!obstacle->IsVehicle() || ((CVehicle*)obstacle)->m_vehType == VEHICLE_TYPE_CAR) { - distanceToCountItDone = 2.5f; - } else { - CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(obstacle->GetModelIndex()); - float yLength = vehModel->GetColModel()->boundingBox.max.y - - vehModel->GetColModel()->boundingBox.min.y; - distanceToCountItDone = yLength * 0.55f; - } - } - } - } - } - - if (!m_pSeekTarget && m_nPedState == PED_SEEK_ENTITY) - ClearSeek(); - - float seekPosDist = (m_vecSeekPos - GetPosition()).Magnitude2D(); - if (seekPosDist < 2.0f || m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT) { - - if (m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION) { - - if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) - nextMove = m_pedInObjective->m_nMoveState; - } else - nextMove = PEDMOVE_WALK; - - } else if (m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION) { - - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || m_objective == OBJECTIVE_RUN_TO_AREA || bIsRunning) - nextMove = PEDMOVE_RUN; - else - nextMove = PEDMOVE_WALK; - - } else if (seekPosDist <= 2.0f) { - - if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) - nextMove = m_pedInObjective->m_nMoveState; - - } else { - nextMove = PEDMOVE_RUN; - } - - if (m_nPedState == PED_SEEK_ENTITY) { - if (m_pSeekTarget->IsPed()) { - if (((CPed*)m_pSeekTarget)->bInVehicle) - distanceToCountItDone += 2.0f; - } - } - - if (seekPosDist >= distanceToCountItDone) { - if (bIsRunning) - nextMove = PEDMOVE_RUN; - - if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) { - - if (m_actionX != 0.0f && m_actionY != 0.0f) { - - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - m_actionX, m_actionY, - GetPosition().x, GetPosition().y); - - float neededTurn = Abs(m_fRotationDest - m_fRotationCur); - - if (neededTurn > PI) - neededTurn = TWOPI - neededTurn; - - if (neededTurn > HALFPI) { - if (seekPosDist >= 1.0f) { - if (seekPosDist < 2.0f) { - if (bIsRunning) - nextMove = PEDMOVE_RUN; - else - nextMove = PEDMOVE_WALK; - } - } else { - nextMove = PEDMOVE_STILL; - } - } - - CVector2D moveDist(GetPosition().x - m_actionX, GetPosition().y - m_actionY); - if (moveDist.Magnitude() < 0.5f) { - m_nPedStateTimer = 0; - m_actionX = 0; - m_actionY = 0; - } - } - } else { - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - m_vecSeekPos.x, m_vecSeekPos.y, - GetPosition().x, GetPosition().y); - - float neededTurn = Abs(m_fRotationDest - m_fRotationCur); - - if (neededTurn > PI) - neededTurn = TWOPI - neededTurn; - - if (neededTurn > HALFPI) { - if (seekPosDist >= 1.0 && neededTurn <= DEGTORAD(135.0f)) { - if (seekPosDist < 2.0f) - nextMove = PEDMOVE_WALK; - } else { - nextMove = PEDMOVE_STILL; - } - } - } - - if (((m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY) && m_nMoveState < nextMove) - || (m_nPedState != PED_FLEE_POS && m_nPedState != PED_FLEE_ENTITY && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT && m_nWaitState == WAITSTATE_FALSE)) { - - SetMoveState(nextMove); - } - - SetMoveAnim(); - return false; - } - - if ((m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION || m_pedInObjective->m_nMoveState == PEDMOVE_STILL) && m_nMoveState != PEDMOVE_STILL) { - m_nPedStateTimer = 0; - m_actionX = 0; - m_actionY = 0; - } - - if (m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA || m_objective == OBJECTIVE_GOTO_AREA_ANY_MEANS) { - if (m_pNextPathNode) - m_pNextPathNode = nil; - else - bScriptObjectiveCompleted = true; - - bUsePedNodeSeek = true; - } - - if (SeekFollowingPath(nil)) - m_nCurPathNode++; - - return true; -} - -bool -CPed::SeekFollowingPath(CVector *unused) -{ - return m_nCurPathNode <= m_nPathNodes && m_nPathNodes; -} - -void -CPed::Flee(void) -{ - if (CTimer::GetTimeInMilliseconds() > m_fleeTimer && m_fleeTimer) { - bool mayFinishFleeing = true; - if (m_nPedState == PED_FLEE_ENTITY) { - if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < sq(30.0f)) - mayFinishFleeing = false; - } - - if (mayFinishFleeing) { - eMoveState moveState = m_nMoveState; - ClearFlee(); - - if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE || m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) - RestorePreviousObjective(); - - if ((m_nPedState == PED_IDLE || m_nPedState == PED_WANDER_PATH) && CGeneral::GetRandomNumber() & 1) { - SetWaitState(moveState <= PEDMOVE_WALK ? WAITSTATE_CROSS_ROAD_LOOK : WAITSTATE_FINISH_FLEE, nil); - } - return; - } - m_fleeTimer = CTimer::GetTimeInMilliseconds() + 5000; - } - - if (bUsePedNodeSeek) { - CPathNode *realLastNode = nil; - uint8 nextDirection = 0; - uint8 curDirectionShouldBe = 9; // means not defined yet - - if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds() - && m_collidingThingTimer < CTimer::GetTimeInMilliseconds()) { - - if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) { - - curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); - if (m_nPathDir < curDirectionShouldBe) - m_nPathDir += 8; - - int dirDiff = m_nPathDir - curDirectionShouldBe; - if (dirDiff > 2 && dirDiff < 6) { - realLastNode = nil; - m_pLastPathNode = m_pNextPathNode; - m_pNextPathNode = nil; - } - } - - if (m_pNextPathNode) { - m_vecSeekPos = m_pNextPathNode->GetPosition(); - if (m_nMoveState == PEDMOVE_RUN) - bIsRunning = true; - - eMoveState moveState = m_nMoveState; - if (Seek()) { - realLastNode = m_pLastPathNode; - m_pLastPathNode = m_pNextPathNode; - m_pNextPathNode = nil; - } - bIsRunning = false; - SetMoveState(moveState); - } - } - - if (!m_pNextPathNode) { - if (curDirectionShouldBe == 9) { - curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); - } - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - curDirectionShouldBe, - &nextDirection); - - if (curDirectionShouldBe < nextDirection) - curDirectionShouldBe += 8; - - if (m_pNextPathNode && m_pNextPathNode != realLastNode && m_pNextPathNode != m_pLastPathNode && curDirectionShouldBe - nextDirection != 4) { - m_nPathDir = nextDirection; - m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; - } else { - bUsePedNodeSeek = false; - SetMoveState(PEDMOVE_RUN); - Flee(); - } - } - return; - } - - if ((m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_ON_FIRE) && m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) { - - float angleToFleeFromPos = CGeneral::GetRadianAngleBetweenPoints( - GetPosition().x, - GetPosition().y, - ms_vec2DFleePosition.x, - ms_vec2DFleePosition.y); - - m_fRotationDest = CGeneral::LimitRadianAngle(angleToFleeFromPos); - - if (m_fRotationCur - PI > m_fRotationDest) - m_fRotationDest += TWOPI; - else if (PI + m_fRotationCur < m_fRotationDest) - m_fRotationDest -= TWOPI; - } - - if (CTimer::GetTimeInMilliseconds() & 0x20) { - //CVector forwardPos = GetPosition(); - CMatrix forwardMat(GetMatrix()); - forwardMat.GetPosition() += Multiply3x3(forwardMat, CVector(0.0f, 4.0f, 0.0f)); - CVector forwardPos = forwardMat.GetPosition(); - - CEntity *foundEnt; - CColPoint foundCol; - bool found = CWorld::ProcessVerticalLine(forwardPos, forwardMat.GetPosition().z - 100.0f, foundCol, foundEnt, 1, 0, 0, 0, 1, 0, 0); - - if (!found || Abs(forwardPos.z - forwardMat.GetPosition().z) > 1.0f) { - m_fRotationDest += DEGTORAD(112.5f); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000; - } - } - - if (CTimer::GetTimeInMilliseconds() >= m_collidingThingTimer) - return; - - if (!m_collidingEntityWhileFleeing) - return; - - double collidingThingPriorityMult = (double)(m_collidingThingTimer - CTimer::GetTimeInMilliseconds()) * 2.0 / 2500; - - if (collidingThingPriorityMult <= 1.5) { - - double angleToFleeEntity = CGeneral::GetRadianAngleBetweenPoints( - GetPosition().x, - GetPosition().y, - m_collidingEntityWhileFleeing->GetPosition().x, - m_collidingEntityWhileFleeing->GetPosition().y); - angleToFleeEntity = CGeneral::LimitRadianAngle(angleToFleeEntity); - - double angleToFleeCollidingThing = CGeneral::GetRadianAngleBetweenPoints( - m_vecDamageNormal.x, - m_vecDamageNormal.y, - 0.0f, - 0.0f); - angleToFleeCollidingThing = CGeneral::LimitRadianAngle(angleToFleeCollidingThing); - - if (angleToFleeEntity - PI > angleToFleeCollidingThing) - angleToFleeCollidingThing += TWOPI; - else if (PI + angleToFleeEntity < angleToFleeCollidingThing) - angleToFleeCollidingThing -= TWOPI; - - if (collidingThingPriorityMult <= 1.0f) { - // Range [0.0, 1.0] - - float angleToFleeBoth = (angleToFleeCollidingThing + angleToFleeEntity) * 0.5f; - - if (m_fRotationDest - PI > angleToFleeBoth) - angleToFleeBoth += TWOPI; - else if (PI + m_fRotationDest < angleToFleeBoth) - angleToFleeBoth -= TWOPI; - - m_fRotationDest = (1.0f - collidingThingPriorityMult) * m_fRotationDest + collidingThingPriorityMult * angleToFleeBoth; - } else { - // Range (1.0, 1.5] - - double adjustedMult = (collidingThingPriorityMult - 1.0f) * 2.0f; - m_fRotationDest = angleToFleeEntity * (1.0 - adjustedMult) + adjustedMult * angleToFleeCollidingThing; - } - } else { - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - m_vecDamageNormal.x, - m_vecDamageNormal.y, - 0.0f, - 0.0f); - m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); - } - - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - - if (m_fRotationCur - PI > m_fRotationDest) - m_fRotationDest += TWOPI; - else if (PI + m_fRotationCur < m_fRotationDest) - m_fRotationDest -= TWOPI; - -} - -void -CPed::FollowPath(void) -{ - m_vecSeekPos.x = m_stPathNodeStates[m_nCurPathNode].x; - m_vecSeekPos.y = m_stPathNodeStates[m_nCurPathNode].y; - m_vecSeekPos.z = GetPosition().z; - - // Mysterious code -/* int v4 = 0; - int maxNodeIndex = m_nPathNodes - 1; - if (maxNodeIndex > 0) { - if (maxNodeIndex > 8) { - while (v4 < maxNodeIndex - 8) - v4 += 8; - } - - while (v4 < maxNodeIndex) - v4++; - - } -*/ - if (Seek()) { - m_nCurPathNode++; - if (m_nCurPathNode == m_nPathNodes) - RestorePreviousState(); - } -} - -CVector -CPed::GetFormationPosition(void) -{ - if (m_pedInObjective->m_nPedState == PED_DEAD) { - if (!m_pedInObjective->m_pedInObjective) { - m_pedInObjective = nil; - return GetPosition(); - } - m_pedInObjective = m_pedInObjective->m_pedInObjective; - } - - CVector formationOffset; - switch (m_pedFormation) { - case FORMATION_REAR: - formationOffset = CVector(0.0f, -1.5f, 0.0f); - break; - case FORMATION_REAR_LEFT: - formationOffset = CVector(-1.5f, -1.5f, 0.0f); - break; - case FORMATION_REAR_RIGHT: - formationOffset = CVector(1.5f, -1.5f, 0.0f); - break; - case FORMATION_FRONT_LEFT: - formationOffset = CVector(-1.5f, 1.5f, 0.0f); - break; - case FORMATION_FRONT_RIGHT: - formationOffset = CVector(1.5f, 1.5f, 0.0f); - break; - case FORMATION_LEFT: - formationOffset = CVector(-1.5f, 0.0f, 0.0f); - break; - case FORMATION_RIGHT: - formationOffset = CVector(1.5f, 0.0f, 0.0f); - break; - case FORMATION_FRONT: - formationOffset = CVector(0.0f, 1.5f, 0.0f); - break; - default: - formationOffset = CVector(0.0f, 0.0f, 0.0f); - break; - } - return formationOffset + m_pedInObjective->GetPosition(); -} - -void -CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen) -{ - CVector *enterOffset = nil; - if (m_vehEnterType == CAR_DOOR_LF && veh->pDriver - || m_vehEnterType == CAR_DOOR_RF && veh->pPassengers[0] - || m_vehEnterType == CAR_DOOR_LR && veh->pPassengers[1] - || m_vehEnterType == CAR_DOOR_RR && veh->pPassengers[2]) - { - enterOffset = &vecPedQuickDraggedOutCarAnimOffset; - } - - CVector lfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LF); - CVector rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); - - // Left front door is closer - if ((lfPos - GetPosition()).MagnitudeSqr2D() < (rfPos - GetPosition()).MagnitudeSqr2D()) { - - if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - m_vehEnterType = CAR_DOOR_LF; - posToOpen = lfPos; - } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { - m_vehEnterType = CAR_DOOR_RF; - posToOpen = rfPos; - } - } else { - - if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { - - CPed *rfPassenger = veh->pPassengers[0]; - if (rfPassenger && (rfPassenger->m_leader == this || rfPassenger->bDontDragMeOutCar || - veh->VehicleCreatedBy == MISSION_VEHICLE && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) - && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) - || (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - - m_vehEnterType = CAR_DOOR_LF; - posToOpen = lfPos; - } else { - m_vehEnterType = CAR_DOOR_RF; - posToOpen = rfPos; - } - } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { - m_vehEnterType = CAR_DOOR_LF; - posToOpen = lfPos; - } - } -} - -bool -CPed::GetNearestPassengerDoor(CVehicle *veh, CVector &posToOpen) -{ - CVector rfPos, lrPos, rrPos; - bool canEnter = false; - - CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(veh->GetModelIndex()); - - switch (veh->GetModelIndex()) { - case MI_BUS: - m_vehEnterType = CAR_DOOR_RF; - posToOpen = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); - return true; - case MI_RHINO: - default: - break; - } - - CVector2D rfPosDist(999.0f, 999.0f); - CVector2D lrPosDist(999.0f, 999.0f); - CVector2D rrPosDist(999.0f, 999.0f); - - if (!veh->pPassengers[0] - && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) - && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, nil)) { - - rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); - canEnter = true; - rfPosDist = rfPos - GetPosition(); - } - if (vehModel->m_numDoors == 4) { - if (!veh->pPassengers[1] - && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) - && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LR, nil)) { - lrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LR); - canEnter = true; - lrPosDist = lrPos - GetPosition(); - } - if (!veh->pPassengers[2] - && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) - && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RR, nil)) { - rrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RR); - canEnter = true; - rrPosDist = rrPos - GetPosition(); - } - - // When the door we should enter is blocked by some object. - if (!canEnter) - veh->ShufflePassengersToMakeSpace(); - } - - CVector2D nextToCompare = rfPosDist; - posToOpen = rfPos; - m_vehEnterType = CAR_DOOR_RF; - if (lrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { - m_vehEnterType = CAR_DOOR_LR; - posToOpen = lrPos; - nextToCompare = lrPosDist; - } - - if (rrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { - m_vehEnterType = CAR_DOOR_RR; - posToOpen = rrPos; - } - return canEnter; -} - -int -CPed::GetNextPointOnRoute(void) -{ - int16 nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; - - // Route is complete - if (nextPoint < 0 || nextPoint > NUMPEDROUTES || m_routeLastPoint != CRouteNode::GetRouteThisPointIsOn(nextPoint)) { - - switch (m_routeType) { - case PEDROUTE_STOP_WHEN_DONE: - nextPoint = -1; - break; - case PEDROUTE_GO_BACKWARD_WHEN_DONE: - m_routePointsBeingPassed = -m_routePointsBeingPassed; - nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; - break; - case PEDROUTE_GO_TO_START_WHEN_DONE: - m_routePointsPassed = -1; - nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; - break; - default: - break; - } - } - return nextPoint; -} - -// These categories are purely random, most of ped models have no correlation. So I don't think making an enum. -uint8 -CPed::GetPedRadioCategory(uint32 modelIndex) -{ - switch (modelIndex) { - case MI_MALE01: - case MI_FEMALE03: - case MI_PROSTITUTE2: - case MI_WORKER1: - case MI_MOD_MAN: - case MI_MOD_WOM: - case MI_ST_WOM: - case MI_FAN_WOM: - return 3; - case MI_TAXI_D: - case MI_PIMP: - case MI_MALE02: - case MI_FEMALE02: - case MI_FATFEMALE01: - case MI_FATFEMALE02: - case MI_DOCKER1: - case MI_WORKER2: - case MI_FAN_MAN2: - return 9; - case MI_GANG01: - case MI_GANG02: - case MI_SCUM_MAN: - case MI_SCUM_WOM: - case MI_HOS_WOM: - case MI_CONST1: - return 1; - case MI_GANG03: - case MI_GANG04: - case MI_GANG07: - case MI_GANG08: - case MI_CT_MAN2: - case MI_CT_WOM2: - case MI_B_MAN3: - case MI_SHOPPER3: - return 4; - case MI_GANG05: - case MI_GANG06: - case MI_GANG11: - case MI_GANG12: - case MI_CRIMINAL02: - case MI_B_WOM2: - case MI_ST_MAN: - case MI_HOS_MAN: - return 5; - case MI_FATMALE01: - case MI_LI_MAN2: - case MI_SHOPPER1: - case MI_CAS_MAN: - return 6; - case MI_PROSTITUTE: - case MI_P_WOM2: - case MI_LI_WOM2: - case MI_B_WOM3: - case MI_CAS_WOM: - return 2; - case MI_P_WOM1: - case MI_DOCKER2: - case MI_STUD_MAN: - return 7; - case MI_CT_MAN1: - case MI_CT_WOM1: - case MI_LI_MAN1: - case MI_LI_WOM1: - case MI_B_MAN1: - case MI_B_MAN2: - case MI_B_WOM1: - case MI_SHOPPER2: - case MI_STUD_WOM: - return 8; - default: - return 0; - } -} - -// Some kind of VC leftover I think -int -CPed::GetWeaponSlot(eWeaponType weaponType) -{ - if (HasWeapon(weaponType)) - return weaponType; - else - return -1; -} - -void -CPed::GoToNearestDoor(CVehicle *veh) -{ - CVector posToOpen; - GetNearestDoor(veh, posToOpen); - SetSeek(posToOpen, 0.5f); - SetMoveState(PEDMOVE_RUN); -} - -bool -CPed::HaveReachedNextPointOnRoute(float distToCountReached) -{ - if ((m_nextRoutePointPos - GetPosition()).Magnitude2D() >= distToCountReached) - return false; - - m_routePointsPassed += m_routePointsBeingPassed; - return true; -} - -void -CPed::Idle(void) -{ - CVehicle *veh = m_pMyVehicle; - if (veh && veh->m_nGettingOutFlags && m_vehEnterType) { - - if (veh->m_nGettingOutFlags & GetCarDoorFlag(m_vehEnterType)) { - - if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { - - CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehEnterType); - CVector doorDist = GetPosition() - doorPos; - - if (doorDist.MagnitudeSqr() < sq(0.5f)) { - SetMoveState(PEDMOVE_WALK); - return; - } - } - } - } - - CAnimBlendAssociation *armedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); - CAnimBlendAssociation *unarmedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - int waitTime; - - if (m_nMoveState == PEDMOVE_STILL) { - - eWeaponType curWeapon = GetWeapon()->m_eWeaponType; - if (!armedIdleAssoc || - CTimer::GetTimeInMilliseconds() <= m_nWaitTimer && curWeapon != WEAPONTYPE_UNARMED && curWeapon != WEAPONTYPE_MOLOTOV && curWeapon != WEAPONTYPE_GRENADE) { - - if ((!GetWeapon()->IsType2Handed() || curWeapon == WEAPONTYPE_SHOTGUN) && curWeapon != WEAPONTYPE_BASEBALLBAT - || !unarmedIdleAssoc || unarmedIdleAssoc->blendAmount <= 0.95f || m_nWaitState != WAITSTATE_FALSE || CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { - - m_moved = CVector2D(0.0f, 0.0f); - return; - } - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_ARMED, 3.0f); - waitTime = CGeneral::GetRandomNumberInRange(4000, 7500); - } else { - armedIdleAssoc->blendDelta = -2.0f; - armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT; - waitTime = CGeneral::GetRandomNumberInRange(3000, 8500); - } - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + waitTime; - } else { - if (armedIdleAssoc) { - armedIdleAssoc->blendDelta = -8.0f; - armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT; - m_nWaitTimer = 0; - } - if (!IsPlayer()) - SetMoveState(PEDMOVE_STILL); - } - m_moved = CVector2D(0.0f, 0.0f); -} - -void -CPed::InTheAir(void) -{ - CColPoint foundCol; - CEntity *foundEnt; - - CVector ourPos = GetPosition(); - CVector bitBelow = GetPosition(); - bitBelow.z -= 4.04f; - - if (m_vecMoveSpeed.z < 0.0f && !bIsPedDieAnimPlaying) { - if (!DyingOrDead()) { - if (CWorld::ProcessLineOfSight(ourPos, bitBelow, foundCol, foundEnt, true, true, false, true, false, false, false)) { - if (GetPosition().z - foundCol.point.z < 1.3f -#ifdef VC_PED_PORTS - || bIsStanding -#endif - ) - SetLanding(); - } else { - if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL)) { - if (m_vecMoveSpeed.z < -0.1f) - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_FALL, 4.0f); - } - } - } - } -} - -void -CPed::SetLanding(void) -{ - if (DyingOrDead()) - return; - - CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); - CAnimBlendAssociation *landAssoc; - - RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); - if (fallAssoc) { - landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_COLLAPSE); - DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_COLLAPSE, 1.0f); - - if (IsPlayer()) - Say(SOUND_PED_LAND); - - } else { - landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_LAND); - DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_LAND, 1.0f); - } - - landAssoc->SetFinishCallback(PedLandCB, this); - bIsInTheAir = false; - bIsLanding = true; -} - -void -CPed::Initialise(void) -{ - debug("Initialising CPed...\n"); - CPedType::Initialise(); - LoadFightData(); - SetAnimOffsetForEnterOrExitVehicle(); - debug("CPed ready\n"); -} - -void -CPed::SetAnimOffsetForEnterOrExitVehicle(void) -{ - // FIX: If there were no translations on enter anims, there were overflows all over this function. - - CAnimBlendHierarchy *enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_JACKED_LHS)->hierarchy; - CAnimBlendSequence *seq = enterAssoc->sequences; - CAnimManager::UncompressAnimation(enterAssoc); - if (seq->numFrames > 0) { - if (!seq->HasTranslation()) - vecPedDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); - else { - KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); - vecPedDraggedOutCarAnimOffset = lastFrame->translation; - } - } - - enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LHS)->hierarchy; - seq = enterAssoc->sequences; - CAnimManager::UncompressAnimation(enterAssoc); - if (seq->numFrames > 0) { - if (!seq->HasTranslation()) - vecPedCarDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); - else { - KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); - vecPedCarDoorAnimOffset = lastFrame->translation; - } - } - - enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS)->hierarchy; - seq = enterAssoc->sequences; - CAnimManager::UncompressAnimation(enterAssoc); - if (seq->numFrames > 0) { - if (!seq->HasTranslation()) - vecPedCarDoorLoAnimOffset = CVector(0.0f, 0.0f, 0.0f); - else { - KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); - vecPedCarDoorLoAnimOffset = lastFrame->translation; - } - } - - enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_QJACKED)->hierarchy; - seq = enterAssoc->sequences; - CAnimManager::UncompressAnimation(enterAssoc); - if (seq->numFrames > 0) { - if (!seq->HasTranslation()) - vecPedQuickDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); - else { - KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); - vecPedQuickDraggedOutCarAnimOffset = lastFrame->translation; - } - } - - enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_VAN_GETIN_L)->hierarchy; - seq = enterAssoc->sequences; - CAnimManager::UncompressAnimation(enterAssoc); - if (seq->numFrames > 0) { - if (!seq->HasTranslation()) - vecPedVanRearDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); - else { - KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); - vecPedVanRearDoorAnimOffset = lastFrame->translation; - } - } - - enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_TRAIN_GETOUT)->hierarchy; - seq = enterAssoc->sequences; - CAnimManager::UncompressAnimation(enterAssoc); - if (seq->numFrames > 0) { - if (!seq->HasTranslation()) - vecPedTrainDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); - else { - KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); - vecPedTrainDoorAnimOffset = lastFrame->translation; - } - } -} - -void -CPed::InvestigateEvent(void) -{ - CAnimBlendAssociation *animAssoc; - AnimationId animToPlay; - AssocGroupId animGroup; - - if (m_nWaitState == WAITSTATE_TURN180) - return; - - if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { - - if (m_standardTimer) { - if (m_eventType < EVENT_ASSAULT_NASTYWEAPON) - SetWaitState(WAITSTATE_TURN180, nil); - - m_standardTimer = 0; - } else { - ClearInvestigateEvent(); - } - return; - } - - CVector2D vecDist = m_eventOrThreat - GetPosition(); - float distSqr = vecDist.MagnitudeSqr(); - if (sq(m_distanceToCountSeekDone) >= distSqr) { - - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(vecDist.x, vecDist.y, 0.0f, 0.0f); - SetMoveState(PEDMOVE_STILL); - - switch (m_eventType) { - case EVENT_DEAD_PED: - case EVENT_HIT_AND_RUN: - case EVENT_HIT_AND_RUN_COP: - - if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); - - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (m_pEventEntity) - SetLookFlag(m_pEventEntity, true); - - SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); - - } else if (CGeneral::GetRandomNumber() & 3) { - ClearLookFlag(); - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 4.0f); - - SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); - Say(SOUND_PED_CHAT_EVENT); - - } else { - ClearInvestigateEvent(); - } - } - break; - case EVENT_FIRE: - case EVENT_EXPLOSION: - - if (bHasACamera && CTimer::GetTimeInMilliseconds() > m_lookTimer) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CAM); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - - if (animAssoc && animAssoc->animId == ANIM_IDLE_CAM) { - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); - SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); - - } else if (CGeneral::GetRandomNumber() & 3) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CAM, 4.0f); - SetLookTimer(CGeneral::GetRandomNumberInRange(2500, 5000)); - Say(SOUND_PED_CHAT_EVENT); - - } else { - m_standardTimer = 0; - } - - } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); - - if (!animAssoc) - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); - - if (animAssoc && animAssoc->animId == ANIM_IDLE_STANCE) { - if (CGeneral::GetRandomNumber() & 1) - animToPlay = ANIM_IDLE_HBHB; - else - animToPlay = ANIM_XPRESS_SCRATCH; - - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); - SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); - - } else if (animAssoc && animAssoc->animId == ANIM_IDLE_HBHB) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (CGeneral::GetRandomNumber() & 1) { - animToPlay = ANIM_IDLE_STANCE; - animGroup = m_animGroup; - } else { - animToPlay = ANIM_XPRESS_SCRATCH; - animGroup = ASSOCGRP_STD; - } - - CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); - SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); - - } else { - if (CGeneral::GetRandomNumber() & 1) { - animToPlay = ANIM_IDLE_STANCE; - animGroup = m_animGroup; - } else { - animToPlay = ANIM_IDLE_HBHB; - animGroup = ASSOCGRP_STD; - } - - CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); - SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); - } - Say(SOUND_PED_CHAT_EVENT); - } - break; - case EVENT_ICECREAM: - case EVENT_SHOPSTALL: - - m_fRotationDest = m_fAngleToEvent; - if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - - if (m_lookTimer) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); - - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (m_eventType == EVENT_ICECREAM) - animToPlay = ANIM_IDLE_CHAT; - else - animToPlay = ANIM_XPRESS_SCRATCH; - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay,4.0f); - SetLookTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); - - } else { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - ClearInvestigateEvent(); - } else { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); - if (animAssoc) { - animAssoc->blendDelta = -8.0f; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - ClearInvestigateEvent(); - } - } - } else { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 4.0f); - SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); - } - } - break; - default: - return; - } - } else { - m_vecSeekPos.x = m_eventOrThreat.x; - m_vecSeekPos.y = m_eventOrThreat.y; - m_vecSeekPos.z = GetPosition().z; - Seek(); - - if (m_eventType < EVENT_ICECREAM) { - if (sq(5.0f + m_distanceToCountSeekDone) < distSqr) { - SetMoveState(PEDMOVE_RUN); - return; - } - } - if (m_eventType <= EVENT_EXPLOSION || m_eventType >= EVENT_SHOPSTALL) { - SetMoveState(PEDMOVE_WALK); - return; - } - if (distSqr > sq(1.2f)) { - SetMoveState(PEDMOVE_WALK); - return; - } - - for (int i = 0; i < m_numNearPeds; i++) { - if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < sq(0.4f)) { - SetMoveState(PEDMOVE_STILL); - return; - } - } - - SetMoveState(PEDMOVE_WALK); - } -} - -bool -CPed::IsPedDoingDriveByShooting(void) -{ - if (FindPlayerPed() == this && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { - if (TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight) - return true; - } - return false; -} - -bool -CPed::IsPedShootable(void) -{ - return m_nPedState <= PED_STATES_NO_ST; -} - -bool -CPed::IsRoomToBeCarJacked(void) -{ - if (!m_pMyVehicle) - return false; - - CVector offset; - if (m_pMyVehicle->bLowVehicle || m_nPedType == PEDTYPE_COP) { - offset = vecPedDraggedOutCarAnimOffset; - } else { - offset = vecPedQuickDraggedOutCarAnimOffset; - } - - offset.z = 0.0f; - if (m_pMyVehicle->IsRoomForPedToLeaveCar(CAR_DOOR_LF, &offset)) { - return true; - } - - return false; -} - -void -CPed::KillPedWithCar(CVehicle *car, float impulse) -{ - CVehicleModelInfo *vehModel; - CColModel *vehColModel; - uint8 damageDir; - PedNode nodeToDamage; - eWeaponType killMethod; - - if (m_nPedState == PED_FALL || m_nPedState == PED_DIE) { - if (!this->m_pCollidingEntity || car->GetStatus() == STATUS_PLAYER) - this->m_pCollidingEntity = car; - return; - } - - if (m_nPedState == PED_DEAD) - return; - - if (m_pCurSurface) { - if (m_pCurSurface->IsVehicle() && (((CVehicle*)m_pCurSurface)->m_vehType == VEHICLE_TYPE_BOAT || IsPlayer())) - return; - } - - CVector distVec = GetPosition() - car->GetPosition(); - - if ((impulse > 12.0f || car->GetModelIndex() == MI_TRAIN) && !IsPlayer()) { - nodeToDamage = PED_TORSO; - killMethod = WEAPONTYPE_RAMMEDBYCAR; - uint8 randVal = CGeneral::GetRandomNumber() & 3; - - if (car == FindPlayerVehicle()) { - float carSpeed = car->m_vecMoveSpeed.Magnitude(); - uint8 shakeFreq; - if (100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f <= 250.0f) { - shakeFreq = 100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f; - } else { - shakeFreq = 250.0f; - } - CPad::GetPad(0)->StartShake(40000 / shakeFreq, shakeFreq); - } - bIsStanding = false; - damageDir = GetLocalDirection(-m_vecMoveSpeed); - vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(car->GetModelIndex()); - vehColModel = vehModel->GetColModel(); - float carRightAndDistDotProd = DotProduct(distVec, car->GetRight()); - - if (car->GetModelIndex() == MI_TRAIN) { - killMethod = WEAPONTYPE_RUNOVERBYCAR; - nodeToDamage = PED_HEAD; - m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; - m_vecMoveSpeed.z = 0.0f; - if (damageDir == 1 || damageDir == 3) - damageDir = 2; - if (CGame::nastyGame) - DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); - - // Car doesn't look to us - } else if (DotProduct(car->m_vecMoveSpeed, car->GetForward()) >= 0.0f){ - - if (0.99f * vehColModel->boundingBox.max.x < Abs(carRightAndDistDotProd)) { - - // We're at the right of the car - if (carRightAndDistDotProd <= 0.0f) - nodeToDamage = PED_UPPERARML; - else - nodeToDamage = PED_UPPERARMR; - - if (Abs(DotProduct(distVec, car->GetForward())) < 0.85f * vehColModel->boundingBox.max.y) { - killMethod = WEAPONTYPE_RUNOVERBYCAR; - m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; - m_vecMoveSpeed.z = 0.0f; - if (damageDir == 1 || damageDir == 3) - damageDir = 2; - if (CGame::nastyGame) - DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); - - } - } else { - float carFrontAndDistDotProd = DotProduct(distVec, car->GetForward()); - - // carFrontAndDistDotProd <= 0.0 car looks to us - if ((carFrontAndDistDotProd <= 0.1 || randVal == 1) && randVal != 0) { - killMethod = WEAPONTYPE_RUNOVERBYCAR; - nodeToDamage = PED_HEAD; - m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; - m_vecMoveSpeed.z = 0.0f; - if (damageDir == 1 || damageDir == 3) - damageDir = 2; - - if (CGame::nastyGame) - DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); - - } else { - nodeToDamage = PED_MID; - float vehColMaxY = vehColModel->boundingBox.max.y; - float vehColMinY = vehColModel->boundingBox.min.y; - float vehColMaxZ = vehColModel->boundingBox.max.z; - float carFrontZ = car->GetForward().z; - float carHighestZ, carLength; - - if (carFrontZ < -0.2f) { - // Highest point of car's back - carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMinY, vehColMaxZ)).z; - carLength = vehColMaxY - vehColMinY; - - } else if (carFrontZ > 0.1f) { - // Highest point of car's front - carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; - float highestZDist = carHighestZ - GetPosition().z; - if (highestZDist > 0.0f) { - GetMatrix().GetPosition().z += 0.5f * highestZDist; - carHighestZ += highestZDist * 0.25f; - } - carLength = vehColMaxY; - - } else { - // Highest point of car's front - carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; - carLength = vehColMaxY; - } - - float pedJumpSpeedToReachHighestZ = (carHighestZ - GetPosition().z) / (carLength / car->m_vecMoveSpeed.Magnitude()); - - // TODO: What are we doing down here? - float unknown = ((CGeneral::GetRandomNumber() % 256) * 0.002 + 1.5) * pedJumpSpeedToReachHighestZ; - - // After this point, distVec isn't distVec anymore. - distVec = car->m_vecMoveSpeed; - distVec.Normalise(); - distVec *= 0.2 * unknown; - - if (damageDir != 1 && damageDir != 3) - distVec.z += unknown; - else - distVec.z += 1.5f * unknown; - - m_vecMoveSpeed = distVec; - damageDir += 2; - if (damageDir > 3) - damageDir = damageDir - 4; - - if (car->m_vehType == VEHICLE_TYPE_CAR) { - CObject *bonnet = ((CAutomobile*)car)->RemoveBonnetInPedCollision(); - - if (bonnet) { - if (CGeneral::GetRandomNumber() & 1) { - bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(0.1f, 0.0f, 0.5f)); - } else { - bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(-0.1f, 0.0f, 0.5f)); - } - CVector forceDir = car->GetUp() * 10.0f; - bonnet->ApplyTurnForce(forceDir, car->GetForward()); - } - } - } - } - } - - if (car->pDriver) { - CEventList::RegisterEvent((m_nPedType == PEDTYPE_COP ? EVENT_HIT_AND_RUN_COP : EVENT_HIT_AND_RUN), EVENT_ENTITY_PED, this, car->pDriver, 1000); - } - - ePedPieceTypes pieceToDamage; - switch (nodeToDamage) { - case PED_HEAD: - pieceToDamage = PEDPIECE_HEAD; - break; - case PED_UPPERARML: - pieceToDamage = PEDPIECE_LEFTARM; - break; - case PED_UPPERARMR: - pieceToDamage = PEDPIECE_RIGHTARM; - break; - default: - pieceToDamage = PEDPIECE_MID; - break; - } - InflictDamage(car, killMethod, 1000.0f, pieceToDamage, damageDir); - - if (DyingOrDead() - && bIsPedDieAnimPlaying && !m_pCollidingEntity) { - m_pCollidingEntity = car; - } - if (nodeToDamage == PED_MID) - bKnockedUpIntoAir = true; - else - bKnockedUpIntoAir = false; - - distVec.Normalise(); - -#ifdef VC_PED_PORTS - distVec *= Min(car->m_fMass / 1400.0f, 1.0f); -#endif - car->ApplyMoveForce(distVec * -100.0f); - Say(SOUND_PED_DEFEND); - - } else if (m_vecDamageNormal.z < -0.8f && impulse > 3.0f - || impulse > 6.0f && (!IsPlayer() || impulse > 10.0f)) { - - bIsStanding = false; - uint8 fallDirection = GetLocalDirection(-car->m_vecMoveSpeed); - float damage; - if (IsPlayer() && car->GetModelIndex() == MI_TRAIN) - damage = 150.0f; - else - damage = 30.0f; - - InflictDamage(car, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, fallDirection); - SetFall(1000, (AnimationId)(fallDirection + ANIM_KO_SKID_FRONT), true); - - if (OnGround() && !m_pCollidingEntity && - (!IsPlayer() || bHasHitWall || car->GetModelIndex() == MI_TRAIN || m_vecDamageNormal.z < -0.8f)) { - - m_pCollidingEntity = car; - } - - bKnockedUpIntoAir = false; - if (car->GetModelIndex() != MI_TRAIN && !bHasHitWall) { - m_vecMoveSpeed = car->m_vecMoveSpeed * 0.75f; - } - m_vecMoveSpeed.z = 0.0f; - distVec.Normalise(); -#ifdef VC_PED_PORTS - distVec *= Min(car->m_fMass / 1400.0f, 1.0f); -#endif - car->ApplyMoveForce(distVec * -60.0f); - Say(SOUND_PED_DEFEND); - } - -#ifdef VC_PED_PORTS - // Killing gang members with car wasn't triggering a fight, until now... Taken from VC. - if (IsGangMember()) { - CPed *driver = car->pDriver; - if (driver && driver->IsPlayer() + // BUG: Same bug as above. Fixed at the bottom of function. + flagsOfSomePed = CPedType::GetFlag(driver->m_nPedType); + if (CPedType::GetFlag(driver->m_nPedType) & fearFlags) { + if (driver->m_fHealth > 0.0f && OurPedCanSeeThisOne(nearVeh->pDriver)) { + // FIX: Taken from VC #ifdef FIX_BUGS - && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats) && (!m_leader || m_leader != driver) -#endif - ) { - RegisterThreatWithGangPeds(driver); - } - } -#endif -} - -void -CPed::Look(void) -{ - // UNUSED: This is a perfectly empty function. -} - -bool -CPed::LookForInterestingNodes(void) -{ - CBaseModelInfo *model; - CPtrNode *ptrNode; - CVector effectDist; - C2dEffect *effect; - CMatrix *objMat; - - if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) & 7 || CTimer::GetTimeInMilliseconds() <= m_standardTimer) { - return false; - } - bool found = false; - uint8 randVal = CGeneral::GetRandomNumber() % 256; - - int minX = CWorld::GetSectorIndexX(GetPosition().x - CHECK_NEARBY_THINGS_MAX_DIST); - if (minX < 0) minX = 0; - int minY = CWorld::GetSectorIndexY(GetPosition().y - CHECK_NEARBY_THINGS_MAX_DIST); - if (minY < 0) minY = 0; - int maxX = CWorld::GetSectorIndexX(GetPosition().x + CHECK_NEARBY_THINGS_MAX_DIST); -#ifdef FIX_BUGS - if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1; + float driverDistSqr = (driver->GetPosition() - ourPos).MagnitudeSqr2D(); #else - if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X; + float driverDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); #endif - - int maxY = CWorld::GetSectorIndexY(GetPosition().y + CHECK_NEARBY_THINGS_MAX_DIST); -#ifdef FIX_BUGS - if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1; -#else - if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y; -#endif - - for (int curY = minY; curY <= maxY && !found; curY++) { - for (int curX = minX; curX <= maxX && !found; curX++) { - CSector *sector = CWorld::GetSector(curX, curY); - - for (ptrNode = sector->m_lists[ENTITYLIST_VEHICLES].first; ptrNode && !found; ptrNode = ptrNode->next) { - CVehicle *veh = (CVehicle*)ptrNode->item; - model = veh->GetModelInfo(); - if (model->GetNum2dEffects() != 0) { - for (int e = 0; e < model->GetNum2dEffects(); e++) { - effect = model->Get2dEffect(e); - if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { - objMat = &veh->GetMatrix(); - CVector effectPos = veh->GetMatrix() * effect->pos; - effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < sq(8.0f)) { - found = true; - break; - } - } - } - } - } - for (ptrNode = sector->m_lists[ENTITYLIST_OBJECTS].first; ptrNode && !found; ptrNode = ptrNode->next) { - CObject *obj = (CObject*)ptrNode->item; - model = CModelInfo::GetModelInfo(obj->GetModelIndex()); - if (model->GetNum2dEffects() != 0) { - for (int e = 0; e < model->GetNum2dEffects(); e++) { - effect = model->Get2dEffect(e); - if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { - objMat = &obj->GetMatrix(); - CVector effectPos = obj->GetMatrix() * effect->pos; - effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < sq(8.0f)) { - found = true; - break; - } - } - } - } - } - for (ptrNode = sector->m_lists[ENTITYLIST_BUILDINGS].first; ptrNode && !found; ptrNode = ptrNode->next) { - CBuilding *building = (CBuilding*)ptrNode->item; - model = CModelInfo::GetModelInfo(building->GetModelIndex()); - if (model->GetNum2dEffects() != 0) { - for (int e = 0; e < model->GetNum2dEffects(); e++) { - effect = model->Get2dEffect(e); - if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { - objMat = &building->GetMatrix(); - CVector effectPos = building->GetMatrix() * effect->pos; - effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < sq(8.0f)) { - found = true; - break; - } - } - } - } - } - for (ptrNode = sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].first; ptrNode && !found; ptrNode = ptrNode->next) { - CBuilding *building = (CBuilding*)ptrNode->item; - model = CModelInfo::GetModelInfo(building->GetModelIndex()); - if (model->GetNum2dEffects() != 0) { - for (int e = 0; e < model->GetNum2dEffects(); e++) { - effect = model->Get2dEffect(e); - if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { - objMat = &building->GetMatrix(); - CVector effectPos = building->GetMatrix() * effect->pos; - effectDist = effectPos - GetPosition(); - if (effectDist.MagnitudeSqr() < sq(8.0f)) { - found = true; - break; - } + if (sq(closestPedDist) > driverDistSqr) { + closestPedDist = Sqrt(driverDistSqr); + pedToFearFrom = nearVeh->pDriver; } } } } } - } + m_threatEntity = pedToFearFrom; + if (m_threatEntity) + m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); - if (!found) - return false; +#ifdef FIX_BUGS + if (pedToFearFrom) + flagsOfSomePed = CPedType::GetFlag(((CPed*)m_threatEntity)->m_nPedType); + else + flagsOfSomePed = 0; +#endif - CVector effectFrontLocal = Multiply3x3(*objMat, effect->attractor.dir); - float angleToFace = CGeneral::GetRadianAngleBetweenPoints(effectFrontLocal.x, effectFrontLocal.y, 0.0f, 0.0f); - randVal = CGeneral::GetRandomNumber() % 256; - if (randVal <= m_randomSeed % 256) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; - SetLookFlag(angleToFace, true); - SetLookTimer(1000); - return false; + return flagsOfSomePed; } - - CVector2D effectPos = *objMat * effect->pos; - switch (effect->attractor.type) { - case ATTRACTORTYPE_ICECREAM: - SetInvestigateEvent(EVENT_ICECREAM, effectPos, 0.1f, 15000, angleToFace); - break; - case ATTRACTORTYPE_STARE: - SetInvestigateEvent(EVENT_SHOPSTALL, effectPos, 1.0f, - CGeneral::GetRandomNumberInRange(8000, 10 * effect->attractor.probability + 8500), - angleToFace); - break; - default: - return true; - } - return true; } void -CPed::SetInvestigateEvent(eEventType event, CVector2D pos, float distanceToCountDone, uint16 time, float angle) +CPed::SetLookFlag(float direction, bool keepTryingToLook) { - if (!IsPedInControl() || CharCreatedBy == MISSION_CHAR) - return; - - SetStoredState(); - bFindNewNodeAfterStateRestore = false; - m_nPedState = PED_INVESTIGATE; - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; - m_eventType = event; - m_eventOrThreat = pos; - m_distanceToCountSeekDone = distanceToCountDone; - m_fAngleToEvent = angle; - - if (m_eventType >= EVENT_ICECREAM) - m_lookTimer = 0; - else - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 4.0f); - -} - -void -CPed::LookForSexyCars(void) -{ - CEntity *vehicles[8]; - CVehicle *veh; - int foundVehId = 0; - int bestPriceYet = 0; - int16 lastVehicle; - - if (!IsPedInControl() && m_nPedState != PED_DRIVING) - return; - if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { - CWorld::FindObjectsInRange(GetPosition(), 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - for (int vehId = 0; vehId < lastVehicle; vehId++) { - veh = (CVehicle*)vehicles[vehId]; - if (veh != m_pMyVehicle && bestPriceYet < veh->pHandling->nMonetaryValue) { - foundVehId = vehId; - bestPriceYet = veh->pHandling->nMonetaryValue; - } - } - if (lastVehicle > 0 && bestPriceYet > 40000) - SetLookFlag(vehicles[foundVehId], false); - - m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; - } -} - -void -CPed::LookForSexyPeds(void) -{ - if ((!IsPedInControl() && m_nPedState != PED_DRIVING) - || m_lookTimer >= CTimer::GetTimeInMilliseconds() || m_nPedType != PEDTYPE_CIVMALE) - return; - - for (int i = 0; i < m_numNearPeds; i++) { - if (CanSeeEntity(m_nearPeds[i])) { - if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 10.0f) { - CPed *nearPed = m_nearPeds[i]; - if ((nearPed->m_pedStats->m_sexiness > m_pedStats->m_sexiness) - && nearPed->m_nPedType == PEDTYPE_CIVFEMALE) { - - SetLookFlag(nearPed, true); - m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; - Say(SOUND_PED_CHAT_SEXY); - return; - } - } - } - } - m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; -} - -void -CPed::MakeTyresMuddySectorList(CPtrList &list) -{ - for (CPtrNode *node = list.first; node; node = node->next) { - CVehicle *veh = (CVehicle*)node->item; - if (veh->IsCar() && veh->m_scanCode != CWorld::GetCurrentScanCode()) { - veh->m_scanCode = CWorld::GetCurrentScanCode(); - - if (Abs(GetPosition().x - veh->GetPosition().x) < 10.0f) { - - if (Abs(GetPosition().y - veh->GetPosition().y) < 10.0f - && veh->m_vecMoveSpeed.MagnitudeSqr2D() > 0.05f) { - - for(int wheel = 0; wheel < 4; wheel++) { - - if (!((CAutomobile*)veh)->m_aWheelSkidmarkBloody[wheel] - && ((CAutomobile*)veh)->m_aSuspensionSpringRatio[wheel] < 1.0f) { - - CColModel *vehCol = veh->GetModelInfo()->GetColModel(); - CVector approxWheelOffset; - switch (wheel) { - case 0: - approxWheelOffset = CVector(-vehCol->boundingBox.max.x, vehCol->boundingBox.max.y, 0.0f); - break; - case 1: - approxWheelOffset = CVector(-vehCol->boundingBox.max.x, vehCol->boundingBox.min.y, 0.0f); - break; - case 2: - approxWheelOffset = CVector(vehCol->boundingBox.max.x, vehCol->boundingBox.max.y, 0.0f); - break; - case 3: - approxWheelOffset = CVector(vehCol->boundingBox.max.x, vehCol->boundingBox.min.y, 0.0f); - break; - default: - break; - } - - // I hope so - CVector wheelPos = veh->GetMatrix() * approxWheelOffset; - if (Abs(wheelPos.z - GetPosition().z) < 2.0f) { - - if ((wheelPos - GetPosition()).MagnitudeSqr2D() < 1.0f) { - if (CGame::nastyGame) { - ((CAutomobile*)veh)->m_aWheelSkidmarkBloody[wheel] = true; - DMAudio.PlayOneShot(veh->m_audioEntityId, SOUND_SPLATTER, 0.0f); - } - veh->ApplyMoveForce(CVector(0.0f, 0.0f, 50.0f)); - - CVector vehAndWheelDist = wheelPos - veh->GetPosition(); - veh->ApplyTurnForce(CVector(0.0f, 0.0f, 50.0f), vehAndWheelDist); - - if (veh == FindPlayerVehicle()) { - CPad::GetPad(0)->StartShake(300, 70); - } - } - } - } - } - } - } + bIsLooking = true; + bIsRestoringLook = false; + m_pLookTarget = nil; + m_fLookDirection = direction; + m_lookTimer = 0; + bKeepTryingToLook = keepTryingToLook; + if (m_nPedState != PED_DRIVING) { + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; } } } void -CPed::Mug(void) +CPed::SetLookFlag(CEntity *target, bool keepTryingToLook) { - if (m_pSeekTarget && m_pSeekTarget->IsPed()) { - - if (CTimer::GetTimeInMilliseconds() <= m_attackTimer - 2000) { - if ((m_pSeekTarget->GetPosition() - GetPosition()).Magnitude() > 3.0f) - m_wepSkills = 50; - - Say(SOUND_PED_MUGGING); - ((CPed*)m_pSeekTarget)->Say(SOUND_PED_ROBBED); - } else { - SetWanderPath(CGeneral::GetRandomNumber() & 7); - SetFlee(m_pSeekTarget, 20000); + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + bIsLooking = true; + bIsRestoringLook = false; + m_pLookTarget = target; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + m_fLookDirection = 999999.0f; + m_lookTimer = 0; + bKeepTryingToLook = keepTryingToLook; + if (m_nPedState != PED_DRIVING) { + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; } - - } else { - SetIdle(); } } +void +CPed::ClearLookFlag(void) { + if (bIsLooking) { + bIsLooking = false; + bIsRestoringLook = true; + bShakeFist = false; + + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; + if (IsPlayer()) + m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; + else + m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; + + if (m_nPedState == PED_LOOK_HEADING || m_nPedState == PED_LOOK_ENTITY) { + ClearLook(); + } + } +} + +void +FinishFuckUCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (animAssoc->animId == ANIM_FUCKU && ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) + ped->RemoveWeaponModel(0); +} + void CPed::MoveHeadToLook(void) { @@ -8941,150 +1030,657 @@ CPed::MoveHeadToLook(void) } void -FinishFuckUCB(CAnimBlendAssociation *animAssoc, void *arg) +CPed::RestoreHeadPosition(void) { - CPed *ped = (CPed*)arg; - - if (animAssoc->animId == ANIM_FUCKU && ped->GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) - ped->RemoveWeaponModel(0); + if (m_pedIK.RestoreLookAt()) { + bIsRestoringLook = false; + } } void -CPed::Pause(void) +CPed::SetAimFlag(float angle) { - m_moved = CVector2D(0.0f, 0.0f); - if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) - ClearPause(); + bIsAimingGun = true; + bIsRestoringGun = false; + m_fLookDirection = angle; + m_lookTimer = 0; + m_pLookTarget = nil; + m_pSeekTarget = nil; + if (CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAimWithArm) + m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; + else + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; } void -CPed::PedAnimAlignCB(CAnimBlendAssociation *animAssoc, void *arg) +CPed::SetAimFlag(CEntity *to) { - CPed *ped = (CPed*)arg; + bIsAimingGun = true; + bIsRestoringGun = false; + m_pLookTarget = to; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + m_pSeekTarget = to; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_lookTimer = 0; +} - CVehicle *veh = ped->m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (!ped->IsNotInWreckedVehicle()) - return; - - if (!ped->EnteringCar()) { -#ifdef VC_PED_PORTS - if (ped->m_nPedState != PED_DRIVING) +void +CPed::ClearAimFlag(void) +{ + if (bIsAimingGun) { + bIsAimingGun = false; + bIsRestoringGun = true; + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; +#if defined VC_PED_PORTS || defined FIX_BUGS + m_lookTimer = 0; #endif - ped->QuitEnteringCar(); - - return; - } - if (ped->m_fHealth == 0.0f) { - ped->QuitEnteringCar(); - return; - } - bool itsVan = !!veh->bIsVan; - bool itsBus = !!veh->bIsBus; -#ifdef FIX_BUGS - bool itsLow = !!veh->bLowVehicle; -#endif - eDoors enterDoor; - AnimationId enterAnim; - - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: - itsVan = false; - enterDoor = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_RR: - enterDoor = DOOR_REAR_RIGHT; - break; - case CAR_DOOR_LF: - itsVan = false; - enterDoor = DOOR_FRONT_LEFT; - break; - case CAR_DOOR_LR: - enterDoor = DOOR_REAR_LEFT; - break; - default: - break; } - if (veh->IsDoorMissing(enterDoor) || veh->IsDoorFullyOpen(enterDoor)) { + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; +} - veh->AutoPilot.m_nCruiseSpeed = 0; - if (ped->m_nPedState == PED_CARJACK) { - ped->PedAnimDoorOpenCB(nil, ped); - return; - } - if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { - if (itsVan) { - enterAnim = ANIM_VAN_GETIN; - } else if (itsBus) { - enterAnim = ANIM_COACH_IN_R; -#ifdef FIX_BUGS - } else if (itsLow) { - enterAnim = ANIM_CAR_GETIN_LOW_RHS; -#endif - } else { - enterAnim = ANIM_CAR_GETIN_RHS; - } - } else if (itsVan) { - enterAnim = ANIM_VAN_GETIN_L; - } else if (itsBus) { - enterAnim = ANIM_COACH_IN_L; -#ifdef FIX_BUGS - } else if (itsLow) { - enterAnim = ANIM_CAR_GETIN_LOW_LHS; -#endif +void +CPed::AimGun(void) +{ + CVector vector; + + if (m_pSeekTarget) { + if (m_pSeekTarget->IsPed()) { + ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(vector, PED_MID); } else { - enterAnim = ANIM_CAR_GETIN_LHS; + vector = m_pSeekTarget->GetPosition(); } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, enterAnim); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + Say(SOUND_PED_ATTACK); - } else if (veh->CanPedOpenLocks(ped)) { - - veh->AutoPilot.m_nCruiseSpeed = 0; - if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { - if (itsVan) { - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN); - } else if (itsBus) { - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_R); - } else { - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_RHS); - } - } else if (itsVan) { - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN_L); - } else if (itsBus) { - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_L); - } else { - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && veh->pDriver) { - - if (!veh->bLowVehicle - && veh->pDriver->CharCreatedBy != MISSION_CHAR - && veh->pDriver->m_nPedState == PED_DRIVING) { - - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_QJACK); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - veh->pDriver->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, true); - - if (veh->pDriver->IsGangMember()) - veh->pDriver->RegisterThreatWithGangPeds(ped); - return; - } - } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_LHS); + bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(vector); + if (m_pLookTarget != m_pSeekTarget) { + SetLookFlag(m_pSeekTarget, true); } - ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); } else { - if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_RHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_LHS); + if (IsPlayer()) { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, ((CPlayerPed*)this)->m_fFPSMoveHeading); + } else { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, 0.0f); + } + } +} - ped->bCancelEnteringCar = true; - ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); +void +CPed::RestoreGunPosition(void) +{ + if (bIsLooking) { + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; + bIsRestoringGun = false; + } else if (m_pedIK.RestoreGunPosn()) { + bIsRestoringGun = false; + } else { + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; + } +} + +void +CPed::ScanForInterestingStuff(void) +{ + if (!IsPedInControl()) + return; + + if (m_objective != OBJECTIVE_NONE) + return; + + if (CharCreatedBy == MISSION_CHAR) + return; + + LookForSexyPeds(); + LookForSexyCars(); + if (LookForInterestingNodes()) + return; + + if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { + if (CGeneral::GetRandomNumber() % 100 < 10) { + int mostExpensiveVehAround = -1; + int bestMonetaryValue = 0; + + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; + + if (veh->VehicleCreatedBy != MISSION_VEHICLE) { + if (veh->m_vecMoveSpeed.Magnitude() <= 0.1f && veh->IsVehicleNormal() + && veh->IsCar() && bestMonetaryValue < veh->pHandling->nMonetaryValue) { + mostExpensiveVehAround = i; + bestMonetaryValue = veh->pHandling->nMonetaryValue; + } + } + } + if (bestMonetaryValue > 2000 && mostExpensiveVehAround != -1 && vehicles[mostExpensiveVehAround]) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, vehicles[mostExpensiveVehAround]); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + return; + } + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + } else if (m_objective != OBJECTIVE_MUG_CHAR && !(CGeneral::GetRandomNumber() & 7)) { + CPed *charToMug = nil; + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + + if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) + break; + + if ((nearPed->m_nPedType == PEDTYPE_CIVFEMALE || nearPed->m_nPedType == PEDTYPE_CIVMALE + || nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->m_nPedType == PEDTYPE_UNUSED1 + || nearPed->m_nPedType == PEDTYPE_PROSTITUTE) + && nearPed->CharCreatedBy != MISSION_CHAR + && nearPed->IsPedShootable() + && nearPed->m_objective != OBJECTIVE_MUG_CHAR) { + charToMug = nearPed; + break; + } + } + if (charToMug) + SetObjective(OBJECTIVE_MUG_CHAR, charToMug); + + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + } + } + + if (m_nPedState == PED_WANDER_PATH) { +#ifndef VC_PED_PORTS + if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + + // += 2 is weird + for (int i = 0; i < m_numNearPeds; i += 2) { + if (m_nearPeds[i]->m_nPedState == PED_WANDER_PATH && WillChat(m_nearPeds[i])) { + if (CGeneral::GetRandomNumberInRange(0, 100) >= 100) + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + else { + if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() >= 1.8f) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + } else if (CanSeeEntity(m_nearPeds[i])) { + int time = CGeneral::GetRandomNumber() % 4000 + 10000; + SetChat(m_nearPeds[i], time); + m_nearPeds[i]->SetChat(this, time); + return; + } + } + } + } + } +#else + if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.5f) { + if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + for (int i = 0; i < m_numNearPeds; i ++) { + if (m_nearPeds[i] && m_nearPeds[i]->m_nPedState == PED_WANDER_PATH) { + if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 1.8f + && CanSeeEntity(m_nearPeds[i]) + && m_nearPeds[i]->CanSeeEntity(this) + && WillChat(m_nearPeds[i])) { + + int time = CGeneral::GetRandomNumber() % 4000 + 10000; + SetChat(m_nearPeds[i], time); + m_nearPeds[i]->SetChat(this, time); + return; + } + } + } + } + } else { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 200; + } +#endif + } + + // Parts below aren't there in VC, they're in somewhere else. + if (!CGame::noProstitutes && m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy != MISSION_CHAR + && m_objectiveTimer < CTimer::GetTimeInMilliseconds() && !CTheScripts::IsPlayerOnAMission()) { + + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; + + if (veh->IsVehicleNormal()) { + if (veh->IsCar()) { + if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil)) { + SetObjective(OBJECTIVE_SOLICIT_VEHICLE, veh); + Say(SOUND_PED_SOLICIT); + return; + } + } + } + } + } + if (m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) { + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; + + if (veh->GetModelIndex() == MI_MRWHOOP) { + if (veh->GetStatus() != STATUS_ABANDONED && veh->GetStatus() != STATUS_WRECKED) { + if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f) { + SetObjective(OBJECTIVE_BUY_ICE_CREAM, veh); + return; + } + } + } + } + } +} + +bool +CPed::WillChat(CPed *stranger) +{ + if (m_pNextPathNode && m_pLastPathNode) { + if (m_pNextPathNode != m_pLastPathNode && ThePaths.TestCrossesRoad(m_pNextPathNode, m_pLastPathNode)) { + return false; + } + } + if (m_nSurfaceTouched == SURFACE_TARMAC) + return false; + if (stranger == this) + return false; + if (m_nPedType == stranger->m_nPedType) + return true; + if (m_nPedType == PEDTYPE_CRIMINAL) + return false; + if ((IsGangMember() || stranger->IsGangMember()) && m_nPedType != stranger->m_nPedType) + return false; + return true; +} + +void +CPed::CalculateNewVelocity(void) +{ + if (IsPedInControl()) { + float headAmount = DEGTORAD(m_headingRate) * CTimer::GetTimeStep(); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + float limitedRotDest = CGeneral::LimitRadianAngle(m_fRotationDest); + + if (m_fRotationCur - PI > limitedRotDest) { + limitedRotDest += 2 * PI; + } else if(PI + m_fRotationCur < limitedRotDest) { + limitedRotDest -= 2 * PI; + } + + if (IsPlayer() && m_nPedState == PED_ATTACK) + headAmount /= 4.0f; + + float neededTurn = limitedRotDest - m_fRotationCur; + if (neededTurn <= headAmount) { + if (neededTurn > (-headAmount)) + m_fRotationCur += neededTurn; + else + m_fRotationCur -= headAmount; + } else { + m_fRotationCur += headAmount; + } + } + + CVector2D forward(Sin(m_fRotationCur), Cos(m_fRotationCur)); + + m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * Cos(m_fRotationCur)) + -Sin(m_fRotationCur) * m_vecAnimMoveDelta.y; + m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward); // m_vecAnimMoveDelta.y* Cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * Sin(m_fRotationCur)); + + if (CTimer::GetTimeStep() >= 0.01f) { + m_moved = m_moved * (1 / CTimer::GetTimeStep()); + } else { + m_moved = m_moved * (1 / 100.0f); + } + + if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam()) + || FindPlayerPed() != this || !CanStrafeOrMouseControl()) + return; + + float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur); + float pedSpeed = m_moved.Magnitude(); + float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur); + + if (localWalkAngle < -0.5f * PI) { + localWalkAngle += PI; + } else if (localWalkAngle > 0.5f * PI) { + localWalkAngle -= PI; + } + + // Interestingly this part is responsible for diagonal walking. + if (localWalkAngle > -DEGTORAD(50.0f) && localWalkAngle < DEGTORAD(50.0f)) { + TheCamera.Cams[TheCamera.ActiveCam].m_fPlayerVelocity = pedSpeed; + m_moved = CVector2D(-Sin(walkAngle), Cos(walkAngle)) * pedSpeed; + } + + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + CAnimBlendAssociation *fightAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); +#ifdef VC_PED_PORTS + if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc && !bIsDucking) { +#else + if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) { +#endif + LimbOrientation newUpperLegs; + newUpperLegs.yaw = localWalkAngle; + + if (newUpperLegs.yaw < -DEGTORAD(100.0f)) { + newUpperLegs.yaw += PI; + } else if (newUpperLegs.yaw > DEGTORAD(100.0f)) { + newUpperLegs.yaw -= PI; + } + + if (newUpperLegs.yaw > -DEGTORAD(50.0f) && newUpperLegs.yaw < DEGTORAD(50.0f)) { +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ +/* + // this looks shit + newUpperLegs.pitch = 0.0f; + RwV3d axis = { -1.0f, 0.0f, 0.0f }; + RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &axis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPRECONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &axis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPRECONCAT); +*/ + newUpperLegs.pitch = 0.1f; + RwV3d Xaxis = { 1.0f, 0.0f, 0.0f }; + RwV3d Zaxis = { 0.0f, 0.0f, 1.0f }; + RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &Zaxis, RADTODEG(newUpperLegs.pitch), rwCOMBINEPOSTCONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGL]->hanimFrame->q, &Xaxis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPOSTCONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &Zaxis, RADTODEG(newUpperLegs.pitch), rwCOMBINEPOSTCONCAT); + RtQuatRotate(&m_pFrames[PED_UPPERLEGR]->hanimFrame->q, &Xaxis, RADTODEG(newUpperLegs.yaw), rwCOMBINEPOSTCONCAT); + + bDontAcceptIKLookAts = true; + }else +#endif + { + newUpperLegs.pitch = 0.0f; + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false); + m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false); + } + } + } +} + +float +CPed::WorkOutHeadingForMovingFirstPerson(float offset) +{ + if (!IsPlayer()) + return 0.0f; + + CPad *pad0 = CPad::GetPad(0); + float leftRight = pad0->GetPedWalkLeftRight(); + float upDown = pad0->GetPedWalkUpDown(); + float &angle = ((CPlayerPed*)this)->m_fWalkAngle; + + if (upDown != 0.0f) { + angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); + } else { + if (leftRight < 0.0f) + angle = 0.5f * PI; + else if (leftRight > 0.0f) + angle = -0.5f * PI; + } + + return CGeneral::LimitRadianAngle(offset + angle); +} + +void +CPed::UpdatePosition(void) +{ + if (CReplay::IsPlayingBack() || !bIsStanding) + return; + + CVector2D velocityChange; + + SetHeading(m_fRotationCur); + if (m_pCurrentPhysSurface) { + CVector2D velocityOfSurface; + if (!IsPlayer() && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) { + + // It seems R* didn't like m_vecOffsetFromPhysSurface for boats + CVector offsetToSurface = GetPosition() - m_pCurrentPhysSurface->GetPosition(); + offsetToSurface.z -= FEET_OFFSET; + + CVector surfaceMoveVelocity = m_pCurrentPhysSurface->m_vecMoveSpeed; + CVector surfaceTurnVelocity = CrossProduct(m_pCurrentPhysSurface->m_vecTurnSpeed, offsetToSurface); + + // Also we use that weird formula instead of friction if it's boat + float slideMult = -m_pCurrentPhysSurface->m_vecTurnSpeed.MagnitudeSqr(); + velocityOfSurface = slideMult * offsetToSurface * CTimer::GetTimeStep() + (surfaceTurnVelocity + surfaceMoveVelocity); + m_vecMoveSpeed.z = slideMult * offsetToSurface.z * CTimer::GetTimeStep() + (surfaceTurnVelocity.z + surfaceMoveVelocity.z); + } else { + velocityOfSurface = m_pCurrentPhysSurface->GetSpeed(m_vecOffsetFromPhysSurface); + } + // Reminder: m_moved is displacement from walking/running. + velocityChange = m_moved + velocityOfSurface - m_vecMoveSpeed; + m_fRotationCur += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + m_fRotationDest += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); + } else if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF && (m_vecDamageNormal.x != 0.0f || m_vecDamageNormal.y != 0.0f)) { + // Ped got damaged by steep slope + m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.001f); + // some kind of + CVector2D reactionForce = m_vecDamageNormal; + reactionForce.Normalise(); + + velocityChange = 0.02f * reactionForce + m_moved; + + float reactionAndVelocityDotProd = DotProduct2D(reactionForce, velocityChange); + // they're in same direction + if (reactionAndVelocityDotProd < 0.0f) { + velocityChange -= reactionAndVelocityDotProd * reactionForce; + } + } else { + velocityChange = m_moved - m_vecMoveSpeed; + } + + // Take time step into account + if (m_pCurrentPhysSurface) { + float speedChange = velocityChange.Magnitude(); + float changeMult = speedChange; + if (m_nPedState == PED_DIE && m_pCurrentPhysSurface->IsVehicle()) { + changeMult = 0.002f * CTimer::GetTimeStep(); + } else if (!(m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat())) { + changeMult = 0.01f * CTimer::GetTimeStep(); + } + + if (speedChange > changeMult) { + velocityChange = velocityChange * (changeMult / speedChange); + } + } + m_vecMoveSpeed.x += velocityChange.x; + m_vecMoveSpeed.y += velocityChange.y; +} + +void +CPed::CalculateNewOrientation(void) +{ + if (CReplay::IsPlayingBack() || !IsPedInControl()) + return; + + SetHeading(m_fRotationCur); +} + +void +CPed::ClearAll(void) +{ + if (!IsPedInControl() && m_nPedState != PED_DEAD) + return; + + m_nPedState = PED_NONE; + m_nMoveState = PEDMOVE_NONE; + m_pSeekTarget = nil; + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + m_fleeFromPosX = 0.0f; + m_fleeFromPosY = 0.0f; + m_fleeFrom = nil; + m_fleeTimer = 0; + bUsesCollision = true; +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#else + ClearAimFlag(); + ClearLookFlag(); +#endif + bIsPointingGunAt = false; + bRenderPedInCar = true; + bKnockedUpIntoAir = false; + m_pCollidingEntity = nil; +} + +void +CPed::ProcessBuoyancy(void) +{ + static uint32 nGenerateRaindrops = 0; + static uint32 nGenerateWaterCircles = 0; + CRGBA color(((0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed()) * 127.5f), + ((0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue()) * 127.5f), + ((0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen()) * 127.5f), + (CGeneral::GetRandomNumber() % 256 * 48.0f) + 48); + + if (bInVehicle) + return; + + CVector buoyancyPoint; + CVector buoyancyImpulse; + +#ifndef VC_PED_PORTS + float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.5f : 1.3f); +#else + float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.8f : 1.1f); +#endif + + if (mod_Buoyancy.ProcessBuoyancy(this, GRAVITY * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) { + bTouchingWater = true; + CEntity *entity; + CColPoint point; + if (CWorld::ProcessVerticalLine(GetPosition(), GetPosition().z - 3.0f, point, entity, false, true, false, false, false, false, nil) + && entity->IsVehicle() && ((CVehicle*)entity)->IsBoat()) { + bIsInWater = false; + return; + } + bIsInWater = true; + ApplyMoveForce(buoyancyImpulse); + if (!DyingOrDead()) { + if (bTryingToReachDryLand) { + if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.4f * CTimer::GetTimeStep()) { + bTryingToReachDryLand = false; + CVector pos = GetPosition(); + if (PlacePedOnDryLand()) { + if (m_fHealth > 20.0f) + InflictDamage(nil, WEAPONTYPE_DROWNING, 15.0f, PEDPIECE_TORSO, false); + + if (bIsInTheAir) { + RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); + bIsInTheAir = false; + } + pos.z = pos.z - 0.8f; +#ifdef PC_PARTICLE + CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, pos, CVector(0.0f, 0.0f, 0.0f), 0.0f, 50, color, true); +#else + CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, pos, CVector(0.0f, 0.0f, 0.0f), 0.0f, 50, CRGBA(0, 0, 0, 0), true); +#endif + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_nPedState = PED_IDLE; + return; + } + } + } + float speedMult = 0.0f; + if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.75f * CTimer::GetTimeStep() + || mod_Buoyancy.m_waterlevel > GetPosition().z) { + speedMult = pow(0.9f, CTimer::GetTimeStep()); + m_vecMoveSpeed.x *= speedMult; + m_vecMoveSpeed.y *= speedMult; + m_vecMoveSpeed.z *= speedMult; + bIsStanding = false; + InflictDamage(nil, WEAPONTYPE_DROWNING, 3.0f * CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); + } + if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.25f * CTimer::GetTimeStep()) { + if (speedMult == 0.0f) { + speedMult = pow(0.9f, CTimer::GetTimeStep()); + } + m_vecMoveSpeed.x *= speedMult; + m_vecMoveSpeed.y *= speedMult; + if (m_vecMoveSpeed.z >= -0.1f) { + if (m_vecMoveSpeed.z < -0.04f) + m_vecMoveSpeed.z = -0.02f; + } else { + m_vecMoveSpeed.z = -0.01f; + DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLASH, 0.0f); +#ifdef PC_PARTICLE + CVector aBitForward = 2.2f * m_vecMoveSpeed + GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(aBitForward, &level, false)) + aBitForward.z = level; + + CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, aBitForward, CVector(0.0f, 0.0f, 0.1f), 0.0f, 200, color, true); + nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 80; + nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 100; +#else + CVector aBitForward = 1.6f * m_vecMoveSpeed + GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(aBitForward, &level, false)) + aBitForward.z = level + 0.5f; + + CVector vel = m_vecMoveSpeed * 0.1f; + vel.z = 0.18f; + CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, aBitForward, vel, 0.0f, 350, CRGBA(0, 0, 0, 0), true); + nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 300; + nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 60; +#endif + } + } + } else + return; + } else + bTouchingWater = false; + + if (nGenerateWaterCircles && CTimer::GetTimeInMilliseconds() >= nGenerateWaterCircles) { + CVector pos = GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(pos, &level, false)) + pos.z = level; + + if (pos.z != 0.0f) { + nGenerateWaterCircles = 0; + for(int i = 0; i < 4; i++) { +#ifdef PC_PARTICLE + pos.x += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); + pos.y += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); + CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, 0, 0, 0, 0); +#else + pos.x += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); + pos.y += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); + CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos+CVector(0.0f, 0.0f, 1.0f), CVector(0.0f, 0.0f, 0.0f)); +#endif + } + } + } + + if (nGenerateRaindrops && CTimer::GetTimeInMilliseconds() >= nGenerateRaindrops) { + CVector pos = GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(pos, &level, false)) + pos.z = level; + + if (pos.z >= 0.0f) { +#ifdef PC_PARTICLE + pos.z += 0.25f; +#else + pos.z += 0.5f; +#endif + nGenerateRaindrops = 0; +#ifdef PC_PARTICLE + CParticleObject::AddObject(POBJECT_SPLASHES_AROUND, pos, CVector(0.0f, 0.0f, 0.0f), 4.5f, 1500, CRGBA(0,0,0,0), true); +#else + CParticleObject::AddObject(POBJECT_SPLASHES_AROUND, pos, CVector(0.0f, 0.0f, 0.0f), 4.5f, 2500, CRGBA(0,0,0,0), true); +#endif + } } } @@ -10429,3346 +3025,458 @@ CPed::ProcessControl(void) } } -void -CPed::SetInTheAir(void) +int32 +CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) { - if (bIsInTheAir) - return; + bool collidedWithBoat = false; + bool belowTorsoCollided = false; + float gravityEffect = -0.15f * CTimer::GetTimeStep(); + CColPoint intersectionPoint; + CColLine ourLine; - bIsInTheAir = true; - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_GLIDE, 4.0f); + CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); + CColModel *hisCol = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex())->GetColModel(); - if (m_nPedState == PED_ATTACK) { - ClearAttack(); - ClearPointGunAt(); - } else if (m_nPedState == PED_FIGHT) { - EndFight(ENDFIGHT_FAST); - } + if (!bUsesCollision) + return false; -} + if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) + collidedWithBoat = true; -void -CPed::RestoreHeadPosition(void) -{ - if (m_pedIK.RestoreLookAt()) { - bIsRestoringLook = false; - } -} - -void -CPed::PointGunAt(void) -{ - CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); - if (!weaponAssoc || weaponAssoc->blendDelta < 0.0f) - weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay); - - if (weaponAssoc && weaponAssoc->currentTime > weaponInfo->m_fAnimLoopStart) { - weaponAssoc->SetCurrentTime(weaponInfo->m_fAnimLoopStart); - weaponAssoc->flags &= ~ASSOC_RUNNING; - - if (weaponInfo->m_bCanAimWithArm) - m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; - else - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; - } -} - -void -CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CAutomobile *veh = (CAutomobile*)(ped->m_pMyVehicle); - - if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) - return; - - if (ped->EnteringCar()) { - bool isLow = !!veh->bLowVehicle; - - if (!veh->bIsBus) - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_CLOSEDOOR_LHS, 1.0f); - - eDoors door; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break; - case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break; - case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; break; - case CAR_DOOR_LR: door = DOOR_REAR_LEFT; break; - default: assert(0); - } - - if (veh->Damage.GetDoorStatus(door) == DOOR_STATUS_SWINGING) - veh->Damage.SetDoorStatus(door, DOOR_STATUS_OK); - - if (door == DOOR_FRONT_LEFT || ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || veh->bIsBus) { - PedSetInCarCB(nil, ped); - } else if (ped->m_vehEnterType == CAR_DOOR_RF - && (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF || - (veh->pDriver != nil && - (veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR + // ofc we're not vehicle + if (!m_bIsVehicleBeingShifted && !bSkipLineCol #ifdef VC_PED_PORTS - && veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR_AND_DIE + && !collidingEnt->IsPed() #endif - || !veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil))))) { - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER -#if defined VC_PED_PORTS || defined FIX_BUGS - || ped->m_nPedState == PED_CARJACK -#endif - ) - veh->bIsBeingCarJacked = false; - - ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; - PedSetInCarCB(nil, ped); - - ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - if (!ped->IsPlayer()) - ped->bFleeAfterExitingCar = true; - - ped->bUsePedNodeSeek = true; - ped->m_pNextPathNode = nil; - - } else { - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSHUFFLE_RHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SHUFFLE_RHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, ped); - } - } else { + ) { + if (!bCollisionProcessed) { #ifdef VC_PED_PORTS - if (ped->m_nPedState != PED_DRIVING) + m_pCurrentPhysSurface = nil; #endif - ped->QuitEnteringCar(); - } -} - -void -CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CAutomobile* veh = (CAutomobile*)(ped->m_pMyVehicle); - - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (veh->bLowVehicle) { - veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR_LOW, 1.0f); - } else { - veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR, 1.0f); - } - - veh->m_nGettingOutFlags &= ~CAR_DOOR_FLAG_LF; - - if (veh->Damage.GetDoorStatus(DOOR_FRONT_LEFT) == DOOR_STATUS_SWINGING) - veh->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_OK); -} - -void -CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CVehicle* veh = ped->m_pMyVehicle; - - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (!ped->IsNotInWreckedVehicle()) - return; - - if (!ped->EnteringCar()) { + if (bIsStanding) { + bIsStanding = false; + bWasStanding = true; + } + bCollisionProcessed = true; + m_fCollisionSpeed += m_vecMoveSpeed.Magnitude2D() * CTimer::GetTimeStep(); + bStillOnValidPoly = false; + if (IsPlayer() || m_fCollisionSpeed >= 1.0f + && (m_fCollisionSpeed >= 2.0f || m_nPedState != PED_WANDER_PATH)) { + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + bHitSteepSlope = false; + } else { + CVector pos = GetPosition(); + float potentialGroundZ = GetPosition().z - FEET_OFFSET; + if (bWasStanding) { + pos.z += -0.25f; + potentialGroundZ += gravityEffect; + } + if (CCollision::IsStoredPolyStillValidVerticalLine(pos, potentialGroundZ, intersectionPoint, &m_collPoly)) { + bStillOnValidPoly = true; #ifdef VC_PED_PORTS - if (ped->m_nPedState != PED_DRIVING) + if(!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; + if (bSomeVCflag1) + bSomeVCflag1 = false; + } +#else + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; #endif - ped->QuitEnteringCar(); - return; - } - - eDoors door; - CPed *pedInSeat = nil; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; pedInSeat = veh->pPassengers[0]; break; - case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; pedInSeat = veh->pPassengers[2]; break; - case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; pedInSeat = veh->pDriver; break; - case CAR_DOOR_LR: door = DOOR_REAR_LEFT; pedInSeat = veh->pPassengers[1]; break; - default: assert(0); - } - - if (ped->m_fHealth == 0.0f || CPad::GetPad(0)->ArePlayerControlsDisabled() && pedInSeat && pedInSeat->IsPlayer()) { - ped->QuitEnteringCar(); - return; - } - - bool isVan = veh->bIsVan; - bool isBus = veh->bIsBus; - bool isLow = veh->bLowVehicle; - bool vehUpsideDown = veh->IsUpsideDown(); - if (ped->bCancelEnteringCar) { - if (ped->IsPlayer()) { - if (veh->pDriver) { - if (veh->pDriver->m_nPedType == PEDTYPE_COP) { - FindPlayerPed()->SetWantedLevelNoDrop(1); + m_vecMoveSpeed.z = 0.0f; + bIsStanding = true; + } else { + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + bHitSteepSlope = false; } } } -#ifdef CANCELLABLE_CAR_ENTER - if (!veh->IsDoorMissing(door) && veh->CanPedOpenLocks(ped) && veh->IsCar()) { - ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); - } + + if (!bStillOnValidPoly) { + CVector potentialCenter = GetPosition(); + potentialCenter.z = GetPosition().z - 0.52f; + + // 0.52f should be a ped's approx. radius + float totalRadiusWhenCollided = collidingEnt->GetBoundRadius() + 0.52f - gravityEffect; + if (bWasStanding) { + if (collidedWithBoat) { + potentialCenter.z += 2.0f * gravityEffect; + totalRadiusWhenCollided += Abs(gravityEffect); + } else { + potentialCenter.z += gravityEffect; + } + } + if (sq(totalRadiusWhenCollided) > (potentialCenter - collidingEnt->GetBoundCentre()).MagnitudeSqr()) { + ourLine.p0 = GetPosition(); + ourLine.p1 = GetPosition(); + ourLine.p1.z = GetPosition().z - FEET_OFFSET; + if (bWasStanding) { + ourLine.p1.z = ourLine.p1.z + gravityEffect; + ourLine.p0.z = ourLine.p0.z + -0.25f; + } + float minDist = 1.0f; + belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, + intersectionPoint, minDist, false, &m_collPoly); + + if (collidedWithBoat && bWasStanding && !belowTorsoCollided) { + ourLine.p0.z = ourLine.p1.z; + ourLine.p1.z = ourLine.p1.z + gravityEffect; + belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, + intersectionPoint, minDist, false, &m_collPoly); + } + if (belowTorsoCollided) { +#ifndef VC_PED_PORTS + if (!collidingEnt->IsPed()) { #endif - ped->QuitEnteringCar(); - ped->RestorePreviousObjective(); - ped->bCancelEnteringCar = false; - return; - } - if (!veh->IsDoorMissing(door) && veh->IsCar()) { - ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + if (!bIsStanding + || FEET_OFFSET + intersectionPoint.point.z > GetPosition().z + || collidedWithBoat && 3.12f + intersectionPoint.point.z > GetPosition().z) { + + if (!collidingEnt->IsVehicle() && !collidingEnt->IsObject()) { + m_pCurSurface = collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); + bTryingToReachDryLand = false; + bOnBoat = false; + } else { + m_pCurrentPhysSurface = (CPhysical*)collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurrentPhysSurface); + m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition(); + m_pCurSurface = collidingEnt; + collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); + m_collPoly.valid = false; + if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) { + bOnBoat = true; + } else { + bOnBoat = false; + } + } +#ifdef VC_PED_PORTS + if (!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; + if (bSomeVCflag1) + bSomeVCflag1 = false; + } +#else + GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; +#endif + m_nSurfaceTouched = intersectionPoint.surfaceB; + if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF) { + bHitSteepSlope = true; + m_vecDamageNormal = intersectionPoint.normal; + } + } +#ifdef VC_PED_PORTS + float upperSpeedLimit = 0.33f; + float lowerSpeedLimit = -0.25f; + float speed = m_vecMoveSpeed.Magnitude2D(); + if (m_nPedState == PED_IDLE) { + upperSpeedLimit *= 2.0f; + lowerSpeedLimit *= 1.5f; + } + CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); + if (!bWasStanding && speed > upperSpeedLimit && (/*!bPushedAlongByCar ||*/ m_vecMoveSpeed.z < lowerSpeedLimit) + && m_pCollidingEntity != collidingEnt) { + + float damage = 100.0f * Max(speed - 0.25f, 0.0f); + float damage2 = damage; + if (m_vecMoveSpeed.z < -0.25f) + damage += (-0.25f - m_vecMoveSpeed.z) * 150.0f; + + uint8 dir = 2; // from backward + if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { + CVector2D offset = -m_vecMoveSpeed; + dir = GetLocalDirection(offset); + } + + InflictDamage(collidingEnt, WEAPONTYPE_FALL, damage, PEDPIECE_TORSO, dir); + if (IsPlayer() && damage2 > 5.0f) + Say(SOUND_PED_LAND); + + } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { + InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); + } +#else + float speedSqr = 0.0f; + CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); + if (!bWasStanding && (m_vecMoveSpeed.z < -0.25f || (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) > sq(0.5f))) { + if (speedSqr == 0.0f) + speedSqr = sq(m_vecMoveSpeed.z); + + uint8 dir = 2; // from backward + if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { + CVector2D offset = -m_vecMoveSpeed; + dir = GetLocalDirection(offset); + } + InflictDamage(collidingEnt, WEAPONTYPE_FALL, 350.0f * sq(speedSqr), PEDPIECE_TORSO, dir); + + } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { + InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); + } +#endif + m_vecMoveSpeed.z = 0.0f; + bIsStanding = true; +#ifndef VC_PED_PORTS + } else { + bOnBoat = false; + } +#endif + } else { + bOnBoat = false; + } + } + } } - if (veh->m_vecMoveSpeed.Magnitude() > 0.2f) { - ped->QuitEnteringCar(); - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) - ped->SetFall(1000, ANIM_KO_SPIN_R, false); - else - ped->SetFall(1000, ANIM_KO_SPIN_L, false); + int ourCollidedSpheres = CCollision::ProcessColModels(GetMatrix(), *ourCol, collidingEnt->GetMatrix(), *hisCol, collidingPoints, nil, nil); + if (ourCollidedSpheres > 0 || belowTorsoCollided) { + AddCollisionRecord(collidingEnt); + if (!collidingEnt->IsBuilding()) + ((CPhysical*)collidingEnt)->AddCollisionRecord(this); + + if (ourCollidedSpheres > 0 && (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic())) { + bHasHitWall = true; + } + } + if (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic()) { + + if (bWasStanding) { + CVector sphereNormal; + float normalLength; + for(int sphere = 0; sphere < ourCollidedSpheres; sphere++) { + sphereNormal = collidingPoints[sphere].normal; +#ifdef VC_PED_PORTS + if (sphereNormal.z >= -1.0f || !IsPlayer()) { +#endif + normalLength = sphereNormal.Magnitude2D(); + if (normalLength != 0.0f) { + sphereNormal.x = sphereNormal.x / normalLength; + sphereNormal.y = sphereNormal.y / normalLength; + } +#ifdef VC_PED_PORTS + } else { + float speed = m_vecMoveSpeed.Magnitude2D(); + sphereNormal.x = -m_vecMoveSpeed.x / Max(0.001f, speed); + sphereNormal.y = -m_vecMoveSpeed.y / Max(0.001f, speed); + GetMatrix().GetPosition().z -= 0.05f; + bSomeVCflag1 = true; + } +#endif + sphereNormal.Normalise(); + collidingPoints[sphere].normal = sphereNormal; + if (collidingPoints[sphere].surfaceB == SURFACE_STEEP_CLIFF) + bHitSteepSlope = true; + } + } + } + return ourCollidedSpheres; +} + +static void +particleProduceFootSplash(CPed *ped, CVector const &pos, float size, int times) +{ +#ifdef PC_PARTICLE + for (int i = 0; i < times; i++) { + CVector adjustedPos = pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + + CVector direction = ped->GetForward() * -0.05f; + CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, direction, nil, size, CRGBA(32, 32, 32, 32), 0, 0, CGeneral::GetRandomNumber() & 1, 200); + } +#else + for ( int32 i = 0; i < times; i++ ) + { + CVector adjustedPos = pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.2f, 0.2f); + + CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, CGeneral::GetRandomNumber() & 1, 200); + } +#endif +} + +static void +particleProduceFootDust(CPed *ped, CVector const &pos, float size, int times) +{ + switch (ped->m_nSurfaceTouched) + { + case SURFACE_TARMAC: + case SURFACE_GRAVEL: + case SURFACE_PAVEMENT: + case SURFACE_SAND: + for (int i = 0; i < times; ++i) { + CVector adjustedPos = pos; + adjustedPos.x += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + adjustedPos.y += CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + CParticle::AddParticle(PARTICLE_PEDFOOT_DUST, adjustedPos, CVector(0.0f, 0.0f, 0.0f), nil, size, CRGBA(0, 0, 0, 0), 0, 0, 0, 0); + } + break; + default: + break; + } +} + +void +CPed::PlayFootSteps(void) +{ + if (bDoBloodyFootprints) { + if (m_bloodyFootprintCountOrDeathTime > 0 && m_bloodyFootprintCountOrDeathTime < 300) { + m_bloodyFootprintCountOrDeathTime--; + + if (m_bloodyFootprintCountOrDeathTime == 0) + bDoBloodyFootprints = false; + } + } + + if (!bIsStanding) + return; + + CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); + CAnimBlendAssociation *walkRunAssoc = nil; + float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; + + for (; assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (assoc->flags & ASSOC_WALK) { + walkRunAssoc = assoc; + walkRunAssocBlend += assoc->blendAmount; + } else if ((assoc->flags & ASSOC_NOWALK) == 0) { + idleAssocBlend += assoc->blendAmount; + } + } + +#ifdef GTA_PS2_STUFF + CAnimBlendAssociation *runStopAsoc = NULL; + + if ( IsPlayer() ) + { + runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); - return; + if ( runStopAsoc == NULL ) + runStopAsoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); } - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_OPEN_LHS, 1.0f); - - if (ped->m_vehEnterType == CAR_DOOR_LF || ped->m_vehEnterType == CAR_DOOR_RF) - isVan = false; - - if (ped->m_nPedState != PED_CARJACK || isBus) { - AnimationId animToPlay; - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { - - if (isVan) { - animToPlay = ANIM_VAN_GETIN; - } else if (isBus) { - animToPlay = ANIM_COACH_IN_R; - } else if (isLow) { - animToPlay = ANIM_CAR_GETIN_LOW_RHS; - } else { - animToPlay = ANIM_CAR_GETIN_RHS; - } - } else if (isVan) { - animToPlay = ANIM_VAN_GETIN_L; - } else if (isBus) { - animToPlay = ANIM_COACH_IN_L; - } else if (isLow) { - animToPlay = ANIM_CAR_GETIN_LOW_LHS; - } else { - animToPlay = ANIM_CAR_GETIN_LHS; - } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } else { - CPed *pedToDragOut = nil; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: pedToDragOut = veh->pPassengers[0]; break; - case CAR_DOOR_RR: pedToDragOut = veh->pPassengers[2]; break; - case CAR_DOOR_LF: pedToDragOut = veh->pDriver; break; - case CAR_DOOR_LR: pedToDragOut = veh->pPassengers[1]; break; - default: assert(0); - } - - if (vehUpsideDown) { - ped->QuitEnteringCar(); - if (ped->m_nPedType == PEDTYPE_COP) - ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); - } - - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { - if (pedToDragOut && !pedToDragOut->bDontDragMeOutCar) { - if (pedToDragOut->m_nPedState != PED_DRIVING) { - ped->QuitEnteringCar(); - pedToDragOut = nil; - } else { - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_RHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_RHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); - } - } else if (ped->m_nPedType == PEDTYPE_COP) { - ped->QuitEnteringCar(); - if (ped->m_pedInObjective && ped->m_pedInObjective->m_nPedState == PED_DRIVING) { - veh->SetStatus(STATUS_PLAYER_DISABLED); - ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); - } else if (!veh->IsDoorMissing(DOOR_FRONT_RIGHT)) { - ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_SWINGING); - } - } else { - // BUG: Probably we will sit on top of the passenger if his m_ped_flagF4 is true. - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } - } else { - if (pedToDragOut) { - if (pedToDragOut->m_nPedState != PED_DRIVING || pedToDragOut->bDontDragMeOutCar) { - - // BUG: Player freezes in that condition due to its objective isn't restored. It's an unfinished feature, used in VC. - ped->QuitEnteringCar(); - pedToDragOut = nil; - } else { - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_LHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); - } - } else { - if (isLow) - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); - else - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); - - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } - } - - if (pedToDragOut) { - pedToDragOut->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, false); - if (pedToDragOut->IsGangMember()) - pedToDragOut->RegisterThreatWithGangPeds(ped); - } - } - - if (veh->pDriver && ped) { - veh->pDriver->SetLookFlag(ped, true); - veh->pDriver->SetLookTimer(1000); - } - return; -} - -void -CPed::SetJump(void) -{ - if (!bInVehicle && -#if defined VC_PED_PORTS || defined FIX_BUGS - m_nPedState != PED_JUMP && !RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_LAUNCH) && -#endif - (m_nSurfaceTouched != SURFACE_STEEP_CLIFF || DotProduct(GetForward(), m_vecDamageNormal) >= 0.0f)) { - SetStoredState(); - m_nPedState = PED_JUMP; - CAnimBlendAssociation *jumpAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_JUMP_LAUNCH, 8.0f); - jumpAssoc->SetFinishCallback(FinishLaunchCB, this); - m_fRotationDest = m_fRotationCur; - } -} - -void -CPed::RemoveInCarAnims(void) -{ - if (!IsPlayer()) - return; - - CAnimBlendAssociation *animAssoc; - - if (m_pMyVehicle && m_pMyVehicle->bLowVehicle) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - } else { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - } - -#ifdef VC_PED_PORTS - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_BOAT); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; -#endif - - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); - if (animAssoc) - animAssoc->blendDelta = -1000.0f; -} - -void -CPed::PedAnimGetInCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*) arg; - - CVehicle *veh = ped->m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) - return; - - if (!ped->EnteringCar()) { -#ifdef VC_PED_PORTS - if(ped->m_nPedState != PED_DRIVING) -#endif - ped->QuitEnteringCar(); - return; - } - - if (ped->IsPlayer() && ped->bGonnaKillTheCarJacker && ((CPlayerPed*)ped)->m_pArrestingCop) { - PedSetInCarCB(nil, ped); - ped->m_nLastPedState = ped->m_nPedState; - ped->m_nPedState = PED_ARRESTED; - ped->bGonnaKillTheCarJacker = false; - if (veh) { - veh->m_nNumGettingIn = 0; - veh->m_nGettingInFlags = 0; - veh->bIsHandbrakeOn = true; - veh->SetStatus(STATUS_PLAYER_DISABLED); - } - return; - } - if (ped->IsPlayer() && ped->m_vehEnterType == CAR_DOOR_LF - && (Pads[0].GetAccelerate() >= 255.0f || Pads[0].GetBrake() >= 255.0f) - && veh->IsCar()) { - if (((CAutomobile*)veh)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) != DOOR_STATUS_MISSING) - ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING); - - PedSetInCarCB(nil, ped); - return; - } - bool isVan = !!veh->bIsVan; - bool isBus = !!veh->bIsBus; - bool isLow = !!veh->bLowVehicle; - eDoors enterDoor; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: - isVan = false; - enterDoor = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_RR: - enterDoor = DOOR_REAR_RIGHT; - break; - case CAR_DOOR_LF: - isVan = false; - enterDoor = DOOR_FRONT_LEFT; - break; - case CAR_DOOR_LR: - enterDoor = DOOR_REAR_LEFT; - break; - default: - break; - } - if (!veh->IsDoorMissing(enterDoor)) { - if (veh->IsCar()) - ((CAutomobile*)veh)->Damage.SetDoorStatus(enterDoor, DOOR_STATUS_SWINGING); - } - CPed *driver = veh->pDriver; - if (driver && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { - if (veh->bIsBus) { - driver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - if (driver->IsPlayer()) { - veh->bIsHandbrakeOn = true; - veh->SetStatus(STATUS_PLAYER_DISABLED); - } - driver->bBusJacked = true; - veh->bIsBeingCarJacked = false; - PedSetInCarCB(nil, ped); - if (ped->m_nPedType == PEDTYPE_COP - || ped->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT - || ped->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { - ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - } - ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 400; - return; - } - if (driver != ped && ped->m_vehEnterType != CAR_DOOR_LF) { - if (!driver->IsPlayer()) { - driver->bUsePedNodeSeek = true; - driver->m_pLastPathNode = nil; - if (driver->m_pedStats->m_temper <= driver->m_pedStats->m_fear - || driver->CharCreatedBy == MISSION_CHAR - || veh->VehicleCreatedBy == MISSION_VEHICLE) { - driver->bFleeAfterExitingCar = true; - } else { - driver->bGonnaKillTheCarJacker = true; - veh->pDriver->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped); - - if (veh->pDriver->m_nPedType == PEDTYPE_COP && ped->IsPlayer()) { - FindPlayerPed()->SetWantedLevelNoDrop(1); - } - } - } - if ((ped->m_nPedType != PEDTYPE_EMERGENCY || veh->pDriver->m_nPedType != PEDTYPE_EMERGENCY) - && (ped->m_nPedType != PEDTYPE_COP || veh->pDriver->m_nPedType != PEDTYPE_COP)) { - veh->pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - veh->pDriver->Say(SOUND_PED_CAR_JACKED); -#ifdef VC_PED_PORTS - veh->pDriver->SetRadioStation(); -#endif - } else { - ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; - } - } - } - if (veh->IsDoorMissing(enterDoor) || isBus) { - PedAnimDoorCloseCB(nil, ped); - } else { - AnimationId animToPlay; - if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { - if (isVan) { - animToPlay = ANIM_VAN_CLOSE; - } else if (isLow) { - animToPlay = ANIM_CAR_CLOSEDOOR_LOW_RHS; - } else { - animToPlay = ANIM_CAR_CLOSEDOOR_RHS; - } - } else if (isVan) { - animToPlay = ANIM_VAN_CLOSE_L; - } else if (isLow) { - animToPlay = ANIM_CAR_CLOSEDOOR_LOW_LHS; - } else { - animToPlay = ANIM_CAR_CLOSEDOOR_LHS; - } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorCloseCB, ped); - } -} - -void -CPed::SetPedPositionInTrain(void) -{ - LineUpPedWithTrain(); -} - -void -CPed::PedAnimPullPedOutCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CVehicle* veh = ped->m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (ped->EnteringCar()) { - if (!ped->IsNotInWreckedVehicle()) - return; - -#ifdef CANCELLABLE_CAR_ENTER - if (ped->bCancelEnteringCar) { - ped->QuitEnteringCar(); - ped->RestorePreviousObjective(); - ped->bCancelEnteringCar = false; - return; - } -#endif - - bool isLow = !!veh->bLowVehicle; - - int padNo; - if (ped->IsPlayer()) { - - // BUG? This will cause crash if m_nPedType is bigger then 1, there are only 2 pads - switch (ped->m_nPedType) { - case PEDTYPE_PLAYER1: - padNo = 0; - break; - case PEDTYPE_PLAYER2: - padNo = 1; - break; - case PEDTYPE_PLAYER3: - padNo = 2; - break; - case PEDTYPE_PLAYER4: - padNo = 3; - break; - } - CPad *pad = CPad::GetPad(padNo); - - if (!pad->ArePlayerControlsDisabled()) { - - if (pad->GetTarget() - || pad->NewState.LeftStickX - || pad->NewState.LeftStickY - || pad->NewState.DPadUp - || pad->NewState.DPadDown - || pad->NewState.DPadLeft - || pad->NewState.DPadRight) { - ped->QuitEnteringCar(); - ped->RestorePreviousObjective(); - return; - } - } - } - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - AnimationId animToPlay; - if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { - if (isLow) - animToPlay = ANIM_CAR_GETIN_LOW_RHS; - else - animToPlay = ANIM_CAR_GETIN_RHS; - } else if (isLow) { - animToPlay = ANIM_CAR_GETIN_LOW_LHS; - } else { - animToPlay = ANIM_CAR_GETIN_LHS; - } - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); - ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); - } else { - ped->QuitEnteringCar(); - } - } else { - ped->QuitEnteringCar(); - } -} - -void -CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - CVehicle* veh = ped->m_pMyVehicle; - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - if (!veh) { - PedSetOutCarCB(nil, ped); - return; - } -#ifdef VC_PED_PORTS - CVector posForZ = ped->GetPosition(); - CPedPlacement::FindZCoorForPed(&posForZ); - if (ped->GetPosition().z - 0.5f > posForZ.z) { - PedSetOutCarCB(nil, ped); - return; - } -#endif - veh->m_nStaticFrames = 0; - veh->m_vecMoveSpeed += CVector(0.001f, 0.001f, 0.001f); - veh->m_vecTurnSpeed += CVector(0.001f, 0.001f, 0.001f); - if (!veh->bIsBus) - veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_GETOUT_LHS, 1.0f); - - /* - // Duplicate and only in PC for some reason - if (!veh) { - PedSetOutCarCB(nil, ped); - return; - } - */ - eDoors door; - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: - door = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_RR: - door = DOOR_REAR_RIGHT; - break; - case CAR_DOOR_LF: - door = DOOR_FRONT_LEFT; - break; - case CAR_DOOR_LR: - door = DOOR_REAR_LEFT; - break; - default: - break; - } - bool closeDoor = !veh->IsDoorMissing(door); - - int padNo; - if (ped->IsPlayer()) { - - // BUG? This will cause crash if m_nPedType is bigger then 1, there are only 2 pads - switch (ped->m_nPedType) { - case PEDTYPE_PLAYER1: - padNo = 0; - break; - case PEDTYPE_PLAYER2: - padNo = 1; - break; - case PEDTYPE_PLAYER3: - padNo = 2; - break; - case PEDTYPE_PLAYER4: - padNo = 3; - break; - } - CPad* pad = CPad::GetPad(padNo); - bool engineIsIntact = veh->IsCar() && ((CAutomobile*)veh)->Damage.GetEngineStatus() >= 225; - if (!pad->ArePlayerControlsDisabled() && veh->m_nDoorLock != CARLOCK_FORCE_SHUT_DOORS - && (pad->GetTarget() - || pad->NewState.LeftStickX - || pad->NewState.LeftStickY - || pad->NewState.DPadUp - || pad->NewState.DPadDown - || pad->NewState.DPadLeft - || pad->NewState.DPadRight) - || veh->bIsBus - || veh->m_pCarFire - || engineIsIntact) { - closeDoor = false; - } - } - -#ifdef VC_PED_PORTS - if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) - closeDoor = false; -#endif - - if (!closeDoor) { - if (!veh->IsDoorMissing(door) && !veh->bIsBus) { - ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); - } - PedSetOutCarCB(nil, ped); - return; - } - - if (ped->bFleeAfterExitingCar || ped->bGonnaKillTheCarJacker) { - // POTENTIAL BUG? Why DOOR_FRONT_LEFT instead of door variable? or vice versa? - if (!veh->IsDoorMissing(door)) - ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING); - } else { - switch (door) { - case DOOR_FRONT_LEFT: - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_LHS); - break; - case DOOR_FRONT_RIGHT: - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_RHS); - break; - case DOOR_REAR_LEFT: - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_LHS); - break; - case DOOR_REAR_RIGHT: - ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_RHS); - break; - default: - break; - } - } - - if (ped->m_pVehicleAnim) - ped->m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, ped); - return; -} - -void -CPed::PedEvadeCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - if (!animAssoc) { - ped->ClearLookFlag(); - if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) - ped->RestorePreviousState(); - } else if (animAssoc->animId == ANIM_EV_DIVE) { - ped->bUpdateAnimHeading = true; - ped->ClearLookFlag(); - if (ped->m_nPedState == PED_DIVE_AWAY) + if ( runStopAsoc != NULL && runStopAsoc->blendAmount > 0.1f ) + { { - ped->m_getUpTimer = CTimer::GetTimeInMilliseconds() + 1; - ped->m_nPedState = PED_FALL; - } - animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - - } else if (animAssoc->flags & ASSOC_FADEOUTWHENDONE) { - ped->ClearLookFlag(); - if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) - ped->RestorePreviousState(); - - } else if (ped->m_nPedState != PED_ARRESTED) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (animAssoc->blendDelta >= 0.0f) - animAssoc->blendDelta = -4.0f; - - ped->ClearLookFlag(); - if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) { - ped->RestorePreviousState(); - } - } -} - -void -CPed::PedGetupCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - if (ped->m_nPedState == PED_GETUP) - RpAnimBlendClumpSetBlendDeltas(ped->GetClump(), ASSOC_PARTIAL, -1000.0f); - - ped->bFallenDown = false; - animAssoc->blendDelta = -1000.0f; - if (ped->m_nPedState == PED_GETUP) - ped->RestorePreviousState(); - - if (ped->m_nPedState != PED_FLEE_POS && ped->m_nPedState != PED_FLEE_ENTITY) - ped->SetMoveState(PEDMOVE_STILL); - else - ped->SetMoveState(PEDMOVE_RUN); - - ped->SetMoveAnim(); - ped->bGetUpAnimStarted = false; -} - -void -CPed::PedLandCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed* ped = (CPed*)arg; - - animAssoc->blendDelta = -1000.0f; - ped->bIsLanding = false; - - if (ped->m_nPedState == PED_JUMP) - ped->RestorePreviousState(); -} - -void -CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed *ped = (CPed*)arg; - - ped->bUsesCollision = true; - ped->RestartNonPartialAnims(); - bool itsRearDoor = false; - - if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) - itsRearDoor = true; - - CMatrix pedMat(ped->GetMatrix()); - CVector posAfterBeingDragged = Multiply3x3(pedMat, (itsRearDoor ? -vecPedDraggedOutCarAnimOffset : vecPedDraggedOutCarAnimOffset)); - posAfterBeingDragged += ped->GetPosition(); -#ifndef VC_PED_PORTS - posAfterBeingDragged.z += 1.0f; -#endif - CPedPlacement::FindZCoorForPed(&posAfterBeingDragged); - ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - ped->SetPosition(posAfterBeingDragged); - - if (ped->m_pMyVehicle && !ped->m_pMyVehicle->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedDraggedOutCarAnimOffset)) { - ped->PositionPedOutOfCollision(); - } - - if (!ped->CanSetPedState()) - return; - - if (!ped->m_pMyVehicle) { - ped->SetIdle(); - ped->SetGetUp(); - return; - } - - CPed *driver = ped->m_pMyVehicle->pDriver; - - if (ped->IsPlayer()) { - ped->SetIdle(); - - } else if (ped->bFleeAfterExitingCar) { - ped->bFleeAfterExitingCar = false; - ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); - - } else if (ped->bWanderPathAfterExitingCar) { - ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - ped->bWanderPathAfterExitingCar = false; - - } else if (ped->bGonnaKillTheCarJacker) { - // Kill objective is already set at this point. - - ped->bGonnaKillTheCarJacker = false; - if (!ped->m_pedInObjective || !(CGeneral::GetRandomNumber() & 1)) { - if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { - ped->m_nPedState = PED_NONE; - ped->m_nLastPedState = PED_NONE; - ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); - } else { - ped->ClearObjective(); - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); - } - } - - } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR - && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && driver - && driver->IsPlayer() && !CTheScripts::IsPlayerOnAMission()) { - -#ifndef VC_PED_PORTS - if (CGeneral::GetRandomNumber() & 1) - ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, driver); - else -#endif - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); - - } else { -#ifdef VC_PED_PORTS - if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR - && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && !driver - && FindPlayerPed()->m_carInObjective == ped->m_pMyVehicle && !CTheScripts::IsPlayerOnAMission()) - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); - else -#endif - { - ped->m_nPedState = PED_NONE; - ped->m_nLastPedState = PED_NONE; - ped->SetFindPathAndFlee(ped->m_pMyVehicle->GetPosition(), 10000); - } - } - ped->SetGetUp(); -} - -void -CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - // Pointless code - if (!veh) - return; - -#ifdef VC_PED_PORTS - // Situation of entering car as a driver while there is already a driver exiting atm. - CPed *driver = veh->pDriver; - if (driver && driver->m_nPedState == PED_DRIVING && !veh->bIsBus && driver->m_objective == OBJECTIVE_LEAVE_CAR - && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { - - if (!ped->IsPlayer() && (ped->CharCreatedBy != MISSION_CHAR || driver->IsPlayer())) { - ped->QuitEnteringCar(); - return; - } - if (driver->CharCreatedBy == MISSION_CHAR) { - PedSetOutCarCB(nil, veh->pDriver); - if (driver->m_pMyVehicle) { - driver->PositionPedOutOfCollision(); - } else { - driver->m_pMyVehicle = veh; - driver->PositionPedOutOfCollision(); - driver->m_pMyVehicle = nil; - } - veh->pDriver = nil; - } else { - driver->SetDead(); - driver->FlagToDestroyWhenNextProcessed(); - veh->pDriver = nil; - } - } -#endif - - if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) - return; - - ped->bInVehicle = true; - if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { - if (veh->pDriver) { - if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { - CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 1000; - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; - CWorld::Players[CWorld::PlayerInFocus].m_pHooker = (CCivilianPed*)ped; - } - } - } - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER -#if defined VC_PED_PORTS || defined FIX_BUGS - || ped->m_nPedState == PED_CARJACK -#endif - ) - veh->bIsBeingCarJacked = false; - - if (veh->m_nNumGettingIn) - --veh->m_nNumGettingIn; - - if (ped->IsPlayer() && ((CPlayerPed*)ped)->m_bAdrenalineActive) - ((CPlayerPed*)ped)->ClearAdrenaline(); - - if (veh->IsBoat()) { - if (ped->IsPlayer()) { -#if defined VC_PED_PORTS || defined FIX_BUGS - CCarCtrl::RegisterVehicleOfInterest(veh); -#endif - if (veh->GetStatus() == STATUS_SIMPLE) { - veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.00001f); - veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - } - veh->SetStatus(STATUS_PLAYER); - AudioManager.PlayerJustGotInCar(); - } - veh->SetDriver(ped); - if (!veh->bEngineOn) - veh->bEngineOn = true; - - ped->m_nPedState = PED_DRIVING; - ped->StopNonPartialAnims(); - return; - } - - if (ped->m_pVehicleAnim) - ped->m_pVehicleAnim->blendDelta = -1000.0f; - - ped->bDoBloodyFootprints = false; - if (veh->m_nAlarmState == -1) - veh->m_nAlarmState = 15000; - - if (ped->IsPlayer()) { - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (veh->GetStatus() == STATUS_SIMPLE) { - veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - } - veh->SetStatus(STATUS_PLAYER); - } - AudioManager.PlayerJustGotInCar(); - } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (veh->GetStatus() == STATUS_SIMPLE) { - veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - } - veh->SetStatus(STATUS_PHYSICS); - } - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - for (int i = 0; i < veh->m_nNumMaxPassengers; ++i) { - CPed *passenger = veh->pPassengers[i]; - if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) { - passenger->SetObjective(OBJECTIVE_LEAVE_CAR, veh); -#ifdef VC_PED_PORTS - passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds(); -#endif - } - } - } - // This shouldn't happen at all. Passengers can't enter with PED_CARJACK. Even though they did, we shouldn't call AddPassenger in here and SetDriver in below. -#if !defined VC_PED_PORTS && !defined FIX_BUGS - else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (ped->m_nPedState == PED_CARJACK) { - veh->AddPassenger(ped, 0); - ped->m_nPedState = PED_DRIVING; - ped->RestorePreviousObjective(); - ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); - } else if (veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) { - veh->AutoPilot.m_nCruiseSpeed = 17; - } - } -#endif - - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK) { - veh->SetDriver(ped); - if (veh->VehicleCreatedBy == PARKED_VEHICLE) { - veh->VehicleCreatedBy = RANDOM_VEHICLE; - ++CCarCtrl::NumRandomCars; - --CCarCtrl::NumParkedCars; - } - if (veh->bIsAmbulanceOnDuty) { - veh->bIsAmbulanceOnDuty = false; - --CCarCtrl::NumAmbulancesOnDuty; - } - if (veh->bIsFireTruckOnDuty) { - veh->bIsFireTruckOnDuty = false; - --CCarCtrl::NumFiretrucksOnDuty; - } - if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) - veh->ChangeLawEnforcerState(true); - - if (!veh->bEngineOn) { - veh->bEngineOn = true; - DMAudio.PlayOneShot(ped->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); - } - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && ped->CharCreatedBy == RANDOM_CHAR - && ped != FindPlayerPed() && ped->m_nPedType != PEDTYPE_EMERGENCY) { - - CCarCtrl::JoinCarWithRoadSystem(veh); - veh->AutoPilot.m_nCarMission = MISSION_CRUISE; - veh->AutoPilot.m_nTempAction = TEMPACT_NONE; - veh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - veh->AutoPilot.m_nCruiseSpeed = 25; - } - ped->m_nPedState = PED_DRIVING; - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - - if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) - ped->m_prevObjective = OBJECTIVE_NONE; - - ped->RestorePreviousObjective(); - } - - } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (veh->bIsBus) { - veh->AddPassenger(ped); - } else { - switch (ped->m_vehEnterType) { - case CAR_DOOR_RF: - veh->AddPassenger(ped, 0); - break; - case CAR_DOOR_RR: - veh->AddPassenger(ped, 2); - break; - case CAR_DOOR_LR: - veh->AddPassenger(ped, 1); - break; - default: - veh->AddPassenger(ped); - break; - } - } - ped->m_nPedState = PED_DRIVING; - if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) - ped->m_prevObjective = OBJECTIVE_NONE; - - ped->RestorePreviousObjective(); -#ifdef VC_PED_PORTS - if(veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) - veh->AutoPilot.m_nCruiseSpeed = 17; -#endif - } - - veh->m_nGettingInFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); - - if (veh->bIsBus && !veh->m_nGettingInFlags) - ((CAutomobile*)veh)->SetBusDoorTimer(1000, 1); - - switch (ped->m_objective) { - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_FOLLOW_CAR_IN_CAR: - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - break; - default: - ped->SetObjective(OBJECTIVE_NONE); - } - - if (veh->pDriver == ped) { - if (veh->bLowVehicle) { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); - } else { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); - } - } else if (veh->bLowVehicle) { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITPLO, 100.0f); - } else { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITP, 100.0f); - } - - ped->StopNonPartialAnims(); - if (veh->bIsBus) - ped->bRenderPedInCar = false; - - // FIX: RegisterVehicleOfInterest not just registers the vehicle, but also updates register time. So remove the IsThisVehicleInteresting check. -#ifndef FIX_BUGS - if (ped->IsPlayer() && !CCarCtrl::IsThisVehicleInteresting(veh) && veh->VehicleCreatedBy != MISSION_VEHICLE) { -#else - if (ped->IsPlayer() && veh->VehicleCreatedBy != MISSION_VEHICLE) { -#endif - CCarCtrl::RegisterVehicleOfInterest(veh); - - if (!veh->bHasBeenOwnedByPlayer && veh->VehicleCreatedBy != MISSION_VEHICLE) - CEventList::RegisterEvent(EVENT_STEAL_CAR, EVENT_ENTITY_VEHICLE, veh, ped, 1500); - - veh->bHasBeenOwnedByPlayer = true; - } - ped->bChangedSeat = true; -} - -void -CPed::PedSetInTrainCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - CPed *ped = (CPed*)arg; - CTrain *veh = (CTrain*)ped->m_pMyVehicle; - - if (!veh) - return; - - ped->bInVehicle = true; - ped->m_nPedState = PED_DRIVING; - ped->RestorePreviousObjective(); - ped->SetMoveState(PEDMOVE_STILL); - veh->AddPassenger(ped); -} - -void -CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) -{ - /* - CPed *ped = (CPed*)arg; - - if (ped->m_nPedState == PED_STAGGER) - // nothing - */ -} - -// It's "CPhoneInfo::ProcessNearestFreePhone" in PC IDB but that's not true, someone made it up. -bool -CPed::RunToReportCrime(eCrimeType crimeToReport) -{ -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - if (bRunningToPhone) { - if (!isPhoneAvailable(m_phoneId)) { - m_phoneId = -1; - bIsRunning = false; - ClearSeek(); // clears bRunningToPhone - return false; - } - - return true; - } -#else - // They changed true into false to make this function unusable. So running to phone actually starts but first frame after that cancels it. - if (m_nPedState == PED_SEEK_POS) - return false; -#endif - - CVector pos = GetPosition(); - int phoneId = gPhoneInfo.FindNearestFreePhone(&pos); - - if (phoneId == -1) - return false; - - CPhone *phone = &gPhoneInfo.m_aPhones[phoneId]; -#ifndef PEDS_REPORT_CRIMES_ON_PHONE - if (phone->m_nState != PHONE_STATE_FREE) - return false; -#endif - - bRunningToPhone = true; - SetSeek(phone->m_pEntity->GetMatrix() * -phone->m_pEntity->GetForward(), 1.0f); // original: phone.m_vecPos, 0.3f - SetMoveState(PEDMOVE_RUN); - bIsRunning = true; // not there in original - m_phoneId = phoneId; - m_crimeToReportOnPhone = crimeToReport; - return true; -} - -void -CPed::RegisterThreatWithGangPeds(CEntity *attacker) -{ - CPed *attackerPed = nil; - if (attacker) { - if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS) { - if (attacker->IsPed()) { - attackerPed = (CPed*)attacker; - } else { - if (!attacker->IsVehicle()) - return; - - attackerPed = ((CVehicle*)attacker)->pDriver; - if (!attackerPed) - return; - } - - if (attackerPed && (attackerPed->IsPlayer() || attackerPed->IsGangMember())) { - for (int i = 0; i < m_numNearPeds; ++i) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed->IsPointerValid()) { - if (nearPed != this && nearPed->m_nPedType == m_nPedType) - nearPed->m_fearFlags |= CPedType::GetFlag(attackerPed->m_nPedType); - } - } - } - } - } - - if (attackerPed && attackerPed->IsPlayer() && (attackerPed->m_nPedState == PED_CARJACK || attackerPed->bInVehicle)) { - if (!attackerPed->m_pMyVehicle || attackerPed->m_pMyVehicle->GetModelIndex() != MI_TOYZ) { - int16 lastVehicle; - CEntity *vehicles[8]; - CWorld::FindObjectsInRange(GetPosition(), ENTER_CAR_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - if (lastVehicle > 8) - lastVehicle = 8; - - for (int j = 0; j < lastVehicle; ++j) { - CVehicle *nearVeh = (CVehicle*) vehicles[j]; - - if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { - CPed *nearVehDriver = nearVeh->pDriver; - - if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { - - if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { - nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; - nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; - nearVeh->SetStatus(STATUS_PHYSICS); - nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; - nearVeh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - } - } - } - } - } - } -} - -void -CPed::ReactToPointGun(CEntity *entWithGun) -{ - CPed *pedWithGun = (CPed*)entWithGun; - int waitTime; - - if (IsPlayer() || !IsPedInControl() || CharCreatedBy == MISSION_CHAR) - return; - - if (m_leader == pedWithGun) - return; - - if (m_nWaitState == WAITSTATE_PLAYANIM_HANDSUP || m_nWaitState == WAITSTATE_PLAYANIM_HANDSCOWER || - (GetPosition() - pedWithGun->GetPosition()).MagnitudeSqr2D() > 225.0f) - return; - - if (m_leader) { - if (FindPlayerPed() == m_leader) - return; - - ClearLeader(); - } - if (m_pedStats->m_flags & STAT_GUN_PANIC - && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) - && m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_AIM_GUN) { - - waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); - SetWaitState(WAITSTATE_PLAYANIM_HANDSCOWER, &waitTime); - Say(SOUND_PED_HANDS_COWER); - m_pLookTarget = pedWithGun; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - SetMoveState(PEDMOVE_NONE); - - } else if (m_nPedType != pedWithGun->m_nPedType) { - if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { - RegisterThreatWithGangPeds(pedWithGun); - } - - if (m_nPedType == PEDTYPE_COP) { - if (pedWithGun->IsPlayer()) { - ((CPlayerPed*)pedWithGun)->m_pWanted->SetWantedLevelNoDrop(2); - if (bCrouchWhenShooting || bKindaStayInSamePlace) { - SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); - return; - } - } - } - - if (m_nPedType != PEDTYPE_COP - && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) - && (m_nPedState != PED_FLEE_ENTITY || pedWithGun->IsPlayer() && m_fleeFrom != pedWithGun) - && m_nPedState != PED_AIM_GUN && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { - - waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); - SetWaitState(WAITSTATE_PLAYANIM_HANDSUP, &waitTime); - Say(SOUND_PED_HANDS_UP); - m_pLookTarget = pedWithGun; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - SetMoveState(PEDMOVE_NONE); - if (m_nPedState == PED_FLEE_ENTITY) { - m_fleeFrom = pedWithGun; - m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); - } - - if (FindPlayerPed() == pedWithGun && bRichFromMugging) { - int money = CGeneral::GetRandomNumberInRange(100, 300); - int pickupCount = money / 40 + 1; - int moneyPerPickup = money / pickupCount; - - for (int i = 0; i < pickupCount; i++) { - float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().x; - float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().y; - bool found = false; - float groundZ = CWorld::FindGroundZFor3DCoord(pickupX, pickupY, GetPosition().z, &found) + 0.5f; - if (found) { - CPickups::GenerateNewOne(CVector(pickupX, pickupY, groundZ), MI_MONEY, PICKUP_MONEY, moneyPerPickup + (CGeneral::GetRandomNumber() & 7)); - } - } - bRichFromMugging = false; - } - } - } -} - -void -CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - bool startedToRun = false; - ped->bUsesCollision = true; - ped->m_actionX = 0.0f; - ped->m_actionY = 0.0f; - ped->bVehExitWillBeInstant = false; - if (veh && veh->IsBoat()) - ped->ApplyMoveSpeed(); - - if (ped->m_objective == OBJECTIVE_LEAVE_CAR) - ped->RestorePreviousObjective(); -#ifdef VC_PED_PORTS - else if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { - ped->m_fHealth = 0.0f; - ped->SetDie(ANIM_FLOOR_HIT, 4.0f, 0.5f); - } -#endif - - ped->bInVehicle = false; - if (veh && veh->IsCar() && !veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, nil)) { - ped->PositionPedOutOfCollision(); - } - - if (ped->m_nPedState == PED_EXIT_CAR) { - if (ped->m_nPedType == PEDTYPE_COP) - ped->SetIdle(); - else - ped->RestorePreviousState(); - - veh = ped->m_pMyVehicle; - if (ped->bFleeAfterExitingCar && veh) { - ped->bFleeAfterExitingCar = false; - ped->SetFlee(veh->GetPosition(), 12000); - ped->bUsePedNodeSeek = true; - ped->m_pNextPathNode = nil; - if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { - ped->SetMoveState(PEDMOVE_SPRINT); - ped->Say(SOUND_PED_FLEE_SPRINT); - } else { - ped->SetMoveState(PEDMOVE_RUN); - ped->Say(SOUND_PED_FLEE_RUN); - } - startedToRun = true; - - // This is not a good way to do this... - ped->m_nLastPedState = PED_WANDER_PATH; - - } else if (ped->bWanderPathAfterExitingCar) { - ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - ped->bWanderPathAfterExitingCar = false; - if (ped->m_nPedType == PEDTYPE_PROSTITUTE) - ped->SetObjectiveTimer(30000); - ped->m_nLastPedState = PED_NONE; - - } else if (ped->bGonnaKillTheCarJacker) { - - // Kill objective is already given at this point. - ped->bGonnaKillTheCarJacker = false; - if (ped->m_pedInObjective) { - if (!(CGeneral::GetRandomNumber() & 1) - && ped->m_nPedType != PEDTYPE_COP - && (!ped->m_pedInObjective->IsPlayer() || !CTheScripts::IsPlayerOnAMission())) { - ped->ClearObjective(); - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); - } - ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1500; - } - int waitTime = 1500; - ped->SetWaitState(WAITSTATE_PLAYANIM_COWER, &waitTime); - ped->SetMoveState(PEDMOVE_RUN); - startedToRun = true; - } else if (ped->m_objective == OBJECTIVE_NONE && ped->CharCreatedBy != MISSION_CHAR && ped->m_nPedState == PED_IDLE && !ped->IsPlayer()) { - ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - } - } -#ifdef VC_PED_PORTS - else { - ped->m_nPedState = PED_IDLE; - } -#endif - - if (animAssoc) - animAssoc->blendDelta = -1000.0f; - - ped->RestartNonPartialAnims(); - ped->m_pVehicleAnim = nil; - CVector posFromZ = ped->GetPosition(); - CPedPlacement::FindZCoorForPed(&posFromZ); - ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - ped->SetPosition(posFromZ); - veh = ped->m_pMyVehicle; - if (veh) { - if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { - if (veh->pDriver) { - if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = 0; - CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = 0; - CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; - CWorld::Players[CWorld::PlayerInFocus].m_nMoney -= 100; - if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney < 0) - CWorld::Players[CWorld::PlayerInFocus].m_nMoney = 0; - } - } - } - veh->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); - if (veh->pDriver == ped) { - veh->RemoveDriver(); - veh->SetStatus(STATUS_ABANDONED); - if (veh->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - veh->m_nDoorLock = CARLOCK_UNLOCKED; - if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) - veh->ChangeLawEnforcerState(false); - } else { - veh->RemovePassenger(ped); - } - - if (veh->bIsBus && !veh->IsUpsideDown() && !veh->IsOnItsSide()) { - float angleAfterExit; - if (ped->m_vehEnterType == CAR_DOOR_LF) { - angleAfterExit = HALFPI + veh->GetForward().Heading(); - } else { - angleAfterExit = veh->GetForward().Heading() - HALFPI; - } - ped->SetHeading(angleAfterExit); - ped->m_fRotationDest = angleAfterExit; - ped->m_fRotationCur = angleAfterExit; - if (!ped->bBusJacked) - ped->SetMoveState(PEDMOVE_WALK); - } - if (CGarages::IsPointWithinAnyGarage(ped->GetPosition())) - veh->bLightsOn = false; - } - - if (ped->IsPlayer()) - AudioManager.PlayerJustLeftCar(); - - ped->ReplaceWeaponWhenExitingVehicle(); - - ped->bOnBoat = false; - if (ped->bBusJacked) { - ped->SetFall(1500, ANIM_KO_SKID_BACK, false); - ped->bBusJacked = false; - } - ped->m_nStoredMoveState = PEDMOVE_NONE; - if (!ped->IsPlayer()) { - // It's a shame... -#ifdef FIX_BUGS - int createdBy = ped->CharCreatedBy; -#else - int createdBy = !ped->CharCreatedBy; -#endif - - if (createdBy == MISSION_CHAR && !startedToRun) - ped->SetMoveState(PEDMOVE_WALK); - } -} - -// It was inlined in III but not in VC. -inline void -CPed::ReplaceWeaponWhenExitingVehicle(void) -{ - eWeaponType weaponType = GetWeapon()->m_eWeaponType; - - // If it's Uzi, we may have stored weapon. Uzi is the only gun we can use in car. - if (IsPlayer() && weaponType == WEAPONTYPE_UZI) { - if (/*IsPlayer() && */ m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { - SetCurrentWeapon(m_storedWeapon); - m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; - } - } else { - AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); - } -} - -// Same, it's inlined in III. -inline void -CPed::RemoveWeaponWhenEnteringVehicle(void) -{ - if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { - if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) - m_storedWeapon = GetWeapon()->m_eWeaponType; - SetCurrentWeapon(WEAPONTYPE_UZI); - } else { - CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(ourWeapon->m_nModelId); - } -} - -void -CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - if (ped->m_pVehicleAnim) - ped->m_pVehicleAnim->blendDelta = -1000.0f; - - ped->bUsesCollision = true; - ped->m_pVehicleAnim = nil; - ped->bInVehicle = false; - ped->m_nPedState = PED_IDLE; - ped->RestorePreviousObjective(); - ped->SetMoveState(PEDMOVE_STILL); - - CMatrix pedMat(ped->GetMatrix()); - ped->m_fRotationCur = HALFPI + veh->GetForward().Heading(); - ped->m_fRotationDest = ped->m_fRotationCur; - CVector posAfterExit = Multiply3x3(pedMat, vecPedTrainDoorAnimOffset); - posAfterExit += ped->GetPosition(); - CPedPlacement::FindZCoorForPed(&posAfterExit); - ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - ped->SetPosition(posAfterExit); - ped->SetHeading(ped->m_fRotationCur); - veh->RemovePassenger(ped); -} - -bool -CPed::PlacePedOnDryLand(void) -{ - float waterLevel = 0.0f; - CEntity *foundEnt = nil; - CColPoint foundCol; - float foundColZ; - - CWaterLevel::GetWaterLevelNoWaves(GetPosition().x, GetPosition().y, GetPosition().z, &waterLevel); - - CVector potentialGround = GetPosition(); - potentialGround.z = waterLevel; - - if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false)) - return false; - - CVector potentialGroundDist = gaTempSphereColPoints[0].point - GetPosition(); - potentialGroundDist.z = 0.0f; - potentialGroundDist.Normalise(); - - CVector posToCheck = 0.5f * potentialGroundDist + gaTempSphereColPoints[0].point; - posToCheck.z = 3.0f + waterLevel; - - if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) { - foundColZ = foundCol.point.z; - if (foundColZ >= waterLevel) { - posToCheck.z = 0.8f + foundColZ; - SetPosition(posToCheck); - bIsStanding = true; - bWasStanding = true; - return true; - } - } - - posToCheck = 5.0f * potentialGroundDist + GetPosition(); - posToCheck.z = 3.0f + waterLevel; - - if (!CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) - return false; - - foundColZ = foundCol.point.z; - if (foundColZ < waterLevel) - return false; - - posToCheck.z = 0.8f + foundColZ; - SetPosition(posToCheck); - bIsStanding = true; - bWasStanding = true; - return true; -} - -void -CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; - - CVehicle *veh = ped->m_pMyVehicle; - - CVector finalPos; - CVector draggedOutOffset; - - CMatrix pedMat(ped->GetMatrix()); - ped->bUsesCollision = true; - ped->RestartNonPartialAnims(); - draggedOutOffset = vecPedQuickDraggedOutCarAnimOffset; - if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) - draggedOutOffset.x = -draggedOutOffset.x; - - finalPos = Multiply3x3(pedMat, draggedOutOffset) + ped->GetPosition(); - CPedPlacement::FindZCoorForPed(&finalPos); - ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - ped->SetPosition(finalPos); - - if (veh) { - ped->m_fRotationDest = veh->GetForward().Heading() - HALFPI; - ped->m_fRotationCur = ped->m_fRotationDest; - ped->CalculateNewOrientation(); - - if (!veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedQuickDraggedOutCarAnimOffset)) - ped->PositionPedOutOfCollision(); - } - - if (!ped->CanSetPedState()) - return; - - ped->SetIdle(); - if (veh) { - if (ped->bFleeAfterExitingCar) { - ped->bFleeAfterExitingCar = false; - ped->SetFlee(veh->GetPosition(), 14000); - - } else if (ped->bWanderPathAfterExitingCar) { - ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); - ped->bWanderPathAfterExitingCar = false; - - } else if (ped->bGonnaKillTheCarJacker) { - ped->bGonnaKillTheCarJacker = false; - if (ped->m_pedInObjective && CGeneral::GetRandomNumber() & 1) { - if (ped->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) - ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped->m_pedInObjective); - - } else { - CPed *driver = veh->pDriver; - if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { - ped->SetFlee(veh->GetPosition(), 14000); - } else { - ped->ClearObjective(); - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); - } - ped->bUsePedNodeSeek = true; - ped->m_pNextPathNode = nil; - ped->Say(SOUND_PED_FLEE_RUN); - } - } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear - && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE - && veh->pDriver && veh->pDriver->IsPlayer() - && !CTheScripts::IsPlayerOnAMission()) { - -#ifndef VC_PED_PORTS - if (CGeneral::GetRandomNumber() < MYRAND_MAX / 2) { - ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, veh->pDriver); - } else -#endif - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); - -#ifdef VC_PED_PORTS - } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear - && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE - && !veh->pDriver && FindPlayerPed()->m_carInObjective == veh - && !CTheScripts::IsPlayerOnAMission()) { - ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); -#endif - } else { - ped->SetFindPathAndFlee(veh->GetPosition(), 10000); - if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { - ped->SetMoveState(PEDMOVE_SPRINT); - ped->Say(SOUND_PED_FLEE_SPRINT); - } else { - ped->Say(SOUND_PED_FLEE_RUN); - } - } - } - if (ped->m_nLastPedState == PED_IDLE) - ped->m_nLastPedState = PED_WANDER_PATH; -} - -bool -CPed::PositionPedOutOfCollision(void) -{ - CVehicle *veh; - CVector posNearVeh; - CVector posSomewhereClose; - bool putNearVeh = false; - bool putSomewhereClose = false; - int smallestDistNearVeh = 999; - int smallestDistSomewhereClose = 999; - - if (!m_pMyVehicle) - return false; - - CVector vehPos = m_pMyVehicle->GetPosition(); - CVector potentialPos; - potentialPos.y = GetPosition().y - 3.5f; - potentialPos.z = GetPosition().z; - - for (int yTry = 0; yTry < 15; yTry++) { - potentialPos.x = GetPosition().x - 3.5f; - - for (int xTry = 0; xTry < 15; xTry++) { - CPedPlacement::FindZCoorForPed(&potentialPos); - CVector distVec = potentialPos - vehPos; - float dist = distVec.Magnitude(); - - // Makes close distances bigger for some reason. - float mult = (0.6f + dist) / dist; - CVector adjustedPotentialPos = distVec * mult + vehPos; - if (CWorld::GetIsLineOfSightClear(vehPos, adjustedPotentialPos, true, false, false, true, false, false, false) - && !CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, true, false, false, true, false, false)) { - - float potentialChangeSqr = (potentialPos - GetPosition()).MagnitudeSqr(); - veh = (CVehicle*)CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, false, true, false, false, false, false); - if (veh) { - if (potentialChangeSqr < smallestDistNearVeh) { - posNearVeh = potentialPos; - putNearVeh = true; - smallestDistNearVeh = potentialChangeSqr; - } - } else if (potentialChangeSqr < smallestDistSomewhereClose) { - smallestDistSomewhereClose = potentialChangeSqr; - posSomewhereClose = potentialPos; - putSomewhereClose = true; - } - } - potentialPos.x += 0.5f; - } - potentialPos.y += 0.5f; - } - - if (!putSomewhereClose && !putNearVeh) - return false; - - // We refrain from using posNearVeh, probably because of it may be top of the vehicle. - if (putSomewhereClose) { - SetPosition(posSomewhereClose); - } else { - CVector vehSize = veh->GetModelInfo()->GetColModel()->boundingBox.max; - posNearVeh.z += vehSize.z; - SetPosition(posNearVeh); - } - return true; -} - -bool -CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) -{ - bool foundIt = false; - - CVector helperPos = GetPosition(); - helperPos.z = pos->z - 0.5f; - - CVector foundPos = *pos; - foundPos.z -= 0.5f; - - // If there is another car between target car and us. - if (CWorld::TestSphereAgainstWorld((foundPos + helperPos) / 2.0f, 0.25f, veh, false, true, false, false, false, false)) { - - CColModel *vehCol = veh->GetModelInfo()->GetColModel(); - CVector *colMin = &vehCol->boundingBox.min; - CVector *colMax = &vehCol->boundingBox.max; - - CVector leftRearPos = CVector(colMin->x - 0.5f, colMin->y - 0.5f, 0.0f); - CVector rightRearPos = CVector(0.5f + colMax->x, colMin->y - 0.5f, 0.0f); - CVector leftFrontPos = CVector(colMin->x - 0.5f, 0.5f + colMax->y, 0.0f); - CVector rightFrontPos = CVector(0.5f + colMax->x, 0.5f + colMax->y, 0.0f); - - leftRearPos = veh->GetMatrix() * leftRearPos; - rightRearPos = veh->GetMatrix() * rightRearPos; - leftFrontPos = veh->GetMatrix() * leftFrontPos; - rightFrontPos = veh->GetMatrix() * rightFrontPos; - - // Makes helperPos veh-ped distance vector. - helperPos -= veh->GetPosition(); - - // ?!? I think it's absurd to use this unless another function like SeekCar finds next pos. with it and we're trying to simulate it's behaviour. - // On every run it returns another pos. for ped, with same distance to the veh. - // Sequence of positions are not guaranteed, it depends on global pos. (So sometimes it returns positions to make ped draw circle, sometimes don't) - helperPos = veh->GetMatrix() * helperPos; - - float vehForwardHeading = veh->GetForward().Heading(); - - // I'm absolutely not sure about these namings. - // NTVF = needed turn if we're looking to vehicle front and wanna look to... - - float potentialLrHeading = Atan2(leftRearPos.x - helperPos.x, leftRearPos.y - helperPos.y); - float NTVF_LR = CGeneral::LimitRadianAngle(potentialLrHeading - vehForwardHeading); - - float potentialRrHeading = Atan2(rightRearPos.x - helperPos.x, rightRearPos.y - helperPos.y); - float NTVF_RR = CGeneral::LimitRadianAngle(potentialRrHeading - vehForwardHeading); - - float potentialLfHeading = Atan2(leftFrontPos.x - helperPos.x, leftFrontPos.y - helperPos.y); - float NTVF_LF = CGeneral::LimitRadianAngle(potentialLfHeading - vehForwardHeading); - - float potentialRfHeading = Atan2(rightFrontPos.x - helperPos.x, rightFrontPos.y - helperPos.y); - float NTVF_RF = CGeneral::LimitRadianAngle(potentialRfHeading - vehForwardHeading); - - bool canHeadToLr = NTVF_LR <= -PI || NTVF_LR >= -HALFPI; - - bool canHeadToRr = NTVF_RR <= HALFPI || NTVF_RR >= PI; - - bool canHeadToLf = NTVF_LF >= 0.0f || NTVF_LF <= -HALFPI; - - bool canHeadToRf = NTVF_RF <= 0.0f || NTVF_RF >= HALFPI; - - // Only order of conditions are different among enterTypes. - if (m_vehEnterType == CAR_DOOR_RR) { - if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } else if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } else if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } else if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } - } else if(m_vehEnterType == CAR_DOOR_RF) { - if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } else if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } else if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } else if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } - } else if (m_vehEnterType == CAR_DOOR_LF) { - if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } else if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } else if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } else if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } - } else if (m_vehEnterType == CAR_DOOR_LR) { - if (canHeadToLr) { - foundPos = leftRearPos; - foundIt = true; - } else if (canHeadToLf) { - foundPos = leftFrontPos; - foundIt = true; - } else if (canHeadToRr) { - foundPos = rightRearPos; - foundIt = true; - } else if (canHeadToRf) { - foundPos = rightFrontPos; - foundIt = true; - } - } - } - if (!foundIt) - return false; - - helperPos = GetPosition() - foundPos; - helperPos.z = 0.0f; - if (helperPos.MagnitudeSqr() <= sq(0.5f)) - return false; - - pos->x = foundPos.x; - pos->y = foundPos.y; - return true; -} - -void -CPed::Render(void) -{ - if (bInVehicle && m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR) { - if (!bRenderPedInCar) - return; - - float camDistSq = (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr(); - if (camDistSq > SQR(25.0f * TheCamera.LODDistMultiplier)) - return; - } - - CEntity::Render(); - -#ifdef PED_SKIN - if(IsClumpSkinned(GetClump())){ - renderLimb(PED_HEAD); - renderLimb(PED_HANDL); - renderLimb(PED_HANDR); - } - if(m_pWeaponModel && IsClumpSkinned(GetClump())){ - RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); - int idx = RpHAnimIDGetIndex(hier, m_pFrames[PED_HANDR]->nodeID); - RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; - RwFrame *frame = RpAtomicGetFrame(m_pWeaponModel); - *RwFrameGetMatrix(frame) = *mat; - RwFrameUpdateObjects(frame); - RpAtomicRender(m_pWeaponModel); - } -#endif -} - -#ifdef PED_SKIN -static RpMaterial* -SetLimbAlphaCB(RpMaterial *material, void *data) -{ - ((RwRGBA*)RpMaterialGetColor(material))->alpha = *(uint8*)data; - return material; -} - -void -CPed::renderLimb(int node) -{ - RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); - int idx = RpHAnimIDGetIndex(hier, m_pFrames[node]->nodeID); - RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; - CPedModelInfo *mi = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); - RpAtomic *atomic; - switch(node){ - case PED_HEAD: - atomic = mi->getHead(); - break; - case PED_HANDL: - atomic = mi->getLeftHand(); - break; - case PED_HANDR: - atomic = mi->getRightHand(); - break; - default: - return; - } - if(atomic == nil) - return; - - RwFrame *frame = RpAtomicGetFrame(atomic); - *RwFrameGetMatrix(frame) = *mat; - RwFrameUpdateObjects(frame); - int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); - RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), SetLimbAlphaCB, &alpha); - RpAtomicRender(atomic); -} -#endif - -void -CPed::ProcessObjective(void) -{ - if (bClearObjective && (IsPedInControl() || m_nPedState == PED_DRIVING)) { - ClearObjective(); - bClearObjective = false; - } - UpdateFromLeader(); - - CVector carOrOurPos; - CVector targetCarOrHisPos; - CVector distWithTarget; - - if (m_objective != OBJECTIVE_NONE && (IsPedInControl() || m_nPedState == PED_DRIVING)) { - if (bInVehicle) { - if (!m_pMyVehicle) { - bInVehicle = false; - return; - } - carOrOurPos = m_pMyVehicle->GetPosition(); - } else { - carOrOurPos = GetPosition(); - } - - if (m_pedInObjective) { - if (m_pedInObjective->InVehicle() && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { - targetCarOrHisPos = m_pedInObjective->m_pMyVehicle->GetPosition(); - } else { - targetCarOrHisPos = m_pedInObjective->GetPosition(); - } - distWithTarget = targetCarOrHisPos - carOrOurPos; - } else if (m_carInObjective) { - targetCarOrHisPos = m_carInObjective->GetPosition(); - distWithTarget = targetCarOrHisPos - carOrOurPos; - } - - switch (m_objective) { - case OBJECTIVE_NONE: - case OBJECTIVE_GUARD_AREA: - case OBJECTIVE_FOLLOW_CAR_IN_CAR: - case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: - case OBJECTIVE_DESTROY_OBJECT: - case OBJECTIVE_GOTO_AREA_IN_CAR: - case OBJECTIVE_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: - case OBJECTIVE_SET_LEADER: - break; - case OBJECTIVE_WAIT_ON_FOOT: - SetIdle(); - m_objective = OBJECTIVE_NONE; - SetMoveState(PEDMOVE_STILL); - break; - case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: - if (InVehicle()) { - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - bFleeAfterExitingCar = true; - } else if (m_nPedState != PED_FLEE_POS) { - CVector2D fleePos = GetPosition(); - SetFlee(fleePos, 10000); - bUsePedNodeSeek = true; - m_pNextPathNode = nil; - } - break; - case OBJECTIVE_GUARD_SPOT: - { - distWithTarget = m_vecSeekPosEx - GetPosition(); - if (m_pedInObjective) { - SetLookFlag(m_pedInObjective, true); - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - } - float distWithTargetSc = distWithTarget.Magnitude(); - if (2.0f * m_distanceToCountSeekDoneEx >= distWithTargetSc) { - if (m_pedInObjective) { - if (distWithTargetSc <= m_distanceToCountSeekDoneEx) - SetIdle(); - else - SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); - } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - int threatType = ScanForThreats(); - SetLookTimer(CGeneral::GetRandomNumberInRange(500, 1500)); - - // Second condition is pointless and isn't there in Mobile. - if (threatType == PED_FLAG_GUN || (threatType == PED_FLAG_EXPLOSION && m_threatEntity) || m_threatEntity) { - if (m_threatEntity->IsPed()) - SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); - } - } - } else { - SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); - } - break; - } - case OBJECTIVE_WAIT_IN_CAR: - m_nPedState = PED_DRIVING; - break; - case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: - m_nPedState = PED_DRIVING; - break; - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - { - if (m_pedInObjective) { - if (m_pedInObjective->IsPlayer() && CharCreatedBy != MISSION_CHAR - && m_nPedType != PEDTYPE_COP && FindPlayerPed()->m_pWanted->m_CurrentCops != 0 - && !bKindaStayInSamePlace) { - - SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); - break; - } - if (InVehicle()) { - if (distWithTarget.Magnitude() >= 20.0f - || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= sq(0.02f)) { - if (m_pMyVehicle->pDriver == this - && !m_pMyVehicle->m_nGettingInFlags) { - m_pMyVehicle->SetStatus(STATUS_PHYSICS); - m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; - if (m_nPedType == PEDTYPE_COP) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); - m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); - } else { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; - m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; - } - m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; - } - } else { - bool targetHasVeh = m_pedInObjective->bInVehicle; - if (!targetHasVeh - || targetHasVeh && m_pedInObjective->m_pMyVehicle->CanPedExitCar()) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } - } - break; - } - if (distWithTarget.Magnitude() > 30.0f && !bKindaStayInSamePlace) { - if (m_pMyVehicle) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } else { - float closestVehDist = 60.0f; - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - CVehicle *foundVeh = nil; - for(int i = 0; i < lastVehicle; i++) { - CVehicle *nearVeh = (CVehicle*)vehicles[i]; - /* - Not used. - CVector vehSpeed = nearVeh->GetSpeed(); - CVector ourSpeed = GetSpeed(); - */ - CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); - if (vehDistVec.Magnitude() < closestVehDist && m_pedInObjective->m_pMyVehicle != nearVeh - && nearVeh->CanPedOpenLocks(this)) { - - foundVeh = nearVeh; - closestVehDist = vehDistVec.Magnitude(); - } - } - m_pMyVehicle = foundVeh; - if (m_pMyVehicle) { - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } else if (!GetIsOnScreen()) { - CVector ourPos = GetPosition(); - int closestNode = ThePaths.FindNodeClosestToCoors(ourPos, PATH_CAR, 20.0f); - if (closestNode >= 0) { - int16 colliding; - CWorld::FindObjectsKindaColliding( - ThePaths.m_pathNodes[closestNode].GetPosition(), 10.0f, true, &colliding, 2, nil, false, true, true, false, false); - if (!colliding) { - CZoneInfo zoneInfo; - int chosenCarClass; - CTheZones::GetZoneInfoForTimeOfDay(&ourPos, &zoneInfo); - int chosenModel = CCarCtrl::ChooseModel(&zoneInfo, &ourPos, &chosenCarClass); - CAutomobile *newVeh = new CAutomobile(chosenModel, RANDOM_VEHICLE); - if (newVeh) { - newVeh->GetMatrix().GetPosition() = ThePaths.m_pathNodes[closestNode].GetPosition(); - newVeh->GetMatrix().GetPosition().z += 4.0f; - newVeh->SetHeading(DEGTORAD(200.0f)); - newVeh->SetStatus(STATUS_ABANDONED); - newVeh->m_nDoorLock = CARLOCK_UNLOCKED; - CWorld::Add(newVeh); - m_pMyVehicle = newVeh; - if (m_pMyVehicle) { - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } - } - } - } - } - } - break; - } - } else { - ClearLookFlag(); - bObjectiveCompleted = true; - } - } - case OBJECTIVE_KILL_CHAR_ON_FOOT: - { - bool killPlayerInNoPoliceZone = false; - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && InVehicle()) { - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - break; - } - if (!m_pedInObjective || m_pedInObjective->DyingOrDead()) { - ClearLookFlag(); - bObjectiveCompleted = true; - SetMoveAnim(); - break; - } - if (m_pedInObjective->IsPlayer() && CCullZones::NoPolice()) - killPlayerInNoPoliceZone = true; - - if (!bNotAllowedToDuck || killPlayerInNoPoliceZone) { - if (m_nPedType == PEDTYPE_COP && !m_pedInObjective->GetWeapon()->IsTypeMelee() && !GetWeapon()->IsTypeMelee()) - bNotAllowedToDuck = true; - } else { - if (!m_pedInObjective->bInVehicle) { - if (m_pedInObjective->GetWeapon()->IsTypeMelee() || GetWeapon()->IsTypeMelee()) { - bNotAllowedToDuck = false; - bCrouchWhenShooting = false; - } else if (DuckAndCover()) { - break; - } - } else { - bNotAllowedToDuck = false; - bCrouchWhenShooting = false; - } - } - if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds() && !bKindaStayInSamePlace) { - SetMoveState(PEDMOVE_STILL); - break; - } - if (m_pedInObjective->IsPlayer()) { - CPlayerPed *player = FindPlayerPed(); - if (m_nPedType == PEDTYPE_COP && player->m_pWanted->m_bIgnoredByCops - || player->m_pWanted->m_bIgnoredByEveryone - || m_pedInObjective->bIsInWater - || m_pedInObjective->m_nPedState == PED_ARRESTED) { - - if (m_nPedState != PED_ARREST_PLAYER) - SetIdle(); - - break; - } - } - CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - float wepRange = wepInfo->m_fRange; - float wepRangeAdjusted; - if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { - wepRangeAdjusted = wepRange / 3.0f; - } else { - if (m_nPedState == PED_FIGHT) { - if (!IsPlayer() && !(m_pedStats->m_flags & STAT_CAN_KICK)) - wepRange = 2.0f; - } else { - wepRange = 1.3f; - } - wepRangeAdjusted = wepRange; - } - if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() && wepRangeAdjusted < 2.5f) { - wepRangeAdjusted = 2.5f; - } - if (m_pedInObjective->IsPlayer() && m_nPedType != PEDTYPE_COP - && CharCreatedBy != MISSION_CHAR && FindPlayerPed()->m_pWanted->m_CurrentCops) { - SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); - break; - } - if (m_pedInObjective->m_fHealth <= 0.0f) { - bObjectiveCompleted = true; - bScriptObjectiveCompleted = true; - SetMoveAnim(); - break; - } - float distWithTargetSc = distWithTarget.Magnitude(); - if (m_pedInObjective->bInVehicle && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { - CVehicle *vehOfTarget = m_pedInObjective->m_pMyVehicle; - if (vehOfTarget->bIsInWater || vehOfTarget->GetStatus() == STATUS_PLAYER_DISABLED - || m_pedInObjective->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled()) { - SetIdle(); - return; - } - SetLookFlag(vehOfTarget, false); - if (m_nPedState != PED_CARJACK) { - if (m_pedInObjective->m_nPedState != PED_ARRESTED) { - if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE - && distWithTargetSc < wepRange && distWithTargetSc > 3.0f) { - - // I hope so - CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); - CVector maxShotPos = vehOfTarget->GetPosition() - ourHead; - maxShotPos.Normalise(); - maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; - - CWorld::bIncludeDeadPeds = true; - CColPoint foundCol; - CEntity *foundEnt; - CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, - true, true, true, true, false, true, false); - CWorld::bIncludeDeadPeds = false; - if (foundEnt == vehOfTarget) { - SetAttack(vehOfTarget); - m_pPointGunAt = vehOfTarget; - if (vehOfTarget) - vehOfTarget->RegisterReference((CEntity **) &m_pPointGunAt); - - SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); - if (distWithTargetSc <= m_distanceToCountSeekDone) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(200, 500)); - SetMoveState(PEDMOVE_STILL); - } else { - SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); - } - } - } - else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace && !killPlayerInNoPoliceZone) { - if (vehOfTarget) { - if (m_nPedType == PEDTYPE_COP || vehOfTarget->bIsBus) { - GoToNearestDoor(vehOfTarget); - } else { - m_vehEnterType = 0; - if (m_pedInObjective == vehOfTarget->pDriver || vehOfTarget->bIsBus) { - m_vehEnterType = CAR_DOOR_LF; - } else if (m_pedInObjective == vehOfTarget->pPassengers[0]) { - m_vehEnterType = CAR_DOOR_RF; - } else if (m_pedInObjective == vehOfTarget->pPassengers[1]) { - m_vehEnterType = CAR_DOOR_LR; - } else if (m_pedInObjective == vehOfTarget->pPassengers[2]) { - m_vehEnterType = CAR_DOOR_RR; - } - // Unused - // GetPositionToOpenCarDoor(vehOfTarget, m_vehEnterType); - SetSeekCar(vehOfTarget, m_vehEnterType); - SetMoveState(PEDMOVE_RUN); - } - } - } - } - } - SetMoveAnim(); - break; - } - if (m_nMoveState == PEDMOVE_STILL && IsPedInControl()) { - SetLookFlag(m_pedInObjective, false); - TurnBody(); - } - if (m_nPedType == PEDTYPE_COP && distWithTargetSc < 1.5f && m_pedInObjective->IsPlayer()) { - if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() - || m_pedInObjective->m_nPedState == PED_DRAG_FROM_CAR) { - - ((CCopPed*)this)->SetArrestPlayer(m_pedInObjective); - return; - } - } - if (!bKindaStayInSamePlace && !bStopAndShoot && m_nPedState != PED_ATTACK && !killPlayerInNoPoliceZone) { - if (distWithTargetSc > wepRange - || m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() - || m_pedInObjective->m_nPedState == PED_ARRESTED - || m_pedInObjective->EnteringCar() && distWithTargetSc < 3.0f - || distWithTargetSc > m_distanceToCountSeekDone && !CanSeeEntity(m_pedInObjective)) { - - if (m_pedInObjective->EnteringCar()) - wepRangeAdjusted = 2.0f; - - if (bUsePedNodeSeek) { - CVector bestCoords(0.0f, 0.0f, 0.0f); - m_vecSeekPos = m_pedInObjective->GetPosition(); - - if (!m_pNextPathNode) - FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); - - if (m_pNextPathNode) - m_vecSeekPos = m_pNextPathNode->GetPosition(); - - SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); - } else { - SetSeek(m_pedInObjective, wepRangeAdjusted); - } - bCrouchWhenShooting = false; - if (m_pedInObjective->m_pCurrentPhysSurface && distWithTargetSc < 5.0f) { - if (wepRange <= 5.0f) { - if (m_pedInObjective->IsPlayer() - && FindPlayerPed()->m_bSpeedTimerFlag - && (IsGangMember() || m_nPedType == PEDTYPE_COP) - && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { - GiveWeapon(WEAPONTYPE_COLT45, 1000); - SetCurrentWeapon(WEAPONTYPE_COLT45); - } - } else { - bStopAndShoot = true; - } - SetMoveState(PEDMOVE_STILL); - SetMoveAnim(); - break; - } - bStopAndShoot = false; - SetMoveAnim(); - break; - } - } - if (m_attackTimer < CTimer::GetTimeInMilliseconds() - && distWithTargetSc < wepRange && m_pedInObjective->m_nPedState != PED_GETUP && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { - if (bIsDucking) { - CAnimBlendAssociation *duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (duckAnim) { - duckAnim->blendDelta = -2.0f; - break; - } - bIsDucking = false; - } else if (wepRange <= 5.0f) { - SetMoveState(PEDMOVE_STILL); - SetAttack(m_pedInObjective); - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, - GetPosition().x, GetPosition().y); - SetShootTimer(CGeneral::GetRandomNumberInRange(0.0f, 500.0f)); - SetAttackTimer(CGeneral::GetRandomNumberInRange(0.0f, 1500.0f)); - bObstacleShowedUpDuringKillObjective = false; - - } else { - CVector target; - CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); - if (m_pedInObjective->IsPed()) - m_pedInObjective->m_pedIK.GetComponentPosition((RwV3d*)&target, PED_MID); - else - target = m_pedInObjective->GetPosition(); - - target -= ourHead; - target.Normalise(); - target = target * wepInfo->m_fRange + ourHead; - - CWorld::bIncludeDeadPeds = true; - CEntity *foundEnt = nil; - CColPoint foundCol; - - CWorld::ProcessLineOfSight( - ourHead, target, foundCol, foundEnt, - true, true, true, false, true, false); - CWorld::bIncludeDeadPeds = 0; - if (foundEnt == m_pedInObjective) { - SetAttack(m_pedInObjective); - m_pPointGunAt = m_pedInObjective; - if (m_pedInObjective) - m_pedInObjective->RegisterReference((CEntity **) &m_pPointGunAt); - - SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 2000.0f)); - - int time; - if (distWithTargetSc <= wepRangeAdjusted) - time = CGeneral::GetRandomNumberInRange(100.0f, 500.0f); - else - time = CGeneral::GetRandomNumberInRange(1500.0f, 3000.0f); - - SetAttackTimer(time); - bObstacleShowedUpDuringKillObjective = false; - - } else if (foundEnt) { - if (foundEnt->IsPed()) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(500.0f, 1000.0f)); - bObstacleShowedUpDuringKillObjective = false; - } else { - if (foundEnt->IsObject()) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(200.0f, 400.0f)); - bObstacleShowedUpDuringKillObjective = true; - } else if (foundEnt->IsVehicle()) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(400.0f, 600.0f)); - bObstacleShowedUpDuringKillObjective = true; - } else { - SetAttackTimer(CGeneral::GetRandomNumberInRange(700.0f, 1200.0f)); - bObstacleShowedUpDuringKillObjective = true; - } - } - - m_fleeFrom = foundEnt; - m_fleeFrom->RegisterReference((CEntity**) &m_fleeFrom); - SetPointGunAt(m_pedInObjective); - } - } - } else { - if (!m_pedInObjective->m_pCurrentPhysSurface) - bStopAndShoot = false; - - if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT) { - - // This is weird... - if (bNotAllowedToDuck && bKindaStayInSamePlace) { - if (!bIsDucking) { - CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!duckAnim || duckAnim->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); - bIsDucking = true; - } - break; - } else { - CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!duckAnim || duckAnim->blendDelta < 0.0f) { - bIsDucking = false; - } else { - break; - } - } - } - if (bObstacleShowedUpDuringKillObjective) { - if (m_nPedType == PEDTYPE_COP) { - if (GetWeapon()->m_eWeaponType > WEAPONTYPE_COLT45 - || m_fleeFrom && m_fleeFrom->IsObject()) { - wepRangeAdjusted = 6.0f; - } else if (m_fleeFrom && m_fleeFrom->IsVehicle()) { - wepRangeAdjusted = 4.0f; - } else { - wepRangeAdjusted = 2.0f; - } - } else { - wepRangeAdjusted = 2.0f; - } - } - if (distWithTargetSc <= wepRangeAdjusted) { - SetMoveState(PEDMOVE_STILL); - bIsPointingGunAt = true; - if (m_nPedState != PED_AIM_GUN && !bDuckAndCover) { - m_attackTimer = CTimer::GetTimeInMilliseconds(); - SetIdle(); - } - } else { - if (m_nPedState != PED_SEEK_ENTITY && m_nPedState != PED_SEEK_POS - && !bStopAndShoot && !killPlayerInNoPoliceZone && !bKindaStayInSamePlace) { - Say(SOUND_PED_ATTACK); - SetSeek(m_pedInObjective, wepRangeAdjusted); - bIsRunning = true; - } - } - } - } - - if (distWithTargetSc < 2.5f && wepRange > 5.0f - && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE) { - - SetAttack(m_pedInObjective); - if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { - int time = CGeneral::GetRandomNumberInRange(500.0f, 1000.0f); - SetAttackTimer(time); - SetShootTimer(time - 500); - } - SetMoveState(PEDMOVE_STILL); - } - if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, GetPosition().x, GetPosition().y); + CVector pos(0.0f, 0.0f, 0.0f); + TransformToNode(pos, PED_FOOTL); - SetMoveAnim(); - break; - } - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - { - if (InVehicle()) { - if (m_nPedState == PED_DRIVING) - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } else if (m_nPedState != PED_FLEE_ENTITY) { - int time; - if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) - time = 0; - else - time = 6000; - - SetFindPathAndFlee(m_pedInObjective, time); - } - break; - } - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - { - if (m_pedInObjective) { - float safeDistance = 2.0f; - if (m_pedInObjective->bInVehicle) - safeDistance = 3.0f; - - float distWithTargetSc = distWithTarget.Magnitude(); - if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) { - if (distWithTargetSc <= safeDistance) { - bScriptObjectiveCompleted = true; - if (m_nPedState != PED_ATTACK) { - SetIdle(); - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - } - if (distWithTargetSc > 2.0f) - SetMoveState(m_pedInObjective->m_nMoveState); - else - SetMoveState(PEDMOVE_STILL); - } else { - SetSeek(m_pedInObjective, safeDistance); - if (distWithTargetSc >= 5.0f) { - if (m_leader && m_leader->m_nMoveState == PEDMOVE_SPRINT) - SetMoveState(PEDMOVE_SPRINT); - else - SetMoveState(PEDMOVE_RUN); - } else { - if (m_leader && m_leader->m_nMoveState != PEDMOVE_STILL - && m_leader->m_nMoveState != PEDMOVE_NONE) { - if (m_leader->IsPlayer()) { - if (distWithTargetSc >= 3.0f && FindPlayerPed()->m_fMoveSpeed >= 1.3f) - SetMoveState(PEDMOVE_RUN); - else - SetMoveState(PEDMOVE_WALK); - } else { - SetMoveState(m_leader->m_nMoveState); - } - } else if (distWithTargetSc <= 3.0f) { - SetMoveState(PEDMOVE_WALK); - } else { - SetMoveState(PEDMOVE_RUN); - } - } - } - } - } else { - SetObjective(OBJECTIVE_NONE); - } - break; - } - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - { - if (m_pedInObjective) { - CVector posToGo = GetFormationPosition(); - distWithTarget = posToGo - carOrOurPos; - SetSeek(posToGo, 1.0f); - if (distWithTarget.Magnitude() <= 3.0f) { - SetSeek(posToGo, 1.0f); - if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) - SetMoveState(m_pedInObjective->m_nMoveState); - } else { - SetSeek(posToGo, 1.0f); - SetMoveState(PEDMOVE_RUN); - } - } else { - SetObjective(OBJECTIVE_NONE); - } - break; - } - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - { - if (m_carInObjective) { - if (!bInVehicle && m_carInObjective->m_nNumPassengers >= m_carInObjective->m_nNumMaxPassengers) { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - - break; - } - - if (m_prevObjective == OBJECTIVE_HAIL_TAXI && !((CAutomobile*)m_carInObjective)->bTaxiLight) { - RestorePreviousObjective(); - ClearObjective(); - SetWanderPath(CGeneral::GetRandomNumber() & 7); - bIsRunning = false; - break; - } - if (m_objectiveTimer && m_objectiveTimer < CTimer::GetTimeInMilliseconds()) { - if (!EnteringCar()) { - bool foundSeat = false; - if (m_carInObjective->pPassengers[0] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { - if (m_carInObjective->pPassengers[1] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { - if (m_carInObjective->pPassengers[2] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { - foundSeat = false; - } else { - m_vehEnterType = CAR_DOOR_RR; - foundSeat = true; - } - } else { - m_vehEnterType = CAR_DOOR_LR; - foundSeat = true; - } - } else { - m_vehEnterType = CAR_DOOR_RF; - foundSeat = true; - } - for (int i = 2; i < m_carInObjective->m_nNumMaxPassengers; ++i) { - if (!m_carInObjective->pPassengers[i] && !(m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { - m_vehEnterType = CAR_DOOR_RF; - foundSeat = true; - } - } - if (foundSeat) { - SetPosition(GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType)); - SetEnterCar(m_carInObjective, m_vehEnterType); - } - } - m_objectiveTimer = 0; - } - } - // fall through - } - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - { - if (!m_carInObjective || bInVehicle) { -#ifdef VC_PED_PORTS - if (bInVehicle && m_pMyVehicle != m_carInObjective) { - SetExitCar(m_pMyVehicle, 0); - } else -#endif - { - bObjectiveCompleted = true; - bScriptObjectiveCompleted = true; - RestorePreviousState(); - } - } else { - if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) { - SetMoveState(PEDMOVE_STILL); - break; - } - if (IsPedInControl()) { - if (m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { - if (distWithTarget.Magnitude() < 20.0f) { - RestorePreviousObjective(); - RestorePreviousState(); - return; - } - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (m_carInObjective->pDriver -#ifdef VC_PED_PORTS - && !IsPlayer() -#endif - ) { - if (m_carInObjective->pDriver->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS && m_carInObjective->pDriver != m_pedInObjective) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); - m_carInObjective->bIsBeingCarJacked = false; - } - } - } - } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (m_carInObjective->pDriver -#ifdef VC_PED_PORTS - && (CharCreatedBy != MISSION_CHAR || m_carInObjective->pDriver->CharCreatedBy != RANDOM_CHAR) -#endif - ) { - if (m_carInObjective->pDriver->m_nPedType == m_nPedType) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); - m_carInObjective->bIsBeingCarJacked = false; - } - } - } - if (m_carInObjective->IsUpsideDown() && m_carInObjective->m_vehType != VEHICLE_TYPE_BIKE) { - RestorePreviousObjective(); - RestorePreviousState(); - return; - } - if (!m_carInObjective->IsBoat() || m_nPedState == PED_SEEK_IN_BOAT) { - if (m_nPedState != PED_SEEK_CAR) - SetSeekCar(m_carInObjective, 0); - } else { - SetSeekBoatPosition(m_carInObjective); - } - if (m_nMoveState == PEDMOVE_STILL && !bVehEnterDoorIsBlocked) - SetMoveState(PEDMOVE_RUN); - - if (m_carInObjective && m_carInObjective->m_fHealth > 0.0f) { - distWithTarget = m_carInObjective->GetPosition() - GetPosition(); - if (!bInVehicle) { - if (nEnterCarRangeMultiplier * ENTER_CAR_MAX_DIST < distWithTarget.Magnitude()) { - if (!m_carInObjective->pDriver && !m_carInObjective->GetIsOnScreen() && !GetIsOnScreen()) - WarpPedToNearEntityOffScreen(m_carInObjective); - - if (CharCreatedBy != MISSION_CHAR || m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS -#ifdef VC_PED_PORTS - || IsPlayer() && !CPad::GetPad(0)->ArePlayerControlsDisabled() -#endif - ) { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } else { - SetIdle(); - SetMoveState(PEDMOVE_STILL); - } - } - } - } else if (!bInVehicle) { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } - } - } - break; - } - case OBJECTIVE_DESTROY_CAR: - { - if (!m_carInObjective) { - ClearLookFlag(); - bObjectiveCompleted = true; - break; - } - float distWithTargetSc = distWithTarget.Magnitude(); - CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - float wepRange = wepInfo->m_fRange; - m_pLookTarget = m_carInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - - m_pSeekTarget = m_carInObjective; - m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - - TurnBody(); - if (m_carInObjective->m_fHealth <= 0.0f) { - ClearLookFlag(); - bScriptObjectiveCompleted = true; - break; - } - - if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE - && distWithTargetSc < wepRange) { - - // I hope so - CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); - CVector maxShotPos = m_carInObjective->GetPosition() - ourHead; - maxShotPos.Normalise(); - maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; - - CWorld::bIncludeDeadPeds = true; - CColPoint foundCol; - CEntity *foundEnt; - CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, - true, true, true, true, false, true, false); - CWorld::bIncludeDeadPeds = false; - if (foundEnt == m_carInObjective) { - SetAttack(m_carInObjective); - m_pPointGunAt = m_carInObjective; - if (m_pPointGunAt) - m_pPointGunAt->RegisterReference((CEntity **) &m_pPointGunAt); - - SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); - if (distWithTargetSc > 10.0f && !bKindaStayInSamePlace) { - SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); - } else { - SetAttackTimer(CGeneral::GetRandomNumberInRange(50, 300)); - SetMoveState(PEDMOVE_STILL); - } - } - } else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace) { - - float safeDistance; - if (wepRange <= 5.0f) - safeDistance = 3.0f; - else - safeDistance = wepRange * 0.25f; - - SetSeek(m_carInObjective, safeDistance); - SetMoveState(PEDMOVE_RUN); - } - SetLookFlag(m_carInObjective, false); - TurnBody(); - break; - } - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - { - distWithTarget = m_nextRoutePointPos - GetPosition(); - distWithTarget.z = 0.0f; - if (InVehicle()) { - CCarAI::GetCarToGoToCoors(m_pMyVehicle, &m_nextRoutePointPos); - CCarCtrl::RegisterVehicleOfInterest(m_pMyVehicle); - if (distWithTarget.MagnitudeSqr() < sq(20.0f)) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } - break; - } - if (distWithTarget.Magnitude() > 30.0f) { - if (m_pMyVehicle) { - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - } else { - float closestVehDist = SQR(60.0f); - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - CVehicle* foundVeh = nil; - for (int i = 0; i < lastVehicle; i++) { - CVehicle* nearVeh = (CVehicle*)vehicles[i]; - /* - Not used. - CVector vehSpeed = nearVeh->GetSpeed(); - CVector ourSpeed = GetSpeed(); - */ - CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); - if (vehDistVec.MagnitudeSqr() < closestVehDist - && m_pedInObjective->m_pMyVehicle != nearVeh) - { - foundVeh = nearVeh; - closestVehDist = vehDistVec.MagnitudeSqr(); - } - } - m_pMyVehicle = foundVeh; - if (m_pMyVehicle) { - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); - } - } - break; - } - // fall through - } - case OBJECTIVE_GOTO_AREA_ON_FOOT: - case OBJECTIVE_RUN_TO_AREA: - { - if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) - && InVehicle()) { - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } else { - distWithTarget = m_nextRoutePointPos - GetPosition(); - distWithTarget.z = 0.0f; - if (sq(m_distanceToCountSeekDone) >= distWithTarget.MagnitudeSqr()) { - bObjectiveCompleted = true; - bScriptObjectiveCompleted = true; - SetMoveState(PEDMOVE_STILL); - } else if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer || m_nPedState != PED_SEEK_POS) { - if (bUsePedNodeSeek) { - CVector bestCoords(0.0f, 0.0f, 0.0f); - m_vecSeekPos = m_nextRoutePointPos; - - if (!m_pNextPathNode) - FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); - - if (m_pNextPathNode) - m_vecSeekPos = m_pNextPathNode->GetPosition(); - } - SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); - } - } - - break; - } - case OBJECTIVE_GUARD_ATTACK: - { - if (m_pedInObjective) { - SetLookFlag(m_pedInObjective, true); - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - m_lookTimer = m_attackTimer; - TurnBody(); - float distWithTargetSc = distWithTarget.Magnitude(); - if (distWithTargetSc >= 20.0f) { - RestorePreviousObjective(); - } else if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { - if (m_nPedState != PED_SEEK_ENTITY && distWithTargetSc >= 2.0f) { - SetSeek(m_pedInObjective, 1.0f); - } else { - SetAttack(m_pedInObjective); - SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 1500.0f)); - } - SetAttackTimer(1000); - } - } else { - RestorePreviousObjective(); - } - break; - } - case OBJECTIVE_FOLLOW_ROUTE: - if (HaveReachedNextPointOnRoute(1.0f)) { - int nextPoint = GetNextPointOnRoute(); - m_nextRoutePointPos = CRouteNode::GetPointPosition(nextPoint); - } else { - SetSeek(m_nextRoutePointPos, 0.8f); - } - break; - case OBJECTIVE_SOLICIT_VEHICLE: - if (m_carInObjective) { - if (m_objectiveTimer <= CTimer::GetTimeInMilliseconds()) { - if (!bInVehicle) { - SetObjective(OBJECTIVE_NONE); - SetWanderPath(CGeneral::GetRandomNumber() & 7); - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; - if (IsPedInControl()) - m_pMyVehicle = nil; - } - } else { - if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_SOLICIT) - SetSeekCar(m_carInObjective, 0); - } - } else { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } - break; - case OBJECTIVE_HAIL_TAXI: - if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TAXI) && CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { - Say(SOUND_PED_TAXI_WAIT); - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TAXI, 4.0f); - m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; - } - break; - case OBJECTIVE_CATCH_TRAIN: - { - if (m_carInObjective) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); - } else { - CVehicle* trainToEnter = nil; - float closestCarDist = CHECK_NEARBY_THINGS_MAX_DIST; - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity* vehicles[8]; - - CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - for (int i = 0; i < lastVehicle; i++) { - CVehicle* nearVeh = (CVehicle*)vehicles[i]; - if (nearVeh->IsTrain()) { - CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); - float vehDist = vehDistVec.Magnitude(); - if (vehDist < closestCarDist && m_pedInObjective->m_pMyVehicle != nearVeh) - { - trainToEnter = nearVeh; - closestCarDist = vehDist; - } - } - } - if (trainToEnter) { - m_carInObjective = trainToEnter; - m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); - } - } - break; - } - case OBJECTIVE_BUY_ICE_CREAM: - if (m_carInObjective) { - if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_BUY_ICECREAM) - SetSeekCar(m_carInObjective, 0); - } else { - RestorePreviousObjective(); - RestorePreviousState(); - if (IsPedInControl()) - m_pMyVehicle = nil; - } - break; - case OBJECTIVE_STEAL_ANY_CAR: - { - if (bInVehicle) { - bScriptObjectiveCompleted = true; - RestorePreviousObjective(); - } else if (m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { - CVehicle *carToSteal = nil; - float closestCarDist = ENTER_CAR_MAX_DIST; - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity *vehicles[8]; - - // NB: This should've been ENTER_CAR_MAX_DIST actually, and is fixed in VC. - CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - for(int i = 0; i < lastVehicle; i++) { - CVehicle *nearVeh = (CVehicle*)vehicles[i]; - if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { - if (nearVeh->m_vecMoveSpeed.Magnitude() <= 0.1f) { - if (nearVeh->CanPedOpenLocks(this)) { - CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); - float vehDist = vehDistVec.Magnitude(); - if (vehDist < closestCarDist) { - carToSteal = nearVeh; - closestCarDist = vehDist; - } - } - } - } - } - if (carToSteal) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carToSteal); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - } else { - RestorePreviousObjective(); - RestorePreviousState(); - } - } - break; - } - case OBJECTIVE_MUG_CHAR: - { - if (m_pedInObjective) { - if (m_pedInObjective->IsPlayer() || m_pedInObjective->bInVehicle || m_pedInObjective->m_fHealth <= 0.0f) { - ClearObjective(); - return; - } - if (m_pedInObjective->m_nMoveState > PEDMOVE_WALK) { - ClearObjective(); - return; - } - if (m_pedInObjective->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && m_pedInObjective->m_pedInObjective == this) { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pedInObjective); - SetMoveState(PEDMOVE_SPRINT); - return; - } - if (m_pedInObjective->m_nPedState == PED_FLEE_ENTITY && m_fleeFrom == this - || m_pedInObjective->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE && m_pedInObjective->m_pedInObjective == this) { - ClearObjective(); - SetFindPathAndFlee(m_pedInObjective, 15000, true); - return; - } - float distWithTargetScSqr = distWithTarget.MagnitudeSqr(); - if (distWithTargetScSqr <= sq(10.0f)) { - if (distWithTargetScSqr <= sq(1.4f)) { - CAnimBlendAssociation *reloadAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD); - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, - GetPosition().x, GetPosition().y); - - if (reloadAssoc || !m_pedInObjective->IsPedShootable()) { - if (reloadAssoc && - (!reloadAssoc->IsRunning() || reloadAssoc->currentTime / reloadAssoc->hierarchy->totalLength > 0.8f)) { - CAnimBlendAssociation *punchAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f); - punchAssoc->flags |= ASSOC_DELETEFADEDOUT; - punchAssoc->flags |= ASSOC_FADEOUTWHENDONE; - CVector2D offset(distWithTarget.x, distWithTarget.y); - int dir = m_pedInObjective->GetLocalDirection(offset); - m_pedInObjective->StartFightDefend(dir, HITLEVEL_HIGH, 5); - m_pedInObjective->ReactToAttack(this); - m_pedInObjective->Say(SOUND_PED_ROBBED); - Say(SOUND_PED_MUGGING); - bRichFromMugging = true; - - // VC FIX: ClearObjective() clears m_pedInObjective in VC (also same with VC_PED_PORTS), so get it before call - CPed *victim = m_pedInObjective; - ClearObjective(); - if (victim->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT - || victim->m_pedInObjective != this) { - SetFindPathAndFlee(victim, 15000, true); - m_nLastPedState = PED_WANDER_PATH; - } else { - SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, victim); - SetMoveState(PEDMOVE_SPRINT); - m_nLastPedState = PED_WANDER_PATH; - } - } - } else { - eWeaponType weaponType = GetWeapon()->m_eWeaponType; - if (weaponType != WEAPONTYPE_UNARMED && weaponType != WEAPONTYPE_BASEBALLBAT) - SetCurrentWeapon(WEAPONTYPE_UNARMED); - - CAnimBlendAssociation *newReloadAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_AK_RELOAD, 8.0f); - newReloadAssoc->flags |= ASSOC_DELETEFADEDOUT; - newReloadAssoc->flags |= ASSOC_FADEOUTWHENDONE; - } - } else { - SetSeek(m_pedInObjective, 1.0f); - CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK); - - if (walkAssoc) - walkAssoc->speed = 1.3f; - } - } else { - ClearObjective(); - SetWanderPath(CGeneral::GetRandomNumber() & 7); - } - } else { -#ifdef VC_PED_PORTS - m_objective = OBJECTIVE_NONE; -#endif - ClearObjective(); - } - break; - } - case OBJECTIVE_FLEE_CAR: - if (!bInVehicle && m_nPedState != PED_FLEE_ENTITY && m_pMyVehicle) { - RestorePreviousObjective(); - SetFlee(m_pMyVehicle, 6000); - break; - } - // fall through - case OBJECTIVE_LEAVE_CAR: - if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (InVehicle() -#ifdef VC_PED_PORTS - && (FindPlayerPed() != this || !CPad::GetPad(0)->GetAccelerate() - || bBusJacked) -#endif - ) { - if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN - && (m_nPedType != PEDTYPE_COP -#ifdef VC_PED_PORTS - || m_pMyVehicle->IsBoat() -#endif - || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr2D() < sq(0.005f))) { - if (m_pMyVehicle->IsTrain()) - SetExitTrain(m_pMyVehicle); -#ifdef VC_PED_PORTS - else if (m_pMyVehicle->IsBoat()) - SetExitBoat(m_pMyVehicle); -#endif - else - SetExitCar(m_pMyVehicle, 0); - } - } else { - RestorePreviousObjective(); - } - } - break; -#ifdef VC_PED_PORTS - case OBJECTIVE_LEAVE_CAR_AND_DIE: - { - if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { - if (InVehicle()) { - if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN) { - if (m_pMyVehicle->IsBoat()) - SetExitBoat(m_pMyVehicle); - else if (m_pMyVehicle->bIsBus) - SetExitCar(m_pMyVehicle, 0); - else { - eCarNodes doorNode = CAR_DOOR_LF; - if (m_pMyVehicle->pDriver != this) { - if (m_pMyVehicle->pPassengers[0] == this) { - doorNode = CAR_DOOR_RF; - } else if (m_pMyVehicle->pPassengers[1] == this) { - doorNode = CAR_DOOR_LR; - } else if (m_pMyVehicle->pPassengers[2] == this) { - doorNode = CAR_DOOR_RR; - } - } - SetBeingDraggedFromCar(m_pMyVehicle, doorNode, false); - } - } - } - } - break; - } -#endif + pos.z -= 0.1f; + pos += GetForward()*0.2f; + particleProduceFootDust(this, pos, 0.02f, 1); } - if (bObjectiveCompleted - || m_objectiveTimer > 0 && CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { - RestorePreviousObjective(); - if (m_objectiveTimer > CTimer::GetTimeInMilliseconds() || !m_objectiveTimer) - m_objectiveTimer = CTimer::GetTimeInMilliseconds() - 1; - if (CharCreatedBy != RANDOM_CHAR || bInVehicle) { - if (IsPedInControl()) - RestorePreviousState(); - } else { - SetWanderPath(CGeneral::GetRandomNumber() & 7); + { + CVector pos(0.0f, 0.0f, 0.0f); + TransformToNode(pos, PED_FOOTR); + + pos.z -= 0.1f; + pos += GetForward()*0.2f; + particleProduceFootDust(this, pos, 0.02f, 1); + } + } +#endif + + + if (walkRunAssoc && walkRunAssocBlend > 0.5f && idleAssocBlend < 1.0f) { + float stepStart = 1 / 15.0f; + float stepEnd = walkRunAssoc->hierarchy->totalLength / 2.0f + stepStart; + float currentTime = walkRunAssoc->currentTime; + int stepPart = 0; + + if (currentTime >= stepStart && currentTime - walkRunAssoc->timeStep < stepStart) + stepPart = 1; + else if (currentTime >= stepEnd && currentTime - walkRunAssoc->timeStep < stepEnd) + stepPart = 2; + + if (stepPart != 0) { + DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); + CVector footPos(0.0f, 0.0f, 0.0f); + TransformToNode(footPos, stepPart == 1 ? PED_FOOTL : PED_FOOTR); + + CVector forward = GetForward(); + + footPos.z -= 0.1f; + footPos += 0.2f * forward; + + if (bDoBloodyFootprints) { + CVector2D top(forward * 0.26f); + CVector2D right(GetRight() * 0.14f); + + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &footPos, + top.x, top.y, + right.x, right.y, + 255, 255, 0, 0, 4.0f, 3000.0f, 1.0f); + + if (m_bloodyFootprintCountOrDeathTime <= 20) { + m_bloodyFootprintCountOrDeathTime = 0; + bDoBloodyFootprints = false; + } else { + m_bloodyFootprintCountOrDeathTime -= 20; + } } - ClearAimFlag(); - ClearLookFlag(); + if (CWeather::Rain <= 0.1f || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) { + if(IsPlayer()) + particleProduceFootDust(this, footPos, 0.0f, 4); + } +#ifdef PC_PARTICLE + else if(stepPart == 2) +#else + else +#endif + { + particleProduceFootSplash(this, footPos, 0.15f, 4); + } + } + } + + if (m_nSurfaceTouched == SURFACE_WATER) { + float pedSpeed = CVector2D(m_vecMoveSpeed).Magnitude(); + if (pedSpeed > 0.03f && CTimer::GetFrameCounter() % 2 == 0 && pedSpeed > 0.13f) { +#ifdef PC_PARTICLE + float particleSize = pedSpeed * 2.0f; + + if (particleSize < 0.25f) + particleSize = 0.25f; + + if (particleSize > 0.75f) + particleSize = 0.75f; + + CVector particlePos = GetPosition() + GetForward() * 0.3f; + particlePos.z -= 1.2f; + + CVector particleDir = m_vecMoveSpeed * -0.75f; + + particleDir.z = CGeneral::GetRandomNumberInRange(0.01f, 0.03f); + CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos, particleDir, nil, 0.8f * particleSize, CRGBA(155,155,185,128), 0, 0, 0, 0); + + particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); + CParticle::AddParticle(PARTICLE_RUBBER_SMOKE, particlePos, particleDir, nil, particleSize, CRGBA(255,255,255,255), 0, 0, 0, 0); +#else + CVector particlePos = (GetPosition() - 0.3f * GetUp()) + GetForward()*0.3f; + CVector particleDir = m_vecMoveSpeed * 0.45f; + particleDir.z = CGeneral::GetRandomNumberInRange(0.03f, 0.05f); + CParticle::AddParticle(PARTICLE_PED_SPLASH, particlePos-CVector(0.0f, 0.0f, 1.2f), particleDir, nil, 0.0f, CRGBA(155, 185, 155, 255)); +#endif } } } -void -CPed::SetShootTimer(uint32 time) +// Actually GetLocalDirectionTo(Turn/Look) +int +CPed::GetLocalDirection(const CVector2D &posOffset) { - if (CTimer::GetTimeInMilliseconds() > m_shootTimer) { - m_shootTimer = CTimer::GetTimeInMilliseconds() + time; - } -} + int direction; + float angle; -void -CPed::SetSeekCar(CVehicle *car, uint32 doorNode) -{ - if (m_nPedState == PED_SEEK_CAR) - return; + for (angle = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); angle < 0.0f; angle += TWOPI); -#ifdef VC_PED_PORTS - if (!CanSetPedState() || m_nPedState == PED_DRIVING) - return; -#endif + for (direction = RADTODEG(angle)/90.0f; direction > 3; direction -= 4); - SetStoredState(); - m_pSeekTarget = car; - m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_carInObjective = car; - m_carInObjective->RegisterReference((CEntity**) &m_carInObjective); - m_pMyVehicle = car; - m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); - // m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_vehEnterType = doorNode; - m_distanceToCountSeekDone = 0.5f; - m_nPedState = PED_SEEK_CAR; - -} - -void -CPed::SetSeekBoatPosition(CVehicle *boat) -{ - if (m_nPedState == PED_SEEK_IN_BOAT || boat->pDriver -#if defined VC_PED_PORTS || defined FIX_BUGS - || !IsPedInControl() -#endif - ) - return; - - SetStoredState(); - m_carInObjective = boat; - m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); - m_pMyVehicle = boat; - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_distanceToCountSeekDone = 0.5f; - m_nPedState = PED_SEEK_IN_BOAT; -} - -void -CPed::SetExitTrain(CVehicle* train) -{ - if (m_nPedState == PED_EXIT_TRAIN || train->GetStatus() != STATUS_TRAIN_NOT_MOVING || !((CTrain*)train)->Doors[0].IsFullyOpen()) - return; - - /* - // Not used - CVector exitPos; - GetNearestTrainPedPosition(train, exitPos); - */ - m_nPedState = PED_EXIT_TRAIN; - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETOUT, 4.0f); - m_pVehicleAnim->SetFinishCallback(PedSetOutTrainCB, this); - bUsesCollision = false; - LineUpPedWithTrain(); + // 0-forward, 1-left, 2-backward, 3-right. + return direction; } #ifdef NEW_WALK_AROUND_ALGORITHM @@ -14363,486 +4071,734 @@ CPed::SetDirectionToWalkAroundObject(CEntity *obj) m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 280.0f * dist * checkIntervalInTime; } -int32 -CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) +bool +CPed::IsPedInControl(void) { - bool collidedWithBoat = false; - bool belowTorsoCollided = false; - float gravityEffect = -0.15f * CTimer::GetTimeStep(); - CColPoint intersectionPoint; - CColLine ourLine; - - CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); - CColModel *hisCol = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex())->GetColModel(); - - if (!bUsesCollision) - return false; - - if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) - collidedWithBoat = true; - - // ofc we're not vehicle - if (!m_bIsVehicleBeingShifted && !bSkipLineCol -#ifdef VC_PED_PORTS - && !collidingEnt->IsPed() -#endif - ) { - if (!bCollisionProcessed) { -#ifdef VC_PED_PORTS - m_pCurrentPhysSurface = nil; -#endif - if (bIsStanding) { - bIsStanding = false; - bWasStanding = true; - } - bCollisionProcessed = true; - m_fCollisionSpeed += m_vecMoveSpeed.Magnitude2D() * CTimer::GetTimeStep(); - bStillOnValidPoly = false; - if (IsPlayer() || m_fCollisionSpeed >= 1.0f - && (m_fCollisionSpeed >= 2.0f || m_nPedState != PED_WANDER_PATH)) { - m_collPoly.valid = false; - m_fCollisionSpeed = 0.0f; - bHitSteepSlope = false; - } else { - CVector pos = GetPosition(); - float potentialGroundZ = GetPosition().z - FEET_OFFSET; - if (bWasStanding) { - pos.z += -0.25f; - potentialGroundZ += gravityEffect; - } - if (CCollision::IsStoredPolyStillValidVerticalLine(pos, potentialGroundZ, intersectionPoint, &m_collPoly)) { - bStillOnValidPoly = true; -#ifdef VC_PED_PORTS - if(!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; - if (bSomeVCflag1) - bSomeVCflag1 = false; - } -#else - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; -#endif - - m_vecMoveSpeed.z = 0.0f; - bIsStanding = true; - } else { - m_collPoly.valid = false; - m_fCollisionSpeed = 0.0f; - bHitSteepSlope = false; - } - } - } - - if (!bStillOnValidPoly) { - CVector potentialCenter = GetPosition(); - potentialCenter.z = GetPosition().z - 0.52f; - - // 0.52f should be a ped's approx. radius - float totalRadiusWhenCollided = collidingEnt->GetBoundRadius() + 0.52f - gravityEffect; - if (bWasStanding) { - if (collidedWithBoat) { - potentialCenter.z += 2.0f * gravityEffect; - totalRadiusWhenCollided += Abs(gravityEffect); - } else { - potentialCenter.z += gravityEffect; - } - } - if (sq(totalRadiusWhenCollided) > (potentialCenter - collidingEnt->GetBoundCentre()).MagnitudeSqr()) { - ourLine.p0 = GetPosition(); - ourLine.p1 = GetPosition(); - ourLine.p1.z = GetPosition().z - FEET_OFFSET; - if (bWasStanding) { - ourLine.p1.z = ourLine.p1.z + gravityEffect; - ourLine.p0.z = ourLine.p0.z + -0.25f; - } - float minDist = 1.0f; - belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, - intersectionPoint, minDist, false, &m_collPoly); - - if (collidedWithBoat && bWasStanding && !belowTorsoCollided) { - ourLine.p0.z = ourLine.p1.z; - ourLine.p1.z = ourLine.p1.z + gravityEffect; - belowTorsoCollided = CCollision::ProcessVerticalLine(ourLine, collidingEnt->GetMatrix(), *hisCol, - intersectionPoint, minDist, false, &m_collPoly); - } - if (belowTorsoCollided) { -#ifndef VC_PED_PORTS - if (!collidingEnt->IsPed()) { -#endif - if (!bIsStanding - || FEET_OFFSET + intersectionPoint.point.z > GetPosition().z - || collidedWithBoat && 3.12f + intersectionPoint.point.z > GetPosition().z) { - - if (!collidingEnt->IsVehicle() && !collidingEnt->IsObject()) { - m_pCurSurface = collidingEnt; - collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); - bTryingToReachDryLand = false; - bOnBoat = false; - } else { - m_pCurrentPhysSurface = (CPhysical*)collidingEnt; - collidingEnt->RegisterReference((CEntity**)&m_pCurrentPhysSurface); - m_vecOffsetFromPhysSurface = intersectionPoint.point - collidingEnt->GetPosition(); - m_pCurSurface = collidingEnt; - collidingEnt->RegisterReference((CEntity**)&m_pCurSurface); - m_collPoly.valid = false; - if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) { - bOnBoat = true; - } else { - bOnBoat = false; - } - } -#ifdef VC_PED_PORTS - if (!bSomeVCflag1 || FEET_OFFSET + intersectionPoint.point.z < GetPosition().z) { - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; - if (bSomeVCflag1) - bSomeVCflag1 = false; - } -#else - GetMatrix().GetPosition().z = FEET_OFFSET + intersectionPoint.point.z; -#endif - m_nSurfaceTouched = intersectionPoint.surfaceB; - if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF) { - bHitSteepSlope = true; - m_vecDamageNormal = intersectionPoint.normal; - } - } -#ifdef VC_PED_PORTS - float upperSpeedLimit = 0.33f; - float lowerSpeedLimit = -0.25f; - float speed = m_vecMoveSpeed.Magnitude2D(); - if (m_nPedState == PED_IDLE) { - upperSpeedLimit *= 2.0f; - lowerSpeedLimit *= 1.5f; - } - CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); - if (!bWasStanding && speed > upperSpeedLimit && (/*!bPushedAlongByCar ||*/ m_vecMoveSpeed.z < lowerSpeedLimit) - && m_pCollidingEntity != collidingEnt) { - - float damage = 100.0f * Max(speed - 0.25f, 0.0f); - float damage2 = damage; - if (m_vecMoveSpeed.z < -0.25f) - damage += (-0.25f - m_vecMoveSpeed.z) * 150.0f; - - uint8 dir = 2; // from backward - if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { - CVector2D offset = -m_vecMoveSpeed; - dir = GetLocalDirection(offset); - } - - InflictDamage(collidingEnt, WEAPONTYPE_FALL, damage, PEDPIECE_TORSO, dir); - if (IsPlayer() && damage2 > 5.0f) - Say(SOUND_PED_LAND); - - } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { - InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); - } -#else - float speedSqr = 0.0f; - CAnimBlendAssociation *fallAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); - if (!bWasStanding && (m_vecMoveSpeed.z < -0.25f || (speedSqr = m_vecMoveSpeed.MagnitudeSqr()) > sq(0.5f))) { - if (speedSqr == 0.0f) - speedSqr = sq(m_vecMoveSpeed.z); - - uint8 dir = 2; // from backward - if (m_vecMoveSpeed.x > 0.01f || m_vecMoveSpeed.x < -0.01f || m_vecMoveSpeed.y > 0.01f || m_vecMoveSpeed.y < -0.01f) { - CVector2D offset = -m_vecMoveSpeed; - dir = GetLocalDirection(offset); - } - InflictDamage(collidingEnt, WEAPONTYPE_FALL, 350.0f * sq(speedSqr), PEDPIECE_TORSO, dir); - - } else if (!bWasStanding && fallAnim && -0.016f * CTimer::GetTimeStep() > m_vecMoveSpeed.z) { - InflictDamage(collidingEnt, WEAPONTYPE_FALL, 15.0f, PEDPIECE_TORSO, 2); - } -#endif - m_vecMoveSpeed.z = 0.0f; - bIsStanding = true; -#ifndef VC_PED_PORTS - } else { - bOnBoat = false; - } -#endif - } else { - bOnBoat = false; - } - } - } - } - - int ourCollidedSpheres = CCollision::ProcessColModels(GetMatrix(), *ourCol, collidingEnt->GetMatrix(), *hisCol, collidingPoints, nil, nil); - if (ourCollidedSpheres > 0 || belowTorsoCollided) { - AddCollisionRecord(collidingEnt); - if (!collidingEnt->IsBuilding()) - ((CPhysical*)collidingEnt)->AddCollisionRecord(this); - - if (ourCollidedSpheres > 0 && (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic())) { - bHasHitWall = true; - } - } - if (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic()) { - - if (bWasStanding) { - CVector sphereNormal; - float normalLength; - for(int sphere = 0; sphere < ourCollidedSpheres; sphere++) { - sphereNormal = collidingPoints[sphere].normal; -#ifdef VC_PED_PORTS - if (sphereNormal.z >= -1.0f || !IsPlayer()) { -#endif - normalLength = sphereNormal.Magnitude2D(); - if (normalLength != 0.0f) { - sphereNormal.x = sphereNormal.x / normalLength; - sphereNormal.y = sphereNormal.y / normalLength; - } -#ifdef VC_PED_PORTS - } else { - float speed = m_vecMoveSpeed.Magnitude2D(); - sphereNormal.x = -m_vecMoveSpeed.x / Max(0.001f, speed); - sphereNormal.y = -m_vecMoveSpeed.y / Max(0.001f, speed); - GetMatrix().GetPosition().z -= 0.05f; - bSomeVCflag1 = true; - } -#endif - sphereNormal.Normalise(); - collidingPoints[sphere].normal = sphereNormal; - if (collidingPoints[sphere].surfaceB == SURFACE_STEEP_CLIFF) - bHitSteepSlope = true; - } - } - } - return ourCollidedSpheres; -} - -void -CPed::SetFormation(eFormation type) -{ - // FIX: Formations in GetFormationPosition were in range 1-8, whereas in here it's 0-7. - // To not change the behaviour, range in here tweaked by 1 with the use of enum. - - switch (m_pedFormation) { - case FORMATION_REAR: - case FORMATION_REAR_LEFT: - case FORMATION_REAR_RIGHT: - case FORMATION_FRONT_LEFT: - case FORMATION_FRONT_RIGHT: - case FORMATION_LEFT: - case FORMATION_RIGHT: - case FORMATION_FRONT: - break; - default: - Error("Unknown formation type, PedAI.cpp"); - break; - } - m_pedFormation = type; -} - -void -CPed::SetFollowRoute(int16 currentPoint, int16 routeType) -{ - m_routeLastPoint = currentPoint; - m_routeStartPoint = CRouteNode::GetRouteStart(currentPoint); - m_routePointsPassed = 0; - m_routeType = routeType; - m_routePointsBeingPassed = 1; - m_objective = OBJECTIVE_FOLLOW_ROUTE; - m_nextRoutePointPos = CRouteNode::GetPointPosition(GetNextPointOnRoute()); -} - -// "Wander range" state is unused in game, and you can't use it without SetWanderRange anyway -void -CPed::WanderRange(void) -{ - bool arrived = Seek(); - if (arrived) { - Idle(); - if ((m_randomSeed + 3 * CTimer::GetFrameCounter()) % 1000 > 997) { - CVector2D newCoords2D = m_wanderRangeBounds->GetRandomPointInRange(); - SetSeek(CVector(newCoords2D.x, newCoords2D.y, GetPosition().z), 2.5f); - } - } + return m_nPedState <= PED_STATES_NO_AI + && !bIsInTheAir && !bIsLanding + && m_fHealth > 0.0f; } bool -CPed::WillChat(CPed *stranger) +CPed::IsPedShootable(void) { - if (m_pNextPathNode && m_pLastPathNode) { - if (m_pNextPathNode != m_pLastPathNode && ThePaths.TestCrossesRoad(m_pNextPathNode, m_pLastPathNode)) { - return false; - } - } - if (m_nSurfaceTouched == SURFACE_TARMAC) + return m_nPedState <= PED_STATES_NO_ST; +} + +bool +CPed::UseGroundColModel(void) +{ + return m_nPedState == PED_FALL || + m_nPedState == PED_DIVE_AWAY || + m_nPedState == PED_DIE || + m_nPedState == PED_DEAD; +} + +bool +CPed::CanPedReturnToState(void) +{ + return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK && + m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY; +} + +bool +CPed::CanSetPedState(void) +{ + return !DyingOrDead() && m_nPedState != PED_ARRESTED && !EnteringCar() && m_nPedState != PED_STEAL_CAR; +} + +bool +CPed::CanStrafeOrMouseControl(void) +{ +#ifdef FREE_CAM + if (CCamera::bFreeCam) return false; - if (stranger == this) - return false; - if (m_nPedType == stranger->m_nPedType) - return true; - if (m_nPedType == PEDTYPE_CRIMINAL) - return false; - if ((IsGangMember() || stranger->IsGangMember()) && m_nPedType != stranger->m_nPedType) - return false; - return true; +#endif + return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY || + m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP; } void -CPed::SetEnterTrain(CVehicle *train, uint32 unused) +CPed::PedGetupCB(CAnimBlendAssociation* animAssoc, void* arg) { - if (m_nPedState == PED_ENTER_TRAIN || !((CTrain*)train)->Doors[0].IsFullyOpen()) - return; + CPed* ped = (CPed*)arg; + if (ped->m_nPedState == PED_GETUP) + RpAnimBlendClumpSetBlendDeltas(ped->GetClump(), ASSOC_PARTIAL, -1000.0f); + + ped->bFallenDown = false; + animAssoc->blendDelta = -1000.0f; + if (ped->m_nPedState == PED_GETUP) + ped->RestorePreviousState(); + + if (ped->m_nPedState != PED_FLEE_POS && ped->m_nPedState != PED_FLEE_ENTITY) + ped->SetMoveState(PEDMOVE_STILL); + else + ped->SetMoveState(PEDMOVE_RUN); + + ped->SetMoveAnim(); + ped->bGetUpAnimStarted = false; +} + +void +CPed::PedLandCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + animAssoc->blendDelta = -1000.0f; + ped->bIsLanding = false; + + if (ped->m_nPedState == PED_JUMP) + ped->RestorePreviousState(); +} + +void +CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) +{ /* - // Not used - CVector enterPos; - GetNearestTrainPedPosition(train, enterPos); + CPed *ped = (CPed*)arg; + + if (ped->m_nPedState == PED_STAGGER) + // nothing */ - m_fRotationCur = train->GetForward().Heading() - HALFPI; - m_pMyVehicle = train; - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); +} - m_nPedState = PED_ENTER_TRAIN; - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETIN, 4.0f); - m_pVehicleAnim->SetFinishCallback(PedSetInTrainCB, this); - bUsesCollision = false; - LineUpPedWithTrain(); - if (IsPlayer()) { - if (((CPlayerPed*)this)->m_bAdrenalineActive) - ((CPlayerPed*)this)->ClearAdrenaline(); +void +CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + bool startedToRun = false; + ped->bUsesCollision = true; + ped->m_actionX = 0.0f; + ped->m_actionY = 0.0f; + ped->bVehExitWillBeInstant = false; + if (veh && veh->IsBoat()) + ped->ApplyMoveSpeed(); + + if (ped->m_objective == OBJECTIVE_LEAVE_CAR) + ped->RestorePreviousObjective(); +#ifdef VC_PED_PORTS + else if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { + ped->m_fHealth = 0.0f; + ped->SetDie(ANIM_FLOOR_HIT, 4.0f, 0.5f); } -} +#endif -void -CPed::SetDuck(uint32 time) -{ - if (bIsDucking || CTimer::GetTimeInMilliseconds() <= m_duckTimer) - return; - - if (bCrouchWhenShooting && (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN)) { - CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); - if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_LOW, 4.0f); - bIsDucking = true; - m_duckTimer = CTimer::GetTimeInMilliseconds() + time; - } - } else { - CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); - bIsDucking = true; - m_duckTimer = CTimer::GetTimeInMilliseconds() + time; - } + ped->bInVehicle = false; + if (veh && veh->IsCar() && !veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, nil)) { + ped->PositionPedOutOfCollision(); } -} -void -CPed::SeekBoatPosition(void) -{ - if (m_carInObjective && !m_carInObjective->pDriver) { - CVehicleModelInfo *boatModel = m_carInObjective->GetModelInfo(); - - CVector enterOffset; - enterOffset = boatModel->GetFrontSeatPosn(); - enterOffset.x = 0.0f; - CMatrix boatMat(m_carInObjective->GetMatrix()); - SetMoveState(PEDMOVE_WALK); - m_vecSeekPos = boatMat * enterOffset; - if (Seek()) { - // We arrived to the boat - m_vehEnterType = 0; - SetEnterCar(m_carInObjective, 0); - } - } else - RestorePreviousState(); -} - -void -CPed::SetEnterCar(CVehicle *car, uint32 unused) -{ - if (CCranes::IsThisCarBeingCarriedByAnyCrane(car)) { - RestorePreviousState(); - RestorePreviousObjective(); - } else { - uint8 doorFlag; - eDoors door; - switch (m_vehEnterType) { - case CAR_DOOR_RF: - doorFlag = CAR_DOOR_FLAG_RF; - door = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_RR: - doorFlag = CAR_DOOR_FLAG_RR; - door = DOOR_REAR_RIGHT; - break; - case CAR_DOOR_LF: - doorFlag = CAR_DOOR_FLAG_LF; - door = DOOR_FRONT_LEFT; - break; - case CAR_DOOR_LR: - doorFlag = CAR_DOOR_FLAG_LR; - door = DOOR_REAR_LEFT; - break; - default: - doorFlag = CAR_DOOR_FLAG_UNKNOWN; - break; - } - if (!IsPedInControl() || m_fHealth <= 0.0f - || doorFlag & car->m_nGettingInFlags || doorFlag & car->m_nGettingOutFlags - || car->bIsBeingCarJacked || m_pVehicleAnim - || doorFlag && !car->IsDoorReady(door) && !car->IsDoorFullyOpen(door)) - SetMoveState(PEDMOVE_STILL); + if (ped->m_nPedState == PED_EXIT_CAR) { + if (ped->m_nPedType == PEDTYPE_COP) + ped->SetIdle(); else - SetEnterCar_AllClear(car, m_vehEnterType, doorFlag); + ped->RestorePreviousState(); + + veh = ped->m_pMyVehicle; + if (ped->bFleeAfterExitingCar && veh) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(veh->GetPosition(), 12000); + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { + ped->SetMoveState(PEDMOVE_SPRINT); + ped->Say(SOUND_PED_FLEE_SPRINT); + } else { + ped->SetMoveState(PEDMOVE_RUN); + ped->Say(SOUND_PED_FLEE_RUN); + } + startedToRun = true; + + // This is not a good way to do this... + ped->m_nLastPedState = PED_WANDER_PATH; + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) + ped->SetObjectiveTimer(30000); + ped->m_nLastPedState = PED_NONE; + + } else if (ped->bGonnaKillTheCarJacker) { + + // Kill objective is already given at this point. + ped->bGonnaKillTheCarJacker = false; + if (ped->m_pedInObjective) { + if (!(CGeneral::GetRandomNumber() & 1) + && ped->m_nPedType != PEDTYPE_COP + && (!ped->m_pedInObjective->IsPlayer() || !CTheScripts::IsPlayerOnAMission())) { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + } + ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1500; + } + int waitTime = 1500; + ped->SetWaitState(WAITSTATE_PLAYANIM_COWER, &waitTime); + ped->SetMoveState(PEDMOVE_RUN); + startedToRun = true; + } else if (ped->m_objective == OBJECTIVE_NONE && ped->CharCreatedBy != MISSION_CHAR && ped->m_nPedState == PED_IDLE && !ped->IsPlayer()) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + } + } +#ifdef VC_PED_PORTS + else { + ped->m_nPedState = PED_IDLE; + } +#endif + + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + ped->RestartNonPartialAnims(); + ped->m_pVehicleAnim = nil; + CVector posFromZ = ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posFromZ); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(posFromZ); + veh = ped->m_pMyVehicle; + if (veh) { + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { + if (veh->pDriver) { + if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = 0; + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = 0; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = nil; + CWorld::Players[CWorld::PlayerInFocus].m_nMoney -= 100; + if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney < 0) + CWorld::Players[CWorld::PlayerInFocus].m_nMoney = 0; + } + } + } + veh->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + if (veh->pDriver == ped) { + veh->RemoveDriver(); + veh->SetStatus(STATUS_ABANDONED); + if (veh->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + veh->m_nDoorLock = CARLOCK_UNLOCKED; + if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) + veh->ChangeLawEnforcerState(false); + } else { + veh->RemovePassenger(ped); + } + + if (veh->bIsBus && !veh->IsUpsideDown() && !veh->IsOnItsSide()) { + float angleAfterExit; + if (ped->m_vehEnterType == CAR_DOOR_LF) { + angleAfterExit = HALFPI + veh->GetForward().Heading(); + } else { + angleAfterExit = veh->GetForward().Heading() - HALFPI; + } + ped->SetHeading(angleAfterExit); + ped->m_fRotationDest = angleAfterExit; + ped->m_fRotationCur = angleAfterExit; + if (!ped->bBusJacked) + ped->SetMoveState(PEDMOVE_WALK); + } + if (CGarages::IsPointWithinAnyGarage(ped->GetPosition())) + veh->bLightsOn = false; + } + + if (ped->IsPlayer()) + AudioManager.PlayerJustLeftCar(); + + ped->ReplaceWeaponWhenExitingVehicle(); + + ped->bOnBoat = false; + if (ped->bBusJacked) { + ped->SetFall(1500, ANIM_KO_SKID_BACK, false); + ped->bBusJacked = false; + } + ped->m_nStoredMoveState = PEDMOVE_NONE; + if (!ped->IsPlayer()) { + // It's a shame... +#ifdef FIX_BUGS + int createdBy = ped->CharCreatedBy; +#else + int createdBy = !ped->CharCreatedBy; +#endif + + if (createdBy == MISSION_CHAR && !startedToRun) + ped->SetMoveState(PEDMOVE_WALK); } } void -CPed::SetRadioStation(void) +CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) { - static const uint8 radiosPerRadioCategories[10][4] = { - {JAH_RADIO, RISE_FM, GAME_FM, MSX_FM}, - {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, - {RISE_FM, GAME_FM, MSX_FM, FLASHBACK}, - {HEAD_RADIO, RISE_FM, LIPS_106, MSX_FM}, - {HEAD_RADIO, RISE_FM, MSX_FM, FLASHBACK}, - {JAH_RADIO, RISE_FM, LIPS_106, FLASHBACK}, - {HEAD_RADIO, RISE_FM, LIPS_106, FLASHBACK}, - {HEAD_RADIO, JAH_RADIO, LIPS_106, FLASHBACK}, - {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, - {CHATTERBOX, HEAD_RADIO, LIPS_106, GAME_FM} - }; - uint8 orderInCat = 0; // BUG: this wasn't initialized + CAnimBlendAssociation *quickJackedAssoc; + CVehicle *vehicle; + CPed *ped = (CPed*)arg; - if (IsPlayer() || !m_pMyVehicle || m_pMyVehicle->pDriver != this) - return; + quickJackedAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_CAR_QJACKED); + if (ped->m_nPedState != PED_ARRESTED) { + ped->m_nLastPedState = PED_NONE; + if (dragAssoc) + dragAssoc->blendDelta = -1000.0f; + } + ped->RestartNonPartialAnims(); + ped->m_pVehicleAnim = nil; + ped->m_pSeekTarget = nil; + vehicle = ped->m_pMyVehicle; - uint8 category = GetPedRadioCategory(GetModelIndex()); - if (DMAudio.IsMP3RadioChannelAvailable()) { - if (CGeneral::GetRandomNumber() & 15) { - for (orderInCat = 0; orderInCat < 4; orderInCat++) { - if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) - break; - } + if (vehicle) { + vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + + if (vehicle->pDriver == ped) { + vehicle->RemoveDriver(); + if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + vehicle->m_nDoorLock = CARLOCK_UNLOCKED; + + if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) + vehicle->ChangeLawEnforcerState(false); } else { - m_pMyVehicle->m_nRadioStation = USERTRACK; - } - } else { - for (orderInCat = 0; orderInCat < 4; orderInCat++) { - if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) - break; + vehicle->RemovePassenger(ped); } } - if (orderInCat == 4) { - if (DMAudio.IsMP3RadioChannelAvailable()) { - if (CGeneral::GetRandomNumber() & 15) - m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; - else - m_pMyVehicle->m_nRadioStation = USERTRACK; - } else { - m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; + ped->bInVehicle = false; + if (ped->IsPlayer()) + AudioManager.PlayerJustLeftCar(); + +#ifdef VC_PED_PORTS + if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { + dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); + ped->m_fHealth = 0.0f; + ped->SetDie(ANIM_FLOOR_HIT, 1000.0f, 0.5f); + return; + } +#endif + + if (quickJackedAssoc) { + dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); + } else { + dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); + if (ped->CanSetPedState()) + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); + } + + ped->ReplaceWeaponWhenExitingVehicle(); + + ped->m_nStoredMoveState = PEDMOVE_NONE; + ped->bVehExitWillBeInstant = false; +} + +void +CPed::PedSetInCarCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + // Pointless code + if (!veh) + return; + +#ifdef VC_PED_PORTS + // Situation of entering car as a driver while there is already a driver exiting atm. + CPed *driver = veh->pDriver; + if (driver && driver->m_nPedState == PED_DRIVING && !veh->bIsBus && driver->m_objective == OBJECTIVE_LEAVE_CAR + && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { + + if (!ped->IsPlayer() && (ped->CharCreatedBy != MISSION_CHAR || driver->IsPlayer())) { + ped->QuitEnteringCar(); + return; } + if (driver->CharCreatedBy == MISSION_CHAR) { + PedSetOutCarCB(nil, veh->pDriver); + if (driver->m_pMyVehicle) { + driver->PositionPedOutOfCollision(); + } else { + driver->m_pMyVehicle = veh; + driver->PositionPedOutOfCollision(); + driver->m_pMyVehicle = nil; + } + veh->pDriver = nil; + } else { + driver->SetDead(); + driver->FlagToDestroyWhenNextProcessed(); + veh->pDriver = nil; + } + } +#endif + + if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) + return; + + ped->bInVehicle = true; + if (ped->m_nPedType == PEDTYPE_PROSTITUTE) { + if (veh->pDriver) { + if (veh->pDriver->IsPlayer() && ped->CharCreatedBy == RANDOM_CHAR) { + CWorld::Players[CWorld::PlayerInFocus].m_nSexFrequency = 1000; + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; + CWorld::Players[CWorld::PlayerInFocus].m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; + CWorld::Players[CWorld::PlayerInFocus].m_pHooker = (CCivilianPed*)ped; + } + } + } + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER +#if defined VC_PED_PORTS || defined FIX_BUGS + || ped->m_nPedState == PED_CARJACK +#endif + ) + veh->bIsBeingCarJacked = false; + + if (veh->m_nNumGettingIn) + --veh->m_nNumGettingIn; + + if (ped->IsPlayer() && ((CPlayerPed*)ped)->m_bAdrenalineActive) + ((CPlayerPed*)ped)->ClearAdrenaline(); + + if (veh->IsBoat()) { + if (ped->IsPlayer()) { +#if defined VC_PED_PORTS || defined FIX_BUGS + CCarCtrl::RegisterVehicleOfInterest(veh); +#endif + if (veh->GetStatus() == STATUS_SIMPLE) { + veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.00001f); + veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + } + veh->SetStatus(STATUS_PLAYER); + AudioManager.PlayerJustGotInCar(); + } + veh->SetDriver(ped); + if (!veh->bEngineOn) + veh->bEngineOn = true; + + ped->m_nPedState = PED_DRIVING; + ped->StopNonPartialAnims(); + return; + } + + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->blendDelta = -1000.0f; + + ped->bDoBloodyFootprints = false; + if (veh->m_nAlarmState == -1) + veh->m_nAlarmState = 15000; + + if (ped->IsPlayer()) { + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (veh->GetStatus() == STATUS_SIMPLE) { + veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + } + veh->SetStatus(STATUS_PLAYER); + } + AudioManager.PlayerJustGotInCar(); + } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (veh->GetStatus() == STATUS_SIMPLE) { + veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + veh->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + } + veh->SetStatus(STATUS_PHYSICS); + } + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + for (int i = 0; i < veh->m_nNumMaxPassengers; ++i) { + CPed *passenger = veh->pPassengers[i]; + if (passenger && passenger->CharCreatedBy == RANDOM_CHAR) { + passenger->SetObjective(OBJECTIVE_LEAVE_CAR, veh); +#ifdef VC_PED_PORTS + passenger->m_leaveCarTimer = CTimer::GetTimeInMilliseconds(); +#endif + } + } + } + // This shouldn't happen at all. Passengers can't enter with PED_CARJACK. Even though they did, we shouldn't call AddPassenger in here and SetDriver in below. +#if !defined VC_PED_PORTS && !defined FIX_BUGS + else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + if (ped->m_nPedState == PED_CARJACK) { + veh->AddPassenger(ped, 0); + ped->m_nPedState = PED_DRIVING; + ped->RestorePreviousObjective(); + ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + } else if (veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) { + veh->AutoPilot.m_nCruiseSpeed = 17; + } + } +#endif + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK) { + veh->SetDriver(ped); + if (veh->VehicleCreatedBy == PARKED_VEHICLE) { + veh->VehicleCreatedBy = RANDOM_VEHICLE; + ++CCarCtrl::NumRandomCars; + --CCarCtrl::NumParkedCars; + } + if (veh->bIsAmbulanceOnDuty) { + veh->bIsAmbulanceOnDuty = false; + --CCarCtrl::NumAmbulancesOnDuty; + } + if (veh->bIsFireTruckOnDuty) { + veh->bIsFireTruckOnDuty = false; + --CCarCtrl::NumFiretrucksOnDuty; + } + if (ped->m_nPedType == PEDTYPE_COP && veh->IsLawEnforcementVehicle()) + veh->ChangeLawEnforcerState(true); + + if (!veh->bEngineOn) { + veh->bEngineOn = true; + DMAudio.PlayOneShot(ped->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); + } + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && ped->CharCreatedBy == RANDOM_CHAR + && ped != FindPlayerPed() && ped->m_nPedType != PEDTYPE_EMERGENCY) { + + CCarCtrl::JoinCarWithRoadSystem(veh); + veh->AutoPilot.m_nCarMission = MISSION_CRUISE; + veh->AutoPilot.m_nTempAction = TEMPACT_NONE; + veh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + veh->AutoPilot.m_nCruiseSpeed = 25; + } + ped->m_nPedState = PED_DRIVING; + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + + if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) + ped->m_prevObjective = OBJECTIVE_NONE; + + ped->RestorePreviousObjective(); + } + + } else if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + if (veh->bIsBus) { + veh->AddPassenger(ped); + } else { + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + veh->AddPassenger(ped, 0); + break; + case CAR_DOOR_RR: + veh->AddPassenger(ped, 2); + break; + case CAR_DOOR_LR: + veh->AddPassenger(ped, 1); + break; + default: + veh->AddPassenger(ped); + break; + } + } + ped->m_nPedState = PED_DRIVING; + if (ped->m_prevObjective == OBJECTIVE_RUN_TO_AREA || ped->m_prevObjective == OBJECTIVE_GOTO_CHAR_ON_FOOT || ped->m_prevObjective == OBJECTIVE_KILL_CHAR_ON_FOOT) + ped->m_prevObjective = OBJECTIVE_NONE; + + ped->RestorePreviousObjective(); +#ifdef VC_PED_PORTS + if(veh->pDriver && ped->CharCreatedBy == RANDOM_CHAR) + veh->AutoPilot.m_nCruiseSpeed = 17; +#endif + } + + veh->m_nGettingInFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + + if (veh->bIsBus && !veh->m_nGettingInFlags) + ((CAutomobile*)veh)->SetBusDoorTimer(1000, 1); + + switch (ped->m_objective) { + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + break; + default: + ped->SetObjective(OBJECTIVE_NONE); + } + + if (veh->pDriver == ped) { + if (veh->bLowVehicle) { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); + } else { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); + } + } else if (veh->bLowVehicle) { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITPLO, 100.0f); + } else { + ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SITP, 100.0f); + } + + ped->StopNonPartialAnims(); + if (veh->bIsBus) + ped->bRenderPedInCar = false; + + // FIX: RegisterVehicleOfInterest not just registers the vehicle, but also updates register time. So remove the IsThisVehicleInteresting check. +#ifndef FIX_BUGS + if (ped->IsPlayer() && !CCarCtrl::IsThisVehicleInteresting(veh) && veh->VehicleCreatedBy != MISSION_VEHICLE) { +#else + if (ped->IsPlayer() && veh->VehicleCreatedBy != MISSION_VEHICLE) { +#endif + CCarCtrl::RegisterVehicleOfInterest(veh); + + if (!veh->bHasBeenOwnedByPlayer && veh->VehicleCreatedBy != MISSION_VEHICLE) + CEventList::RegisterEvent(EVENT_STEAL_CAR, EVENT_ENTITY_VEHICLE, veh, ped, 1500); + + veh->bHasBeenOwnedByPlayer = true; + } + ped->bChangedSeat = true; +} + +bool +CPed::CanBeDeleted(void) +{ + if (bInVehicle) + return false; + + switch (CharCreatedBy) { + case RANDOM_CHAR: + return true; + case MISSION_CHAR: + return false; + default: + return true; } } -inline bool -CPed::IsNotInWreckedVehicle() +void +CPed::AddWeaponModel(int id) { - return m_pMyVehicle != nil && m_pMyVehicle->GetStatus() != STATUS_WRECKED; + RpAtomic *atm; + + if (id != -1) { +#ifdef PED_SKIN + if (IsClumpSkinned(GetClump())) { + if (m_pWeaponModel) + RemoveWeaponModel(-1); + + m_pWeaponModel = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + } else +#endif + { + atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + RwFrameDestroy(RpAtomicGetFrame(atm)); + RpAtomicSetFrame(atm, m_pFrames[PED_HANDR]->frame); + RpClumpAddAtomic(GetClump(), atm); + } + m_wepModelID = id; + } +} + +static RwObject* +RemoveAllModelCB(RwObject *object, void *data) +{ + RpAtomic *atomic = (RpAtomic*)object; + if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { + RpClumpRemoveAtomic(RpAtomicGetClump(atomic), atomic); + RpAtomicDestroy(atomic); + } + return object; +} + +void +CPed::RemoveWeaponModel(int modelId) +{ + // modelId is not used!! This function just removes the current weapon. +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + if(m_pWeaponModel){ + RwFrame *frm = RpAtomicGetFrame(m_pWeaponModel); + RpAtomicDestroy(m_pWeaponModel); + RwFrameDestroy(frm); + m_pWeaponModel = nil; + } + }else +#endif + RwFrameForAllObjects(m_pFrames[PED_HANDR]->frame,RemoveAllModelCB,nil); + m_wepModelID = -1; +} + +uint32 +CPed::GiveWeapon(eWeaponType weaponType, uint32 ammo) +{ + CWeapon &weapon = GetWeapon(weaponType); + + if (HasWeapon(weaponType)) { + if (weapon.m_nAmmoTotal + ammo > 99999) + weapon.m_nAmmoTotal = 99999; + else + weapon.m_nAmmoTotal += ammo; + + weapon.Reload(); + } else { + weapon.Initialise(weaponType, ammo); + // TODO: It seems game uses this as both weapon count and max WeaponType we have, which is ofcourse erroneous. + m_maxWeaponTypeAllowed++; + } + if (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) + weapon.m_eWeaponState = WEAPONSTATE_READY; + + return weaponType; +} + +// Some kind of VC leftover I think +int +CPed::GetWeaponSlot(eWeaponType weaponType) +{ + if (HasWeapon(weaponType)) + return weaponType; + else + return -1; +} + +void +CPed::SetCurrentWeapon(uint32 weaponType) +{ + CWeaponInfo *weaponInfo; + if (HasWeapon(weaponType)) { + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(weaponInfo->m_nModelId); + + m_currentWeapon = weaponType; + + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(weaponInfo->m_nModelId); + } +} + +void +CPed::GrantAmmo(eWeaponType weaponType, uint32 ammo) +{ + if (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal += ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; + } +} + +void +CPed::SetAmmo(eWeaponType weaponType, uint32 ammo) +{ + if (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal = ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; + } +} + +void +CPed::ClearWeapons(void) +{ + CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(currentWeapon->m_nModelId); + + m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT; + m_currentWeapon = WEAPONTYPE_UNARMED; + + currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(currentWeapon->m_nModelId); + for(int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { + CWeapon &weapon = GetWeapon(i); + weapon.m_eWeaponType = WEAPONTYPE_UNARMED; + weapon.m_eWeaponState = WEAPONSTATE_READY; + weapon.m_nAmmoInClip = 0; + weapon.m_nAmmoTotal = 0; + weapon.m_nTimer = 0; + } } void @@ -14938,180 +4894,1131 @@ CPed::PreRender(void) } void -CPed::ProcessBuoyancy(void) +CPed::Render(void) { - static uint32 nGenerateRaindrops = 0; - static uint32 nGenerateWaterCircles = 0; - CRGBA color(((0.5f * CTimeCycle::GetDirectionalRed() + CTimeCycle::GetAmbientRed()) * 127.5f), - ((0.5f * CTimeCycle::GetDirectionalBlue() + CTimeCycle::GetAmbientBlue()) * 127.5f), - ((0.5f * CTimeCycle::GetDirectionalGreen() + CTimeCycle::GetAmbientGreen()) * 127.5f), - (CGeneral::GetRandomNumber() % 256 * 48.0f) + 48); + if (bInVehicle && m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR) { + if (!bRenderPedInCar) + return; - if (bInVehicle) + float camDistSq = (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr(); + if (camDistSq > SQR(25.0f * TheCamera.LODDistMultiplier)) + return; + } + + CEntity::Render(); + +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + renderLimb(PED_HEAD); + renderLimb(PED_HANDL); + renderLimb(PED_HANDR); + } + if(m_pWeaponModel && IsClumpSkinned(GetClump())){ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, m_pFrames[PED_HANDR]->nodeID); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + RwFrame *frame = RpAtomicGetFrame(m_pWeaponModel); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + RpAtomicRender(m_pWeaponModel); + } +#endif +} + +void +CPed::CheckAroundForPossibleCollisions(void) +{ + CVector ourCentre, objCentre; + CEntity *objects[8]; + int16 maxObject; + + if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) return; - CVector buoyancyPoint; - CVector buoyancyImpulse; + GetBoundCentre(ourCentre); -#ifndef VC_PED_PORTS - float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.5f : 1.3f); -#else - float buoyancyLevel = (m_nPedState == PED_DEAD ? 1.8f : 1.1f); -#endif - - if (mod_Buoyancy.ProcessBuoyancy(this, GRAVITY * m_fMass * buoyancyLevel, &buoyancyPoint, &buoyancyImpulse)) { - bTouchingWater = true; - CEntity *entity; - CColPoint point; - if (CWorld::ProcessVerticalLine(GetPosition(), GetPosition().z - 3.0f, point, entity, false, true, false, false, false, false, nil) - && entity->IsVehicle() && ((CVehicle*)entity)->IsBoat()) { - bIsInWater = false; - return; + CWorld::FindObjectsInRange(ourCentre, 10.0f, true, &maxObject, 6, objects, false, true, false, true, false); + for (int i = 0; i < maxObject; i++) { + CEntity *object = objects[i]; + if (bRunningToPhone) { + if (gPhoneInfo.PhoneAtThisPosition(object->GetPosition())) + break; } - bIsInWater = true; - ApplyMoveForce(buoyancyImpulse); - if (!DyingOrDead()) { - if (bTryingToReachDryLand) { - if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.4f * CTimer::GetTimeStep()) { - bTryingToReachDryLand = false; - CVector pos = GetPosition(); - if (PlacePedOnDryLand()) { - if (m_fHealth > 20.0f) - InflictDamage(nil, WEAPONTYPE_DROWNING, 15.0f, PEDPIECE_TORSO, false); + object->GetBoundCentre(objCentre); + float radius = object->GetBoundRadius(); + if (radius > 4.5f || radius < 1.0f) + radius = 1.0f; - if (bIsInTheAir) { - RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); - bIsInTheAir = false; - } - pos.z = pos.z - 0.8f; -#ifdef PC_PARTICLE - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, pos, CVector(0.0f, 0.0f, 0.0f), 0.0f, 50, color, true); -#else - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, pos, CVector(0.0f, 0.0f, 0.0f), 0.0f, 50, CRGBA(0, 0, 0, 0), true); + // Developers gave up calculating Z diff. later according to asm. + float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); + + if (sq(radius + 1.0f) > diff) + m_fRotationDest += DEGTORAD(22.5f); + } +} + +void +CPed::SetIdle(void) +{ + if (m_nPedState != PED_IDLE && m_nPedState != PED_MUG && m_nPedState != PED_FLEE_ENTITY) { +#ifdef VC_PED_PORTS + if (m_nPedState == PED_AIM_GUN) + ClearPointGunAt(); + + m_nLastPedState = PED_NONE; #endif - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - m_nPedState = PED_IDLE; - return; - } - } - } - float speedMult = 0.0f; - if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.75f * CTimer::GetTimeStep() - || mod_Buoyancy.m_waterlevel > GetPosition().z) { - speedMult = pow(0.9f, CTimer::GetTimeStep()); - m_vecMoveSpeed.x *= speedMult; - m_vecMoveSpeed.y *= speedMult; - m_vecMoveSpeed.z *= speedMult; - bIsStanding = false; - InflictDamage(nil, WEAPONTYPE_DROWNING, 3.0f * CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); - } - if (buoyancyImpulse.z / m_fMass > GRAVITY * 0.25f * CTimer::GetTimeStep()) { - if (speedMult == 0.0f) { - speedMult = pow(0.9f, CTimer::GetTimeStep()); - } - m_vecMoveSpeed.x *= speedMult; - m_vecMoveSpeed.y *= speedMult; - if (m_vecMoveSpeed.z >= -0.1f) { - if (m_vecMoveSpeed.z < -0.04f) - m_vecMoveSpeed.z = -0.02f; - } else { - m_vecMoveSpeed.z = -0.01f; - DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLASH, 0.0f); -#ifdef PC_PARTICLE - CVector aBitForward = 2.2f * m_vecMoveSpeed + GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(aBitForward, &level, false)) - aBitForward.z = level; + m_nPedState = PED_IDLE; + SetMoveState(PEDMOVE_STILL); + } + if (m_nWaitState == WAITSTATE_FALSE) { + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000); + } +} - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, aBitForward, CVector(0.0f, 0.0f, 0.1f), 0.0f, 200, color, true); - nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 80; - nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 100; -#else - CVector aBitForward = 1.6f * m_vecMoveSpeed + GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(aBitForward, &level, false)) - aBitForward.z = level + 0.5f; - - CVector vel = m_vecMoveSpeed * 0.1f; - vel.z = 0.18f; - CParticleObject::AddObject(POBJECT_PED_WATER_SPLASH, aBitForward, vel, 0.0f, 350, CRGBA(0, 0, 0, 0), true); - nGenerateRaindrops = CTimer::GetTimeInMilliseconds() + 300; - nGenerateWaterCircles = CTimer::GetTimeInMilliseconds() + 60; -#endif +void +CPed::Idle(void) +{ + CVehicle *veh = m_pMyVehicle; + if (veh && veh->m_nGettingOutFlags && m_vehEnterType) { + + if (veh->m_nGettingOutFlags & GetCarDoorFlag(m_vehEnterType)) { + + if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + + CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehEnterType); + CVector doorDist = GetPosition() - doorPos; + + if (doorDist.MagnitudeSqr() < sq(0.5f)) { + SetMoveState(PEDMOVE_WALK); + return; } } - } else - return; - } else - bTouchingWater = false; - - if (nGenerateWaterCircles && CTimer::GetTimeInMilliseconds() >= nGenerateWaterCircles) { - CVector pos = GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(pos, &level, false)) - pos.z = level; - - if (pos.z != 0.0f) { - nGenerateWaterCircles = 0; - for(int i = 0; i < 4; i++) { -#ifdef PC_PARTICLE - pos.x += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); - pos.y += CGeneral::GetRandomNumberInRange(-0.75f, 0.75f); - CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, color, 0, 0, 0, 0); -#else - pos.x += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); - pos.y += CGeneral::GetRandomNumberInRange(-2.5f, 2.5f); - CParticle::AddParticle(PARTICLE_RAIN_SPLASH_BIGGROW, pos+CVector(0.0f, 0.0f, 1.0f), CVector(0.0f, 0.0f, 0.0f)); -#endif - } } } - if (nGenerateRaindrops && CTimer::GetTimeInMilliseconds() >= nGenerateRaindrops) { - CVector pos = GetPosition(); - float level = 0.0f; - if (CWaterLevel::GetWaterLevel(pos, &level, false)) - pos.z = level; + CAnimBlendAssociation *armedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); + CAnimBlendAssociation *unarmedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + int waitTime; - if (pos.z >= 0.0f) { -#ifdef PC_PARTICLE - pos.z += 0.25f; -#else - pos.z += 0.5f; + if (m_nMoveState == PEDMOVE_STILL) { + + eWeaponType curWeapon = GetWeapon()->m_eWeaponType; + if (!armedIdleAssoc || + CTimer::GetTimeInMilliseconds() <= m_nWaitTimer && curWeapon != WEAPONTYPE_UNARMED && curWeapon != WEAPONTYPE_MOLOTOV && curWeapon != WEAPONTYPE_GRENADE) { + + if ((!GetWeapon()->IsType2Handed() || curWeapon == WEAPONTYPE_SHOTGUN) && curWeapon != WEAPONTYPE_BASEBALLBAT + || !unarmedIdleAssoc || unarmedIdleAssoc->blendAmount <= 0.95f || m_nWaitState != WAITSTATE_FALSE || CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + + m_moved = CVector2D(0.0f, 0.0f); + return; + } + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_ARMED, 3.0f); + waitTime = CGeneral::GetRandomNumberInRange(4000, 7500); + } else { + armedIdleAssoc->blendDelta = -2.0f; + armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT; + waitTime = CGeneral::GetRandomNumberInRange(3000, 8500); + } + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + waitTime; + } else { + if (armedIdleAssoc) { + armedIdleAssoc->blendDelta = -8.0f; + armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT; + m_nWaitTimer = 0; + } + if (!IsPlayer()) + SetMoveState(PEDMOVE_STILL); + } + m_moved = CVector2D(0.0f, 0.0f); +} + +void +CPed::ClearPause(void) +{ + RestorePreviousState(); +} + +void +CPed::Pause(void) +{ + m_moved = CVector2D(0.0f, 0.0f); + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) + ClearPause(); +} + +void +CPed::SetFall(int extraTime, AnimationId animId, uint8 evenIfNotInControl) +{ + if (!IsPedInControl() && (!evenIfNotInControl || DyingOrDead())) + return; + + ClearLookFlag(); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_FALL; + CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), animId); + + if (fallAssoc) { + fallAssoc->SetCurrentTime(0.0f); + fallAssoc->blendAmount = 0.0f; + fallAssoc->blendDelta = 8.0f; + fallAssoc->SetRun(); + } else { + fallAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, 8.0f); + } + + if (extraTime == -1) { + m_getUpTimer = UINT32_MAX; + } else if (fallAssoc) { + if (IsPlayer()) { + m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength + + CTimer::GetTimeInMilliseconds() + + 500.0f; + } else { + m_getUpTimer = 1000.0f * fallAssoc->hierarchy->totalLength + + CTimer::GetTimeInMilliseconds() + + extraTime + + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000); + } + } else { + m_getUpTimer = extraTime + + CTimer::GetTimeInMilliseconds() + + 1000 + + ((m_randomSeed + CTimer::GetFrameCounter()) % 1000); + } + bFallenDown = true; +} + +void +CPed::ClearFall(void) +{ + SetGetUp(); +} + +void +CPed::Fall(void) +{ + if (m_getUpTimer != UINT32_MAX && CTimer::GetTimeInMilliseconds() > m_getUpTimer +#ifdef VC_PED_PORTS + && bIsStanding #endif - nGenerateRaindrops = 0; -#ifdef PC_PARTICLE - CParticleObject::AddObject(POBJECT_SPLASHES_AROUND, pos, CVector(0.0f, 0.0f, 0.0f), 4.5f, 1500, CRGBA(0,0,0,0), true); -#else - CParticleObject::AddObject(POBJECT_SPLASHES_AROUND, pos, CVector(0.0f, 0.0f, 0.0f), 4.5f, 2500, CRGBA(0,0,0,0), true); + ) + ClearFall(); + + // VC plays animations ANIM_STD_FALL_ONBACK and ANIM_STD_FALL_ONFRONT in here, which doesn't exist in III. +} + +bool +CPed::CheckIfInTheAir(void) +{ + if (bInVehicle) + return false; + + CVector pos = GetPosition(); + CColPoint foundColPoint; + CEntity *foundEntity; + + float startZ = pos.z - 1.54f; + bool foundGround = CWorld::ProcessVerticalLine(pos, startZ, foundColPoint, foundEntity, true, true, false, true, false, false, nil); + if (!foundGround && m_nPedState != PED_JUMP) + { + pos.z -= FEET_OFFSET; + if (CWorld::TestSphereAgainstWorld(pos, 0.15f, this, true, false, false, false, false, false)) + foundGround = true; + } + return !foundGround; +} + +void +CPed::SetInTheAir(void) +{ + if (bIsInTheAir) + return; + + bIsInTheAir = true; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_GLIDE, 4.0f); + + if (m_nPedState == PED_ATTACK) { + ClearAttack(); + ClearPointGunAt(); + } else if (m_nPedState == PED_FIGHT) { + EndFight(ENDFIGHT_FAST); + } + +} + +void +CPed::InTheAir(void) +{ + CColPoint foundCol; + CEntity *foundEnt; + + CVector ourPos = GetPosition(); + CVector bitBelow = GetPosition(); + bitBelow.z -= 4.04f; + + if (m_vecMoveSpeed.z < 0.0f && !bIsPedDieAnimPlaying) { + if (!DyingOrDead()) { + if (CWorld::ProcessLineOfSight(ourPos, bitBelow, foundCol, foundEnt, true, true, false, true, false, false, false)) { + if (GetPosition().z - foundCol.point.z < 1.3f +#ifdef VC_PED_PORTS + || bIsStanding #endif + ) + SetLanding(); + } else { + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL)) { + if (m_vecMoveSpeed.z < -0.1f) + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_FALL, 4.0f); + } + } } } } void -CPed::SetSolicit(uint32 time) +CPed::SetLanding(void) { - if (m_nPedState == PED_SOLICIT || !IsPedInControl() || !m_carInObjective) + if (DyingOrDead()) return; - if (CharCreatedBy != MISSION_CHAR && m_carInObjective->m_nNumGettingIn == 0 - && CTimer::GetTimeInMilliseconds() < m_objectiveTimer) { - if (m_vehEnterType == CAR_DOOR_LF) { - m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; - } else { - m_fRotationDest = m_carInObjective->GetForward().Heading() + HALFPI; + CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL); + CAnimBlendAssociation *landAssoc; + + RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); + if (fallAssoc) { + landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_COLLAPSE); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_COLLAPSE, 1.0f); + + if (IsPlayer()) + Say(SOUND_PED_LAND); + + } else { + landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_LAND); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_LAND, 1.0f); + } + + landAssoc->SetFinishCallback(PedLandCB, this); + bIsInTheAir = false; + bIsLanding = true; +} + +void +CPed::SetGetUp(void) +{ + if (m_nPedState == PED_GETUP && bGetUpAnimStarted) + return; + + if (!CanSetPedState()) + return; + + if (m_fHealth >= 1.0f || IsPedHeadAbovePos(-0.3f)) { + if (bUpdateAnimHeading) { + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + m_fRotationCur -= HALFPI; + bUpdateAnimHeading = false; + } + if (m_nPedState != PED_GETUP) { + SetStoredState(); + m_nPedState = PED_GETUP; } - if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + CVehicle *collidingVeh = (CVehicle*)m_pCollidingEntity; + CVehicle *veh = (CVehicle*)CPedPlacement::IsPositionClearOfCars(&GetPosition()); + if (veh && veh->m_vehType != VEHICLE_TYPE_BIKE || + collidingVeh && collidingVeh->IsVehicle() && collidingVeh->m_vehType != VEHICLE_TYPE_BIKE + && ((uint8)(CTimer::GetFrameCounter() + m_randomSeed + 5) % 8 || + CCollision::ProcessColModels(GetMatrix(), *GetColModel(), collidingVeh->GetMatrix(), *collidingVeh->GetColModel(), + aTempPedColPts, nil, nil) > 0)) { - if(!m_carInObjective->bIsVan && !m_carInObjective->bIsBus) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_HOOKERTALK, 4.0f); + bGetUpAnimStarted = false; + if (IsPlayer()) + InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); + else { + if (!CPad::GetPad(0)->ArePlayerControlsDisabled()) + return; - m_nPedState = PED_SOLICIT; + InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, 1000.0f, PEDPIECE_TORSO, 0); + } + return; + } + bGetUpAnimStarted = true; + m_pCollidingEntity = nil; + bKnockedUpIntoAir = false; + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT); + if (animAssoc) { + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN)) { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_RUN, 8.0f); + } else { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); + } + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + + if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP_FRONT, 1000.0f); + else + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); + + animAssoc->SetFinishCallback(PedGetupCB,this); + } else { + m_fHealth = 0.0f; + SetDie(NUM_ANIMS, 4.0f, 0.0f); + } +} + +void +CPed::Mug(void) +{ + if (m_pSeekTarget && m_pSeekTarget->IsPed()) { + + if (CTimer::GetTimeInMilliseconds() <= m_attackTimer - 2000) { + if ((m_pSeekTarget->GetPosition() - GetPosition()).Magnitude() > 3.0f) + m_wepSkills = 50; + + Say(SOUND_PED_MUGGING); + ((CPed*)m_pSeekTarget)->Say(SOUND_PED_ROBBED); + } else { + SetWanderPath(CGeneral::GetRandomNumber() & 7); + SetFlee(m_pSeekTarget, 20000); + } + + } else { + SetIdle(); + } +} + +void +CPed::SetLookTimer(int time) +{ + if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + m_lookTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::SetAttackTimer(uint32 time) +{ + if (CTimer::GetTimeInMilliseconds() > m_attackTimer) + m_attackTimer = Max(m_shootTimer, CTimer::GetTimeInMilliseconds()) + time; +} + +void +CPed::SetShootTimer(uint32 time) +{ + if (CTimer::GetTimeInMilliseconds() > m_shootTimer) { + m_shootTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::ClearLook(void) +{ + RestorePreviousState(); + ClearLookFlag(); +} + +void +CPed::Look(void) +{ + // UNUSED: This is a perfectly empty function. +} + +bool +CPed::TurnBody(void) +{ + bool turnDone = true; + + if (m_pLookTarget) + m_fLookDirection = CGeneral::GetRadianAngleBetweenPoints( + m_pLookTarget->GetPosition().x, + m_pLookTarget->GetPosition().y, + GetPosition().x, + GetPosition().y); + + float limitedLookDir = CGeneral::LimitRadianAngle(m_fLookDirection); + float currentRot = m_fRotationCur; + + if (currentRot - PI > limitedLookDir) + limitedLookDir += 2 * PI; + else if (PI + currentRot < limitedLookDir) + limitedLookDir -= 2 * PI; + + float neededTurn = currentRot - limitedLookDir; + m_fRotationDest = limitedLookDir; + + if (Abs(neededTurn) > 0.05f) { + turnDone = false; + currentRot -= neededTurn * 0.2f; + } + + m_fRotationCur = currentRot; + m_fLookDirection = limitedLookDir; + return turnDone; +} + +void +CPed::SetSeek(CVector pos, float distanceToCountDone) +{ + if (!IsPedInControl() + || (m_nPedState == PED_SEEK_POS && m_vecSeekPos.x == pos.x && m_vecSeekPos.y == pos.y)) + return; + + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_M16 + || GetWeapon()->m_eWeaponType == WEAPONTYPE_AK47 + || GetWeapon()->m_eWeaponType == WEAPONTYPE_SNIPERRIFLE + || GetWeapon()->m_eWeaponType == WEAPONTYPE_ROCKETLAUNCHER + || GetWeapon()->m_eWeaponType == WEAPONTYPE_SHOTGUN) { + ClearPointGunAt(); + } + + if (m_nPedState != PED_SEEK_POS) + SetStoredState(); + + m_nPedState = PED_SEEK_POS; + m_distanceToCountSeekDone = distanceToCountDone; + m_vecSeekPos = pos; +} + +void +CPed::SetSeek(CEntity *seeking, float distanceToCountDone) +{ + if (!IsPedInControl()) + return; + + if (m_nPedState == PED_SEEK_ENTITY && m_pSeekTarget == seeking) + return; + + if (!seeking) + return; + + if (m_nPedState != PED_SEEK_ENTITY) + SetStoredState(); + + m_nPedState = PED_SEEK_ENTITY; + m_distanceToCountSeekDone = distanceToCountDone; + m_pSeekTarget = seeking; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + SetMoveState(PEDMOVE_STILL); +} + +void +CPed::ClearSeek(void) +{ + SetIdle(); + bRunningToPhone = false; +} + +bool +CPed::Seek(void) +{ + float distanceToCountItDone = m_distanceToCountSeekDone; + eMoveState nextMove = PEDMOVE_NONE; + + if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + + if (m_nPedState != PED_EXIT_TRAIN && m_nPedState != PED_ENTER_TRAIN && m_nPedState != PED_SEEK_IN_BOAT && + m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_SOLICIT_VEHICLE && !bDuckAndCover) { + + if ((!m_pedInObjective || !m_pedInObjective->bInVehicle) + && !((CTimer::GetFrameCounter() + (m_randomSeed % 256) + 17) & 7)) { + + CEntity *obstacle = CWorld::TestSphereAgainstWorld(m_vecSeekPos, 0.4f, nil, + false, true, false, false, false, false); + + if (obstacle) { + if (!obstacle->IsVehicle() || ((CVehicle*)obstacle)->m_vehType == VEHICLE_TYPE_CAR) { + distanceToCountItDone = 2.5f; + } else { + CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(obstacle->GetModelIndex()); + float yLength = vehModel->GetColModel()->boundingBox.max.y + - vehModel->GetColModel()->boundingBox.min.y; + distanceToCountItDone = yLength * 0.55f; + } + } + } } } + + if (!m_pSeekTarget && m_nPedState == PED_SEEK_ENTITY) + ClearSeek(); + + float seekPosDist = (m_vecSeekPos - GetPosition()).Magnitude2D(); + if (seekPosDist < 2.0f || m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT) { + + if (m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION) { + + if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) + nextMove = m_pedInObjective->m_nMoveState; + } else + nextMove = PEDMOVE_WALK; + + } else if (m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION) { + + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || m_objective == OBJECTIVE_RUN_TO_AREA || bIsRunning) + nextMove = PEDMOVE_RUN; + else + nextMove = PEDMOVE_WALK; + + } else if (seekPosDist <= 2.0f) { + + if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) + nextMove = m_pedInObjective->m_nMoveState; + + } else { + nextMove = PEDMOVE_RUN; + } + + if (m_nPedState == PED_SEEK_ENTITY) { + if (m_pSeekTarget->IsPed()) { + if (((CPed*)m_pSeekTarget)->bInVehicle) + distanceToCountItDone += 2.0f; + } + } + + if (seekPosDist >= distanceToCountItDone) { + if (bIsRunning) + nextMove = PEDMOVE_RUN; + + if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) { + + if (m_actionX != 0.0f && m_actionY != 0.0f) { + + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_actionX, m_actionY, + GetPosition().x, GetPosition().y); + + float neededTurn = Abs(m_fRotationDest - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; + + if (neededTurn > HALFPI) { + if (seekPosDist >= 1.0f) { + if (seekPosDist < 2.0f) { + if (bIsRunning) + nextMove = PEDMOVE_RUN; + else + nextMove = PEDMOVE_WALK; + } + } else { + nextMove = PEDMOVE_STILL; + } + } + + CVector2D moveDist(GetPosition().x - m_actionX, GetPosition().y - m_actionY); + if (moveDist.Magnitude() < 0.5f) { + m_nPedStateTimer = 0; + m_actionX = 0; + m_actionY = 0; + } + } + } else { + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_vecSeekPos.x, m_vecSeekPos.y, + GetPosition().x, GetPosition().y); + + float neededTurn = Abs(m_fRotationDest - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; + + if (neededTurn > HALFPI) { + if (seekPosDist >= 1.0 && neededTurn <= DEGTORAD(135.0f)) { + if (seekPosDist < 2.0f) + nextMove = PEDMOVE_WALK; + } else { + nextMove = PEDMOVE_STILL; + } + } + } + + if (((m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY) && m_nMoveState < nextMove) + || (m_nPedState != PED_FLEE_POS && m_nPedState != PED_FLEE_ENTITY && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT && m_nWaitState == WAITSTATE_FALSE)) { + + SetMoveState(nextMove); + } + + SetMoveAnim(); + return false; + } + + if ((m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION || m_pedInObjective->m_nMoveState == PEDMOVE_STILL) && m_nMoveState != PEDMOVE_STILL) { + m_nPedStateTimer = 0; + m_actionX = 0; + m_actionY = 0; + } + + if (m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA || m_objective == OBJECTIVE_GOTO_AREA_ANY_MEANS) { + if (m_pNextPathNode) + m_pNextPathNode = nil; + else + bScriptObjectiveCompleted = true; + + bUsePedNodeSeek = true; + } + + if (SeekFollowingPath(nil)) + m_nCurPathNode++; + + return true; +} + +void +CPed::SetFlee(CVector2D const &from, int time) +{ + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer || !IsPedInControl() || bKindaStayInSamePlace) + return; + + if (m_nPedState != PED_FLEE_ENTITY) { + SetStoredState(); + m_nPedState = PED_FLEE_POS; + SetMoveState(PEDMOVE_RUN); + m_fleeFromPosX = from.x; + m_fleeFromPosY = from.y; + } + + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, GetPosition().y, + from.x, from.y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); + if (m_fRotationCur - PI > m_fRotationDest) { + m_fRotationDest += 2 * PI; + } else if (PI + m_fRotationCur < m_fRotationDest) { + m_fRotationDest -= 2 * PI; + } +} + +void +CPed::SetFlee(CEntity *fleeFrom, int time) +{ + if (!IsPedInControl() || bKindaStayInSamePlace || !fleeFrom) + return; + + SetStoredState(); + m_nPedState = PED_FLEE_ENTITY; + bUsePedNodeSeek = true; + SetMoveState(PEDMOVE_RUN); + m_fleeFrom = fleeFrom; + m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); + + if (time <= 0) + m_fleeTimer = 0; + else + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, GetPosition().y, + fleeFrom->GetPosition().x, fleeFrom->GetPosition().y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); + if (m_fRotationCur - PI > m_fRotationDest) { + m_fRotationDest += 2 * PI; + } else if (PI + m_fRotationCur < m_fRotationDest) { + m_fRotationDest -= 2 * PI; + } +} + +void +CPed::ClearFlee(void) +{ + RestorePreviousState(); + bUsePedNodeSeek = false; + m_standardTimer = 0; + m_fleeTimer = 0; +} + +void +CPed::Flee(void) +{ + if (CTimer::GetTimeInMilliseconds() > m_fleeTimer && m_fleeTimer) { + bool mayFinishFleeing = true; + if (m_nPedState == PED_FLEE_ENTITY) { + if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < sq(30.0f)) + mayFinishFleeing = false; + } + + if (mayFinishFleeing) { + eMoveState moveState = m_nMoveState; + ClearFlee(); + + if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE || m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) + RestorePreviousObjective(); + + if ((m_nPedState == PED_IDLE || m_nPedState == PED_WANDER_PATH) && CGeneral::GetRandomNumber() & 1) { + SetWaitState(moveState <= PEDMOVE_WALK ? WAITSTATE_CROSS_ROAD_LOOK : WAITSTATE_FINISH_FLEE, nil); + } + return; + } + m_fleeTimer = CTimer::GetTimeInMilliseconds() + 5000; + } + + if (bUsePedNodeSeek) { + CPathNode *realLastNode = nil; + uint8 nextDirection = 0; + uint8 curDirectionShouldBe = 9; // means not defined yet + + if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds() + && m_collidingThingTimer < CTimer::GetTimeInMilliseconds()) { + + if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + + curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); + if (m_nPathDir < curDirectionShouldBe) + m_nPathDir += 8; + + int dirDiff = m_nPathDir - curDirectionShouldBe; + if (dirDiff > 2 && dirDiff < 6) { + realLastNode = nil; + m_pLastPathNode = m_pNextPathNode; + m_pNextPathNode = nil; + } + } + + if (m_pNextPathNode) { + m_vecSeekPos = m_pNextPathNode->GetPosition(); + if (m_nMoveState == PEDMOVE_RUN) + bIsRunning = true; + + eMoveState moveState = m_nMoveState; + if (Seek()) { + realLastNode = m_pLastPathNode; + m_pLastPathNode = m_pNextPathNode; + m_pNextPathNode = nil; + } + bIsRunning = false; + SetMoveState(moveState); + } + } + + if (!m_pNextPathNode) { + if (curDirectionShouldBe == 9) { + curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); + } + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + curDirectionShouldBe, + &nextDirection); + + if (curDirectionShouldBe < nextDirection) + curDirectionShouldBe += 8; + + if (m_pNextPathNode && m_pNextPathNode != realLastNode && m_pNextPathNode != m_pLastPathNode && curDirectionShouldBe - nextDirection != 4) { + m_nPathDir = nextDirection; + m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; + } else { + bUsePedNodeSeek = false; + SetMoveState(PEDMOVE_RUN); + Flee(); + } + } + return; + } + + if ((m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_ON_FIRE) && m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) { + + float angleToFleeFromPos = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, + GetPosition().y, + ms_vec2DFleePosition.x, + ms_vec2DFleePosition.y); + + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFleeFromPos); + + if (m_fRotationCur - PI > m_fRotationDest) + m_fRotationDest += TWOPI; + else if (PI + m_fRotationCur < m_fRotationDest) + m_fRotationDest -= TWOPI; + } + + if (CTimer::GetTimeInMilliseconds() & 0x20) { + //CVector forwardPos = GetPosition(); + CMatrix forwardMat(GetMatrix()); + forwardMat.GetPosition() += Multiply3x3(forwardMat, CVector(0.0f, 4.0f, 0.0f)); + CVector forwardPos = forwardMat.GetPosition(); + + CEntity *foundEnt; + CColPoint foundCol; + bool found = CWorld::ProcessVerticalLine(forwardPos, forwardMat.GetPosition().z - 100.0f, foundCol, foundEnt, 1, 0, 0, 0, 1, 0, 0); + + if (!found || Abs(forwardPos.z - forwardMat.GetPosition().z) > 1.0f) { + m_fRotationDest += DEGTORAD(112.5f); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000; + } + } + + if (CTimer::GetTimeInMilliseconds() >= m_collidingThingTimer) + return; + + if (!m_collidingEntityWhileFleeing) + return; + + double collidingThingPriorityMult = (double)(m_collidingThingTimer - CTimer::GetTimeInMilliseconds()) * 2.0 / 2500; + + if (collidingThingPriorityMult <= 1.5) { + + double angleToFleeEntity = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, + GetPosition().y, + m_collidingEntityWhileFleeing->GetPosition().x, + m_collidingEntityWhileFleeing->GetPosition().y); + angleToFleeEntity = CGeneral::LimitRadianAngle(angleToFleeEntity); + + double angleToFleeCollidingThing = CGeneral::GetRadianAngleBetweenPoints( + m_vecDamageNormal.x, + m_vecDamageNormal.y, + 0.0f, + 0.0f); + angleToFleeCollidingThing = CGeneral::LimitRadianAngle(angleToFleeCollidingThing); + + if (angleToFleeEntity - PI > angleToFleeCollidingThing) + angleToFleeCollidingThing += TWOPI; + else if (PI + angleToFleeEntity < angleToFleeCollidingThing) + angleToFleeCollidingThing -= TWOPI; + + if (collidingThingPriorityMult <= 1.0f) { + // Range [0.0, 1.0] + + float angleToFleeBoth = (angleToFleeCollidingThing + angleToFleeEntity) * 0.5f; + + if (m_fRotationDest - PI > angleToFleeBoth) + angleToFleeBoth += TWOPI; + else if (PI + m_fRotationDest < angleToFleeBoth) + angleToFleeBoth -= TWOPI; + + m_fRotationDest = (1.0f - collidingThingPriorityMult) * m_fRotationDest + collidingThingPriorityMult * angleToFleeBoth; + } else { + // Range (1.0, 1.5] + + double adjustedMult = (collidingThingPriorityMult - 1.0f) * 2.0f; + m_fRotationDest = angleToFleeEntity * (1.0 - adjustedMult) + adjustedMult * angleToFleeCollidingThing; + } + } else { + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_vecDamageNormal.x, + m_vecDamageNormal.y, + 0.0f, + 0.0f); + m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); + } + + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + + if (m_fRotationCur - PI > m_fRotationDest) + m_fRotationDest += TWOPI; + else if (PI + m_fRotationCur < m_fRotationDest) + m_fRotationDest -= TWOPI; + +} + +// "Wander range" state is unused in game, and you can't use it without SetWanderRange anyway +void +CPed::WanderRange(void) +{ + bool arrived = Seek(); + if (arrived) { + Idle(); + if ((m_randomSeed + 3 * CTimer::GetFrameCounter()) % 1000 > 997) { + CVector2D newCoords2D = m_wanderRangeBounds->GetRandomPointInRange(); + SetSeek(CVector(newCoords2D.x, newCoords2D.y, GetPosition().z), 2.5f); + } + } +} + +bool +CPed::SetWanderPath(int8 pathStateDest) +{ + uint8 nextPathState; + + if (IsPedInControl()) { + if (bKindaStayInSamePlace) { + SetIdle(); + return false; + } else { + m_nPathDir = pathStateDest; + if (pathStateDest == 0) + pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); + + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &nextPathState); + + // Circular loop until we find a node for current m_nPathDir + while (!m_pNextPathNode) { + m_nPathDir = (m_nPathDir+1) % 8; + + // We're at where we started and couldn't find any node + if (m_nPathDir == pathStateDest) { + ClearAll(); + SetIdle(); + return false; + } + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &nextPathState); + } + + // We did it, save next path state and return true + m_nPathDir = nextPathState; + m_nPedState = PED_WANDER_PATH; + SetMoveState(PEDMOVE_WALK); + bIsRunning = false; + return true; + } + } else { + m_nPathDir = pathStateDest; + bStartWanderPathOnFoot = true; + return false; + } +} + +void +CPed::WanderPath(void) +{ + if (!m_pNextPathNode) { + printf("THIS SHOULDN@T HAPPEN TOO OFTEN\n"); + SetIdle(); + return; + } + if (m_nWaitState == WAITSTATE_FALSE) { + if (m_nMoveState == PEDMOVE_STILL || m_nMoveState == PEDMOVE_NONE) + SetMoveState(PEDMOVE_WALK); + } + m_vecSeekPos = m_pNextPathNode->GetPosition(); + m_vecSeekPos.z += 1.0f; + + // Only returns true when ped is stuck(not stopped) I think, then we should assign new direction or wait state to him. + if (!Seek()) + return; + + CPathNode *previousLastNode = m_pLastPathNode; + uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; + + // We don't prefer 180-degree turns in normal situations + uint8 dirWeWouldntPrefer = m_nPathDir; + if (dirWeWouldntPrefer <= 3) + dirWeWouldntPrefer += 4; + else + dirWeWouldntPrefer -= 4; + + CPathNode *nodeWeWouldntPrefer = nil; + uint8 dirToSet = 9; // means undefined + uint8 dirWeWouldntPrefer2 = 9; // means undefined + if (randVal <= 90) { + if (randVal > 80) { + m_nPathDir += 2; + m_nPathDir %= 8; + } + } else { + m_nPathDir -= 2; + if (m_nPathDir < 0) + m_nPathDir += 8; + } + + m_pLastPathNode = m_pNextPathNode; + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + + uint8 tryCount = 0; + + // NB: SetWanderPath checks for m_nPathDir == dirToStartWith, this one checks for tryCount > 7 + while (!m_pNextPathNode) { + tryCount++; + m_nPathDir = (m_nPathDir + 1) % 8; + + // We're at where we started and couldn't find any node + if (tryCount > 7) { + if (!nodeWeWouldntPrefer) { + ClearAll(); + SetIdle(); + // Probably this text carried over here after copy-pasting this loop from early version of SetWanderPath. + Error("Can't find valid path node, SetWanderPath, Ped.cpp"); + return; + } + m_pNextPathNode = nodeWeWouldntPrefer; + dirToSet = dirWeWouldntPrefer2; + } else { + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, + m_nPathDir, &dirToSet); + if (m_pNextPathNode) { + if (dirToSet == dirWeWouldntPrefer) { + nodeWeWouldntPrefer = m_pNextPathNode; + dirWeWouldntPrefer2 = dirToSet; + m_pNextPathNode = nil; + } + } + } + } + + m_nPathDir = dirToSet; + if (m_pLastPathNode == m_pNextPathNode) { + m_pNextPathNode = previousLastNode; + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } else if (ThePaths.TestForPedTrafficLight(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_TRAFFIC_LIGHTS, nil); + } else if (ThePaths.TestCrossesRoad(m_pLastPathNode, m_pNextPathNode)) { + SetWaitState(WAITSTATE_CROSS_ROAD, nil); + } else if (m_pNextPathNode == previousLastNode) { + SetWaitState(WAITSTATE_DOUBLEBACK, nil); + Say(SOUND_PED_WAIT_DOUBLEBACK); + } +} + +void +CPed::Avoid(void) +{ + CPed *nearestPed; + + if(m_pedStats->m_temper > m_pedStats->m_fear && m_pedStats->m_temper > 50) + return; + + if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { + + if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { + nearestPed = m_nearPeds[0]; + + if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) { + + // Check if this ped wants to avoid the nearest one + if (CPedType::GetAvoid(m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) { + + // Further codes checks whether the distance between us and ped will be equal or below 1.0, if we walk up to him by 1.25 meters. + // If so, we want to avoid it, so we turn our body 45 degree and look to somewhere else. + + // Game converts from radians to degress and back again here, doesn't make much sense + CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); + forward.Normalise(); // this is kinda pointless + + // Move forward 1.25 meters + CVector2D testPosition = CVector2D(GetPosition()) + forward*1.25f; + + // Get distance to ped we want to avoid + CVector2D distToPed = CVector2D(nearestPed->GetPosition()) - testPosition; + + if (distToPed.Magnitude() <= 1.0f && OurPedCanSeeThisOne((CEntity*)nearestPed)) { + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + + 500 + (m_randomSeed + 3 * CTimer::GetFrameCounter()) + % 1000 / 5; + + m_fRotationDest += DEGTORAD(45.0f); + if (!bIsLooking) { + SetLookFlag(nearestPed, false); + SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); + } + } + } + } + } + } +} + +bool +CPed::SeekFollowingPath(CVector *unused) +{ + return m_nCurPathNode <= m_nPathNodes && m_nPathNodes; } bool @@ -15146,667 +6053,613 @@ CPed::SetFollowPath(CVector dest) } void -AddYardieDoorSmoke(CVehicle *veh, uint32 doorNode) +CPed::FollowPath(void) { - eDoors door; - switch (doorNode) { - case CAR_DOOR_RF: - door = DOOR_FRONT_RIGHT; - break; - case CAR_DOOR_LF: - door = DOOR_FRONT_LEFT; - break; - default: - break; - } - - if (!veh->IsDoorMissing(door) && veh->IsComponentPresent(doorNode)) { - CVector pos; -#ifdef FIX_BUGS - veh->GetComponentWorldPosition(doorNode, pos); -#else - veh->GetComponentWorldPosition(CAR_DOOR_LF, pos); -#endif - CParticle::AddYardieDoorSmoke(pos, veh->GetMatrix()); - } -} - -// wantedDoorNode = 0 means that func. will determine it -void -CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) -{ - uint32 optedDoorNode = wantedDoorNode; - bool teleportNeeded = false; - bool isLow = !!veh->bLowVehicle; - if (!veh->CanPedExitCar()) { - if (veh->pDriver && !veh->pDriver->IsPlayer()) { - veh->AutoPilot.m_nCruiseSpeed = 0; - veh->AutoPilot.m_nCarMission = MISSION_NONE; - } - return; - } - - if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) - return; - - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - if (wantedDoorNode == 0) { - optedDoorNode = CAR_DOOR_LF; - if (!veh->bIsBus) { - if (veh->pDriver == this) { - optedDoorNode = CAR_DOOR_LF; - } else if (veh->pPassengers[0] == this) { - optedDoorNode = CAR_DOOR_RF; - } else if (veh->pPassengers[1] == this) { - optedDoorNode = CAR_DOOR_LR; - } else if (veh->pPassengers[2] == this) { - optedDoorNode = CAR_DOOR_RR; - } else { - for (int i = 3; i < veh->m_nNumMaxPassengers; ++i) { - if (veh->pPassengers[i] == this) { - if (i & 1) - optedDoorNode = CAR_DOOR_RR; - else - optedDoorNode = CAR_DOOR_LR; - - break; - } - } - } - } - } - bool someoneExitsFromOurExitDoor = false; - bool someoneEntersFromOurExitDoor = false; - switch (optedDoorNode) { - case CAR_DOOR_RF: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RF) - someoneExitsFromOurExitDoor = true; - break; - case CAR_DOOR_RR: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RR) - someoneExitsFromOurExitDoor = true; - break; - case CAR_DOOR_LF: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LF) - someoneExitsFromOurExitDoor = true; - break; - case CAR_DOOR_LR: - if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) - someoneEntersFromOurExitDoor = true; - if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LR) - someoneExitsFromOurExitDoor = true; - break; - default: - break; - } - if (someoneEntersFromOurExitDoor && m_objective == OBJECTIVE_LEAVE_CAR) { - RestorePreviousObjective(); - return; - } - if (!someoneExitsFromOurExitDoor || m_nPedType == PEDTYPE_COP && veh->bIsBus) { - // Again, unused... - // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); - bool thereIsRoom = veh->IsRoomForPedToLeaveCar(optedDoorNode, nil); - if (veh->IsOnItsSide()) { - teleportNeeded = true; - } else if (!thereIsRoom) { - bool trySideSeat = false; - CPed *pedOnSideSeat = nil; - switch (optedDoorNode) { - case CAR_DOOR_RF: - if (veh->pDriver || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) { - pedOnSideSeat = veh->pDriver; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_LF; - - break; - case CAR_DOOR_RR: - if (veh->pPassengers[1] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { - pedOnSideSeat = veh->pPassengers[1]; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_LR; - - break; - case CAR_DOOR_LF: - if (veh->pPassengers[0] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { - pedOnSideSeat = veh->pPassengers[0]; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_RF; - - break; - case CAR_DOOR_LR: - if (veh->pPassengers[2] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { - pedOnSideSeat = (CPed*)veh->pPassengers[2]; - trySideSeat = true; - } else - optedDoorNode = CAR_DOOR_RR; - - break; - default: - break; - } - if (trySideSeat) { - if (!pedOnSideSeat || !IsPlayer() && CharCreatedBy != MISSION_CHAR) - return; - - switch (optedDoorNode) { - case CAR_DOOR_RF: - optedDoorNode = CAR_DOOR_LF; - break; - case CAR_DOOR_RR: - optedDoorNode = CAR_DOOR_LR; - break; - case CAR_DOOR_LF: - optedDoorNode = CAR_DOOR_RF; - break; - case CAR_DOOR_LR: - optedDoorNode = CAR_DOOR_RR; - break; - default: - break; - } - } - // ... - // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); - if (!veh->IsRoomForPedToLeaveCar(optedDoorNode, nil)) { - if (!IsPlayer() && CharCreatedBy != MISSION_CHAR) - return; - - teleportNeeded = true; - } - } - if (m_nPedState == PED_FLEE_POS) { - m_nLastPedState = PED_FLEE_POS; - m_nPrevMoveState = PEDMOVE_RUN; - SetMoveState(PEDMOVE_SPRINT); - } else { - m_nLastPedState = PED_IDLE; - m_nPrevMoveState = PEDMOVE_STILL; - SetMoveState(PEDMOVE_STILL); - } - - ReplaceWeaponWhenExitingVehicle(); - bUsesCollision = false; - m_pSeekTarget = veh; - m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); - m_vehEnterType = optedDoorNode; - m_nPedState = PED_EXIT_CAR; - if (m_pVehicleAnim && m_pVehicleAnim->flags & ASSOC_PARTIAL) - m_pVehicleAnim->blendDelta = -1000.0f; - SetMoveState(PEDMOVE_NONE); - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); - RemoveInCarAnims(); - veh->AutoPilot.m_nCruiseSpeed = 0; - if (teleportNeeded) { - PedSetOutCarCB(nil, this); - - // This is same code with CPedPlacement::FindZCoorForPed, except we start from z + 1.5 and also check vehicles. - float zForPed; - float startZ = GetPosition().z - 100.0f; - float foundColZ = -100.0f; - float foundColZ2 = -100.0f; - CColPoint foundCol; - CEntity* foundEnt; - - CVector vec = GetPosition(); - vec.z += 1.5f; - - if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, true, false, false, true, false, nil)) - 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, true, false, false, true, false, nil)) - foundColZ2 = foundCol.point.z; - - zForPed = Max(foundColZ, foundColZ2); - - if (zForPed > -99.0f) - GetMatrix().GetPosition().z = FEET_OFFSET + zForPed; - } else { - if (veh->GetUp().z > -0.8f) { - bool addDoorSmoke = false; - if (veh->GetModelIndex() == MI_YARDIE) - addDoorSmoke = true; - - switch (m_vehEnterType) { - case CAR_DOOR_RF: - if (veh->bIsBus) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); - } else { - if (isLow) - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); - else - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); - - if (addDoorSmoke) - AddYardieDoorSmoke(veh, CAR_DOOR_RF); - } - break; - case CAR_DOOR_RR: - if (veh->bIsVan) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT); - } else if (isLow) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); - } else { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); - } - break; - case CAR_DOOR_LF: - if (veh->bIsBus) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); - } else { - if (isLow) - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); - else - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); - - if (addDoorSmoke) - AddYardieDoorSmoke(veh, CAR_DOOR_LF); - } - break; - case CAR_DOOR_LR: - if (veh->bIsVan) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT_L); - } else if (isLow) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); - } else { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); - } - break; - default: - break; - } - if (!bBusJacked) { - switch (m_vehEnterType) { - case CAR_DOOR_RF: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RF; - break; - case CAR_DOOR_RR: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RR; - break; - case CAR_DOOR_LF: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LF; - break; - case CAR_DOOR_LR: - veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LR; - break; - default: - break; - } - } - m_pVehicleAnim->SetFinishCallback(PedAnimStepOutCarCB, this); - } else { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS2); - } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { - m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS); - } - m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); - } - } - bChangedSeat = false; - if (veh->bIsBus) - bRenderPedInCar = true; - - SetRadioStation(); - if (veh->pDriver == this) { - if (IsPlayer()) - veh->SetStatus(STATUS_PLAYER_DISABLED); - else - veh->SetStatus(STATUS_ABANDONED); - } - } -} - -void -CPed::ScanForInterestingStuff(void) -{ - if (!IsPedInControl()) - return; - - if (m_objective != OBJECTIVE_NONE) - return; - - if (CharCreatedBy == MISSION_CHAR) - return; - - LookForSexyPeds(); - LookForSexyCars(); - if (LookForInterestingNodes()) - return; - - if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { - if (CGeneral::GetRandomNumber() % 100 < 10) { - int mostExpensiveVehAround = -1; - int bestMonetaryValue = 0; - - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity *vehicles[8]; - CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - for (int i = 0; i < lastVehicle; i++) { - CVehicle* veh = (CVehicle*)vehicles[i]; - - if (veh->VehicleCreatedBy != MISSION_VEHICLE) { - if (veh->m_vecMoveSpeed.Magnitude() <= 0.1f && veh->IsVehicleNormal() - && veh->IsCar() && bestMonetaryValue < veh->pHandling->nMonetaryValue) { - mostExpensiveVehAround = i; - bestMonetaryValue = veh->pHandling->nMonetaryValue; - } - } - } - if (bestMonetaryValue > 2000 && mostExpensiveVehAround != -1 && vehicles[mostExpensiveVehAround]) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, vehicles[mostExpensiveVehAround]); - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - return; - } - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - } else if (m_objective != OBJECTIVE_MUG_CHAR && !(CGeneral::GetRandomNumber() & 7)) { - CPed *charToMug = nil; - for (int i = 0; i < m_numNearPeds; ++i) { - CPed *nearPed = m_nearPeds[i]; - - if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) - break; - - if ((nearPed->m_nPedType == PEDTYPE_CIVFEMALE || nearPed->m_nPedType == PEDTYPE_CIVMALE - || nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->m_nPedType == PEDTYPE_UNUSED1 - || nearPed->m_nPedType == PEDTYPE_PROSTITUTE) - && nearPed->CharCreatedBy != MISSION_CHAR - && nearPed->IsPedShootable() - && nearPed->m_objective != OBJECTIVE_MUG_CHAR) { - charToMug = nearPed; - break; - } - } - if (charToMug) - SetObjective(OBJECTIVE_MUG_CHAR, charToMug); - - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; - } - } - - if (m_nPedState == PED_WANDER_PATH) { -#ifndef VC_PED_PORTS - if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { - - // += 2 is weird - for (int i = 0; i < m_numNearPeds; i += 2) { - if (m_nearPeds[i]->m_nPedState == PED_WANDER_PATH && WillChat(m_nearPeds[i])) { - if (CGeneral::GetRandomNumberInRange(0, 100) >= 100) - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; - else { - if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() >= 1.8f) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; - } else if (CanSeeEntity(m_nearPeds[i])) { - int time = CGeneral::GetRandomNumber() % 4000 + 10000; - SetChat(m_nearPeds[i], time); - m_nearPeds[i]->SetChat(this, time); - return; - } - } - } - } - } -#else - if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < 0.5f) { - if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { - for (int i = 0; i < m_numNearPeds; i ++) { - if (m_nearPeds[i] && m_nearPeds[i]->m_nPedState == PED_WANDER_PATH) { - if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 1.8f - && CanSeeEntity(m_nearPeds[i]) - && m_nearPeds[i]->CanSeeEntity(this) - && WillChat(m_nearPeds[i])) { - - int time = CGeneral::GetRandomNumber() % 4000 + 10000; - SetChat(m_nearPeds[i], time); - m_nearPeds[i]->SetChat(this, time); - return; - } - } - } - } - } else { - m_standardTimer = CTimer::GetTimeInMilliseconds() + 200; - } -#endif - } - - // Parts below aren't there in VC, they're in somewhere else. - if (!CGame::noProstitutes && m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy != MISSION_CHAR - && m_objectiveTimer < CTimer::GetTimeInMilliseconds() && !CTheScripts::IsPlayerOnAMission()) { - - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - for (int i = 0; i < lastVehicle; i++) { - CVehicle* veh = (CVehicle*)vehicles[i]; - - if (veh->IsVehicleNormal()) { - if (veh->IsCar()) { - if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil)) { - SetObjective(OBJECTIVE_SOLICIT_VEHICLE, veh); - Say(SOUND_PED_SOLICIT); - return; - } - } - } - } - } - if (m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) { - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - - for (int i = 0; i < lastVehicle; i++) { - CVehicle* veh = (CVehicle*)vehicles[i]; - - if (veh->GetModelIndex() == MI_MRWHOOP) { - if (veh->GetStatus() != STATUS_ABANDONED && veh->GetStatus() != STATUS_WRECKED) { - if ((GetPosition() - veh->GetPosition()).Magnitude() < 5.0f) { - SetObjective(OBJECTIVE_BUY_ICE_CREAM, veh); - return; - } - } - } - } - } -} - -uint32 -CPed::ScanForThreats(void) -{ - int fearFlags = m_fearFlags; - CVector ourPos = GetPosition(); - float closestPedDist = 60.0f; - CVector2D explosionPos = GetPosition(); - if (fearFlags & PED_FLAG_EXPLOSION && CheckForExplosions(explosionPos)) { - m_eventOrThreat = explosionPos; - return PED_FLAG_EXPLOSION; - } + m_vecSeekPos.x = m_stPathNodeStates[m_nCurPathNode].x; + m_vecSeekPos.y = m_stPathNodeStates[m_nCurPathNode].y; + m_vecSeekPos.z = GetPosition().z; - CPed *shooter = nil; - if ((fearFlags & PED_FLAG_GUN) && (shooter = CheckForGunShots()) && (m_nPedType != shooter->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE)) { - if (!IsGangMember()) { - m_threatEntity = shooter; - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); - return PED_FLAG_GUN; + // Mysterious code +/* int v4 = 0; + int maxNodeIndex = m_nPathNodes - 1; + if (maxNodeIndex > 0) { + if (maxNodeIndex > 8) { + while (v4 < maxNodeIndex - 8) + v4 += 8; } - if (CPedType::GetFlag(shooter->m_nPedType) & fearFlags) { - m_threatEntity = shooter; - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); - return CPedType::GetFlag(shooter->m_nPedType); + while (v4 < maxNodeIndex) + v4++; + + } +*/ + if (Seek()) { + m_nCurPathNode++; + if (m_nCurPathNode == m_nPathNodes) + RestorePreviousState(); + } +} + +void +CPed::SetEvasiveStep(CEntity *reason, uint8 animType) +{ + AnimationId stepAnim; + + if (m_nPedState == PED_STEP_AWAY || !IsPedInControl() || ((IsPlayer() || !bRespondsToThreats) && animType == 0)) + return; + + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + reason->GetPosition().x, reason->GetPosition().y, + GetPosition().x, GetPosition().y); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + float neededTurn = Abs(angleToFace - m_fRotationCur); + bool vehPressedHorn = false; + + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; + + CVehicle *veh = (CVehicle*)reason; + if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR) { + if (veh->m_nCarHornTimer != 0) { + vehPressedHorn = true; + if (!IsPlayer()) + animType = 1; } } + if (neededTurn <= DEGTORAD(90.0f) || veh->GetModelIndex() == MI_RCBANDIT || vehPressedHorn || animType != 0) { + SetLookFlag(veh, true); + if ((CGeneral::GetRandomNumber() & 1) && veh->GetModelIndex() != MI_RCBANDIT && animType == 0) { + stepAnim = ANIM_IDLE_TAXI; + } else { - CPed *deadPed = nil; - if (fearFlags & PED_FLAG_DEADPEDS && CharCreatedBy != MISSION_CHAR - && (deadPed = CheckForDeadPeds()) != nil && (deadPed->GetPosition() - ourPos).MagnitudeSqr() < sq(20.0f)) { - m_pEventEntity = deadPed; - m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); - return PED_FLAG_DEADPEDS; + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); + + // Let's turn our back to the "reason" + angleToFace += PI; + + if (angleToFace > PI) + angleToFace -= TWOPI; + + // We don't want to run towards car's direction + float dangerZone = angleToFace - vehDirection; + dangerZone = CGeneral::LimitRadianAngle(dangerZone); + + // So, add or subtract 90deg (jump to left/right) according to that + if (dangerZone > 0.0f) + angleToFace = vehDirection - HALFPI; + else + angleToFace = vehDirection + HALFPI; + + stepAnim = NUM_ANIMS; + if (animType == 0 || animType == 1) + stepAnim = ANIM_EV_STEP; + else if (animType == 2) + stepAnim = ANIM_HANDSCOWER; + } + if (!RpAnimBlendClumpGetAssociation(GetClump(), stepAnim)) { + CAnimBlendAssociation *stepAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, stepAnim, 8.0f); + stepAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + stepAssoc->SetFinishCallback(PedEvadeCB, this); + + if (animType == 0) + Say(SOUND_PED_EVADE); + + m_fRotationCur = CGeneral::LimitRadianAngle(angleToFace); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_STEP_AWAY; + } + } +} + +void +CPed::SetEvasiveDive(CPhysical *reason, uint8 onlyRandomJump) +{ + if (!IsPedInControl() || !bRespondsToThreats) + return; + + CAnimBlendAssociation *animAssoc; + float angleToFace, neededTurn; + bool handsUp = false; + + angleToFace = m_fRotationCur; + CVehicle *veh = (CVehicle*) reason; + if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR && veh->m_nCarHornTimer != 0 && !IsPlayer()) { + onlyRandomJump = true; + } + + if (onlyRandomJump) { + if (reason) { + // Simple version of my bug fix below. Doesn't calculate "danger zone", selects jump direction randomly. + // Also doesn't include random hands up, sound etc. Only used on player ped and peds running from gun shots. + + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); + angleToFace = (CGeneral::GetRandomNumber() & 1) * PI + (-0.5f*PI) + vehDirection; + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + } } else { - uint32 flagsOfSomePed = 0; - - CPed *pedToFearFrom = nil; -#ifndef VC_PED_PORTS - for (int i = 0; i < m_numNearPeds; i++) { - if (CharCreatedBy != RANDOM_CHAR || m_nearPeds[i]->CharCreatedBy != MISSION_CHAR || m_nearPeds[i]->IsPlayer()) { - CPed *nearPed = m_nearPeds[i]; - - // BUG: WTF Rockstar?! Putting this here will result in returning the flags of farthest ped to us, since m_nearPeds is sorted by distance. - // Fixed at the bottom of the function. - flagsOfSomePed = CPedType::GetFlag(nearPed->m_nPedType); - - if (CPedType::GetFlag(nearPed->m_nPedType) & fearFlags) { - if (nearPed->m_fHealth > 0.0f && OurPedCanSeeThisOne(m_nearPeds[i])) { - // FIX: Taken from VC -#ifdef FIX_BUGS - float nearPedDistSqr = (nearPed->GetPosition() - ourPos).MagnitudeSqr2D(); -#else - float nearPedDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); -#endif - if (sq(closestPedDist) > nearPedDistSqr) { - closestPedDist = Sqrt(nearPedDistSqr); - pedToFearFrom = m_nearPeds[i]; - } - } - } - } + if (IsPlayer()) { + ((CPlayerPed*)this)->m_nEvadeAmount = 5; + ((CPlayerPed*)this)->m_pEvadingFrom = reason; + reason->RegisterReference((CEntity**) &((CPlayerPed*)this)->m_pEvadingFrom); + return; } -#else - bool weSawOurEnemy = false; - bool weMaySeeOurEnemy = false; - float closestEnemyDist = 60.0f; - if ((CTimer::GetFrameCounter() + (uint8)m_randomSeed + 16) & 4) { - for (int i = 0; i < m_numNearPeds; ++i) { - if (CharCreatedBy == RANDOM_CHAR && m_nearPeds[i]->CharCreatedBy == MISSION_CHAR && !m_nearPeds[i]->IsPlayer()) { - continue; - } + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + reason->GetPosition().x, reason->GetPosition().y, + GetPosition().x, GetPosition().y); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - // BUG: Explained at the same occurence of this bug above. Fixed at the bottom of the function. - flagsOfSomePed = CPedType::GetFlag(m_nearPeds[i]->m_nPedType); - - if (flagsOfSomePed & fearFlags) { - if (m_nearPeds[i]->m_fHealth > 0.0f) { - - // VC also has ability to include objects to line of sight check here (via last bit of flagsL) - if (OurPedCanSeeThisOne(m_nearPeds[i])) { - if (m_nearPeds[i]->m_nPedState == PED_ATTACK) { - if (m_nearPeds[i]->m_pedInObjective == this) { - - float enemyDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestEnemyDist) > enemyDistSqr) { - float enemyDist = Sqrt(enemyDistSqr); - weSawOurEnemy = true; - closestPedDist = enemyDist; - closestEnemyDist = enemyDist; - pedToFearFrom = m_nearPeds[i]; - } - } - } else { - float nearPedDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestPedDist) > nearPedDistSqr && !weSawOurEnemy) { - closestPedDist = Sqrt(nearPedDistSqr); - pedToFearFrom = m_nearPeds[i]; - } - } - } else if (!weSawOurEnemy) { - CPed *nearPed = m_nearPeds[i]; - if (nearPed->m_nPedState == PED_ATTACK) { - CColPoint foundCol; - CEntity *foundEnt; - - // We don't see him yet but he's behind a ped, vehicle or object - // VC also has ability to include objects to line of sight check here (via last bit of flagsL) - if (!CWorld::ProcessLineOfSight(ourPos, nearPed->GetPosition(), foundCol, foundEnt, - true, false, false, false, false, false, false)) { - - if (nearPed->m_pedInObjective == this) { - float enemyDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestEnemyDist) > enemyDistSqr) { - float enemyDist = Sqrt(enemyDistSqr); - weMaySeeOurEnemy = true; - closestPedDist = enemyDist; - closestEnemyDist = enemyDist; - pedToFearFrom = m_nearPeds[i]; - } - } else if (!nearPed->GetWeapon()->IsTypeMelee() && !weMaySeeOurEnemy) { - float nearPedDistSqr = (m_nearPeds[i]->GetPosition() - ourPos).MagnitudeSqr2D(); - if (sq(closestPedDist) > nearPedDistSqr) { - weMaySeeOurEnemy = true; - closestPedDist = Sqrt(nearPedDistSqr); - pedToFearFrom = m_nearPeds[i]; - } - } - } - } - } - } - } - } - } -#endif - int16 lastVehicle; - CEntity* vehicles[8]; - CWorld::FindObjectsInRange(ourPos, 20.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - CVehicle* foundVeh = nil; - for (int i = 0; i < lastVehicle; i++) { - CVehicle* nearVeh = (CVehicle*)vehicles[i]; - - CPed *driver = nearVeh->pDriver; - if (driver) { - - // BUG: Same bug as above. Fixed at the bottom of function. - flagsOfSomePed = CPedType::GetFlag(driver->m_nPedType); - if (CPedType::GetFlag(driver->m_nPedType) & fearFlags) { - if (driver->m_fHealth > 0.0f && OurPedCanSeeThisOne(nearVeh->pDriver)) { - // FIX: Taken from VC + // FIX: Peds no more dive into cars. Taken from SetEvasiveStep, last if statement inverted #ifdef FIX_BUGS - float driverDistSqr = (driver->GetPosition() - ourPos).MagnitudeSqr2D(); -#else - float driverDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); -#endif - if (sq(closestPedDist) > driverDistSqr) { - closestPedDist = Sqrt(driverDistSqr); - pedToFearFrom = nearVeh->pDriver; - } - } - } - } - } - m_threatEntity = pedToFearFrom; - if (m_threatEntity) - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + float vehDirection = CGeneral::GetRadianAngleBetweenPoints( + veh->m_vecMoveSpeed.x, veh->m_vecMoveSpeed.y, + 0.0f, 0.0f); -#ifdef FIX_BUGS - if (pedToFearFrom) - flagsOfSomePed = CPedType::GetFlag(((CPed*)m_threatEntity)->m_nPedType); + // Let's turn our back to the "reason" + angleToFace += PI; + + if (angleToFace > PI) + angleToFace -= 2 * PI; + + // We don't want to dive towards car's direction + float dangerZone = angleToFace - vehDirection; + dangerZone = CGeneral::LimitRadianAngle(dangerZone); + + // So, add or subtract 90deg (jump to left/right) according to that + if (dangerZone > 0.0f) + angleToFace = 0.5f * PI + vehDirection; else - flagsOfSomePed = 0; + angleToFace = vehDirection - 0.5f * PI; #endif - return flagsOfSomePed; + neededTurn = Abs(angleToFace - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = 2 * PI - neededTurn; + + if (neededTurn <= 0.5f*PI) { + if (CGeneral::GetRandomNumber() & 1) + handsUp = true; + } else { + if (CGeneral::GetRandomNumber() & 7) + return; + } + Say(SOUND_PED_EVADE); } + + if (handsUp || !IsPlayer() && m_pedStats->m_flags & STAT_NO_DIVE) { + m_fRotationCur = angleToFace; + ClearLookFlag(); + ClearAimFlag(); + SetLookFlag(reason, true); + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSUP); + if (animAssoc) + return; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSUP, 8.0f); + animAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + animAssoc->SetFinishCallback(PedEvadeCB, this); + SetStoredState(); + m_nPedState = PED_STEP_AWAY; + } else { + m_fRotationCur = angleToFace; + ClearLookFlag(); + ClearAimFlag(); + SetStoredState(); + m_nPedState = PED_DIVE_AWAY; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_EV_DIVE, 8.0f); + animAssoc->SetFinishCallback(PedEvadeCB, this); + } + + if (reason->IsVehicle() && m_nPedType == PEDTYPE_COP) { + if (veh->pDriver && veh->pDriver->IsPlayer()) { + CWanted *wanted = FindPlayerPed()->m_pWanted; + wanted->RegisterCrime_Immediately(CRIME_RECKLESS_DRIVING, GetPosition(), (uintptr)this, false); + wanted->RegisterCrime_Immediately(CRIME_SPEEDING, GetPosition(), (uintptr)this, false); + } + } +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + else if (reason->IsVehicle()) { + if (veh->pDriver && veh->pDriver->IsPlayer()) { + CWanted* wanted = FindPlayerPed()->m_pWanted; + wanted->RegisterCrime(CRIME_RECKLESS_DRIVING, GetPosition(), (uintptr)this, false); + } + } +#endif +} + +void +CPed::PedEvadeCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + if (!animAssoc) { + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) + ped->RestorePreviousState(); + + } else if (animAssoc->animId == ANIM_EV_DIVE) { + ped->bUpdateAnimHeading = true; + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY) + { + ped->m_getUpTimer = CTimer::GetTimeInMilliseconds() + 1; + ped->m_nPedState = PED_FALL; + } + animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + + } else if (animAssoc->flags & ASSOC_FADEOUTWHENDONE) { + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) + ped->RestorePreviousState(); + + } else if (ped->m_nPedState != PED_ARRESTED) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (animAssoc->blendDelta >= 0.0f) + animAssoc->blendDelta = -4.0f; + + ped->ClearLookFlag(); + if (ped->m_nPedState == PED_DIVE_AWAY || ped->m_nPedState == PED_STEP_AWAY) { + ped->RestorePreviousState(); + } + } +} + +void +CPed::SetDie(AnimationId animId, float delta, float speed) +{ + CPlayerPed *player = FindPlayerPed(); + if (player == this) { + if (!player->m_bCanBeDamaged) + return; + } + + m_threatEntity = nil; + if (DyingOrDead()) + return; + + if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) + delta *= 0.5f; + + SetStoredState(); + ClearAll(); + m_fHealth = 0.0f; + if (m_nPedState == PED_DRIVING) { + if (!IsPlayer()) + FlagToDestroyWhenNextProcessed(); + } else if (bInVehicle) { + if (m_pVehicleAnim) + m_pVehicleAnim->blendDelta = -1000.0f; + } else if (EnteringCar()) { + QuitEnteringCar(); + } + + m_nPedState = PED_DIE; + if (animId == NUM_ANIMS) { + bIsPedDieAnimPlaying = false; + } else { + CAnimBlendAssociation *dieAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animId, delta); + if (speed > 0.0f) + dieAssoc->speed = speed; + + dieAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + if (dieAssoc->IsRunning()) { + dieAssoc->SetFinishCallback(FinishDieAnimCB, this); + bIsPedDieAnimPlaying = true; + } + } + + Say(SOUND_PED_DEATH); + if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK) + QuitEnteringCar(); + if (!bInVehicle) + StopNonPartialAnims(); + + m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); +} + +void +CPed::FinishDieAnimCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (ped->bIsPedDieAnimPlaying) + ped->bIsPedDieAnimPlaying = false; +} + +void +CPed::SetDead(void) +{ + bUsesCollision = false; + + m_fHealth = 0.0f; + if (m_nPedState == PED_DRIVING) + bIsVisible = false; + + m_nPedState = PED_DEAD; + m_pVehicleAnim = nil; + m_pCollidingEntity = nil; + + CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(weapon->m_nModelId); + + m_currentWeapon = WEAPONTYPE_UNARMED; + CEventList::RegisterEvent(EVENT_INJURED_PED, EVENT_ENTITY_PED, this, nil, 250); + if (this != FindPlayerPed()) { + CreateDeadPedWeaponPickups(); + CreateDeadPedMoney(); + } + + m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); + m_deadBleeding = false; + bDoBloodyFootprints = false; + bVehExitWillBeInstant = false; + CEventList::RegisterEvent(EVENT_DEAD_PED, EVENT_ENTITY_PED, this, nil, 1000); +} + +void +CPed::Die(void) +{ + // UNUSED: This is a perfectly empty function. +} + +void +CPed::SetChat(CEntity *chatWith, uint32 time) +{ + if(m_nPedState != PED_CHAT) + SetStoredState(); + + m_nPedState = PED_CHAT; + SetMoveState(PEDMOVE_STILL); +#if defined VC_PED_PORTS || defined FIX_BUGS + m_lookTimer = 0; +#endif + SetLookFlag(chatWith, true); + m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; +} + +void +CPed::Chat(void) +{ + // We're already looking to our partner + if (bIsLooking && TurnBody()) + ClearLookFlag(); + + if (!m_pLookTarget || !m_pLookTarget->IsPed()) { + ClearChat(); + return; + } + + CPed *partner = (CPed*) m_pLookTarget; + + if (partner->m_nPedState != PED_CHAT) { + ClearChat(); + if (partner->m_pedInObjective) { + if (partner->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || + partner->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE) + ReactToAttack(partner->m_pedInObjective); + } + return; + } + if (bIsTalking) { + if (CGeneral::GetRandomNumber() < 512) { + CAnimBlendAssociation *chatAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); + if (chatAssoc) { + chatAssoc->blendDelta = -4.0f; + chatAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + bIsTalking = false; + } else + Say(SOUND_PED_CHAT); + + } else { + + if (CGeneral::GetRandomNumber() < 20 && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); + } + if (!bIsTalking && !RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_IDLE)) { + CAnimBlendAssociation *chatAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CHAT, 4.0f); + float chatTime = CGeneral::GetRandomNumberInRange(0.0f, 3.0f); + chatAssoc->SetCurrentTime(chatTime); + + bIsTalking = true; + Say(SOUND_PED_CHAT); + } + } + if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + ClearChat(); + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; + } +} + +void +CPed::ClearChat(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + bIsTalking = false; + ClearLookFlag(); + RestorePreviousState(); +} + +#ifdef PEDS_REPORT_CRIMES_ON_PHONE +void +ReportPhonePickUpCB(CAnimBlendAssociation* assoc, void* arg) +{ + CPed* ped = (CPed*)arg; + ped->m_nMoveState = PEDMOVE_STILL; + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); + + if (assoc->blendAmount > 0.5f && ped) { + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); + } +} + +void +ReportPhonePutDownCB(CAnimBlendAssociation* assoc, void* arg) +{ + assoc->flags |= ASSOC_DELETEFADEDOUT; + assoc->blendDelta = -1000.0f; + CPed* ped = (CPed*)arg; + + if (ped->m_phoneId != -1 && crimeReporters[ped->m_phoneId] == ped) { + crimeReporters[ped->m_phoneId] = nil; + gPhoneInfo.m_aPhones[ped->m_phoneId].m_nState = PHONE_STATE_FREE; + ped->m_phoneId = -1; + } + + if (assoc->blendAmount > 0.5f) + ped->bUpdateAnimHeading = true; + + ped->SetWanderPath(CGeneral::GetRandomNumber() & 7); +} +#endif + +bool +CPed::FacePhone(void) +{ + // This function was broken since it's left unused early in development. +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + float phoneDir = CGeneral::GetRadianAngleBetweenPoints( + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, + GetPosition().x, GetPosition().y); + + if (m_facePhoneStart) { + m_lookTimer = 0; + SetLookFlag(phoneDir, true); + m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; + m_facePhoneStart = false; + } + + if (bIsLooking && TurnBody()) { + ClearLookFlag(); + SetIdle(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + CAnimBlendAssociation* assoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_IN, 4.0f); + assoc->SetFinishCallback(ReportPhonePickUpCB, this); + return true; + } + + return false; +#else + float currentRot = RADTODEG(m_fRotationCur); + float phoneDir = CGeneral::GetRadianAngleBetweenPoints( + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.x, + gPhoneInfo.m_aPhones[m_phoneId].m_vecPos.y, + GetPosition().x, + GetPosition().y); + + SetLookFlag(phoneDir, false); + phoneDir = CGeneral::LimitAngle(phoneDir); + m_moved = CVector2D(0.0f, 0.0f); + + if (currentRot - 180.0f > phoneDir) + phoneDir += 2 * 180.0f; + else if (180.0f + currentRot < phoneDir) + phoneDir -= 2 * 180.0f; + + float neededTurn = currentRot - phoneDir; + + if (Abs(neededTurn) <= 0.75f) { + SetIdle(); + ClearLookFlag(); + m_phoneTalkTimer = CTimer::GetTimeInMilliseconds() + 10000; + return true; + } else { + m_fRotationCur = DEGTORAD(currentRot - neededTurn * 0.2f); + return false; + } +#endif +} +bool +CPed::MakePhonecall(void) +{ +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + if (!IsPlayer() && CTimer::GetTimeInMilliseconds() > m_phoneTalkTimer - 7000 && bRunningToPhone) { + + FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(m_crimeToReportOnPhone, GetPosition(), + (m_crimeToReportOnPhone == CRIME_POSSESSION_GUN ? (uintptr)m_threatEntity : (uintptr)m_victimOfPlayerCrime), false); + + if (m_crimeToReportOnPhone != CRIME_POSSESSION_GUN) + FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1); + + bRunningToPhone = false; + } +#endif + if (CTimer::GetTimeInMilliseconds() <= m_phoneTalkTimer) + return false; + +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + CAnimBlendAssociation* talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_PHONE_TALK); + if (talkAssoc && talkAssoc->blendAmount > 0.5f) { + CAnimBlendAssociation* endAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_PHONE_OUT, 8.0f); + endAssoc->flags &= ~ASSOC_DELETEFADEDOUT; + endAssoc->SetFinishCallback(ReportPhonePutDownCB, this); + } +#endif + SetIdle(); + + gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; +#ifndef PEDS_REPORT_CRIMES_ON_PHONE + m_phoneId = -1; +#endif + + // Because SetWanderPath is now done async in ReportPhonePutDownCB +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + return false; +#else + return true; +#endif +} + +void +CPed::Teleport(CVector pos) +{ + CWorld::Remove(this); + SetPosition(pos); + bIsStanding = false; + m_nPedStateTimer = 0; + m_actionX = 0.0f; + m_actionY = 0.0f; + m_pDamageEntity = nil; + CWorld::Add(this); +} + +void +CPed::SetSeekCar(CVehicle *car, uint32 doorNode) +{ + if (m_nPedState == PED_SEEK_CAR) + return; + +#ifdef VC_PED_PORTS + if (!CanSetPedState() || m_nPedState == PED_DRIVING) + return; +#endif + + SetStoredState(); + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + m_carInObjective = car; + m_carInObjective->RegisterReference((CEntity**) &m_carInObjective); + m_pMyVehicle = car; + m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); + // m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + m_vehEnterType = doorNode; + m_distanceToCountSeekDone = 0.5f; + m_nPedState = PED_SEEK_CAR; + } void @@ -15973,485 +6826,104 @@ CPed::SeekCar(void) } } -void -CPed::StartFightDefend(uint8 direction, uint8 hitLevel, uint8 unk) +bool +CPed::CheckForExplosions(CVector2D &area) { - if (m_nPedState == PED_DEAD) { - if (CGame::nastyGame) { - if (hitLevel == HITLEVEL_GROUND) { - CAnimBlendAssociation *floorHitAssoc; - if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) { - floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f); - } else { - floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[FIGHTMOVE_HITONFLOOR].animId, 8.0f); - } - if (floorHitAssoc) { - floorHitAssoc->SetCurrentTime(0.0f); - floorHitAssoc->SetRun(); - floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - } - } - if (CGame::nastyGame) { - CVector headPos = GetNodePosition(PED_HEAD); - for(int i = 0; i < 4; ++i) { - CVector bloodDir(0.0f, 0.0f, 0.1f); - CVector bloodPos = headPos - 0.2f * GetForward(); - CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, bloodDir, nil, 0.0f, 0, 0, 0, 0); - } - } + int event = 0; + if (CEventList::FindClosestEvent(EVENT_EXPLOSION, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEntity *actualEntity = nil; + + switch (gaEvent[event].entityType) { + case EVENT_ENTITY_PED: + actualEntity = CPools::GetPed(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_VEHICLE: + actualEntity = CPools::GetVehicle(gaEvent[event].entityRef); + break; + case EVENT_ENTITY_OBJECT: + actualEntity = CPools::GetObject(gaEvent[event].entityRef); + break; + default: + break; } - } else if (m_nPedState == PED_FALL) { - if (hitLevel == HITLEVEL_GROUND && !IsPedHeadAbovePos(-0.3f)) { - CAnimBlendAssociation *floorHitAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL) ? - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f) : - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT, 8.0f); - if (floorHitAssoc) { - floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - floorHitAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - } else if (IsPedInControl()) { - if ((IsPlayer() && m_nPedState != PED_FIGHT && ((CPlayerPed*)this)->m_fMoveSpeed > 1.0f) - || (!IsPlayer() && m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE)) { -#ifndef VC_PED_PORTS - if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 3) && CGeneral::GetRandomNumber() & 7) { - if (IsPlayer() || CGeneral::GetRandomNumber() & 3) { -#else - if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 1) && CGeneral::GetRandomNumber() & 7) { - if (IsPlayer() || CGeneral::GetRandomNumber() & 1) { -#endif - AnimationId shotAnim; - switch (direction) { - case 1: - shotAnim = ANIM_SHOT_LEFT_PARTIAL; - break; - case 2: - shotAnim = ANIM_SHOT_BACK_PARTIAL; - break; - case 3: - shotAnim = ANIM_SHOT_RIGHT_PARTIAL; - break; - default: - shotAnim = ANIM_SHOT_FRONT_PARTIAL; - break; - } - CAnimBlendAssociation *shotAssoc = RpAnimBlendClumpGetAssociation(GetClump(), shotAnim); - if (!shotAssoc || shotAssoc->blendDelta < 0.0f) - shotAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, shotAnim, 8.0f); - shotAssoc->SetCurrentTime(0.0f); - shotAssoc->SetRun(); - shotAssoc->flags |= ASSOC_FADEOUTWHENDONE; - } else { - int time = CGeneral::GetRandomNumberInRange(1000, 3000); - SetWaitState(WAITSTATE_PLAYANIM_DUCK, &time); - } - } else { -#ifndef VC_PED_PORTS - switch (direction) { - case 1: - SetFall(500, ANIM_KO_SPIN_R, false); - break; - case 2: - SetFall(500, ANIM_KO_SKID_BACK, false); - break; - case 3: - SetFall(500, ANIM_KO_SPIN_L, false); - break; - default: - SetFall(500, ANIM_KO_SHOT_STOM, false); - break; - } -#else - bool fall = true; - AnimationId hitAnim; - switch (direction) { - case 1: - hitAnim = ANIM_KO_SPIN_R; - break; - case 2: - if (CGeneral::GetRandomNumber() & 1) { - fall = false; - hitAnim = ANIM_HIT_BACK; - } else { - hitAnim = ANIM_KO_SKID_BACK; - } - break; - case 3: - hitAnim = ANIM_KO_SPIN_L; - break; - default: - if (hitLevel == HITLEVEL_LOW) { - hitAnim = ANIM_KO_SHOT_STOM; - } else if (CGeneral::GetRandomNumber() & 1) { - fall = false; - hitAnim = ANIM_HIT_WALK; - } else if (CGeneral::GetRandomNumber() & 1) { - fall = false; - hitAnim = ANIM_HIT_HEAD; - } else { - hitAnim = ANIM_KO_SHOT_FACE; - } - break; - } - if (fall) { - SetFall(500, hitAnim, false); - } else { - CAnimBlendAssociation *hitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), hitAnim); - if (!hitAssoc || hitAssoc->blendDelta < 0.0f) - hitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, hitAnim, 8.0f); + if (actualEntity) { + m_pEventEntity = actualEntity; + m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); + bGonnaInvestigateEvent = true; + } else + bGonnaInvestigateEvent = false; - hitAssoc->SetCurrentTime(0.0f); - hitAssoc->SetRun(); - hitAssoc->flags |= ASSOC_FADEOUTWHENDONE; - } -#endif - } - Say(SOUND_PED_DEFEND); - } else { - Say(SOUND_PED_DEFEND); - switch (hitLevel) { - case HITLEVEL_GROUND: - m_curFightMove = FIGHTMOVE_HITONFLOOR; - break; - case HITLEVEL_LOW: -#ifndef VC_PED_PORTS - if (direction == 2) { - SetFall(1000, ANIM_KO_SKID_BACK, false); - return; - } -#else - if (direction == 2 && (!IsPlayer() || ((CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f))) { - SetFall(1000, ANIM_KO_SKID_BACK, false); - return; - } else if (direction != 2 && !IsPlayer() && (CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f) { - SetFall(1000, ANIM_KO_SHOT_STOM, false); - return; - } -#endif - m_curFightMove = FIGHTMOVE_HITBODY; - break; - case HITLEVEL_HIGH: - switch (direction) { - case 1: - m_curFightMove = FIGHTMOVE_HITLEFT; - break; - case 2: - m_curFightMove = FIGHTMOVE_HITBACK; - break; - case 3: - m_curFightMove = FIGHTMOVE_HITRIGHT; - break; - default: - if (unk <= 5) - m_curFightMove = FIGHTMOVE_HITHEAD; - else - m_curFightMove = FIGHTMOVE_HITBIGSTEP; - break; - } - break; - default: - switch (direction) { - case 1: - m_curFightMove = FIGHTMOVE_HITLEFT; - break; - case 2: - m_curFightMove = FIGHTMOVE_HITBACK; - break; - case 3: - m_curFightMove = FIGHTMOVE_HITRIGHT; - break; - default: - if (unk <= 5) - m_curFightMove = FIGHTMOVE_HITCHEST; - else - m_curFightMove = FIGHTMOVE_HITBIGSTEP; - break; - } - break; - } - if (m_nPedState == PED_GETUP && !IsPedHeadAbovePos(0.0f)) - m_curFightMove = FIGHTMOVE_HITONFLOOR; - - if (m_nPedState == PED_FIGHT) { - CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); - moveAssoc->SetCurrentTime(0.0f); - moveAssoc->SetFinishCallback(FinishFightMoveCB, this); - if (IsPlayer()) - moveAssoc->speed = 1.3f; - - m_takeAStepAfterAttack = 0; - m_fightButtonPressure = 0; - } else if (IsPlayer() && m_currentWeapon != WEAPONTYPE_UNARMED) { - CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); - moveAssoc->SetCurrentTime(0.0f); - moveAssoc->speed = 1.3f; - } else { - if (m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK) - SetStoredState(); - - if (m_nWaitState != WAITSTATE_FALSE) { - m_nWaitState = WAITSTATE_FALSE; - RestoreHeadingRate(); - } - m_nPedState = PED_FIGHT; - m_fightButtonPressure = 0; - RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT); - CAnimBlendAssociation *walkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START); - if (walkStartAssoc) { - walkStartAssoc->flags |= ASSOC_DELETEFADEDOUT; - walkStartAssoc->blendDelta = -1000.0f; - } - CAnimBlendAssociation *walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); - if (!walkStopAssoc) - walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); - if (walkStopAssoc) { - walkStopAssoc->flags |= ASSOC_DELETEFADEDOUT; - walkStopAssoc->blendDelta = -1000.0f; - RestoreHeadingRate(); - } - SetMoveState(PEDMOVE_NONE); - m_nStoredMoveState = PEDMOVE_NONE; - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f; - CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); - moveAssoc->SetFinishCallback(FinishFightMoveCB, this); - m_fightState = FIGHTSTATE_NO_MOVE; - m_takeAStepAfterAttack = false; - bIsAttacking = true; - } - } + CEventList::ClearEvent(event); + return true; + } else if (CEventList::FindClosestEvent(EVENT_FIRE, GetPosition(), &event)) { + area.x = gaEvent[event].posn.x; + area.y = gaEvent[event].posn.y; + CEventList::ClearEvent(event); + bGonnaInvestigateEvent = false; + return true; } + + bGonnaInvestigateEvent = false; + return false; } -void -CPed::UpdateFromLeader(void) +CPed * +CPed::CheckForGunShots(void) { - if (CTimer::GetTimeInMilliseconds() <= m_objectiveTimer) - return; - - if (!m_leader) - return; - - CVector leaderDist; - if (m_leader->InVehicle()) - leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); - else - leaderDist = m_leader->GetPosition() - GetPosition(); - - if (leaderDist.Magnitude() > 30.0f) { - if (IsPedInControl()) { - SetObjective(OBJECTIVE_NONE); - SetIdle(); - SetMoveState(PEDMOVE_STILL); - } - SetLeader(nil); - return; - } - - if (IsPedInControl()) { - if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) - WarpPedToNearLeaderOffScreen(); - - if (m_leader->m_nPedState == PED_DEAD) { - SetLeader(nil); - SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); - return; - } - if (!m_leader->bInVehicle) { - if (m_leader->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (bInVehicle) { - if (m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT && m_objective != OBJECTIVE_LEAVE_CAR) - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - - return; - } - if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - RestorePreviousObjective(); - RestorePreviousState(); - } - } - if (m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy == RANDOM_CHAR) { - SetLeader(nil); - return; - } - } - if (!bInVehicle && m_leader->bInVehicle && m_leader->m_nPedState == PED_DRIVING) { - if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (m_leader->m_pMyVehicle->m_nNumPassengers < m_leader->m_pMyVehicle->m_nNumMaxPassengers) - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_pMyVehicle); - } - } else if (m_leader->m_objective == OBJECTIVE_NONE || (m_leader->IsPlayer() && m_leader->m_objective == OBJECTIVE_WAIT_ON_FOOT) - || m_objective == m_leader->m_objective) { - - if (m_leader->m_nPedState == PED_ATTACK) { - CEntity *lookTargetOfLeader = m_leader->m_pLookTarget; - if (lookTargetOfLeader && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT - && lookTargetOfLeader->IsPed() && lookTargetOfLeader != this) { - - SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, lookTargetOfLeader); - SetObjectiveTimer(8000); - SetLookFlag(m_leader->m_pLookTarget, false); - SetLookTimer(500); - } - } else { - if (IsPedInControl() && m_nPedState != PED_ATTACK) { -#ifndef VC_PED_PORTS - SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); - SetObjectiveTimer(0); -#else - if (m_leader->m_objective == OBJECTIVE_NONE && m_objective == OBJECTIVE_NONE - && m_leader->m_nPedState == PED_CHAT && m_nPedState == PED_CHAT) { - - SetObjective(OBJECTIVE_NONE); - } else { - SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); - SetObjectiveTimer(0); - } -#endif - } - if (m_nPedState == PED_IDLE && m_leader->IsPlayer()) { - if (ScanForThreats() && m_threatEntity) { - m_pLookTarget = m_threatEntity; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - if (m_attackTimer < CTimer::GetTimeInMilliseconds() && !GetWeapon()->IsTypeMelee()) { - m_pPointGunAt = m_threatEntity; - if (m_threatEntity) - m_threatEntity->RegisterReference((CEntity **) &m_pPointGunAt); - SetAttack(m_threatEntity); - } - } - } - } - } else { - switch (m_leader->m_objective) { - case OBJECTIVE_WAIT_ON_FOOT: - case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: - case OBJECTIVE_WAIT_IN_CAR: - case OBJECTIVE_FOLLOW_ROUTE: - SetObjective(m_leader->m_objective); - m_objectiveTimer = m_leader->m_objectiveTimer; - break; - case OBJECTIVE_GUARD_SPOT: - SetObjective(OBJECTIVE_GUARD_SPOT, m_leader->m_vecSeekPosEx); - m_objectiveTimer = m_leader->m_objectiveTimer; - break; - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - if (m_leader->m_pedInObjective) { - SetObjective(m_leader->m_objective, m_leader->m_pedInObjective); - m_objectiveTimer = m_leader->m_objectiveTimer; - } - break; - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - if (m_leader->m_carInObjective) { - SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_carInObjective); - return; - } - break; - case OBJECTIVE_GUARD_ATTACK: - return; - case OBJECTIVE_HAIL_TAXI: - m_leader = nil; - SetObjective(OBJECTIVE_NONE); - break; - default: - SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); - SetObjectiveTimer(0); - break; - } - } - } else if (bInVehicle) { - if ((!m_leader->bInVehicle || m_leader->m_nPedState == PED_EXIT_CAR) && m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { - - switch (m_leader->m_objective) { - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - if (m_pMyVehicle == m_leader->m_pMyVehicle || m_pMyVehicle == m_leader->m_carInObjective) - break; - - // fall through - default: - if (m_pMyVehicle && m_objective != OBJECTIVE_LEAVE_CAR) { -#ifdef VC_PED_PORTS - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 250; -#endif - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } - - break; - } + int event; + if (CEventList::FindClosestEvent(EVENT_GUNSHOT, GetPosition(), &event)) { + if (gaEvent[event].entityType == EVENT_ENTITY_PED) { + // Probably due to we don't want peds to go gunshot area? (same on VC) + bGonnaInvestigateEvent = false; + return CPools::GetPed(gaEvent[event].entityRef); } } + bGonnaInvestigateEvent = false; + return nil; } -void -CPed::UpdatePosition(void) +CPed * +CPed::CheckForDeadPeds(void) { - if (CReplay::IsPlayingBack() || !bIsStanding) - return; - - CVector2D velocityChange; - - SetHeading(m_fRotationCur); - if (m_pCurrentPhysSurface) { - CVector2D velocityOfSurface; - if (!IsPlayer() && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) { - - // It seems R* didn't like m_vecOffsetFromPhysSurface for boats - CVector offsetToSurface = GetPosition() - m_pCurrentPhysSurface->GetPosition(); - offsetToSurface.z -= FEET_OFFSET; - - CVector surfaceMoveVelocity = m_pCurrentPhysSurface->m_vecMoveSpeed; - CVector surfaceTurnVelocity = CrossProduct(m_pCurrentPhysSurface->m_vecTurnSpeed, offsetToSurface); - - // Also we use that weird formula instead of friction if it's boat - float slideMult = -m_pCurrentPhysSurface->m_vecTurnSpeed.MagnitudeSqr(); - velocityOfSurface = slideMult * offsetToSurface * CTimer::GetTimeStep() + (surfaceTurnVelocity + surfaceMoveVelocity); - m_vecMoveSpeed.z = slideMult * offsetToSurface.z * CTimer::GetTimeStep() + (surfaceTurnVelocity.z + surfaceMoveVelocity.z); - } else { - velocityOfSurface = m_pCurrentPhysSurface->GetSpeed(m_vecOffsetFromPhysSurface); - } - // Reminder: m_moved is displacement from walking/running. - velocityChange = m_moved + velocityOfSurface - m_vecMoveSpeed; - m_fRotationCur += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); - m_fRotationDest += m_pCurrentPhysSurface->m_vecTurnSpeed.z * CTimer::GetTimeStep(); - } else if (m_nSurfaceTouched == SURFACE_STEEP_CLIFF && (m_vecDamageNormal.x != 0.0f || m_vecDamageNormal.y != 0.0f)) { - // Ped got damaged by steep slope - m_vecMoveSpeed = CVector(0.0f, 0.0f, -0.001f); - // some kind of - CVector2D reactionForce = m_vecDamageNormal; - reactionForce.Normalise(); - - velocityChange = 0.02f * reactionForce + m_moved; - - float reactionAndVelocityDotProd = DotProduct2D(reactionForce, velocityChange); - // they're in same direction - if (reactionAndVelocityDotProd < 0.0f) { - velocityChange -= reactionAndVelocityDotProd * reactionForce; - } - } else { - velocityChange = m_moved - m_vecMoveSpeed; - } - - // Take time step into account - if (m_pCurrentPhysSurface) { - float speedChange = velocityChange.Magnitude(); - float changeMult = speedChange; - if (m_nPedState == PED_DIE && m_pCurrentPhysSurface->IsVehicle()) { - changeMult = 0.002f * CTimer::GetTimeStep(); - } else if (!(m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat())) { - changeMult = 0.01f * CTimer::GetTimeStep(); - } - - if (speedChange > changeMult) { - velocityChange = velocityChange * (changeMult / speedChange); + int event; + if (CEventList::FindClosestEvent(EVENT_DEAD_PED, GetPosition(), &event)) { + int pedHandle = gaEvent[event].entityRef; + if (pedHandle && gaEvent[event].entityType == EVENT_ENTITY_PED) { + bGonnaInvestigateEvent = true; + return CPools::GetPed(pedHandle); } } - m_vecMoveSpeed.x += velocityChange.x; - m_vecMoveSpeed.y += velocityChange.y; + bGonnaInvestigateEvent = false; + return nil; +} + +bool +CPed::IsPlayer(void) const +{ + return m_nPedType == PEDTYPE_PLAYER1 || m_nPedType == PEDTYPE_PLAYER2 || + m_nPedType == PEDTYPE_PLAYER3 || m_nPedType == PEDTYPE_PLAYER4; +} + +bool +CPed::IsGangMember(void) const +{ + return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; +} + +bool +CPed::IsPointerValid(void) +{ + int pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; + if (pedIndex < 0 || pedIndex >= NUMPEDS) + return false; + + if (m_entryInfoList.first || FindPlayerPed() == this) + return true; + + return false; } void @@ -16528,109 +7000,1283 @@ CPed::SetPedPositionInCar(void) GetMatrix() = newMat; } -static RwObject* -CloneAtomicToFrameCB(RwObject *frame, void *data) +void +CPed::LookForSexyPeds(void) { - RpAtomic *newAtomic = RpAtomicClone((RpAtomic*)frame); - RpAtomicSetFrame(newAtomic, (RwFrame*)data); - RpClumpAddAtomic(flyingClumpTemp, newAtomic); - CVisibilityPlugins::SetAtomicRenderCallback(newAtomic, nil); - return frame; + if ((!IsPedInControl() && m_nPedState != PED_DRIVING) + || m_lookTimer >= CTimer::GetTimeInMilliseconds() || m_nPedType != PEDTYPE_CIVMALE) + return; + + for (int i = 0; i < m_numNearPeds; i++) { + if (CanSeeEntity(m_nearPeds[i])) { + if ((GetPosition() - m_nearPeds[i]->GetPosition()).Magnitude() < 10.0f) { + CPed *nearPed = m_nearPeds[i]; + if ((nearPed->m_pedStats->m_sexiness > m_pedStats->m_sexiness) + && nearPed->m_nPedType == PEDTYPE_CIVFEMALE) { + + SetLookFlag(nearPed, true); + m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; + Say(SOUND_PED_CHAT_SEXY); + return; + } + } + } + } + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; } -static RwFrame* -RecurseFrameChildrenToCloneCB(RwFrame *frame, void *data) +void +CPed::LookForSexyCars(void) { - RwFrame *newFrame = RwFrameCreate(); - RwFrameAddChild((RwFrame*)data, newFrame); - RwFrameTransform(newFrame, RwFrameGetMatrix(frame), rwCOMBINEREPLACE); - RwFrameForAllObjects(frame, CloneAtomicToFrameCB, newFrame); - RwFrameForAllChildren(frame, RecurseFrameChildrenToCloneCB, newFrame); - return newFrame; + CEntity *vehicles[8]; + CVehicle *veh; + int foundVehId = 0; + int bestPriceYet = 0; + int16 lastVehicle; + + if (!IsPedInControl() && m_nPedState != PED_DRIVING) + return; + + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + CWorld::FindObjectsInRange(GetPosition(), 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int vehId = 0; vehId < lastVehicle; vehId++) { + veh = (CVehicle*)vehicles[vehId]; + if (veh != m_pMyVehicle && bestPriceYet < veh->pHandling->nMonetaryValue) { + foundVehId = vehId; + bestPriceYet = veh->pHandling->nMonetaryValue; + } + } + if (lastVehicle > 0 && bestPriceYet > 40000) + SetLookFlag(vehicles[foundVehId], false); + + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; + } } -CObject* -CPed::SpawnFlyingComponent(int pedNode, int8 direction) +bool +CPed::LookForInterestingNodes(void) { - if (CObject::nNoTempObjects >= NUMTEMPOBJECTS) - return nil; + CBaseModelInfo *model; + CPtrNode *ptrNode; + CVector effectDist; + C2dEffect *effect; + CMatrix *objMat; -#ifdef PED_SKIN - assert(!IsClumpSkinned(GetClump())); + if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) & 7 || CTimer::GetTimeInMilliseconds() <= m_standardTimer) { + return false; + } + bool found = false; + uint8 randVal = CGeneral::GetRandomNumber() % 256; + + int minX = CWorld::GetSectorIndexX(GetPosition().x - CHECK_NEARBY_THINGS_MAX_DIST); + if (minX < 0) minX = 0; + int minY = CWorld::GetSectorIndexY(GetPosition().y - CHECK_NEARBY_THINGS_MAX_DIST); + if (minY < 0) minY = 0; + int maxX = CWorld::GetSectorIndexX(GetPosition().x + CHECK_NEARBY_THINGS_MAX_DIST); +#ifdef FIX_BUGS + if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1; +#else + if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X; #endif - CObject *obj = new CObject(); - if (!obj) - return nil; + int maxY = CWorld::GetSectorIndexY(GetPosition().y + CHECK_NEARBY_THINGS_MAX_DIST); +#ifdef FIX_BUGS + if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1; +#else + if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y; +#endif - RwFrame *frame = RwFrameCreate(); - RpClump *clump = RpClumpCreate(); - RpClumpSetFrame(clump, frame); - RwMatrix *matrix = RwFrameGetLTM(m_pFrames[pedNode]->frame); - *RwFrameGetMatrix(frame) = *matrix; + for (int curY = minY; curY <= maxY && !found; curY++) { + for (int curX = minX; curX <= maxX && !found; curX++) { + CSector *sector = CWorld::GetSector(curX, curY); - flyingClumpTemp = clump; - RwFrameForAllObjects(m_pFrames[pedNode]->frame, CloneAtomicToFrameCB, frame); - RwFrameForAllChildren(m_pFrames[pedNode]->frame, RecurseFrameChildrenToCloneCB, frame); - flyingClumpTemp = nil; - switch (pedNode) { - case PED_HEAD: - // So popping head would have wheel collision. They disabled it anyway - obj->SetModelIndexNoCreate(MI_CAR_WHEEL); + for (ptrNode = sector->m_lists[ENTITYLIST_VEHICLES].first; ptrNode && !found; ptrNode = ptrNode->next) { + CVehicle *veh = (CVehicle*)ptrNode->item; + model = veh->GetModelInfo(); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &veh->GetMatrix(); + CVector effectPos = veh->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + for (ptrNode = sector->m_lists[ENTITYLIST_OBJECTS].first; ptrNode && !found; ptrNode = ptrNode->next) { + CObject *obj = (CObject*)ptrNode->item; + model = CModelInfo::GetModelInfo(obj->GetModelIndex()); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &obj->GetMatrix(); + CVector effectPos = obj->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + for (ptrNode = sector->m_lists[ENTITYLIST_BUILDINGS].first; ptrNode && !found; ptrNode = ptrNode->next) { + CBuilding *building = (CBuilding*)ptrNode->item; + model = CModelInfo::GetModelInfo(building->GetModelIndex()); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &building->GetMatrix(); + CVector effectPos = building->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + for (ptrNode = sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].first; ptrNode && !found; ptrNode = ptrNode->next) { + CBuilding *building = (CBuilding*)ptrNode->item; + model = CModelInfo::GetModelInfo(building->GetModelIndex()); + if (model->GetNum2dEffects() != 0) { + for (int e = 0; e < model->GetNum2dEffects(); e++) { + effect = model->Get2dEffect(e); + if (effect->type == EFFECT_ATTRACTOR && effect->attractor.probability >= randVal) { + objMat = &building->GetMatrix(); + CVector effectPos = building->GetMatrix() * effect->pos; + effectDist = effectPos - GetPosition(); + if (effectDist.MagnitudeSqr() < sq(8.0f)) { + found = true; + break; + } + } + } + } + } + } + } + + if (!found) + return false; + + CVector effectFrontLocal = Multiply3x3(*objMat, effect->attractor.dir); + float angleToFace = CGeneral::GetRadianAngleBetweenPoints(effectFrontLocal.x, effectFrontLocal.y, 0.0f, 0.0f); + randVal = CGeneral::GetRandomNumber() % 256; + if (randVal <= m_randomSeed % 256) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000; + SetLookFlag(angleToFace, true); + SetLookTimer(1000); + return false; + } + + CVector2D effectPos = *objMat * effect->pos; + switch (effect->attractor.type) { + case ATTRACTORTYPE_ICECREAM: + SetInvestigateEvent(EVENT_ICECREAM, effectPos, 0.1f, 15000, angleToFace); break; - case PED_UPPERARML: - case PED_UPPERARMR: - obj->SetModelIndexNoCreate(MI_BODYPARTB); - obj->SetCenterOfMass(0.25f, 0.0f, 0.0f); + case ATTRACTORTYPE_STARE: + SetInvestigateEvent(EVENT_SHOPSTALL, effectPos, 1.0f, + CGeneral::GetRandomNumberInRange(8000, 10 * effect->attractor.probability + 8500), + angleToFace); break; - case PED_UPPERLEGL: - case PED_UPPERLEGR: - obj->SetModelIndexNoCreate(MI_BODYPARTA); - obj->SetCenterOfMass(0.4f, 0.0f, 0.0f); + default: + return true; + } + return true; +} + +void +CPed::SetWaitState(eWaitState state, void *time) +{ + AnimationId waitAnim = NUM_ANIMS; + CAnimBlendAssociation *animAssoc; + + if (!IsPedInControl()) + return; + + if (state != m_nWaitState) + FinishedWaitCB(nil, this); + + switch (state) { + case WAITSTATE_TRAFFIC_LIGHTS: + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500; + SetMoveState(PEDMOVE_STILL); + break; + case WAITSTATE_CROSS_ROAD: + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 1000; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); + break; + case WAITSTATE_CROSS_ROAD_LOOK: + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 8.0f); + + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000,5000); + + break; + case WAITSTATE_LOOK_PED: + case WAITSTATE_LOOK_SHOP: + case WAITSTATE_LOOK_ACCIDENT: + case WAITSTATE_FACEOFF_GANG: + break; + case WAITSTATE_DOUBLEBACK: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3500; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + break; + case WAITSTATE_HITWALL: + m_headingRate = 2.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 16.0f); + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->flags |= ASSOC_FADEOUTWHENDONE; + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { + ClearObjective(); + RestorePreviousState(); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + } + break; + case WAITSTATE_TURN180: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TURN_180, 4.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + animAssoc->SetDeleteCallback(RestoreHeadingRateCB, this); + break; + case WAITSTATE_SURPRISE: + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 4.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + break; + case WAITSTATE_STUCK: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) { + ClearObjective(); + RestorePreviousState(); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + } + break; + case WAITSTATE_LOOK_ABOUT: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + + break; + case WAITSTATE_PLAYANIM_COWER: + waitAnim = ANIM_HANDSCOWER; + case WAITSTATE_PLAYANIM_HANDSUP: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_HANDSUP; + case WAITSTATE_PLAYANIM_HANDSCOWER: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_HANDSCOWER; + m_headingRate = 0.0f; + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 4.0f); + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + break; + case WAITSTATE_PLAYANIM_DUCK: + waitAnim = ANIM_DUCK_DOWN; + case WAITSTATE_PLAYANIM_TAXI: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_IDLE_TAXI; + case WAITSTATE_PLAYANIM_CHAT: + if (waitAnim == NUM_ANIMS) + waitAnim = ANIM_IDLE_CHAT; + if (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000; + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 4.0f); + animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->SetDeleteCallback(FinishedWaitCB, this); + break; + case WAITSTATE_FINISH_FLEE: + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + m_headingRate = 0.0f; + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2500; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f); +#ifdef FIX_BUGS + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); +#endif + break; + default: + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + return; + } + m_nWaitState = state; +} + +void +CPed::Wait(void) +{ + AnimationId mustHaveAnim = NUM_ANIMS; + CAnimBlendAssociation *animAssoc; + CPed *pedWeLook; + + if (DyingOrDead()) { + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + return; + } + + switch (m_nWaitState) { + + case WAITSTATE_TRAFFIC_LIGHTS: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (CTrafficLights::LightForPeds() == PED_LIGHTS_WALK) { + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + } + } + break; + + case WAITSTATE_CROSS_ROAD: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (CGeneral::GetRandomNumber() & 1 || !m_nWaitTimer) + m_nWaitState = WAITSTATE_FALSE; + else + SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, nil); + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + + case WAITSTATE_CROSS_ROAD_LOOK: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + m_nWaitState = WAITSTATE_FALSE; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + + case WAITSTATE_DOUBLEBACK: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + uint32 timeLeft = m_nWaitTimer - CTimer::GetTimeInMilliseconds(); + if (timeLeft < 2500 && timeLeft > 2000) { + m_nWaitTimer -= 500; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); + } + } else { + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + } + break; + + case WAITSTATE_HITWALL: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) { + m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; + } + } else { + m_nWaitState = WAITSTATE_FALSE; + } + break; + + case WAITSTATE_TURN180: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + m_fRotationCur = m_fRotationCur + PI; + if (m_nPedState == PED_INVESTIGATE) + ClearInvestigateEvent(); + } + + if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) { + m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; + } + break; + + case WAITSTATE_SURPRISE: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HIT_WALL)) { + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f); + animAssoc->SetFinishCallback(FinishedWaitCB, this); + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000; + } else { + m_nWaitState = WAITSTATE_FALSE; + } + } + break; + + case WAITSTATE_STUCK: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) + break; + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_TURN_180); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + + if (animAssoc) { + if (animAssoc->IsPartial()) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } else { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); + } + + if (animAssoc->animId == ANIM_TURN_180) { + m_fRotationCur = CGeneral::LimitRadianAngle(PI + m_fRotationCur); + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + m_nStoredMoveState = PEDMOVE_NONE; + m_panicCounter = 0; + return; + } + } + + AnimationId animToPlay; + + switch (CGeneral::GetRandomNumber() & 3) { + case 0: + animToPlay = ANIM_ROAD_CROSS; + break; + case 1: + animToPlay = ANIM_IDLE_TIRED; + break; + case 2: + animToPlay = ANIM_XPRESS_SCRATCH; + break; + case 3: + animToPlay = ANIM_TURN_180; + break; + default: + break; + } + + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); + + if (animToPlay == ANIM_TURN_180) + animAssoc->SetFinishCallback(FinishedWaitCB, this); + + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(1500, 5000); + break; + + case WAITSTATE_LOOK_ABOUT: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + m_nWaitState = WAITSTATE_FALSE; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + + case WAITSTATE_PLAYANIM_HANDSUP: + mustHaveAnim = ANIM_HANDSUP; + + case WAITSTATE_PLAYANIM_HANDSCOWER: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_HANDSCOWER; + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + pedWeLook = (CPed*) m_pLookTarget; + + if ((!m_pLookTarget || !m_pLookTarget->IsPed() || pedWeLook->m_pPointGunAt) + && m_nPedState != PED_FLEE_ENTITY + && m_nPedState != PED_ATTACK + && CTimer::GetTimeInMilliseconds() <= m_nWaitTimer + && animAssoc) { + + TurnBody(); + } else { + m_nWaitState = WAITSTATE_FALSE; + m_nWaitTimer = 0; + if (m_pLookTarget && m_pLookTarget->IsPed()) { + + if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_ATTACK) { + + if (m_pedStats->m_fear <= 100 - pedWeLook->m_pedStats->m_temper) { + + if (GetWeapon()->IsTypeMelee()) { +#ifdef VC_PED_PORTS + if(m_pedStats->m_flags & STAT_GUN_PANIC) { +#endif + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget); + if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) { + + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + if (m_nMoveState != PEDMOVE_RUN) + SetMoveState(PEDMOVE_WALK); + + if (m_nPedType != PEDTYPE_COP) { + ProcessObjective(); + SetMoveState(PEDMOVE_WALK); + } +#ifdef VC_PED_PORTS + } else { + SetObjective(OBJECTIVE_NONE); + SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + } +#endif + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_pLookTarget); + SetObjectiveTimer(20000); + } + } else { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget); + if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) + { + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + SetMoveState(PEDMOVE_RUN); + Say(SOUND_PED_FLEE_RUN); + } + } + } + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + break; + case WAITSTATE_PLAYANIM_COWER: + mustHaveAnim = ANIM_HANDSCOWER; + + case WAITSTATE_PLAYANIM_DUCK: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_DUCK_DOWN; + + case WAITSTATE_PLAYANIM_TAXI: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_IDLE_TAXI; + + case WAITSTATE_PLAYANIM_CHAT: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_IDLE_CHAT; + + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + m_nWaitState = WAITSTATE_FALSE; + } +#ifdef VC_PED_PORTS + else if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) { + if (m_pedInObjective) { + if (m_objective == OBJECTIVE_GOTO_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT) { + + // VC also calls CleanUpOldReference here for old LookTarget. + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + } + } + } +#endif + break; + + case WAITSTATE_FINISH_FLEE: + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); + if (animAssoc) { + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); + int timer = 2000; + m_nWaitState = WAITSTATE_FALSE; + SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &timer); + } + } else { + m_nWaitState = WAITSTATE_FALSE; + } break; default: break; } - obj->RefModelInfo(GetModelIndex()); - obj->AttachToRwObject((RwObject*)clump); - obj->m_fMass = 15.0f; - obj->m_fTurnMass = 5.0f; - obj->m_fAirResistance = 0.99f; - obj->m_fElasticity = 0.03f; - obj->m_fBuoyancy = m_fMass*GRAVITY/0.75f; - obj->ObjectCreatedBy = TEMP_OBJECT; - obj->SetIsStatic(false); - obj->bIsPickup = false; - obj->m_nSpecialCollisionResponseCases = COLLRESPONSE_SMALLBOX; - // life time - the more objects the are, the shorter this one will live - CObject::nNoTempObjects++; - if (CObject::nNoTempObjects > 20) - obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 12000; - else if (CObject::nNoTempObjects > 10) - obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 30000; - else - obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 60000; + if(!m_nWaitState) + RestoreHeadingRate(); +} - CVector localForcePos, forceDir; +void +CPed::FinishedWaitCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; - if (direction == 2) { - obj->m_vecMoveSpeed = 0.03f * GetForward(); - obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f; - obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - localForcePos = CVector(0.0f, 0.0f, 0.0f); - forceDir = GetForward(); - } else { - obj->m_vecMoveSpeed = -0.03f * GetForward(); - obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f; - obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); - localForcePos = CVector(0.0f, 0.0f, 0.0f); - forceDir = -GetForward(); + ped->m_nWaitTimer = 0; + ped->RestoreHeadingRate(); + ped->Wait(); +} + +void +CPed::RestoreHeadingRate(void) +{ + m_headingRate = m_pedStats->m_headingChangeRate; +} + +void +CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) +{ + ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate; +} + +void +CPed::FlagToDestroyWhenNextProcessed(void) +{ + bRemoveFromWorld = true; + if (!InVehicle()) + return; + if (m_pMyVehicle->pDriver == this){ + m_pMyVehicle->pDriver = nil; + if (IsPlayer() && m_pMyVehicle->GetStatus() != STATUS_WRECKED) + m_pMyVehicle->SetStatus(STATUS_ABANDONED); + }else{ + m_pMyVehicle->RemovePassenger(this); } - obj->ApplyTurnForce(forceDir, localForcePos); - CWorld::Add(obj); + bInVehicle = false; + m_pMyVehicle = nil; + if (CharCreatedBy == MISSION_CHAR) + m_nPedState = PED_DEAD; + else + m_nPedState = PED_NONE; + m_pVehicleAnim = nil; +} - return obj; +void +CPed::SetSolicit(uint32 time) +{ + if (m_nPedState == PED_SOLICIT || !IsPedInControl() || !m_carInObjective) + return; + + if (CharCreatedBy != MISSION_CHAR && m_carInObjective->m_nNumGettingIn == 0 + && CTimer::GetTimeInMilliseconds() < m_objectiveTimer) { + if (m_vehEnterType == CAR_DOOR_LF) { + m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; + } else { + m_fRotationDest = m_carInObjective->GetForward().Heading() + HALFPI; + } + + if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + + if(!m_carInObjective->bIsVan && !m_carInObjective->bIsBus) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_HOOKERTALK, 4.0f); + + m_nPedState = PED_SOLICIT; + } + } +} + +void +CPed::Solicit(void) +{ + if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { + CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); + SetMoveState(PEDMOVE_STILL); + + // Game uses GetAngleBetweenPoints and converts it to radian + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + doorPos.x, doorPos.y, + GetPosition().x, GetPosition().y); + + if (m_fRotationDest < 0.0f) { + m_fRotationDest = m_fRotationDest + TWOPI; + } else if (m_fRotationDest > TWOPI) { + m_fRotationDest = m_fRotationDest - TWOPI; + } + + if ((GetPosition() - doorPos).MagnitudeSqr() <= 1.0f) + return; + CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_HOOKERTALK); + if (talkAssoc) { + talkAssoc->blendDelta = -1000.0f; + talkAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (!m_carInObjective) { + RestorePreviousState(); + RestorePreviousObjective(); + SetObjectiveTimer(10000); + } else if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney <= 100) { + m_carInObjective = nil; + } else { + m_pVehicleAnim = nil; + SetLeader(m_carInObjective->pDriver); + } +} + +void +CPed::SetBuyIceCream(void) +{ + if (m_nPedState == PED_BUY_ICECREAM || !IsPedInControl()) + return; + + if (!m_carInObjective) + return; + +#ifdef FIX_ICECREAM + + // Simulating BuyIceCream + CPed* driver = m_carInObjective->pDriver; + if (driver) { + m_nPedState = PED_BUY_ICECREAM; + bFindNewNodeAfterStateRestore = true; + SetObjectiveTimer(8000); + SetChat(driver, 8000); + driver->SetChat(this, 8000); + return; + } +#endif + + // Side of the Ice Cream van + m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; + + if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 3000; + m_nPedState = PED_BUY_ICECREAM; + } +} + +bool +CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) +{ + bool foundIt = false; + + CVector helperPos = GetPosition(); + helperPos.z = pos->z - 0.5f; + + CVector foundPos = *pos; + foundPos.z -= 0.5f; + + // If there is another car between target car and us. + if (CWorld::TestSphereAgainstWorld((foundPos + helperPos) / 2.0f, 0.25f, veh, false, true, false, false, false, false)) { + + CColModel *vehCol = veh->GetModelInfo()->GetColModel(); + CVector *colMin = &vehCol->boundingBox.min; + CVector *colMax = &vehCol->boundingBox.max; + + CVector leftRearPos = CVector(colMin->x - 0.5f, colMin->y - 0.5f, 0.0f); + CVector rightRearPos = CVector(0.5f + colMax->x, colMin->y - 0.5f, 0.0f); + CVector leftFrontPos = CVector(colMin->x - 0.5f, 0.5f + colMax->y, 0.0f); + CVector rightFrontPos = CVector(0.5f + colMax->x, 0.5f + colMax->y, 0.0f); + + leftRearPos = veh->GetMatrix() * leftRearPos; + rightRearPos = veh->GetMatrix() * rightRearPos; + leftFrontPos = veh->GetMatrix() * leftFrontPos; + rightFrontPos = veh->GetMatrix() * rightFrontPos; + + // Makes helperPos veh-ped distance vector. + helperPos -= veh->GetPosition(); + + // ?!? I think it's absurd to use this unless another function like SeekCar finds next pos. with it and we're trying to simulate it's behaviour. + // On every run it returns another pos. for ped, with same distance to the veh. + // Sequence of positions are not guaranteed, it depends on global pos. (So sometimes it returns positions to make ped draw circle, sometimes don't) + helperPos = veh->GetMatrix() * helperPos; + + float vehForwardHeading = veh->GetForward().Heading(); + + // I'm absolutely not sure about these namings. + // NTVF = needed turn if we're looking to vehicle front and wanna look to... + + float potentialLrHeading = Atan2(leftRearPos.x - helperPos.x, leftRearPos.y - helperPos.y); + float NTVF_LR = CGeneral::LimitRadianAngle(potentialLrHeading - vehForwardHeading); + + float potentialRrHeading = Atan2(rightRearPos.x - helperPos.x, rightRearPos.y - helperPos.y); + float NTVF_RR = CGeneral::LimitRadianAngle(potentialRrHeading - vehForwardHeading); + + float potentialLfHeading = Atan2(leftFrontPos.x - helperPos.x, leftFrontPos.y - helperPos.y); + float NTVF_LF = CGeneral::LimitRadianAngle(potentialLfHeading - vehForwardHeading); + + float potentialRfHeading = Atan2(rightFrontPos.x - helperPos.x, rightFrontPos.y - helperPos.y); + float NTVF_RF = CGeneral::LimitRadianAngle(potentialRfHeading - vehForwardHeading); + + bool canHeadToLr = NTVF_LR <= -PI || NTVF_LR >= -HALFPI; + + bool canHeadToRr = NTVF_RR <= HALFPI || NTVF_RR >= PI; + + bool canHeadToLf = NTVF_LF >= 0.0f || NTVF_LF <= -HALFPI; + + bool canHeadToRf = NTVF_RF <= 0.0f || NTVF_RF >= HALFPI; + + // Only order of conditions are different among enterTypes. + if (m_vehEnterType == CAR_DOOR_RR) { + if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } else if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } else if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } else if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } + } else if(m_vehEnterType == CAR_DOOR_RF) { + if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } else if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } else if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } else if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } + } else if (m_vehEnterType == CAR_DOOR_LF) { + if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } else if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } else if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } else if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } + } else if (m_vehEnterType == CAR_DOOR_LR) { + if (canHeadToLr) { + foundPos = leftRearPos; + foundIt = true; + } else if (canHeadToLf) { + foundPos = leftFrontPos; + foundIt = true; + } else if (canHeadToRr) { + foundPos = rightRearPos; + foundIt = true; + } else if (canHeadToRf) { + foundPos = rightFrontPos; + foundIt = true; + } + } + } + if (!foundIt) + return false; + + helperPos = GetPosition() - foundPos; + helperPos.z = 0.0f; + if (helperPos.MagnitudeSqr() <= sq(0.5f)) + return false; + + pos->x = foundPos.x; + pos->y = foundPos.y; + return true; +} + +void +CPed::SetLeader(CEntity *leader) +{ + m_leader = (CPed*)leader; + + if(m_leader) + m_leader->RegisterReference((CEntity **)&m_leader); +} + +#ifdef VC_PED_PORTS +bool +CPed::CanPedJumpThis(CEntity *unused, CVector *damageNormal) +{ + if (m_nSurfaceTouched == SURFACE_WATER) + return true; + + CVector pos = GetPosition(); + CVector forwardOffset = GetForward(); + if (damageNormal && damageNormal->z > 0.17f) { + if (damageNormal->z > 0.9f) + return false; + + CColModel *ourCol = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(); + pos.z = ourCol->spheres->center.z - ourCol->spheres->radius * damageNormal->z + pos.z; + pos.z = pos.z + 0.05f; + float collPower = damageNormal->Magnitude2D(); + if (damageNormal->z > 0.5f) { + CVector invDamageNormal(-damageNormal->x, -damageNormal->y, 0.0f); + invDamageNormal *= 1.0f / collPower; + CVector estimatedJumpDist = invDamageNormal + collPower * invDamageNormal * ourCol->spheres->radius; + forwardOffset = estimatedJumpDist * Min(2.0f / collPower, 4.0f); + } else { + forwardOffset += collPower * ourCol->spheres->radius * forwardOffset; + } + } else { + pos.z -= 0.15f; + } + + CVector forwardPos = pos + forwardOffset; + return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); +} +#else +bool +CPed::CanPedJumpThis(CEntity *unused) +{ + CVector2D forward(-Sin(m_fRotationCur), Cos(m_fRotationCur)); + CVector pos = GetPosition(); + CVector forwardPos( + forward.x + pos.x, + forward.y + pos.y, + pos.z); + + return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); +} +#endif + +void +CPed::SetJump(void) +{ + if (!bInVehicle && +#if defined VC_PED_PORTS || defined FIX_BUGS + m_nPedState != PED_JUMP && !RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_LAUNCH) && +#endif + (m_nSurfaceTouched != SURFACE_STEEP_CLIFF || DotProduct(GetForward(), m_vecDamageNormal) >= 0.0f)) { + SetStoredState(); + m_nPedState = PED_JUMP; + CAnimBlendAssociation *jumpAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_JUMP_LAUNCH, 8.0f); + jumpAssoc->SetFinishCallback(FinishLaunchCB, this); + m_fRotationDest = m_fRotationCur; + } +} + +void +CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (ped->m_nPedState != PED_JUMP) + return; + + CVector forward(0.15f * ped->GetForward() + ped->GetPosition()); + forward.z += CModelInfo::GetModelInfo(ped->GetModelIndex())->GetColModel()->spheres->center.z + 0.25f; + + CEntity *obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); + if (!obstacle) { + // Forward of forward + forward += 0.15f * ped->GetForward(); + forward.z += 0.15f; + obstacle = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false); + } + + if (obstacle) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + + // ANIM_HIT_WALL in VC (which makes more sense) + CAnimBlendAssociation *handsCoverAssoc = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 8.0f); + handsCoverAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + handsCoverAssoc->SetFinishCallback(FinishHitHeadCB, ped); + ped->bIsLanding = true; + return; + } + + float velocityFromAnim = 0.1f; + CAnimBlendAssociation *sprintAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_SPRINT); + + if (sprintAssoc) { + velocityFromAnim = 0.05f * sprintAssoc->blendAmount + 0.17f; + } else { + CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_RUN); + if (runAssoc) { + velocityFromAnim = 0.07f * runAssoc->blendAmount + 0.1f; + } + } + + if (ped->IsPlayer() +#ifdef VC_PED_PORTS + || ped->m_pedInObjective && ped->m_pedInObjective->IsPlayer() +#endif + ) + ped->ApplyMoveForce(0.0f, 0.0f, 8.5f); + else + ped->ApplyMoveForce(0.0f, 0.0f, 4.5f); + + if (sq(velocityFromAnim) > ped->m_vecMoveSpeed.MagnitudeSqr2D() +#ifdef VC_PED_PORTS + || ped->m_pCurrentPhysSurface +#endif + ) { + +#ifdef FREE_CAM + if (TheCamera.Cams[0].Using3rdPersonMouseCam() && !CCamera::bFreeCam) { +#else + if (TheCamera.Cams[0].Using3rdPersonMouseCam()) { +#endif + float fpsAngle = ped->WorkOutHeadingForMovingFirstPerson(ped->m_fRotationCur); + ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(fpsAngle); + ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(fpsAngle); + } else { + ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(ped->m_fRotationCur); + ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(ped->m_fRotationCur); + } +#ifdef VC_PED_PORTS + if (ped->m_pCurrentPhysSurface) { + ped->m_vecMoveSpeed.x += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.x; + ped->m_vecMoveSpeed.y += ped->m_pCurrentPhysSurface->m_vecMoveSpeed.y; + } +#endif + } + + ped->bIsStanding = false; + ped->bIsInTheAir = true; + animAssoc->blendDelta = -1000.0f; + CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_JUMP_GLIDE); + + if (ped->bDoBloodyFootprints) { + CVector bloodPos(0.0f, 0.0f, 0.0f); + ped->TransformToNode(bloodPos, PED_FOOTL); + + bloodPos.z -= 0.1f; + bloodPos += 0.2f * ped->GetForward(); + + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, + 0.26f * ped->GetForward().x, + 0.26f * ped->GetForward().y, + 0.14f * ped->GetRight().x, + 0.14f * ped->GetRight().y, + 255, 255, 0, 0, 4.0f, 3000, 1.0f); + + bloodPos = CVector(0.0f, 0.0f, 0.0f); + ped->TransformToNode(bloodPos, PED_FOOTR); + + bloodPos.z -= 0.1f; + bloodPos += 0.2f * ped->GetForward(); + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, + 0.26f * ped->GetForward().x, + 0.26f * ped->GetForward().y, + 0.14f * ped->GetRight().x, + 0.14f * ped->GetRight().y, + 255, 255, 0, 0, 4.0f, 3000, 1.0f); + + if (ped->m_bloodyFootprintCountOrDeathTime <= 40) { + ped->m_bloodyFootprintCountOrDeathTime = 0; + ped->bDoBloodyFootprints = false; + } else { + ped->m_bloodyFootprintCountOrDeathTime -= 40; + } + } +} + +void +CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + ped->bResetWalkAnims = true; + ped->bIsLanding = false; + + animAssoc->blendDelta = -1000.0f; +} + +void +CPed::FinishHitHeadCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + + if (ped->m_nPedState == PED_JUMP) + ped->RestorePreviousState(); + + ped->bIsLanding = false; +} + +bool +CPed::CanPedDriveOff(void) +{ + if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) + return false; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->m_nPedType == m_nPedType && nearPed->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && nearPed->m_carInObjective == m_carInObjective) { + m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000; + return false; + } + } + return true; +} + +// These categories are purely random, most of ped models have no correlation. So I don't think making an enum. +uint8 +CPed::GetPedRadioCategory(uint32 modelIndex) +{ + switch (modelIndex) { + case MI_MALE01: + case MI_FEMALE03: + case MI_PROSTITUTE2: + case MI_WORKER1: + case MI_MOD_MAN: + case MI_MOD_WOM: + case MI_ST_WOM: + case MI_FAN_WOM: + return 3; + case MI_TAXI_D: + case MI_PIMP: + case MI_MALE02: + case MI_FEMALE02: + case MI_FATFEMALE01: + case MI_FATFEMALE02: + case MI_DOCKER1: + case MI_WORKER2: + case MI_FAN_MAN2: + return 9; + case MI_GANG01: + case MI_GANG02: + case MI_SCUM_MAN: + case MI_SCUM_WOM: + case MI_HOS_WOM: + case MI_CONST1: + return 1; + case MI_GANG03: + case MI_GANG04: + case MI_GANG07: + case MI_GANG08: + case MI_CT_MAN2: + case MI_CT_WOM2: + case MI_B_MAN3: + case MI_SHOPPER3: + return 4; + case MI_GANG05: + case MI_GANG06: + case MI_GANG11: + case MI_GANG12: + case MI_CRIMINAL02: + case MI_B_WOM2: + case MI_ST_MAN: + case MI_HOS_MAN: + return 5; + case MI_FATMALE01: + case MI_LI_MAN2: + case MI_SHOPPER1: + case MI_CAS_MAN: + return 6; + case MI_PROSTITUTE: + case MI_P_WOM2: + case MI_LI_WOM2: + case MI_B_WOM3: + case MI_CAS_WOM: + return 2; + case MI_P_WOM1: + case MI_DOCKER2: + case MI_STUD_MAN: + return 7; + case MI_CT_MAN1: + case MI_CT_WOM1: + case MI_LI_MAN1: + case MI_LI_WOM1: + case MI_B_MAN1: + case MI_B_MAN2: + case MI_B_WOM1: + case MI_SHOPPER2: + case MI_STUD_WOM: + return 8; + default: + return 0; + } +} + +void +CPed::SetRadioStation(void) +{ + static const uint8 radiosPerRadioCategories[10][4] = { + {JAH_RADIO, RISE_FM, GAME_FM, MSX_FM}, + {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, + {RISE_FM, GAME_FM, MSX_FM, FLASHBACK}, + {HEAD_RADIO, RISE_FM, LIPS_106, MSX_FM}, + {HEAD_RADIO, RISE_FM, MSX_FM, FLASHBACK}, + {JAH_RADIO, RISE_FM, LIPS_106, FLASHBACK}, + {HEAD_RADIO, RISE_FM, LIPS_106, FLASHBACK}, + {HEAD_RADIO, JAH_RADIO, LIPS_106, FLASHBACK}, + {HEAD_RADIO, DOUBLE_CLEF, LIPS_106, FLASHBACK}, + {CHATTERBOX, HEAD_RADIO, LIPS_106, GAME_FM} + }; + uint8 orderInCat = 0; // BUG: this wasn't initialized + + if (IsPlayer() || !m_pMyVehicle || m_pMyVehicle->pDriver != this) + return; + + uint8 category = GetPedRadioCategory(GetModelIndex()); + if (DMAudio.IsMP3RadioChannelAvailable()) { + if (CGeneral::GetRandomNumber() & 15) { + for (orderInCat = 0; orderInCat < 4; orderInCat++) { + if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) + break; + } + } else { + m_pMyVehicle->m_nRadioStation = USERTRACK; + } + } else { + for (orderInCat = 0; orderInCat < 4; orderInCat++) { + if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) + break; + } + } + if (orderInCat == 4) { + if (DMAudio.IsMP3RadioChannelAvailable()) { + if (CGeneral::GetRandomNumber() & 15) + m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; + else + m_pMyVehicle->m_nRadioStation = USERTRACK; + } else { + m_pMyVehicle->m_nRadioStation = radiosPerRadioCategories[category][CGeneral::GetRandomNumber() & 3]; + } + } } void @@ -16718,680 +8364,104 @@ CPed::WarpPedIntoCar(CVehicle *car) bChangedSeat = true; } -void -CPed::SetObjective(eObjective newObj, CVector dest) + +#ifdef PEDS_REPORT_CRIMES_ON_PHONE +// returns event id, parameter is optional +int32 +CPed::CheckForPlayerCrimes(CPed *victim) { - if (DyingOrDead()) - return; + int i; + float dist; + float mindist = 60.0f; + CPlayerPed *player = FindPlayerPed(); + int32 victimRef = (victim ? CPools::GetPedRef(victim) : 0); + int event = -1; - if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) - return; + for (i = 0; i < NUMEVENTS; i++) { + if (gaEvent[i].type == EVENT_NULL || gaEvent[i].type > EVENT_CAR_SET_ON_FIRE) + continue; - SetObjectiveTimer(0); - if (m_objective == newObj) { - if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { - if (m_nextRoutePointPos == dest) - return; - } else if (newObj == OBJECTIVE_GUARD_SPOT) { - if (m_vecSeekPosEx == dest) - return; + // those are already handled in game, also DEAD_PED isn't registered alone, most of the time there is SHOOT_PED etc. + if (gaEvent[i].type == EVENT_DEAD_PED || gaEvent[i].type == EVENT_GUNSHOT || gaEvent[i].type == EVENT_EXPLOSION) + continue; + + if (victim && gaEvent[i].entityRef != victimRef) + continue; + + if (gaEvent[i].criminal != player) + continue; + + dist = (GetPosition() - gaEvent[i].posn).Magnitude(); + if (dist < mindist) { + mindist = dist; + event = i; } } -#ifdef VC_PED_PORTS - ClearPointGunAt(); -#endif - bObjectiveCompleted = false; - switch (newObj) { - case OBJECTIVE_GUARD_SPOT: - m_vecSeekPosEx = dest; - m_distanceToCountSeekDoneEx = 5.0f; - SetMoveState(PEDMOVE_STILL); - break; - case OBJECTIVE_GUARD_AREA: - case OBJECTIVE_WAIT_IN_CAR: - case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: - case OBJECTIVE_KILL_CHAR_ON_FOOT: - case OBJECTIVE_KILL_CHAR_ANY_MEANS: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: - case OBJECTIVE_GOTO_CHAR_ON_FOOT: - case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: - case OBJECTIVE_LEAVE_CAR: - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - case OBJECTIVE_FOLLOW_CAR_IN_CAR: - case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: - case OBJECTIVE_DESTROY_OBJECT: - case OBJECTIVE_DESTROY_CAR: - break; - case OBJECTIVE_GOTO_AREA_ANY_MEANS: - case OBJECTIVE_GOTO_AREA_ON_FOOT: - bIsRunning = false; - m_pNextPathNode = nil; - m_nextRoutePointPos = dest; - m_vecSeekPos = m_nextRoutePointPos; - m_distanceToCountSeekDone = 0.5f; - bUsePedNodeSeek = true; - if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) - return; - break; - case OBJECTIVE_RUN_TO_AREA: - bIsRunning = true; - m_pNextPathNode = nil; - m_nextRoutePointPos = dest; - m_vecSeekPos = m_nextRoutePointPos; - m_distanceToCountSeekDone = 0.5f; - bUsePedNodeSeek = true; - if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) - return; - break; - default: break; - } - - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } -} - -void -CPed::SetMoveAnim(void) -{ - if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) - return; - - if (m_nMoveState == PEDMOVE_NONE) { - m_nStoredMoveState = PEDMOVE_NONE; - return; - } - - AssocGroupId animGroupToUse; - if (m_leader && m_leader->IsPlayer()) - animGroupToUse = ASSOCGRP_PLAYER; - else - animGroupToUse = m_animGroup; - - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_BLOCK); - if (!animAssoc) { - CAnimBlendAssociation *fightIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); - animAssoc = fightIdleAssoc; - if (fightIdleAssoc && m_nPedState == PED_FIGHT) - return; - - if (fightIdleAssoc) { - CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 8.0f); - } - } - } - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED); - if (animAssoc) - if (m_nWaitState == WAITSTATE_STUCK || m_nWaitState == WAITSTATE_FINISH_FLEE) - return; - - if (animAssoc) { - CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); - if (!idleAssoc || idleAssoc->blendDelta <= 0.0f) { - animAssoc->flags |= ASSOC_DELETEFADEDOUT; - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); - } - } - } - if (!animAssoc) { - m_nStoredMoveState = m_nMoveState; - if (m_nMoveState == PEDMOVE_WALK || m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT) { - for (CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_PARTIAL); - assoc; assoc = RpAnimBlendGetNextAssociation(assoc, ASSOC_PARTIAL)) { - - if (!(assoc->flags & ASSOC_FADEOUTWHENDONE)) { - assoc->blendDelta = -2.0f; - assoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - - ClearAimFlag(); - ClearLookFlag(); - } - - switch (m_nMoveState) { - case PEDMOVE_STILL: - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + if (event != -1) { + if (victim) { + m_victimOfPlayerCrime = victim; + } else { + switch (gaEvent[event].entityType) { + case EVENT_ENTITY_PED: + m_victimOfPlayerCrime = CPools::GetPed(gaEvent[event].entityRef); break; - case PEDMOVE_WALK: - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_WALK, 1.0f); + case EVENT_ENTITY_VEHICLE: + m_victimOfPlayerCrime = CPools::GetVehicle(gaEvent[event].entityRef); break; - case PEDMOVE_RUN: - if (m_nPedState == PED_FLEE_ENTITY) { - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 3.0f); - } else { - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_RUN, 1.0f); - } - break; - case PEDMOVE_SPRINT: - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_SPRINT, 1.0f); + case EVENT_ENTITY_OBJECT: + m_victimOfPlayerCrime = CPools::GetObject(gaEvent[event].entityRef); break; default: break; - } - - if (animAssoc) { - if (m_leader) { - CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); - if (!walkAssoc) - walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); - - if (!walkAssoc) - walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_SPRINT); - - if (walkAssoc) { - animAssoc->speed = walkAssoc->speed; - } else { - if (CharCreatedBy == MISSION_CHAR) - animAssoc->speed = 1.0f; - else - animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; - - } - } else { - if (CharCreatedBy == MISSION_CHAR) - animAssoc->speed = 1.0f; - else - animAssoc->speed = 1.2f - m_randomSeed * 0.4f / MYRAND_MAX; } } } + + return event; } - -void -CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) -{ - float zDiff = 0.0f; - RemoveWeaponWhenEnteringVehicle(); - car->m_nGettingInFlags |= doorFlag; - bVehEnterDoorIsBlocked = false; - if (m_nPedState != PED_SEEK_CAR && m_nPedState != PED_SEEK_IN_BOAT) - SetStoredState(); - - m_pSeekTarget = car; - m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); - m_vehEnterType = doorNode; - m_nPedState = PED_ENTER_CAR; - if (m_vehEnterType == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { - car->bIsBeingCarJacked = true; - } - - m_pMyVehicle = (CVehicle*)m_pSeekTarget; - m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); - ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; - bUsesCollision = false; - CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); - - // Because buses have stairs - if (!m_pMyVehicle->bIsBus) - zDiff = Max(0.0f, doorOpenPos.z - GetPosition().z); - - m_vecOffsetSeek = doorOpenPos - GetPosition(); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; - if (car->IsBoat()) { -#ifdef VC_PED_PORTS - // VC checks for handling flag, but we can't do that - if(car->GetModelIndex() == MI_SPEEDER) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); - - PedSetInCarCB(nil, this); - bVehExitWillBeInstant = true; -#else - -#ifndef FIX_BUGS - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); -#else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, car->GetDriverAnim(), 100.0f); #endif - m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, this); +#ifdef PED_SKIN +static RpMaterial* +SetLimbAlphaCB(RpMaterial *material, void *data) +{ + ((RwRGBA*)RpMaterialGetColor(material))->alpha = *(uint8*)data; + return material; +} + +void +CPed::renderLimb(int node) +{ + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int idx = RpHAnimIDGetIndex(hier, m_pFrames[node]->nodeID); + RwMatrix *mat = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + CPedModelInfo *mi = (CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()); + RpAtomic *atomic; + switch(node){ + case PED_HEAD: + atomic = mi->getHead(); + break; + case PED_HANDL: + atomic = mi->getLeftHand(); + break; + case PED_HANDR: + atomic = mi->getRightHand(); + break; + default: + return; + } + if(atomic == nil) + return; + + RwFrame *frame = RpAtomicGetFrame(atomic); + *RwFrameGetMatrix(frame) = *mat; + RwFrameUpdateObjects(frame); + int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); + RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), SetLimbAlphaCB, &alpha); + RpAtomicRender(atomic); +} #endif - if (IsPlayer()) - CWaterLevel::AllocateBoatWakeArray(); - } else { - if (zDiff > 4.4f) { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); - - } else { - if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); - } - m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); - car->AutoPilot.m_nCruiseSpeed = 0; - } -} - -void -CPed::WanderPath(void) -{ - if (!m_pNextPathNode) { - printf("THIS SHOULDN@T HAPPEN TOO OFTEN\n"); - SetIdle(); - return; - } - if (m_nWaitState == WAITSTATE_FALSE) { - if (m_nMoveState == PEDMOVE_STILL || m_nMoveState == PEDMOVE_NONE) - SetMoveState(PEDMOVE_WALK); - } - m_vecSeekPos = m_pNextPathNode->GetPosition(); - m_vecSeekPos.z += 1.0f; - - // Only returns true when ped is stuck(not stopped) I think, then we should assign new direction or wait state to him. - if (!Seek()) - return; - - CPathNode *previousLastNode = m_pLastPathNode; - uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; - - // We don't prefer 180-degree turns in normal situations - uint8 dirWeWouldntPrefer = m_nPathDir; - if (dirWeWouldntPrefer <= 3) - dirWeWouldntPrefer += 4; - else - dirWeWouldntPrefer -= 4; - - CPathNode *nodeWeWouldntPrefer = nil; - uint8 dirToSet = 9; // means undefined - uint8 dirWeWouldntPrefer2 = 9; // means undefined - if (randVal <= 90) { - if (randVal > 80) { - m_nPathDir += 2; - m_nPathDir %= 8; - } - } else { - m_nPathDir -= 2; - if (m_nPathDir < 0) - m_nPathDir += 8; - } - - m_pLastPathNode = m_pNextPathNode; - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &dirToSet); - - uint8 tryCount = 0; - - // NB: SetWanderPath checks for m_nPathDir == dirToStartWith, this one checks for tryCount > 7 - while (!m_pNextPathNode) { - tryCount++; - m_nPathDir = (m_nPathDir + 1) % 8; - - // We're at where we started and couldn't find any node - if (tryCount > 7) { - if (!nodeWeWouldntPrefer) { - ClearAll(); - SetIdle(); - // Probably this text carried over here after copy-pasting this loop from early version of SetWanderPath. - Error("Can't find valid path node, SetWanderPath, Ped.cpp"); - return; - } - m_pNextPathNode = nodeWeWouldntPrefer; - dirToSet = dirWeWouldntPrefer2; - } else { - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &dirToSet); - if (m_pNextPathNode) { - if (dirToSet == dirWeWouldntPrefer) { - nodeWeWouldntPrefer = m_pNextPathNode; - dirWeWouldntPrefer2 = dirToSet; - m_pNextPathNode = nil; - } - } - } - } - - m_nPathDir = dirToSet; - if (m_pLastPathNode == m_pNextPathNode) { - m_pNextPathNode = previousLastNode; - SetWaitState(WAITSTATE_DOUBLEBACK, nil); - Say(SOUND_PED_WAIT_DOUBLEBACK); - } else if (ThePaths.TestForPedTrafficLight(m_pLastPathNode, m_pNextPathNode)) { - SetWaitState(WAITSTATE_TRAFFIC_LIGHTS, nil); - } else if (ThePaths.TestCrossesRoad(m_pLastPathNode, m_pNextPathNode)) { - SetWaitState(WAITSTATE_CROSS_ROAD, nil); - } else if (m_pNextPathNode == previousLastNode) { - SetWaitState(WAITSTATE_DOUBLEBACK, nil); - Say(SOUND_PED_WAIT_DOUBLEBACK); - } -} - -bool -CPed::WarpPedToNearEntityOffScreen(CEntity *warpTo) -{ - bool teleported = false; - if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) - return false; - - CVector warpToPos = warpTo->GetPosition(); - CVector distVec = warpToPos - GetPosition(); - float halfOfDist = distVec.Magnitude() * 0.5f; - CVector halfNormalizedDist = distVec / halfOfDist; - - CVector appropriatePos = GetPosition(); - CVector zCorrectedPos = appropriatePos; - int tryCount = Min(10, halfOfDist); - for (int i = 0; i < tryCount; ++i) { - appropriatePos += halfNormalizedDist; - CPedPlacement::FindZCoorForPed(&zCorrectedPos); - - if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) - continue; - - appropriatePos.z = zCorrectedPos.z; - if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) - && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) - && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { - teleported = true; - Teleport(appropriatePos); - } - } - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; - return teleported; -} - -bool -CPed::WarpPedToNearLeaderOffScreen(void) -{ - bool teleported = false; - if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) - return false; - - CVector warpToPos = m_leader->GetPosition(); - CVector distVec = warpToPos - GetPosition(); - float halfOfDist = distVec.Magnitude() * 0.5f; - CVector halfNormalizedDist = distVec / halfOfDist; - - CVector appropriatePos = GetPosition(); - CVector zCorrectedPos = appropriatePos; - int tryCount = Min(10, halfOfDist); - for (int i = 0; i < tryCount; ++i) { - appropriatePos += halfNormalizedDist; - CPedPlacement::FindZCoorForPed(&zCorrectedPos); - - if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) - continue; - - appropriatePos.z = zCorrectedPos.z; - if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) - && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) - && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { - teleported = true; - Teleport(appropriatePos); - } - } - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; - return teleported; -} - -void -CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) -{ - RemoveWeaponWhenEnteringVehicle(); - if (m_nPedState != PED_SEEK_CAR) - SetStoredState(); - - m_pSeekTarget = car; - m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); - m_nPedState = PED_CARJACK; - car->bIsBeingCarJacked = true; - m_pMyVehicle = (CVehicle*)m_pSeekTarget; - m_pMyVehicle->RegisterReference((CEntity**)&m_pMyVehicle); - ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; - - Say(m_nPedType == PEDTYPE_COP ? SOUND_PED_ARREST_COP : SOUND_PED_CAR_JACKING); - CVector carEnterPos; - carEnterPos = GetPositionToOpenCarDoor(car, m_vehEnterType); - - car->m_nGettingInFlags |= doorFlag; - m_vecOffsetSeek = carEnterPos - GetPosition(); - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; - float zDiff = Max(0.0f, carEnterPos.z - GetPosition().z); - bUsesCollision = false; - - if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_LHS : ANIM_CAR_ALIGN_LHS, 4.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_RHS : ANIM_CAR_ALIGN_RHS, 4.0f); - - m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); -} - -void -CPed::SetObjective(eObjective newObj, CVector dest, float safeDist) -{ - if (DyingOrDead()) - return; - - if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) - return; - - SetObjectiveTimer(0); - if (m_objective == newObj) { - if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { - if (m_nextRoutePointPos == dest && m_distanceToCountSeekDone == safeDist) - return; - } else if (newObj == OBJECTIVE_GUARD_SPOT) { - if (m_vecSeekPosEx == dest && m_distanceToCountSeekDoneEx == safeDist) - return; - } - } - -#ifdef VC_PED_PORTS - ClearPointGunAt(); -#endif - bObjectiveCompleted = false; - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); - - m_objective = newObj; - } - - if (newObj == OBJECTIVE_GUARD_SPOT) { - m_vecSeekPosEx = dest; - m_distanceToCountSeekDoneEx = safeDist; - } else if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { - m_pNextPathNode = nil; - m_nextRoutePointPos = dest; - m_vecSeekPos = m_nextRoutePointPos; - bUsePedNodeSeek = true; - } -} - -void -CPed::SetCarJack(CVehicle* car) -{ - uint8 doorFlag; - eDoors door; - CPed *pedInSeat = nil; - - if (car->IsBoat()) - return; - - switch (m_vehEnterType) { - case CAR_DOOR_RF: - doorFlag = CAR_DOOR_FLAG_RF; - door = DOOR_FRONT_RIGHT; - if (car->pPassengers[0]) { - pedInSeat = car->pPassengers[0]; - } else if (m_nPedType == PEDTYPE_COP) { - pedInSeat = car->pDriver; - } - break; - case CAR_DOOR_RR: - doorFlag = CAR_DOOR_FLAG_RR; - door = DOOR_REAR_RIGHT; - pedInSeat = car->pPassengers[2]; - break; - case CAR_DOOR_LF: - doorFlag = CAR_DOOR_FLAG_LF; - door = DOOR_FRONT_LEFT; - pedInSeat = car->pDriver; - break; - case CAR_DOOR_LR: - doorFlag = CAR_DOOR_FLAG_LR; - door = DOOR_REAR_LEFT; - pedInSeat = car->pPassengers[1]; - break; - default: - doorFlag = CAR_DOOR_FLAG_UNKNOWN; - break; - } - - if(car->bIsBus) - pedInSeat = car->pDriver; - - if (m_fHealth > 0.0f && (IsPlayer() || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || - (car->VehicleCreatedBy != MISSION_VEHICLE && car->GetModelIndex() != MI_DODO))) - if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) - if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) - if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) - if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) - SetCarJack_AllClear(car, m_vehEnterType, doorFlag); -} - -void -CPed::Solicit(void) -{ - if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { - CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); - SetMoveState(PEDMOVE_STILL); - - // Game uses GetAngleBetweenPoints and converts it to radian - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - doorPos.x, doorPos.y, - GetPosition().x, GetPosition().y); - - if (m_fRotationDest < 0.0f) { - m_fRotationDest = m_fRotationDest + TWOPI; - } else if (m_fRotationDest > TWOPI) { - m_fRotationDest = m_fRotationDest - TWOPI; - } - - if ((GetPosition() - doorPos).MagnitudeSqr() <= 1.0f) - return; - CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_HOOKERTALK); - if (talkAssoc) { - talkAssoc->blendDelta = -1000.0f; - talkAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - RestorePreviousState(); - RestorePreviousObjective(); - SetObjectiveTimer(10000); - } else if (!m_carInObjective) { - RestorePreviousState(); - RestorePreviousObjective(); - SetObjectiveTimer(10000); - } else if (CWorld::Players[CWorld::PlayerInFocus].m_nMoney <= 100) { - m_carInObjective = nil; - } else { - m_pVehicleAnim = nil; - SetLeader(m_carInObjective->pDriver); - } -} - -// Seperate function in VC, more logical. Not sure is it inlined in III. -void -CPed::SetExitBoat(CVehicle *boat) -{ -#ifndef VC_PED_PORTS - m_nPedState = PED_IDLE; - CVector firstPos = GetPosition(); - CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); - if (boat->GetModelIndex() == MI_SPEEDER && boat->IsUpsideDown()) { - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS, 8.0f); - m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); - m_vehEnterType = CAR_DOOR_RF; - m_nPedState = PED_EXIT_CAR; - } else { - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - m_pCurSurface = boat; - m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); - } - SetPosition(firstPos); - SetMoveState(PEDMOVE_STILL); - m_vecMoveSpeed = boat->m_vecMoveSpeed; - bTryingToReachDryLand = true; -#else - m_nPedState = PED_IDLE; - CVector newPos = GetPosition(); - RemoveInCarAnims(); - CColModel* boatCol = boat->GetColModel(); - if (boat->IsUpsideDown()) { - newPos = { 0.0f, 0.0f, boatCol->boundingBox.min.z }; - newPos = boat->GetMatrix() * newPos; - newPos.z += 1.0f; - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - m_pCurSurface = boat; - m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); - m_pCurrentPhysSurface = boat; - } else { -/* if (boat->m_modelIndex != MI_SKIMMER || boat->bIsInWater) { - if (boat->m_modelIndex == MI_SKIMMER) - newPos.z += 2.0f -*/ - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - m_pCurSurface = boat; - m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); - m_pCurrentPhysSurface = boat; - CColPoint foundCol; - CEntity *foundEnt = nil; - if (CWorld::ProcessVerticalLine(newPos, newPos.z - 1.4f, foundCol, foundEnt, false, true, false, false, false, false, nil)) - newPos.z = FEET_OFFSET + foundCol.point.z; -/* // VC specific - } else { - m_vehEnterType = CAR_DOOR_RF; - PedSetOutCarCB(nil, this); - bIsStanding = true; - SetMoveState(PEDMOVE_STILL); - bTryingToReachDryLand = true; - float upMult = 1.04f + boatCol->boundingBox.min.z; - float rightMult = 0.6f * boatCol->boundingBox.max.x; - newPos = upMult * boat->GetUp() + rightMult * boat->GetRight() + boat->GetPosition(); - GetPosition() = newPos; - if (m_pMyVehicle) { - PositionPedOutOfCollision(); - } else { - m_pMyVehicle = boat; - PositionPedOutOfCollision(); - m_pMyVehicle = nil; - } - return; - } -*/ } - SetPosition(newPos); - SetMoveState(PEDMOVE_STILL); - m_vecMoveSpeed = boat->m_vecMoveSpeed; -#endif - // Not there in VC. - CWaterLevel::FreeBoatWakeArray(); -} #ifdef COMPATIBLE_SAVES #define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); SkipSaveBuf(buf, sizeof(data)); diff --git a/src/peds/Ped.h b/src/peds/Ped.h index dbe61572..a3d4997d 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -5,7 +5,7 @@ #include "Crime.h" #include "EventList.h" #include "PedIK.h" -#include "PedStats.h" +#include "PedType.h" #include "Physical.h" #include "Weapon.h" #include "WeaponInfo.h" @@ -13,6 +13,7 @@ #define FEET_OFFSET 1.04f #define CHECK_NEARBY_THINGS_MAX_DIST 15.0f #define ENTER_CAR_MAX_DIST 30.0f +#define CAN_SEE_ENTITY_ANGLE_THRESHOLD DEGTORAD(60.0f) struct CPathNode; class CAccident; @@ -568,7 +569,7 @@ public: void CalculateNewOrientation(void); float WorkOutHeadingForMovingFirstPerson(float); void CalculateNewVelocity(void); - bool CanSeeEntity(CEntity*, float); + bool CanSeeEntity(CEntity*, float threshold = CAN_SEE_ENTITY_ANGLE_THRESHOLD); void RestorePreviousObjective(void); void SetIdle(void); #ifdef _MSC_VER @@ -747,7 +748,7 @@ public: static void PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg); - bool IsPlayer(void); + bool IsPlayer(void) const; bool UseGroundColModel(void); bool CanSetPedState(void); bool IsPedInControl(void); @@ -765,7 +766,7 @@ public: void SetStoredObjective(void); void SetLeader(CEntity* leader); void SetPedStats(ePedStats); - bool IsGangMember(void); + bool IsGangMember(void) const; void Die(void); void EnterTrain(void); void ExitTrain(void); @@ -788,7 +789,7 @@ public: CObject *SpawnFlyingComponent(int, int8); void SetCarJack_AllClear(CVehicle*, uint32, uint32); #ifdef VC_PED_PORTS - bool CanPedJumpThis(CEntity*, CVector*); + bool CanPedJumpThis(CEntity *unused, CVector *damageNormal = nil); #else bool CanPedJumpThis(CEntity*); #endif @@ -809,9 +810,40 @@ public: bool InVehicle(void) { return bInVehicle && m_pMyVehicle; } // True when ped is sitting/standing in vehicle, not in enter/exit state. bool EnteringCar(void) { return m_nPedState == PED_ENTER_CAR || m_nPedState == PED_CARJACK; } - void ReplaceWeaponWhenExitingVehicle(void); - void RemoveWeaponWhenEnteringVehicle(void); - bool IsNotInWreckedVehicle(); + // It was inlined in III but not in VC. + inline void + ReplaceWeaponWhenExitingVehicle(void) + { + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + + // If it's Uzi, we may have stored weapon. Uzi is the only gun we can use in car. + if (IsPlayer() && weaponType == WEAPONTYPE_UZI) { + if (/*IsPlayer() && */ m_storedWeapon != WEAPONTYPE_UNIDENTIFIED) { + SetCurrentWeapon(m_storedWeapon); + m_storedWeapon = WEAPONTYPE_UNIDENTIFIED; + } + } else { + AddWeaponModel(CWeaponInfo::GetWeaponInfo(weaponType)->m_nModelId); + } + } + + // It was inlined in III but not in VC. + inline void + RemoveWeaponWhenEnteringVehicle(void) + { + if (IsPlayer() && HasWeapon(WEAPONTYPE_UZI) && GetWeapon(WEAPONTYPE_UZI).m_nAmmoTotal > 0) { + if (m_storedWeapon == WEAPONTYPE_UNIDENTIFIED) + m_storedWeapon = GetWeapon()->m_eWeaponType; + SetCurrentWeapon(WEAPONTYPE_UZI); + } else { + CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(ourWeapon->m_nModelId); + } + } + bool IsNotInWreckedVehicle() + { + return m_pMyVehicle != nil && ((CEntity*)m_pMyVehicle)->GetStatus() != STATUS_WRECKED; + } // My additions, because there were many, many instances of that. inline void SetFindPathAndFlee(CEntity *fleeFrom, int time, bool walk = false) { diff --git a/src/peds/PedAI.cpp b/src/peds/PedAI.cpp new file mode 100644 index 00000000..38303473 --- /dev/null +++ b/src/peds/PedAI.cpp @@ -0,0 +1,5413 @@ +#include "common.h" + +#include "main.h" +#include "Particle.h" +#include "RpAnimBlend.h" +#include "Ped.h" +#include "Wanted.h" +#include "AnimBlendAssociation.h" +#include "DMAudio.h" +#include "General.h" +#include "HandlingMgr.h" +#include "Replay.h" +#include "Camera.h" +#include "PedPlacement.h" +#include "ZoneCull.h" +#include "Pad.h" +#include "Pickups.h" +#include "Train.h" +#include "PedRoutes.h" +#include "CopPed.h" +#include "Script.h" +#include "CarCtrl.h" +#include "WaterLevel.h" +#include "CarAI.h" +#include "Zones.h" +#include "Cranes.h" + +CVector vecPedCarDoorAnimOffset; +CVector vecPedCarDoorLoAnimOffset; +CVector vecPedVanRearDoorAnimOffset; +CVector vecPedQuickDraggedOutCarAnimOffset; +CVector vecPedDraggedOutCarAnimOffset; +CVector vecPedTrainDoorAnimOffset; + +void +CPed::SetObjectiveTimer(int time) +{ + if (time == 0) { + m_objectiveTimer = 0; + } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; + } +} + +void +CPed::SetStoredObjective(void) +{ + if (m_objective == m_prevObjective) + return; + + switch (m_objective) + { + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +void +CPed::ForceStoredObjective(eObjective objective) +{ + if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + m_prevObjective = m_objective; + return; + } + + switch (m_objective) + { + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + return; + default: + m_prevObjective = m_objective; + } +} + +bool +CPed::IsTemporaryObjective(eObjective objective) +{ + return objective == OBJECTIVE_LEAVE_CAR || objective == OBJECTIVE_SET_LEADER || +#ifdef VC_PED_PORTS + objective == OBJECTIVE_LEAVE_CAR_AND_DIE || +#endif + objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER; +} + +void +CPed::SetObjective(eObjective newObj) +{ + if (DyingOrDead()) + return; + + if (newObj == OBJECTIVE_NONE) { + if ((m_objective == OBJECTIVE_LEAVE_CAR || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER +#ifdef VC_PED_PORTS + || m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) + && !IsPlayer() +#else + ) +#endif + && !IsPedInControl()) { + + bStartWanderPathOnFoot = true; + return; + } + // Unused code from assembly... + /* + else if(m_objective == OBJECTIVE_FLEE_CAR) { + + } else { + + } + */ + m_objective = OBJECTIVE_NONE; + m_prevObjective = OBJECTIVE_NONE; + } else if (m_prevObjective != newObj || m_prevObjective == OBJECTIVE_NONE) { + SetObjectiveTimer(0); + + if (m_objective == newObj) + return; + + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + bObjectiveCompleted = false; + + switch (newObj) { + case OBJECTIVE_NONE: + m_prevObjective = OBJECTIVE_NONE; + break; + case OBJECTIVE_HAIL_TAXI: + m_nWaitTimer = 0; + SetIdle(); + SetMoveState(PEDMOVE_STILL); + break; + default: + break; + } + } +} + +void +CPed::SetObjective(eObjective newObj, void *entity) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective == newObj) { + // Why? + if (m_prevObjective != OBJECTIVE_NONE) + return; + } + + if (entity == this) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + switch (newObj) { + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GUARD_ATTACK: + if (m_pedInObjective == entity) + return; + + break; + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_FLEE_CAR: +#ifdef VC_PED_PORTS + case OBJECTIVE_LEAVE_CAR_AND_DIE: +#endif + return; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT_VEHICLE: + case OBJECTIVE_BUY_ICE_CREAM: + if (m_carInObjective == entity) + return; + + break; + case OBJECTIVE_SET_LEADER: + if (m_leader == entity) + return; + + break; + default: + break; + } + } else { + if ((newObj == OBJECTIVE_LEAVE_CAR +#ifdef VC_PED_PORTS + || newObj == OBJECTIVE_LEAVE_CAR_AND_DIE +#endif + ) && !bInVehicle) + return; + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective) && !IsTemporaryObjective(newObj)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) { + if (IsTemporaryObjective(newObj)) + ForceStoredObjective(newObj); + else + SetStoredObjective(); + } + m_objective = newObj; + } + + switch (newObj) { + case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: + + // In this special case, entity parameter isn't CEntity, but int. + SetObjectiveTimer((uintptr)entity); + break; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_MUG_CHAR: + m_pNextPathNode = nil; + bUsePedNodeSeek = false; + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + m_pLookTarget = (CEntity*)entity; + m_pLookTarget->RegisterReference((CEntity**)&m_pLookTarget); + break; + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_GUARD_ATTACK: + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + break; + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + m_pedInObjective = (CPed*)entity; + m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective); + m_pedFormation = FORMATION_REAR; + break; + case OBJECTIVE_LEAVE_CAR: +#ifdef VC_PED_PORTS + case OBJECTIVE_LEAVE_CAR_AND_DIE: +#endif + case OBJECTIVE_FLEE_CAR: + m_carInObjective = (CVehicle*)entity; + m_carInObjective->RegisterReference((CEntity **)&m_carInObjective); + if (m_carInObjective->bIsBus && m_leaveCarTimer == 0) { + for (int i = 0; i < m_carInObjective->m_nNumMaxPassengers; i++) { + if (m_carInObjective->pPassengers[i] == this) { + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i; + break; + } + } + } + + break; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_nMoveState == PEDMOVE_STILL) + SetMoveState(PEDMOVE_RUN); + + if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) { + RestorePreviousObjective(); + break; + } + // fall through + case OBJECTIVE_DESTROY_CAR: + case OBJECTIVE_SOLICIT_VEHICLE: + case OBJECTIVE_BUY_ICE_CREAM: + m_carInObjective = (CVehicle*)entity; + m_carInObjective->RegisterReference((CEntity**)&m_carInObjective); + m_pSeekTarget = m_carInObjective; + m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + if (newObj == OBJECTIVE_SOLICIT_VEHICLE) { + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; + } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == MISSION_CHAR && + (m_carInObjective->GetStatus() == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->ArePlayerControlsDisabled())) { + SetObjectiveTimer(14000); + } else { + m_objectiveTimer = 0; + } + break; + case OBJECTIVE_SET_LEADER: + SetLeader((CEntity*)entity); + RestorePreviousObjective(); + break; + default: + break; + } +} + +void +CPed::SetObjective(eObjective newObj, CVector dest, float safeDist) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest && m_distanceToCountSeekDone == safeDist) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest && m_distanceToCountSeekDoneEx == safeDist) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + + if (newObj == OBJECTIVE_GUARD_SPOT) { + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = safeDist; + } else if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + bUsePedNodeSeek = true; + } +} + +// Only used in 01E1: SET_CHAR_OBJ_FOLLOW_ROUTE opcode +// IDA fails very badly in here, puts a fake loop and ignores SetFollowRoute call... +void +CPed::SetObjective(eObjective newObj, int16 routePoint, int16 routeType) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective == newObj && m_prevObjective != OBJECTIVE_NONE) + return; + + SetObjectiveTimer(0); + + if (m_objective == newObj && newObj == OBJECTIVE_FOLLOW_ROUTE && m_routeLastPoint == routePoint && m_routeType == routeType) + return; + + bObjectiveCompleted = false; + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } + + if (newObj == OBJECTIVE_FOLLOW_ROUTE) { + SetFollowRoute(routePoint, routeType); + } +} + +void +CPed::SetObjective(eObjective newObj, CVector dest) +{ + if (DyingOrDead()) + return; + + if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) + return; + + SetObjectiveTimer(0); + if (m_objective == newObj) { + if (newObj == OBJECTIVE_GOTO_AREA_ANY_MEANS || newObj == OBJECTIVE_GOTO_AREA_ON_FOOT || newObj == OBJECTIVE_RUN_TO_AREA) { + if (m_nextRoutePointPos == dest) + return; + } else if (newObj == OBJECTIVE_GUARD_SPOT) { + if (m_vecSeekPosEx == dest) + return; + } + } + +#ifdef VC_PED_PORTS + ClearPointGunAt(); +#endif + bObjectiveCompleted = false; + switch (newObj) { + case OBJECTIVE_GUARD_SPOT: + m_vecSeekPosEx = dest; + m_distanceToCountSeekDoneEx = 5.0f; + SetMoveState(PEDMOVE_STILL); + break; + case OBJECTIVE_GUARD_AREA: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + case OBJECTIVE_LEAVE_CAR: + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: + case OBJECTIVE_DESTROY_OBJECT: + case OBJECTIVE_DESTROY_CAR: + break; + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + case OBJECTIVE_GOTO_AREA_ON_FOOT: + bIsRunning = false; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + case OBJECTIVE_RUN_TO_AREA: + bIsRunning = true; + m_pNextPathNode = nil; + m_nextRoutePointPos = dest; + m_vecSeekPos = m_nextRoutePointPos; + m_distanceToCountSeekDone = 0.5f; + bUsePedNodeSeek = true; + if (sq(m_distanceToCountSeekDone) > (m_nextRoutePointPos - GetPosition()).MagnitudeSqr2D()) + return; + break; + default: break; + } + + if (IsTemporaryObjective(m_objective)) { + m_prevObjective = newObj; + } else { + if (m_objective != newObj) + SetStoredObjective(); + + m_objective = newObj; + } +} + +void +CPed::ClearObjective(void) +{ + if (IsPedInControl() || m_nPedState == PED_DRIVING) { + m_objective = OBJECTIVE_NONE; +#ifdef VC_PED_PORTS + m_pedInObjective = nil; + m_carInObjective = nil; +#endif + if (m_nPedState == PED_DRIVING && m_pMyVehicle) { + + if (m_pMyVehicle->pDriver != this) { +#if defined VC_PED_PORTS || defined FIX_BUGS + if(!IsPlayer()) +#endif + bWanderPathAfterExitingCar = true; + + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } +#ifdef VC_PED_PORTS + m_nLastPedState = PED_NONE; +#endif + } else { + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + } else { + bClearObjective = true; + } +} + +void +CPed::ClearLeader(void) +{ + if (!m_leader) + return; + + m_leader = nil; + if (IsPedInControl()) { + SetObjective(OBJECTIVE_NONE); + if (CharCreatedBy == MISSION_CHAR) { + SetIdle(); + } else { + SetWanderPath(CGeneral::GetRandomNumberInRange(0,8)); + } + } else if (m_objective != OBJECTIVE_NONE) { + bClearObjective = true; + } +} + +void +CPed::UpdateFromLeader(void) +{ + if (CTimer::GetTimeInMilliseconds() <= m_objectiveTimer) + return; + + if (!m_leader) + return; + + CVector leaderDist; + if (m_leader->InVehicle()) + leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); + else + leaderDist = m_leader->GetPosition() - GetPosition(); + + if (leaderDist.Magnitude() > 30.0f) { + if (IsPedInControl()) { + SetObjective(OBJECTIVE_NONE); + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + SetLeader(nil); + return; + } + + if (IsPedInControl()) { + if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) + WarpPedToNearLeaderOffScreen(); + + if (m_leader->m_nPedState == PED_DEAD) { + SetLeader(nil); + SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + return; + } + if (!m_leader->bInVehicle) { + if (m_leader->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (bInVehicle) { + if (m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT && m_objective != OBJECTIVE_LEAVE_CAR) + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + + return; + } + if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + RestorePreviousObjective(); + RestorePreviousState(); + } + } + if (m_nPedType == PEDTYPE_PROSTITUTE && CharCreatedBy == RANDOM_CHAR) { + SetLeader(nil); + return; + } + } + if (!bInVehicle && m_leader->bInVehicle && m_leader->m_nPedState == PED_DRIVING) { + if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (m_leader->m_pMyVehicle->m_nNumPassengers < m_leader->m_pMyVehicle->m_nNumMaxPassengers) + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_pMyVehicle); + } + } else if (m_leader->m_objective == OBJECTIVE_NONE || (m_leader->IsPlayer() && m_leader->m_objective == OBJECTIVE_WAIT_ON_FOOT) + || m_objective == m_leader->m_objective) { + + if (m_leader->m_nPedState == PED_ATTACK) { + CEntity *lookTargetOfLeader = m_leader->m_pLookTarget; + if (lookTargetOfLeader && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT + && lookTargetOfLeader->IsPed() && lookTargetOfLeader != this) { + + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, lookTargetOfLeader); + SetObjectiveTimer(8000); + SetLookFlag(m_leader->m_pLookTarget, false); + SetLookTimer(500); + } + } else { + if (IsPedInControl() && m_nPedState != PED_ATTACK) { +#ifndef VC_PED_PORTS + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); +#else + if (m_leader->m_objective == OBJECTIVE_NONE && m_objective == OBJECTIVE_NONE + && m_leader->m_nPedState == PED_CHAT && m_nPedState == PED_CHAT) { + + SetObjective(OBJECTIVE_NONE); + } else { + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); + } +#endif + } + if (m_nPedState == PED_IDLE && m_leader->IsPlayer()) { + if (ScanForThreats() && m_threatEntity) { + m_pLookTarget = m_threatEntity; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && !GetWeapon()->IsTypeMelee()) { + m_pPointGunAt = m_threatEntity; + if (m_threatEntity) + m_threatEntity->RegisterReference((CEntity **) &m_pPointGunAt); + SetAttack(m_threatEntity); + } + } + } + } + } else { + switch (m_leader->m_objective) { + case OBJECTIVE_WAIT_ON_FOOT: + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + case OBJECTIVE_WAIT_IN_CAR: + case OBJECTIVE_FOLLOW_ROUTE: + SetObjective(m_leader->m_objective); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_GUARD_SPOT: + SetObjective(OBJECTIVE_GUARD_SPOT, m_leader->m_vecSeekPosEx); + m_objectiveTimer = m_leader->m_objectiveTimer; + break; + case OBJECTIVE_KILL_CHAR_ON_FOOT: + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + if (m_leader->m_pedInObjective) { + SetObjective(m_leader->m_objective, m_leader->m_pedInObjective); + m_objectiveTimer = m_leader->m_objectiveTimer; + } + break; + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_leader->m_carInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_leader->m_carInObjective); + return; + } + break; + case OBJECTIVE_GUARD_ATTACK: + return; + case OBJECTIVE_HAIL_TAXI: + m_leader = nil; + SetObjective(OBJECTIVE_NONE); + break; + default: + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); + break; + } + } + } else if (bInVehicle) { + if ((!m_leader->bInVehicle || m_leader->m_nPedState == PED_EXIT_CAR) && m_objective != OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { + + switch (m_leader->m_objective) { + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + if (m_pMyVehicle == m_leader->m_pMyVehicle || m_pMyVehicle == m_leader->m_carInObjective) + break; + + // fall through + default: + if (m_pMyVehicle && m_objective != OBJECTIVE_LEAVE_CAR) { +#ifdef VC_PED_PORTS + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 250; +#endif + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } + + break; + } + } + } +} + +void +CPed::RestorePreviousObjective(void) +{ + if (m_objective == OBJECTIVE_NONE) + return; + + if (m_objective != OBJECTIVE_LEAVE_CAR && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER +#if defined VC_PED_PORTS || defined FIX_BUGS + && m_nPedState != PED_CARJACK +#endif + ) + m_pedInObjective = nil; + + if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { + m_objective = OBJECTIVE_NONE; + if (m_pMyVehicle) + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + + } else { + m_objective = m_prevObjective; + m_prevObjective = OBJECTIVE_NONE; + } + bObjectiveCompleted = false; +} + +void +CPed::ProcessObjective(void) +{ + if (bClearObjective && (IsPedInControl() || m_nPedState == PED_DRIVING)) { + ClearObjective(); + bClearObjective = false; + } + UpdateFromLeader(); + + CVector carOrOurPos; + CVector targetCarOrHisPos; + CVector distWithTarget; + + if (m_objective != OBJECTIVE_NONE && (IsPedInControl() || m_nPedState == PED_DRIVING)) { + if (bInVehicle) { + if (!m_pMyVehicle) { + bInVehicle = false; + return; + } + carOrOurPos = m_pMyVehicle->GetPosition(); + } else { + carOrOurPos = GetPosition(); + } + + if (m_pedInObjective) { + if (m_pedInObjective->InVehicle() && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { + targetCarOrHisPos = m_pedInObjective->m_pMyVehicle->GetPosition(); + } else { + targetCarOrHisPos = m_pedInObjective->GetPosition(); + } + distWithTarget = targetCarOrHisPos - carOrOurPos; + } else if (m_carInObjective) { + targetCarOrHisPos = m_carInObjective->GetPosition(); + distWithTarget = targetCarOrHisPos - carOrOurPos; + } + + switch (m_objective) { + case OBJECTIVE_NONE: + case OBJECTIVE_GUARD_AREA: + case OBJECTIVE_FOLLOW_CAR_IN_CAR: + case OBJECTIVE_FIRE_AT_OBJECT_FROM_VEHICLE: + case OBJECTIVE_DESTROY_OBJECT: + case OBJECTIVE_GOTO_AREA_IN_CAR: + case OBJECTIVE_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: + case OBJECTIVE_SET_LEADER: + break; + case OBJECTIVE_WAIT_ON_FOOT: + SetIdle(); + m_objective = OBJECTIVE_NONE; + SetMoveState(PEDMOVE_STILL); + break; + case OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE: + if (InVehicle()) { + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + bFleeAfterExitingCar = true; + } else if (m_nPedState != PED_FLEE_POS) { + CVector2D fleePos = GetPosition(); + SetFlee(fleePos, 10000); + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + } + break; + case OBJECTIVE_GUARD_SPOT: + { + distWithTarget = m_vecSeekPosEx - GetPosition(); + if (m_pedInObjective) { + SetLookFlag(m_pedInObjective, true); + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + } + float distWithTargetSc = distWithTarget.Magnitude(); + if (2.0f * m_distanceToCountSeekDoneEx >= distWithTargetSc) { + if (m_pedInObjective) { + if (distWithTargetSc <= m_distanceToCountSeekDoneEx) + SetIdle(); + else + SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); + } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + int threatType = ScanForThreats(); + SetLookTimer(CGeneral::GetRandomNumberInRange(500, 1500)); + + // Second condition is pointless and isn't there in Mobile. + if (threatType == PED_FLAG_GUN || (threatType == PED_FLAG_EXPLOSION && m_threatEntity) || m_threatEntity) { + if (m_threatEntity->IsPed()) + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_threatEntity); + } + } + } else { + SetSeek(m_vecSeekPosEx, m_distanceToCountSeekDoneEx); + } + break; + } + case OBJECTIVE_WAIT_IN_CAR: + m_nPedState = PED_DRIVING; + break; + case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: + m_nPedState = PED_DRIVING; + break; + case OBJECTIVE_KILL_CHAR_ANY_MEANS: + { + if (m_pedInObjective) { + if (m_pedInObjective->IsPlayer() && CharCreatedBy != MISSION_CHAR + && m_nPedType != PEDTYPE_COP && FindPlayerPed()->m_pWanted->m_CurrentCops != 0 + && !bKindaStayInSamePlace) { + + SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + break; + } + if (InVehicle()) { + if (distWithTarget.Magnitude() >= 20.0f + || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr() >= sq(0.02f)) { + if (m_pMyVehicle->pDriver == this + && !m_pMyVehicle->m_nGettingInFlags) { + m_pMyVehicle->SetStatus(STATUS_PHYSICS); + m_pMyVehicle->AutoPilot.m_nPrevRouteNode = 0; + if (m_nPedType == PEDTYPE_COP) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = (FindPlayerPed()->m_pWanted->m_nWantedLevel * 0.1f + 0.6f) * (GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity); + m_pMyVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); + } else { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; + } + m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + } + } else { + bool targetHasVeh = m_pedInObjective->bInVehicle; + if (!targetHasVeh + || targetHasVeh && m_pedInObjective->m_pMyVehicle->CanPedExitCar()) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } + } + break; + } + if (distWithTarget.Magnitude() > 30.0f && !bKindaStayInSamePlace) { + if (m_pMyVehicle) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } else { + float closestVehDist = 60.0f; + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + CVehicle *foundVeh = nil; + for(int i = 0; i < lastVehicle; i++) { + CVehicle *nearVeh = (CVehicle*)vehicles[i]; + /* + Not used. + CVector vehSpeed = nearVeh->GetSpeed(); + CVector ourSpeed = GetSpeed(); + */ + CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); + if (vehDistVec.Magnitude() < closestVehDist && m_pedInObjective->m_pMyVehicle != nearVeh + && nearVeh->CanPedOpenLocks(this)) { + + foundVeh = nearVeh; + closestVehDist = vehDistVec.Magnitude(); + } + } + m_pMyVehicle = foundVeh; + if (m_pMyVehicle) { + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } else if (!GetIsOnScreen()) { + CVector ourPos = GetPosition(); + int closestNode = ThePaths.FindNodeClosestToCoors(ourPos, PATH_CAR, 20.0f); + if (closestNode >= 0) { + int16 colliding; + CWorld::FindObjectsKindaColliding( + ThePaths.m_pathNodes[closestNode].GetPosition(), 10.0f, true, &colliding, 2, nil, false, true, true, false, false); + if (!colliding) { + CZoneInfo zoneInfo; + int chosenCarClass; + CTheZones::GetZoneInfoForTimeOfDay(&ourPos, &zoneInfo); + int chosenModel = CCarCtrl::ChooseModel(&zoneInfo, &ourPos, &chosenCarClass); + CAutomobile *newVeh = new CAutomobile(chosenModel, RANDOM_VEHICLE); + if (newVeh) { + newVeh->GetMatrix().GetPosition() = ThePaths.m_pathNodes[closestNode].GetPosition(); + newVeh->GetMatrix().GetPosition().z += 4.0f; + newVeh->SetHeading(DEGTORAD(200.0f)); + newVeh->SetStatus(STATUS_ABANDONED); + newVeh->m_nDoorLock = CARLOCK_UNLOCKED; + CWorld::Add(newVeh); + m_pMyVehicle = newVeh; + if (m_pMyVehicle) { + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } + } + } + } + } + break; + } + } else { + ClearLookFlag(); + bObjectiveCompleted = true; + } + } + case OBJECTIVE_KILL_CHAR_ON_FOOT: + { + bool killPlayerInNoPoliceZone = false; + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && InVehicle()) { + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + break; + } + if (!m_pedInObjective || m_pedInObjective->DyingOrDead()) { + ClearLookFlag(); + bObjectiveCompleted = true; + SetMoveAnim(); + break; + } + if (m_pedInObjective->IsPlayer() && CCullZones::NoPolice()) + killPlayerInNoPoliceZone = true; + + if (!bNotAllowedToDuck || killPlayerInNoPoliceZone) { + if (m_nPedType == PEDTYPE_COP && !m_pedInObjective->GetWeapon()->IsTypeMelee() && !GetWeapon()->IsTypeMelee()) + bNotAllowedToDuck = true; + } else { + if (!m_pedInObjective->bInVehicle) { + if (m_pedInObjective->GetWeapon()->IsTypeMelee() || GetWeapon()->IsTypeMelee()) { + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + } else if (DuckAndCover()) { + break; + } + } else { + bNotAllowedToDuck = false; + bCrouchWhenShooting = false; + } + } + if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds() && !bKindaStayInSamePlace) { + SetMoveState(PEDMOVE_STILL); + break; + } + if (m_pedInObjective->IsPlayer()) { + CPlayerPed *player = FindPlayerPed(); + if (m_nPedType == PEDTYPE_COP && player->m_pWanted->m_bIgnoredByCops + || player->m_pWanted->m_bIgnoredByEveryone + || m_pedInObjective->bIsInWater + || m_pedInObjective->m_nPedState == PED_ARRESTED) { + + if (m_nPedState != PED_ARREST_PLAYER) + SetIdle(); + + break; + } + } + CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + float wepRange = wepInfo->m_fRange; + float wepRangeAdjusted; + if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { + wepRangeAdjusted = wepRange / 3.0f; + } else { + if (m_nPedState == PED_FIGHT) { + if (!IsPlayer() && !(m_pedStats->m_flags & STAT_CAN_KICK)) + wepRange = 2.0f; + } else { + wepRange = 1.3f; + } + wepRangeAdjusted = wepRange; + } + if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() && wepRangeAdjusted < 2.5f) { + wepRangeAdjusted = 2.5f; + } + if (m_pedInObjective->IsPlayer() && m_nPedType != PEDTYPE_COP + && CharCreatedBy != MISSION_CHAR && FindPlayerPed()->m_pWanted->m_CurrentCops) { + SetObjective(OBJECTIVE_FLEE_ON_FOOT_TILL_SAFE); + break; + } + if (m_pedInObjective->m_fHealth <= 0.0f) { + bObjectiveCompleted = true; + bScriptObjectiveCompleted = true; + SetMoveAnim(); + break; + } + float distWithTargetSc = distWithTarget.Magnitude(); + if (m_pedInObjective->bInVehicle && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { + CVehicle *vehOfTarget = m_pedInObjective->m_pMyVehicle; + if (vehOfTarget->bIsInWater || vehOfTarget->GetStatus() == STATUS_PLAYER_DISABLED + || m_pedInObjective->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled()) { + SetIdle(); + return; + } + SetLookFlag(vehOfTarget, false); + if (m_nPedState != PED_CARJACK) { + if (m_pedInObjective->m_nPedState != PED_ARRESTED) { + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE + && distWithTargetSc < wepRange && distWithTargetSc > 3.0f) { + + // I hope so + CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); + CVector maxShotPos = vehOfTarget->GetPosition() - ourHead; + maxShotPos.Normalise(); + maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; + + CWorld::bIncludeDeadPeds = true; + CColPoint foundCol; + CEntity *foundEnt; + CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, + true, true, true, true, false, true, false); + CWorld::bIncludeDeadPeds = false; + if (foundEnt == vehOfTarget) { + SetAttack(vehOfTarget); + m_pPointGunAt = vehOfTarget; + if (vehOfTarget) + vehOfTarget->RegisterReference((CEntity **) &m_pPointGunAt); + + SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); + if (distWithTargetSc <= m_distanceToCountSeekDone) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(200, 500)); + SetMoveState(PEDMOVE_STILL); + } else { + SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); + } + } + } + else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace && !killPlayerInNoPoliceZone) { + if (vehOfTarget) { + if (m_nPedType == PEDTYPE_COP || vehOfTarget->bIsBus) { + GoToNearestDoor(vehOfTarget); + } else { + m_vehEnterType = 0; + if (m_pedInObjective == vehOfTarget->pDriver || vehOfTarget->bIsBus) { + m_vehEnterType = CAR_DOOR_LF; + } else if (m_pedInObjective == vehOfTarget->pPassengers[0]) { + m_vehEnterType = CAR_DOOR_RF; + } else if (m_pedInObjective == vehOfTarget->pPassengers[1]) { + m_vehEnterType = CAR_DOOR_LR; + } else if (m_pedInObjective == vehOfTarget->pPassengers[2]) { + m_vehEnterType = CAR_DOOR_RR; + } + // Unused + // GetPositionToOpenCarDoor(vehOfTarget, m_vehEnterType); + SetSeekCar(vehOfTarget, m_vehEnterType); + SetMoveState(PEDMOVE_RUN); + } + } + } + } + } + SetMoveAnim(); + break; + } + if (m_nMoveState == PEDMOVE_STILL && IsPedInControl()) { + SetLookFlag(m_pedInObjective, false); + TurnBody(); + } + if (m_nPedType == PEDTYPE_COP && distWithTargetSc < 1.5f && m_pedInObjective->IsPlayer()) { + if (m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() + || m_pedInObjective->m_nPedState == PED_DRAG_FROM_CAR) { + + ((CCopPed*)this)->SetArrestPlayer(m_pedInObjective); + return; + } + } + if (!bKindaStayInSamePlace && !bStopAndShoot && m_nPedState != PED_ATTACK && !killPlayerInNoPoliceZone) { + if (distWithTargetSc > wepRange + || m_pedInObjective->m_getUpTimer > CTimer::GetTimeInMilliseconds() + || m_pedInObjective->m_nPedState == PED_ARRESTED + || m_pedInObjective->EnteringCar() && distWithTargetSc < 3.0f + || distWithTargetSc > m_distanceToCountSeekDone && !CanSeeEntity(m_pedInObjective)) { + + if (m_pedInObjective->EnteringCar()) + wepRangeAdjusted = 2.0f; + + if (bUsePedNodeSeek) { + CVector bestCoords(0.0f, 0.0f, 0.0f); + m_vecSeekPos = m_pedInObjective->GetPosition(); + + if (!m_pNextPathNode) + FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); + + if (m_pNextPathNode) + m_vecSeekPos = m_pNextPathNode->GetPosition(); + + SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); + } else { + SetSeek(m_pedInObjective, wepRangeAdjusted); + } + bCrouchWhenShooting = false; + if (m_pedInObjective->m_pCurrentPhysSurface && distWithTargetSc < 5.0f) { + if (wepRange <= 5.0f) { + if (m_pedInObjective->IsPlayer() + && FindPlayerPed()->m_bSpeedTimerFlag + && (IsGangMember() || m_nPedType == PEDTYPE_COP) + && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { + GiveWeapon(WEAPONTYPE_COLT45, 1000); + SetCurrentWeapon(WEAPONTYPE_COLT45); + } + } else { + bStopAndShoot = true; + } + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + break; + } + bStopAndShoot = false; + SetMoveAnim(); + break; + } + } + if (m_attackTimer < CTimer::GetTimeInMilliseconds() + && distWithTargetSc < wepRange && m_pedInObjective->m_nPedState != PED_GETUP && m_pedInObjective->m_nPedState != PED_DRAG_FROM_CAR) { + if (bIsDucking) { + CAnimBlendAssociation *duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (duckAnim) { + duckAnim->blendDelta = -2.0f; + break; + } + bIsDucking = false; + } else if (wepRange <= 5.0f) { + SetMoveState(PEDMOVE_STILL); + SetAttack(m_pedInObjective); + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, + GetPosition().x, GetPosition().y); + SetShootTimer(CGeneral::GetRandomNumberInRange(0.0f, 500.0f)); + SetAttackTimer(CGeneral::GetRandomNumberInRange(0.0f, 1500.0f)); + bObstacleShowedUpDuringKillObjective = false; + + } else { + CVector target; + CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); + if (m_pedInObjective->IsPed()) + m_pedInObjective->m_pedIK.GetComponentPosition((RwV3d*)&target, PED_MID); + else + target = m_pedInObjective->GetPosition(); + + target -= ourHead; + target.Normalise(); + target = target * wepInfo->m_fRange + ourHead; + + CWorld::bIncludeDeadPeds = true; + CEntity *foundEnt = nil; + CColPoint foundCol; + + CWorld::ProcessLineOfSight( + ourHead, target, foundCol, foundEnt, + true, true, true, false, true, false); + CWorld::bIncludeDeadPeds = 0; + if (foundEnt == m_pedInObjective) { + SetAttack(m_pedInObjective); + m_pPointGunAt = m_pedInObjective; + if (m_pedInObjective) + m_pedInObjective->RegisterReference((CEntity **) &m_pPointGunAt); + + SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 2000.0f)); + + int time; + if (distWithTargetSc <= wepRangeAdjusted) + time = CGeneral::GetRandomNumberInRange(100.0f, 500.0f); + else + time = CGeneral::GetRandomNumberInRange(1500.0f, 3000.0f); + + SetAttackTimer(time); + bObstacleShowedUpDuringKillObjective = false; + + } else if (foundEnt) { + if (foundEnt->IsPed()) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(500.0f, 1000.0f)); + bObstacleShowedUpDuringKillObjective = false; + } else { + if (foundEnt->IsObject()) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(200.0f, 400.0f)); + bObstacleShowedUpDuringKillObjective = true; + } else if (foundEnt->IsVehicle()) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(400.0f, 600.0f)); + bObstacleShowedUpDuringKillObjective = true; + } else { + SetAttackTimer(CGeneral::GetRandomNumberInRange(700.0f, 1200.0f)); + bObstacleShowedUpDuringKillObjective = true; + } + } + + m_fleeFrom = foundEnt; + m_fleeFrom->RegisterReference((CEntity**) &m_fleeFrom); + SetPointGunAt(m_pedInObjective); + } + } + } else { + if (!m_pedInObjective->m_pCurrentPhysSurface) + bStopAndShoot = false; + + if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT) { + + // This is weird... + if (bNotAllowedToDuck && bKindaStayInSamePlace) { + if (!bIsDucking) { + CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!duckAnim || duckAnim->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); + bIsDucking = true; + } + break; + } else { + CAnimBlendAssociation* duckAnim = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!duckAnim || duckAnim->blendDelta < 0.0f) { + bIsDucking = false; + } else { + break; + } + } + } + if (bObstacleShowedUpDuringKillObjective) { + if (m_nPedType == PEDTYPE_COP) { + if (GetWeapon()->m_eWeaponType > WEAPONTYPE_COLT45 + || m_fleeFrom && m_fleeFrom->IsObject()) { + wepRangeAdjusted = 6.0f; + } else if (m_fleeFrom && m_fleeFrom->IsVehicle()) { + wepRangeAdjusted = 4.0f; + } else { + wepRangeAdjusted = 2.0f; + } + } else { + wepRangeAdjusted = 2.0f; + } + } + if (distWithTargetSc <= wepRangeAdjusted) { + SetMoveState(PEDMOVE_STILL); + bIsPointingGunAt = true; + if (m_nPedState != PED_AIM_GUN && !bDuckAndCover) { + m_attackTimer = CTimer::GetTimeInMilliseconds(); + SetIdle(); + } + } else { + if (m_nPedState != PED_SEEK_ENTITY && m_nPedState != PED_SEEK_POS + && !bStopAndShoot && !killPlayerInNoPoliceZone && !bKindaStayInSamePlace) { + Say(SOUND_PED_ATTACK); + SetSeek(m_pedInObjective, wepRangeAdjusted); + bIsRunning = true; + } + } + } + } + + if (distWithTargetSc < 2.5f && wepRange > 5.0f + && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE) { + + SetAttack(m_pedInObjective); + if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { + int time = CGeneral::GetRandomNumberInRange(500.0f, 1000.0f); + SetAttackTimer(time); + SetShootTimer(time - 500); + } + SetMoveState(PEDMOVE_STILL); + } + if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, GetPosition().x, GetPosition().y); + + SetMoveAnim(); + break; + } + case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS: + { + if (InVehicle()) { + if (m_nPedState == PED_DRIVING) + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } else if (m_nPedState != PED_FLEE_ENTITY) { + int time; + if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) + time = 0; + else + time = 6000; + + SetFindPathAndFlee(m_pedInObjective, time); + } + break; + } + case OBJECTIVE_GOTO_CHAR_ON_FOOT: + { + if (m_pedInObjective) { + float safeDistance = 2.0f; + if (m_pedInObjective->bInVehicle) + safeDistance = 3.0f; + + float distWithTargetSc = distWithTarget.Magnitude(); + if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) { + if (distWithTargetSc <= safeDistance) { + bScriptObjectiveCompleted = true; + if (m_nPedState != PED_ATTACK) { + SetIdle(); + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + } + if (distWithTargetSc > 2.0f) + SetMoveState(m_pedInObjective->m_nMoveState); + else + SetMoveState(PEDMOVE_STILL); + } else { + SetSeek(m_pedInObjective, safeDistance); + if (distWithTargetSc >= 5.0f) { + if (m_leader && m_leader->m_nMoveState == PEDMOVE_SPRINT) + SetMoveState(PEDMOVE_SPRINT); + else + SetMoveState(PEDMOVE_RUN); + } else { + if (m_leader && m_leader->m_nMoveState != PEDMOVE_STILL + && m_leader->m_nMoveState != PEDMOVE_NONE) { + if (m_leader->IsPlayer()) { + if (distWithTargetSc >= 3.0f && FindPlayerPed()->m_fMoveSpeed >= 1.3f) + SetMoveState(PEDMOVE_RUN); + else + SetMoveState(PEDMOVE_WALK); + } else { + SetMoveState(m_leader->m_nMoveState); + } + } else if (distWithTargetSc <= 3.0f) { + SetMoveState(PEDMOVE_WALK); + } else { + SetMoveState(PEDMOVE_RUN); + } + } + } + } + } else { + SetObjective(OBJECTIVE_NONE); + } + break; + } + case OBJECTIVE_FOLLOW_CHAR_IN_FORMATION: + { + if (m_pedInObjective) { + CVector posToGo = GetFormationPosition(); + distWithTarget = posToGo - carOrOurPos; + SetSeek(posToGo, 1.0f); + if (distWithTarget.Magnitude() <= 3.0f) { + SetSeek(posToGo, 1.0f); + if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL) + SetMoveState(m_pedInObjective->m_nMoveState); + } else { + SetSeek(posToGo, 1.0f); + SetMoveState(PEDMOVE_RUN); + } + } else { + SetObjective(OBJECTIVE_NONE); + } + break; + } + case OBJECTIVE_ENTER_CAR_AS_PASSENGER: + { + if (m_carInObjective) { + if (!bInVehicle && m_carInObjective->m_nNumPassengers >= m_carInObjective->m_nNumMaxPassengers) { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + + break; + } + + if (m_prevObjective == OBJECTIVE_HAIL_TAXI && !((CAutomobile*)m_carInObjective)->bTaxiLight) { + RestorePreviousObjective(); + ClearObjective(); + SetWanderPath(CGeneral::GetRandomNumber() & 7); + bIsRunning = false; + break; + } + if (m_objectiveTimer && m_objectiveTimer < CTimer::GetTimeInMilliseconds()) { + if (!EnteringCar()) { + bool foundSeat = false; + if (m_carInObjective->pPassengers[0] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { + if (m_carInObjective->pPassengers[1] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { + if (m_carInObjective->pPassengers[2] || m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { + foundSeat = false; + } else { + m_vehEnterType = CAR_DOOR_RR; + foundSeat = true; + } + } else { + m_vehEnterType = CAR_DOOR_LR; + foundSeat = true; + } + } else { + m_vehEnterType = CAR_DOOR_RF; + foundSeat = true; + } + for (int i = 2; i < m_carInObjective->m_nNumMaxPassengers; ++i) { + if (!m_carInObjective->pPassengers[i] && !(m_carInObjective->m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { + m_vehEnterType = CAR_DOOR_RF; + foundSeat = true; + } + } + if (foundSeat) { + SetPosition(GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType)); + SetEnterCar(m_carInObjective, m_vehEnterType); + } + } + m_objectiveTimer = 0; + } + } + // fall through + } + case OBJECTIVE_ENTER_CAR_AS_DRIVER: + { + if (!m_carInObjective || bInVehicle) { +#ifdef VC_PED_PORTS + if (bInVehicle && m_pMyVehicle != m_carInObjective) { + SetExitCar(m_pMyVehicle, 0); + } else +#endif + { + bObjectiveCompleted = true; + bScriptObjectiveCompleted = true; + RestorePreviousState(); + } + } else { + if (m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) { + SetMoveState(PEDMOVE_STILL); + break; + } + if (IsPedInControl()) { + if (m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (distWithTarget.Magnitude() < 20.0f) { + RestorePreviousObjective(); + RestorePreviousState(); + return; + } + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (m_carInObjective->pDriver +#ifdef VC_PED_PORTS + && !IsPlayer() +#endif + ) { + if (m_carInObjective->pDriver->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS && m_carInObjective->pDriver != m_pedInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); + m_carInObjective->bIsBeingCarJacked = false; + } + } + } + } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + if (m_carInObjective->pDriver +#ifdef VC_PED_PORTS + && (CharCreatedBy != MISSION_CHAR || m_carInObjective->pDriver->CharCreatedBy != RANDOM_CHAR) +#endif + ) { + if (m_carInObjective->pDriver->m_nPedType == m_nPedType) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); + m_carInObjective->bIsBeingCarJacked = false; + } + } + } + if (m_carInObjective->IsUpsideDown() && m_carInObjective->m_vehType != VEHICLE_TYPE_BIKE) { + RestorePreviousObjective(); + RestorePreviousState(); + return; + } + if (!m_carInObjective->IsBoat() || m_nPedState == PED_SEEK_IN_BOAT) { + if (m_nPedState != PED_SEEK_CAR) + SetSeekCar(m_carInObjective, 0); + } else { + SetSeekBoatPosition(m_carInObjective); + } + if (m_nMoveState == PEDMOVE_STILL && !bVehEnterDoorIsBlocked) + SetMoveState(PEDMOVE_RUN); + + if (m_carInObjective && m_carInObjective->m_fHealth > 0.0f) { + distWithTarget = m_carInObjective->GetPosition() - GetPosition(); + if (!bInVehicle) { + if (nEnterCarRangeMultiplier * ENTER_CAR_MAX_DIST < distWithTarget.Magnitude()) { + if (!m_carInObjective->pDriver && !m_carInObjective->GetIsOnScreen() && !GetIsOnScreen()) + WarpPedToNearEntityOffScreen(m_carInObjective); + + if (CharCreatedBy != MISSION_CHAR || m_prevObjective == OBJECTIVE_KILL_CHAR_ANY_MEANS +#ifdef VC_PED_PORTS + || IsPlayer() && !CPad::GetPad(0)->ArePlayerControlsDisabled() +#endif + ) { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } else { + SetIdle(); + SetMoveState(PEDMOVE_STILL); + } + } + } + } else if (!bInVehicle) { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } + } + } + break; + } + case OBJECTIVE_DESTROY_CAR: + { + if (!m_carInObjective) { + ClearLookFlag(); + bObjectiveCompleted = true; + break; + } + float distWithTargetSc = distWithTarget.Magnitude(); + CWeaponInfo *wepInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + float wepRange = wepInfo->m_fRange; + m_pLookTarget = m_carInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + + m_pSeekTarget = m_carInObjective; + m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + + TurnBody(); + if (m_carInObjective->m_fHealth <= 0.0f) { + ClearLookFlag(); + bScriptObjectiveCompleted = true; + break; + } + + if (m_attackTimer < CTimer::GetTimeInMilliseconds() && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE + && distWithTargetSc < wepRange) { + + // I hope so + CVector ourHead = GetMatrix() * CVector(0.5f, 0.0f, 0.6f); + CVector maxShotPos = m_carInObjective->GetPosition() - ourHead; + maxShotPos.Normalise(); + maxShotPos = maxShotPos * wepInfo->m_fRange + ourHead; + + CWorld::bIncludeDeadPeds = true; + CColPoint foundCol; + CEntity *foundEnt; + CWorld::ProcessLineOfSight(ourHead, maxShotPos, foundCol, foundEnt, + true, true, true, true, false, true, false); + CWorld::bIncludeDeadPeds = false; + if (foundEnt == m_carInObjective) { + SetAttack(m_carInObjective); + m_pPointGunAt = m_carInObjective; + if (m_pPointGunAt) + m_pPointGunAt->RegisterReference((CEntity **) &m_pPointGunAt); + + SetShootTimer(CGeneral::GetRandomNumberInRange(500, 2000)); + if (distWithTargetSc > 10.0f && !bKindaStayInSamePlace) { + SetAttackTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); + } else { + SetAttackTimer(CGeneral::GetRandomNumberInRange(50, 300)); + SetMoveState(PEDMOVE_STILL); + } + } + } else if (m_nPedState != PED_ATTACK && !bKindaStayInSamePlace) { + + float safeDistance; + if (wepRange <= 5.0f) + safeDistance = 3.0f; + else + safeDistance = wepRange * 0.25f; + + SetSeek(m_carInObjective, safeDistance); + SetMoveState(PEDMOVE_RUN); + } + SetLookFlag(m_carInObjective, false); + TurnBody(); + break; + } + case OBJECTIVE_GOTO_AREA_ANY_MEANS: + { + distWithTarget = m_nextRoutePointPos - GetPosition(); + distWithTarget.z = 0.0f; + if (InVehicle()) { + CCarAI::GetCarToGoToCoors(m_pMyVehicle, &m_nextRoutePointPos); + CCarCtrl::RegisterVehicleOfInterest(m_pMyVehicle); + if (distWithTarget.MagnitudeSqr() < sq(20.0f)) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + ForceStoredObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS); + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } + break; + } + if (distWithTarget.Magnitude() > 30.0f) { + if (m_pMyVehicle) { + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + } else { + float closestVehDist = SQR(60.0f); + int16 lastVehicle; + CEntity* vehicles[8]; + CWorld::FindObjectsInRange(GetPosition(), 25.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + CVehicle* foundVeh = nil; + for (int i = 0; i < lastVehicle; i++) { + CVehicle* nearVeh = (CVehicle*)vehicles[i]; + /* + Not used. + CVector vehSpeed = nearVeh->GetSpeed(); + CVector ourSpeed = GetSpeed(); + */ + CVector vehDistVec = nearVeh->GetPosition() - GetPosition(); + if (vehDistVec.MagnitudeSqr() < closestVehDist + && m_pedInObjective->m_pMyVehicle != nearVeh) + { + foundVeh = nearVeh; + closestVehDist = vehDistVec.MagnitudeSqr(); + } + } + m_pMyVehicle = foundVeh; + if (m_pMyVehicle) { + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle); + } + } + break; + } + // fall through + } + case OBJECTIVE_GOTO_AREA_ON_FOOT: + case OBJECTIVE_RUN_TO_AREA: + { + if ((m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA) + && InVehicle()) { + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } else { + distWithTarget = m_nextRoutePointPos - GetPosition(); + distWithTarget.z = 0.0f; + if (sq(m_distanceToCountSeekDone) >= distWithTarget.MagnitudeSqr()) { + bObjectiveCompleted = true; + bScriptObjectiveCompleted = true; + SetMoveState(PEDMOVE_STILL); + } else if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer || m_nPedState != PED_SEEK_POS) { + if (bUsePedNodeSeek) { + CVector bestCoords(0.0f, 0.0f, 0.0f); + m_vecSeekPos = m_nextRoutePointPos; + + if (!m_pNextPathNode) + FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); + + if (m_pNextPathNode) + m_vecSeekPos = m_pNextPathNode->GetPosition(); + } + SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); + } + } + + break; + } + case OBJECTIVE_GUARD_ATTACK: + { + if (m_pedInObjective) { + SetLookFlag(m_pedInObjective, true); + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + m_lookTimer = m_attackTimer; + TurnBody(); + float distWithTargetSc = distWithTarget.Magnitude(); + if (distWithTargetSc >= 20.0f) { + RestorePreviousObjective(); + } else if (m_attackTimer < CTimer::GetTimeInMilliseconds()) { + if (m_nPedState != PED_SEEK_ENTITY && distWithTargetSc >= 2.0f) { + SetSeek(m_pedInObjective, 1.0f); + } else { + SetAttack(m_pedInObjective); + SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 1500.0f)); + } + SetAttackTimer(1000); + } + } else { + RestorePreviousObjective(); + } + break; + } + case OBJECTIVE_FOLLOW_ROUTE: + if (HaveReachedNextPointOnRoute(1.0f)) { + int nextPoint = GetNextPointOnRoute(); + m_nextRoutePointPos = CRouteNode::GetPointPosition(nextPoint); + } else { + SetSeek(m_nextRoutePointPos, 0.8f); + } + break; + case OBJECTIVE_SOLICIT_VEHICLE: + if (m_carInObjective) { + if (m_objectiveTimer <= CTimer::GetTimeInMilliseconds()) { + if (!bInVehicle) { + SetObjective(OBJECTIVE_NONE); + SetWanderPath(CGeneral::GetRandomNumber() & 7); + m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000; + if (IsPedInControl()) + m_pMyVehicle = nil; + } + } else { + if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_SOLICIT) + SetSeekCar(m_carInObjective, 0); + } + } else { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } + break; + case OBJECTIVE_HAIL_TAXI: + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TAXI) && CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + Say(SOUND_PED_TAXI_WAIT); + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TAXI, 4.0f); + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; + } + break; + case OBJECTIVE_CATCH_TRAIN: + { + if (m_carInObjective) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_carInObjective); + } else { + CVehicle* trainToEnter = nil; + float closestCarDist = CHECK_NEARBY_THINGS_MAX_DIST; + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity* vehicles[8]; + + CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + for (int i = 0; i < lastVehicle; i++) { + CVehicle* nearVeh = (CVehicle*)vehicles[i]; + if (nearVeh->IsTrain()) { + CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); + float vehDist = vehDistVec.Magnitude(); + if (vehDist < closestCarDist && m_pedInObjective->m_pMyVehicle != nearVeh) + { + trainToEnter = nearVeh; + closestCarDist = vehDist; + } + } + } + if (trainToEnter) { + m_carInObjective = trainToEnter; + m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); + } + } + break; + } + case OBJECTIVE_BUY_ICE_CREAM: + if (m_carInObjective) { + if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_BUY_ICECREAM) + SetSeekCar(m_carInObjective, 0); + } else { + RestorePreviousObjective(); + RestorePreviousState(); + if (IsPedInControl()) + m_pMyVehicle = nil; + } + break; + case OBJECTIVE_STEAL_ANY_CAR: + { + if (bInVehicle) { + bScriptObjectiveCompleted = true; + RestorePreviousObjective(); + } else if (m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { + CVehicle *carToSteal = nil; + float closestCarDist = ENTER_CAR_MAX_DIST; + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity *vehicles[8]; + + // NB: This should've been ENTER_CAR_MAX_DIST actually, and is fixed in VC. + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + for(int i = 0; i < lastVehicle; i++) { + CVehicle *nearVeh = (CVehicle*)vehicles[i]; + if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { + if (nearVeh->m_vecMoveSpeed.Magnitude() <= 0.1f) { + if (nearVeh->CanPedOpenLocks(this)) { + CVector vehDistVec = GetPosition() - nearVeh->GetPosition(); + float vehDist = vehDistVec.Magnitude(); + if (vehDist < closestCarDist) { + carToSteal = nearVeh; + closestCarDist = vehDist; + } + } + } + } + } + if (carToSteal) { + SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, carToSteal); + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 5000; + } else { + RestorePreviousObjective(); + RestorePreviousState(); + } + } + break; + } + case OBJECTIVE_MUG_CHAR: + { + if (m_pedInObjective) { + if (m_pedInObjective->IsPlayer() || m_pedInObjective->bInVehicle || m_pedInObjective->m_fHealth <= 0.0f) { + ClearObjective(); + return; + } + if (m_pedInObjective->m_nMoveState > PEDMOVE_WALK) { + ClearObjective(); + return; + } + if (m_pedInObjective->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && m_pedInObjective->m_pedInObjective == this) { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pedInObjective); + SetMoveState(PEDMOVE_SPRINT); + return; + } + if (m_pedInObjective->m_nPedState == PED_FLEE_ENTITY && m_fleeFrom == this + || m_pedInObjective->m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE && m_pedInObjective->m_pedInObjective == this) { + ClearObjective(); + SetFindPathAndFlee(m_pedInObjective, 15000, true); + return; + } + float distWithTargetScSqr = distWithTarget.MagnitudeSqr(); + if (distWithTargetScSqr <= sq(10.0f)) { + if (distWithTargetScSqr <= sq(1.4f)) { + CAnimBlendAssociation *reloadAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD); + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + m_pedInObjective->GetPosition().x, m_pedInObjective->GetPosition().y, + GetPosition().x, GetPosition().y); + + if (reloadAssoc || !m_pedInObjective->IsPedShootable()) { + if (reloadAssoc && + (!reloadAssoc->IsRunning() || reloadAssoc->currentTime / reloadAssoc->hierarchy->totalLength > 0.8f)) { + CAnimBlendAssociation *punchAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f); + punchAssoc->flags |= ASSOC_DELETEFADEDOUT; + punchAssoc->flags |= ASSOC_FADEOUTWHENDONE; + CVector2D offset(distWithTarget.x, distWithTarget.y); + int dir = m_pedInObjective->GetLocalDirection(offset); + m_pedInObjective->StartFightDefend(dir, HITLEVEL_HIGH, 5); + m_pedInObjective->ReactToAttack(this); + m_pedInObjective->Say(SOUND_PED_ROBBED); + Say(SOUND_PED_MUGGING); + bRichFromMugging = true; + + // VC FIX: ClearObjective() clears m_pedInObjective in VC (also same with VC_PED_PORTS), so get it before call + CPed *victim = m_pedInObjective; + ClearObjective(); + if (victim->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT + || victim->m_pedInObjective != this) { + SetFindPathAndFlee(victim, 15000, true); + m_nLastPedState = PED_WANDER_PATH; + } else { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, victim); + SetMoveState(PEDMOVE_SPRINT); + m_nLastPedState = PED_WANDER_PATH; + } + } + } else { + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + if (weaponType != WEAPONTYPE_UNARMED && weaponType != WEAPONTYPE_BASEBALLBAT) + SetCurrentWeapon(WEAPONTYPE_UNARMED); + + CAnimBlendAssociation *newReloadAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_AK_RELOAD, 8.0f); + newReloadAssoc->flags |= ASSOC_DELETEFADEDOUT; + newReloadAssoc->flags |= ASSOC_FADEOUTWHENDONE; + } + } else { + SetSeek(m_pedInObjective, 1.0f); + CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK); + + if (walkAssoc) + walkAssoc->speed = 1.3f; + } + } else { + ClearObjective(); + SetWanderPath(CGeneral::GetRandomNumber() & 7); + } + } else { +#ifdef VC_PED_PORTS + m_objective = OBJECTIVE_NONE; +#endif + ClearObjective(); + } + break; + } + case OBJECTIVE_FLEE_CAR: + if (!bInVehicle && m_nPedState != PED_FLEE_ENTITY && m_pMyVehicle) { + RestorePreviousObjective(); + SetFlee(m_pMyVehicle, 6000); + break; + } + // fall through + case OBJECTIVE_LEAVE_CAR: + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { + if (InVehicle() +#ifdef VC_PED_PORTS + && (FindPlayerPed() != this || !CPad::GetPad(0)->GetAccelerate() + || bBusJacked) +#endif + ) { + if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN + && (m_nPedType != PEDTYPE_COP +#ifdef VC_PED_PORTS + || m_pMyVehicle->IsBoat() +#endif + || m_pMyVehicle->m_vecMoveSpeed.MagnitudeSqr2D() < sq(0.005f))) { + if (m_pMyVehicle->IsTrain()) + SetExitTrain(m_pMyVehicle); +#ifdef VC_PED_PORTS + else if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); +#endif + else + SetExitCar(m_pMyVehicle, 0); + } + } else { + RestorePreviousObjective(); + } + } + break; +#ifdef VC_PED_PORTS + case OBJECTIVE_LEAVE_CAR_AND_DIE: + { + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { + if (InVehicle()) { + if (m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR && m_nPedState != PED_EXIT_TRAIN) { + if (m_pMyVehicle->IsBoat()) + SetExitBoat(m_pMyVehicle); + else if (m_pMyVehicle->bIsBus) + SetExitCar(m_pMyVehicle, 0); + else { + eCarNodes doorNode = CAR_DOOR_LF; + if (m_pMyVehicle->pDriver != this) { + if (m_pMyVehicle->pPassengers[0] == this) { + doorNode = CAR_DOOR_RF; + } else if (m_pMyVehicle->pPassengers[1] == this) { + doorNode = CAR_DOOR_LR; + } else if (m_pMyVehicle->pPassengers[2] == this) { + doorNode = CAR_DOOR_RR; + } + } + SetBeingDraggedFromCar(m_pMyVehicle, doorNode, false); + } + } + } + } + break; + } +#endif + } + if (bObjectiveCompleted + || m_objectiveTimer > 0 && CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { + RestorePreviousObjective(); + if (m_objectiveTimer > CTimer::GetTimeInMilliseconds() || !m_objectiveTimer) + m_objectiveTimer = CTimer::GetTimeInMilliseconds() - 1; + + if (CharCreatedBy != RANDOM_CHAR || bInVehicle) { + if (IsPedInControl()) + RestorePreviousState(); + } else { + SetWanderPath(CGeneral::GetRandomNumber() & 7); + } + ClearAimFlag(); + ClearLookFlag(); + } + } +} + +void +CPed::SetFollowRoute(int16 currentPoint, int16 routeType) +{ + m_routeLastPoint = currentPoint; + m_routeStartPoint = CRouteNode::GetRouteStart(currentPoint); + m_routePointsPassed = 0; + m_routeType = routeType; + m_routePointsBeingPassed = 1; + m_objective = OBJECTIVE_FOLLOW_ROUTE; + m_nextRoutePointPos = CRouteNode::GetPointPosition(GetNextPointOnRoute()); +} + +int +CPed::GetNextPointOnRoute(void) +{ + int16 nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; + + // Route is complete + if (nextPoint < 0 || nextPoint > NUMPEDROUTES || m_routeLastPoint != CRouteNode::GetRouteThisPointIsOn(nextPoint)) { + + switch (m_routeType) { + case PEDROUTE_STOP_WHEN_DONE: + nextPoint = -1; + break; + case PEDROUTE_GO_BACKWARD_WHEN_DONE: + m_routePointsBeingPassed = -m_routePointsBeingPassed; + nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; + break; + case PEDROUTE_GO_TO_START_WHEN_DONE: + m_routePointsPassed = -1; + nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint; + break; + default: + break; + } + } + return nextPoint; +} + +bool +CPed::HaveReachedNextPointOnRoute(float distToCountReached) +{ + if ((m_nextRoutePointPos - GetPosition()).Magnitude2D() >= distToCountReached) + return false; + + m_routePointsPassed += m_routePointsBeingPassed; + return true; +} + +bool +CPed::CanSeeEntity(CEntity *entity, float threshold) +{ + float neededAngle = CGeneral::GetRadianAngleBetweenPoints( + entity->GetPosition().x, + entity->GetPosition().y, + GetPosition().x, + GetPosition().y); + + if (neededAngle < 0.0f) + neededAngle += TWOPI; + else if (neededAngle > TWOPI) + neededAngle -= TWOPI; + + float ourAngle = m_fRotationCur; + if (ourAngle < 0.0f) + ourAngle += TWOPI; + else if (ourAngle > TWOPI) + ourAngle -= TWOPI; + + float neededTurn = Abs(neededAngle - ourAngle); + + return neededTurn < threshold || TWOPI - threshold < neededTurn; +} + +// Only used while deciding which gun ped should switch to, if no ammo left. +bool +CPed::SelectGunIfArmed(void) +{ + for (int i = 0; i < m_maxWeaponTypeAllowed; i++) { + if (GetWeapon(i).m_nAmmoTotal > 0) { + eWeaponType weaponType = GetWeapon(i).m_eWeaponType; + if (weaponType >= WEAPONTYPE_COLT45 && weaponType != WEAPONTYPE_M16 && weaponType <= WEAPONTYPE_FLAMETHROWER) { + SetCurrentWeapon(i); + return true; + } + } + } + SetCurrentWeapon(WEAPONTYPE_UNARMED); + return false; +} + +void +CPed::ReactToPointGun(CEntity *entWithGun) +{ + CPed *pedWithGun = (CPed*)entWithGun; + int waitTime; + + if (IsPlayer() || !IsPedInControl() || CharCreatedBy == MISSION_CHAR) + return; + + if (m_leader == pedWithGun) + return; + + if (m_nWaitState == WAITSTATE_PLAYANIM_HANDSUP || m_nWaitState == WAITSTATE_PLAYANIM_HANDSCOWER || + (GetPosition() - pedWithGun->GetPosition()).MagnitudeSqr2D() > 225.0f) + return; + + if (m_leader) { + if (FindPlayerPed() == m_leader) + return; + + ClearLeader(); + } + if (m_pedStats->m_flags & STAT_GUN_PANIC + && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) + && m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_AIM_GUN) { + + waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); + SetWaitState(WAITSTATE_PLAYANIM_HANDSCOWER, &waitTime); + Say(SOUND_PED_HANDS_COWER); + m_pLookTarget = pedWithGun; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + SetMoveState(PEDMOVE_NONE); + + } else if (m_nPedType != pedWithGun->m_nPedType) { + if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { + RegisterThreatWithGangPeds(pedWithGun); + } + + if (m_nPedType == PEDTYPE_COP) { + if (pedWithGun->IsPlayer()) { + ((CPlayerPed*)pedWithGun)->m_pWanted->SetWantedLevelNoDrop(2); + if (bCrouchWhenShooting || bKindaStayInSamePlace) { + SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); + return; + } + } + } + + if (m_nPedType != PEDTYPE_COP + && (m_nPedState != PED_ATTACK || GetWeapon()->IsTypeMelee()) + && (m_nPedState != PED_FLEE_ENTITY || pedWithGun->IsPlayer() && m_fleeFrom != pedWithGun) + && m_nPedState != PED_AIM_GUN && m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) { + + waitTime = CGeneral::GetRandomNumberInRange(3000, 6000); + SetWaitState(WAITSTATE_PLAYANIM_HANDSUP, &waitTime); + Say(SOUND_PED_HANDS_UP); + m_pLookTarget = pedWithGun; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + SetMoveState(PEDMOVE_NONE); + if (m_nPedState == PED_FLEE_ENTITY) { + m_fleeFrom = pedWithGun; + m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); + } + + if (FindPlayerPed() == pedWithGun && bRichFromMugging) { + int money = CGeneral::GetRandomNumberInRange(100, 300); + int pickupCount = money / 40 + 1; + int moneyPerPickup = money / pickupCount; + + for (int i = 0; i < pickupCount; i++) { + float pickupX = 1.5f * Sin((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().x; + float pickupY = 1.5f * Cos((CGeneral::GetRandomNumber() % 256)/256.0f * TWOPI) + GetPosition().y; + bool found = false; + float groundZ = CWorld::FindGroundZFor3DCoord(pickupX, pickupY, GetPosition().z, &found) + 0.5f; + if (found) { + CPickups::GenerateNewOne(CVector(pickupX, pickupY, groundZ), MI_MONEY, PICKUP_MONEY, moneyPerPickup + (CGeneral::GetRandomNumber() & 7)); + } + } + bRichFromMugging = false; + } + } + } +} + +void +CPed::ReactToAttack(CEntity *attacker) +{ + if (IsPlayer() && attacker->IsPed()) { + InformMyGangOfAttack(attacker); + SetLookFlag(attacker, true); + SetLookTimer(700); + return; + } + +#ifdef VC_PED_PORTS + if (m_nPedState == PED_DRIVING && InVehicle() + && (m_pMyVehicle->pDriver == this || m_pMyVehicle->pDriver && m_pMyVehicle->pDriver->m_nPedState == PED_DRIVING && m_pMyVehicle->pDriver->m_objective != OBJECTIVE_LEAVE_CAR_AND_DIE)) { + + if (m_pMyVehicle->VehicleCreatedBy == RANDOM_VEHICLE + && (m_pMyVehicle->GetStatus() == STATUS_SIMPLE || m_pMyVehicle->GetStatus() == STATUS_PHYSICS) + && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) { + + CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); + m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * m_pMyVehicle->pHandling->Transmission.fUnkMaxVelocity; + m_pMyVehicle->SetStatus(STATUS_PHYSICS); + } + } else +#endif + if (IsPedInControl() && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats)) { + CPed *ourLeader = m_leader; + if (ourLeader != attacker && (!ourLeader || FindPlayerPed() != ourLeader) + && attacker->IsPed()) { + + CPed *attackerPed = (CPed*)attacker; + if (bNotAllowedToDuck) { + if (!attackerPed->GetWeapon()->IsTypeMelee()) { + m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds(); + return; + } + } else if (bCrouchWhenShooting || bKindaStayInSamePlace) { + SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); + return; + } + + if (m_pedStats->m_fear <= 100 - attackerPed->m_pedStats->m_temper) { + if (m_pedStats != attackerPed->m_pedStats) { + if (IsGangMember() || m_nPedType == PEDTYPE_EMERGENCY || m_nPedType == PEDTYPE_FIREMAN) { + RegisterThreatWithGangPeds(attackerPed); + } + if (!attackerPed->GetWeapon()->IsTypeMelee() && GetWeapon()->IsTypeMelee()) { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attacker); + SetMoveState(PEDMOVE_RUN); + } else { + SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attacker); + SetObjectiveTimer(20000); + } + } + } else { + SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, attackerPed); + SetMoveState(PEDMOVE_RUN); + if (attackerPed->GetWeapon()->IsTypeMelee()) + Say(SOUND_PED_FLEE_RUN); + } + } + } +} + +void +CPed::PedAnimAlignCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!ped->IsNotInWreckedVehicle()) + return; + + if (!ped->EnteringCar()) { +#ifdef VC_PED_PORTS + if (ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + + return; + } + if (ped->m_fHealth == 0.0f) { + ped->QuitEnteringCar(); + return; + } + bool itsVan = !!veh->bIsVan; + bool itsBus = !!veh->bIsBus; +#ifdef FIX_BUGS + bool itsLow = !!veh->bLowVehicle; +#endif + eDoors enterDoor; + AnimationId enterAnim; + + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + itsVan = false; + enterDoor = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + enterDoor = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + itsVan = false; + enterDoor = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + enterDoor = DOOR_REAR_LEFT; + break; + default: + break; + } + + if (veh->IsDoorMissing(enterDoor) || veh->IsDoorFullyOpen(enterDoor)) { + + veh->AutoPilot.m_nCruiseSpeed = 0; + if (ped->m_nPedState == PED_CARJACK) { + ped->PedAnimDoorOpenCB(nil, ped); + return; + } + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (itsVan) { + enterAnim = ANIM_VAN_GETIN; + } else if (itsBus) { + enterAnim = ANIM_COACH_IN_R; +#ifdef FIX_BUGS + } else if (itsLow) { + enterAnim = ANIM_CAR_GETIN_LOW_RHS; +#endif + } else { + enterAnim = ANIM_CAR_GETIN_RHS; + } + } else if (itsVan) { + enterAnim = ANIM_VAN_GETIN_L; + } else if (itsBus) { + enterAnim = ANIM_COACH_IN_L; +#ifdef FIX_BUGS + } else if (itsLow) { + enterAnim = ANIM_CAR_GETIN_LOW_LHS; +#endif + } else { + enterAnim = ANIM_CAR_GETIN_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, enterAnim); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + + } else if (veh->CanPedOpenLocks(ped)) { + + veh->AutoPilot.m_nCruiseSpeed = 0; + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (itsVan) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN); + } else if (itsBus) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_R); + } else { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_RHS); + } + } else if (itsVan) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_VAN_OPEN_L); + } else if (itsBus) { + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_COACH_OPEN_L); + } else { + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && veh->pDriver) { + + if (!veh->bLowVehicle + && veh->pDriver->CharCreatedBy != MISSION_CHAR + && veh->pDriver->m_nPedState == PED_DRIVING) { + + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_QJACK); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + veh->pDriver->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, true); + + if (veh->pDriver->IsGangMember()) + veh->pDriver->RegisterThreatWithGangPeds(ped); + return; + } + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_OPEN_LHS); + } + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + + } else { + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_RHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_DOORLOCKED_LHS); + + ped->bCancelEnteringCar = true; + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorOpenCB, ped); + } +} + +void +CPed::PedAnimDoorOpenCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CVehicle* veh = ped->m_pMyVehicle; + + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!ped->IsNotInWreckedVehicle()) + return; + + if (!ped->EnteringCar()) { +#ifdef VC_PED_PORTS + if (ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + + return; + } + + eDoors door; + CPed *pedInSeat = nil; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; pedInSeat = veh->pPassengers[0]; break; + case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; pedInSeat = veh->pPassengers[2]; break; + case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; pedInSeat = veh->pDriver; break; + case CAR_DOOR_LR: door = DOOR_REAR_LEFT; pedInSeat = veh->pPassengers[1]; break; + default: assert(0); + } + + if (ped->m_fHealth == 0.0f || CPad::GetPad(0)->ArePlayerControlsDisabled() && pedInSeat && pedInSeat->IsPlayer()) { + ped->QuitEnteringCar(); + return; + } + + bool isVan = veh->bIsVan; + bool isBus = veh->bIsBus; + bool isLow = veh->bLowVehicle; + bool vehUpsideDown = veh->IsUpsideDown(); + if (ped->bCancelEnteringCar) { + if (ped->IsPlayer()) { + if (veh->pDriver) { + if (veh->pDriver->m_nPedType == PEDTYPE_COP) { + FindPlayerPed()->SetWantedLevelNoDrop(1); + } + } + } +#ifdef CANCELLABLE_CAR_ENTER + if (!veh->IsDoorMissing(door) && veh->CanPedOpenLocks(ped) && veh->IsCar()) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + } +#endif + ped->QuitEnteringCar(); + ped->RestorePreviousObjective(); + ped->bCancelEnteringCar = false; + return; + } + if (!veh->IsDoorMissing(door) && veh->IsCar()) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + } + + if (veh->m_vecMoveSpeed.Magnitude() > 0.2f) { + ped->QuitEnteringCar(); + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) + ped->SetFall(1000, ANIM_KO_SPIN_R, false); + else + ped->SetFall(1000, ANIM_KO_SPIN_L, false); + + return; + } + veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_OPEN_LHS, 1.0f); + + if (ped->m_vehEnterType == CAR_DOOR_LF || ped->m_vehEnterType == CAR_DOOR_RF) + isVan = false; + + if (ped->m_nPedState != PED_CARJACK || isBus) { + AnimationId animToPlay; + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + + if (isVan) { + animToPlay = ANIM_VAN_GETIN; + } else if (isBus) { + animToPlay = ANIM_COACH_IN_R; + } else if (isLow) { + animToPlay = ANIM_CAR_GETIN_LOW_RHS; + } else { + animToPlay = ANIM_CAR_GETIN_RHS; + } + } else if (isVan) { + animToPlay = ANIM_VAN_GETIN_L; + } else if (isBus) { + animToPlay = ANIM_COACH_IN_L; + } else if (isLow) { + animToPlay = ANIM_CAR_GETIN_LOW_LHS; + } else { + animToPlay = ANIM_CAR_GETIN_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } else { + CPed *pedToDragOut = nil; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: pedToDragOut = veh->pPassengers[0]; break; + case CAR_DOOR_RR: pedToDragOut = veh->pPassengers[2]; break; + case CAR_DOOR_LF: pedToDragOut = veh->pDriver; break; + case CAR_DOOR_LR: pedToDragOut = veh->pPassengers[1]; break; + default: assert(0); + } + + if (vehUpsideDown) { + ped->QuitEnteringCar(); + if (ped->m_nPedType == PEDTYPE_COP) + ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); + } + + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + if (pedToDragOut && !pedToDragOut->bDontDragMeOutCar) { + if (pedToDragOut->m_nPedState != PED_DRIVING) { + ped->QuitEnteringCar(); + pedToDragOut = nil; + } else { + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_RHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_RHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); + } + } else if (ped->m_nPedType == PEDTYPE_COP) { + ped->QuitEnteringCar(); + if (ped->m_pedInObjective && ped->m_pedInObjective->m_nPedState == PED_DRIVING) { + veh->SetStatus(STATUS_PLAYER_DISABLED); + ((CCopPed*)ped)->SetArrestPlayer(ped->m_pedInObjective); + } else if (!veh->IsDoorMissing(DOOR_FRONT_RIGHT)) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_SWINGING); + } + } else { + // BUG: Probably we will sit on top of the passenger if his m_ped_flagF4 is true. + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } + } else { + if (pedToDragOut) { + if (pedToDragOut->m_nPedState != PED_DRIVING || pedToDragOut->bDontDragMeOutCar) { + + // BUG: Player freezes in that condition due to its objective isn't restored. It's an unfinished feature, used in VC. + ped->QuitEnteringCar(); + pedToDragOut = nil; + } else { + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LOW_LHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_PULLOUT_LHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimPullPedOutCB, ped); + } + } else { + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_GETIN_LHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } + } + + if (pedToDragOut) { + pedToDragOut->SetBeingDraggedFromCar(veh, ped->m_vehEnterType, false); + if (pedToDragOut->IsGangMember()) + pedToDragOut->RegisterThreatWithGangPeds(ped); + } + } + + if (veh->pDriver && ped) { + veh->pDriver->SetLookFlag(ped, true); + veh->pDriver->SetLookTimer(1000); + } + return; +} + +void +CPed::PedAnimPullPedOutCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CVehicle* veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (ped->EnteringCar()) { + if (!ped->IsNotInWreckedVehicle()) + return; + +#ifdef CANCELLABLE_CAR_ENTER + if (ped->bCancelEnteringCar) { + ped->QuitEnteringCar(); + ped->RestorePreviousObjective(); + ped->bCancelEnteringCar = false; + return; + } +#endif + + bool isLow = !!veh->bLowVehicle; + + int padNo; + if (ped->IsPlayer()) { + + // BUG? This will cause crash if m_nPedType is bigger then 1, there are only 2 pads + switch (ped->m_nPedType) { + case PEDTYPE_PLAYER1: + padNo = 0; + break; + case PEDTYPE_PLAYER2: + padNo = 1; + break; + case PEDTYPE_PLAYER3: + padNo = 2; + break; + case PEDTYPE_PLAYER4: + padNo = 3; + break; + } + CPad *pad = CPad::GetPad(padNo); + + if (!pad->ArePlayerControlsDisabled()) { + + if (pad->GetTarget() + || pad->NewState.LeftStickX + || pad->NewState.LeftStickY + || pad->NewState.DPadUp + || pad->NewState.DPadDown + || pad->NewState.DPadLeft + || pad->NewState.DPadRight) { + ped->QuitEnteringCar(); + ped->RestorePreviousObjective(); + return; + } + } + } + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + AnimationId animToPlay; + if (ped->m_vehEnterType != CAR_DOOR_LF && ped->m_vehEnterType != CAR_DOOR_LR) { + if (isLow) + animToPlay = ANIM_CAR_GETIN_LOW_RHS; + else + animToPlay = ANIM_CAR_GETIN_RHS; + } else if (isLow) { + animToPlay = ANIM_CAR_GETIN_LOW_LHS; + } else { + animToPlay = ANIM_CAR_GETIN_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimGetInCB, ped); + } else { + ped->QuitEnteringCar(); + } + } else { + ped->QuitEnteringCar(); + } +} + +void +CPed::PedAnimGetInCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*) arg; + + CVehicle *veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) + return; + + if (!ped->EnteringCar()) { +#ifdef VC_PED_PORTS + if(ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + return; + } + + if (ped->IsPlayer() && ped->bGonnaKillTheCarJacker && ((CPlayerPed*)ped)->m_pArrestingCop) { + PedSetInCarCB(nil, ped); + ped->m_nLastPedState = ped->m_nPedState; + ped->m_nPedState = PED_ARRESTED; + ped->bGonnaKillTheCarJacker = false; + if (veh) { + veh->m_nNumGettingIn = 0; + veh->m_nGettingInFlags = 0; + veh->bIsHandbrakeOn = true; + veh->SetStatus(STATUS_PLAYER_DISABLED); + } + return; + } + if (ped->IsPlayer() && ped->m_vehEnterType == CAR_DOOR_LF + && (Pads[0].GetAccelerate() >= 255.0f || Pads[0].GetBrake() >= 255.0f) + && veh->IsCar()) { + if (((CAutomobile*)veh)->Damage.GetDoorStatus(DOOR_FRONT_LEFT) != DOOR_STATUS_MISSING) + ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING); + + PedSetInCarCB(nil, ped); + return; + } + bool isVan = !!veh->bIsVan; + bool isBus = !!veh->bIsBus; + bool isLow = !!veh->bLowVehicle; + eDoors enterDoor; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + isVan = false; + enterDoor = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + enterDoor = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + isVan = false; + enterDoor = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + enterDoor = DOOR_REAR_LEFT; + break; + default: + break; + } + if (!veh->IsDoorMissing(enterDoor)) { + if (veh->IsCar()) + ((CAutomobile*)veh)->Damage.SetDoorStatus(enterDoor, DOOR_STATUS_SWINGING); + } + CPed *driver = veh->pDriver; + if (driver && (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || ped->m_nPedState == PED_CARJACK)) { + if (veh->bIsBus) { + driver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + if (driver->IsPlayer()) { + veh->bIsHandbrakeOn = true; + veh->SetStatus(STATUS_PLAYER_DISABLED); + } + driver->bBusJacked = true; + veh->bIsBeingCarJacked = false; + PedSetInCarCB(nil, ped); + if (ped->m_nPedType == PEDTYPE_COP + || ped->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT + || ped->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) { + ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + } + ped->m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 400; + return; + } + if (driver != ped && ped->m_vehEnterType != CAR_DOOR_LF) { + if (!driver->IsPlayer()) { + driver->bUsePedNodeSeek = true; + driver->m_pLastPathNode = nil; + if (driver->m_pedStats->m_temper <= driver->m_pedStats->m_fear + || driver->CharCreatedBy == MISSION_CHAR + || veh->VehicleCreatedBy == MISSION_VEHICLE) { + driver->bFleeAfterExitingCar = true; + } else { + driver->bGonnaKillTheCarJacker = true; + veh->pDriver->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped); + + if (veh->pDriver->m_nPedType == PEDTYPE_COP && ped->IsPlayer()) { + FindPlayerPed()->SetWantedLevelNoDrop(1); + } + } + } + if ((ped->m_nPedType != PEDTYPE_EMERGENCY || veh->pDriver->m_nPedType != PEDTYPE_EMERGENCY) + && (ped->m_nPedType != PEDTYPE_COP || veh->pDriver->m_nPedType != PEDTYPE_COP)) { + veh->pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + veh->pDriver->Say(SOUND_PED_CAR_JACKED); +#ifdef VC_PED_PORTS + veh->pDriver->SetRadioStation(); +#endif + } else { + ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; + } + } + } + if (veh->IsDoorMissing(enterDoor) || isBus) { + PedAnimDoorCloseCB(nil, ped); + } else { + AnimationId animToPlay; + if (enterDoor != DOOR_FRONT_LEFT && enterDoor != DOOR_REAR_LEFT) { + if (isVan) { + animToPlay = ANIM_VAN_CLOSE; + } else if (isLow) { + animToPlay = ANIM_CAR_CLOSEDOOR_LOW_RHS; + } else { + animToPlay = ANIM_CAR_CLOSEDOOR_RHS; + } + } else if (isVan) { + animToPlay = ANIM_VAN_CLOSE_L; + } else if (isLow) { + animToPlay = ANIM_CAR_CLOSEDOOR_LOW_LHS; + } else { + animToPlay = ANIM_CAR_CLOSEDOOR_LHS; + } + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, animToPlay); + ped->m_pVehicleAnim->SetFinishCallback(PedAnimDoorCloseCB, ped); + } +} + +void +CPed::PedAnimDoorCloseCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CAutomobile *veh = (CAutomobile*)(ped->m_pMyVehicle); + + if (!ped->IsNotInWreckedVehicle() || ped->DyingOrDead()) + return; + + if (ped->EnteringCar()) { + bool isLow = !!veh->bLowVehicle; + + if (!veh->bIsBus) + veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_CLOSEDOOR_LHS, 1.0f); + + eDoors door; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: door = DOOR_FRONT_RIGHT; break; + case CAR_DOOR_RR: door = DOOR_REAR_RIGHT; break; + case CAR_DOOR_LF: door = DOOR_FRONT_LEFT; break; + case CAR_DOOR_LR: door = DOOR_REAR_LEFT; break; + default: assert(0); + } + + if (veh->Damage.GetDoorStatus(door) == DOOR_STATUS_SWINGING) + veh->Damage.SetDoorStatus(door, DOOR_STATUS_OK); + + if (door == DOOR_FRONT_LEFT || ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER || veh->bIsBus) { + PedSetInCarCB(nil, ped); + } else if (ped->m_vehEnterType == CAR_DOOR_RF + && (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF || + (veh->pDriver != nil && + (veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR +#ifdef VC_PED_PORTS + && veh->pDriver->m_objective != OBJECTIVE_LEAVE_CAR_AND_DIE +#endif + || !veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, nil))))) { + + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER +#if defined VC_PED_PORTS || defined FIX_BUGS + || ped->m_nPedState == PED_CARJACK +#endif + ) + veh->bIsBeingCarJacked = false; + + ped->m_objective = OBJECTIVE_ENTER_CAR_AS_PASSENGER; + PedSetInCarCB(nil, ped); + + ped->SetObjective(OBJECTIVE_LEAVE_CAR, veh); + if (!ped->IsPlayer()) + ped->bFleeAfterExitingCar = true; + + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + + } else { + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (isLow) + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSHUFFLE_RHS); + else + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SHUFFLE_RHS); + + ped->m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, ped); + } + } else { +#ifdef VC_PED_PORTS + if (ped->m_nPedState != PED_DRIVING) +#endif + ped->QuitEnteringCar(); + } +} + +void +CPed::SetFormation(eFormation type) +{ + // FIX: Formations in GetFormationPosition were in range 1-8, whereas in here it's 0-7. + // To not change the behaviour, range in here tweaked by 1 with the use of enum. + + switch (m_pedFormation) { + case FORMATION_REAR: + case FORMATION_REAR_LEFT: + case FORMATION_REAR_RIGHT: + case FORMATION_FRONT_LEFT: + case FORMATION_FRONT_RIGHT: + case FORMATION_LEFT: + case FORMATION_RIGHT: + case FORMATION_FRONT: + break; + default: + Error("Unknown formation type, PedAI.cpp"); + break; + } + m_pedFormation = type; +} + +CVector +CPed::GetFormationPosition(void) +{ + if (m_pedInObjective->m_nPedState == PED_DEAD) { + if (!m_pedInObjective->m_pedInObjective) { + m_pedInObjective = nil; + return GetPosition(); + } + m_pedInObjective = m_pedInObjective->m_pedInObjective; + } + + CVector formationOffset; + switch (m_pedFormation) { + case FORMATION_REAR: + formationOffset = CVector(0.0f, -1.5f, 0.0f); + break; + case FORMATION_REAR_LEFT: + formationOffset = CVector(-1.5f, -1.5f, 0.0f); + break; + case FORMATION_REAR_RIGHT: + formationOffset = CVector(1.5f, -1.5f, 0.0f); + break; + case FORMATION_FRONT_LEFT: + formationOffset = CVector(-1.5f, 1.5f, 0.0f); + break; + case FORMATION_FRONT_RIGHT: + formationOffset = CVector(1.5f, 1.5f, 0.0f); + break; + case FORMATION_LEFT: + formationOffset = CVector(-1.5f, 0.0f, 0.0f); + break; + case FORMATION_RIGHT: + formationOffset = CVector(1.5f, 0.0f, 0.0f); + break; + case FORMATION_FRONT: + formationOffset = CVector(0.0f, 1.5f, 0.0f); + break; + default: + formationOffset = CVector(0.0f, 0.0f, 0.0f); + break; + } + return formationOffset + m_pedInObjective->GetPosition(); +} + +void +CPed::PedAnimStepOutCarCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CVehicle* veh = ped->m_pMyVehicle; + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (!veh) { + PedSetOutCarCB(nil, ped); + return; + } +#ifdef VC_PED_PORTS + CVector posForZ = ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posForZ); + if (ped->GetPosition().z - 0.5f > posForZ.z) { + PedSetOutCarCB(nil, ped); + return; + } +#endif + veh->m_nStaticFrames = 0; + veh->m_vecMoveSpeed += CVector(0.001f, 0.001f, 0.001f); + veh->m_vecTurnSpeed += CVector(0.001f, 0.001f, 0.001f); + if (!veh->bIsBus) + veh->ProcessOpenDoor(ped->m_vehEnterType, ANIM_CAR_GETOUT_LHS, 1.0f); + + /* + // Duplicate and only in PC for some reason + if (!veh) { + PedSetOutCarCB(nil, ped); + return; + } + */ + eDoors door; + switch (ped->m_vehEnterType) { + case CAR_DOOR_RF: + door = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + door = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + door = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + door = DOOR_REAR_LEFT; + break; + default: + break; + } + bool closeDoor = !veh->IsDoorMissing(door); + + int padNo; + if (ped->IsPlayer()) { + + // BUG? This will cause crash if m_nPedType is bigger then 1, there are only 2 pads + switch (ped->m_nPedType) { + case PEDTYPE_PLAYER1: + padNo = 0; + break; + case PEDTYPE_PLAYER2: + padNo = 1; + break; + case PEDTYPE_PLAYER3: + padNo = 2; + break; + case PEDTYPE_PLAYER4: + padNo = 3; + break; + } + CPad* pad = CPad::GetPad(padNo); + bool engineIsIntact = veh->IsCar() && ((CAutomobile*)veh)->Damage.GetEngineStatus() >= 225; + if (!pad->ArePlayerControlsDisabled() && veh->m_nDoorLock != CARLOCK_FORCE_SHUT_DOORS + && (pad->GetTarget() + || pad->NewState.LeftStickX + || pad->NewState.LeftStickY + || pad->NewState.DPadUp + || pad->NewState.DPadDown + || pad->NewState.DPadLeft + || pad->NewState.DPadRight) + || veh->bIsBus + || veh->m_pCarFire + || engineIsIntact) { + closeDoor = false; + } + } + +#ifdef VC_PED_PORTS + if (ped->m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) + closeDoor = false; +#endif + + if (!closeDoor) { + if (!veh->IsDoorMissing(door) && !veh->bIsBus) { + ((CAutomobile*)veh)->Damage.SetDoorStatus(door, DOOR_STATUS_SWINGING); + } + PedSetOutCarCB(nil, ped); + return; + } + + if (ped->bFleeAfterExitingCar || ped->bGonnaKillTheCarJacker) { + // POTENTIAL BUG? Why DOOR_FRONT_LEFT instead of door variable? or vice versa? + if (!veh->IsDoorMissing(door)) + ((CAutomobile*)veh)->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING); + } else { + switch (door) { + case DOOR_FRONT_LEFT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_LHS); + break; + case DOOR_FRONT_RIGHT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_RHS); + break; + case DOOR_REAR_LEFT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_LHS); + break; + case DOOR_REAR_RIGHT: + ped->m_pVehicleAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_CLOSE_RHS); + break; + default: + break; + } + } + + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, ped); + return; +} + +void +CPed::LineUpPedWithCar(PedLineUpPhase phase) +{ + bool vehIsUpsideDown = false; + int vehAnim; + float seatPosMult = 0.0f; + float currentZ; + float adjustedTimeStep; + + if (CReplay::IsPlayingBack()) + return; + + if (!bChangedSeat && phase != LINE_UP_TO_CAR_2) { + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP)) { + SetPedPositionInCar(); + return; + } + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO)) { + SetPedPositionInCar(); + return; + } + bChangedSeat = true; + } + 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. + if (veh->GetUp().z <= -0.8f) + vehIsUpsideDown = true; + + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + if (vehIsUpsideDown) { + m_fRotationDest = -PI + veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + if (vehIsUpsideDown) { + m_fRotationDest = veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = -0.5f * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } else { + // I don't know will this part ever run(maybe boats?), but the game also handles that. I don't know is it intentional. + + if (vehIsUpsideDown) { + m_fRotationDest = veh->GetForward().Heading(); + } else if (veh->bIsBus) { + m_fRotationDest = 0.5f * PI + veh->GetForward().Heading(); + } else { + m_fRotationDest = veh->GetForward().Heading(); + } + } + + if (!bInVehicle) + seatPosMult = 1.0f; + +#ifdef VC_PED_PORTS + bool multExtractedFromAnim = false; + bool multExtractedFromAnimBus = false; + float zBlend; +#endif + 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_VAN_GETIN_L: + case ANIM_VAN_GETIN: +#ifdef VC_PED_PORTS + multExtractedFromAnim = true; + zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.3f, 0.0f) / (1.0f - 0.3f); + // fall through +#endif + 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: +#ifdef VC_PED_PORTS + if (!multExtractedFromAnim) { + multExtractedFromAnim = true; + zBlend = Max(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength - 0.5f, 0.0f) / (1.0f - 0.5f); + } + // fall through +#endif + case ANIM_CAR_CRAWLOUT_RHS: + case ANIM_CAR_CRAWLOUT_RHS2: + case ANIM_VAN_GETOUT_L: + case ANIM_VAN_GETOUT: + seatPosMult = m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength; + break; + case ANIM_CAR_GETIN_RHS: + case ANIM_CAR_GETIN_LHS: +#ifdef VC_PED_PORTS + if (veh && veh->IsCar() && veh->bIsBus) { + multExtractedFromAnimBus = true; + zBlend = Min(m_pVehicleAnim->currentTime / m_pVehicleAnim->hierarchy->totalLength, 0.5f) / 0.5f; + } + // fall through +#endif + case ANIM_CAR_QJACK: + case ANIM_CAR_GETIN_LOW_LHS: + 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 { + neededPos = GetPositionToOpenCarDoor(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 nextZSpeed = m_vecMoveSpeed.z - GRAVITY * CTimer::GetTimeStep(); + + // If we're not in ground at next step, apply animation + if (neededPos.z + nextZSpeed >= autoZPos.z) { + m_vecMoveSpeed.z = nextZSpeed; + 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) { +#ifdef VC_PED_PORTS + if (multExtractedFromAnim) { + neededPos.z += (autoZPos.z - neededPos.z) * zBlend; + } else { +#endif + 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); + } +#ifdef VC_PED_PORTS + } +#endif + } else { + // We may need to raise up the ped + if (phase == LINE_UP_TO_CAR_START) { + currentZ = GetPosition().z; + + if (neededPos.z > currentZ) { +#ifdef VC_PED_PORTS + if (multExtractedFromAnimBus) { + neededPos.z = (neededPos.z - currentZ) * zBlend + currentZ; + } else { +#endif + 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 (EnteringCar()) { + neededPos.z = Max(currentZ, autoZPos.z); + } +#ifdef VC_PED_PORTS + } +#endif + } + } + } + + bool stillGettingInOut = false; + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) + stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || bOnBoat; + + if (!stillGettingInOut) { + m_fRotationCur = m_fRotationDest; + } else { + float limitedDest = CGeneral::LimitRadianAngle(m_fRotationDest); + float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; + + if (timeUntilStateChange <= 0.0f) { + m_vecOffsetSeek.x = 0.0f; + m_vecOffsetSeek.y = 0.0f; + } + m_vecOffsetSeek.z = 0.0f; + + neededPos -= timeUntilStateChange * m_vecOffsetSeek; + + if (PI + m_fRotationCur < limitedDest) { + limitedDest -= 2 * PI; + } else if (m_fRotationCur - PI > limitedDest) { + limitedDest += 2 * PI; + } + m_fRotationCur -= (m_fRotationCur - limitedDest) * (1.0f - timeUntilStateChange); + } + + if (seatPosMult > 0.2f || vehIsUpsideDown) { + SetPosition(neededPos); + SetHeading(m_fRotationCur); + } else { + CMatrix vehDoorMat(veh->GetMatrix()); + vehDoorMat.GetPosition() += Multiply3x3(vehDoorMat, GetLocalPositionToOpenCarDoor(veh, m_vehEnterType, 0.0f)); + // VC couch anims are inverted, so they're fixing it here. + GetMatrix() = vehDoorMat; + } + +} + +void +CPed::SetCarJack(CVehicle* car) +{ + uint8 doorFlag; + eDoors door; + CPed *pedInSeat = nil; + + if (car->IsBoat()) + return; + + switch (m_vehEnterType) { + case CAR_DOOR_RF: + doorFlag = CAR_DOOR_FLAG_RF; + door = DOOR_FRONT_RIGHT; + if (car->pPassengers[0]) { + pedInSeat = car->pPassengers[0]; + } else if (m_nPedType == PEDTYPE_COP) { + pedInSeat = car->pDriver; + } + break; + case CAR_DOOR_RR: + doorFlag = CAR_DOOR_FLAG_RR; + door = DOOR_REAR_RIGHT; + pedInSeat = car->pPassengers[2]; + break; + case CAR_DOOR_LF: + doorFlag = CAR_DOOR_FLAG_LF; + door = DOOR_FRONT_LEFT; + pedInSeat = car->pDriver; + break; + case CAR_DOOR_LR: + doorFlag = CAR_DOOR_FLAG_LR; + door = DOOR_REAR_LEFT; + pedInSeat = car->pPassengers[1]; + break; + default: + doorFlag = CAR_DOOR_FLAG_UNKNOWN; + break; + } + + if(car->bIsBus) + pedInSeat = car->pDriver; + + if (m_fHealth > 0.0f && (IsPlayer() || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || + (car->VehicleCreatedBy != MISSION_VEHICLE && car->GetModelIndex() != MI_DODO))) + if (pedInSeat && !pedInSeat->IsPedDoingDriveByShooting() && pedInSeat->m_nPedState == PED_DRIVING) + if (m_nPedState != PED_CARJACK && !m_pVehicleAnim) + if ((car->IsDoorReady(door) || car->IsDoorFullyOpen(door))) + if (!car->bIsBeingCarJacked && !(doorFlag & car->m_nGettingInFlags) && !(doorFlag & car->m_nGettingOutFlags)) + SetCarJack_AllClear(car, m_vehEnterType, doorFlag); +} + +void +CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + RemoveWeaponWhenEnteringVehicle(); + if (m_nPedState != PED_SEEK_CAR) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity**)&m_pSeekTarget); + m_nPedState = PED_CARJACK; + car->bIsBeingCarJacked = true; + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**)&m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + + Say(m_nPedType == PEDTYPE_COP ? SOUND_PED_ARREST_COP : SOUND_PED_CAR_JACKING); + CVector carEnterPos; + carEnterPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + car->m_nGettingInFlags |= doorFlag; + m_vecOffsetSeek = carEnterPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + float zDiff = Max(0.0f, carEnterPos.z - GetPosition().z); + bUsesCollision = false; + + if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_LHS : ANIM_CAR_ALIGN_LHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, zDiff > 4.4f ? ANIM_CAR_ALIGNHI_RHS : ANIM_CAR_ALIGN_RHS, 4.0f); + + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); +} + +void +CPed::SetBeingDraggedFromCar(CVehicle *veh, uint32 vehEnterType, bool quickJack) +{ + if (m_nPedState == PED_DRAG_FROM_CAR) + return; + + bUsesCollision = false; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_nLastPedState = PED_IDLE; + SetMoveState(PEDMOVE_STILL); + m_pSeekTarget = veh; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_vehEnterType = vehEnterType; + if (m_vehEnterType == CAR_DOOR_LF) { + if (veh->pDriver && veh->pDriver->IsPlayer()) + veh->SetStatus(STATUS_PLAYER_DISABLED); + else + veh->SetStatus(STATUS_ABANDONED); + } + RemoveInCarAnims(); + SetMoveState(PEDMOVE_NONE); + LineUpPedWithCar(LINE_UP_TO_CAR_START); + m_pVehicleAnim = nil; + m_nPedState = PED_DRAG_FROM_CAR; + bChangedSeat = false; + bWillBeQuickJacked = quickJack; + + SetHeading(m_fRotationCur); + + Say(SOUND_PED_CAR_JACKED); + SetRadioStation(); + veh->m_nGettingOutFlags |= GetCarDoorFlag(m_vehEnterType); +} + +void +CPed::BeingDraggedFromCar(void) +{ + CAnimBlendAssociation *animAssoc; + AnimationId enterAnim; + bool dontRunAnim = false; + PedLineUpPhase lineUpType; + + if (!m_pVehicleAnim) { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITP); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SITPLO); + } + } + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + if (bWillBeQuickJacked) { + enterAnim = ANIM_CAR_QJACKED; + } else if (m_pMyVehicle->bLowVehicle) { + enterAnim = ANIM_CAR_LJACKED_LHS; + } else { + enterAnim = ANIM_CAR_JACKED_LHS; + } + } else if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + if (m_pMyVehicle->bLowVehicle) + enterAnim = ANIM_CAR_LJACKED_RHS; + else + enterAnim = ANIM_CAR_JACKED_RHS; + } else + dontRunAnim = true; + + + if (!dontRunAnim) + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), 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); +#ifdef VC_PED_PORTS + if (m_objective == OBJECTIVE_LEAVE_CAR_AND_DIE) { + if (m_pMyVehicle) { + m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, NUM_ANIMS, m_pVehicleAnim->currentTime * 5.0f); + } + } +#endif +} + +void +CPed::SetEnterCar(CVehicle *car, uint32 unused) +{ + if (CCranes::IsThisCarBeingCarriedByAnyCrane(car)) { + RestorePreviousState(); + RestorePreviousObjective(); + } else { + uint8 doorFlag; + eDoors door; + switch (m_vehEnterType) { + case CAR_DOOR_RF: + doorFlag = CAR_DOOR_FLAG_RF; + door = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_RR: + doorFlag = CAR_DOOR_FLAG_RR; + door = DOOR_REAR_RIGHT; + break; + case CAR_DOOR_LF: + doorFlag = CAR_DOOR_FLAG_LF; + door = DOOR_FRONT_LEFT; + break; + case CAR_DOOR_LR: + doorFlag = CAR_DOOR_FLAG_LR; + door = DOOR_REAR_LEFT; + break; + default: + doorFlag = CAR_DOOR_FLAG_UNKNOWN; + break; + } + if (!IsPedInControl() || m_fHealth <= 0.0f + || doorFlag & car->m_nGettingInFlags || doorFlag & car->m_nGettingOutFlags + || car->bIsBeingCarJacked || m_pVehicleAnim + || doorFlag && !car->IsDoorReady(door) && !car->IsDoorFullyOpen(door)) + SetMoveState(PEDMOVE_STILL); + else + SetEnterCar_AllClear(car, m_vehEnterType, doorFlag); + } +} + +void +CPed::SetEnterCar_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +{ + float zDiff = 0.0f; + RemoveWeaponWhenEnteringVehicle(); + car->m_nGettingInFlags |= doorFlag; + bVehEnterDoorIsBlocked = false; + if (m_nPedState != PED_SEEK_CAR && m_nPedState != PED_SEEK_IN_BOAT) + SetStoredState(); + + m_pSeekTarget = car; + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + m_vehEnterType = doorNode; + m_nPedState = PED_ENTER_CAR; + if (m_vehEnterType == CAR_DOOR_RF && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && car->m_vehType != VEHICLE_TYPE_BIKE) { + car->bIsBeingCarJacked = true; + } + + m_pMyVehicle = (CVehicle*)m_pSeekTarget; + m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); + ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; + bUsesCollision = false; + CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + + // Because buses have stairs + if (!m_pMyVehicle->bIsBus) + zDiff = Max(0.0f, doorOpenPos.z - GetPosition().z); + + m_vecOffsetSeek = doorOpenPos - GetPosition(); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 600; + if (car->IsBoat()) { +#ifdef VC_PED_PORTS + // VC checks for handling flag, but we can't do that + if(car->GetModelIndex() == MI_SPEEDER) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); + + PedSetInCarCB(nil, this); + bVehExitWillBeInstant = true; +#else + +#ifndef FIX_BUGS + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_BOAT, 100.0f); +#else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, car->GetDriverAnim(), 100.0f); +#endif + + m_pVehicleAnim->SetFinishCallback(PedSetInCarCB, this); +#endif + if (IsPlayer()) + CWaterLevel::AllocateBoatWakeArray(); + } else { + if (zDiff > 4.4f) { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGNHI_LHS, 4.0f); + + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_RHS, 4.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_ALIGN_LHS, 4.0f); + } + m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); + car->AutoPilot.m_nCruiseSpeed = 0; + } +} + +void +CPed::EnterCar(void) +{ + if (IsNotInWreckedVehicle() && m_fHealth > 0.0f) { + CVehicle *veh = (CVehicle*)m_pSeekTarget; + + // Not used. + // CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehEnterType); + + if (veh->CanPedOpenLocks(this)) { + if (m_vehEnterType && m_pVehicleAnim) { + veh->ProcessOpenDoor(m_vehEnterType, m_pVehicleAnim->animId, m_pVehicleAnim->currentTime); + } + } + bIsInTheAir = false; + LineUpPedWithCar(LINE_UP_TO_CAR_START); + } else { + QuitEnteringCar(); + SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } +} + +void +CPed::QuitEnteringCar(void) +{ + CVehicle *veh = m_pMyVehicle; + if (m_pVehicleAnim) + m_pVehicleAnim->blendDelta = -1000.0f; + + RestartNonPartialAnims(); + + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE)) + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + + if (veh) { + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_nPedState == PED_CARJACK) + veh->bIsBeingCarJacked = false; + + if (veh->m_nNumGettingIn != 0) + veh->m_nNumGettingIn--; + +#ifdef VC_PED_PORTS + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) + RestorePreviousObjective(); +#endif + + veh->m_nGettingInFlags &= ~GetCarDoorFlag(m_vehEnterType); + } + + bUsesCollision = true; + + ReplaceWeaponWhenExitingVehicle(); + + if (DyingOrDead()) { + if (m_pVehicleAnim) { + m_pVehicleAnim->blendDelta = -4.0f; + m_pVehicleAnim->flags |= ASSOC_DELETEFADEDOUT; + m_pVehicleAnim->flags &= ~ASSOC_RUNNING; + } + } else + SetIdle(); + + m_pVehicleAnim = nil; + + if (veh) { +#ifdef VC_PED_PORTS + if (veh->AutoPilot.m_nCruiseSpeed == 0 && veh->VehicleCreatedBy == RANDOM_VEHICLE) +#else + if (veh->AutoPilot.m_nCruiseSpeed == 0) +#endif + veh->AutoPilot.m_nCruiseSpeed = 17; + } +} + +void +AddYardieDoorSmoke(CVehicle *veh, uint32 doorNode) +{ + eDoors door; + switch (doorNode) { + case CAR_DOOR_RF: + door = DOOR_FRONT_RIGHT; + break; + case CAR_DOOR_LF: + door = DOOR_FRONT_LEFT; + break; + default: + break; + } + + if (!veh->IsDoorMissing(door) && veh->IsComponentPresent(doorNode)) { + CVector pos; +#ifdef FIX_BUGS + veh->GetComponentWorldPosition(doorNode, pos); +#else + veh->GetComponentWorldPosition(CAR_DOOR_LF, pos); +#endif + CParticle::AddYardieDoorSmoke(pos, veh->GetMatrix()); + } +} + +// Seperate function in VC, more logical. Not sure is it inlined in III. +void +CPed::SetExitBoat(CVehicle *boat) +{ +#ifndef VC_PED_PORTS + m_nPedState = PED_IDLE; + CVector firstPos = GetPosition(); + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + if (boat->GetModelIndex() == MI_SPEEDER && boat->IsUpsideDown()) { + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS, 8.0f); + m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); + m_vehEnterType = CAR_DOOR_RF; + m_nPedState = PED_EXIT_CAR; + } else { + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + } + SetPosition(firstPos); + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; + bTryingToReachDryLand = true; +#else + m_nPedState = PED_IDLE; + CVector newPos = GetPosition(); + RemoveInCarAnims(); + CColModel* boatCol = boat->GetColModel(); + if (boat->IsUpsideDown()) { + newPos = { 0.0f, 0.0f, boatCol->boundingBox.min.z }; + newPos = boat->GetMatrix() * newPos; + newPos.z += 1.0f; + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + } else { +/* if (boat->m_modelIndex != MI_SKIMMER || boat->bIsInWater) { + if (boat->m_modelIndex == MI_SKIMMER) + newPos.z += 2.0f +*/ + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + m_pCurSurface = boat; + m_pCurSurface->RegisterReference((CEntity**)&m_pCurSurface); + m_pCurrentPhysSurface = boat; + CColPoint foundCol; + CEntity *foundEnt = nil; + if (CWorld::ProcessVerticalLine(newPos, newPos.z - 1.4f, foundCol, foundEnt, false, true, false, false, false, false, nil)) + newPos.z = FEET_OFFSET + foundCol.point.z; +/* // VC specific + } else { + m_vehEnterType = CAR_DOOR_RF; + PedSetOutCarCB(nil, this); + bIsStanding = true; + SetMoveState(PEDMOVE_STILL); + bTryingToReachDryLand = true; + float upMult = 1.04f + boatCol->boundingBox.min.z; + float rightMult = 0.6f * boatCol->boundingBox.max.x; + newPos = upMult * boat->GetUp() + rightMult * boat->GetRight() + boat->GetPosition(); + GetPosition() = newPos; + if (m_pMyVehicle) { + PositionPedOutOfCollision(); + } else { + m_pMyVehicle = boat; + PositionPedOutOfCollision(); + m_pMyVehicle = nil; + } + return; + } +*/ } + SetPosition(newPos); + SetMoveState(PEDMOVE_STILL); + m_vecMoveSpeed = boat->m_vecMoveSpeed; +#endif + // Not there in VC. + CWaterLevel::FreeBoatWakeArray(); +} + +// wantedDoorNode = 0 means that func. will determine it +void +CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) +{ + uint32 optedDoorNode = wantedDoorNode; + bool teleportNeeded = false; + bool isLow = !!veh->bLowVehicle; + if (!veh->CanPedExitCar()) { + if (veh->pDriver && !veh->pDriver->IsPlayer()) { + veh->AutoPilot.m_nCruiseSpeed = 0; + veh->AutoPilot.m_nCarMission = MISSION_NONE; + } + return; + } + + if (m_nPedState == PED_EXIT_CAR || m_nPedState == PED_DRAG_FROM_CAR) + return; + + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + if (wantedDoorNode == 0) { + optedDoorNode = CAR_DOOR_LF; + if (!veh->bIsBus) { + if (veh->pDriver == this) { + optedDoorNode = CAR_DOOR_LF; + } else if (veh->pPassengers[0] == this) { + optedDoorNode = CAR_DOOR_RF; + } else if (veh->pPassengers[1] == this) { + optedDoorNode = CAR_DOOR_LR; + } else if (veh->pPassengers[2] == this) { + optedDoorNode = CAR_DOOR_RR; + } else { + for (int i = 3; i < veh->m_nNumMaxPassengers; ++i) { + if (veh->pPassengers[i] == this) { + if (i & 1) + optedDoorNode = CAR_DOOR_RR; + else + optedDoorNode = CAR_DOOR_LR; + + break; + } + } + } + } + } + bool someoneExitsFromOurExitDoor = false; + bool someoneEntersFromOurExitDoor = false; + switch (optedDoorNode) { + case CAR_DOOR_RF: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RF) + someoneExitsFromOurExitDoor = true; + break; + case CAR_DOOR_RR: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_RR) + someoneExitsFromOurExitDoor = true; + break; + case CAR_DOOR_LF: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LF) + someoneExitsFromOurExitDoor = true; + break; + case CAR_DOOR_LR: + if (veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) + someoneEntersFromOurExitDoor = true; + if (veh->m_nGettingOutFlags & CAR_DOOR_FLAG_LR) + someoneExitsFromOurExitDoor = true; + break; + default: + break; + } + if (someoneEntersFromOurExitDoor && m_objective == OBJECTIVE_LEAVE_CAR) { + RestorePreviousObjective(); + return; + } + if (!someoneExitsFromOurExitDoor || m_nPedType == PEDTYPE_COP && veh->bIsBus) { + // Again, unused... + // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); + bool thereIsRoom = veh->IsRoomForPedToLeaveCar(optedDoorNode, nil); + if (veh->IsOnItsSide()) { + teleportNeeded = true; + } else if (!thereIsRoom) { + bool trySideSeat = false; + CPed *pedOnSideSeat = nil; + switch (optedDoorNode) { + case CAR_DOOR_RF: + if (veh->pDriver || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LF) { + pedOnSideSeat = veh->pDriver; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_LF; + + break; + case CAR_DOOR_RR: + if (veh->pPassengers[1] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) { + pedOnSideSeat = veh->pPassengers[1]; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_LR; + + break; + case CAR_DOOR_LF: + if (veh->pPassengers[0] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) { + pedOnSideSeat = veh->pPassengers[0]; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_RF; + + break; + case CAR_DOOR_LR: + if (veh->pPassengers[2] || veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) { + pedOnSideSeat = (CPed*)veh->pPassengers[2]; + trySideSeat = true; + } else + optedDoorNode = CAR_DOOR_RR; + + break; + default: + break; + } + if (trySideSeat) { + if (!pedOnSideSeat || !IsPlayer() && CharCreatedBy != MISSION_CHAR) + return; + + switch (optedDoorNode) { + case CAR_DOOR_RF: + optedDoorNode = CAR_DOOR_LF; + break; + case CAR_DOOR_RR: + optedDoorNode = CAR_DOOR_LR; + break; + case CAR_DOOR_LF: + optedDoorNode = CAR_DOOR_RF; + break; + case CAR_DOOR_LR: + optedDoorNode = CAR_DOOR_RR; + break; + default: + break; + } + } + // ... + // CVector exitPos = GetPositionToOpenCarDoor(veh, optedDoorNode); + if (!veh->IsRoomForPedToLeaveCar(optedDoorNode, nil)) { + if (!IsPlayer() && CharCreatedBy != MISSION_CHAR) + return; + + teleportNeeded = true; + } + } + if (m_nPedState == PED_FLEE_POS) { + m_nLastPedState = PED_FLEE_POS; + m_nPrevMoveState = PEDMOVE_RUN; + SetMoveState(PEDMOVE_SPRINT); + } else { + m_nLastPedState = PED_IDLE; + m_nPrevMoveState = PEDMOVE_STILL; + SetMoveState(PEDMOVE_STILL); + } + + ReplaceWeaponWhenExitingVehicle(); + bUsesCollision = false; + m_pSeekTarget = veh; + m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget); + m_vehEnterType = optedDoorNode; + m_nPedState = PED_EXIT_CAR; + if (m_pVehicleAnim && m_pVehicleAnim->flags & ASSOC_PARTIAL) + m_pVehicleAnim->blendDelta = -1000.0f; + SetMoveState(PEDMOVE_NONE); + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 100.0f); + RemoveInCarAnims(); + veh->AutoPilot.m_nCruiseSpeed = 0; + if (teleportNeeded) { + PedSetOutCarCB(nil, this); + + // This is same code with CPedPlacement::FindZCoorForPed, except we start from z + 1.5 and also check vehicles. + float zForPed; + float startZ = GetPosition().z - 100.0f; + float foundColZ = -100.0f; + float foundColZ2 = -100.0f; + CColPoint foundCol; + CEntity* foundEnt; + + CVector vec = GetPosition(); + vec.z += 1.5f; + + if (CWorld::ProcessVerticalLine(vec, startZ, foundCol, foundEnt, true, true, false, false, true, false, nil)) + 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, true, false, false, true, false, nil)) + foundColZ2 = foundCol.point.z; + + zForPed = Max(foundColZ, foundColZ2); + + if (zForPed > -99.0f) + GetMatrix().GetPosition().z = FEET_OFFSET + zForPed; + } else { + if (veh->GetUp().z > -0.8f) { + bool addDoorSmoke = false; + if (veh->GetModelIndex() == MI_YARDIE) + addDoorSmoke = true; + + switch (m_vehEnterType) { + case CAR_DOOR_RF: + if (veh->bIsBus) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); + } else { + if (isLow) + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); + else + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); + + if (addDoorSmoke) + AddYardieDoorSmoke(veh, CAR_DOOR_RF); + } + break; + case CAR_DOOR_RR: + if (veh->bIsVan) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT); + } else if (isLow) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_RHS); + } else { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_RHS); + } + break; + case CAR_DOOR_LF: + if (veh->bIsBus) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_COACH_OUT_L); + } else { + if (isLow) + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); + else + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); + + if (addDoorSmoke) + AddYardieDoorSmoke(veh, CAR_DOOR_LF); + } + break; + case CAR_DOOR_LR: + if (veh->bIsVan) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_VAN_GETOUT_L); + } else if (isLow) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LOW_LHS); + } else { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_GETOUT_LHS); + } + break; + default: + break; + } + if (!bBusJacked) { + switch (m_vehEnterType) { + case CAR_DOOR_RF: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RF; + break; + case CAR_DOOR_RR: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_RR; + break; + case CAR_DOOR_LF: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LF; + break; + case CAR_DOOR_LR: + veh->m_nGettingOutFlags |= CAR_DOOR_FLAG_LR; + break; + default: + break; + } + } + m_pVehicleAnim->SetFinishCallback(PedAnimStepOutCarCB, this); + } else { + if (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS2); + } else if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) { + m_pVehicleAnim = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_CRAWLOUT_RHS); + } + m_pVehicleAnim->SetFinishCallback(PedSetOutCarCB, this); + } + } + bChangedSeat = false; + if (veh->bIsBus) + bRenderPedInCar = true; + + SetRadioStation(); + if (veh->pDriver == this) { + if (IsPlayer()) + veh->SetStatus(STATUS_PLAYER_DISABLED); + else + veh->SetStatus(STATUS_ABANDONED); + } + } +} + +void +CPed::ExitCar(void) +{ + if (!m_pVehicleAnim) + return; + + AnimationId exitAnim = (AnimationId) m_pVehicleAnim->animId; + float animTime = m_pVehicleAnim->currentTime; + + m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, exitAnim, animTime); + + if (m_pSeekTarget) { + // Car is upside down + if (m_pMyVehicle->GetUp().z > -0.8f) { + if (exitAnim == ANIM_CAR_CLOSE_RHS || exitAnim == ANIM_CAR_CLOSE_LHS || animTime > 0.3f) + LineUpPedWithCar(LINE_UP_TO_CAR_END); + else + LineUpPedWithCar((m_pMyVehicle->GetModelIndex() == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START)); + } else { + LineUpPedWithCar(LINE_UP_TO_CAR_END); + } + } + + // If there is someone in front of the door, make him fall while we exit. + if (m_nPedState == PED_EXIT_CAR) { + CPed *foundPed = nil; + for (int i = 0; i < m_numNearPeds; i++) { + if ((m_nearPeds[i]->GetPosition() - GetPosition()).MagnitudeSqr2D() < 0.04f) { + foundPed = m_nearPeds[i]; + break; + } + } + if (foundPed && animTime > 0.4f && foundPed->IsPedInControl()) + foundPed->SetFall(1000, ANIM_KO_SKID_FRONT, 1); + } +} + +// This function was mostly duplicate of GetLocalPositionToOpenCarDoor, so I've used it. +CVector +CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component) +{ + CVector localPos; + CVector vehDoorPos; + + localPos = GetLocalPositionToOpenCarDoor(veh, component, 1.0f); + vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); + +/* + // Not used. + CVector localVehDoorOffset; + + if (veh->bIsVan && (component == VEHICLE_ENTER_REAR_LEFT || component == VEHICLE_ENTER_REAR_RIGHT)) { + localVehDoorOffset = vecPedVanRearDoorAnimOffset; + } else { + if (veh->bIsLow) { + localVehDoorOffset = vecPedCarDoorLoAnimOffset; + } else { + localVehDoorOffset = vecPedCarDoorAnimOffset; + } + } + + vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); +*/ + return vehDoorPos; +} + +void +CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen) +{ + CVector *enterOffset = nil; + if (m_vehEnterType == CAR_DOOR_LF && veh->pDriver + || m_vehEnterType == CAR_DOOR_RF && veh->pPassengers[0] + || m_vehEnterType == CAR_DOOR_LR && veh->pPassengers[1] + || m_vehEnterType == CAR_DOOR_RR && veh->pPassengers[2]) + { + enterOffset = &vecPedQuickDraggedOutCarAnimOffset; + } + + CVector lfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LF); + CVector rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); + + // Left front door is closer + if ((lfPos - GetPosition()).MagnitudeSqr2D() < (rfPos - GetPosition()).MagnitudeSqr2D()) { + + if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { + m_vehEnterType = CAR_DOOR_RF; + posToOpen = rfPos; + } + } else { + + if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) { + + CPed *rfPassenger = veh->pPassengers[0]; + if (rfPassenger && (rfPassenger->m_leader == this || rfPassenger->bDontDragMeOutCar || + veh->VehicleCreatedBy == MISSION_VEHICLE && m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) + || (veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } else { + m_vehEnterType = CAR_DOOR_RF; + posToOpen = rfPos; + } + } else if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) { + m_vehEnterType = CAR_DOOR_LF; + posToOpen = lfPos; + } + } +} + +bool +CPed::GetNearestPassengerDoor(CVehicle *veh, CVector &posToOpen) +{ + CVector rfPos, lrPos, rrPos; + bool canEnter = false; + + CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(veh->GetModelIndex()); + + switch (veh->GetModelIndex()) { + case MI_BUS: + m_vehEnterType = CAR_DOOR_RF; + posToOpen = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); + return true; + case MI_RHINO: + default: + break; + } + + CVector2D rfPosDist(999.0f, 999.0f); + CVector2D lrPosDist(999.0f, 999.0f); + CVector2D rrPosDist(999.0f, 999.0f); + + if (!veh->pPassengers[0] + && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, nil)) { + + rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF); + canEnter = true; + rfPosDist = rfPos - GetPosition(); + } + if (vehModel->m_numDoors == 4) { + if (!veh->pPassengers[1] + && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LR, nil)) { + lrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LR); + canEnter = true; + lrPosDist = lrPos - GetPosition(); + } + if (!veh->pPassengers[2] + && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR) + && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RR, nil)) { + rrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RR); + canEnter = true; + rrPosDist = rrPos - GetPosition(); + } + + // When the door we should enter is blocked by some object. + if (!canEnter) + veh->ShufflePassengersToMakeSpace(); + } + + CVector2D nextToCompare = rfPosDist; + posToOpen = rfPos; + m_vehEnterType = CAR_DOOR_RF; + if (lrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { + m_vehEnterType = CAR_DOOR_LR; + posToOpen = lrPos; + nextToCompare = lrPosDist; + } + + if (rrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) { + m_vehEnterType = CAR_DOOR_RR; + posToOpen = rrPos; + } + return canEnter; +} + +void +CPed::GoToNearestDoor(CVehicle *veh) +{ + CVector posToOpen; + GetNearestDoor(veh, posToOpen); + SetSeek(posToOpen, 0.5f); + SetMoveState(PEDMOVE_RUN); +} + +void +CPed::SetAnimOffsetForEnterOrExitVehicle(void) +{ + // FIX: If there were no translations on enter anims, there were overflows all over this function. + + CAnimBlendHierarchy *enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_JACKED_LHS)->hierarchy; + CAnimBlendSequence *seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedDraggedOutCarAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LHS)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedCarDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedCarDoorAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedCarDoorLoAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedCarDoorLoAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_QJACKED)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedQuickDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedQuickDraggedOutCarAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_VAN_GETIN_L)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedVanRearDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedVanRearDoorAnimOffset = lastFrame->translation; + } + } + + enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_TRAIN_GETOUT)->hierarchy; + seq = enterAssoc->sequences; + CAnimManager::UncompressAnimation(enterAssoc); + if (seq->numFrames > 0) { + if (!seq->HasTranslation()) + vecPedTrainDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f); + else { + KeyFrameTrans *lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1); + vecPedTrainDoorAnimOffset = lastFrame->translation; + } + } +} + +void +CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + CVector finalPos; + CVector draggedOutOffset; + + CMatrix pedMat(ped->GetMatrix()); + ped->bUsesCollision = true; + ped->RestartNonPartialAnims(); + draggedOutOffset = vecPedQuickDraggedOutCarAnimOffset; + if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) + draggedOutOffset.x = -draggedOutOffset.x; + + finalPos = Multiply3x3(pedMat, draggedOutOffset) + ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&finalPos); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(finalPos); + + if (veh) { + ped->m_fRotationDest = veh->GetForward().Heading() - HALFPI; + ped->m_fRotationCur = ped->m_fRotationDest; + ped->CalculateNewOrientation(); + + if (!veh->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedQuickDraggedOutCarAnimOffset)) + ped->PositionPedOutOfCollision(); + } + + if (!ped->CanSetPedState()) + return; + + ped->SetIdle(); + if (veh) { + if (ped->bFleeAfterExitingCar) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(veh->GetPosition(), 14000); + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + + } else if (ped->bGonnaKillTheCarJacker) { + ped->bGonnaKillTheCarJacker = false; + if (ped->m_pedInObjective && CGeneral::GetRandomNumber() & 1) { + if (ped->m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, ped->m_pedInObjective); + + } else { + CPed *driver = veh->pDriver; + if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { + ped->SetFlee(veh->GetPosition(), 14000); + } else { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + } + ped->bUsePedNodeSeek = true; + ped->m_pNextPathNode = nil; + ped->Say(SOUND_PED_FLEE_RUN); + } + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear + && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE + && veh->pDriver && veh->pDriver->IsPlayer() + && !CTheScripts::IsPlayerOnAMission()) { + +#ifndef VC_PED_PORTS + if (CGeneral::GetRandomNumber() < MYRAND_MAX / 2) { + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, veh->pDriver); + } else +#endif + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); + +#ifdef VC_PED_PORTS + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear + && ped->CharCreatedBy != MISSION_CHAR && veh->VehicleCreatedBy != MISSION_VEHICLE + && !veh->pDriver && FindPlayerPed()->m_carInObjective == veh + && !CTheScripts::IsPlayerOnAMission()) { + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, veh); +#endif + } else { + ped->SetFindPathAndFlee(veh->GetPosition(), 10000); + if (CGeneral::GetRandomNumber() & 1 || ped->m_pedStats->m_fear > 70) { + ped->SetMoveState(PEDMOVE_SPRINT); + ped->Say(SOUND_PED_FLEE_SPRINT); + } else { + ped->Say(SOUND_PED_FLEE_RUN); + } + } + } + if (ped->m_nLastPedState == PED_IDLE) + ped->m_nLastPedState = PED_WANDER_PATH; +} + +void +CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed *ped = (CPed*)arg; + + ped->bUsesCollision = true; + ped->RestartNonPartialAnims(); + bool itsRearDoor = false; + + if (ped->m_vehEnterType == CAR_DOOR_RF || ped->m_vehEnterType == CAR_DOOR_RR) + itsRearDoor = true; + + CMatrix pedMat(ped->GetMatrix()); + CVector posAfterBeingDragged = Multiply3x3(pedMat, (itsRearDoor ? -vecPedDraggedOutCarAnimOffset : vecPedDraggedOutCarAnimOffset)); + posAfterBeingDragged += ped->GetPosition(); +#ifndef VC_PED_PORTS + posAfterBeingDragged.z += 1.0f; +#endif + CPedPlacement::FindZCoorForPed(&posAfterBeingDragged); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(posAfterBeingDragged); + + if (ped->m_pMyVehicle && !ped->m_pMyVehicle->IsRoomForPedToLeaveCar(ped->m_vehEnterType, &vecPedDraggedOutCarAnimOffset)) { + ped->PositionPedOutOfCollision(); + } + + if (!ped->CanSetPedState()) + return; + + if (!ped->m_pMyVehicle) { + ped->SetIdle(); + ped->SetGetUp(); + return; + } + + CPed *driver = ped->m_pMyVehicle->pDriver; + + if (ped->IsPlayer()) { + ped->SetIdle(); + + } else if (ped->bFleeAfterExitingCar) { + ped->bFleeAfterExitingCar = false; + ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); + + } else if (ped->bWanderPathAfterExitingCar) { + ped->SetWanderPath(CGeneral::GetRandomNumberInRange(0.0f, 8.0f)); + ped->bWanderPathAfterExitingCar = false; + + } else if (ped->bGonnaKillTheCarJacker) { + // Kill objective is already set at this point. + + ped->bGonnaKillTheCarJacker = false; + if (!ped->m_pedInObjective || !(CGeneral::GetRandomNumber() & 1)) { + if (!driver || driver == ped || driver->IsPlayer() && CTheScripts::IsPlayerOnAMission()) { + ped->m_nPedState = PED_NONE; + ped->m_nLastPedState = PED_NONE; + ped->SetFlee(ped->m_pMyVehicle->GetPosition(), 4000); + } else { + ped->ClearObjective(); + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); + } + } + + } else if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR + && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && driver + && driver->IsPlayer() && !CTheScripts::IsPlayerOnAMission()) { + +#ifndef VC_PED_PORTS + if (CGeneral::GetRandomNumber() & 1) + ped->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, driver); + else +#endif + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); + + } else { +#ifdef VC_PED_PORTS + if (ped->m_pedStats->m_temper > ped->m_pedStats->m_fear && ped->CharCreatedBy != MISSION_CHAR + && ped->m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE && !driver + && FindPlayerPed()->m_carInObjective == ped->m_pMyVehicle && !CTheScripts::IsPlayerOnAMission()) + ped->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, ped->m_pMyVehicle); + else +#endif + { + ped->m_nPedState = PED_NONE; + ped->m_nLastPedState = PED_NONE; + ped->SetFindPathAndFlee(ped->m_pMyVehicle->GetPosition(), 10000); + } + } + ped->SetGetUp(); +} + +uint8 +CPed::GetNearestTrainDoor(CVehicle *train, CVector &doorPos) +{ + GetNearestTrainPedPosition(train, doorPos); +/* + // Not used. + CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(train->m_modelIndex); + CMatrix trainMat = CMatrix(train->GetMatrix()); + + doorPos = trainModel->m_positions[m_vehEnterType]; + doorPos.x -= 1.5f; + doorPos = Multiply3x3(trainMat, doorPos); + doorPos += train->GetPosition(); +*/ + return 1; +} + +uint8 +CPed::GetNearestTrainPedPosition(CVehicle *train, CVector &enterPos) +{ + CVector enterStepOffset; + CVehicleModelInfo *trainModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(train->GetModelIndex()); + CMatrix trainMat = CMatrix(train->GetMatrix()); + CVector leftEntryPos, rightEntryPos, midEntryPos; + float distLeftEntry, distRightEntry, distMidEntry; + + // enterStepOffset = vecPedCarDoorAnimOffset; + enterStepOffset = CVector(1.5f, 0.0f, 0.0f); + + if (train->pPassengers[TRAIN_POS_LEFT_ENTRY]) { + distLeftEntry = 999.0f; + } else { + leftEntryPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterStepOffset; + leftEntryPos = Multiply3x3(trainMat, leftEntryPos); + leftEntryPos += train->GetPosition(); + distLeftEntry = (leftEntryPos - GetPosition()).Magnitude(); + } + + if (train->pPassengers[TRAIN_POS_MID_ENTRY]) { + distMidEntry = 999.0f; + } else { + midEntryPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterStepOffset; + midEntryPos = Multiply3x3(trainMat, midEntryPos); + midEntryPos += train->GetPosition(); + distMidEntry = (midEntryPos - GetPosition()).Magnitude(); + } + + if (train->pPassengers[TRAIN_POS_RIGHT_ENTRY]) { + distRightEntry = 999.0f; + } else { + rightEntryPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterStepOffset; + rightEntryPos = Multiply3x3(trainMat, rightEntryPos); + rightEntryPos += train->GetPosition(); + distRightEntry = (rightEntryPos - GetPosition()).Magnitude(); + } + + if (distMidEntry < distLeftEntry) { + if (distMidEntry < distRightEntry) { + enterPos = midEntryPos; + m_vehEnterType = TRAIN_POS_MID_ENTRY; + } else { + enterPos = rightEntryPos; + m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; + } + } else if (distRightEntry < distLeftEntry) { + enterPos = rightEntryPos; + m_vehEnterType = TRAIN_POS_RIGHT_ENTRY; + } else { + enterPos = leftEntryPos; + m_vehEnterType = TRAIN_POS_LEFT_ENTRY; + } + + return 1; +} + +void +CPed::PedSetInTrainCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed *ped = (CPed*)arg; + CTrain *veh = (CTrain*)ped->m_pMyVehicle; + + if (!veh) + return; + + ped->bInVehicle = true; + ped->m_nPedState = PED_DRIVING; + ped->RestorePreviousObjective(); + ped->SetMoveState(PEDMOVE_STILL); + veh->AddPassenger(ped); +} + +void +CPed::SetEnterTrain(CVehicle *train, uint32 unused) +{ + if (m_nPedState == PED_ENTER_TRAIN || !((CTrain*)train)->Doors[0].IsFullyOpen()) + return; + + /* + // Not used + CVector enterPos; + GetNearestTrainPedPosition(train, enterPos); + */ + m_fRotationCur = train->GetForward().Heading() - HALFPI; + m_pMyVehicle = train; + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + + m_nPedState = PED_ENTER_TRAIN; + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETIN, 4.0f); + m_pVehicleAnim->SetFinishCallback(PedSetInTrainCB, this); + bUsesCollision = false; + LineUpPedWithTrain(); + if (IsPlayer()) { + if (((CPlayerPed*)this)->m_bAdrenalineActive) + ((CPlayerPed*)this)->ClearAdrenaline(); + } +} + +void +CPed::EnterTrain(void) +{ + LineUpPedWithTrain(); +} + +void +CPed::SetPedPositionInTrain(void) +{ + LineUpPedWithTrain(); +} + +void +CPed::LineUpPedWithTrain(void) +{ + CVector lineUpPos; + CVehicleModelInfo *trainModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(m_pMyVehicle->GetModelIndex()); + CVector enterOffset(1.5f, 0.0f, -0.2f); + + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI; + m_fRotationDest = m_fRotationCur; + + if (!bInVehicle) { + GetNearestTrainDoor(m_pMyVehicle, lineUpPos); + lineUpPos.z += 0.2f; + } else { + if (m_pMyVehicle->pPassengers[TRAIN_POS_LEFT_ENTRY] == this) { + + lineUpPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterOffset; + + } else if (m_pMyVehicle->pPassengers[TRAIN_POS_MID_ENTRY] == this) { + + lineUpPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterOffset; + + } else if (m_pMyVehicle->pPassengers[TRAIN_POS_RIGHT_ENTRY] == this) { + + lineUpPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterOffset; + } + lineUpPos = Multiply3x3(m_pMyVehicle->GetMatrix(), lineUpPos); + lineUpPos += m_pMyVehicle->GetPosition(); + } + + if (m_pVehicleAnim) { + float percentageLeft = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength; + lineUpPos += (GetPosition() - lineUpPos) * percentageLeft; + } + + SetPosition(lineUpPos); + SetHeading(m_fRotationCur); +} + +void +CPed::SetExitTrain(CVehicle* train) +{ + if (m_nPedState == PED_EXIT_TRAIN || train->GetStatus() != STATUS_TRAIN_NOT_MOVING || !((CTrain*)train)->Doors[0].IsFullyOpen()) + return; + + /* + // Not used + CVector exitPos; + GetNearestTrainPedPosition(train, exitPos); + */ + m_nPedState = PED_EXIT_TRAIN; + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TRAIN_GETOUT, 4.0f); + m_pVehicleAnim->SetFinishCallback(PedSetOutTrainCB, this); + bUsesCollision = false; + LineUpPedWithTrain(); +} + +void +CPed::ExitTrain(void) +{ + LineUpPedWithTrain(); +} + +void +CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + CVehicle *veh = ped->m_pMyVehicle; + + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->blendDelta = -1000.0f; + + ped->bUsesCollision = true; + ped->m_pVehicleAnim = nil; + ped->bInVehicle = false; + ped->m_nPedState = PED_IDLE; + ped->RestorePreviousObjective(); + ped->SetMoveState(PEDMOVE_STILL); + + CMatrix pedMat(ped->GetMatrix()); + ped->m_fRotationCur = HALFPI + veh->GetForward().Heading(); + ped->m_fRotationDest = ped->m_fRotationCur; + CVector posAfterExit = Multiply3x3(pedMat, vecPedTrainDoorAnimOffset); + posAfterExit += ped->GetPosition(); + CPedPlacement::FindZCoorForPed(&posAfterExit); + ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + ped->SetPosition(posAfterExit); + ped->SetHeading(ped->m_fRotationCur); + veh->RemovePassenger(ped); +} + +void +CPed::RegisterThreatWithGangPeds(CEntity *attacker) +{ + CPed *attackerPed = nil; + if (attacker) { + if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (attacker->IsPed()) { + attackerPed = (CPed*)attacker; + } else { + if (!attacker->IsVehicle()) + return; + + attackerPed = ((CVehicle*)attacker)->pDriver; + if (!attackerPed) + return; + } + + if (attackerPed && (attackerPed->IsPlayer() || attackerPed->IsGangMember())) { + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed->IsPointerValid()) { + if (nearPed != this && nearPed->m_nPedType == m_nPedType) + nearPed->m_fearFlags |= CPedType::GetFlag(attackerPed->m_nPedType); + } + } + } + } + } + + if (attackerPed && attackerPed->IsPlayer() && (attackerPed->m_nPedState == PED_CARJACK || attackerPed->bInVehicle)) { + if (!attackerPed->m_pMyVehicle || attackerPed->m_pMyVehicle->GetModelIndex() != MI_TOYZ) { + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(GetPosition(), ENTER_CAR_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + if (lastVehicle > 8) + lastVehicle = 8; + + for (int j = 0; j < lastVehicle; ++j) { + CVehicle *nearVeh = (CVehicle*) vehicles[j]; + + if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { + CPed *nearVehDriver = nearVeh->pDriver; + + if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { + + if (nearVeh->IsVehicleNormal() && nearVeh->IsCar()) { + nearVeh->AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * nearVeh->pHandling->Transmission.fUnkMaxVelocity * 0.8f; + nearVeh->AutoPilot.m_nCarMission = MISSION_RAMPLAYER_FARAWAY; + nearVeh->SetStatus(STATUS_PHYSICS); + nearVeh->AutoPilot.m_nTempAction = TEMPACT_NONE; + nearVeh->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + } + } + } + } + } + } +} + +// Some helper function which doesn't exist in og game. +inline void +SelectClosestNodeForSeek(CPed *ped, CPathNode *node, CVector2D closeDist, CVector2D farDist, CPathNode *closeNode, CPathNode *closeNode2, int runCount = 3) +{ + for (int i = 0; i < node->numLinks; i++) { + + CPathNode *testNode = &ThePaths.m_pathNodes[ThePaths.ConnectedNode(i + node->firstLink)]; + + if (testNode && testNode != closeNode && testNode != closeNode2) { + CVector2D posDiff(ped->m_vecSeekPos - testNode->GetPosition()); + float dist = posDiff.MagnitudeSqr(); + + if (farDist.MagnitudeSqr() > dist) { + + if (closeDist.MagnitudeSqr() <= dist) { + ped->m_pNextPathNode = closeNode; + closeDist = posDiff; + } else { + ped->m_pNextPathNode = (closeNode2 ? closeNode2 : testNode); + farDist = posDiff; + } + } + + if (--runCount > 0) + SelectClosestNodeForSeek(ped, testNode, closeDist, farDist, closeNode, (closeNode2 ? closeNode2 : testNode), runCount); + } + } +} + +bool +CPed::FindBestCoordsFromNodes(CVector unused, CVector *bestCoords) +{ + if (m_pNextPathNode || !bUsePedNodeSeek) + return false; + + CVector ourPos = GetPosition(); + + int closestNodeId = ThePaths.FindNodeClosestToCoors(GetPosition(), 1, 999999.9f); + + CVector seekObjPos = m_vecSeekPos; + seekObjPos.z += 1.0f; + + if (CWorld::GetIsLineOfSightClear(ourPos, seekObjPos, true, false, false, true, false, false, false)) + return false; + + m_pNextPathNode = nil; + + CVector2D seekPosDist (m_vecSeekPos - ourPos); + + CPathNode *closestNode = &ThePaths.m_pathNodes[closestNodeId]; + CVector2D closeDist(m_vecSeekPos - closestNode->GetPosition()); + + SelectClosestNodeForSeek(this, closestNode, closeDist, seekPosDist, closestNode, nil); + + // Above function decided that going to the next node is more logical than seeking the object. + if (m_pNextPathNode) { + + CVector pathToNextNode = m_pNextPathNode->GetPosition() - ourPos; + if (pathToNextNode.MagnitudeSqr2D() < seekPosDist.MagnitudeSqr()) { + *bestCoords = m_pNextPathNode->GetPosition(); + return true; + } + m_pNextPathNode = nil; + } + + return false; +} + +bool +CPed::DuckAndCover(void) +{ + if (!m_pedInObjective || CTimer::GetTimeInMilliseconds() <= m_duckAndCoverTimer) + return false; + + if (bKindaStayInSamePlace){ + + if (CTimer::GetTimeInMilliseconds() <= m_leaveCarTimer) { + if (!m_pLookTarget || m_pLookTarget != m_pedInObjective) { + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + } + if (!bIsAimingGun) + SetAimFlag(m_pedInObjective); + + } else { + bCrouchWhenShooting = false; + bKindaStayInSamePlace = false; + bIsDucking = false; + bDuckAndCover = false; + m_headingRate = 10.0f; + m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(20000,30000); + if (m_pSeekTarget && m_pSeekTarget->IsVehicle()) + ((CVehicle*)m_pSeekTarget)->m_numPedsUseItAsCover--; + } + return false; + } + + bool justDucked = false; + CVehicle *foundVeh = nil; + float maxDist = 225.0f; + bIsDucking = false; + bCrouchWhenShooting = false; + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) { + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(pos, CHECK_NEARBY_THINGS_MAX_DIST, true, &lastVehicle, 6, vehicles, false, true, false, false, false); + + for (int i = 0; i < lastVehicle; i++) { + CVehicle *veh = (CVehicle*) vehicles[i]; + if (veh->m_vecMoveSpeed.Magnitude() <= 0.02f + && !veh->bIsBus + && !veh->bIsVan + && !veh->bIsBig + && veh->m_numPedsUseItAsCover < 3) { + float dist = (GetPosition() - veh->GetPosition()).MagnitudeSqr(); + if (dist < maxDist) { + maxDist = dist; + foundVeh = veh; + } + } + } + if (foundVeh) { + // Unused. + // CVector lfWheelPos, rfWheelPos; + // foundVeh->GetComponentWorldPosition(CAR_WHEEL_RF, rfWheelPos); + // foundVeh->GetComponentWorldPosition(CAR_WHEEL_LF, lfWheelPos); + CVector rightSide, leftSide; + + // 3 persons can use the car as cover. Found the correct position for us. + if (foundVeh->m_numPedsUseItAsCover == 2) { + rightSide = CVector(1.5f, -0.5f, 0.0f); + leftSide = CVector(-1.5f, -0.5f, 0.0f); + } else if (foundVeh->m_numPedsUseItAsCover == 1) { + rightSide = CVector(1.5f, 0.5f, 0.0f); + leftSide = CVector(-1.5f, 0.5f, 0.0f); + } else if (foundVeh->m_numPedsUseItAsCover == 0) { + rightSide = CVector(1.5f, 0.0f, 0.0f); + leftSide = CVector(-1.5f, 0.0f, 0.0f); + } + + CMatrix vehMatrix(foundVeh->GetMatrix()); + CVector duckAtRightSide = Multiply3x3(vehMatrix, rightSide) + foundVeh->GetPosition(); + + CVector duckAtLeftSide = Multiply3x3(vehMatrix, leftSide) + foundVeh->GetPosition(); + + CVector distWithPedRightSide = m_pedInObjective->GetPosition() - duckAtRightSide; + CVector distWithPedLeftSide = m_pedInObjective->GetPosition() - duckAtLeftSide; + + CVector duckPos; + if (distWithPedRightSide.MagnitudeSqr() <= distWithPedLeftSide.MagnitudeSqr()) + duckPos = duckAtLeftSide; + else + duckPos = duckAtRightSide; + + if (CWorld::TestSphereAgainstWorld(duckPos, 0.5f, nil, true, true, true, false, false, false) + && CWorld::GetIsLineOfSightClear(GetPosition(), duckPos, 1, 0, 0, 1, 0, 0, 0)) { + SetSeek(duckPos, 1.0f); + m_headingRate = 15.0f; + bIsRunning = true; + bDuckAndCover = true; + justDucked = true; + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 500; + if (foundVeh->bIsLawEnforcer) + m_carInObjective = foundVeh; + + // BUG? Shouldn't we register the reference? + m_pSeekTarget = foundVeh; + ClearPointGunAt(); + } else { + m_duckAndCoverTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(10000, 15000); + bDuckAndCover = false; + } + } else { + bDuckAndCover = false; + } + } + + if (!justDucked && !bDuckAndCover) + return false; + + if (!Seek()) + return true; + + bKindaStayInSamePlace = true; + bDuckAndCover = false; + m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f); + if (m_pSeekTarget && m_pSeekTarget->IsVehicle()) + ((CVehicle*)m_pSeekTarget)->m_numPedsUseItAsCover++; + + SetIdle(); + SetMoveState(PEDMOVE_STILL); + SetMoveAnim(); + if (!m_pLookTarget || m_pLookTarget != m_pedInObjective) { + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + } + + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(3000, 6000); + return false; +} + +CVector +CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset) +{ + CVector doorPos; + CMatrix vehMat(veh->GetMatrix()); + + doorPos = Multiply3x3(vehMat, GetLocalPositionToOpenCarDoor(veh, component, offset)); + + return veh->GetPosition() + doorPos; +} + +CVector +CPed::GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatPosMult) +{ + CVehicleModelInfo *vehModel; + CVector vehDoorPos; + CVector vehDoorOffset; + float seatOffset; + + vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(veh->GetModelIndex()); + if (veh->bIsVan && (component == CAR_DOOR_LR || component == CAR_DOOR_RR)) { + seatOffset = 0.0f; + vehDoorOffset = vecPedVanRearDoorAnimOffset; + } else { + seatOffset = veh->pHandling->fSeatOffsetDistance * seatPosMult; + if (veh->bLowVehicle) { + vehDoorOffset = vecPedCarDoorLoAnimOffset; + } else { + vehDoorOffset = vecPedCarDoorAnimOffset; + } + } + + switch (component) { + case CAR_DOOR_RF: + vehDoorPos = vehModel->GetFrontSeatPosn(); + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case CAR_DOOR_RR: + vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; + vehDoorPos.x += seatOffset; + vehDoorOffset.x = -vehDoorOffset.x; + break; + + case CAR_DOOR_LF: + vehDoorPos = vehModel->GetFrontSeatPosn(); + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + case CAR_DOOR_LR: + vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; + vehDoorPos.x = -(vehDoorPos.x + seatOffset); + break; + + default: + vehDoorPos = vehModel->GetFrontSeatPosn(); + vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); + } + return vehDoorPos - vehDoorOffset; +} + +void +CPed::SetDuck(uint32 time) +{ + if (bIsDucking || CTimer::GetTimeInMilliseconds() <= m_duckTimer) + return; + + if (bCrouchWhenShooting && (m_nPedState == PED_ATTACK || m_nPedState == PED_AIM_GUN)) { + CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); + if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_LOW, 4.0f); + bIsDucking = true; + m_duckTimer = CTimer::GetTimeInMilliseconds() + time; + } + } else { + CAnimBlendAssociation *duckAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!duckAssoc || duckAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_DUCK_DOWN, 4.0f); + bIsDucking = true; + m_duckTimer = CTimer::GetTimeInMilliseconds() + time; + } + } +} + +void +CPed::Duck(void) +{ + if (CTimer::GetTimeInMilliseconds() > m_duckTimer) + ClearDuck(); +} + +void +CPed::ClearDuck(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); + if (!animAssoc) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); + + if (!animAssoc) { + bIsDucking = false; + return; + } + } + + if (!bCrouchWhenShooting) + return; + + if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN) + return; + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT); + if (!animAssoc || animAssoc->blendDelta < 0.0f) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); + } +} + +void +CPed::InformMyGangOfAttack(CEntity *attacker) +{ + CPed *attackerPed; + + if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) + return; + + if (attacker->IsPed()) { + attackerPed = (CPed*)attacker; + } else { + if (!attacker->IsVehicle()) + return; + + attackerPed = ((CVehicle*)attacker)->pDriver; + if (!attackerPed) + return; + } + + if (attackerPed->m_nPedType == PEDTYPE_COP) + return; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + if (nearPed && nearPed != this) { + CPed *leader = nearPed->m_leader; + if (leader && leader == this && nearPed->m_pedStats->m_fear < nearPed->m_pedStats->m_temper) + { + nearPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, attackerPed); + nearPed->SetObjectiveTimer(30000); + } + } + } +} + +void +CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + CPed* ped = (CPed*)arg; + + CAutomobile* veh = (CAutomobile*)(ped->m_pMyVehicle); + + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + + if (veh->bLowVehicle) { + veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR_LOW, 1.0f); + } else { + veh->ProcessOpenDoor(CAR_DOOR_LF, ANIM_CAR_ROLLDOOR, 1.0f); + } + + veh->m_nGettingOutFlags &= ~CAR_DOOR_FLAG_LF; + + if (veh->Damage.GetDoorStatus(DOOR_FRONT_LEFT) == DOOR_STATUS_SWINGING) + veh->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_OK); +} + +void +CPed::SetSeekBoatPosition(CVehicle *boat) +{ + if (m_nPedState == PED_SEEK_IN_BOAT || boat->pDriver +#if defined VC_PED_PORTS || defined FIX_BUGS + || !IsPedInControl() +#endif + ) + return; + + SetStoredState(); + m_carInObjective = boat; + m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); + m_pMyVehicle = boat; + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_distanceToCountSeekDone = 0.5f; + m_nPedState = PED_SEEK_IN_BOAT; +} + +void +CPed::SeekBoatPosition(void) +{ + if (m_carInObjective && !m_carInObjective->pDriver) { + CVehicleModelInfo *boatModel = m_carInObjective->GetModelInfo(); + + CVector enterOffset; + enterOffset = boatModel->GetFrontSeatPosn(); + enterOffset.x = 0.0f; + CMatrix boatMat(m_carInObjective->GetMatrix()); + SetMoveState(PEDMOVE_WALK); + m_vecSeekPos = boatMat * enterOffset; + if (Seek()) { + // We arrived to the boat + m_vehEnterType = 0; + SetEnterCar(m_carInObjective, 0); + } + } else + RestorePreviousState(); +} + +bool +CPed::IsRoomToBeCarJacked(void) +{ + if (!m_pMyVehicle) + return false; + + CVector offset; + if (m_pMyVehicle->bLowVehicle || m_nPedType == PEDTYPE_COP) { + offset = vecPedDraggedOutCarAnimOffset; + } else { + offset = vecPedQuickDraggedOutCarAnimOffset; + } + + offset.z = 0.0f; + if (m_pMyVehicle->IsRoomForPedToLeaveCar(CAR_DOOR_LF, &offset)) { + return true; + } + + return false; +} + +void +CPed::RemoveInCarAnims(void) +{ + if (!IsPlayer()) + return; + + CAnimBlendAssociation *animAssoc; + + if (m_pMyVehicle && m_pMyVehicle->bLowVehicle) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + } else { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; + } + +#ifdef VC_PED_PORTS + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_BOAT); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; +#endif + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); + if (animAssoc) + animAssoc->blendDelta = -1000.0f; +} + +bool +CPed::PositionPedOutOfCollision(void) +{ + CVehicle *veh; + CVector posNearVeh; + CVector posSomewhereClose; + bool putNearVeh = false; + bool putSomewhereClose = false; + int smallestDistNearVeh = 999; + int smallestDistSomewhereClose = 999; + + if (!m_pMyVehicle) + return false; + + CVector vehPos = m_pMyVehicle->GetPosition(); + CVector potentialPos; + potentialPos.y = GetPosition().y - 3.5f; + potentialPos.z = GetPosition().z; + + for (int yTry = 0; yTry < 15; yTry++) { + potentialPos.x = GetPosition().x - 3.5f; + + for (int xTry = 0; xTry < 15; xTry++) { + CPedPlacement::FindZCoorForPed(&potentialPos); + CVector distVec = potentialPos - vehPos; + float dist = distVec.Magnitude(); + + // Makes close distances bigger for some reason. + float mult = (0.6f + dist) / dist; + CVector adjustedPotentialPos = distVec * mult + vehPos; + if (CWorld::GetIsLineOfSightClear(vehPos, adjustedPotentialPos, true, false, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, true, false, false, true, false, false)) { + + float potentialChangeSqr = (potentialPos - GetPosition()).MagnitudeSqr(); + veh = (CVehicle*)CWorld::TestSphereAgainstWorld(potentialPos, 0.6f, this, false, true, false, false, false, false); + if (veh) { + if (potentialChangeSqr < smallestDistNearVeh) { + posNearVeh = potentialPos; + putNearVeh = true; + smallestDistNearVeh = potentialChangeSqr; + } + } else if (potentialChangeSqr < smallestDistSomewhereClose) { + smallestDistSomewhereClose = potentialChangeSqr; + posSomewhereClose = potentialPos; + putSomewhereClose = true; + } + } + potentialPos.x += 0.5f; + } + potentialPos.y += 0.5f; + } + + if (!putSomewhereClose && !putNearVeh) + return false; + + // We refrain from using posNearVeh, probably because of it may be top of the vehicle. + if (putSomewhereClose) { + SetPosition(posSomewhereClose); + } else { + CVector vehSize = veh->GetModelInfo()->GetColModel()->boundingBox.max; + posNearVeh.z += vehSize.z; + SetPosition(posNearVeh); + } + return true; +} + +bool +CPed::WarpPedToNearLeaderOffScreen(void) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = m_leader->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = Min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} + +bool +CPed::WarpPedToNearEntityOffScreen(CEntity *warpTo) +{ + bool teleported = false; + if (GetIsOnScreen() || m_leaveCarTimer > CTimer::GetTimeInMilliseconds()) + return false; + + CVector warpToPos = warpTo->GetPosition(); + CVector distVec = warpToPos - GetPosition(); + float halfOfDist = distVec.Magnitude() * 0.5f; + CVector halfNormalizedDist = distVec / halfOfDist; + + CVector appropriatePos = GetPosition(); + CVector zCorrectedPos = appropriatePos; + int tryCount = Min(10, halfOfDist); + for (int i = 0; i < tryCount; ++i) { + appropriatePos += halfNormalizedDist; + CPedPlacement::FindZCoorForPed(&zCorrectedPos); + + if (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) + continue; + + appropriatePos.z = zCorrectedPos.z; + if (!TheCamera.IsSphereVisible(appropriatePos, 0.6f, &TheCamera.GetCameraMatrix()) + && CWorld::GetIsLineOfSightClear(appropriatePos, warpToPos, true, true, false, true, false, false, false) + && !CWorld::TestSphereAgainstWorld(appropriatePos, 0.6f, this, true, true, false, true, false, false)) { + teleported = true; + Teleport(appropriatePos); + } + } + m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; + return teleported; +} \ No newline at end of file diff --git a/src/peds/PedFight.cpp b/src/peds/PedFight.cpp new file mode 100644 index 00000000..21310aaa --- /dev/null +++ b/src/peds/PedFight.cpp @@ -0,0 +1,3250 @@ +#include "common.h" + +#include "main.h" +#include "RpAnimBlend.h" +#include "AnimBlendClumpData.h" +#include "AnimBlendAssociation.h" +#include "Camera.h" +#include "CarCtrl.h" +#include "Darkel.h" +#include "DMAudio.h" +#include "FileMgr.h" +#include "General.h" +#include "Object.h" +#include "Pad.h" +#include "Particle.h" +#include "Ped.h" +#include "PlayerPed.h" +#include "Stats.h" +#include "TempColModels.h" +#include "VisibilityPlugins.h" +#include "Vehicle.h" +#include "Automobile.h" +#include "WaterLevel.h" +#include "World.h" + +uint16 nPlayerInComboMove; + +RpClump *flyingClumpTemp; + +// This is beta fistfite.dat array. Not used anymore since they're being fetched from fistfite.dat. +FightMove tFightMoves[NUM_FIGHTMOVES] = { + {NUM_ANIMS, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_PUNCH_R, 0.2f, 8.0f / 30.0f, 0.0f, 0.3f, HITLEVEL_HIGH, 1, 0}, + {ANIM_FIGHT_IDLE, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_FIGHT_SH_F, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_FIGHT_KNEE, 4.0f / 30.0f, 0.2f, 0.0f, 0.6f, HITLEVEL_LOW, 2, 0}, + {ANIM_FIGHT_HEAD, 4.0f / 30.0f, 0.2f, 0.0f, 0.7f, HITLEVEL_HIGH, 3, 0}, + {ANIM_FIGHT_PUNCH, 4.0f / 30.0f, 7.0f / 30.0f, 10.0f / 30.0f, 0.4f, HITLEVEL_HIGH, 1, 0}, + {ANIM_FIGHT_LHOOK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.4f, HITLEVEL_HIGH, 3, 0}, + {ANIM_FIGHT_KICK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.5, HITLEVEL_MEDIUM, 2, 0}, + {ANIM_FIGHT_LONGKICK, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.5, HITLEVEL_MEDIUM, 4, 0}, + {ANIM_FIGHT_ROUNDHOUSE, 8.0f / 30.0f, 10.0f / 30.0f, 0.0f, 0.6f, HITLEVEL_MEDIUM, 4, 0}, + {ANIM_FIGHT_BODYBLOW, 5.0f / 30.0f, 7.0f / 30.0f, 0.0f, 0.35f, HITLEVEL_LOW, 2, 0}, + {ANIM_KICK_FLOOR, 10.0f / 30.0f, 14.0f / 30.0f, 0.0f, 0.4f, HITLEVEL_GROUND, 1, 0}, + {ANIM_HIT_FRONT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_BACK, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_RIGHT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_LEFT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_BODYBLOW, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_CHEST, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_HEAD, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_WALK, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_FLOOR_HIT, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_HIT_BEHIND, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, + {ANIM_FIGHT2_IDLE, 0.0f, 0.0f, 0.0f, 0.0f, HITLEVEL_NULL, 0, 0}, +}; + +static PedOnGroundState +CheckForPedsOnGroundToAttack(CPed *attacker, CPed **pedOnGround) +{ + PedOnGroundState stateToReturn; + float angleToFace; + CPed *currentPed = nil; + PedState currentPedState; + CPed *pedOnTheFloor = nil; + CPed *deadPed = nil; + CPed *pedBelow = nil; + bool foundDead = false; + bool foundOnTheFloor = false; + bool foundBelow = false; + float angleDiff; + float distance; + + if (!CGame::nastyGame) + return NO_PED; + + for (int currentPedId = 0; currentPedId < attacker->m_numNearPeds; currentPedId++) { + + currentPed = attacker->m_nearPeds[currentPedId]; + + CVector posDifference = currentPed->GetPosition() - attacker->GetPosition(); + distance = posDifference.Magnitude(); + + if (distance < 2.0f) { + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + currentPed->GetPosition().x, currentPed->GetPosition().y, + attacker->GetPosition().x, attacker->GetPosition().y); + + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + attacker->m_fRotationCur = CGeneral::LimitRadianAngle(attacker->m_fRotationCur); + + angleDiff = Abs(angleToFace - attacker->m_fRotationCur); + + if (angleDiff > PI) + angleDiff = 2 * PI - angleDiff; + + currentPedState = currentPed->m_nPedState; + + if (currentPed->OnGroundOrGettingUp()) { + if (distance < 2.0f && angleDiff < DEGTORAD(65.0f)) { + if (currentPedState == PED_DEAD) { + foundDead = 1; + if (!deadPed) + deadPed = currentPed; + } else if (!currentPed->IsPedHeadAbovePos(-0.6f)) { + foundOnTheFloor = 1; + if (!pedOnTheFloor) + pedOnTheFloor = currentPed; + } + } + } else if ((distance < 0.8f && angleDiff < DEGTORAD(75.0f)) + || (distance < 1.3f && angleDiff < DEGTORAD(55.0f)) + || (distance < 1.7f && angleDiff < DEGTORAD(35.0f)) + || (distance < 2.0f && angleDiff < DEGTORAD(30.0f))) { + + // Either this condition or below one was probably returning 4 early in development. See Fight(). + foundBelow = 1; + pedBelow = currentPed; + break; + } else { + if (angleDiff < DEGTORAD(75.0f)) { + foundBelow = 1; + if (!pedBelow) + pedBelow = currentPed; + } + } + } + } + + if (foundOnTheFloor) { + currentPed = pedOnTheFloor; + stateToReturn = PED_ON_THE_FLOOR; + } else if (foundDead) { + currentPed = deadPed; + stateToReturn = PED_DEAD_ON_THE_FLOOR; + } else if (foundBelow) { + currentPed = pedBelow; + stateToReturn = PED_IN_FRONT_OF_ATTACKER; + } else { + currentPed = nil; + stateToReturn = NO_PED; + } + + if (pedOnGround) + *pedOnGround = currentPed; + + return stateToReturn; +} + +void +CPed::SetPointGunAt(CEntity *to) +{ + if (to) { + SetLookFlag(to, true); + SetAimFlag(to); +#ifdef VC_PED_PORTS + SetLookTimer(INT32_MAX); +#endif + } + + if (m_nPedState == PED_AIM_GUN || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) + return; + + if (m_nPedState != PED_ATTACK) + SetStoredState(); + + m_nPedState = PED_AIM_GUN; + bIsPointingGunAt = true; + CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + SetMoveState(PEDMOVE_NONE); + + CAnimBlendAssociation *aimAssoc; + + if (bCrouchWhenShooting) + aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_Anim2ToPlay); + else + aimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), curWeapon->m_AnimToPlay); + + if (!aimAssoc || aimAssoc->blendDelta < 0.0f) { + if (bCrouchWhenShooting) + aimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, 4.0f); + else + aimAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay); + + aimAssoc->blendAmount = 0.0f; + aimAssoc->blendDelta = 8.0f; + } + if (to) + Say(SOUND_PED_ATTACK); +} + +void +CPed::PointGunAt(void) +{ + CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); + if (!weaponAssoc || weaponAssoc->blendDelta < 0.0f) + weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay); + + if (weaponAssoc && weaponAssoc->currentTime > weaponInfo->m_fAnimLoopStart) { + weaponAssoc->SetCurrentTime(weaponInfo->m_fAnimLoopStart); + weaponAssoc->flags &= ~ASSOC_RUNNING; + + if (weaponInfo->m_bCanAimWithArm) + m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; + else + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; + } +} + +void +CPed::ClearPointGunAt(void) +{ + CAnimBlendAssociation *animAssoc; + CWeaponInfo *weaponInfo; + + ClearLookFlag(); + ClearAimFlag(); + bIsPointingGunAt = false; +#ifndef VC_PED_PORTS + if (m_nPedState == PED_AIM_GUN) { + RestorePreviousState(); +#else + if (m_nPedState == PED_AIM_GUN || m_nPedState == PED_ATTACK) { + m_nPedState = PED_IDLE; + RestorePreviousState(); + } +#endif + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_AnimToPlay); + if (!animAssoc || animAssoc->blendDelta < 0.0f) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weaponInfo->m_Anim2ToPlay); + } + if (animAssoc) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->blendDelta = -4.0f; + } +#ifndef VC_PED_PORTS + } +#endif +} + +void +CPed::SetAttack(CEntity *victim) +{ + CPed *victimPed = nil; + if (victim && victim->IsPed()) + victimPed = (CPed*)victim; + + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); + if (animAssoc) { + animAssoc->blendDelta = -1000.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + + if (m_attackTimer > CTimer::GetTimeInMilliseconds() || m_nWaitState == WAITSTATE_SURPRISE) + return; + + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HGUN_RELOAD)) { + bIsAttacking = false; + return; + } + + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD)) { + if (!IsPlayer() || m_nPedState != PED_ATTACK || ((CPlayerPed*)this)->m_bHaveTargetSelected) + bIsAttacking = false; + else + bIsAttacking = true; + + return; + } + + CWeaponInfo *curWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + if (curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT && !IsPlayer()) { + if (GetWeapon()->HitsGround(this, nil, victim)) + return; + } + + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { + if (IsPlayer() || + (m_nPedState != PED_FIGHT && m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL && !(m_pedStats->m_flags & STAT_SHOPPING_BAGS))) { + + if (m_nPedState != PED_ATTACK) { + m_nPedState = PED_ATTACK; + bIsAttacking = false; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, 8.0f); + animAssoc->SetRun(); + if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) + animAssoc->SetCurrentTime(0.0f); + + animAssoc->SetFinishCallback(FinishedAttackCB, this); + } + } else { + StartFightAttack(CGeneral::GetRandomNumber() % 256); + } + return; + } + + m_pSeekTarget = victim; + if (m_pSeekTarget) + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + + if (curWeapon->m_bCanAim) { + CVector aimPos = GetRight() * 0.1f + GetForward() * 0.2f + GetPosition(); + CEntity *obstacle = CWorld::TestSphereAgainstWorld(aimPos, 0.2f, nil, true, false, false, true, false, false); + if (obstacle) + return; + + m_pLookTarget = victim; + if (victim) { + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget); + } + if (m_pLookTarget) { + SetAimFlag(m_pLookTarget); + } else { + SetAimFlag(m_fRotationCur); + + if (FindPlayerPed() == this && TheCamera.Cams[0].Using3rdPersonMouseCam()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = TheCamera.Find3rdPersonQuickAimPitch(); + } + } + if (m_nPedState == PED_ATTACK) { + bIsAttacking = true; + return; + } + + if (IsPlayer() || !victimPed || victimPed->IsPedInControl()) { + if (IsPlayer()) + CPad::GetPad(0)->ResetAverageWeapon(); + + PointBlankNecessity pointBlankStatus; + if ((curWeapon->m_eWeaponFire == WEAPON_FIRE_INSTANT_HIT || GetWeapon()->m_eWeaponType == WEAPONTYPE_FLAMETHROWER) + && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON + && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON_RUNABOUT + && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER + && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER_RUNABOUT + && (pointBlankStatus = CheckForPointBlankPeds(victimPed)) != NO_POINT_BLANK_PED) { + ClearAimFlag(); + + // This condition is pointless + if (pointBlankStatus == POINT_BLANK_FOR_WANTED_PED || !victimPed) + StartFightAttack(200); + } else { + if (!curWeapon->m_bCanAim) + m_pSeekTarget = nil; + + if (m_nPedState != PED_AIM_GUN) + SetStoredState(); + + m_nPedState = PED_ATTACK; + SetMoveState(PEDMOVE_NONE); + if (bCrouchWhenShooting) { + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_RBLOCK_CSHOOT, 4.0f); + } else { + float animDelta = 8.0f; + if (curWeapon->m_eWeaponFire == WEAPON_FIRE_MELEE) + animDelta = 1000.0f; + + if (GetWeapon()->m_eWeaponType != WEAPONTYPE_BASEBALLBAT + || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, animDelta); + } else { + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, animDelta); + } + } + + animAssoc->SetRun(); + if (animAssoc->currentTime == animAssoc->hierarchy->totalLength) + animAssoc->SetCurrentTime(0.0f); + + animAssoc->SetFinishCallback(FinishedAttackCB, this); + } + return; + } + + if (GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT && victimPed->m_nPedState == PED_GETUP) + SetWaitState(WAITSTATE_SURPRISE, nil); + + SetLookFlag(victim, false); + SetLookTimer(100); +} + +void +CPed::ClearAttack(void) +{ + if (m_nPedState != PED_ATTACK || bIsDucking || m_nWaitState == WAITSTATE_PLAYANIM_DUCK) + return; + +#ifdef VC_PED_PORTS + // VC uses CCamera::Using1stPersonWeaponMode + if (FindPlayerPed() == this && (TheCamera.PlayerWeaponMode.Mode == CCam::MODE_SNIPER || + TheCamera.PlayerWeaponMode.Mode == CCam::MODE_M16_1STPERSON || TheCamera.PlayerWeaponMode.Mode == CCam::MODE_ROCKETLAUNCHER)) { + SetPointGunAt(nil); + } else +#endif + if (bIsPointingGunAt) { + if (m_pLookTarget) + SetPointGunAt(m_pLookTarget); + else + ClearPointGunAt(); + } else if (m_objective != OBJECTIVE_NONE) { + SetIdle(); + } else { + RestorePreviousState(); + } +} + +void +CPed::ClearAttackByRemovingAnim(void) +{ + if (m_nPedState != PED_ATTACK || bIsDucking) + return; + + CWeaponInfo *weapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + CAnimBlendAssociation *weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_AnimToPlay); + if (!weaponAssoc) { + weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), weapon->m_Anim2ToPlay); + + if (!weaponAssoc && weapon->m_bThrow) + weaponAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU); + + if (!weaponAssoc) { + ClearAttack(); + return; + } + } + weaponAssoc->blendDelta = -8.0f; + weaponAssoc->flags &= ~ASSOC_RUNNING; + weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; + weaponAssoc->SetDeleteCallback(FinishedAttackCB, this); +} + +void +CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg) +{ + CWeaponInfo *currentWeapon; + CAnimBlendAssociation *newAnim; + CPed *ped = (CPed*)arg; + + if (attackAssoc) { + switch (attackAssoc->animId) { + case ANIM_WEAPON_START_THROW: + // what?! + if ((!ped->IsPlayer() || ((CPlayerPed*)ped)->m_bHaveTargetSelected) && ped->IsPlayer()) { + attackAssoc->blendDelta = -1000.0f; + newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROWU); + } else { + attackAssoc->blendDelta = -1000.0f; + newAnim = CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_WEAPON_THROW); + } + + newAnim->SetFinishCallback(FinishedAttackCB, ped); + return; + + case ANIM_FIGHT_PPUNCH: + attackAssoc->blendDelta = -8.0f; + attackAssoc->flags |= ASSOC_DELETEFADEDOUT; + ped->ClearAttack(); + return; + + case ANIM_WEAPON_THROW: + case ANIM_WEAPON_THROWU: + if (ped->GetWeapon()->m_nAmmoTotal > 0) { + currentWeapon = CWeaponInfo::GetWeaponInfo(ped->GetWeapon()->m_eWeaponType); + ped->AddWeaponModel(currentWeapon->m_nModelId); + } + break; + default: + break; + } + } + + if (!ped->bIsAttacking) + ped->ClearAttack(); +} + +PointBlankNecessity +CPed::CheckForPointBlankPeds(CPed *pedToVerify) +{ + float pbDistance = 1.1f; + if (GetWeapon()->IsType2Handed()) + pbDistance = 1.6f; + + for (int i = 0; i < m_numNearPeds; i++) { + CPed *nearPed = m_nearPeds[i]; + + if (!pedToVerify || pedToVerify == nearPed) { + + CVector diff = nearPed->GetPosition() - GetPosition(); + if (diff.Magnitude() < pbDistance) { + + float neededAngle = CGeneral::GetRadianAngleBetweenPoints( + nearPed->GetPosition().x, nearPed->GetPosition().y, + GetPosition().x, GetPosition().y); + neededAngle = CGeneral::LimitRadianAngle(neededAngle); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + + float neededTurn = Abs(neededAngle - m_fRotationCur); + + if (neededTurn > PI) + neededTurn = 2*PI - neededTurn; + + if (nearPed->OnGroundOrGettingUp() || nearPed->m_nPedState == PED_DIVE_AWAY) + return NO_POINT_BLANK_PED; + + if (neededTurn < CAN_SEE_ENTITY_ANGLE_THRESHOLD) { + if (pedToVerify == nearPed) + return POINT_BLANK_FOR_WANTED_PED; + else + return POINT_BLANK_FOR_SOMEONE_ELSE; + } + } + } + } + return NO_POINT_BLANK_PED; +} + +void +CPed::Attack(void) +{ + CAnimBlendAssociation *weaponAnimAssoc; + int32 weaponAnim; + float animStart; + eWeaponType ourWeaponType; + float weaponAnimTime; + eWeaponFire ourWeaponFire; + float animLoopEnd; + CWeaponInfo *ourWeapon; + bool attackShouldContinue; + AnimationId reloadAnim; + CAnimBlendAssociation *reloadAnimAssoc; + float delayBetweenAnimAndFire; + CVector firePos; + + ourWeaponType = GetWeapon()->m_eWeaponType; + ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType); + ourWeaponFire = ourWeapon->m_eWeaponFire; + weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay); + attackShouldContinue = bIsAttacking; + reloadAnimAssoc = nil; + reloadAnim = NUM_ANIMS; + delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire; + weaponAnim = ourWeapon->m_AnimToPlay; + + if (weaponAnim == ANIM_WEAPON_HGUN_BODY) + reloadAnim = ANIM_HGUN_RELOAD; + else if (weaponAnim == ANIM_WEAPON_AK_BODY) + reloadAnim = ANIM_AK_RELOAD; + + if (reloadAnim != NUM_ANIMS) + reloadAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), reloadAnim); + + if (bIsDucking) + return; + + if (reloadAnimAssoc) { + if (!IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) + ClearAttack(); + + return; + } + + if (CTimer::GetTimeInMilliseconds() < m_shootTimer) + attackShouldContinue = true; + + if (!weaponAnimAssoc) { + weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_Anim2ToPlay); + delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; + + // Long throw granade, molotov + if (!weaponAnimAssoc && ourWeapon->m_bThrow) { + weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU); + delayBetweenAnimAndFire = 0.2f; + } + + if (!weaponAnimAssoc) { + if (attackShouldContinue) { + if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) { + if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { + weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); + } + else { + weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + } + + weaponAnimAssoc->SetFinishCallback(FinishedAttackCB, this); + weaponAnimAssoc->SetRun(); + + if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) + weaponAnimAssoc->SetCurrentTime(0.0f); + + if (IsPlayer()) { + ((CPlayerPed*)this)->m_fAttackButtonCounter = 0.0f; + ((CPlayerPed*)this)->m_bHaveTargetSelected = false; + } + } + } else + FinishedAttackCB(nil, this); + + return; + } + } + + animStart = ourWeapon->m_fAnimLoopStart; + weaponAnimTime = weaponAnimAssoc->currentTime; + if (weaponAnimTime > animStart && weaponAnimTime - weaponAnimAssoc->timeStep <= animStart) { + if (ourWeapon->m_bCanAimWithArm) + m_pedIK.m_flags |= CPedIK::AIMS_WITH_ARM; + else + m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; + } + + if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { + if (weaponAnimAssoc->speed < 1.0f) + weaponAnimAssoc->speed = 1.0f; + + } else { + firePos = ourWeapon->m_vecFireOffset; + if (ourWeaponType == WEAPONTYPE_BASEBALLBAT) { + if (weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) + firePos.z = 0.7f * ourWeapon->m_fRadius - 1.0f; + + firePos = GetMatrix() * firePos; + } else if (ourWeaponType != WEAPONTYPE_UNARMED) { + TransformToNode(firePos, weaponAnimAssoc->animId == ANIM_KICK_FLOOR ? PED_FOOTR : PED_HANDR); + } else { + firePos = GetMatrix() * firePos; + } + + GetWeapon()->Fire(this, &firePos); + + if (ourWeaponType == WEAPONTYPE_MOLOTOV || ourWeaponType == WEAPONTYPE_GRENADE) { + RemoveWeaponModel(ourWeapon->m_nModelId); + } + if (!GetWeapon()->m_nAmmoTotal && ourWeaponFire != WEAPON_FIRE_MELEE && FindPlayerPed() != this) { + SelectGunIfArmed(); + } + + if (GetWeapon()->m_eWeaponState != WEAPONSTATE_MELEE_MADECONTACT) { + // If reloading just began, start the animation + // Last condition will always return true, even IDA hides it + if (GetWeapon()->m_eWeaponState == WEAPONSTATE_RELOADING && reloadAnim != NUM_ANIMS /* && !reloadAnimAssoc*/) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, reloadAnim, 8.0f); + ClearLookFlag(); + ClearAimFlag(); + bIsAttacking = false; + bIsPointingGunAt = false; + m_shootTimer = CTimer::GetTimeInMilliseconds(); + return; + } + } else { + if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); + } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); + } + + weaponAnimAssoc->speed = 0.5f; + + if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) { + weaponAnimAssoc->callbackType = 0; + } + } + + attackShouldContinue = false; + } + + if (ourWeaponType == WEAPONTYPE_SHOTGUN) { + weaponAnimTime = weaponAnimAssoc->currentTime; + firePos = ourWeapon->m_vecFireOffset; + + if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { + TransformToNode(firePos, PED_HANDR); + + CVector gunshellPos( + firePos.x - 0.6f * GetForward().x, + firePos.y - 0.6f * GetForward().y, + firePos.z - 0.15f * GetUp().z + ); + + CVector2D gunshellRot( + GetRight().x, + GetRight().y + ); + + gunshellRot.Normalise(); + GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); + } + } +#ifdef VC_PED_PORTS + if (IsPlayer()) { + if (CPad::GetPad(0)->GetSprint()) { + // animBreakout is a member of WeaponInfo in VC, so it's me that added the below line. + float animBreakOut = ((ourWeaponType == WEAPONTYPE_FLAMETHROWER || ourWeaponType == WEAPONTYPE_UZI || ourWeaponType == WEAPONTYPE_SHOTGUN) ? 25 / 30.0f : 99 / 30.0f); + if (!attackShouldContinue && weaponAnimAssoc->currentTime > animBreakOut) { + weaponAnimAssoc->blendDelta = -4.0f; + FinishedAttackCB(nil, this); + return; + } + } + } +#endif + animLoopEnd = ourWeapon->m_fAnimLoopEnd; + if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) + animLoopEnd = 3.4f/6.0f; + + weaponAnimTime = weaponAnimAssoc->currentTime; + + // Anim loop end, either start the loop again or finish the attack + if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { + + if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd + && (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) + && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { + + weaponAnim = weaponAnimAssoc->animId; + if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) { + if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) { + weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart); + } else { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); + } + } else { + if (weaponAnim == ourWeapon->m_Anim2ToPlay) + weaponAnimAssoc->SetCurrentTime(0.1f); + else + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + } +#ifdef VC_PED_PORTS + } else if (IsPlayer() && m_pPointGunAt && bIsAimingGun && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { + weaponAnimAssoc->SetCurrentTime(ourWeapon->m_fAnimLoopEnd); + weaponAnimAssoc->flags &= ~ASSOC_RUNNING; + SetPointGunAt(m_pPointGunAt); +#endif + } else { + ClearAimFlag(); + + // Echoes of bullets, at the end of the attack. (Bug: doesn't play while reloading) + if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { + switch (ourWeaponType) { + case WEAPONTYPE_UZI: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_AK47: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); + break; + case WEAPONTYPE_M16: + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); + break; + default: + break; + } + } + + // Fun fact: removing this part leds to reloading flamethrower + if (ourWeaponType == WEAPONTYPE_FLAMETHROWER && weaponAnimAssoc->IsRunning()) { + weaponAnimAssoc->flags |= ASSOC_DELETEFADEDOUT; + weaponAnimAssoc->flags &= ~ASSOC_RUNNING; + weaponAnimAssoc->blendDelta = -4.0f; + } + } + } + if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire) + attackShouldContinue = false; + + bIsAttacking = attackShouldContinue; +} + +void +CPed::StartFightAttack(uint8 buttonPressure) +{ + if (!IsPedInControl() || m_attackTimer > CTimer::GetTimeInMilliseconds()) + return; + + if (m_nPedState == PED_FIGHT) { + m_fightButtonPressure = buttonPressure; + return; + } + + if (m_nPedState != PED_AIM_GUN) + SetStoredState(); + + if (m_nWaitState != WAITSTATE_FALSE) { + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + } + + m_nPedState = PED_FIGHT; + m_fightButtonPressure = 0; + RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT); + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START); + + if (animAssoc) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->blendDelta = -1000.0f; + } + + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); + + if (animAssoc) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + animAssoc->blendDelta = -1000.0f; + RestoreHeadingRate(); + } + + SetMoveState(PEDMOVE_NONE); + m_nStoredMoveState = PEDMOVE_NONE; + + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f; + + CPed *pedOnGround = nil; + if (IsPlayer() && CheckForPedsOnGroundToAttack(this, &pedOnGround) > PED_IN_FRONT_OF_ATTACKER) { + m_curFightMove = FIGHTMOVE_GROUNDKICK; + } else if (m_pedStats->m_flags & STAT_SHOPPING_BAGS) { + m_curFightMove = FIGHTMOVE_ROUNDHOUSE; + } else { + m_curFightMove = FIGHTMOVE_STDPUNCH; + } + + if (pedOnGround && IsPlayer()) { + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( + pedOnGround->GetPosition().x, pedOnGround->GetPosition().y, + GetPosition().x, GetPosition().y); + + m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); + m_fRotationCur = m_fRotationDest; + m_lookTimer = 0; + SetLookFlag(pedOnGround, true); + SetLookTimer(1500); + } + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); + animAssoc->SetFinishCallback(FinishFightMoveCB, this); + m_fightState = FIGHTSTATE_NO_MOVE; + m_takeAStepAfterAttack = false; + bIsAttacking = true; + + if (IsPlayer()) + nPlayerInComboMove = 0; +} + +void +CPed::StartFightDefend(uint8 direction, uint8 hitLevel, uint8 unk) +{ + if (m_nPedState == PED_DEAD) { + if (CGame::nastyGame) { + if (hitLevel == HITLEVEL_GROUND) { + CAnimBlendAssociation *floorHitAssoc; + if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) { + floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f); + } else { + floorHitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[FIGHTMOVE_HITONFLOOR].animId, 8.0f); + } + if (floorHitAssoc) { + floorHitAssoc->SetCurrentTime(0.0f); + floorHitAssoc->SetRun(); + floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + } + } + if (CGame::nastyGame) { + CVector headPos = GetNodePosition(PED_HEAD); + for(int i = 0; i < 4; ++i) { + CVector bloodDir(0.0f, 0.0f, 0.1f); + CVector bloodPos = headPos - 0.2f * GetForward(); + CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, bloodDir, nil, 0.0f, 0, 0, 0, 0); + } + } + } + } else if (m_nPedState == PED_FALL) { + if (hitLevel == HITLEVEL_GROUND && !IsPedHeadAbovePos(-0.3f)) { + CAnimBlendAssociation *floorHitAssoc = RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL) ? + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT_F, 8.0f) : + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FLOOR_HIT, 8.0f); + if (floorHitAssoc) { + floorHitAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; + floorHitAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + } else if (IsPedInControl()) { + if ((IsPlayer() && m_nPedState != PED_FIGHT && ((CPlayerPed*)this)->m_fMoveSpeed > 1.0f) + || (!IsPlayer() && m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE)) { +#ifndef VC_PED_PORTS + if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 3) && CGeneral::GetRandomNumber() & 7) { + if (IsPlayer() || CGeneral::GetRandomNumber() & 3) { +#else + if (hitLevel != HITLEVEL_HIGH && hitLevel != HITLEVEL_LOW || (IsPlayer() || CGeneral::GetRandomNumber() & 1) && CGeneral::GetRandomNumber() & 7) { + if (IsPlayer() || CGeneral::GetRandomNumber() & 1) { +#endif + AnimationId shotAnim; + switch (direction) { + case 1: + shotAnim = ANIM_SHOT_LEFT_PARTIAL; + break; + case 2: + shotAnim = ANIM_SHOT_BACK_PARTIAL; + break; + case 3: + shotAnim = ANIM_SHOT_RIGHT_PARTIAL; + break; + default: + shotAnim = ANIM_SHOT_FRONT_PARTIAL; + break; + } + CAnimBlendAssociation *shotAssoc = RpAnimBlendClumpGetAssociation(GetClump(), shotAnim); + if (!shotAssoc || shotAssoc->blendDelta < 0.0f) + shotAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, shotAnim, 8.0f); + + shotAssoc->SetCurrentTime(0.0f); + shotAssoc->SetRun(); + shotAssoc->flags |= ASSOC_FADEOUTWHENDONE; + } else { + int time = CGeneral::GetRandomNumberInRange(1000, 3000); + SetWaitState(WAITSTATE_PLAYANIM_DUCK, &time); + } + } else { +#ifndef VC_PED_PORTS + switch (direction) { + case 1: + SetFall(500, ANIM_KO_SPIN_R, false); + break; + case 2: + SetFall(500, ANIM_KO_SKID_BACK, false); + break; + case 3: + SetFall(500, ANIM_KO_SPIN_L, false); + break; + default: + SetFall(500, ANIM_KO_SHOT_STOM, false); + break; + } +#else + bool fall = true; + AnimationId hitAnim; + switch (direction) { + case 1: + hitAnim = ANIM_KO_SPIN_R; + break; + case 2: + if (CGeneral::GetRandomNumber() & 1) { + fall = false; + hitAnim = ANIM_HIT_BACK; + } else { + hitAnim = ANIM_KO_SKID_BACK; + } + break; + case 3: + hitAnim = ANIM_KO_SPIN_L; + break; + default: + if (hitLevel == HITLEVEL_LOW) { + hitAnim = ANIM_KO_SHOT_STOM; + } else if (CGeneral::GetRandomNumber() & 1) { + fall = false; + hitAnim = ANIM_HIT_WALK; + } else if (CGeneral::GetRandomNumber() & 1) { + fall = false; + hitAnim = ANIM_HIT_HEAD; + } else { + hitAnim = ANIM_KO_SHOT_FACE; + } + break; + } + if (fall) { + SetFall(500, hitAnim, false); + } else { + CAnimBlendAssociation *hitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), hitAnim); + if (!hitAssoc || hitAssoc->blendDelta < 0.0f) + hitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, hitAnim, 8.0f); + + hitAssoc->SetCurrentTime(0.0f); + hitAssoc->SetRun(); + hitAssoc->flags |= ASSOC_FADEOUTWHENDONE; + } +#endif + } + Say(SOUND_PED_DEFEND); + } else { + Say(SOUND_PED_DEFEND); + switch (hitLevel) { + case HITLEVEL_GROUND: + m_curFightMove = FIGHTMOVE_HITONFLOOR; + break; + case HITLEVEL_LOW: +#ifndef VC_PED_PORTS + if (direction == 2) { + SetFall(1000, ANIM_KO_SKID_BACK, false); + return; + } +#else + if (direction == 2 && (!IsPlayer() || ((CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f))) { + SetFall(1000, ANIM_KO_SKID_BACK, false); + return; + } else if (direction != 2 && !IsPlayer() && (CGeneral::GetRandomNumber() & 1) && m_fHealth < 30.0f) { + SetFall(1000, ANIM_KO_SHOT_STOM, false); + return; + } +#endif + m_curFightMove = FIGHTMOVE_HITBODY; + break; + case HITLEVEL_HIGH: + switch (direction) { + case 1: + m_curFightMove = FIGHTMOVE_HITLEFT; + break; + case 2: + m_curFightMove = FIGHTMOVE_HITBACK; + break; + case 3: + m_curFightMove = FIGHTMOVE_HITRIGHT; + break; + default: + if (unk <= 5) + m_curFightMove = FIGHTMOVE_HITHEAD; + else + m_curFightMove = FIGHTMOVE_HITBIGSTEP; + break; + } + break; + default: + switch (direction) { + case 1: + m_curFightMove = FIGHTMOVE_HITLEFT; + break; + case 2: + m_curFightMove = FIGHTMOVE_HITBACK; + break; + case 3: + m_curFightMove = FIGHTMOVE_HITRIGHT; + break; + default: + if (unk <= 5) + m_curFightMove = FIGHTMOVE_HITCHEST; + else + m_curFightMove = FIGHTMOVE_HITBIGSTEP; + break; + } + break; + } + if (m_nPedState == PED_GETUP && !IsPedHeadAbovePos(0.0f)) + m_curFightMove = FIGHTMOVE_HITONFLOOR; + + if (m_nPedState == PED_FIGHT) { + CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); + moveAssoc->SetCurrentTime(0.0f); + moveAssoc->SetFinishCallback(FinishFightMoveCB, this); + if (IsPlayer()) + moveAssoc->speed = 1.3f; + + m_takeAStepAfterAttack = 0; + m_fightButtonPressure = 0; + } else if (IsPlayer() && m_currentWeapon != WEAPONTYPE_UNARMED) { + CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); + moveAssoc->SetCurrentTime(0.0f); + moveAssoc->speed = 1.3f; + } else { + if (m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK) + SetStoredState(); + + if (m_nWaitState != WAITSTATE_FALSE) { + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + } + m_nPedState = PED_FIGHT; + m_fightButtonPressure = 0; + RpAnimBlendClumpRemoveAssociations(GetClump(), ASSOC_REPEAT); + CAnimBlendAssociation *walkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START); + if (walkStartAssoc) { + walkStartAssoc->flags |= ASSOC_DELETEFADEDOUT; + walkStartAssoc->blendDelta = -1000.0f; + } + CAnimBlendAssociation *walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP); + if (!walkStopAssoc) + walkStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R); + if (walkStopAssoc) { + walkStopAssoc->flags |= ASSOC_DELETEFADEDOUT; + walkStopAssoc->blendDelta = -1000.0f; + RestoreHeadingRate(); + } + SetMoveState(PEDMOVE_NONE); + m_nStoredMoveState = PEDMOVE_NONE; + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f; + CAnimBlendAssociation *moveAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 8.0f); + moveAssoc->SetFinishCallback(FinishFightMoveCB, this); + m_fightState = FIGHTSTATE_NO_MOVE; + m_takeAStepAfterAttack = false; + bIsAttacking = true; + } + } + } +} + +void +CPed::Fight(void) +{ + CAnimBlendAssociation *currentAssoc, *animAssoc; + bool hasShoppingBags, punchOnly, canKick, canKneeHead, canRoundhouse; + float angleToFace, nextAngle; + bool goForward = false; + int nextFightMove; + + switch (m_curFightMove) { + case FIGHTMOVE_NULL: + return; + case FIGHTMOVE_IDLE2NORM: + m_curFightMove = FIGHTMOVE_NULL; + RestorePreviousState(); + + // FIX: Uninitialized + currentAssoc = nil; + break; + case FIGHTMOVE_IDLE: + currentAssoc = nil; + break; + default: + currentAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId); + break; + } + + if (!bIsAttacking && IsPlayer()) { + if (currentAssoc) { + currentAssoc->blendDelta = -1000.0f; + currentAssoc->flags |= ASSOC_DELETEFADEDOUT; + currentAssoc->flags &= ~ASSOC_RUNNING; + } + if (m_takeAStepAfterAttack) + EndFight(ENDFIGHT_WITH_A_STEP); + else + EndFight(ENDFIGHT_FAST); + + } else if (currentAssoc && m_fightState > FIGHTSTATE_MOVE_FINISHED) { + float animTime = currentAssoc->currentTime; + FightMove &curMove = tFightMoves[m_curFightMove]; + if (curMove.hitLevel != HITLEVEL_NULL && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightState >= FIGHTSTATE_NO_MOVE) { + + CVector touchingNodePos(0.0f, 0.0f, 0.0f); + + switch (m_curFightMove) { + case FIGHTMOVE_STDPUNCH: + case FIGHTMOVE_PUNCHHOOK: + case FIGHTMOVE_BODYBLOW: + TransformToNode(touchingNodePos, PED_HANDR); + break; + case FIGHTMOVE_IDLE: + case FIGHTMOVE_SHUFFLE_F: + break; + case FIGHTMOVE_KNEE: + TransformToNode(touchingNodePos, PED_LOWERLEGR); + break; + case FIGHTMOVE_HEADBUTT: + TransformToNode(touchingNodePos, PED_HEAD); + break; + case FIGHTMOVE_PUNCHJAB: + TransformToNode(touchingNodePos, PED_HANDL); + break; + case FIGHTMOVE_KICK: + case FIGHTMOVE_LONGKICK: + case FIGHTMOVE_ROUNDHOUSE: + case FIGHTMOVE_GROUNDKICK: + TransformToNode(touchingNodePos, PED_FOOTR); + break; + } + + if (m_curFightMove == FIGHTMOVE_PUNCHJAB) { + touchingNodePos += 0.1f * GetForward(); + } else if (m_curFightMove == FIGHTMOVE_PUNCHHOOK) { + touchingNodePos += 0.22f * GetForward(); + } + FightStrike(touchingNodePos); + m_fightButtonPressure = 0; + return; + } + + if (curMove.hitLevel != HITLEVEL_NULL) { + if (animTime > curMove.endFireTime) { + if (IsPlayer()) + currentAssoc->speed = 1.0f; + else + currentAssoc->speed = 0.8f; + } + + if (IsPlayer() && !nPlayerInComboMove) { + if (curMove.comboFollowOnTime > 0.0f && m_fightButtonPressure != 0 && animTime > curMove.comboFollowOnTime) { + + // Notice that it increases fight move index, because we're in combo! + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[++m_curFightMove].animId, 8.0f); + animAssoc->SetFinishCallback(FinishFightMoveCB, this); + animAssoc->SetCurrentTime(0.1f * animAssoc->hierarchy->totalLength); + m_fightButtonPressure = 0; + nPlayerInComboMove = 1; + } + } + } else { + if (curMove.startFireTime > 0.0f && m_curFightMove != FIGHTMOVE_SHUFFLE_F && animTime > curMove.startFireTime) { + if (IsPlayer()) + currentAssoc->speed = 1.3f; + else + currentAssoc->speed = 0.8f; + } + } + } else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { + EndFight(ENDFIGHT_FAST); + + } else if (m_fightButtonPressure != 0) { + bool canAffectMultiplePeople = true; + nextAngle = m_fRotationCur; + bool kickGround = false; + float angleForGroundKick = 0.0f; + CPed *pedOnGround = nil; + + Say(SOUND_PED_ATTACK); + + if (IsPlayer()) { + canRoundhouse = false; + punchOnly = false; + canKick = true; + nextFightMove = (m_fightButtonPressure > 190 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE); + hasShoppingBags = false; + canKneeHead = true; + nPlayerInComboMove = 0; + } else { + nextFightMove = (m_fightButtonPressure > 120 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE); + uint16 pedFeatures = m_pedStats->m_flags; + punchOnly = pedFeatures & STAT_PUNCH_ONLY; + canRoundhouse = pedFeatures & STAT_CAN_ROUNDHOUSE; + canKneeHead = pedFeatures & STAT_CAN_KNEE_HEAD; + canKick = pedFeatures & STAT_CAN_KICK; + hasShoppingBags = pedFeatures & STAT_SHOPPING_BAGS; + } + + // Attack isn't scripted, find the victim + if (IsPlayer() || !m_pedInObjective) { + + for (int i = 0; i < m_numNearPeds; i++) { + + CPed *nearPed = m_nearPeds[i]; + float nearPedDist = (nearPed->GetPosition() - GetPosition()).Magnitude(); + if (nearPedDist < 3.0f) { + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + nearPed->GetPosition().x, nearPed->GetPosition().y, + GetPosition().x, GetPosition().y); + + nextAngle = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + + float neededTurn = Abs(nextAngle - m_fRotationCur); + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; + + if (!nearPed->OnGroundOrGettingUp()) { + + if (nearPedDist < 0.8f && neededTurn < DEGTORAD(75.0f) && canKneeHead) { + canAffectMultiplePeople = false; + } else if (nearPedDist >= 1.3f || neededTurn >= DEGTORAD(55.0f) || hasShoppingBags) { + + if (nearPedDist < 1.7f + && neededTurn < DEGTORAD(35.0f) + && (canKick || hasShoppingBags)) { + + nextFightMove = FIGHTMOVE_KICK; + if (hasShoppingBags) { + nextFightMove = FIGHTMOVE_ROUNDHOUSE; + } else if (canRoundhouse && CGeneral::GetRandomNumber() & 1) { + nextFightMove = FIGHTMOVE_ROUNDHOUSE; + } + canAffectMultiplePeople = false; + } else if (nearPedDist < 2.0f && neededTurn < DEGTORAD(30.0f) && canKick) { + canAffectMultiplePeople = false; + nextFightMove = FIGHTMOVE_LONGKICK; + } else if (neededTurn < DEGTORAD(30.0f)) { + goForward = true; + } + } else { + nextFightMove += 2; // Makes it 6 or 7 + if (punchOnly) + nextFightMove = FIGHTMOVE_PUNCHJAB; + + canAffectMultiplePeople = false; + } + } else if (!CGame::nastyGame + || nearPedDist >= 1.3f + || neededTurn >= DEGTORAD(55.0f) + || punchOnly) { + + if (nearPedDist > 0.8f + && nearPedDist < 3.0f + && neededTurn < DEGTORAD(30.0f)) { + goForward = true; + } + + } else if (nearPed->m_nPedState != PED_DEAD || pedOnGround) { + if (!nearPed->IsPedHeadAbovePos(-0.3f)) { + canAffectMultiplePeople = false; + nextFightMove = FIGHTMOVE_GROUNDKICK; + } + + } else { + pedOnGround = nearPed; + kickGround = true; + angleForGroundKick = nextAngle; + } + } + + if (!canAffectMultiplePeople) { + m_fRotationDest = nextAngle; + if (IsPlayer()) { + m_fRotationCur = m_fRotationDest; + m_lookTimer = 0; + SetLookFlag(nearPed, true); + SetLookTimer(1500); + } + break; + } + } + } else { + // Because we're in a scripted fight with some particular ped. + canAffectMultiplePeople = false; + + float fightingPedDist = (m_pedInObjective->GetPosition() - GetPosition()).Magnitude(); + if (hasShoppingBags) { + if (fightingPedDist >= 1.7f) + nextFightMove = FIGHTMOVE_SHUFFLE_F; + else + nextFightMove = FIGHTMOVE_ROUNDHOUSE; + + } else if (punchOnly) { + if (fightingPedDist >= 1.3f) + nextFightMove = FIGHTMOVE_SHUFFLE_F; + else + nextFightMove = FIGHTMOVE_PUNCHJAB; + + } else if (fightingPedDist >= 3.0f) { + nextFightMove = FIGHTMOVE_STDPUNCH; + + } else { + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + m_pedInObjective->GetPosition().x, + m_pedInObjective->GetPosition().y, + GetPosition().x, + GetPosition().y); + + nextAngle = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationDest = nextAngle; + m_fRotationCur = m_fRotationDest; + if (!m_pedInObjective->OnGroundOrGettingUp()) { + + if (fightingPedDist >= 0.8f || !canKneeHead) { + + if (fightingPedDist >= 1.3f) { + + if (fightingPedDist < 1.7f && canKick) { + nextFightMove = FIGHTMOVE_KICK; + if (canRoundhouse && CGeneral::GetRandomNumber() & 1) + nextFightMove = FIGHTMOVE_ROUNDHOUSE; + + } else if (fightingPedDist < 2.0f && canKick) { + nextFightMove += 5; // Makes it 9 or 10 + + } else { + nextFightMove = FIGHTMOVE_SHUFFLE_F; + + } + } else { + nextFightMove += 2; // Makes it 6 or 7 + } + } + } else if (!CGame::nastyGame + || fightingPedDist >= 1.3f + || m_pedInObjective->IsPlayer() + || m_pedInObjective->m_nPedState != PED_DEAD && m_pedInObjective->IsPedHeadAbovePos(-0.3f)) { + nextFightMove = FIGHTMOVE_IDLE; + } else { + nextFightMove = FIGHTMOVE_GROUNDKICK; + } + } + } + + if (canAffectMultiplePeople) { + if (kickGround && IsPlayer()) { + m_fRotationDest = angleForGroundKick; + nextFightMove = FIGHTMOVE_GROUNDKICK; + m_fRotationCur = m_fRotationDest; + m_lookTimer = 0; + SetLookFlag(pedOnGround, true); + SetLookTimer(1500); + } else if (goForward) { + nextFightMove = FIGHTMOVE_SHUFFLE_F; + } else { + nextFightMove = FIGHTMOVE_STDPUNCH; + } + } + + if (nextFightMove != FIGHTMOVE_IDLE) { + m_curFightMove = nextFightMove; + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 4.0f); + + animAssoc->SetFinishCallback(FinishFightMoveCB, this); + if (m_fightState == FIGHTSTATE_MOVE_FINISHED && animAssoc->currentTime != 0.0f) { + animAssoc->SetCurrentTime(0.0f); + animAssoc->SetRun(); + } + m_fightButtonPressure = 0; + } + m_fightState = FIGHTSTATE_NO_MOVE; + } else if (m_takeAStepAfterAttack && m_curFightMove != FIGHTMOVE_SHUFFLE_F +#ifndef FIX_BUGS + && CheckForPedsOnGroundToAttack(this, nil) == 4) { +#else + && CheckForPedsOnGroundToAttack(this, nil) == PED_IN_FRONT_OF_ATTACKER) { +#endif + m_curFightMove = FIGHTMOVE_SHUFFLE_F; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId); + + if (animAssoc) { + animAssoc->SetCurrentTime(0.0f); + animAssoc->blendDelta = 4.0f; + animAssoc->SetRun(); + } else { + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_curFightMove].animId, 32.0f); + } + animAssoc->SetFinishCallback(FinishFightMoveCB, this); + m_fightState = FIGHTSTATE_NO_MOVE; + m_fightButtonPressure = 0; + m_takeAStepAfterAttack = false; + + } else if (m_takeAStepAfterAttack) { + EndFight(ENDFIGHT_FAST); + + } else if (m_curFightMove == FIGHTMOVE_IDLE) { + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + EndFight(ENDFIGHT_NORMAL); + } + + } else { + m_curFightMove = FIGHTMOVE_IDLE; + if (IsPlayer()) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000; + } +} + +void +CPed::EndFight(uint8 endType) +{ + if (m_nPedState != PED_FIGHT) + return; + + m_curFightMove = FIGHTMOVE_NULL; + RestorePreviousState(); + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); + if (animAssoc) + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + + switch (endType) { + case ENDFIGHT_NORMAL: + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 8.0f); + break; + case ENDFIGHT_WITH_A_STEP: + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 1.0f); + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_WALK_START, 8.0f); + break; + case ENDFIGHT_FAST: + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 8.0f)->speed = 2.0f; + break; + default: + break; + } + m_nWaitTimer = 0; +} + + +void +CPed::PlayHitSound(CPed *hitTo) +{ + // That was very complicated to reverse for me... + // First index is our fight move ID (from 1 to 12, total 12), second is the one of we fight with (from 13 to 22, total 10). + enum { + S33 = SOUND_FIGHT_PUNCH_33, + S34 = SOUND_FIGHT_KICK_34, + S35 = SOUND_FIGHT_HEADBUTT_35, + S36 = SOUND_FIGHT_PUNCH_36, + S37 = SOUND_FIGHT_PUNCH_37, + S38 = SOUND_FIGHT_CLOSE_PUNCH_38, + S39 = SOUND_FIGHT_PUNCH_39, + S40 = SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 , + S41 = SOUND_FIGHT_PUNCH_41, + S42 = SOUND_FIGHT_PUNCH_FROM_BEHIND_42, + S43 = SOUND_FIGHT_KNEE_OR_KICK_43, + S44 = SOUND_FIGHT_KICK_44, + NO_SND = SOUND_NO_SOUND + }; + uint16 hitSoundsByFightMoves[12][10] = { + {S39,S42,S43,S43,S39,S39,S39,S39,S39,S42}, + {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND}, + {NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND}, + {S39,S39,S39,S39,S33,S43,S39,S39,S39,S39}, + {S39,S39,S39,S39,S35,S39,S38,S38,S39,S39}, + {S39,S39,S39,S39,S33,S39,S41,S36,S39,S39}, + {S39,S39,S39,S39,S37,S40,S38,S38,S39,S39}, + {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39}, + {S39,S39,S39,S39,S34,S43,S44,S37,S39,S39}, + {S39,S39,S39,S39,S34,S43,S44,S37,S39,S40}, + {S39,S39,S39,S39,S33,S39,S41,S37,S39,S40}, + {S39,S39,S39,S39,S39,S39,S39,S39,S33,S33} + }; + + // This is why first dimension is between FightMove 1 and 12. + if (m_curFightMove == FIGHTMOVE_NULL || m_curFightMove >= FIGHTMOVE_HITFRONT) + return; + + uint16 soundId; + + // And this is why second dimension is between 13 and 22. + if (hitTo->m_curFightMove > FIGHTMOVE_GROUNDKICK && hitTo->m_curFightMove < FIGHTMOVE_IDLE2NORM) { + soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][hitTo->m_curFightMove - FIGHTMOVE_HITFRONT]; + + } else { + if (hitTo->m_nPedState == PED_DEAD || hitTo->UseGroundColModel()) { + soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITONFLOOR - FIGHTMOVE_HITFRONT]; + } else { + soundId = hitSoundsByFightMoves[m_curFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITFRONT - FIGHTMOVE_HITFRONT]; + } + } + + if (soundId != NO_SND) + DMAudio.PlayOneShot(m_audioEntityId, soundId, 0.0f); +} + +bool +CPed::FightStrike(CVector &touchedNodePos) +{ + CColModel *ourCol; + CVector attackDistance; + ePedPieceTypes closestPedPiece = PEDPIECE_TORSO; + float maxDistanceToBeBeaten; + CPed *nearPed; + int state = m_fightState; + bool pedFound = false; + + if (state == FIGHTSTATE_JUST_ATTACKED) + return false; + + // Pointless code + if (state > FIGHTSTATE_NO_MOVE) + attackDistance = touchedNodePos - m_vecHitLastPos; + + for (int i = 0; i < m_numNearPeds; i++) { + nearPed = m_nearPeds[i]; + if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) + maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_curFightMove].strikeRadius + 0.1f; + else + maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_curFightMove].strikeRadius; + + if (nearPed->bUsesCollision || nearPed->m_nPedState == PED_DEAD) { + CVector nearPedCentre; + nearPed->GetBoundCentre(nearPedCentre); + CVector potentialAttackDistance = nearPedCentre - touchedNodePos; + + // He can beat us + if (sq(maxDistanceToBeBeaten) > potentialAttackDistance.MagnitudeSqr()) { + +#ifdef PED_SKIN + // Have to animate a skinned clump because the initial col model is useless + if(IsClumpSkinned(GetClump())) + ourCol = ((CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()))->AnimatePedColModelSkinned(GetClump()); + else +#endif + if (nearPed->OnGround() || !nearPed->IsPedHeadAbovePos(-0.3f)) { + ourCol = &CTempColModels::ms_colModelPedGroundHit; + } else { +#ifdef ANIMATE_PED_COL_MODEL + ourCol = CPedModelInfo::AnimatePedColModel(((CPedModelInfo *)CModelInfo::GetModelInfo(GetModelIndex()))->GetHitColModel(), + RpClumpGetFrame(GetClump())); +#else + ourCol = ((CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex))->GetHitColModel(); +#endif + } + + for (int j = 0; j < ourCol->numSpheres; j++) { + attackDistance = nearPed->GetPosition() + ourCol->spheres[j].center; + attackDistance -= touchedNodePos; + CColSphere *ourPieces = ourCol->spheres; + float maxDistanceToBeat = ourPieces[j].radius + tFightMoves[m_curFightMove].strikeRadius; + + // We can beat him too + if (sq(maxDistanceToBeat) > attackDistance.MagnitudeSqr()) { + pedFound = true; + closestPedPiece = (ePedPieceTypes) ourPieces[j].piece; + break; + } + } + } + } + if (pedFound) + break; + } + + if (pedFound) { + if (nearPed->IsPlayer() && nearPed->m_nPedState == PED_GETUP) + return false; + + float oldVictimHealth = nearPed->m_fHealth; + CVector bloodPos = 0.5f * attackDistance + touchedNodePos; + int damageMult = tFightMoves[m_curFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1; + + CVector2D diff (GetPosition() - nearPed->GetPosition()); + int direction = nearPed->GetLocalDirection(diff); + if (IsPlayer()) { + if (((CPlayerPed*)this)->m_bAdrenalineActive) + damageMult = 20; + } else { + damageMult *= m_pedStats->m_attackStrength; + } + + // Change direction if we used kick. + if (m_curFightMove == FIGHTMOVE_KICK) { + if (CGeneral::GetRandomNumber() & 1) { + direction++; + if (direction > 3) + direction -= 4; + } + } + nearPed->ReactToAttack(this); + + // Mostly unused. if > 5, ANIM_HIT_WALK will be run, that's it. + int unk2; + if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !nearPed->IsPlayer()) + unk2 = 101; + else + unk2 = damageMult; + + nearPed->StartFightDefend(direction, tFightMoves[m_curFightMove].hitLevel, unk2); + PlayHitSound(nearPed); + m_fightState = FIGHTSTATE_JUST_ATTACKED; + RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_curFightMove].animId)->speed = 0.6f; + if (!nearPed->DyingOrDead()) { + nearPed->InflictDamage(this, WEAPONTYPE_UNARMED, damageMult * 3.0f, closestPedPiece, direction); + } + + if (CGame::nastyGame + && tFightMoves[m_curFightMove].hitLevel > HITLEVEL_MEDIUM + && nearPed->m_nPedState == PED_DIE + && nearPed->GetIsOnScreen()) { + + // Just for blood particle. We will restore it below. + attackDistance /= (10.0f * attackDistance.Magnitude()); + for(int i=0; i<4; i++) { + CParticle::AddParticle(PARTICLE_BLOOD, bloodPos, attackDistance, nil, 0.0f, 0, 0, 0, 0); + } + } + if (!nearPed->OnGround()) { + float curVictimHealth = nearPed->m_fHealth; + if (curVictimHealth > 0.0f + && (curVictimHealth < 40.0f && oldVictimHealth > 40.0f && !nearPed->IsPlayer() + || nearPed->m_fHealth < 20.0f && oldVictimHealth > 20.0f + || GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && IsPlayer() + || nearPed->m_pedStats->m_flags & STAT_ONE_HIT_KNOCKDOWN)) { + + nearPed->SetFall(0, (AnimationId)(direction + ANIM_KO_SKID_FRONT), 0); + if (nearPed->m_nPedState == PED_FALL) + nearPed->bIsStanding = false; + } + } + if (nearPed->m_nPedState == PED_DIE || !nearPed->bIsStanding) { + attackDistance = nearPed->GetPosition() - GetPosition(); + attackDistance.Normalise(); + attackDistance.z = 1.0f; + nearPed->bIsStanding = false; + + float moveMult; + if (m_curFightMove == FIGHTMOVE_GROUNDKICK) { + moveMult = Min(damageMult * 0.6f, 4.0f); + } else { + if (nearPed->m_nPedState != PED_DIE || damageMult >= 20) { + moveMult = damageMult; + } else { + moveMult = Min(damageMult * 2.0f, 14.0f); + } + } + + nearPed->ApplyMoveForce(moveMult * 0.6f * attackDistance); + } + CEventList::RegisterEvent(nearPed->m_nPedType == PEDTYPE_COP ? EVENT_ASSAULT_POLICE : EVENT_ASSAULT, EVENT_ENTITY_PED, nearPed, this, 2000); + } + + if (m_fightState == FIGHTSTATE_NO_MOVE) + m_fightState = FIGHTSTATE_1; + + m_vecHitLastPos = *touchedNodePos; + return false; +} + +void +CPed::FinishFightMoveCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; + + if (tFightMoves[ped->m_curFightMove].animId == animAssoc->animId) { + ped->m_fightState = FIGHTSTATE_MOVE_FINISHED; + animAssoc->blendDelta = -1000.0f; + } +} + +void +CPed::LoadFightData(void) +{ + float startFireTime, endFireTime, comboFollowOnTime, strikeRadius; + int damage, flags; + char line[256], moveName[32], animName[32], hitLevel; + int moveId = 0; + + CAnimBlendAssociation *animAssoc; + + size_t bp, buflen; + int lp, linelen; + + buflen = CFileMgr::LoadFile("DATA\\fistfite.dat", work_buff, sizeof(work_buff), "r"); + + for (bp = 0; bp < buflen; ) { + // read file line by line + for (linelen = 0; work_buff[bp] != '\n' && bp < buflen; bp++) { + line[linelen++] = work_buff[bp]; + } + bp++; + line[linelen] = '\0'; + + // skip white space + for (lp = 0; line[lp] <= ' ' && line[lp] != '\0'; lp++); + + if (line[lp] == '\0' || + line[lp] == '#') + continue; + + sscanf( + &line[lp], + "%s %f %f %f %f %c %s %d %d", + moveName, + &startFireTime, + &endFireTime, + &comboFollowOnTime, + &strikeRadius, + &hitLevel, + animName, + &damage, + &flags); + + if (strncmp(moveName, "ENDWEAPONDATA", 13) == 0) + return; + + tFightMoves[moveId].startFireTime = startFireTime / 30.0f; + tFightMoves[moveId].endFireTime = endFireTime / 30.0f; + tFightMoves[moveId].comboFollowOnTime = comboFollowOnTime / 30.0f; + tFightMoves[moveId].strikeRadius = strikeRadius; + tFightMoves[moveId].damage = damage; + tFightMoves[moveId].flags = flags; + + switch (hitLevel) { + case 'G': + tFightMoves[moveId].hitLevel = HITLEVEL_GROUND; + break; + case 'H': + tFightMoves[moveId].hitLevel = HITLEVEL_HIGH; + break; + case 'L': + tFightMoves[moveId].hitLevel = HITLEVEL_LOW; + break; + case 'M': + tFightMoves[moveId].hitLevel = HITLEVEL_MEDIUM; + break; + case 'N': + tFightMoves[moveId].hitLevel = HITLEVEL_NULL; + break; + default: + break; + } + + if (strncmp(animName, "null", 4) != 0) { + animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animName); + tFightMoves[moveId].animId = (AnimationId)animAssoc->animId; + } else { + tFightMoves[moveId].animId = ANIM_WALK; + } + moveId++; + } +} + +void +CPed::SetInvestigateEvent(eEventType event, CVector2D pos, float distanceToCountDone, uint16 time, float angle) +{ + if (!IsPedInControl() || CharCreatedBy == MISSION_CHAR) + return; + + SetStoredState(); + bFindNewNodeAfterStateRestore = false; + m_nPedState = PED_INVESTIGATE; + m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + m_eventType = event; + m_eventOrThreat = pos; + m_distanceToCountSeekDone = distanceToCountDone; + m_fAngleToEvent = angle; + + if (m_eventType >= EVENT_ICECREAM) + m_lookTimer = 0; + else + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 4.0f); + +} + +void +CPed::InvestigateEvent(void) +{ + CAnimBlendAssociation *animAssoc; + AnimationId animToPlay; + AssocGroupId animGroup; + + if (m_nWaitState == WAITSTATE_TURN180) + return; + + if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { + + if (m_standardTimer) { + if (m_eventType < EVENT_ASSAULT_NASTYWEAPON) + SetWaitState(WAITSTATE_TURN180, nil); + + m_standardTimer = 0; + } else { + ClearInvestigateEvent(); + } + return; + } + + CVector2D vecDist = m_eventOrThreat - GetPosition(); + float distSqr = vecDist.MagnitudeSqr(); + if (sq(m_distanceToCountSeekDone) >= distSqr) { + + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(vecDist.x, vecDist.y, 0.0f, 0.0f); + SetMoveState(PEDMOVE_STILL); + + switch (m_eventType) { + case EVENT_DEAD_PED: + case EVENT_HIT_AND_RUN: + case EVENT_HIT_AND_RUN_COP: + + if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (m_pEventEntity) + SetLookFlag(m_pEventEntity, true); + + SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); + + } else if (CGeneral::GetRandomNumber() & 3) { + ClearLookFlag(); + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 4.0f); + + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + Say(SOUND_PED_CHAT_EVENT); + + } else { + ClearInvestigateEvent(); + } + } + break; + case EVENT_FIRE: + case EVENT_EXPLOSION: + + if (bHasACamera && CTimer::GetTimeInMilliseconds() > m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CAM); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + + if (animAssoc && animAssoc->animId == ANIM_IDLE_CAM) { + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + + } else if (CGeneral::GetRandomNumber() & 3) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_CAM, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(2500, 5000)); + Say(SOUND_PED_CHAT_EVENT); + + } else { + m_standardTimer = 0; + } + + } else if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); + + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); + + if (animAssoc && animAssoc->animId == ANIM_IDLE_STANCE) { + if (CGeneral::GetRandomNumber() & 1) + animToPlay = ANIM_IDLE_HBHB; + else + animToPlay = ANIM_XPRESS_SCRATCH; + + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1500, 4000)); + + } else if (animAssoc && animAssoc->animId == ANIM_IDLE_HBHB) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (CGeneral::GetRandomNumber() & 1) { + animToPlay = ANIM_IDLE_STANCE; + animGroup = m_animGroup; + } else { + animToPlay = ANIM_XPRESS_SCRATCH; + animGroup = ASSOCGRP_STD; + } + + CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + + } else { + if (CGeneral::GetRandomNumber() & 1) { + animToPlay = ANIM_IDLE_STANCE; + animGroup = m_animGroup; + } else { + animToPlay = ANIM_IDLE_HBHB; + animGroup = ASSOCGRP_STD; + } + + CAnimManager::BlendAnimation(GetClump(), animGroup, animToPlay, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + } + Say(SOUND_PED_CHAT_EVENT); + } + break; + case EVENT_ICECREAM: + case EVENT_SHOPSTALL: + + m_fRotationDest = m_fAngleToEvent; + if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { + + if (m_lookTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (m_eventType == EVENT_ICECREAM) + animToPlay = ANIM_IDLE_CHAT; + else + animToPlay = ANIM_XPRESS_SCRATCH; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay,4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(2000, 5000)); + + } else { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + ClearInvestigateEvent(); + } else { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + ClearInvestigateEvent(); + } + } + } else { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 4.0f); + SetLookTimer(CGeneral::GetRandomNumberInRange(1000, 2500)); + } + } + break; + default: + return; + } + } else { + m_vecSeekPos.x = m_eventOrThreat.x; + m_vecSeekPos.y = m_eventOrThreat.y; + m_vecSeekPos.z = GetPosition().z; + Seek(); + + if (m_eventType < EVENT_ICECREAM) { + if (sq(5.0f + m_distanceToCountSeekDone) < distSqr) { + SetMoveState(PEDMOVE_RUN); + return; + } + } + if (m_eventType <= EVENT_EXPLOSION || m_eventType >= EVENT_SHOPSTALL) { + SetMoveState(PEDMOVE_WALK); + return; + } + if (distSqr > sq(1.2f)) { + SetMoveState(PEDMOVE_WALK); + return; + } + + for (int i = 0; i < m_numNearPeds; i++) { + if ((m_eventOrThreat - m_nearPeds[i]->GetPosition()).MagnitudeSqr() < sq(0.4f)) { + SetMoveState(PEDMOVE_STILL); + return; + } + } + + SetMoveState(PEDMOVE_WALK); + } +} + +void +CPed::ClearInvestigateEvent(void) +{ + CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB); + if (!animAssoc) + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_CHAT); + if (animAssoc) { + animAssoc->blendDelta = -8.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + if (m_eventType > EVENT_EXPLOSION) + m_standardTimer = CTimer::GetTimeInMilliseconds() + 15000; + + bGonnaInvestigateEvent = false; + m_pEventEntity = nil; + ClearLookFlag(); + RestorePreviousState(); + if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) + SetMoveState(PEDMOVE_WALK); +} + +bool +CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPieceTypes pedPiece, uint8 direction) +{ + CPlayerPed *player = FindPlayerPed(); + float dieDelta = 4.0f; + float dieSpeed = 0.0f; + AnimationId dieAnim = ANIM_KO_SHOT_FRONT1; + bool headShot = false; + bool willLinger = false; + int random; + + if (player == this) { + if (!player->m_bCanBeDamaged) + return false; + + player->AnnoyPlayerPed(false); + } + + if (DyingOrDead()) + return false; + + if (!bUsesCollision && method != WEAPONTYPE_DROWNING) + return false; + + if (bOnlyDamagedByPlayer && damagedBy != player && damagedBy != FindPlayerVehicle() && + method != WEAPONTYPE_DROWNING && method != WEAPONTYPE_EXPLOSION) + return false; + + float healthImpact; + if (IsPlayer()) + healthImpact = damage * 0.33f; + else + healthImpact = damage * m_pedStats->m_defendWeakness; + + bool detectDieAnim = true; + if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) { + if (!IsPedHeadAbovePos(-0.3f)) { + if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) + dieAnim = ANIM_FLOOR_HIT_F; + else + dieAnim = ANIM_FLOOR_HIT; + dieDelta *= 2.0f; + dieSpeed = 0.5f; + detectDieAnim = false; + } else if (m_nPedState == PED_FALL) { + dieAnim = NUM_ANIMS; + detectDieAnim = false; + } + } + if (detectDieAnim) { + switch (method) { + case WEAPONTYPE_UNARMED: + if (bMeleeProof) + return false; + + if (m_nPedState == PED_FALL) { + if (IsPedHeadAbovePos(-0.3f)) { + dieAnim = NUM_ANIMS; + } else { + if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) + dieAnim = ANIM_FLOOR_HIT_F; + else + dieAnim = ANIM_FLOOR_HIT; + dieDelta = dieDelta * 2.0f; + dieSpeed = 0.5f; + } + } else { + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + } + break; + case WEAPONTYPE_BASEBALLBAT: + if (bMeleeProof) + return false; + + if (m_nPedState == PED_FALL) { + if (IsPedHeadAbovePos(-0.3f)) { + dieAnim = NUM_ANIMS; + } else { + if (RpAnimBlendClumpGetFirstAssociation(GetClump(), ASSOC_FRONTAL)) + dieAnim = ANIM_FLOOR_HIT_F; + else + dieAnim = ANIM_FLOOR_HIT; + dieDelta = dieDelta * 2.0f; + dieSpeed = 0.5f; + } + } else { + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + } + break; + case WEAPONTYPE_COLT45: + case WEAPONTYPE_UZI: + case WEAPONTYPE_SHOTGUN: + case WEAPONTYPE_AK47: + case WEAPONTYPE_M16: + case WEAPONTYPE_SNIPERRIFLE: + if (bBulletProof) + return false; + + bool dontRemoveLimb; + if (IsPlayer() || bNoCriticalHits) + dontRemoveLimb = true; + else { + switch (method) { + case WEAPONTYPE_SNIPERRIFLE: + dontRemoveLimb = false; + break; + case WEAPONTYPE_M16: + dontRemoveLimb = false; + break; + case WEAPONTYPE_SHOTGUN: + dontRemoveLimb = CGeneral::GetRandomNumber() & 7; + break; + default: + dontRemoveLimb = CGeneral::GetRandomNumber() & 15; + break; + } + } + + if (dontRemoveLimb) { + if (method == WEAPONTYPE_SHOTGUN) { + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + } else + dieAnim = ANIM_KO_SHOT_FRONT1; + + willLinger = false; + } else { + switch (pedPiece) { + case PEDPIECE_TORSO: + willLinger = false; + dieAnim = ANIM_KO_SHOT_FRONT1; + break; + case PEDPIECE_MID: + willLinger = false; + dieAnim = ANIM_KO_SHOT_STOM; + break; + case PEDPIECE_LEFTARM: + dieAnim = ANIM_KO_SHOT_ARML; + RemoveBodyPart(PED_UPPERARML, direction); + willLinger = true; + break; + case PEDPIECE_RIGHTARM: + dieAnim = ANIM_KO_SHOT_ARMR; + RemoveBodyPart(PED_UPPERARMR, direction); + willLinger = true; + break; + case PEDPIECE_LEFTLEG: + dieAnim = ANIM_KO_SHOT_LEGL; + RemoveBodyPart(PED_UPPERLEGL, direction); + willLinger = true; + break; + case PEDPIECE_RIGHTLEG: + dieAnim = ANIM_KO_SHOT_LEGR; + RemoveBodyPart(PED_UPPERLEGR, direction); + willLinger = true; + break; + case PEDPIECE_HEAD: + dieAnim = ANIM_KO_SHOT_FACE; + RemoveBodyPart(PED_HEAD, direction); + headShot = true; + willLinger = true; + break; + default: + break; + } + } + break; + case WEAPONTYPE_ROCKETLAUNCHER: + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_EXPLOSION: + if (bExplosionProof) + return false; + + if (CGame::nastyGame && !IsPlayer() && !bInVehicle && + 1.0f + healthImpact > m_fArmour + m_fHealth) { + + random = CGeneral::GetRandomNumber(); + if (random & 1) + RemoveBodyPart(PED_UPPERARML, direction); + if (random & 2) + RemoveBodyPart(PED_UPPERLEGR, direction); + if (random & 4) + RemoveBodyPart(PED_HEAD, direction); + if (random & 8) + RemoveBodyPart(PED_UPPERARMR, direction); + if (random & 0x10) + RemoveBodyPart(PED_UPPERLEGL, direction); + if (bBodyPartJustCameOff) + willLinger = true; + } + // fall through + case WEAPONTYPE_MOLOTOV: + if (bExplosionProof) + return false; + + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + break; + case WEAPONTYPE_FLAMETHROWER: + if (bFireProof) + return false; + + dieAnim = ANIM_KO_SHOT_FRONT1; + break; + case WEAPONTYPE_RAMMEDBYCAR: + case WEAPONTYPE_RUNOVERBYCAR: + if (bCollisionProof) + return false; + + random = CGeneral::GetRandomNumber() & 3; + switch (random) { + case 0: + if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) + && (pedPiece != PEDPIECE_MID || random != 1)) { + if (pedPiece == PEDPIECE_RIGHTARM && random > 1 + || pedPiece == PEDPIECE_MID && random == 2) + + dieAnim = ANIM_KO_SPIN_L; + else + dieAnim = ANIM_KO_SKID_FRONT; + } else + dieAnim = ANIM_KO_SPIN_R; + + break; + case 1: + if (m_nPedState == PED_DIVE_AWAY) + dieAnim = ANIM_KD_LEFT; + else + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + if ((pedPiece != PEDPIECE_LEFTARM || random <= 1) + && (pedPiece != PEDPIECE_MID || random != 1)) { + if ((pedPiece != PEDPIECE_RIGHTARM || random <= 1) + && (pedPiece != PEDPIECE_MID || random != 2)) { + dieAnim = ANIM_KO_SKID_BACK; + } else { + dieAnim = ANIM_KD_RIGHT; + } + } else + dieAnim = ANIM_KD_LEFT; + break; + case 3: + if (m_nPedState == PED_DIVE_AWAY) + dieAnim = ANIM_KD_RIGHT; + else + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + if (damagedBy) { + CVehicle *vehicle = (CVehicle*)damagedBy; + if (method == WEAPONTYPE_RAMMEDBYCAR) { + float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); + dieDelta = 8.0f * vehSpeed + 4.0f; + } else { + float vehSpeed = vehicle->m_vecMoveSpeed.Magnitude(); + dieDelta = 12.0f * vehSpeed + 4.0f; + dieSpeed = 16.0f * vehSpeed + 1.0f; + } + } + break; + case WEAPONTYPE_DROWNING: + dieAnim = ANIM_DROWN; + break; + case WEAPONTYPE_FALL: + if (bCollisionProof) + return false; + + switch (direction) { + case 0: + dieAnim = ANIM_KO_SKID_FRONT; + break; + case 1: + dieAnim = ANIM_KO_SPIN_R; + break; + case 2: + dieAnim = ANIM_KO_SKID_BACK; + break; + case 3: + dieAnim = ANIM_KO_SPIN_L; + break; + default: + break; + } + break; + default: + break; + } + } + + if (m_fArmour != 0.0f && method != WEAPONTYPE_DROWNING) { + if (player == this) + CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds(); + + if (healthImpact < m_fArmour) { + m_fArmour = m_fArmour - healthImpact; + healthImpact = 0.0f; + } else { + healthImpact = healthImpact - m_fArmour; + m_fArmour = 0.0f; + } + } + + if (healthImpact != 0.0f) { + if (player == this) + CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss = CTimer::GetTimeInMilliseconds(); + + m_lastWepDam = method; + } + + if (m_fHealth - healthImpact >= 1.0f && !willLinger) { + m_fHealth -= healthImpact; + return false; + } + + if (bInVehicle) { + if (method != WEAPONTYPE_DROWNING) { +#ifdef VC_PED_PORTS + if (m_pMyVehicle) { + if (m_pMyVehicle->IsCar() && m_pMyVehicle->pDriver == this) { + if (m_pMyVehicle->GetStatus() == STATUS_SIMPLE) { + m_pMyVehicle->SetStatus(STATUS_PHYSICS); + CCarCtrl::SwitchVehicleToRealPhysics(m_pMyVehicle); + } + m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_NONE; + m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + m_pMyVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKESTRAIGHT; + m_pMyVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000; + } + if (m_pMyVehicle->CanPedExitCar()) { + SetObjective(OBJECTIVE_LEAVE_CAR_AND_DIE, m_pMyVehicle); + } else { + m_fHealth = 0.0f; + if (m_pMyVehicle && m_pMyVehicle->pDriver == this) { + SetRadioStation(); + m_pMyVehicle->SetStatus(STATUS_ABANDONED); + } + SetDie(dieAnim, dieDelta, dieSpeed); + /* + if (damagedBy == FindPlayerPed() && damagedBy != this) { + // PlayerInfo stuff + } + */ + } + for (int i = 0; i < ARRAY_SIZE(m_pMyVehicle->pPassengers); i++) { + CPed* passenger = m_pMyVehicle->pPassengers[i]; + if (passenger && passenger != this && damagedBy) + passenger->ReactToAttack(damagedBy); + } + + CPed *driverOfVeh = m_pMyVehicle->pDriver; + if (driverOfVeh && driverOfVeh != this && damagedBy) + driverOfVeh->ReactToAttack(damagedBy); + + if (damagedBy == FindPlayerPed() || damagedBy && damagedBy == FindPlayerVehicle()) { + CDarkel::RegisterKillByPlayer(this, method, headShot); + m_threatEntity = FindPlayerPed(); + } else { + CDarkel::RegisterKillNotByPlayer(this, method); + } + } +#endif + m_fHealth = 1.0f; + return false; + } + m_fHealth = 0.0f; + if (player == this) + m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED); + + SetDie(NUM_ANIMS, 4.0f, 0.0f); + return true; + } else { + m_fHealth = 0.0f; + SetDie(dieAnim, dieDelta, dieSpeed); + + if (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) { + + // There are PlayerInfo stuff here in VC + CDarkel::RegisterKillByPlayer(this, method, headShot); + m_threatEntity = player; + } else { + CDarkel::RegisterKillNotByPlayer(this, method); + } + if (method == WEAPONTYPE_DROWNING) + bIsInTheAir = false; + + return true; + } +} + +static RwObject* +SetPedAtomicVisibilityCB(RwObject* object, void* data) +{ + if (data == nil) + RpAtomicSetFlags((RpAtomic*)object, 0); + return object; +} + +static RwFrame* +RecurseFrameChildrenVisibilityCB(RwFrame* frame, void* data) +{ + RwFrameForAllObjects(frame, SetPedAtomicVisibilityCB, data); + RwFrameForAllChildren(frame, RecurseFrameChildrenVisibilityCB, nil); + return frame; +} + +static RwObject* +CloneAtomicToFrameCB(RwObject *frame, void *data) +{ + RpAtomic *newAtomic = RpAtomicClone((RpAtomic*)frame); + RpAtomicSetFrame(newAtomic, (RwFrame*)data); + RpClumpAddAtomic(flyingClumpTemp, newAtomic); + CVisibilityPlugins::SetAtomicRenderCallback(newAtomic, nil); + return frame; +} + +static RwFrame* +RecurseFrameChildrenToCloneCB(RwFrame *frame, void *data) +{ + RwFrame *newFrame = RwFrameCreate(); + RwFrameAddChild((RwFrame*)data, newFrame); + RwFrameTransform(newFrame, RwFrameGetMatrix(frame), rwCOMBINEREPLACE); + RwFrameForAllObjects(frame, CloneAtomicToFrameCB, newFrame); + RwFrameForAllChildren(frame, RecurseFrameChildrenToCloneCB, newFrame); + return newFrame; +} + +void +CPed::RemoveBodyPart(PedNode nodeId, int8 direction) +{ + RwFrame *frame; + CVector pos; + + frame = m_pFrames[nodeId]->frame; + if (frame) { + if (CGame::nastyGame) { +#ifdef PED_SKIN + if(!IsClumpSkinned(GetClump())) +#endif + { +#ifdef DEBUGMENU + if (bPopHeadsOnHeadshot || nodeId != PED_HEAD) +#else + if (nodeId != PED_HEAD) +#endif + SpawnFlyingComponent(nodeId, direction); + + RecurseFrameChildrenVisibilityCB(frame, nil); + } + pos.x = 0.0f; + pos.y = 0.0f; + pos.z = 0.0f; + TransformToNode(pos, PED_HEAD); + + if (CEntity::GetIsOnScreen()) { + CParticle::AddParticle(PARTICLE_TEST, pos, + CVector(0.0f, 0.0f, 0.0f), + nil, 0.1f, 0, 0, 0, 0); + + for (int i = 0; i < 16; i++) { + CParticle::AddParticle(PARTICLE_BLOOD_SMALL, + pos, + CVector(0.0f, 0.0f, 0.03f), + nil, 0.0f, 0, 0, 0, 0); + } + } + bBodyPartJustCameOff = true; + m_bodyPartBleeding = nodeId; + } + } else { + printf("Trying to remove ped component"); + } +} + +CObject* +CPed::SpawnFlyingComponent(int pedNode, int8 direction) +{ + if (CObject::nNoTempObjects >= NUMTEMPOBJECTS) + return nil; + +#ifdef PED_SKIN + assert(!IsClumpSkinned(GetClump())); +#endif + + CObject *obj = new CObject(); + if (!obj) + return nil; + + RwFrame *frame = RwFrameCreate(); + RpClump *clump = RpClumpCreate(); + RpClumpSetFrame(clump, frame); + RwMatrix *matrix = RwFrameGetLTM(m_pFrames[pedNode]->frame); + *RwFrameGetMatrix(frame) = *matrix; + + flyingClumpTemp = clump; + RwFrameForAllObjects(m_pFrames[pedNode]->frame, CloneAtomicToFrameCB, frame); + RwFrameForAllChildren(m_pFrames[pedNode]->frame, RecurseFrameChildrenToCloneCB, frame); + flyingClumpTemp = nil; + switch (pedNode) { + case PED_HEAD: + // So popping head would have wheel collision. They disabled it anyway + obj->SetModelIndexNoCreate(MI_CAR_WHEEL); + break; + case PED_UPPERARML: + case PED_UPPERARMR: + obj->SetModelIndexNoCreate(MI_BODYPARTB); + obj->SetCenterOfMass(0.25f, 0.0f, 0.0f); + break; + case PED_UPPERLEGL: + case PED_UPPERLEGR: + obj->SetModelIndexNoCreate(MI_BODYPARTA); + obj->SetCenterOfMass(0.4f, 0.0f, 0.0f); + break; + default: + break; + } + obj->RefModelInfo(GetModelIndex()); + obj->AttachToRwObject((RwObject*)clump); + obj->m_fMass = 15.0f; + obj->m_fTurnMass = 5.0f; + obj->m_fAirResistance = 0.99f; + obj->m_fElasticity = 0.03f; + obj->m_fBuoyancy = m_fMass*GRAVITY/0.75f; + obj->ObjectCreatedBy = TEMP_OBJECT; + obj->SetIsStatic(false); + obj->bIsPickup = false; + obj->m_nSpecialCollisionResponseCases = COLLRESPONSE_SMALLBOX; + + // life time - the more objects the are, the shorter this one will live + CObject::nNoTempObjects++; + if (CObject::nNoTempObjects > 20) + obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 12000; + else if (CObject::nNoTempObjects > 10) + obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 30000; + else + obj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 60000; + + CVector localForcePos, forceDir; + + if (direction == 2) { + obj->m_vecMoveSpeed = 0.03f * GetForward(); + obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f; + obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + localForcePos = CVector(0.0f, 0.0f, 0.0f); + forceDir = GetForward(); + } else { + obj->m_vecMoveSpeed = -0.03f * GetForward(); + obj->m_vecMoveSpeed.z = (CGeneral::GetRandomNumber() & 0x3F) * 0.001f; + obj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + localForcePos = CVector(0.0f, 0.0f, 0.0f); + forceDir = -GetForward(); + } + obj->ApplyTurnForce(forceDir, localForcePos); + CWorld::Add(obj); + + return obj; +} + +void +CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) +{ + CVector pos2 = CVector( + pos.x, + pos.y, + pos.z + 0.1f + ); + + if (!IsPlayer() || evenOnPlayer) { + ++CStats::HeadsPopped; + + // BUG: This condition will always return true. Even fixing it won't work, because these states are unused. + // if (m_nPedState != PED_PASSENGER || m_nPedState != PED_TAXI_PASSENGER) { + SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + // } + + bBodyPartJustCameOff = true; + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; + + CParticle::AddParticle(PARTICLE_TEST, pos2, + CVector(0.0f, 0.0f, 0.0f), nil, 0.2f, 0, 0, 0, 0); + + if (CEntity::GetIsOnScreen()) { + for(int i=0; i < 32; i++) { + CParticle::AddParticle(PARTICLE_BLOOD_SMALL, + pos2, CVector(0.0f, 0.0f, 0.03f), + nil, 0.0f, 0, 0, 0, 0); + } + + for (int i = 0; i < 16; i++) { + CParticle::AddParticle(PARTICLE_DEBRIS2, + pos2, + CVector(0.0f, 0.0f, 0.01f), + nil, 0.0f, 0, 0, 0, 0); + } + } + } +} + +uint8 +CPed::DoesLOSBulletHitPed(CColPoint &colPoint) +{ +#ifdef FIX_BUGS + return 1; +#else + uint8 retVal = 2; + + float headZ = GetNodePosition(PED_HEAD).z; + + if (m_nPedState == PED_FALL) + retVal = 1; + + float colZ = colPoint.point.z; + if (colZ < headZ) + retVal = 1; + + if (headZ + 0.2f <= colZ) + retVal = 0; + + return retVal; +#endif +} + +bool +CPed::IsPedHeadAbovePos(float zOffset) +{ + return zOffset + GetPosition().z < GetNodePosition(PED_HEAD).z; +} + +bool +CPed::PlacePedOnDryLand(void) +{ + float waterLevel = 0.0f; + CEntity *foundEnt = nil; + CColPoint foundCol; + float foundColZ; + + CWaterLevel::GetWaterLevelNoWaves(GetPosition().x, GetPosition().y, GetPosition().z, &waterLevel); + + CVector potentialGround = GetPosition(); + potentialGround.z = waterLevel; + + if (!CWorld::TestSphereAgainstWorld(potentialGround, 5.0f, nil, true, false, false, false, false, false)) + return false; + + CVector potentialGroundDist = gaTempSphereColPoints[0].point - GetPosition(); + potentialGroundDist.z = 0.0f; + potentialGroundDist.Normalise(); + + CVector posToCheck = 0.5f * potentialGroundDist + gaTempSphereColPoints[0].point; + posToCheck.z = 3.0f + waterLevel; + + if (CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) { + foundColZ = foundCol.point.z; + if (foundColZ >= waterLevel) { + posToCheck.z = 0.8f + foundColZ; + SetPosition(posToCheck); + bIsStanding = true; + bWasStanding = true; + return true; + } + } + + posToCheck = 5.0f * potentialGroundDist + GetPosition(); + posToCheck.z = 3.0f + waterLevel; + + if (!CWorld::ProcessVerticalLine(posToCheck, waterLevel - 1.0f, foundCol, foundEnt, true, true, false, true, false, false, nil)) + return false; + + foundColZ = foundCol.point.z; + if (foundColZ < waterLevel) + return false; + + posToCheck.z = 0.8f + foundColZ; + SetPosition(posToCheck); + bIsStanding = true; + bWasStanding = true; + return true; +} + +void +CPed::CollideWithPed(CPed *collideWith) +{ + CAnimBlendAssociation *animAssoc; + AnimationId animToPlay; + + bool weAreMissionChar = CharCreatedBy == MISSION_CHAR; + bool heIsMissionChar = collideWith->CharCreatedBy == MISSION_CHAR; + CVector posDiff = collideWith->GetPosition() - GetPosition(); + int waitTime = 0; + + if (weAreMissionChar || !collideWith->IsPlayer() || collideWith->m_nPedState != PED_MAKE_CALL) { + bool weDontLookToHim = DotProduct(posDiff, GetForward()) > 0.0f; + bool heLooksToUs = DotProduct(posDiff, collideWith->GetForward()) < 0.0f; + + if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) { + + if ((!IsPlayer() || ((CPlayerPed*)this)->m_fMoveSpeed <= 1.8f) + && (IsPlayer() || heIsMissionChar && weAreMissionChar || m_nMoveState != PEDMOVE_RUN && m_nMoveState != PEDMOVE_SPRINT +#ifdef VC_PED_PORTS + || m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && m_pedInObjective == collideWith + || collideWith->m_objective == OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && collideWith->m_pedInObjective == this +#endif + )) { + + if (m_objective != OBJECTIVE_FOLLOW_CHAR_IN_FORMATION && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT) { + + if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { + + if (heIsMissionChar || !weAreMissionChar && collideWith->m_nMoveState != PEDMOVE_STILL) { + + if (weAreMissionChar && (m_nPedState == PED_SEEK_POS || m_nPedState == PED_SEEK_ENTITY)) { + + if (collideWith->m_nMoveState != PEDMOVE_STILL + && (!collideWith->IsPlayer() || collideWith->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled())) { + float seekPosDist = (GetPosition() - m_vecSeekPos).MagnitudeSqr2D(); + float heAndSeekPosDist = (collideWith->GetPosition() - m_vecSeekPos).MagnitudeSqr2D(); + + if (seekPosDist <= heAndSeekPosDist) { + waitTime = 1000; + collideWith->SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime); + collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime; + } else { + waitTime = 500; + SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime; + } + } else if (collideWith->m_nMoveState == PEDMOVE_STILL) { + SetDirectionToWalkAroundObject(collideWith); + } + } else { + if (weAreMissionChar || m_pedStats->m_fear <= 100 - collideWith->m_pedStats->m_temper + || (collideWith->IsPlayer() || collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL) && + (!collideWith->IsPlayer() || ((CPlayerPed*)collideWith)->m_fMoveSpeed <= 1.0f)) { + SetDirectionToWalkAroundObject(collideWith); + if (!weAreMissionChar) + Say(SOUND_PED_CHAT); + } else { + SetEvasiveStep(collideWith, 2); + } + } + } else { + if (m_pedStats->m_temper <= m_pedStats->m_fear + || GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED + || weAreMissionChar + || collideWith->m_nPedType == PEDTYPE_CIVFEMALE + || collideWith->m_nPedType == m_nPedType + || collideWith->GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) { + SetDirectionToWalkAroundObject(collideWith); + Say(SOUND_PED_CHAT); + } else { + TurnBody(); + SetAttack(collideWith); +#ifdef VC_PED_PORTS + m_fRotationCur = 0.3f + m_fRotationCur; + m_fRotationDest = m_fRotationCur; +#endif + } + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(250, 450); + } + } + } else { +#ifdef VC_PED_PORTS + if (m_pedInObjective && (collideWith == m_pedInObjective || collideWith->m_pedInObjective == m_pedInObjective) && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { +#else + if (m_pedInObjective && collideWith == m_pedInObjective && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { +#endif + if (heLooksToUs) { + SetEvasiveStep(collideWith, 1); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; + } + } else if (weDontLookToHim && IsPedInControl()) { + + if (m_pedStats != collideWith->m_pedStats) { + + if (collideWith->m_pedStats->m_fear <= 100 - m_pedStats->m_temper +#ifdef VC_PED_PORTS + || collideWith->IsPlayer() || CTimer::GetTimeInMilliseconds() < m_nPedStateTimer +#endif + ) { + + if (collideWith->IsPlayer()) { + // He's on our right side + if (DotProduct(posDiff,GetRight()) <= 0.0f) + m_fRotationCur -= m_headingRate; + else + m_fRotationCur += m_headingRate; + } else { + // He's on our right side + if (DotProduct(posDiff, collideWith->GetRight()) <= 0.0f) + collideWith->m_fRotationCur -= collideWith->m_headingRate; + else + collideWith->m_fRotationCur += collideWith->m_headingRate; + } + } else { + SetLookFlag(collideWith, false); + TurnBody(); + animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_PPUNCH, 8.0f); + animAssoc->flags |= ASSOC_FADEOUTWHENDONE; +#ifdef VC_PED_PORTS + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000; +#endif + if (!heIsMissionChar) { + CVector2D posDiff2D(posDiff); + int direction = collideWith->GetLocalDirection(posDiff2D); + collideWith->StartFightDefend(direction, HITLEVEL_HIGH, 5); + } + } + } + } + } + } else if (collideWith->m_pedStats->m_defendWeakness <= 1.5f || heIsMissionChar +#ifdef VC_PED_PORTS + || m_pedStats->m_defendWeakness <= collideWith->m_pedStats->m_defendWeakness +#endif + ) { + // He looks us and we're not at his right side + if (heLooksToUs && DotProduct(posDiff,collideWith->GetRight()) > 0.0f) { + CVector moveForce = GetRight(); + moveForce.z += 0.1f; + ApplyMoveForce(moveForce); + if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) + animToPlay = ANIM_HIT_LEFT; + else + animToPlay = ANIM_SHOT_LEFT_PARTIAL; + } else if (heLooksToUs) { + CVector moveForce = GetRight() * -1.0f; + moveForce.z += 0.1f; + ApplyMoveForce(moveForce); + if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) + animToPlay = ANIM_HIT_RIGHT; + else + animToPlay = ANIM_SHOT_RIGHT_PARTIAL; + } else { + if (collideWith->m_nMoveState != PEDMOVE_RUN && collideWith->m_nMoveState != PEDMOVE_SPRINT) + animToPlay = ANIM_HIT_BACK; + else + animToPlay = ANIM_SHOT_BACK_PARTIAL; + } + + if (collideWith->IsPedInControl() && CTimer::GetTimeInMilliseconds() > collideWith->m_nPedStateTimer) { + animAssoc = CAnimManager::BlendAnimation(collideWith->GetClump(), ASSOCGRP_STD, animToPlay, 8.0f); + animAssoc->flags |= ASSOC_FADEOUTWHENDONE; + collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 1000; + if (m_nPedState == PED_ATTACK) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); + } + } else { + // We're at his right side + if (DotProduct(posDiff, collideWith->GetRight()) <= 0.0f) { + CVector moveForce = GetRight() * -1.0f; + moveForce.z += 0.1f; + ApplyMoveForce(moveForce); + if (heLooksToUs) + animToPlay = ANIM_KO_SPIN_L; + else + animToPlay = ANIM_KD_RIGHT; + } else { + CVector moveForce = GetRight(); + moveForce.z += 0.1f; + ApplyMoveForce(moveForce); + if (heLooksToUs) + animToPlay = ANIM_KO_SPIN_R; + else + animToPlay = ANIM_KD_LEFT; + } + + if (m_nPedState == PED_ATTACK && collideWith->IsPedInControl()) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f); + + collideWith->SetFall(3000, animToPlay, 0); + } + } else { + if (!IsPedInControl()) + return; + + if (collideWith->m_nMoveState == PEDMOVE_NONE || collideWith->m_nMoveState == PEDMOVE_STILL) + return; + + if (m_nPedType != collideWith->m_nPedType || m_nPedType == PEDTYPE_CIVMALE || m_nPedType == PEDTYPE_CIVFEMALE) { + + if (!weAreMissionChar && heLooksToUs && m_pedStats->m_fear > 100 - collideWith->m_pedStats->m_temper) { + + if (CGeneral::GetRandomNumber() & 1 && CTimer::GetTimeInMilliseconds() < m_nPedStateTimer){ + SetEvasiveStep(collideWith, 2); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; + } else if (collideWith->m_nMoveState > PEDMOVE_WALK) { + waitTime = 2000; + SetWaitState(WAITSTATE_PLAYANIM_DUCK, &waitTime); + } + } + } else if (heLooksToUs + && collideWith->m_nPedState != PED_STEP_AWAY + && m_nPedState != PED_STEP_AWAY + && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { + + SetEvasiveStep(collideWith, 1); + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 3000; + } + } + + if (IsPlayer()) { + SetLookFlag(collideWith, true); + SetLookTimer(800); + } + } else { + bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; + SetFindPathAndFlee(collideWith, 5000, !isRunning); + } +} + +void +CPed::KillPedWithCar(CVehicle *car, float impulse) +{ + CVehicleModelInfo *vehModel; + CColModel *vehColModel; + uint8 damageDir; + PedNode nodeToDamage; + eWeaponType killMethod; + + if (m_nPedState == PED_FALL || m_nPedState == PED_DIE) { + if (!this->m_pCollidingEntity || car->GetStatus() == STATUS_PLAYER) + this->m_pCollidingEntity = car; + return; + } + + if (m_nPedState == PED_DEAD) + return; + + if (m_pCurSurface) { + if (m_pCurSurface->IsVehicle() && (((CVehicle*)m_pCurSurface)->m_vehType == VEHICLE_TYPE_BOAT || IsPlayer())) + return; + } + + CVector distVec = GetPosition() - car->GetPosition(); + + if ((impulse > 12.0f || car->GetModelIndex() == MI_TRAIN) && !IsPlayer()) { + nodeToDamage = PED_TORSO; + killMethod = WEAPONTYPE_RAMMEDBYCAR; + uint8 randVal = CGeneral::GetRandomNumber() & 3; + + if (car == FindPlayerVehicle()) { + float carSpeed = car->m_vecMoveSpeed.Magnitude(); + uint8 shakeFreq; + if (100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f <= 250.0f) { + shakeFreq = 100.0f * carSpeed * 2000.0f / car->m_fMass + 80.0f; + } else { + shakeFreq = 250.0f; + } + CPad::GetPad(0)->StartShake(40000 / shakeFreq, shakeFreq); + } + bIsStanding = false; + damageDir = GetLocalDirection(-m_vecMoveSpeed); + vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(car->GetModelIndex()); + vehColModel = vehModel->GetColModel(); + float carRightAndDistDotProd = DotProduct(distVec, car->GetRight()); + + if (car->GetModelIndex() == MI_TRAIN) { + killMethod = WEAPONTYPE_RUNOVERBYCAR; + nodeToDamage = PED_HEAD; + m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; + m_vecMoveSpeed.z = 0.0f; + if (damageDir == 1 || damageDir == 3) + damageDir = 2; + if (CGame::nastyGame) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); + + // Car doesn't look to us + } else if (DotProduct(car->m_vecMoveSpeed, car->GetForward()) >= 0.0f){ + + if (0.99f * vehColModel->boundingBox.max.x < Abs(carRightAndDistDotProd)) { + + // We're at the right of the car + if (carRightAndDistDotProd <= 0.0f) + nodeToDamage = PED_UPPERARML; + else + nodeToDamage = PED_UPPERARMR; + + if (Abs(DotProduct(distVec, car->GetForward())) < 0.85f * vehColModel->boundingBox.max.y) { + killMethod = WEAPONTYPE_RUNOVERBYCAR; + m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; + m_vecMoveSpeed.z = 0.0f; + if (damageDir == 1 || damageDir == 3) + damageDir = 2; + if (CGame::nastyGame) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); + + } + } else { + float carFrontAndDistDotProd = DotProduct(distVec, car->GetForward()); + + // carFrontAndDistDotProd <= 0.0 car looks to us + if ((carFrontAndDistDotProd <= 0.1 || randVal == 1) && randVal != 0) { + killMethod = WEAPONTYPE_RUNOVERBYCAR; + nodeToDamage = PED_HEAD; + m_vecMoveSpeed = 0.9f * car->m_vecMoveSpeed; + m_vecMoveSpeed.z = 0.0f; + if (damageDir == 1 || damageDir == 3) + damageDir = 2; + + if (CGame::nastyGame) + DMAudio.PlayOneShot(m_audioEntityId, SOUND_SPLATTER, 0.0f); + + } else { + nodeToDamage = PED_MID; + float vehColMaxY = vehColModel->boundingBox.max.y; + float vehColMinY = vehColModel->boundingBox.min.y; + float vehColMaxZ = vehColModel->boundingBox.max.z; + float carFrontZ = car->GetForward().z; + float carHighestZ, carLength; + + if (carFrontZ < -0.2f) { + // Highest point of car's back + carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMinY, vehColMaxZ)).z; + carLength = vehColMaxY - vehColMinY; + + } else if (carFrontZ > 0.1f) { + // Highest point of car's front + carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; + float highestZDist = carHighestZ - GetPosition().z; + if (highestZDist > 0.0f) { + GetMatrix().GetPosition().z += 0.5f * highestZDist; + carHighestZ += highestZDist * 0.25f; + } + carLength = vehColMaxY; + + } else { + // Highest point of car's front + carHighestZ = (car->GetMatrix() * CVector(0.0f, vehColMaxY, vehColMaxZ)).z; + carLength = vehColMaxY; + } + + float pedJumpSpeedToReachHighestZ = (carHighestZ - GetPosition().z) / (carLength / car->m_vecMoveSpeed.Magnitude()); + + // TODO: What are we doing down here? + float unknown = ((CGeneral::GetRandomNumber() % 256) * 0.002 + 1.5) * pedJumpSpeedToReachHighestZ; + + // After this point, distVec isn't distVec anymore. + distVec = car->m_vecMoveSpeed; + distVec.Normalise(); + distVec *= 0.2 * unknown; + + if (damageDir != 1 && damageDir != 3) + distVec.z += unknown; + else + distVec.z += 1.5f * unknown; + + m_vecMoveSpeed = distVec; + damageDir += 2; + if (damageDir > 3) + damageDir = damageDir - 4; + + if (car->m_vehType == VEHICLE_TYPE_CAR) { + CObject *bonnet = ((CAutomobile*)car)->RemoveBonnetInPedCollision(); + + if (bonnet) { + if (CGeneral::GetRandomNumber() & 1) { + bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(0.1f, 0.0f, 0.5f)); + } else { + bonnet->m_vecMoveSpeed += Multiply3x3(car->GetMatrix(), CVector(-0.1f, 0.0f, 0.5f)); + } + CVector forceDir = car->GetUp() * 10.0f; + bonnet->ApplyTurnForce(forceDir, car->GetForward()); + } + } + } + } + } + + if (car->pDriver) { + CEventList::RegisterEvent((m_nPedType == PEDTYPE_COP ? EVENT_HIT_AND_RUN_COP : EVENT_HIT_AND_RUN), EVENT_ENTITY_PED, this, car->pDriver, 1000); + } + + ePedPieceTypes pieceToDamage; + switch (nodeToDamage) { + case PED_HEAD: + pieceToDamage = PEDPIECE_HEAD; + break; + case PED_UPPERARML: + pieceToDamage = PEDPIECE_LEFTARM; + break; + case PED_UPPERARMR: + pieceToDamage = PEDPIECE_RIGHTARM; + break; + default: + pieceToDamage = PEDPIECE_MID; + break; + } + InflictDamage(car, killMethod, 1000.0f, pieceToDamage, damageDir); + + if (DyingOrDead() + && bIsPedDieAnimPlaying && !m_pCollidingEntity) { + m_pCollidingEntity = car; + } + if (nodeToDamage == PED_MID) + bKnockedUpIntoAir = true; + else + bKnockedUpIntoAir = false; + + distVec.Normalise(); + +#ifdef VC_PED_PORTS + distVec *= Min(car->m_fMass / 1400.0f, 1.0f); +#endif + car->ApplyMoveForce(distVec * -100.0f); + Say(SOUND_PED_DEFEND); + + } else if (m_vecDamageNormal.z < -0.8f && impulse > 3.0f + || impulse > 6.0f && (!IsPlayer() || impulse > 10.0f)) { + + bIsStanding = false; + uint8 fallDirection = GetLocalDirection(-car->m_vecMoveSpeed); + float damage; + if (IsPlayer() && car->GetModelIndex() == MI_TRAIN) + damage = 150.0f; + else + damage = 30.0f; + + InflictDamage(car, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, fallDirection); + SetFall(1000, (AnimationId)(fallDirection + ANIM_KO_SKID_FRONT), true); + + if (OnGround() && !m_pCollidingEntity && + (!IsPlayer() || bHasHitWall || car->GetModelIndex() == MI_TRAIN || m_vecDamageNormal.z < -0.8f)) { + + m_pCollidingEntity = car; + } + + bKnockedUpIntoAir = false; + if (car->GetModelIndex() != MI_TRAIN && !bHasHitWall) { + m_vecMoveSpeed = car->m_vecMoveSpeed * 0.75f; + } + m_vecMoveSpeed.z = 0.0f; + distVec.Normalise(); +#ifdef VC_PED_PORTS + distVec *= Min(car->m_fMass / 1400.0f, 1.0f); +#endif + car->ApplyMoveForce(distVec * -60.0f); + Say(SOUND_PED_DEFEND); + } + +#ifdef VC_PED_PORTS + // Killing gang members with car wasn't triggering a fight, until now... Taken from VC. + if (IsGangMember()) { + CPed *driver = car->pDriver; + if (driver && driver->IsPlayer() +#ifdef FIX_BUGS + && (CharCreatedBy != MISSION_CHAR || bRespondsToThreats) && (!m_leader || m_leader != driver) +#endif + ) { + RegisterThreatWithGangPeds(driver); + } + } +#endif +} \ No newline at end of file diff --git a/src/peds/PedStats.cpp b/src/peds/PedStats.cpp deleted file mode 100644 index 1f7a95b4..00000000 --- a/src/peds/PedStats.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "common.h" - -#include "General.h" -#include "FileMgr.h" -#include "PedStats.h" - -CPedStats *CPedStats::ms_apPedStats[NUM_PEDSTATS]; - -void -CPedStats::Initialise(void) -{ - int i; - - debug("Initialising CPedStats...\n"); - for(i = 0; i < NUM_PEDSTATS; i++){ - ms_apPedStats[i] = new CPedStats; - ms_apPedStats[i]->m_type = PEDSTAT_PLAYER; - ms_apPedStats[i]->m_name[8] = 'R'; // WHAT? - ms_apPedStats[i]->m_fleeDistance = 20.0f; - ms_apPedStats[i]->m_headingChangeRate = 15.0f; - ms_apPedStats[i]->m_fear = 50; - ms_apPedStats[i]->m_temper = 50; - ms_apPedStats[i]->m_lawfulness = 50; - ms_apPedStats[i]->m_sexiness = 50; - ms_apPedStats[i]->m_attackStrength = 1.0f; - ms_apPedStats[i]->m_defendWeakness = 1.0f; - ms_apPedStats[i]->m_flags = 0; - } - debug("Loading pedstats data...\n"); - CPedStats::LoadPedStats(); - debug("CPedStats ready\n"); -} - -void -CPedStats::Shutdown(void) -{ - int i; - debug("Shutting down CPedStats...\n"); - for(i = 0; i < NUM_PEDSTATS; i++) - delete ms_apPedStats[i]; - debug("CPedStats shut down\n"); -} - -void -CPedStats::LoadPedStats(void) -{ - char *buf; - char line[256]; - char name[32]; - size_t bp, buflen; - int lp, linelen; - int type; - float fleeDist, headingChangeRate, attackStrength, defendWeakness; - int fear, temper, lawfullness, sexiness, flags; - - - type = 0; - buf = new char[16 * 1024]; - - CFileMgr::SetDir("DATA"); - buflen = CFileMgr::LoadFile("PEDSTATS.DAT", (uint8*)buf, 16 * 1024, "r"); - CFileMgr::SetDir(""); - - for(bp = 0; bp < buflen; ){ - // read file line by line - for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){ - if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t') - line[linelen++] = ' '; - else - line[linelen++] = buf[bp]; - } - bp++; - line[linelen] = '\0'; - - // skip white space - for(lp = 0; line[lp] <= ' '; lp++); - - if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines - line[lp] == '#') - continue; - - sscanf(&line[lp], "%s %f %f %d %d %d %d %f %f %d", - name, - &fleeDist, - &headingChangeRate, - &fear, - &temper, - &lawfullness, - &sexiness, - &attackStrength, - &defendWeakness, - &flags); - ms_apPedStats[type]->m_type = (ePedStats)type; - strncpy(ms_apPedStats[type]->m_name, name, 24); // FIX: game uses strcpy - ms_apPedStats[type]->m_fleeDistance = fleeDist; - ms_apPedStats[type]->m_headingChangeRate = headingChangeRate; - ms_apPedStats[type]->m_fear = fear; - ms_apPedStats[type]->m_temper = temper; - ms_apPedStats[type]->m_lawfulness = lawfullness; - ms_apPedStats[type]->m_sexiness = sexiness; - ms_apPedStats[type]->m_attackStrength = attackStrength; - ms_apPedStats[type]->m_defendWeakness = defendWeakness; - ms_apPedStats[type]->m_flags = flags; - type++; - } - - delete[] buf; -} - -ePedStats -CPedStats::GetPedStatType(char *name) -{ - for(uint16 type = 0; type < NUM_PEDSTATS; type++) - if(!CGeneral::faststrcmp(ms_apPedStats[type]->m_name, name)) - return (ePedStats) type; - - return NUM_PEDSTATS; -} diff --git a/src/peds/PedStats.h b/src/peds/PedStats.h deleted file mode 100644 index df97bdb8..00000000 --- a/src/peds/PedStats.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -enum ePedStats -{ - PEDSTAT_PLAYER, - PEDSTAT_COP, - PEDSTAT_MEDIC, - PEDSTAT_FIREMAN, - PEDSTAT_GANG1, - PEDSTAT_GANG2, - PEDSTAT_GANG3, - PEDSTAT_GANG4, - PEDSTAT_GANG5, - PEDSTAT_GANG6, - PEDSTAT_GANG7, - PEDSTAT_STREET_GUY, - PEDSTAT_SUIT_GUY, - PEDSTAT_SENSIBLE_GUY, - PEDSTAT_GEEK_GUY, - PEDSTAT_OLD_GUY, - PEDSTAT_TOUGH_GUY, - PEDSTAT_STREET_GIRL, - PEDSTAT_SUIT_GIRL, - PEDSTAT_SENSIBLE_GIRL, - PEDSTAT_GEEK_GIRL, - PEDSTAT_OLD_GIRL, - PEDSTAT_TOUGH_GIRL, - PEDSTAT_TRAMP_MALE, - PEDSTAT_TRAMP_FEMALE, - PEDSTAT_TOURIST, - PEDSTAT_PROSTITUTE, - PEDSTAT_CRIMINAL, - PEDSTAT_BUSKER, - PEDSTAT_TAXIDRIVER, - PEDSTAT_PSYCHO, - PEDSTAT_STEWARD, - PEDSTAT_SPORTSFAN, - PEDSTAT_SHOPPER, - PEDSTAT_OLDSHOPPER, - - NUM_PEDSTATS -}; - -// flags -enum -{ - STAT_PUNCH_ONLY = 1, - STAT_CAN_KNEE_HEAD = 2, - STAT_CAN_KICK = 4, - STAT_CAN_ROUNDHOUSE = 8, - STAT_NO_DIVE = 0x10, - STAT_ONE_HIT_KNOCKDOWN = 0x20, - STAT_SHOPPING_BAGS = 0x40, - STAT_GUN_PANIC = 0x80 -}; - -class CPedStats -{ -public: - ePedStats m_type; - char m_name[24]; - float m_fleeDistance; - float m_headingChangeRate; - int8 m_fear; - int8 m_temper; - int8 m_lawfulness; - int8 m_sexiness; - float m_attackStrength; - float m_defendWeakness; - int16 m_flags; - - static CPedStats *ms_apPedStats[NUM_PEDSTATS]; - - static void Initialise(void); - static void Shutdown(void); - static void LoadPedStats(void); - static ePedStats GetPedStatType(char *name); -}; - -VALIDATE_SIZE(CPedStats, 0x34); diff --git a/src/peds/PedType.cpp b/src/peds/PedType.cpp index 397cd71d..6e745bd7 100644 --- a/src/peds/PedType.cpp +++ b/src/peds/PedType.cpp @@ -1,9 +1,11 @@ #include "common.h" +#include "General.h" #include "FileMgr.h" #include "PedType.h" CPedType *CPedType::ms_apPedType[NUM_PEDTYPES]; +CPedStats *CPedStats::ms_apPedStats[NUM_PEDSTATS]; void CPedType::Initialise(void) @@ -202,3 +204,114 @@ INITSAVEBUF *ms_apPedType[i] = ReadSaveBuf(buf); VALIDATESAVEBUF(size) } + +void +CPedStats::Initialise(void) +{ + int i; + + debug("Initialising CPedStats...\n"); + for(i = 0; i < NUM_PEDSTATS; i++){ + ms_apPedStats[i] = new CPedStats; + ms_apPedStats[i]->m_type = PEDSTAT_PLAYER; + ms_apPedStats[i]->m_name[8] = 'R'; // WHAT? + ms_apPedStats[i]->m_fleeDistance = 20.0f; + ms_apPedStats[i]->m_headingChangeRate = 15.0f; + ms_apPedStats[i]->m_fear = 50; + ms_apPedStats[i]->m_temper = 50; + ms_apPedStats[i]->m_lawfulness = 50; + ms_apPedStats[i]->m_sexiness = 50; + ms_apPedStats[i]->m_attackStrength = 1.0f; + ms_apPedStats[i]->m_defendWeakness = 1.0f; + ms_apPedStats[i]->m_flags = 0; + } + debug("Loading pedstats data...\n"); + CPedStats::LoadPedStats(); + debug("CPedStats ready\n"); +} + +void +CPedStats::Shutdown(void) +{ + int i; + debug("Shutting down CPedStats...\n"); + for(i = 0; i < NUM_PEDSTATS; i++) + delete ms_apPedStats[i]; + debug("CPedStats shut down\n"); +} + +void +CPedStats::LoadPedStats(void) +{ + char *buf; + char line[256]; + char name[32]; + size_t bp, buflen; + int lp, linelen; + int type; + float fleeDist, headingChangeRate, attackStrength, defendWeakness; + int fear, temper, lawfullness, sexiness, flags; + + + type = 0; + buf = new char[16 * 1024]; + + CFileMgr::SetDir("DATA"); + buflen = CFileMgr::LoadFile("PEDSTATS.DAT", (uint8*)buf, 16 * 1024, "r"); + CFileMgr::SetDir(""); + + for(bp = 0; bp < buflen; ){ + // read file line by line + for(linelen = 0; buf[bp] != '\n' && bp < buflen; bp++){ + if(buf[bp] == '\r' || buf[bp] == ',' || buf[bp] == '\t') + line[linelen++] = ' '; + else + line[linelen++] = buf[bp]; + } + bp++; + line[linelen] = '\0'; + + // skip white space + for(lp = 0; line[lp] <= ' '; lp++); + + if(lp >= linelen || // FIX: game uses == here, but this is safer if we have empty lines + line[lp] == '#') + continue; + + sscanf(&line[lp], "%s %f %f %d %d %d %d %f %f %d", + name, + &fleeDist, + &headingChangeRate, + &fear, + &temper, + &lawfullness, + &sexiness, + &attackStrength, + &defendWeakness, + &flags); + ms_apPedStats[type]->m_type = (ePedStats)type; + strncpy(ms_apPedStats[type]->m_name, name, 24); // FIX: game uses strcpy + ms_apPedStats[type]->m_fleeDistance = fleeDist; + ms_apPedStats[type]->m_headingChangeRate = headingChangeRate; + ms_apPedStats[type]->m_fear = fear; + ms_apPedStats[type]->m_temper = temper; + ms_apPedStats[type]->m_lawfulness = lawfullness; + ms_apPedStats[type]->m_sexiness = sexiness; + ms_apPedStats[type]->m_attackStrength = attackStrength; + ms_apPedStats[type]->m_defendWeakness = defendWeakness; + ms_apPedStats[type]->m_flags = flags; + type++; + } + + delete[] buf; +} + +ePedStats +CPedStats::GetPedStatType(char *name) +{ + for(uint16 type = 0; type < NUM_PEDSTATS; type++) + if(!CGeneral::faststrcmp(ms_apPedStats[type]->m_name, name)) + return (ePedStats) type; + + return NUM_PEDSTATS; +} diff --git a/src/peds/PedType.h b/src/peds/PedType.h index 3a765da1..3e23c249 100644 --- a/src/peds/PedType.h +++ b/src/peds/PedType.h @@ -92,3 +92,82 @@ public: }; VALIDATE_SIZE(CPedType, 0x20); + +enum ePedStats +{ + PEDSTAT_PLAYER, + PEDSTAT_COP, + PEDSTAT_MEDIC, + PEDSTAT_FIREMAN, + PEDSTAT_GANG1, + PEDSTAT_GANG2, + PEDSTAT_GANG3, + PEDSTAT_GANG4, + PEDSTAT_GANG5, + PEDSTAT_GANG6, + PEDSTAT_GANG7, + PEDSTAT_STREET_GUY, + PEDSTAT_SUIT_GUY, + PEDSTAT_SENSIBLE_GUY, + PEDSTAT_GEEK_GUY, + PEDSTAT_OLD_GUY, + PEDSTAT_TOUGH_GUY, + PEDSTAT_STREET_GIRL, + PEDSTAT_SUIT_GIRL, + PEDSTAT_SENSIBLE_GIRL, + PEDSTAT_GEEK_GIRL, + PEDSTAT_OLD_GIRL, + PEDSTAT_TOUGH_GIRL, + PEDSTAT_TRAMP_MALE, + PEDSTAT_TRAMP_FEMALE, + PEDSTAT_TOURIST, + PEDSTAT_PROSTITUTE, + PEDSTAT_CRIMINAL, + PEDSTAT_BUSKER, + PEDSTAT_TAXIDRIVER, + PEDSTAT_PSYCHO, + PEDSTAT_STEWARD, + PEDSTAT_SPORTSFAN, + PEDSTAT_SHOPPER, + PEDSTAT_OLDSHOPPER, + + NUM_PEDSTATS +}; + +// flags +enum +{ + STAT_PUNCH_ONLY = 1, + STAT_CAN_KNEE_HEAD = 2, + STAT_CAN_KICK = 4, + STAT_CAN_ROUNDHOUSE = 8, + STAT_NO_DIVE = 0x10, + STAT_ONE_HIT_KNOCKDOWN = 0x20, + STAT_SHOPPING_BAGS = 0x40, + STAT_GUN_PANIC = 0x80 +}; + +class CPedStats +{ +public: + ePedStats m_type; + char m_name[24]; + float m_fleeDistance; + float m_headingChangeRate; + int8 m_fear; + int8 m_temper; + int8 m_lawfulness; + int8 m_sexiness; + float m_attackStrength; + float m_defendWeakness; + int16 m_flags; + + static CPedStats *ms_apPedStats[NUM_PEDSTATS]; + + static void Initialise(void); + static void Shutdown(void); + static void LoadPedStats(void); + static ePedStats GetPedStatType(char *name); +}; + +VALIDATE_SIZE(CPedStats, 0x34); \ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 92bbdd45..949f8c54 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -848,6 +848,37 @@ CRenderer::RequestObjectsInFrustum(void) } } +bool +CPed::SetupLighting(void) +{ + ActivateDirectional(); + SetAmbientColoursForPedsCarsAndObjects(); + +#ifndef MASTER + // Originally this was being called through iteration of Sectors, but putting it here is better. + if (GetDebugDisplay() != 0 && !IsPlayer()) + DebugRenderOnePedText(); +#endif + + if (bRenderScorched) { + WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); + } else { + // Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0. + float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition()); + if (!bHasBlip && lightMult != 1.0f) { + SetAmbientAndDirectionalColours(lightMult); + return true; + } + } + return false; +} + +void +CPed::RemoveLighting(bool reset) +{ + CRenderer::RemoveVehiclePedLights(this, reset); +} + float CalcNewDelta(RwV2d *a, RwV2d *b) { diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 95a68769..66afa1d4 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -4182,6 +4182,93 @@ CAutomobile::HasCarStoppedBecauseOfLight(void) return false; } +void +CPed::DeadPedMakesTyresBloody(void) +{ + int minX = CWorld::GetSectorIndexX(GetPosition().x - 2.0f); + if (minX < 0) minX = 0; + int minY = CWorld::GetSectorIndexY(GetPosition().y - 2.0f); + if (minY < 0) minY = 0; + int maxX = CWorld::GetSectorIndexX(GetPosition().x + 2.0f); + if (maxX > NUMSECTORS_X-1) maxX = NUMSECTORS_X-1; + int maxY = CWorld::GetSectorIndexY(GetPosition().y + 2.0f); + if (maxY > NUMSECTORS_Y-1) maxY = NUMSECTORS_Y-1; + + CWorld::AdvanceCurrentScanCode(); + + for (int curY = minY; curY <= maxY; curY++) { + for (int curX = minX; curX <= maxX; curX++) { + CSector *sector = CWorld::GetSector(curX, curY); + MakeTyresMuddySectorList(sector->m_lists[ENTITYLIST_VEHICLES]); + MakeTyresMuddySectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP]); + } + } +} + +void +CPed::MakeTyresMuddySectorList(CPtrList &list) +{ + for (CPtrNode *node = list.first; node; node = node->next) { + CVehicle *veh = (CVehicle*)node->item; + if (veh->IsCar() && veh->m_scanCode != CWorld::GetCurrentScanCode()) { + veh->m_scanCode = CWorld::GetCurrentScanCode(); + + if (Abs(GetPosition().x - veh->GetPosition().x) < 10.0f) { + + if (Abs(GetPosition().y - veh->GetPosition().y) < 10.0f + && veh->m_vecMoveSpeed.MagnitudeSqr2D() > 0.05f) { + + for(int wheel = 0; wheel < 4; wheel++) { + + if (!((CAutomobile*)veh)->m_aWheelSkidmarkBloody[wheel] + && ((CAutomobile*)veh)->m_aSuspensionSpringRatio[wheel] < 1.0f) { + + CColModel *vehCol = veh->GetModelInfo()->GetColModel(); + CVector approxWheelOffset; + switch (wheel) { + case 0: + approxWheelOffset = CVector(-vehCol->boundingBox.max.x, vehCol->boundingBox.max.y, 0.0f); + break; + case 1: + approxWheelOffset = CVector(-vehCol->boundingBox.max.x, vehCol->boundingBox.min.y, 0.0f); + break; + case 2: + approxWheelOffset = CVector(vehCol->boundingBox.max.x, vehCol->boundingBox.max.y, 0.0f); + break; + case 3: + approxWheelOffset = CVector(vehCol->boundingBox.max.x, vehCol->boundingBox.min.y, 0.0f); + break; + default: + break; + } + + // I hope so + CVector wheelPos = veh->GetMatrix() * approxWheelOffset; + if (Abs(wheelPos.z - GetPosition().z) < 2.0f) { + + if ((wheelPos - GetPosition()).MagnitudeSqr2D() < 1.0f) { + if (CGame::nastyGame) { + ((CAutomobile*)veh)->m_aWheelSkidmarkBloody[wheel] = true; + DMAudio.PlayOneShot(veh->m_audioEntityId, SOUND_SPLATTER, 0.0f); + } + veh->ApplyMoveForce(CVector(0.0f, 0.0f, 50.0f)); + + CVector vehAndWheelDist = wheelPos - veh->GetPosition(); + veh->ApplyTurnForce(CVector(0.0f, 0.0f, 50.0f), vehAndWheelDist); + + if (veh == FindPlayerVehicle()) { + CPad::GetPad(0)->StartShake(300, 70); + } + } + } + } + } + } + } + } + } +} + void CAutomobile::SetBusDoorTimer(uint32 timer, uint8 type) { diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 9494c745..dc15485e 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -2287,6 +2287,16 @@ CWeapon::HasWeaponAmmoToBeUsed(void) } } +bool +CPed::IsPedDoingDriveByShooting(void) +{ + if (FindPlayerPed() == this && GetWeapon()->m_eWeaponType == WEAPONTYPE_UZI) { + if (TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight) + return true; + } + return false; +} + bool CWeapon::ProcessLineOfSight(CVector const &point1, CVector const &point2, CColPoint &point, CEntity *&entity, eWeaponType type, CEntity *shooter, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects) { From 6b6b600cee9bda19d10868b5263cf477043ce56a Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sat, 21 Nov 2020 21:12:47 +0300 Subject: [PATCH 071/129] no script logging --- src/core/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/config.h b/src/core/config.h index db6e5490..f7a3853d 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -295,7 +295,7 @@ enum Config { #endif //#define SIMPLIER_MISSIONS // apply simplifications from mobile #define USE_ADVANCED_SCRIPT_DEBUG_OUTPUT -#define SCRIPT_LOG_FILE_LEVEL 1 // 0 == no log, 1 == overwrite every frame, 2 == full log +#define SCRIPT_LOG_FILE_LEVEL 0 // 0 == no log, 1 == overwrite every frame, 2 == full log #ifndef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT #define USE_BASIC_SCRIPT_DEBUG_OUTPUT From 07303c62d12959927cbb72d4beb131f2647350fa Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 22 Nov 2020 00:13:07 +0100 Subject: [PATCH 072/129] finished cullzones --- src/core/ZoneCull.cpp | 1165 ++++++++++++++++++++++++++++++++-- src/core/ZoneCull.h | 32 +- src/core/re3.cpp | 3 + src/render/Renderer.cpp | 206 +++++- src/render/Renderer.h | 22 + src/rw/VisibilityPlugins.cpp | 2 - 6 files changed, 1326 insertions(+), 104 deletions(-) diff --git a/src/core/ZoneCull.cpp b/src/core/ZoneCull.cpp index c376e11f..075a13bc 100644 --- a/src/core/ZoneCull.cpp +++ b/src/core/ZoneCull.cpp @@ -1,5 +1,6 @@ #include "common.h" +#include "General.h" #include "Building.h" #include "Treadable.h" #include "Train.h" @@ -11,6 +12,9 @@ #include "ZoneCull.h" #include "Zones.h" +#include "Debug.h" +#include "Renderer.h" + int32 CCullZones::NumCullZones; CCullZone CCullZones::aZones[NUMCULLZONES]; int32 CCullZones::NumAttributeZones; @@ -27,6 +31,8 @@ int32 CCullZones::EntityIndicesUsed; bool CCullZones::bCurrentSubwayIsInvisible; bool CCullZones::bCullZonesDisabled; +#define NUMUNCOMPRESSED (6000) +#define NUMTEMPINDICES (140000) void CCullZones::Init(void) @@ -48,26 +54,6 @@ CCullZones::Init(void) aPointersToBigBuildingsForTreadables[i] = -1; } -bool CCullZone::TestLine(CVector vec1, CVector vec2) -{ - CColPoint colPoint; - CEntity *entity; - - if (CWorld::ProcessLineOfSight(vec1, vec2, colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x + 0.05f, vec1.y, vec1.z), CVector(vec2.x + 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x - 0.05f, vec1.y, vec1.z), CVector(vec2.x - 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y + 0.05f, vec1.z), CVector(vec2.x, vec2.y + 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y - 0.05f, vec1.z), CVector(vec2.x, vec2.y - 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) - return true; - if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z + 0.05f), CVector(vec2.x, vec2.y, vec2.z + 0.05f), colPoint, entity, true, false, false, false, false, true, false)) - return true; - return CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z - 0.05f), CVector(vec2.x, vec2.y, vec2.z - 0.05f), colPoint, entity, true, false, false, false, false, true, false); -} - uint16* pTempArrayIndices; int TempEntityIndicesUsed; @@ -89,19 +75,25 @@ CCullZones::ResolveVisibilities(void) CFileMgr::Read(fd, (char*)aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables)); CFileMgr::CloseFile(fd); }else{ -#if 0 - // TODO: implement code from mobile to generate data here +#ifndef MASTER EntityIndicesUsed = 0; BuildListForBigBuildings(); - pTempArrayIndices = new uint16[140000]; + pTempArrayIndices = new uint16[NUMTEMPINDICES]; TempEntityIndicesUsed = 0; - for (int i = 0; i < NumCullZones; i++) { - DoVisibilityTestCullZone(i, true); +// if(!LoadTempFile()) // not in final game + { + for (int i = 0; i < NumCullZones; i++) { +//printf("testing zone %d (%d indices)\n", i, TempEntityIndicesUsed); + DoVisibilityTestCullZone(i, true); + } + +// SaveTempFile(); // not in final game } CompressIndicesArray(); delete[] pTempArrayIndices; + pTempArrayIndices = nil; fd = CFileMgr::OpenFileForWriting("data\\cullzone.dat"); if (fd != 0) { @@ -118,16 +110,53 @@ CCullZones::ResolveVisibilities(void) } } +bool +CCullZones::LoadTempFile(void) +{ + int fd = CFileMgr::OpenFile("cullzone.tmp"); + if (fd != 0) { + CFileMgr::Read(fd, (char*)&NumCullZones, sizeof(NumCullZones)); + CFileMgr::Read(fd, (char*)aZones, sizeof(aZones)); + CFileMgr::Read(fd, (char*)&NumAttributeZones, sizeof(NumAttributeZones)); + CFileMgr::Read(fd, (char*)&aAttributeZones, sizeof(aAttributeZones)); + CFileMgr::Read(fd, (char*)pTempArrayIndices, NUMTEMPINDICES*sizeof(uint16)); + CFileMgr::Read(fd, (char*)&TempEntityIndicesUsed, sizeof(TempEntityIndicesUsed)); + CFileMgr::Read(fd, (char*)&aPointersToBigBuildingsForBuildings, sizeof(aPointersToBigBuildingsForBuildings)); + CFileMgr::Read(fd, (char*)&aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables)); + CFileMgr::CloseFile(fd); + return true; + } + return false; +} + +void +CCullZones::SaveTempFile(void) +{ + int fd = CFileMgr::OpenFileForWriting("cullzone.tmp"); + if (fd != 0) { + CFileMgr::Write(fd, (char*)&NumCullZones, sizeof(NumCullZones)); + CFileMgr::Write(fd, (char*)aZones, sizeof(aZones)); + CFileMgr::Write(fd, (char*)&NumAttributeZones, sizeof(NumAttributeZones)); + CFileMgr::Write(fd, (char*)&aAttributeZones, sizeof(aAttributeZones)); + CFileMgr::Write(fd, (char*)pTempArrayIndices, NUMTEMPINDICES*sizeof(uint16)); + CFileMgr::Write(fd, (char*)&TempEntityIndicesUsed, sizeof(TempEntityIndicesUsed)); + CFileMgr::Write(fd, (char*)&aPointersToBigBuildingsForBuildings, sizeof(aPointersToBigBuildingsForBuildings)); + CFileMgr::Write(fd, (char*)&aPointersToBigBuildingsForTreadables, sizeof(aPointersToBigBuildingsForTreadables)); + CFileMgr::CloseFile(fd); + } +} + + void CCullZones::BuildListForBigBuildings() { for (int i = CPools::GetBuildingPool()->GetSize()-1; i >= 0; i--) { CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); if (building == nil || !building->bIsBIGBuilding) continue; - CSimpleModelInfo *nonlod = (CSimpleModelInfo*)((CSimpleModelInfo *)CModelInfo::GetModelInfo(building->GetModelIndex()))->m_atomics[2]; + CSimpleModelInfo *nonlod = ((CSimpleModelInfo *)CModelInfo::GetModelInfo(building->GetModelIndex()))->GetRelatedModel(); if (nonlod == nil) continue; - for (int j = i; j >= 0; j--) { + for (int j = CPools::GetBuildingPool()->GetSize()-1; j >= 0; j--) { CBuilding *building2 = CPools::GetBuildingPool()->GetSlot(j); if (building2 == nil || building2->bIsBIGBuilding) continue; if (CModelInfo::GetModelInfo(building2->GetModelIndex()) == nonlod) { @@ -150,7 +179,7 @@ CCullZones::BuildListForBigBuildings() } void -CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) +CCullZones::DoVisibilityTestCullZone(int zoneId, bool findIndices) { aZones[zoneId].m_groupIndexCount[0] = 0; aZones[zoneId].m_groupIndexCount[1] = 0; @@ -158,16 +187,17 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) aZones[zoneId].m_indexStart = TempEntityIndicesUsed; aZones[zoneId].FindTestPoints(); - if (!doIt) return; + if (!findIndices) return; for (int i = CPools::GetBuildingPool()->GetSize() - 1; i >= 0; i--) { CBuilding *building = CPools::GetBuildingPool()->GetSlot(i); if (building != nil && !building->bIsBIGBuilding && aZones[zoneId].IsEntityCloseEnoughToZone(building, aPointersToBigBuildingsForBuildings[i] != -1)) { - CBuilding *building2 = nil; + CBuilding *LODbuilding = nil; if (aPointersToBigBuildingsForBuildings[i] != -1) - building2 = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForBuildings[i]); + LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForBuildings[i]); - if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, building2)) { + if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, LODbuilding)) { + assert(TempEntityIndicesUsed < NUMTEMPINDICES); pTempArrayIndices[TempEntityIndicesUsed++] = i; aZones[zoneId].m_groupIndexCount[0]++; } @@ -175,13 +205,14 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) } for (int i = CPools::GetTreadablePool()->GetSize() - 1; i >= 0; i--) { - CTreadable* building = CPools::GetTreadablePool()->GetSlot(i); + CBuilding* building = CPools::GetTreadablePool()->GetSlot(i); if (building != nil && aZones[zoneId].IsEntityCloseEnoughToZone(building, aPointersToBigBuildingsForTreadables[i] != -1)) { - CTreadable* building2 = nil; + CBuilding *LODbuilding = nil; if (aPointersToBigBuildingsForTreadables[i] != -1) - building2 = CPools::GetTreadablePool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); + LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); - if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 10.0f, building2)) { + if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 10.0f, LODbuilding)) { + assert(TempEntityIndicesUsed < NUMTEMPINDICES); pTempArrayIndices[TempEntityIndicesUsed++] = i; aZones[zoneId].m_groupIndexCount[1]++; } @@ -189,23 +220,28 @@ CCullZones::DoVisibilityTestCullZone(int zoneId, bool doIt) } for (int i = CPools::GetTreadablePool()->GetSize() - 1; i >= 0; i--) { - CTreadable *building = CPools::GetTreadablePool()->GetSlot(i); - if (building != nil && aZones[zoneId].CalcDistToCullZoneSquared(building->GetPosition().x, building->GetPosition().y) < 40000.0f) { + CBuilding *building = CPools::GetTreadablePool()->GetSlot(i); + if (building != nil && aZones[zoneId].CalcDistToCullZoneSquared(building->GetPosition().x, building->GetPosition().y) < SQR(200.0f)) { int start = aZones[zoneId].m_groupIndexCount[0] + aZones[zoneId].m_indexStart; int end = aZones[zoneId].m_groupIndexCount[1] + start; bool alreadyAdded = false; for (int k = start; k < end; k++) { +#ifdef FIX_BUGS + if (pTempArrayIndices[k] == i) +#else if (aIndices[k] == i) +#endif alreadyAdded = true; } if (!alreadyAdded) { - CBuilding *building2 = nil; + CBuilding *LODbuilding = nil; if (aPointersToBigBuildingsForTreadables[i] != -1) - building2 = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); - if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, building2)) { + LODbuilding = CPools::GetBuildingPool()->GetSlot(aPointersToBigBuildingsForTreadables[i]); + if (!aZones[zoneId].TestEntityVisibilityFromCullZone(building, 0.0f, LODbuilding)) { + assert(TempEntityIndicesUsed < NUMTEMPINDICES); pTempArrayIndices[TempEntityIndicesUsed++] = i; aZones[zoneId].m_groupIndexCount[2]++; } @@ -353,7 +389,9 @@ CCullZones::AddCullZone(CVector const &position, if((flag & ATTRZONE_NOTCULLZONE) == 0){ cull = &aZones[NumCullZones++]; v = position; - // WTF is this? + // reposition start point to the start/end of the + // alley next to the big building in the industrial district. + // probably isn't analyzed correctly otherwise?s if((v-CVector(1032.14f, -624.255f, 24.93f)).Magnitude() < 1.0f) v = CVector(1061.7f, -613.0f, 19.0f); if((v-CVector(1029.48f, -495.757f, 21.98f)).Magnitude() < 1.0f) @@ -385,6 +423,208 @@ CCullZones::AddCullZone(CVector const &position, } } +uint16 *pExtraArrayIndices; + +void +CCullZones::CompressIndicesArray() +{ + uint16 set[3]; + + // These are used to hold the compressed groups in sets of 3 + int numExtraIndices = 0; + pExtraArrayIndices = new uint16[NUMTEMPINDICES]; + + for(int numOccurrences = 6; numOccurrences > 1; numOccurrences--){ + if(NumCullZones == 0) + break; + +//printf("checking occurrences %d\n", numOccurrences); + int attempt = 0; + while(attempt < 10000){ + for(;;){ + attempt++; + + int zone = CGeneral::GetRandomNumber() % NumCullZones; + int group = CGeneral::GetRandomNumber() % 3; + if(!PickRandomSetForGroup(zone, group, set)) + break; + if(!DoWeHaveMoreThanXOccurencesOfSet(numOccurrences, set)) + break; + + // add this set + attempt = 1; + int setId = numExtraIndices + NUMUNCOMPRESSED; + pExtraArrayIndices[numExtraIndices++] = set[0]; + pExtraArrayIndices[numExtraIndices++] = set[1]; + pExtraArrayIndices[numExtraIndices++] = set[2]; + ReplaceSetForAllGroups(set, setId); + } + } + } + + TidyUpAndMergeLists(pExtraArrayIndices, numExtraIndices); + + delete[] pExtraArrayIndices; +} + +// Get three random indices for this group of a zone +bool +CCullZones::PickRandomSetForGroup(int32 zone, int32 group, uint16 *set) +{ + int32 start; + int32 size; + + aZones[zone].GetGroupStartAndSize(group, start, size); + if(size <= 0) + return false; + + int numIndices = 0; + for(int i = 0; i < size; i++) + if(pTempArrayIndices[start + i] != 0xFFFF) + numIndices++; + if(numIndices < 3) + return false; + + int first = CGeneral::GetRandomNumber() % (numIndices-2); + + numIndices = 0; + int n = 0; + for(int i = 0; i < size; i++) + if(pTempArrayIndices[start + i] != 0xFFFF){ + if(n++ < first) continue; + + set[numIndices++] = pTempArrayIndices[start + i]; + if(numIndices == 3) + break; + } + return true; +} + +bool +CCullZones::DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set) +{ + int32 curCount; + int32 start; + int32 size; + + curCount = 0; + for (int i = 0; i < NumCullZones; i++) { + for (int group = 0; group < 3; group++) { + aZones[i].GetGroupStartAndSize(group, start, size); + if(size <= 0) continue; + + // check if the set is a subset of the group + int n = 0; + for (int j = 0; j < size; j++) { + for (int k = 0; k < 3; k++) { + if (pTempArrayIndices[start+j] == set[k]) + n++; + } + } + // yes it is + if(n == 3){ + curCount++; + // check if we have seen this set often enough + if(curCount >= count) + return true; + } + } + } + return false; +} + +void +CCullZones::ReplaceSetForAllGroups(uint16 *set, uint16 setid) +{ + int32 start; + int32 size; + + for(int i = 0; i < NumCullZones; i++) + for(int group = 0; group < 3; group++){ + aZones[i].GetGroupStartAndSize(group, start, size); + if(size <= 0) continue; + + // check if the set is a subset of the group + int n = 0; + for(int j = 0; j < size; j++){ + for(int k = 0; k < 3; k++){ + if(pTempArrayIndices[start+j] == set[k]) + n++; + } + } + + // yes it is, so replace it + if(n == 3){ + bool insertedSet = false; + for(int j = 0; j < size; j++){ + for(int k = 0; k < 3; k++){ + // replace first element by set, invalidate others + if(pTempArrayIndices[start+j] == set[k]){ + if(!insertedSet) + pTempArrayIndices[start+j] = setid; + else + pTempArrayIndices[start+j] = 0xFFFF; + insertedSet = true; + } + } + } + } + } +} + +void +CCullZones::TidyUpAndMergeLists(uint16 *extraIndices, int32 numExtraIndices) +{ + int numTempIndices = 0; + for(int i = 0; i < TempEntityIndicesUsed; i++) + if(pTempArrayIndices[i] != 0xFFFF) + numTempIndices++; + + // Fix up zone ranges such that there are no holes + for(int i = 0; i < NumCullZones; i++){ + int j; + int start = 0; + for(j = 0; j < aZones[i].m_indexStart; j++) + if(pTempArrayIndices[j] != 0xFFFF) + start++; + + aZones[i].m_indexStart = start; + aZones[i].m_numBuildings = 0; + aZones[i].m_numTreadablesPlus10m = 0; + aZones[i].m_numTreadables = 0; + + for(int k = 0; k < aZones[i].m_groupIndexCount[0]; k++) + if(pTempArrayIndices[j++] != 0xFFFF) + aZones[i].m_numBuildings++; + for(int k = 0; k < aZones[i].m_groupIndexCount[1]; k++) + if(pTempArrayIndices[j++] != 0xFFFF) + aZones[i].m_numTreadablesPlus10m++; + for(int k = 0; k < aZones[i].m_groupIndexCount[2]; k++) + if(pTempArrayIndices[j++] != 0xFFFF) + aZones[i].m_numTreadables++; + } + + // Now copy the actually used indices + EntityIndicesUsed = 0; + for(int i = 0; i < TempEntityIndicesUsed; i++) + if(pTempArrayIndices[i] != 0xFFFF){ + assert(EntityIndicesUsed < NUMZONEINDICES); + if(pTempArrayIndices[i] < NUMUNCOMPRESSED) + aIndices[EntityIndicesUsed++] = pTempArrayIndices[i]; + else + aIndices[EntityIndicesUsed++] = pTempArrayIndices[i] + numTempIndices; + } + for(int i = 0; i < numExtraIndices; i++) + if(extraIndices[i] != 0xFFFF){ + assert(EntityIndicesUsed < NUMZONEINDICES); + if(extraIndices[i] < NUMUNCOMPRESSED) + aIndices[EntityIndicesUsed++] = extraIndices[i]; + else + aIndices[EntityIndicesUsed++] = extraIndices[i] + numTempIndices; + } +} + + void CCullZone::DoStuffLeavingZone(void) @@ -403,13 +643,14 @@ CCullZone::DoStuffLeavingZone_OneBuilding(uint16 i) int16 bb; int j; - if(i < 6000){ + + if(i < NUMUNCOMPRESSED){ CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = false; bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffLeavingZone_OneBuilding(CCullZones::aIndices[i+j]); } @@ -421,14 +662,14 @@ CCullZone::DoStuffLeavingZone_OneTreadableBoth(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = false; CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = false; bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = false; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffLeavingZone_OneTreadableBoth(CCullZones::aIndices[i+j]); } @@ -453,13 +694,13 @@ CCullZone::DoStuffEnteringZone_OneBuilding(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetBuildingPool()->GetSlot(i)->bZoneCulled = true; bb = CCullZones::aPointersToBigBuildingsForBuildings[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffEnteringZone_OneBuilding(CCullZones::aIndices[i+j]); } @@ -471,14 +712,14 @@ CCullZone::DoStuffEnteringZone_OneTreadablePlus10m(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true; CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled2 = true; bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffEnteringZone_OneTreadablePlus10m(CCullZones::aIndices[i+j]); } @@ -490,13 +731,13 @@ CCullZone::DoStuffEnteringZone_OneTreadable(uint16 i) int16 bb; int j; - if(i < 6000){ + if(i < NUMUNCOMPRESSED){ CPools::GetTreadablePool()->GetSlot(i)->bZoneCulled = true; bb = CCullZones::aPointersToBigBuildingsForTreadables[i]; if(bb != -1) CPools::GetBuildingPool()->GetSlot(bb)->bZoneCulled = true; }else{ - i -= 6000; + i -= NUMUNCOMPRESSED; for(j = 0; j < 3; j++) DoStuffEnteringZone_OneTreadable(CCullZones::aIndices[i+j]); } @@ -518,6 +759,68 @@ CCullZone::CalcDistToCullZoneSquared(float x, float y) return rx + ry; } +bool +CCullZone::TestLine(CVector vec1, CVector vec2) +{ + CColPoint colPoint; + CEntity *entity; + + if (CWorld::ProcessLineOfSight(vec1, vec2, colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x + 0.05f, vec1.y, vec1.z), CVector(vec2.x + 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x - 0.05f, vec1.y, vec1.z), CVector(vec2.x - 0.05f, vec2.y, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y + 0.05f, vec1.z), CVector(vec2.x, vec2.y + 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y - 0.05f, vec1.z), CVector(vec2.x, vec2.y - 0.05f, vec2.z), colPoint, entity, true, false, false, false, false, true, false)) + return true; + if (CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z + 0.05f), CVector(vec2.x, vec2.y, vec2.z + 0.05f), colPoint, entity, true, false, false, false, false, true, false)) + return true; + return CWorld::ProcessLineOfSight(CVector(vec1.x, vec1.y, vec1.z - 0.05f), CVector(vec2.x, vec2.y, vec2.z - 0.05f), colPoint, entity, true, false, false, false, false, true, false); +} + +bool +CCullZone::DoThoroughLineTest(CVector start, CVector end, CEntity *testEntity) +{ + CColPoint colPoint; + CEntity *entity; + + if(CWorld::ProcessLineOfSight(start, end, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + + CVector side; +#ifdef FIX_BUGS + if(start.x != end.x || start.y != end.y) +#else + if(start.x != end.x && start.y != end.y) +#endif + side = CVector(0.0f, 0.0f, 1.0f); + else + side = CVector(1.0f, 0.0f, 0.0f); + CVector up = CrossProduct(side, end - start); + side = CrossProduct(up, end - start); + side.Normalise(); + up.Normalise(); + side *= 0.1f; + up *= 0.1f; + + if(CWorld::ProcessLineOfSight(start+side, end+side, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + if(CWorld::ProcessLineOfSight(start-side, end-side, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + if(CWorld::ProcessLineOfSight(start+up, end+up, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + if(CWorld::ProcessLineOfSight(start-up, end-up, colPoint, entity, true, false, false, false, false, true, false) && + testEntity != entity) + return false; + return true; +} + bool CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel) { @@ -526,10 +829,10 @@ CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel) CSimpleModelInfo *minfo = (CSimpleModelInfo*)CModelInfo::GetModelInfo(entity->GetModelIndex()); float distToZone = CalcDistToCullZone(pos.x, pos.y); float lodDist; - if (minfo->m_isSubway) - lodDist = minfo->GetLargestLodDistance() + 30.0f; + if (minfo->m_noFade) + lodDist = minfo->GetLargestLodDistance() + STREAM_DISTANCE; else - lodDist = minfo->GetLargestLodDistance() + 50.0f; + lodDist = minfo->GetLargestLodDistance() + STREAM_DISTANCE + FADE_DISTANCE; if (lodDist > distToZone) return true; if (!checkLevel) return false; @@ -538,27 +841,749 @@ CCullZone::IsEntityCloseEnoughToZone(CEntity *entity, bool checkLevel) } bool -CCullZones::DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set) +CCullZone::PointFallsWithinZone(CVector pos, float radius) { - int32 curCount; - int32 start; - int32 size; + if(minx - radius > pos.x || + maxx + radius < pos.x || + miny - radius > pos.y || + maxy + radius < pos.y || + minz - radius > pos.z || + maxz + radius < pos.z) + return false; + return true; +} - for (int i = 0; i < NumCullZones; i++) { - curCount = 0; - for (int group = 0; group < 3; group++) { - aZones[i].GetGroupStartAndSize(group, start, size); - int unk = 0; // TODO: figure out - for (int j = 0; j < size; j++) { - for (int k = 0; k < 3; k++) { - if (set[k] == pTempArrayIndices[start+j]) - unk++; +CVector ExtraFudgePointsCoors[] = { + CVector(978.0, -394.0, 18.0), + CVector(1189.7, -414.6, 27.0), + CVector(978.8, -391.0, 19.0), + CVector(1199.0, -502.3, 28.0), + CVector(1037.0, -391.9, 18.4), + CVector(1140.0, -608.7, 16.0), + CVector(1051.0, -26.0, 11.0), + CVector(951.5, -345.1, 12.0), + CVector(958.2, -394.6, 16.0), + CVector(1036.5, -390.0, 15.2), + CVector(960.6, -390.5, 20.9), + CVector(1061.0, -640.6, 16.3), + CVector(1034.5, -388.96, 14.78), + CVector(1038.4, -13.98, 12.2), + CVector(1047.2, -16.7, 10.6), + CVector(1257.9, -333.3, 40.0), + CVector(885.6, -424.9, 17.0), + CVector(1127.5, -795.8, 17.7), + CVector(1133.0, -716.0, 19.0), + CVector(1125.0, -694.0, 18.5), + CVector(1125.0, -670.0, 16.3), + CVector(1051.6, 36.3, 17.9), + CVector(1054.6, -11.4, 15.0), + CVector(1058.9, -278.0, 15.0), + CVector(1059.4, -261.0, 10.9), + CVector(1051.5, -638.5, 16.5), + CVector(1058.2, -643.4, 15.5), + CVector(1058.2, -643.4, 18.0), + CVector(826.0, -260.0, 7.0), + CVector(826.0, -260.0, 11.0), + CVector(833.0, -603.6, 16.4), + CVector(833.0, -603.6, 20.0), + CVector(1002.0, -318.5, 10.5), + CVector(998.0, -318.0, 9.8), + CVector(1127.0, -183.0, 18.1), + CVector(1123.0, -331.5, 23.8), + CVector(1123.8, -429.0, 24.0), + CVector(1197.0, -30.0, 13.7), + CVector(1117.5, -230.0, 17.3), + CVector(1117.5, -230.0, 20.0), + CVector(1120.0, -281.6, 21.5), + CVector(1120.0, -281.6, 24.0), + CVector(1084.5, -1022.7, 17.0), + CVector(1071.5, 5.4, 4.6), + CVector(1177.2, -215.7, 27.6), + CVector(841.6, -460.0, 19.7), + CVector(874.8, -456.6, 16.6), + CVector(918.3, -451.8, 17.8), + CVector(844.0, -495.7, 16.7), + CVector(842.0, -493.4, 21.0), + CVector(1433.5, -774.4, 16.9), + CVector(1051.0, -205.0, 7.5), + CVector(885.5, -425.6, 15.6), + CVector(182.6, -470.4, 27.8), + CVector(132.5, -930.2, 29.0), + CVector(124.7, -904.0, 28.0), + CVector(-50.0, -686.0, 22.0), + CVector(-49.1, -694.5, 22.5), + CVector(1063.8, -404.45, 16.2), + CVector(1062.2, -405.5, 17.0) +}; +int32 NumTestPoints; +int32 aTestPointsX[100]; +int32 aTestPointsY[100]; +int32 aTestPointsZ[100]; +CVector aTestPoints[100]; +int32 ElementsX, ElementsY, ElementsZ; +float StepX, StepY, StepZ; +int32 Memsize; +uint8 *pMem; +#define MEM(x, y, z) pMem[((x)*ElementsY + (y))*ElementsZ + (z)] +#define FLAG_FREE 1 +#define FLAG_PROCESSED 2 + +int32 MinValX, MaxValX; +int32 MinValY, MaxValY; +int32 MinValZ, MaxValZ; +int32 Point1, Point2; +int32 NewPointX, NewPointY, NewPointZ; + + +void +CCullZone::FindTestPoints() +{ + static int CZNumber; + + NumTestPoints = 0; + ElementsX = (maxx-minx) < 1.0f ? 2 : (maxx-minx)+1.0f; + ElementsY = (maxy-miny) < 1.0f ? 2 : (maxy-miny)+1.0f; + ElementsZ = (maxz-minz) < 1.0f ? 2 : (maxz-minz)+1.0f; + if(ElementsX > 32) ElementsX = 32; + if(ElementsY > 32) ElementsY = 32; + if(ElementsZ > 32) ElementsZ = 32; + Memsize = ElementsX * ElementsY * ElementsZ; + StepX = (maxx-minx)/(ElementsX-1); + StepY = (maxy-miny)/(ElementsY-1); + StepZ = (maxz-minz)/(ElementsZ-1); + + pMem = new uint8[Memsize]; + memset(pMem, 0, Memsize); + + // indices of center + int x = ElementsX * (position.x-minx)/(maxx-minx); + x = clamp(x, 0, ElementsX-1); + int y = ElementsY * (position.y-miny)/(maxy-miny); + y = clamp(y, 0, ElementsY-1); + int z = ElementsZ * (position.z-minz)/(maxz-minz); + z = clamp(z, 0, ElementsZ-1); + + // Mark which test points inside the zone are not occupied by buildings. + // To do this, mark the start point as free and do a food fill. + + // NB: we just assume the start position is free here! + MEM(x, y, z) |= FLAG_FREE; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + NumTestPoints++; + + bool notDoneYet; + do{ + notDoneYet = false; + for(x = 0; x < ElementsX; x++){ + for(y = 0; y < ElementsY; y++){ + for(z = 0; z < ElementsZ; z++){ + if(!(MEM(x, y, z) & FLAG_FREE) || MEM(x, y, z) & FLAG_PROCESSED) + continue; + + float pX = x*StepX + minx; + float pY = y*StepY + miny; + float pZ = z*StepZ + minz; + + if(x > 0 && !(MEM(x-1, y, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX-StepX, pY, pZ))) + MEM(x-1, y, z) |= FLAG_FREE; + if(x < ElementsX-1 && !(MEM(x+1, y, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX+StepX, pY, pZ))) + MEM(x+1, y, z) |= FLAG_FREE; + + if(y > 0 && !(MEM(x, y-1, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY-StepY, pZ))) + MEM(x, y-1, z) |= FLAG_FREE; + if(y < ElementsY-1 && !(MEM(x, y+1, z) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY+StepY, pZ))) + MEM(x, y+1, z) |= FLAG_FREE; + + if(z > 0 && !(MEM(x, y, z-1) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY, pZ-StepZ))) + MEM(x, y, z-1) |= FLAG_FREE; + if(z < ElementsZ-1 && !(MEM(x, y, z+1) & (FLAG_FREE | FLAG_PROCESSED)) && + !TestLine(CVector(pX, pY, pZ), CVector(pX, pY, pZ+StepZ))) + MEM(x, y, z+1) |= FLAG_FREE; + + notDoneYet = true; + MEM(x, y, z) |= FLAG_PROCESSED; } } - if (unk == 3 && ++curCount >= count) - return true; + } + }while(notDoneYet); + + bool done; + + // Find bound planes of free space + + // increase x, bounds in y and z + x = 0; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(y + z < minA){ + minA = y + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(y + z > maxA){ + maxA = y + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(y - z < minB){ + minB = y - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(y - z > maxB){ + maxB = y - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + x++; + }while(!done); + NumTestPoints += 4; + + // decrease x, bounds in y and z + x = ElementsX-1; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(y + z < minA){ + minA = y + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(y + z > maxA){ + maxA = y + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(y - z < minB){ + minB = y - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(y - z > maxB){ + maxB = y - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + x--; + }while(!done); + NumTestPoints += 4; + + // increase y, bounds in x and z + y = 0; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + z < minA){ + minA = x + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + z > maxA){ + maxA = x + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - z < minB){ + minB = x - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - z > maxB){ + maxB = x - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + y++; + }while(!done); + NumTestPoints += 4; + + // decrease y, bounds in x and z + y = ElementsY-1; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + z < minA){ + minA = x + z; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + z > maxA){ + maxA = x + z; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - z < minB){ + minB = x - z; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - z > maxB){ + maxB = x - z; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + y--; + }while(!done); + NumTestPoints += 4; + + // increase z, bounds in x and y + z = 0; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + y < minA){ + minA = x + y; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + y > maxA){ + maxA = x + y; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - y < minB){ + minB = x - y; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - y > maxB){ + maxB = x - y; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + z++; + }while(!done); + NumTestPoints += 4; + + // decrease z, bounds in x and y + z = ElementsZ-1; + do{ + done = false; + int minA = 10000; + int minB = 10000; + int maxA = -10000; + int maxB = -10000; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, z) & FLAG_FREE){ + if(x + y < minA){ + minA = x + y; + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + } + if(x + y > maxA){ + maxA = x + y; + aTestPointsX[NumTestPoints+1] = x; + aTestPointsY[NumTestPoints+1] = y; + aTestPointsZ[NumTestPoints+1] = z; + } + if(x - y < minB){ + minB = x - y; + aTestPointsX[NumTestPoints+2] = x; + aTestPointsY[NumTestPoints+2] = y; + aTestPointsZ[NumTestPoints+2] = z; + } + if(x - y > maxB){ + maxB = x - y; + aTestPointsX[NumTestPoints+3] = x; + aTestPointsY[NumTestPoints+3] = y; + aTestPointsZ[NumTestPoints+3] = z; + } + done = true; + } + z--; + }while(!done); + NumTestPoints += 4; + + // divide the axis aligned bounding planes into 4 and place some test points + + // x = 0 plane + MinValY = 999999; + MinValZ = 999999; + MaxValY = 0; + MaxValZ = 0; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(0, y, z) & FLAG_FREE){ + if(y < MinValY) MinValY = y; + if(z < MinValZ) MinValZ = z; + if(y > MaxValY) MaxValY = y; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValY != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointY = (Point1 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(0, NewPointY, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = 0; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // x = ElementsX-1 plane + MinValY = 999999; + MinValZ = 999999; + MaxValY = 0; + MaxValZ = 0; + for(y = 0; y < ElementsY; y++) + for(z = 0; z < ElementsZ; z++) + if(MEM(ElementsX-1, y, z) & FLAG_FREE){ + if(y < MinValY) MinValY = y; + if(z < MinValZ) MinValZ = z; + if(y > MaxValY) MaxValY = y; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValY != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointY = (Point1 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(ElementsX-1, NewPointY, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = ElementsX-1; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // y = 0 plane + MinValX = 999999; + MinValZ = 999999; + MaxValX = 0; + MaxValZ = 0; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, 0, z) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(z < MinValZ) MinValZ = z; + if(x > MaxValX) MaxValX = x; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(NewPointX, 0, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = 0; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // y = ElementsY-1 plane + MinValX = 999999; + MinValZ = 999999; + MaxValX = 0; + MaxValZ = 0; + for(x = 0; x < ElementsX; x++) + for(z = 0; z < ElementsZ; z++) + if(MEM(x, ElementsY-1, z) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(z < MinValZ) MinValZ = z; + if(x > MaxValX) MaxValX = x; + if(z > MaxValZ) MaxValZ = z; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValZ != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointZ = (Point2 + 0.5f)*(MaxValZ - MinValZ)*0.5f + MinValZ; + if(MEM(NewPointX, ElementsY-1, NewPointZ) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = ElementsY-1; + aTestPointsZ[NumTestPoints] = NewPointZ; + NumTestPoints++; + } + } + + // z = 0 plane + MinValX = 999999; + MinValY = 999999; + MaxValX = 0; + MaxValY = 0; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, 0) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(y < MinValY) MinValY = y; + if(x > MaxValX) MaxValX = x; + if(y > MaxValY) MaxValY = y; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValY != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointY = (Point2 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + if(MEM(NewPointX, NewPointY, 0) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = 0; + NumTestPoints++; + } + } + + // z = ElementsZ-1 plane + MinValX = 999999; + MinValY = 999999; + MaxValX = 0; + MaxValY = 0; + for(x = 0; x < ElementsX; x++) + for(y = 0; y < ElementsY; y++) + if(MEM(x, y, ElementsZ-1) & FLAG_FREE){ + if(x < MinValX) MinValX = x; + if(y < MinValY) MinValY = y; + if(x > MaxValX) MaxValX = x; + if(y > MaxValY) MaxValY = y; + } + // pick 4 points in the found bounds and add new test points + if(MaxValX != 0 && MaxValY != 0) + for(Point1 = 0; Point1 < 2; Point1++) + for(Point2 = 0; Point2 < 2; Point2++){ + NewPointX = (Point1 + 0.5f)*(MaxValX - MinValX)*0.5f + MinValX; + NewPointY = (Point2 + 0.5f)*(MaxValY - MinValY)*0.5f + MinValY; + if(MEM(NewPointX, NewPointY, ElementsZ-1) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = NewPointX; + aTestPointsY[NumTestPoints] = NewPointY; + aTestPointsZ[NumTestPoints] = ElementsZ-1; + NumTestPoints++; + } + } + + // add some hardcoded test points + for(int i = 0; i < ARRAY_SIZE(ExtraFudgePointsCoors); i++) + if(PointFallsWithinZone(ExtraFudgePointsCoors[i], 0.0f)){ + x = ElementsX * (ExtraFudgePointsCoors[i].x-minx)/(maxx-minx); + y = ElementsY * (ExtraFudgePointsCoors[i].y-miny)/(maxy-miny); + z = ElementsZ * (ExtraFudgePointsCoors[i].z-minz)/(maxz-minz); + if(MEM(x, y, z) & FLAG_FREE){ + aTestPointsX[NumTestPoints] = x; + aTestPointsY[NumTestPoints] = y; + aTestPointsZ[NumTestPoints] = z; + NumTestPoints++; + } + } + + // remove duplicate points + for(int i = 0; i < NumTestPoints; i++) + for(int j = i+1; j < NumTestPoints; j++) + if(aTestPointsX[j] == aTestPointsX[i] && + aTestPointsY[j] == aTestPointsY[i] && + aTestPointsZ[j] == aTestPointsZ[i]){ + // get rid of [j] + for(int k = j; k < NumTestPoints-1; k++){ + aTestPointsX[k] = aTestPointsX[k+1]; + aTestPointsY[k] = aTestPointsY[k+1]; + aTestPointsZ[k] = aTestPointsZ[k+1]; + } + NumTestPoints--; + } + + // convert points to floating point + for(int i = 0; i < NumTestPoints; i++){ + aTestPoints[i].x = aTestPointsX[i]*StepX + minx; + aTestPoints[i].y = aTestPointsY[i]*StepY + miny; + aTestPoints[i].z = aTestPointsZ[i]*StepZ + minz; + } + + CZNumber++; + + delete[] pMem; + pMem = nil; +} + +bool +CCullZone::TestEntityVisibilityFromCullZone(CEntity *entity, float extraDist, CEntity *LODentity) +{ + CColModel *colmodel = entity->GetColModel(); + float boundMaxX = colmodel->boundingBox.max.x; + float boundMaxY = colmodel->boundingBox.max.y; + float boundMaxZ = colmodel->boundingBox.max.z; + float boundMinX = colmodel->boundingBox.min.x; + float boundMinY = colmodel->boundingBox.min.y; + float boundMinZ = colmodel->boundingBox.min.z; + if(LODentity){ + colmodel = LODentity->GetColModel(); + boundMaxX = Max(boundMaxX, colmodel->boundingBox.max.x); + boundMaxY = Max(boundMaxY, colmodel->boundingBox.max.y); + boundMaxZ = Max(boundMaxZ, colmodel->boundingBox.max.z); + boundMinX = Min(boundMinX, colmodel->boundingBox.min.x); + boundMinY = Min(boundMinY, colmodel->boundingBox.min.y); + boundMinZ = Min(boundMinZ, colmodel->boundingBox.min.z); + } + + if(boundMaxZ-boundMinZ + extraDist < 0.5f) + boundMaxZ = boundMinZ + 0.5f; + else + boundMaxZ += extraDist; + + CVector vecMin = entity->GetMatrix() * CVector(boundMinX, boundMinY, boundMinZ); + CVector vecMaxX = entity->GetMatrix() * CVector(boundMaxX, boundMinY, boundMinZ); + CVector vecMaxY = entity->GetMatrix() * CVector(boundMinX, boundMaxY, boundMinZ); + CVector vecMaxZ = entity->GetMatrix() * CVector(boundMinX, boundMinY, boundMaxZ); + CVector dirx = vecMaxX - vecMin; + CVector diry = vecMaxY - vecMin; + CVector dirz = vecMaxZ - vecMin; + + // If building intersects zone at all, it's visible + int x, y, z; + for(x = 0; x < 9; x++){ + CVector posX = vecMin + x/8.0f*dirx; + for(y = 0; y < 9; y++){ + CVector posY = posX + y/8.0f*diry; + for(z = 0; z < 9; z++){ + CVector posZ = posY + z/8.0f*dirz; + if(PointFallsWithinZone(posZ, 2.0f)) + return true; + } } } + + float distToZone = CalcDistToCullZone(entity->GetPosition().x, entity->GetPosition().y)/15.0f; + distToZone = Max(distToZone, 7.0f); + int numX = (boundMaxX - boundMinX)/distToZone + 2.0f; + int numY = (boundMaxY - boundMinY)/distToZone + 2.0f; + int numZ = (boundMaxZ - boundMinZ)/distToZone + 2.0f; + + float stepX = 1.0f/(numX-1); + float stepY = 1.0f/(numY-1); + float stepZ = 1.0f/(numZ-1); + float midX = (boundMaxX + boundMinX)/2.0f; + float midY = (boundMaxY + boundMinY)/2.0f; + float midZ = (boundMaxZ + boundMinZ)/2.0f; + + // check both xy planes + for(int i = 0; i < NumTestPoints; i++){ + CVector testPoint = aTestPoints[i]; + CVector mid = entity->GetMatrix() * CVector(midX, midY, midZ); + mid.z += 0.1f; + if(DoThoroughLineTest(testPoint, mid, entity)) + return true; + + CVector ray = entity->GetPosition() - testPoint; + + float dotX = DotProduct(ray, dirx); + float dotY = DotProduct(ray, diry); + float dotZ = DotProduct(ray, dirz); + + for(x = 0; x < numX; x++){ + CVector pMinZ = vecMin + x*stepX*dirx; + CVector pMaxZ = vecMin + x*stepX*dirx + dirz; + for(y = 0; y < numY; y++) + if(dotZ > 0.0f){ + if(DoThoroughLineTest(testPoint, pMinZ + y*stepY*diry, entity)) + return true; + }else{ + if(DoThoroughLineTest(testPoint, pMaxZ + y*stepY*diry, entity)) + return true; + } + } + + for(x = 0; x < numX; x++){ + CVector pMinY = vecMin + x*stepX*dirx; + CVector pMaxY = vecMin + x*stepX*dirx + diry; + for(z = 1; z < numZ-1; z++) // edge cases already handled + if(dotY > 0.0f){ + if(DoThoroughLineTest(testPoint, pMinY + z*stepZ*dirz, entity)) + return true; + }else{ + if(DoThoroughLineTest(testPoint, pMaxY + z*stepZ*dirz, entity)) + return true; + } + } + + for(y = 1; y < numY-1; y++){ // edge cases already handled + CVector pMinX = vecMin + y*stepY*diry; + CVector pMaxX = vecMin + y*stepY*diry + dirx; + for(z = 1; z < numZ-1; z++) // edge cases already handled + if(dotX > 0.0f){ + if(DoThoroughLineTest(testPoint, pMinX + z*stepZ*dirz, entity)) + return true; + }else{ + if(DoThoroughLineTest(testPoint, pMaxX + z*stepZ*dirz, entity)) + return true; + } + } + } + return false; } diff --git a/src/core/ZoneCull.h b/src/core/ZoneCull.h index 9bc07b8c..10742ffb 100644 --- a/src/core/ZoneCull.h +++ b/src/core/ZoneCull.h @@ -12,7 +12,7 @@ public: float maxz; int32 m_indexStart; - int16 m_groupIndexCount[3]; + int16 m_groupIndexCount[3]; // only useful during resolution stage int16 m_numBuildings; int16 m_numTreadablesPlus10m; int16 m_numTreadables; @@ -26,30 +26,35 @@ public: static void DoStuffEnteringZone_OneTreadable(uint16 i); - static bool TestLine(CVector a1, CVector a2); + static bool TestLine(CVector vec1, CVector vec2); + static bool DoThoroughLineTest(CVector vec1, CVector vec2, CEntity *testEntity); float CalcDistToCullZoneSquared(float x, float y); float CalcDistToCullZone(float x, float y) { return Sqrt(CalcDistToCullZoneSquared(x, y)); }; bool IsEntityCloseEnoughToZone(CEntity* entity, bool checkLevel); + bool PointFallsWithinZone(CVector pos, float radius); + bool TestEntityVisibilityFromCullZone(CEntity *entity, float extraDist, CEntity *LODentity); + void FindTestPoints(); void GetGroupStartAndSize(int32 groupid, int32 &start, int32 &size) { switch (groupid) { + case 0: + default: + // buildings + start = m_indexStart; + size = m_groupIndexCount[0]; + break; case 1: + // treadables + 10m start = m_groupIndexCount[0] + m_indexStart; size = m_groupIndexCount[1]; break; case 2: + // treadables start = m_groupIndexCount[0] + m_groupIndexCount[1] + m_indexStart; size = m_groupIndexCount[2]; break; - default: - start = m_indexStart; - size = m_groupIndexCount[0]; - break; } } - - void FindTestPoints() {}; // todo - bool TestEntityVisibilityFromCullZone(CEntity*, float, CEntity*) { return false; }; // todo }; enum eZoneAttribs @@ -121,5 +126,12 @@ public: static void DoVisibilityTestCullZone(int zoneId, bool doIt); static bool DoWeHaveMoreThanXOccurencesOfSet(int32 count, uint16 *set); - static void CompressIndicesArray() {};// todo + static void CompressIndicesArray(); + static bool PickRandomSetForGroup(int32 zone, int32 group, uint16 *set); + static void ReplaceSetForAllGroups(uint16 *set, uint16 setid); + static void TidyUpAndMergeLists(uint16 *extraIndices, int32 numExtraIndices); + + // debug + static bool LoadTempFile(void); + static void SaveTempFile(void); }; diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 194f75fa..ee747218 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -565,6 +565,9 @@ DebugMenuPopulate(void) DebugMenuAddVarBool8("Render", "Don't render Objects", &gbDontRenderObjects, nil); DebugMenuAddVarBool8("Render", "Don't Render Water", &gbDontRenderWater, nil); + DebugMenuAddVarBool8("Debug", "Show cullzone debug stuff", &gbShowCullZoneDebugStuff, nil); + DebugMenuAddVarBool8("Debug", "Disable zone cull", &gbDisableZoneCull, nil); + DebugMenuAddVarBool8("Debug", "pad 1 -> pad 2", &CPad::m_bMapPadOneToPadTwo, nil); DebugMenuAddVarBool8("Debug", "Edit on", &CSceneEdit::m_bEditOn, nil); #ifdef MENU_MAP diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 92bbdd45..ee6ba58a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -21,12 +21,14 @@ #include "Renderer.h" #include "Frontend.h" #include "custompipes.h" +#include "Debug.h" bool gbShowPedRoadGroups; bool gbShowCarRoadGroups; bool gbShowCollisionPolys; bool gbShowCollisionLines; bool gbShowCullZoneDebugStuff; +bool gbDisableZoneCull; // not original bool gbBigWhiteDebugLightSwitchedOn; bool gbDontRenderBuildings; @@ -35,6 +37,25 @@ bool gbDontRenderPeds; bool gbDontRenderObjects; bool gbDontRenderVehicles; +int32 EntitiesRendered; +int32 EntitiesNotRendered; +int32 RenderedBigBuildings; +int32 RenderedBuildings; +int32 RenderedCars; +int32 RenderedPeds; +int32 RenderedObjects; +int32 RenderedDummies; +int32 TestedBigBuildings; +int32 TestedBuildings; +int32 TestedCars; +int32 TestedPeds; +int32 TestedObjects; +int32 TestedDummies; + +// unused +int16 TestCloseThings; +int16 TestBigThings; + struct EntityInfo { CEntity *ent; @@ -61,6 +82,11 @@ float CRenderer::ms_lodDistScale = 1.2f; #define BACKFACE_CULLING_OFF #endif +// unused +BlockedRange CRenderer::aBlockedRanges[16]; +BlockedRange *CRenderer::pFullBlockedRanges; +BlockedRange *CRenderer::pEmptyBlockedRanges; + void CRenderer::Init(void) { @@ -347,6 +373,14 @@ CRenderer::RenderCollisionLines(void) } } +// unused +void +CRenderer::RenderBlockBuildingLines(void) +{ + for(BlockedRange *br = pFullBlockedRanges; br; br = br->next) + printf("Blocked: %f %f\n", br->a, br->b); +} + enum Visbility { VIS_INVISIBLE, @@ -355,14 +389,6 @@ enum Visbility VIS_STREAMME }; -#ifdef FIX_BUGS -#define LOD_DISTANCE (300.0f*TheCamera.LODDistMultiplier) -#else -#define LOD_DISTANCE 300.0f -#endif -#define FADE_DISTANCE 20.0f -#define STREAM_DISTANCE 30.0f - // Time Objects can be time culled if // other == -1 || CModelInfo::GetModelInfo(other)->GetRwObject() // i.e. we have to draw even at the wrong time if @@ -611,7 +637,21 @@ CRenderer::ConstructRenderList(void) ms_nNoOfVisibleEntities = 0; ms_nNoOfInVisibleEntities = 0; ms_vecCameraPosition = TheCamera.GetPosition(); - // TODO: blocked ranges, but unused + + // unused + pFullBlockedRanges = nil; + pEmptyBlockedRanges = aBlockedRanges; + for(int i = 0; i < 16; i++){ + aBlockedRanges[i].prev = &aBlockedRanges[i-1]; + aBlockedRanges[i].next = &aBlockedRanges[i+1]; + } + aBlockedRanges[0].prev = nil; + aBlockedRanges[15].next = nil; + + // unused + TestCloseThings = 0; + TestBigThings = 0; + ScanWorld(); } @@ -647,6 +687,24 @@ CRenderer::ScanWorld(void) RwMatrix *cammatrix; RwV2d poly[3]; +#ifndef MASTER + // missing in game but has to be done somewhere + EntitiesRendered = 0; + EntitiesNotRendered = 0; + RenderedBigBuildings = 0; + RenderedBuildings = 0; + RenderedCars = 0; + RenderedPeds = 0; + RenderedObjects = 0; + RenderedDummies = 0; + TestedBigBuildings = 0; + TestedBuildings = 0; + TestedCars = 0; + TestedPeds = 0; + TestedObjects = 0; + TestedDummies = 0; +#endif + memset(vectors, 0, sizeof(vectors)); vectors[CORNER_FAR_TOPLEFT].x = -vw.x * f; vectors[CORNER_FAR_TOPLEFT].y = vw.y * f; @@ -765,6 +823,19 @@ CRenderer::ScanWorld(void) ScanBigBuildingList(CWorld::GetBigBuildingList(LEVEL_GENERIC)); } } + +#ifndef MASTER + if(gbShowCullZoneDebugStuff){ + sprintf(gString, "Rejected: %d/%d.", EntitiesNotRendered, EntitiesNotRendered + EntitiesRendered); + CDebug::PrintAt(gString, 10, 10); + sprintf(gString, "Tested:BBuild:%d Build:%d Peds:%d Cars:%d Obj:%d Dummies:%d", + TestedBigBuildings, TestedBuildings, TestedPeds, TestedCars, TestedObjects, TestedDummies); + CDebug::PrintAt(gString, 10, 11); + sprintf(gString, "Rendered:BBuild:%d Build:%d Peds:%d Cars:%d Obj:%d Dummies:%d", + RenderedBigBuildings, RenderedBuildings, RenderedPeds, RenderedCars, RenderedObjects, RenderedDummies); + CDebug::PrintAt(gString, 10, 12); + } +#endif } void @@ -1014,8 +1085,20 @@ CRenderer::ScanBigBuildingList(CPtrList &list) for(node = list.first; node; node = node->next){ ent = (CEntity*)node->item; - if(!ent->bZoneCulled && SetupBigBuildingVisibility(ent) == VIS_VISIBLE) - ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; +#ifndef MASTER + // all missing from game actually + TestedBigBuildings++; +#endif + if(!ent->bZoneCulled){ + if(SetupBigBuildingVisibility(ent) == VIS_VISIBLE) + ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; +#ifndef MASTER + EntitiesRendered++; + RenderedBigBuildings++; + }else{ + EntitiesNotRendered++; +#endif + } } } @@ -1036,7 +1119,7 @@ CRenderer::ScanSectorList(CPtrList *lists) continue; // already seen ent->m_scanCode = CWorld::GetCurrentScanCode(); - if(IsEntityCullZoneVisible(ent)) + if(IsEntityCullZoneVisible(ent)){ switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; @@ -1059,11 +1142,37 @@ CRenderer::ScanSectorList(CPtrList *lists) CStreaming::RequestModel(ent->GetModelIndex(), 0); break; } - else if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){ - if(!CStreaming::ms_disableStreaming) - if(SetupEntityVisibility(ent) == VIS_STREAMME) - if(!m_loadingPriority || CStreaming::ms_numModelsRequested < 10) - CStreaming::RequestModel(ent->GetModelIndex(), 0); +#ifndef MASTER + EntitiesRendered++; + switch(ent->GetType()){ + case ENTITY_TYPE_BUILDING: + if(ent->bIsBIGBuilding) + RenderedBigBuildings++; + else + RenderedBuildings++; + break; + case ENTITY_TYPE_VEHICLE: + RenderedCars++; + break; + case ENTITY_TYPE_PED: + RenderedPeds++; + break; + case ENTITY_TYPE_OBJECT: + RenderedObjects++; + break; + case ENTITY_TYPE_DUMMY: + RenderedDummies++; + break; + } +#endif + }else if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable() && !CStreaming::ms_disableStreaming){ + if(SetupEntityVisibility(ent) == VIS_STREAMME) + if(!m_loadingPriority || CStreaming::ms_numModelsRequested < 10) + CStreaming::RequestModel(ent->GetModelIndex(), 0); + }else{ +#ifndef MASTER + EntitiesNotRendered++; +#endif } } } @@ -1086,7 +1195,7 @@ CRenderer::ScanSectorList_Priority(CPtrList *lists) continue; // already seen ent->m_scanCode = CWorld::GetCurrentScanCode(); - if(IsEntityCullZoneVisible(ent)) + if(IsEntityCullZoneVisible(ent)){ switch(SetupEntityVisibility(ent)){ case VIS_VISIBLE: ms_aVisibleEntityPtrs[ms_nNoOfVisibleEntities++] = ent; @@ -1111,10 +1220,38 @@ CRenderer::ScanSectorList_Priority(CPtrList *lists) } break; } - else if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){ - if(!CStreaming::ms_disableStreaming) - if(SetupEntityVisibility(ent) == VIS_STREAMME) - CStreaming::RequestModel(ent->GetModelIndex(), 0); +#ifndef MASTER + // actually missing in game + EntitiesRendered++; + switch(ent->GetType()){ + case ENTITY_TYPE_BUILDING: + if(ent->bIsBIGBuilding) + RenderedBigBuildings++; + else + RenderedBuildings++; + break; + case ENTITY_TYPE_VEHICLE: + RenderedCars++; + break; + case ENTITY_TYPE_PED: + RenderedPeds++; + break; + case ENTITY_TYPE_OBJECT: + RenderedObjects++; + break; + case ENTITY_TYPE_DUMMY: + RenderedDummies++; + break; + } +#endif + }else if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable() && !CStreaming::ms_disableStreaming){ + if(SetupEntityVisibility(ent) == VIS_STREAMME) + CStreaming::RequestModel(ent->GetModelIndex(), 0); + }else{ +#ifndef MASTER + // actually missing in game + EntitiesNotRendered++; +#endif } } } @@ -1220,9 +1357,34 @@ CRenderer::IsEntityCullZoneVisible(CEntity *ent) CPed *ped; CObject *obj; + if(gbDisableZoneCull) return true; + +#ifndef MASTER + switch(ent->GetType()){ + case ENTITY_TYPE_BUILDING: + if(ent->bIsBIGBuilding) + TestedBigBuildings++; + else + TestedBuildings++; + break; + case ENTITY_TYPE_VEHICLE: + TestedCars++; + break; + case ENTITY_TYPE_PED: + TestedPeds++; + break; + case ENTITY_TYPE_OBJECT: + TestedObjects++; + break; + case ENTITY_TYPE_DUMMY: + TestedDummies++; + break; + } +#endif if(ent->bZoneCulled) return false; + switch(ent->GetType()){ case ENTITY_TYPE_VEHICLE: return IsVehicleCullZoneVisible(ent); diff --git a/src/render/Renderer.h b/src/render/Renderer.h index 362741e3..e14f73b1 100644 --- a/src/render/Renderer.h +++ b/src/render/Renderer.h @@ -2,11 +2,20 @@ class CEntity; +#ifdef FIX_BUGS +#define LOD_DISTANCE (300.0f*TheCamera.LODDistMultiplier) +#else +#define LOD_DISTANCE 300.0f +#endif +#define FADE_DISTANCE 20.0f +#define STREAM_DISTANCE 30.0f + extern bool gbShowPedRoadGroups; extern bool gbShowCarRoadGroups; extern bool gbShowCollisionPolys; extern bool gbShowCollisionLines; extern bool gbShowCullZoneDebugStuff; +extern bool gbDisableZoneCull; // not original extern bool gbBigWhiteDebugLightSwitchedOn; extern bool gbDontRenderBuildings; @@ -18,6 +27,13 @@ extern bool gbDontRenderVehicles; class CVehicle; class CPtrList; +// unused +struct BlockedRange +{ + float a, b; // unknown + BlockedRange *prev, *next; +}; + class CRenderer { static int32 ms_nNoOfVisibleEntities; @@ -28,6 +44,10 @@ class CRenderer static CVector ms_vecCameraPosition; static CVehicle *m_pFirstPersonVehicle; + // unused + static BlockedRange aBlockedRanges[16]; + static BlockedRange *pFullBlockedRanges; + static BlockedRange *pEmptyBlockedRanges; public: static float ms_lodDistScale; static bool m_loadingPriority; @@ -46,6 +66,8 @@ public: static void RenderFirstPersonVehicle(void); static void RenderCollisionLines(void); + // unused + static void RenderBlockBuildingLines(void); static int32 SetupEntityVisibility(CEntity *ent); static int32 SetupBigBuildingVisibility(CEntity *ent); diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 8878a26a..3f10d12a 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -11,8 +11,6 @@ #include "World.h" #include "custompipes.h" -#define FADE_DISTANCE 20.0f - CLinkList CVisibilityPlugins::m_alphaList; CLinkList CVisibilityPlugins::m_alphaEntityList; From d24e1ee5926a1d29633c62f2f29f9112b76b5a08 Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sun, 22 Nov 2020 02:29:17 +0300 Subject: [PATCH 073/129] small improvement --- src/control/Restart.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/Restart.cpp b/src/control/Restart.cpp index a6482d04..5e9865dd 100644 --- a/src/control/Restart.cpp +++ b/src/control/Restart.cpp @@ -81,7 +81,7 @@ CRestart::FindClosestHospitalRestartPoint(const CVector &pos, CVector *outPos, f } eLevelName curlevel = CTheZones::FindZoneForPoint(pos); - float fMinDist = 16000000.0f; + float fMinDist = SQR(4000.0f); int closestPoint = NUM_RESTART_POINTS; // find closest point on this level From 222e7f56ffa950427b45a342f3ea795d639cba19 Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sun, 22 Nov 2020 02:31:52 +0300 Subject: [PATCH 074/129] one more fix --- src/control/Restart.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/Restart.cpp b/src/control/Restart.cpp index 5e9865dd..4ca18c3b 100644 --- a/src/control/Restart.cpp +++ b/src/control/Restart.cpp @@ -128,7 +128,7 @@ CRestart::FindClosestPoliceRestartPoint(const CVector &pos, CVector *outPos, flo } eLevelName curlevel = CTheZones::FindZoneForPoint(pos); - float fMinDist = 16000000.0f; + float fMinDist = SQR(4000.0f); int closestPoint = NUM_RESTART_POINTS; // find closest point on this level From f010777e580a4f2bdbfca9dbe037700822f34a88 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 22 Nov 2020 23:10:41 +0200 Subject: [PATCH 075/129] Audio fixes --- src/audio/AudioLogic.cpp | 245 ++++++------------------------------- src/audio/AudioManager.cpp | 2 +- src/audio/AudioManager.h | 8 +- 3 files changed, 40 insertions(+), 215 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index fc828042..ca493a95 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -2248,7 +2248,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams& params) pedParams.m_fDistance = 0.0f; pedParams.m_bDistanceCalculated = params.m_bDistanceCalculated; pedParams.m_fDistance = params.m_fDistance; - SetupPedComments(&pedParams, SOUND_PED_HELI_PLAYER_FOUND); + SetupPedComments(pedParams, SOUND_PED_HELI_PLAYER_FOUND); continue; case SOUND_PED_BODYCAST_HIT: pedParams.m_pPed = nil; @@ -2256,7 +2256,7 @@ cAudioManager::ProcessVehicleOneShots(cVehicleParams& params) pedParams.m_fDistance = 0.0f; pedParams.m_bDistanceCalculated = params.m_bDistanceCalculated; pedParams.m_fDistance = params.m_fDistance; - SetupPedComments(&pedParams, SOUND_PED_BODYCAST_HIT); + SetupPedComments(pedParams, SOUND_PED_BODYCAST_HIT); continue; case SOUND_WATER_FALL: { const float SOUND_INTENSITY = 40.0f; @@ -2965,21 +2965,21 @@ cAudioManager::ProcessPed(CPhysical *ped) params.m_pPed = (CPed *)ped; params.m_fDistance = GetDistanceSquared(m_sQueueSample.m_vecPos); if (ped->GetModelIndex() == MI_FATMALE02) - ProcessPedHeadphones(¶ms); - ProcessPedOneShots(¶ms); + ProcessPedHeadphones(params); + ProcessPedOneShots(params); } void -cAudioManager::ProcessPedHeadphones(cPedParams *params) +cAudioManager::ProcessPedHeadphones(cPedParams ¶ms) { CPed *ped; CAutomobile *veh; uint8 emittingVol; - if (params->m_fDistance < SQR(7)) { - ped = params->m_pPed; + if (params.m_fDistance < SQR(7)) { + ped = params.m_pPed; if (!ped->bIsAimingGun || ped->m_bodyPartBleeding != PED_HEAD) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); if (ped->bInVehicle && ped->m_nPedState == PED_DRIVING) { emittingVol = 10; veh = (CAutomobile *)ped->m_pMyVehicle; @@ -3021,12 +3021,12 @@ cAudioManager::ProcessPedHeadphones(cPedParams *params) } void -cAudioManager::ProcessPedOneShots(cPedParams *params) +cAudioManager::ProcessPedOneShots(cPedParams ¶ms) { uint8 emittingVol; int32 sampleIndex; - CPed *ped = params->m_pPed; + CPed *ped = params.m_pPed; bool stereo; int16 sound; @@ -3036,7 +3036,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) static uint8 iSound = 21; - weapon = params->m_pPed->GetWeapon(); + weapon = params.m_pPed->GetWeapon(); for (uint32 i = 0; i < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_AudioEvents; i++) { noReflection = false; stereo = false; @@ -3045,12 +3045,12 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) switch (sound) { case SOUND_STEP_START: case SOUND_STEP_END: - if (!params->m_pPed->bIsLooking) { + if (!params.m_pPed->bIsLooking) { emittingVol = m_anRandomTable[3] % 15 + 45; if (FindPlayerPed() != m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_pEntity) emittingVol /= 2; maxDist = 400.f; - switch (params->m_pPed->m_nSurfaceTouched) { + switch (params.m_pPed->m_nSurfaceTouched) { case SURFACE_GRASS: sampleIndex = m_anRandomTable[1] % 5 + SFX_FOOTSTEP_GRASS_1; break; @@ -3094,7 +3094,7 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) m_sQueueSample.m_nCounter = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] - 28; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(m_sQueueSample.m_nSampleIndex); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 17); - switch (params->m_pPed->m_nMoveState) { + switch (params.m_pPed->m_nMoveState) { case PEDMOVE_WALK: emittingVol /= 4; m_sQueueSample.m_nFrequency = 9 * m_sQueueSample.m_nFrequency / 10; @@ -3152,226 +3152,51 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) case SOUND_FIGHT_PUNCH_33: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_1; m_sQueueSample.m_nFrequency = 18000; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_KICK_34: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_1; m_sQueueSample.m_nFrequency = 16500; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_HEADBUTT_35: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_1; m_sQueueSample.m_nFrequency = 20000; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_PUNCH_36: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_2; m_sQueueSample.m_nFrequency = 18000; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_PUNCH_37: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_2; m_sQueueSample.m_nFrequency = 16500; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_CLOSE_PUNCH_38: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_2; m_sQueueSample.m_nFrequency = 20000; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_PUNCH_39: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_4; m_sQueueSample.m_nFrequency = 18000; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_4; m_sQueueSample.m_nFrequency = 16500; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_PUNCH_41: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_4; m_sQueueSample.m_nFrequency = 20000; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_PUNCH_FROM_BEHIND_42: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_5; m_sQueueSample.m_nFrequency = 18000; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_KNEE_OR_KICK_43: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_5; m_sQueueSample.m_nFrequency = 16500; - m_sQueueSample.m_nBankIndex = SFX_BANK_0; - m_sQueueSample.m_nCounter = iSound; - stereo = true; - ++iSound; - m_sQueueSample.m_nReleasingVolumeModificator = 3; - m_sQueueSample.m_fSpeedMultiplier = 0.0f; - m_sQueueSample.m_fSoundIntensity = 30.0f; - maxDist = SQR(30); - m_sQueueSample.m_nLoopCount = 1; - m_sQueueSample.m_nLoopStart = 0; - emittingVol = m_anRandomTable[3] % 26 + 100; - m_sQueueSample.m_nLoopEnd = -1; - m_sQueueSample.m_nEmittingVolume = emittingVol; - m_sQueueSample.m_bIs2D = false; - m_sQueueSample.m_bReleasingSoundFlag = true; - m_sQueueSample.m_bRequireReflection = true; - break; + goto AddFightSound; case SOUND_FIGHT_KICK_44: m_sQueueSample.m_nSampleIndex = SFX_FIGHT_5; m_sQueueSample.m_nFrequency = 20000; + AddFightSound: m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound; stereo = true; @@ -3729,8 +3554,8 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) if (stereo && iSound > 60) iSound = 21; - if (params->m_fDistance < maxDist) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + if (params.m_fDistance < maxDist) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { if (noReflection) { @@ -3762,9 +3587,9 @@ cAudioManager::ProcessPedOneShots(cPedParams *params) } void -cAudioManager::SetupPedComments(cPedParams *params, uint32 sound) +cAudioManager::SetupPedComments(cPedParams ¶ms, uint16 sound) { - CPed *ped = params->m_pPed; + CPed *ped = params.m_pPed; uint8 emittingVol; float soundIntensity; tPedComment pedComment; @@ -3815,8 +3640,8 @@ cAudioManager::SetupPedComments(cPedParams *params, uint32 sound) } } - if (params->m_fDistance < SQR(soundIntensity)) { - CalculateDistance(params->m_bDistanceCalculated, params->m_fDistance); + if (params.m_fDistance < SQR(soundIntensity)) { + CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); if (sound != SOUND_PAGER) { switch (sound) { case SOUND_AMMUNATION_WELCOME_1: @@ -6549,14 +6374,14 @@ cAudioManager::ProcessOneShotScriptObject(uint8 sound) male.m_pPed = nil; male.m_bDistanceCalculated = false; male.m_fDistance = GetDistanceSquared(m_sQueueSample.m_vecPos); - SetupPedComments(&male, SOUND_INJURED_PED_MALE_OUCH); + SetupPedComments(male, SOUND_INJURED_PED_MALE_OUCH); return; case SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_S: case SCRIPT_SOUND_INJURED_PED_FEMALE_OUCH_L: female.m_pPed = nil; female.m_bDistanceCalculated = false; female.m_fDistance = GetDistanceSquared(m_sQueueSample.m_vecPos); - SetupPedComments(&female, SOUND_INJURED_PED_FEMALE); + SetupPedComments(female, SOUND_INJURED_PED_FEMALE); return; case SCRIPT_SOUND_GATE_START_CLUNK: case SCRIPT_SOUND_GATE_STOP_CLUNK: @@ -7934,7 +7759,7 @@ cAudioManager::ProcessPoliceCellBeatingScriptObject(uint8 sound) params.m_bDistanceCalculated = true; params.m_fDistance = distSquared; params.m_pPed = nil; - SetupPedComments(¶ms, SOUND_INJURED_PED_MALE_PRISON); + SetupPedComments(params, SOUND_INJURED_PED_MALE_PRISON); } gCellNextTime = time + 500 + m_anRandomTable[3] % 1500; } diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index d8054181..947bda40 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -167,7 +167,7 @@ cAudioManager::SetEntityStatus(int32 id, uint8 status) } void -cAudioManager::PlayOneShot(int32 index, int16 sound, float vol) +cAudioManager::PlayOneShot(int32 index, uint16 sound, float vol) { static const uint8 OneShotPriority[] = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 3, 5, 2, 2, 1, 1, 3, 1, 3, 3, 1, 1, 1, 4, 4, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 3, 2, 2, 2, 2, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h index 2d971ac9..d781ad71 100644 --- a/src/audio/AudioManager.h +++ b/src/audio/AudioManager.h @@ -351,7 +351,7 @@ public: bool MissionScriptAudioUsesPoliceChannel(int32 soundMission) const; void PlayLoadedMissionAudio(); - void PlayOneShot(int32 index, int16 sound, float vol); + void PlayOneShot(int32 index, uint16 sound, float vol); void PlaySuspectLastSeen(float x, float y, float z); void PlayerJustGotInCar() const; void PlayerJustLeftCar() const; @@ -397,8 +397,8 @@ public: void ProcessModelCarEngine(cVehicleParams& params); void ProcessOneShotScriptObject(uint8 sound); void ProcessPed(CPhysical *ped); - void ProcessPedHeadphones(cPedParams *params); - void ProcessPedOneShots(cPedParams *params); + void ProcessPedHeadphones(cPedParams ¶ms); + void ProcessPedOneShots(cPedParams ¶ms); void ProcessPhysical(int32 id); void ProcessPlane(cVehicleParams& params); void ProcessPlayersVehicleEngine(cVehicleParams& params, CAutomobile *automobile); @@ -462,7 +462,7 @@ public: bool SetupJumboRumbleSound(uint8 emittingVol); bool SetupJumboTaxiSound(uint8 vol); bool SetupJumboWhineSound(uint8 emittingVol, uint32 freq); - void SetupPedComments(cPedParams *params, uint32 sound); + void SetupPedComments(cPedParams ¶ms, uint16 sound); void SetupSuspectLastSeenReport(); void Terminate(); From c814a0a1a6b0f71842306052fbdadb06de7883cb Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 22 Nov 2020 23:11:55 +0200 Subject: [PATCH 076/129] Renderer fix --- src/render/Renderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 949f8c54..97d2b49c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -570,7 +570,7 @@ CRenderer::SetupBigBuildingVisibility(CEntity *ent) // that of an atomic for another draw distance. if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) - if(!ent->IsVisibleComplex()) + if (!ent->IsVisible() || !ent->GetIsOnScreenComplex()) return VIS_INVISIBLE; if(mi->m_drawLast){ CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); @@ -600,7 +600,7 @@ CRenderer::SetupBigBuildingVisibility(CEntity *ent) RpAtomic *rwobj = (RpAtomic*)ent->m_rwObject; if(RpAtomicGetGeometry(a) != RpAtomicGetGeometry(rwobj)) RpAtomicSetGeometry(rwobj, RpAtomicGetGeometry(a), rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) - if(ent->IsVisibleComplex()) + if (ent->IsVisible() && ent->GetIsOnScreenComplex()) CVisibilityPlugins::InsertEntityIntoSortedList(ent, dist); return VIS_INVISIBLE; } From 103b8fb426e7e5555d58cfeeff0ace64fb4b54f6 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 22 Nov 2020 23:24:38 +0200 Subject: [PATCH 077/129] More audio fix --- src/audio/AudioLogic.cpp | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/audio/AudioLogic.cpp b/src/audio/AudioLogic.cpp index ca493a95..7340e73e 100644 --- a/src/audio/AudioLogic.cpp +++ b/src/audio/AudioLogic.cpp @@ -3028,9 +3028,9 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) CPed *ped = params.m_pPed; - bool stereo; + bool narrowSoundRange; int16 sound; - bool noReflection; + bool stereo; CWeapon *weapon; float maxDist = 0.f; // uninitialized variable @@ -3038,8 +3038,8 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) weapon = params.m_pPed->GetWeapon(); for (uint32 i = 0; i < m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_AudioEvents; i++) { - noReflection = false; stereo = false; + narrowSoundRange = false; m_sQueueSample.m_bRequireReflection = false; sound = m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i]; switch (sound) { @@ -3199,7 +3199,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) AddFightSound: m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound; - stereo = true; + narrowSoundRange = true; ++iSound; m_sQueueSample.m_nReleasingVolumeModificator = 3; m_sQueueSample.m_fSpeedMultiplier = 0.0f; @@ -3218,7 +3218,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_BAT_HIT_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = RandomDisplacement(2000) + 22000; m_sQueueSample.m_nReleasingVolumeModificator = 3; m_sQueueSample.m_fSpeedMultiplier = 0.0f; @@ -3234,7 +3234,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case SOUND_WEAPON_SHOT_FIRED: weapon = ped->GetWeapon(); @@ -3243,7 +3243,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_COLT45_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_COLT45_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -3260,13 +3260,13 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case WEAPONTYPE_UZI: m_sQueueSample.m_nSampleIndex = SFX_UZI_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_UZI_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -3285,7 +3285,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_SHOTGUN_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_SHOTGUN_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -3302,13 +3302,13 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case WEAPONTYPE_AK47: m_sQueueSample.m_nSampleIndex = SFX_AK47_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_AK47_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -3327,7 +3327,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_M16_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_M16_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -3346,7 +3346,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_SNIPER_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_SNIPER_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -3363,13 +3363,13 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case WEAPONTYPE_ROCKETLAUNCHER: m_sQueueSample.m_nSampleIndex = SFX_ROCKET_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_ROCKET_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 32); m_sQueueSample.m_nReleasingVolumeModificator = 1; @@ -3386,7 +3386,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case WEAPONTYPE_FLAMETHROWER: m_sQueueSample.m_nSampleIndex = SFX_FLAMETHROWER_LEFT; @@ -3408,7 +3408,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; default: continue; @@ -3451,7 +3451,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) } emittingVol = 75; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency += RandomDisplacement(300); m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nReleasingVolumeModificator = 5; @@ -3472,7 +3472,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_UZI_END_LEFT; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_UZI_END_LEFT); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 16); m_sQueueSample.m_nReleasingVolumeModificator = 3; @@ -3489,7 +3489,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) if (m_bDynamicAcousticModelingStatus) m_sQueueSample.m_bRequireReflection = true; else - noReflection = true; + stereo = true; break; case SOUND_WEAPON_FLAMETHROWER_FIRE: m_sQueueSample.m_nSampleIndex = SFX_FLAMETHROWER_START_LEFT; @@ -3513,7 +3513,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_BULLET_PED; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = SampleManager.GetSampleBaseFrequency(SFX_BULLET_PED); m_sQueueSample.m_nFrequency += RandomDisplacement(m_sQueueSample.m_nFrequency / 8); m_sQueueSample.m_nReleasingVolumeModificator = 7; @@ -3532,7 +3532,7 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) m_sQueueSample.m_nSampleIndex = SFX_SPLASH_1; m_sQueueSample.m_nBankIndex = SFX_BANK_0; m_sQueueSample.m_nCounter = iSound++; - stereo = true; + narrowSoundRange = true; m_sQueueSample.m_nFrequency = RandomDisplacement(1400) + 20000; m_sQueueSample.m_nReleasingVolumeModificator = 1; m_sQueueSample.m_fSpeedMultiplier = 0.0f; @@ -3552,23 +3552,23 @@ cAudioManager::ProcessPedOneShots(cPedParams ¶ms) continue; } - if (stereo && iSound > 60) + if (narrowSoundRange && iSound > 60) iSound = 21; if (params.m_fDistance < maxDist) { CalculateDistance(params.m_bDistanceCalculated, params.m_fDistance); m_sQueueSample.m_nVolume = ComputeVolume(emittingVol, m_sQueueSample.m_fSoundIntensity, m_sQueueSample.m_fDistance); if (m_sQueueSample.m_nVolume != 0) { - if (noReflection) { + if (stereo) { if (m_sQueueSample.m_fDistance < 0.2f * m_sQueueSample.m_fSoundIntensity) { m_sQueueSample.m_bIs2D = true; m_sQueueSample.m_nOffset = 0; } else { - noReflection = false; + stereo = false; } } m_sQueueSample.m_bReverbFlag = true; AddSampleToRequestedQueue(); - if (noReflection) { + if (stereo) { m_sQueueSample.m_nOffset = 127; ++m_sQueueSample.m_nSampleIndex; if (m_asAudioEntities[m_sQueueSample.m_nEntityIndex].m_awAudioEvent[i] != SOUND_WEAPON_SHOT_FIRED || From b6da31cfaa021559939ed596d18a27f4db6acebc Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 23 Nov 2020 09:38:51 +0100 Subject: [PATCH 078/129] two unused functions --- src/rw/Lights.cpp | 41 +++++++++++++++++++++++++++++++++++++++++ src/rw/Lights.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/src/rw/Lights.cpp b/src/rw/Lights.cpp index 5a253854..b3cef6d4 100644 --- a/src/rw/Lights.cpp +++ b/src/rw/Lights.cpp @@ -3,6 +3,7 @@ #include #include "Lights.h" +#include "Timer.h" #include "Timecycle.h" #include "Coronas.h" #include "Weather.h" @@ -248,6 +249,46 @@ SetAmbientAndDirectionalColours(float f) RpLightSetColor(pDirect, &DirectionalLightColour); } +// unused +void +SetFlashyColours(float f) +{ + if(CTimer::GetTimeInMilliseconds() & 0x100){ + AmbientLightColour.red = 1.0f; + AmbientLightColour.green = 1.0f; + AmbientLightColour.blue = 1.0f; + + DirectionalLightColour.red = DirectionalLightColourForFrame.red; + DirectionalLightColour.green = DirectionalLightColourForFrame.green; + DirectionalLightColour.blue = DirectionalLightColourForFrame.blue; + + RpLightSetColor(pAmbient, &AmbientLightColour); + RpLightSetColor(pDirect, &DirectionalLightColour); + }else{ + SetAmbientAndDirectionalColours(f * 0.75f); + } +} + +// unused +void +SetFlashyColours_Mild(float f) +{ + if(CTimer::GetTimeInMilliseconds() & 0x100){ + AmbientLightColour.red = 0.65f; + AmbientLightColour.green = 0.65f; + AmbientLightColour.blue = 0.65f; + + DirectionalLightColour.red = DirectionalLightColourForFrame.red; + DirectionalLightColour.green = DirectionalLightColourForFrame.green; + DirectionalLightColour.blue = DirectionalLightColourForFrame.blue; + + RpLightSetColor(pAmbient, &AmbientLightColour); + RpLightSetColor(pDirect, &DirectionalLightColour); + }else{ + SetAmbientAndDirectionalColours(f * 0.9f); + } +} + void SetBrightMarkerColours(float f) { diff --git a/src/rw/Lights.h b/src/rw/Lights.h index b296816b..5057f1d0 100644 --- a/src/rw/Lights.h +++ b/src/rw/Lights.h @@ -14,6 +14,8 @@ void WorldReplaceScorchedLightsWithNormal(RpWorld *world); void AddAnExtraDirectionalLight(RpWorld *world, float dirx, float diry, float dirz, float red, float green, float blue); void RemoveExtraDirectionalLights(RpWorld *world); void SetAmbientAndDirectionalColours(float f); +void SetFlashyColours(float f); +void SetFlashyColours_Mild(float f); void SetBrightMarkerColours(float f); void ReSetAmbientAndDirectionalColours(void); void DeActivateDirectional(void); From 833bf4a619c7bd40ea69731abe3d31770815d863 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 23 Nov 2020 18:59:50 +0200 Subject: [PATCH 079/129] Add some TODO stubs for unused code to be reversed --- README.md | 12 ++++- src/control/NameGrid.cpp | 87 ++++++++++++++++++++++++++++++ src/control/NameGrid.h | 53 ++++++++++++++++++ src/modelinfo/VehicleModelInfo.cpp | 2 +- src/vehicles/Automobile.cpp | 2 +- src/vehicles/Boat.cpp | 2 +- src/vehicles/HandlingMgr.cpp | 26 ++++++++- src/vehicles/HandlingMgr.h | 21 ++++++-- src/vehicles/Heli.cpp | 2 +- src/vehicles/Plane.cpp | 2 +- src/vehicles/Train.cpp | 2 +- src/vehicles/Vehicle.cpp | 7 +++ src/vehicles/Vehicle.h | 11 ++++ 13 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 src/control/NameGrid.cpp create mode 100644 src/control/NameGrid.h diff --git a/README.md b/README.md index 41e5a094..4ee3d2e9 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,15 @@ Please read the [Coding Style](https://github.com/GTAmodding/re3/blob/master/COD ### Unreversed / incomplete classes (at least the ones we know) The following classes have only unused or practically unused code left: ``` -CCullZone - only mobile stuff -CCullZones - only mobile stuff +CMemoryHeap - only on PS2 +NameGrid.cpp - only on mobile (a player name grid, either a very early player name code ala GTA1 or a multiplayer leftover) +PedDebug.cpp - only on mobile (debug code) +HandlingMgr.cpp - debug functions from mobile +CVehicle::ProcessBikeWheel - early bike code (only on mobile) +CAutomobile::DebugCode - debug function from mobile +CBoat::DebugCode - debug function from mobile +CBoat::ModifyHandlingValue - debug function from mobile +CBoat::DisplayHandlingData - debug function from mobile +TexturePools - only on PC (slight RW modification that we don't actually need) ``` diff --git a/src/control/NameGrid.cpp b/src/control/NameGrid.cpp new file mode 100644 index 00000000..204e8b9c --- /dev/null +++ b/src/control/NameGrid.cpp @@ -0,0 +1,87 @@ +#include "common.h" +#include "NameGrid.h" + +// TODO: reverse mobile code + +CPlayerName::CPlayerName() +{ + // TODO +} + +void +CPlayerName::DisplayName(int) +{ + // TODO +} + +CRow::CRow() +{ + // TODO +} + +void +CRow::SetLetter(int, wchar *) +{ + // TODO +} + +CGrid::CGrid() +{ + // TODO +} + +void +CGrid::ProcessAnyLeftJustDown() +{ + unk_int2--; +} + +void +CGrid::ProcessAnyRightJustDown() +{ + unk_int2++; +} + +void +CGrid::ProcessAnyUpJustDown() +{ + unk_int1--; +} + +void +CGrid::ProcessAnyDownJustDown() +{ + unk_int1++; +} + +void +CGrid::AllDoneMakePlayerName() +{ + // TODO +} + +void +CGrid::ProcessDPadCrossJustDown() +{ + // TODO +} + +void +CGrid::DisplayGrid() +{ + // TODO +} + +void +CGrid::ProcessControllerInput() +{ + // TODO +} + +void +CGrid::Process() +{ + ProcessControllerInput(); + DisplayGrid(); + playerName.DisplayName(2 * playerName.unk_4c); +} \ No newline at end of file diff --git a/src/control/NameGrid.h b/src/control/NameGrid.h new file mode 100644 index 00000000..d52cec73 --- /dev/null +++ b/src/control/NameGrid.h @@ -0,0 +1,53 @@ +#pragma once + +// TODO: reverse mobile code + +class CPlayerName +{ + friend class CGrid; + + float x; + float y; + wchar unk_8[34]; + int unk_4c; +public: + CPlayerName(); + void DisplayName(int); +}; + +class CRow +{ + friend class CGrid; + + int unk_0; + int unk_4; + wchar unk_8[20]; + int unk_30; +public: + CRow(); + void SetLetter(int, wchar *); +}; + +class CGrid +{ + CRow rows[5]; + int unk_int1; + int unk_int2; + int unk_int3; + float unk_float1; + float unk_float2; + CPlayerName playerName; + char unk2[4]; + char unk3[4]; +public: + CGrid(); + void ProcessAnyLeftJustDown(); + void ProcessAnyRightJustDown(); + void ProcessAnyUpJustDown(); + void ProcessAnyDownJustDown(); + void AllDoneMakePlayerName(); + void ProcessDPadCrossJustDown(); + void DisplayGrid(); + void ProcessControllerInput(); + void Process(); +}; \ No newline at end of file diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index a024bb40..5b212f62 100644 --- a/src/modelinfo/VehicleModelInfo.cpp +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -536,7 +536,7 @@ CVehicleModelInfo::SetVehicleComponentFlags(RwFrame *frame, uint32 flags) { tHandlingData *handling; - handling = mod_HandlingManager.GetHandlingData((eHandlingId)m_handlingId); + handling = mod_HandlingManager.GetHandlingData((tVehicleType)m_handlingId); #define SETFLAGS(f) RwFrameForAllObjects(frame, SetAtomicFlagCB, (void*)(f)) diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 66afa1d4..ec71f690 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -75,7 +75,7 @@ CAutomobile::CAutomobile(int32 id, uint8 CreatedBy) SetModelIndex(id); - pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); + pHandling = mod_HandlingManager.GetHandlingData((tVehicleType)mi->m_handlingId); m_auto_unused1 = 20.0f; m_auto_unused2 = 0; diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index dfe9d1d9..aba48bad 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -50,7 +50,7 @@ CBoat::CBoat(int mi, uint8 owner) : CVehicle(owner) m_fMovingRotation = 0.0f; SetModelIndex(mi); - pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)minfo->m_handlingId); + pHandling = mod_HandlingManager.GetHandlingData((tVehicleType)minfo->m_handlingId); minfo->ChooseVehicleColour(m_currentColour1, m_currentColour2); m_fMass = pHandling->fMass; diff --git a/src/vehicles/HandlingMgr.cpp b/src/vehicles/HandlingMgr.cpp index 5beed29e..18a2481e 100644 --- a/src/vehicles/HandlingMgr.cpp +++ b/src/vehicles/HandlingMgr.cpp @@ -127,7 +127,7 @@ cHandlingDataMgr::LoadHandlingData(void) handlingId = FindExactWord(word, (const char*)VehicleNames, 14, NUMHANDLINGS); assert(handlingId >= 0 && handlingId < NUMHANDLINGS); handling = &HandlingData[handlingId]; - handling->nIdentifier = (eHandlingId)handlingId; + handling->nIdentifier = (tVehicleType)handlingId; break; case 1: handling->fMass = strtod(word, nil); break; case 2: handling->Dimension.x = strtod(word, nil); break; @@ -237,3 +237,27 @@ cHandlingDataMgr::GetHandlingId(const char *name) break; return i; } + +void +cHandlingDataMgr::ConvertDataToWorldUnits(tHandlingData *handling) +{ + // TODO: mobile code +} + +void +cHandlingDataMgr::RangeCheck(tHandlingData *handling) +{ + // TODO: mobile code +} + +void +cHandlingDataMgr::ModifyHandlingValue(CVehicle *, const tVehicleType &, const tField &, const bool &) +{ + // TODO: mobile code +} + +void +cHandlingDataMgr::DisplayHandlingData(CVehicle *, tHandlingData *, uint8, bool) +{ + // TODO: mobile code +} \ No newline at end of file diff --git a/src/vehicles/HandlingMgr.h b/src/vehicles/HandlingMgr.h index 10e25573..4d3b8389 100644 --- a/src/vehicles/HandlingMgr.h +++ b/src/vehicles/HandlingMgr.h @@ -2,7 +2,7 @@ #include "Transmission.h" -enum eHandlingId +enum tVehicleType { HANDLING_LANDSTAL, HANDLING_IDAHO, @@ -65,6 +65,11 @@ enum eHandlingId NUMHANDLINGS }; +enum tField : uint32 // most likely a handling field enum, never used so :shrug: +{ + +}; + enum { HANDLING_1G_BOOST = 1, @@ -87,7 +92,7 @@ enum struct tHandlingData { - eHandlingId nIdentifier; + tVehicleType nIdentifier; float fMass; float fInvMass; float fTurnMass; @@ -118,6 +123,8 @@ struct tHandlingData }; VALIDATE_SIZE(tHandlingData, 0xD8); +class CVehicle; + class cHandlingDataMgr { float field_0; // unused it seems @@ -135,11 +142,15 @@ public: void Initialise(void); void LoadHandlingData(void); int FindExactWord(const char *word, const char *words, int wordLen, int numWords); + void ConvertDataToWorldUnits(tHandlingData *handling); void ConvertDataToGameUnits(tHandlingData *handling); + void RangeCheck(tHandlingData *handling); + void ModifyHandlingValue(CVehicle *, const tVehicleType &, const tField &, const bool &); + void DisplayHandlingData(CVehicle *, tHandlingData *, uint8, bool); int32 GetHandlingId(const char *name); - tHandlingData *GetHandlingData(eHandlingId id) { return &HandlingData[id]; } - bool HasRearWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'R'; } - bool HasFrontWheelDrive(eHandlingId id) { return HandlingData[id].Transmission.nDriveType == 'F'; } + tHandlingData *GetHandlingData(tVehicleType id) { return &HandlingData[id]; } + bool HasRearWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType == 'R'; } + bool HasFrontWheelDrive(tVehicleType id) { return HandlingData[id].Transmission.nDriveType == 'F'; } }; VALIDATE_SIZE(cHandlingDataMgr, 0x3030); extern cHandlingDataMgr mod_HandlingManager; diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index e1f662d8..a8705524 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -52,7 +52,7 @@ CHeli::CHeli(int32 id, uint8 CreatedBy) CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id); m_vehType = VEHICLE_TYPE_HELI; - pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); + pHandling = mod_HandlingManager.GetHandlingData((tVehicleType)mi->m_handlingId); SetModelIndex(id); m_heliStatus = HELI_STATUS_HOVER; m_pathState = 0; diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp index b8a957cf..1a6f1a88 100644 --- a/src/vehicles/Plane.cpp +++ b/src/vehicles/Plane.cpp @@ -68,7 +68,7 @@ CPlane::CPlane(int32 id, uint8 CreatedBy) { CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id); m_vehType = VEHICLE_TYPE_PLANE; - pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); + pHandling = mod_HandlingManager.GetHandlingData((tVehicleType)mi->m_handlingId); SetModelIndex(id); m_fMass = 100000000.0f; diff --git a/src/vehicles/Train.cpp b/src/vehicles/Train.cpp index 26d0dee7..4250f6f4 100644 --- a/src/vehicles/Train.cpp +++ b/src/vehicles/Train.cpp @@ -43,7 +43,7 @@ CTrain::CTrain(int32 id, uint8 CreatedBy) { CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id); m_vehType = VEHICLE_TYPE_TRAIN; - pHandling = mod_HandlingManager.GetHandlingData((eHandlingId)mi->m_handlingId); + pHandling = mod_HandlingManager.GetHandlingData((tVehicleType)mi->m_handlingId); SetModelIndex(id); Doors[0].Init(0.8f, 0.0f, 1, 0); diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index bc77b011..d2ca5a1a 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -582,6 +582,13 @@ CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelCon } } +void +CVehicle::ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint, int32 wheelsOnGround, float thrust, + float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, eBikeWheelSpecial special, uint16 wheelStatus) +{ + // TODO: mobile code +} + float CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius) { diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 999ee002..3933f1dd 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -103,6 +103,15 @@ enum eFlightModel FLIGHT_MODEL_SEAPLANE }; +// TODO: what is this even? +enum eBikeWheelSpecial { + BIKE_WHEELSPEC_0, // both wheels on ground + BIKE_WHEELSPEC_1, // rear wheel on ground + BIKE_WHEELSPEC_2, // only front wheel on ground + BIKE_WHEELSPEC_3, // can't happen +}; + + class CVehicle : public CPhysical { public: @@ -237,6 +246,8 @@ public: void FlyingControl(eFlightModel flightModel); void ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint, int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus); + void ProcessBikeWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint, int32 wheelsOnGround, float thrust, + float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, eBikeWheelSpecial special, uint16 wheelStatus); void ExtinguishCarFire(void); void ProcessDelayedExplosion(void); float ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius); From bd3d09fef53680389bd6ef856eb0669e31fba1d7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 24 Nov 2020 02:15:57 +0200 Subject: [PATCH 080/129] Script commands split to original files --- src/control/Script.cpp | 8915 +-------------------------------------- src/control/Script.h | 23 + src/control/Script2.cpp | 1549 +++++++ src/control/Script3.cpp | 2082 +++++++++ src/control/Script4.cpp | 2027 +++++++++ src/control/Script5.cpp | 2011 +++++++++ src/control/Script6.cpp | 1343 ++++++ 7 files changed, 9038 insertions(+), 8912 deletions(-) create mode 100644 src/control/Script2.cpp create mode 100644 src/control/Script3.cpp create mode 100644 src/control/Script4.cpp create mode 100644 src/control/Script5.cpp create mode 100644 src/control/Script6.cpp diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 646bc3f7..085c773a 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -4,94 +4,40 @@ #include "ScriptCommands.h" #include "AnimBlendAssociation.h" +#include "AudioManager.h" #include "Boat.h" -#include "BulletInfo.h" #include "Camera.h" -#include "CarAI.h" #include "CarCtrl.h" -#include "CarGen.h" #include "CivilianPed.h" #include "Clock.h" #include "CopPed.h" -#include "Coronas.h" -#include "Cranes.h" -#include "Credits.h" -#include "CutsceneMgr.h" #include "Debug.h" #include "DMAudio.h" -#include "Darkel.h" #include "EmergencyPed.h" -#include "Explosion.h" #include "FileMgr.h" -#include "Fire.h" #include "Frontend.h" -#include "Gangs.h" -#include "Garages.h" #include "General.h" -#ifdef MISSION_REPLAY -#include "GenericGameStorage.h" -#endif #include "HandlingMgr.h" #include "Heli.h" #include "Hud.h" #include "Lines.h" #include "Messages.h" -#include "ModelIndices.h" #include "Pad.h" -#include "Particle.h" -#include "ParticleObject.h" -#include "PedRoutes.h" -#include "Phones.h" #include "Pickups.h" -#include "Plane.h" -#include "PlayerInfo.h" -#include "PlayerPed.h" -#include "PointLights.h" #include "Pools.h" #include "Population.h" -#include "PowerPoints.h" -#include "ProjectileInfo.h" -#include "Radar.h" -#include "Record.h" #include "Remote.h" #include "Replay.h" -#include "Restart.h" -#include "RpAnimBlend.h" -#include "Rubbish.h" -#include "Shadows.h" -#include "SpecialFX.h" #include "Stats.h" #include "Streaming.h" -#include "Text.h" -#include "TxdStore.h" #include "User.h" -#include "WaterLevel.h" +#include "Wanted.h" #include "Weather.h" -#include "World.h" #include "Zones.h" -#include "main.h" #ifdef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT #include #endif -#define PICKUP_PLACEMENT_OFFSET 0.5f -#define PED_FIND_Z_OFFSET 5.0f - -#define SPHERE_MARKER_R 0 -#define SPHERE_MARKER_G 128 -#define SPHERE_MARKER_B 255 -#define SPHERE_MARKER_A 128 -#define SPHERE_MARKER_PULSE_PERIOD 2048 -#define SPHERE_MARKER_PULSE_FRACTION 0.1f - -#ifdef USE_PRECISE_MEASUREMENT_CONVERTION -#define METERS_IN_FOOT 0.3048f -#define FEET_IN_METER 3.28084f -#else -#define METERS_IN_FOOT 0.3f -#define FEET_IN_METER 3.33f -#endif - uint8 CTheScripts::ScriptSpace[SIZE_SCRIPT_SPACE]; CRunningScript CTheScripts::ScriptsArray[MAX_NUM_SCRIPTS]; int32 CTheScripts::BaseBriefIdForContact[MAX_NUM_CONTACTS]; @@ -1362,7 +1308,7 @@ static void PrintToLog(const char* format, ...) #endif -static void FlushLog() +void FlushLog() { #ifdef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT #if SCRIPT_LOG_FILE_LEVEL == 1 || SCRIPT_LOG_FILE_LEVEL == 2 @@ -1372,7 +1318,6 @@ static void FlushLog() #endif } -#define script_assert(_Expression) FlushLog(); assert(_Expression); const uint32 CRunningScript::nSaveStructSize = #ifdef COMPATIBLE_SAVES @@ -4369,8860 +4314,6 @@ int8 CRunningScript::ProcessCommands200To299(int32 command) return -1; } -int8 CRunningScript::ProcessCommands300To399(int32 command) -{ - switch (command) { - /* Not implemented. - case COMMAND_SET_CHAR_INVINCIBLE: - case COMMAND_SET_PLAYER_INVINCIBLE: - case COMMAND_SET_CHAR_GRAPHIC_TYPE: - case COMMAND_SET_PLAYER_GRAPHIC_TYPE: - */ - case COMMAND_HAS_PLAYER_BEEN_ARRESTED: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_BUSTED); - return 0; - /* Not implemented. - case COMMAND_STOP_CHAR_DRIVING: - case COMMAND_KILL_CHAR: - case COMMAND_SET_FAVOURITE_CAR_MODEL_FOR_CHAR: - case COMMAND_SET_CHAR_OCCUPATION: - */ - case COMMAND_CHANGE_CAR_LOCK: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->m_nDoorLock = (eCarLock)ScriptParams[1]; - return 0; - } - case COMMAND_SHAKE_CAM_WITH_POINT: - CollectParameters(&m_nIp, 4); - TheCamera.CamShake(ScriptParams[0] / 1000.0f, - *(float*)&ScriptParams[1], - *(float*)&ScriptParams[2], - *(float*)&ScriptParams[3]); - return 0; - case COMMAND_IS_CAR_MODEL: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->GetModelIndex() == ScriptParams[1]); - return 0; - } - /* Not implemented. - case COMMAND_IS_CAR_REMAP: - case COMMAND_HAS_CAR_JUST_SUNK: - case COMMAND_SET_CAR_NO_COLLIDE: - */ - case COMMAND_IS_CAR_DEAD_IN_AREA_2D: - { - CollectParameters(&m_nIp, 6); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - float x1 = *(float*)&ScriptParams[1]; - float y1 = *(float*)&ScriptParams[2]; - float x2 = *(float*)&ScriptParams[3]; - float y2 = *(float*)&ScriptParams[4]; - UpdateCompareFlag(pVehicle->GetStatus() == STATUS_WRECKED && - pVehicle->IsWithinArea(x1, y1, x2, y2)); - if (ScriptParams[5]) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) - CTheScripts::DrawDebugSquare(x1, y1, x2, y2); - return 0; - } - case COMMAND_IS_CAR_DEAD_IN_AREA_3D: - { - CollectParameters(&m_nIp, 8); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - float x1 = *(float*)&ScriptParams[1]; - float y1 = *(float*)&ScriptParams[2]; - float z1 = *(float*)&ScriptParams[3]; - float x2 = *(float*)&ScriptParams[4]; - float y2 = *(float*)&ScriptParams[5]; - float z2 = *(float*)&ScriptParams[6]; - UpdateCompareFlag(pVehicle->GetStatus() == STATUS_WRECKED && - pVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2)); - if (ScriptParams[7]) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, (z1 + z2) / 2); - if (CTheScripts::DbgFlag) - CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2); - return 0; - } - /* Not implemented. - case COMMAND_IS_TRAILER_ATTACHED: - case COMMAND_IS_CAR_ON_TRAILER: - case COMMAND_HAS_CAR_GOT_WEAPON: - case COMMAND_PARK: - case COMMAND_HAS_PARK_FINISHED: - case COMMAND_KILL_ALL_PASSENGERS: - case COMMAND_SET_CAR_BULLETPROOF: - case COMMAND_SET_CAR_FLAMEPROOF: - case COMMAND_SET_CAR_ROCKETPROOF: - case COMMAND_IS_CARBOMB_ACTIVE: - case COMMAND_GIVE_CAR_ALARM: - case COMMAND_PUT_CAR_ON_TRAILER: - */ - case COMMAND_IS_CAR_CRUSHED: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CGarages::HasCarBeenCrushed(ScriptParams[0])); - return 0; - /* Not implemented. - case COMMAND_CREATE_GANG_CAR: - */ - case COMMAND_CREATE_CAR_GENERATOR: - CollectParameters(&m_nIp, 12); - ScriptParams[0] = CTheCarGenerators::CreateCarGenerator( - *(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], *(float*)&ScriptParams[3], - ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], - ScriptParams[8], ScriptParams[9], ScriptParams[10], ScriptParams[11]); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_SWITCH_CAR_GENERATOR: - { - CollectParameters(&m_nIp, 2); - CCarGenerator* pCarGen = &CTheCarGenerators::CarGeneratorArray[ScriptParams[0]]; - if (ScriptParams[1] == 0){ - pCarGen->SwitchOff(); - }else if (ScriptParams[1] <= 100){ - pCarGen->SwitchOn(); - pCarGen->SetUsesRemaining(ScriptParams[1]); - }else{ - pCarGen->SwitchOn(); - } - return 0; - } - case COMMAND_ADD_PAGER_MESSAGE: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 3); - CUserDisplay::Pager.AddMessage(text, ScriptParams[0], ScriptParams[1], ScriptParams[2]); - return 0; - } - case COMMAND_DISPLAY_ONSCREEN_TIMER: - { - script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); - m_nIp++; - CUserDisplay::OnscnTimer.AddClock((uint16)CTheScripts::Read2BytesFromScript(&m_nIp), nil); - return 0; - } - case COMMAND_CLEAR_ONSCREEN_TIMER: - { - script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); - m_nIp++; - CUserDisplay::OnscnTimer.ClearClock((uint16)CTheScripts::Read2BytesFromScript(&m_nIp)); - return 0; - } - case COMMAND_DISPLAY_ONSCREEN_COUNTER: - { - script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); - m_nIp++; - uint16 counter = CTheScripts::Read2BytesFromScript(&m_nIp); - CollectParameters(&m_nIp, 1); - CUserDisplay::OnscnTimer.AddCounter(counter, ScriptParams[0], nil); - return 0; - } - case COMMAND_CLEAR_ONSCREEN_COUNTER: - { - script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); - m_nIp++; - CUserDisplay::OnscnTimer.ClearCounter((uint16)CTheScripts::Read2BytesFromScript(&m_nIp)); - return 0; - } - case COMMAND_SET_ZONE_CAR_INFO: - { - char label[12]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CollectParameters(&m_nIp, 16); - int zone = CTheZones::FindZoneByLabelAndReturnIndex(label); - if (zone < 0) { - debug("Couldn't find zone - %s\n", label); - return 0; - } - CTheZones::SetZoneCarInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], - ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], 0, 0, - ScriptParams[9], ScriptParams[10], ScriptParams[11], ScriptParams[12], - ScriptParams[13], ScriptParams[14], ScriptParams[15]); - return 0; - } - /* Not implemented. - case COMMAND_IS_CHAR_IN_GANG_ZONE: - */ - case COMMAND_IS_CHAR_IN_ZONE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - char label[12]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - int zone = CTheZones::FindZoneByLabelAndReturnIndex(label); - if (zone != -1) - m_nIp += KEY_LENGTH_IN_SCRIPT; - CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); - UpdateCompareFlag(CTheZones::PointLiesWithinZone(&pos, CTheZones::GetZone(zone))); - return 0; - } - case COMMAND_SET_CAR_DENSITY: - { - char label[12]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); - m_nIp += 8; - CollectParameters(&m_nIp, 2); - if (zone < 0) { - debug("Couldn't find zone - %s\n", label); - return 0; - } - CTheZones::SetCarDensity(zone, ScriptParams[0], ScriptParams[1]); - return 0; - } - case COMMAND_SET_PED_DENSITY: - { - char label[12]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CollectParameters(&m_nIp, 2); - if (zone < 0) { - debug("Couldn't find zone - %s\n", label); - return 0; - } - CTheZones::SetPedDensity(zone, ScriptParams[0], ScriptParams[1]); - return 0; - } - case COMMAND_POINT_CAMERA_AT_PLAYER: - { - CollectParameters(&m_nIp, 3); - // ScriptParams[0] is unused. - TheCamera.TakeControl(nil, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT); - return 0; - } - case COMMAND_POINT_CAMERA_AT_CAR: - { - CollectParameters(&m_nIp, 3); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - TheCamera.TakeControl(pVehicle, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT); - return 0; - } - case COMMAND_POINT_CAMERA_AT_CHAR: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - TheCamera.TakeControl(pPed, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT); - return 0; - } - case COMMAND_RESTORE_CAMERA: - TheCamera.Restore(); - return 0; - case COMMAND_SHAKE_PAD: - CPad::GetPad(ScriptParams[0])->StartShake(ScriptParams[1], ScriptParams[2]); - return 0; - case COMMAND_SET_ZONE_PED_INFO: - { - char label[12]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, label); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CollectParameters(&m_nIp, 10); - int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); - if (zone < 0) { - debug("Couldn't find zone - %s\n", label); - return 0; - } - CTheZones::SetZonePedInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], - ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], 0, 0, ScriptParams[9]); - return 0; - } - case COMMAND_SET_TIME_SCALE: - CollectParameters(&m_nIp, 1); - CTimer::SetTimeScale(*(float*)&ScriptParams[0]); - return 0; - case COMMAND_IS_CAR_IN_AIR: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle && pVehicle->IsCar()); - CAutomobile* pCar = (CAutomobile*)pVehicle; - UpdateCompareFlag(pCar->GetAllWheelsOffGround()); - return 0; - } - case COMMAND_SET_FIXED_CAMERA_POSITION: - { - CollectParameters(&m_nIp, 6); - TheCamera.SetCamPositionForFixedMode( - CVector(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2]), - CVector(*(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5])); - return 0; - } - case COMMAND_POINT_CAMERA_AT_POINT: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - TheCamera.TakeControlNoEntity(pos, ScriptParams[3], CAMCONTROL_SCRIPT); - return 0; - } - case COMMAND_ADD_BLIP_FOR_CAR_OLD: - { - CollectParameters(&m_nIp, 3); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - // Useless call. - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CRadar::SetEntityBlip(BLIP_CAR, ScriptParams[0], ScriptParams[1], (eBlipDisplay)ScriptParams[2]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_BLIP_FOR_CHAR_OLD: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - // Useless call. - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], ScriptParams[1], (eBlipDisplay)ScriptParams[2]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_BLIP_FOR_OBJECT_OLD: - { - CollectParameters(&m_nIp, 3); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - // Useless call. - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], ScriptParams[1], (eBlipDisplay)ScriptParams[2]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_REMOVE_BLIP: - CollectParameters(&m_nIp, 1); - CRadar::ClearBlip(ScriptParams[0]); - return 0; - case COMMAND_CHANGE_BLIP_COLOUR: - CollectParameters(&m_nIp, 2); - CRadar::ChangeBlipColour(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_DIM_BLIP: - CollectParameters(&m_nIp, 2); - CRadar::ChangeBlipBrightness(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_ADD_BLIP_FOR_COORD_OLD: - { - CollectParameters(&m_nIp, 5); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - // Useless call - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CRadar::SetCoordBlip(BLIP_COORD, pos, ScriptParams[3], (eBlipDisplay)ScriptParams[4]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_CHANGE_BLIP_SCALE: - CollectParameters(&m_nIp, 2); - CRadar::ChangeBlipScale(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_SET_FADING_COLOUR: - CollectParameters(&m_nIp, 3); - TheCamera.SetFadeColour(ScriptParams[0], ScriptParams[1], ScriptParams[2]); - return 0; - case COMMAND_DO_FADE: - CollectParameters(&m_nIp, 2); - TheCamera.Fade(ScriptParams[0] / 1000.0f, ScriptParams[1]); - return 0; - case COMMAND_GET_FADING_STATUS: - UpdateCompareFlag(TheCamera.GetFading()); - return 0; - case COMMAND_ADD_HOSPITAL_RESTART: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - float angle = *(float*)&ScriptParams[3]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CRestart::AddHospitalRestartPoint(pos, angle); - return 0; - } - case COMMAND_ADD_POLICE_RESTART: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - float angle = *(float*)&ScriptParams[3]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CRestart::AddPoliceRestartPoint(pos, angle); - return 0; - } - case COMMAND_OVERRIDE_NEXT_RESTART: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - float angle = *(float*)&ScriptParams[3]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CRestart::OverrideNextRestart(pos, angle); - return 0; - } - case COMMAND_DRAW_SHADOW: - { - CollectParameters(&m_nIp, 10); - CVector pos = *(CVector*)&ScriptParams[1]; - float angle = *(float*)&ScriptParams[4]; - float length = *(float*)&ScriptParams[5]; - float x, y; - if (angle != 0.0f){ - y = cos(angle) * length; - x = sin(angle) * length; - }else{ - y = length; - x = 0.0f; - } - float frontX = -x; - float frontY = y; - float sideX = y; - float sideY = x; - /* Not very nicely named intermediate variables. */ - CShadows::StoreShadowToBeRendered(ScriptParams[0], &pos, frontX, frontY, sideX, sideY, - ScriptParams[6], ScriptParams[7], ScriptParams[8], ScriptParams[9]); - return 0; - } - case COMMAND_GET_PLAYER_HEADING: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - float angle = pPed->bInVehicle ? pPed->m_pMyVehicle->GetForward().Heading() : pPed->GetForward().Heading(); - *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_PLAYER_HEADING: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - if (pPed->bInVehicle){ - // Is script_assertion required? - return 0; - } - pPed->m_fRotationDest = pPed->m_fRotationCur = DEGTORAD(*(float*)&ScriptParams[1]); - pPed->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); - return 0; - } - case COMMAND_GET_CHAR_HEADING: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - float angle = pPed->bInVehicle ? pPed->m_pMyVehicle->GetForward().Heading() : pPed->GetForward().Heading(); - *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CHAR_HEADING: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - if (pPed->bInVehicle) { - // Is script_assertion required? - return 0; - } - pPed->m_fRotationDest = pPed->m_fRotationCur = DEGTORAD(*(float*)&ScriptParams[1]); - pPed->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); - return 0; - } - case COMMAND_GET_CAR_HEADING: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - float angle = pVehicle->GetForward().Heading(); - *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CAR_HEADING: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); - return 0; - } - case COMMAND_GET_OBJECT_HEADING: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - float angle = pObject->GetForward().Heading(); - *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_OBJECT_HEADING: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CWorld::Remove(pObject); - pObject->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); - pObject->GetMatrix().UpdateRW(); - pObject->UpdateRwFrame(); - CWorld::Add(pObject); - return 0; - } - case COMMAND_IS_PLAYER_TOUCHING_OBJECT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); - script_assert(pObject); - CPhysical* pEntityToTest = pPed->bInVehicle ? (CPhysical*)pPed->m_pMyVehicle : pPed; - UpdateCompareFlag(pEntityToTest->GetHasCollidedWith(pObject)); - return 0; - } - case COMMAND_IS_CHAR_TOUCHING_OBJECT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); - script_assert(pObject); - CPhysical* pEntityToTest = pPed->bInVehicle ? (CPhysical*)pPed->m_pMyVehicle : pPed; - UpdateCompareFlag(pEntityToTest->GetHasCollidedWith(pObject)); - return 0; - } - case COMMAND_SET_PLAYER_AMMO: - { - CollectParameters(&m_nIp, 3); - CWorld::Players[0].m_pPed->SetAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]); - return 0; - } - case COMMAND_SET_CHAR_AMMO: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - pPed->SetAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]); - return 0; - } - /* Not implemented. - case COMMAND_SET_CAR_AMMO: - case COMMAND_LOAD_CAMERA_SPLINE: - case COMMAND_MOVE_CAMERA_ALONG_SPLINE: - case COMMAND_GET_CAMERA_POSITION_ALONG_SPLINE: - */ - case COMMAND_DECLARE_MISSION_FLAG: - CTheScripts::OnAMissionFlag = (uint16)CTheScripts::Read2BytesFromScript(&++m_nIp); - return 0; - case COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT: - CollectParameters(&m_nIp, 1); - CTheScripts::OnAMissionForContactFlag[ScriptParams[0]] = (uint16)CTheScripts::Read2BytesFromScript(&++m_nIp); - return 0; - case COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT: - CollectParameters(&m_nIp, 2); - CTheScripts::BaseBriefIdForContact[ScriptParams[0]] = ScriptParams[1]; - return 0; - case COMMAND_IS_PLAYER_HEALTH_GREATER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - UpdateCompareFlag(pPed->m_fHealth > ScriptParams[1]); - return 0; - } - case COMMAND_IS_CHAR_HEALTH_GREATER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(pPed->m_fHealth > ScriptParams[1]); - return 0; - } - case COMMAND_IS_CAR_HEALTH_GREATER: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->m_fHealth > ScriptParams[1]); - return 0; - } - case COMMAND_ADD_BLIP_FOR_CAR: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - // Useless call. - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetEntityBlip(BLIP_CAR, ScriptParams[0], 0, BLIP_DISPLAY_BOTH); - CRadar::ChangeBlipScale(handle, 3); - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_BLIP_FOR_CHAR: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - // Useless call. - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], 1, BLIP_DISPLAY_BOTH); - CRadar::ChangeBlipScale(handle, 3); - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_BLIP_FOR_OBJECT: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - // Useless call. - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], 6, BLIP_DISPLAY_BOTH); - CRadar::ChangeBlipScale(handle, 3); - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_BLIP_FOR_CONTACT_POINT: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - // Useless call - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetCoordBlip(BLIP_CONTACT_POINT, pos, 2, BLIP_DISPLAY_BOTH); - CRadar::ChangeBlipScale(handle, 3); - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_BLIP_FOR_COORD: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - // Useless call - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetCoordBlip(BLIP_COORD, pos, 5, BLIP_DISPLAY_BOTH); - CRadar::ChangeBlipScale(handle, 3); - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_CHANGE_BLIP_DISPLAY: - CollectParameters(&m_nIp, 2); - CRadar::ChangeBlipDisplay(ScriptParams[0], (eBlipDisplay)ScriptParams[1]); - return 0; - case COMMAND_ADD_ONE_OFF_SOUND: - { - CollectParameters(&m_nIp, 4); - switch (ScriptParams[3]) { - case SCRIPT_SOUND_EVIDENCE_PICKUP: - DMAudio.PlayFrontEndSound(SOUND_EVIDENCE_PICKUP, 0); - return 0; - case SCRIPT_SOUND_UNLOAD_GOLD: - DMAudio.PlayFrontEndSound(SOUND_UNLOAD_GOLD, 0); - return 0; - case SCRIPT_SOUND_PART_MISSION_COMPLETE: - DMAudio.PlayFrontEndSound(SOUND_PART_MISSION_COMPLETE, 0); - return 0; - case SCRIPT_SOUND_RACE_START_3: - DMAudio.PlayFrontEndSound(SOUND_RACE_START_3, 0); - return 0; - case SCRIPT_SOUND_RACE_START_2: - DMAudio.PlayFrontEndSound(SOUND_RACE_START_2, 0); - return 0; - case SCRIPT_SOUND_RACE_START_1: - DMAudio.PlayFrontEndSound(SOUND_RACE_START_1, 0); - return 0; - case SCRIPT_SOUND_RACE_START_GO: - DMAudio.PlayFrontEndSound(SOUND_RACE_START_GO, 0); - return 0; - default: - break; - } -#ifdef FIX_BUGS - /* BUG: if audio is not initialized, this object will not be freed. */ - if (!DMAudio.IsAudioInitialised()) - return 0; -#endif - cAudioScriptObject* obj = new cAudioScriptObject(); - obj->Posn = *(CVector*)&ScriptParams[0]; - obj->AudioId = ScriptParams[3]; - obj->AudioEntity = AEHANDLE_NONE; - DMAudio.CreateOneShotScriptObject(obj); - return 0; - } - case COMMAND_ADD_CONTINUOUS_SOUND: - { - CollectParameters(&m_nIp, 4); - cAudioScriptObject* obj = new cAudioScriptObject(); - obj->Posn = *(CVector*)&ScriptParams[0]; - obj->AudioId = ScriptParams[3]; - obj->AudioEntity = DMAudio.CreateLoopingScriptObject(obj); - ScriptParams[0] = CPools::GetAudioScriptObjectPool()->GetIndex(obj); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_REMOVE_SOUND: - { - CollectParameters(&m_nIp, 1); - cAudioScriptObject* obj = CPools::GetAudioScriptObjectPool()->GetAt(ScriptParams[0]); - if (!obj){ - debug("REMOVE_SOUND - Sound doesn't exist\n"); - return 0; - } - DMAudio.DestroyLoopingScriptObject(obj->AudioEntity); - delete obj; - return 0; - } - case COMMAND_IS_CAR_STUCK_ON_ROOF: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(CTheScripts::UpsideDownCars.HasCarBeenUpsideDownForAWhile(ScriptParams[0])); - return 0; - } - default: - script_assert(0); - } - return -1; -} - -int8 CRunningScript::ProcessCommands400To499(int32 command) -{ - switch (command) { - case COMMAND_ADD_UPSIDEDOWN_CAR_CHECK: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CTheScripts::UpsideDownCars.AddCarToCheck(ScriptParams[0]); - return 0; - } - case COMMAND_REMOVE_UPSIDEDOWN_CAR_CHECK: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CTheScripts::UpsideDownCars.RemoveCarFromCheck(ScriptParams[0]); - return 0; - } - case COMMAND_SET_CHAR_OBJ_WAIT_ON_FOOT: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_WAIT_ON_FOOT); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FLEE_ON_FOOT_TILL_SAFE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE); - return 0; - } - case COMMAND_SET_CHAR_OBJ_GUARD_SPOT: - { - CollectParameters(&m_nIp, 4); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_GUARD_SPOT, pos); - return 0; - } - case COMMAND_SET_CHAR_OBJ_GUARD_AREA: - { - CollectParameters(&m_nIp, 5); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - float infX = *(float*)&ScriptParams[1]; - float infY = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - if (infX > supX){ - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[1]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[2]; - } - CVector pos; - pos.x = (infX + supX) / 2; - pos.y = (infY + supY) / 2; - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float radius = Max(pos.x - infX, pos.y - infY); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_GUARD_SPOT, pos, radius); - return 0; - } - case COMMAND_SET_CHAR_OBJ_WAIT_IN_CAR: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_WAIT_IN_CAR); - return 0; - } - case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: - PlayerInAreaCheckCommand(command, &m_nIp); - return 0; - case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_CHAR_IN_AREA_IN_CAR_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_2D: - case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_CHAR_IN_AREA_IN_CAR_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: - CharInAreaCheckCommand(command, &m_nIp); - return 0; - case COMMAND_IS_CAR_STOPPED_IN_AREA_2D: - case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: - CarInAreaCheckCommand(command, &m_nIp); - return 0; - case COMMAND_LOCATE_CAR_2D: - case COMMAND_LOCATE_STOPPED_CAR_2D: - case COMMAND_LOCATE_CAR_3D: - case COMMAND_LOCATE_STOPPED_CAR_3D: - LocateCarCommand(command, &m_nIp); - return 0; - case COMMAND_GIVE_WEAPON_TO_PLAYER: - { - CollectParameters(&m_nIp, 3); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - pPed->m_nSelectedWepSlot = pPed->GiveWeapon((eWeaponType)ScriptParams[1], ScriptParams[2]); - return 0; - } - case COMMAND_GIVE_WEAPON_TO_CHAR: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->SetCurrentWeapon(pPed->GiveWeapon((eWeaponType)ScriptParams[1], ScriptParams[2])); - if (pPed->bInVehicle) - pPed->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType)->m_nModelId); - return 0; - } - /* Not implemented */ - //case COMMAND_GIVE_WEAPON_TO_CAR: - case COMMAND_SET_PLAYER_CONTROL: - { - CollectParameters(&m_nIp, 2); - CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; - if (ScriptParams[1]){ - if (CGame::playingIntro || CTheScripts::DelayMakingPlayerUnsafeThisTime){ - CTheScripts::CountdownToMakePlayerUnsafe = 50; - if (CTheScripts::DelayMakingPlayerUnsafeThisTime) - CTheScripts::DelayMakingPlayerUnsafeThisTime--; - }else{ - pPlayer->MakePlayerSafe(false); - } - }else{ - pPlayer->MakePlayerSafe(true); - if (strcmp(m_abScriptName, "camera") == 0){ - pPlayer->m_pPed->SetMoveSpeed(0.0f, 0.0f, 0.0f); - pPlayer->m_pPed->SetTurnSpeed(0.0f, 0.0f, 0.0f); - CAnimManager::BlendAnimation((RpClump*)pPlayer->m_pPed->m_rwObject, pPlayer->m_pPed->m_animGroup, ANIM_IDLE_STANCE, 1000.0f); - } - } - return 0; - } - case COMMAND_FORCE_WEATHER: - CollectParameters(&m_nIp, 1); - CWeather::ForceWeather(ScriptParams[0]); - return 0; - case COMMAND_FORCE_WEATHER_NOW: - CollectParameters(&m_nIp, 1); - CWeather::ForceWeatherNow(ScriptParams[0]); - return 0; - case COMMAND_RELEASE_WEATHER: - CWeather::ReleaseWeather(); - return 0; - case COMMAND_SET_CURRENT_PLAYER_WEAPON: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++){ - if (pPed->m_weapons[i].m_eWeaponType == ScriptParams[1]) - pPed->m_nSelectedWepSlot = i; - } - return 0; - } - case COMMAND_SET_CURRENT_CHAR_WEAPON: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { - if (pPed->m_weapons[i].m_eWeaponType == ScriptParams[1]) - pPed->SetCurrentWeapon(i); - } - return 0; - } - /* Not implemented */ - //case COMMAND_SET_CURRENT_CAR_WEAPON: - case COMMAND_GET_OBJECT_COORDINATES: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - *(CVector*)&ScriptParams[0] = pObject->GetPosition(); - StoreParameters(&m_nIp, 3); - return 0; - } - case COMMAND_SET_OBJECT_COORDINATES: - { - CollectParameters(&m_nIp, 4); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - pObject->Teleport(pos); - CTheScripts::ClearSpaceForMissionEntity(pos, pObject); - return 0; - } - case COMMAND_GET_GAME_TIMER: - ScriptParams[0] = CTimer::GetTimeInMilliseconds(); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_TURN_CHAR_TO_FACE_COORD: - { - CollectParameters(&m_nIp, 4); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle; - CVector pos; - if (pPed->bInVehicle) - pVehicle = pPed->m_pMyVehicle; - else - pVehicle = nil; - if (pVehicle) - pos = pVehicle->GetPosition(); - else - pos = pPed->GetPosition(); - float heading = CGeneral::GetATanOfXY(pos.x - *(float*)&ScriptParams[1], pos.y - *(float*)&ScriptParams[2]); - heading += HALFPI; - if (heading > TWOPI) - heading -= TWOPI; - if (!pVehicle){ - pPed->m_fRotationCur = heading; - pPed->m_fRotationDest = heading; - pPed->SetHeading(heading); - } - return 0; - } - case COMMAND_TURN_PLAYER_TO_FACE_COORD: - { - CollectParameters(&m_nIp, 4); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CVehicle* pVehicle; - CVector pos; - if (pPed->bInVehicle) - pVehicle = pPed->m_pMyVehicle; - else - pVehicle = nil; - if (pVehicle) - pos = pVehicle->GetPosition(); - else - pos = pPed->GetPosition(); - float heading = CGeneral::GetATanOfXY(pos.x - *(float*)&ScriptParams[1], pos.y - *(float*)&ScriptParams[2]); - heading += HALFPI; - if (heading > TWOPI) - heading -= TWOPI; - if (!pVehicle) { - pPed->m_fRotationCur = heading; - pPed->m_fRotationDest = heading; - pPed->SetHeading(heading); - } - return 0; - } - case COMMAND_STORE_WANTED_LEVEL: - { - CollectParameters(&m_nIp, 1); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - ScriptParams[0] = pPed->m_pWanted->m_nWantedLevel; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_IS_CAR_STOPPED: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(CTheScripts::IsVehicleStopped(pVehicle)); - return 0; - } - case COMMAND_MARK_CHAR_AS_NO_LONGER_NEEDED: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - CTheScripts::CleanUpThisPed(pPed); - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); - return 0; - } - case COMMAND_MARK_CAR_AS_NO_LONGER_NEEDED: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - CTheScripts::CleanUpThisVehicle(pVehicle); - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); - return 0; - } - case COMMAND_MARK_OBJECT_AS_NO_LONGER_NEEDED: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - CTheScripts::CleanUpThisObject(pObject); - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); - return 0; - } - case COMMAND_DONT_REMOVE_CHAR: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); - return 0; - } - case COMMAND_DONT_REMOVE_CAR: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); - return 0; - } - case COMMAND_DONT_REMOVE_OBJECT: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); - return 0; - } - case COMMAND_CREATE_CHAR_AS_PASSENGER: - { - CollectParameters(&m_nIp, 4); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - switch (ScriptParams[2]) { - case MI_COP: - if (ScriptParams[1] == PEDTYPE_COP) - ScriptParams[2] = COP_STREET; - break; - case MI_SWAT: - if (ScriptParams[1] == PEDTYPE_COP) - ScriptParams[2] = COP_SWAT; - break; - case MI_FBI: - if (ScriptParams[1] == PEDTYPE_COP) - ScriptParams[2] = COP_FBI; - break; - case MI_ARMY: - if (ScriptParams[1] == PEDTYPE_COP) - ScriptParams[2] = COP_ARMY; - break; - case MI_MEDIC: - if (ScriptParams[1] == PEDTYPE_EMERGENCY) - ScriptParams[2] = PEDTYPE_EMERGENCY; - break; - case MI_FIREMAN: - if (ScriptParams[1] == PEDTYPE_FIREMAN) - ScriptParams[2] = PEDTYPE_FIREMAN; - break; - default: - break; - } - CPed* pPed; - if (ScriptParams[1] == PEDTYPE_COP) - pPed = new CCopPed((eCopType)ScriptParams[2]); - else if (ScriptParams[1] == PEDTYPE_EMERGENCY || ScriptParams[1] == PEDTYPE_FIREMAN) - pPed = new CEmergencyPed(ScriptParams[2]); - else - pPed = new CCivilianPed((ePedType)ScriptParams[1], ScriptParams[2]); - pPed->CharCreatedBy = MISSION_CHAR; - pPed->bRespondsToThreats = false; - pPed->bAllowMedicsToReviveMe = false; - pPed->SetPosition(pVehicle->GetPosition()); - pPed->SetOrientation(0.0f, 0.0f, 0.0f); - pPed->SetPedState(PED_DRIVING); - CPopulation::ms_nTotalMissionPeds++; - if (ScriptParams[3] >= 0) - pVehicle->AddPassenger(pPed, ScriptParams[3]); - else - pVehicle->AddPassenger(pPed); - pPed->m_pMyVehicle = pVehicle; - pPed->m_pMyVehicle->RegisterReference((CEntity**)&pPed->m_pMyVehicle); - pPed->bInVehicle = true; - pPed->SetPedState(PED_DRIVING); - pVehicle->SetStatus(STATUS_PHYSICS); - pPed->bUsesCollision = false; -#ifdef FIX_BUGS - AnimationId anim = pVehicle->GetDriverAnim(); -#else - AnimationId anim = pVehicle->bLowVehicle ? ANIM_CAR_LSIT : ANIM_CAR_SIT; -#endif - pPed->m_pVehicleAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, anim, 100.0f); - pPed->StopNonPartialAnims(); - pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); - CWorld::Add(pPed); - ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); - StoreParameters(&m_nIp, 1); - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); - return 0; - } - case COMMAND_SET_CHAR_OBJ_KILL_CHAR_ON_FOOT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_KILL_PLAYER_ON_FOOT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_KILL_CHAR_ANY_MEANS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_KILL_PLAYER_ANY_MEANS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FLEE_CHAR_ON_FOOT_TILL_SAFE: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FLEE_PLAYER_ON_FOOT_TILL_SAFE: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FLEE_CHAR_ON_FOOT_ALWAYS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FLEE_PLAYER_ON_FOOT_ALWAYS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_GOTO_CHAR_ON_FOOT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_GOTO_PLAYER_ON_FOOT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_LEAVE_CAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_LEAVE_CAR, pVehicle); - return 0; - } - case COMMAND_SET_CHAR_OBJ_ENTER_CAR_AS_PASSENGER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, pVehicle); - return 0; - } - case COMMAND_SET_CHAR_OBJ_ENTER_CAR_AS_DRIVER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicle); - return 0; - } - /* Not implemented. - case COMMAND_SET_CHAR_OBJ_FOLLOW_CAR_IN_CAR: - case COMMAND_SET_CHAR_OBJ_FIRE_AT_OBJECT_FROM_VEHICLE: - case COMMAND_SET_CHAR_OBJ_DESTROY_OBJECT: - */ - case COMMAND_SET_CHAR_OBJ_DESTROY_CAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_DESTROY_CAR, pVehicle); - return 0; - } - case COMMAND_SET_CHAR_OBJ_GOTO_AREA_ON_FOOT: - { - CollectParameters(&m_nIp, 5); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - float infX = *(float*)&ScriptParams[1]; - float infY = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[1]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[2]; - } - CVector pos; - pos.x = (infX + supX) / 2; - pos.y = (infY + supY) / 2; - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float radius = Max(pos.x - infX, pos.y - infY); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, pos, radius); - return 0; - } - /* Not implemented. - case COMMAND_SET_CHAR_OBJ_GOTO_AREA_IN_CAR: - case COMMAND_SET_CHAR_OBJ_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: - case COMMAND_SET_CHAR_OBJ_GUARD_ATTACK: - */ - case COMMAND_SET_CHAR_AS_LEADER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->SetObjective(OBJECTIVE_SET_LEADER, pTarget); - return 0; - } - case COMMAND_SET_PLAYER_AS_LEADER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; - pPed->SetObjective(OBJECTIVE_SET_LEADER, pTarget); - return 0; - } - case COMMAND_LEAVE_GROUP: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->ClearLeader(); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FOLLOW_ROUTE: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FOLLOW_ROUTE, ScriptParams[1], ScriptParams[2]); - return 0; - } - case COMMAND_ADD_ROUTE_POINT: - { - CollectParameters(&m_nIp, 4); - CRouteNode::AddRoutePoint(ScriptParams[0], *(CVector*)&ScriptParams[1]); - return 0; - } - case COMMAND_PRINT_WITH_NUMBER_BIG: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 3); - CMessages::AddBigMessageWithNumber(text, ScriptParams[1], ScriptParams[2] - 1, ScriptParams[0], -1, -1, -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_NUMBER: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 3); - CMessages::AddMessageWithNumber(text, ScriptParams[1], ScriptParams[2], ScriptParams[0], -1, -1, -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_NUMBER_NOW: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 3); - CMessages::AddMessageJumpQWithNumber(text, ScriptParams[1], ScriptParams[2], ScriptParams[0], -1, -1, -1, -1, -1); - return 0; - } - /* Not implemented. - case COMMAND_PRINT_WITH_NUMBER_SOON: - */ - case COMMAND_SWITCH_ROADS_ON: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX){ - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY){ - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ){ - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ThePaths.SwitchRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, false); - return 0; - } - case COMMAND_SWITCH_ROADS_OFF: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ThePaths.SwitchRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, true); - return 0; - } - case COMMAND_GET_NUMBER_OF_PASSENGERS: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - ScriptParams[0] = pVehicle->m_nNumPassengers; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_MAXIMUM_NUMBER_OF_PASSENGERS: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - ScriptParams[0] = pVehicle->m_nNumMaxPassengers; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CAR_DENSITY_MULTIPLIER: - { - CollectParameters(&m_nIp, 1); - CCarCtrl::CarDensityMultiplier = *(float*)&ScriptParams[0]; - return 0; - } - case COMMAND_SET_CAR_HEAVY: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bIsHeavy = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_CLEAR_CHAR_THREAT_SEARCH: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->m_fearFlags = 0; - return 0; - } - case COMMAND_ACTIVATE_CRANE: - { - CollectParameters(&m_nIp, 10); - float infX = *(float*)&ScriptParams[2]; - float infY = *(float*)&ScriptParams[3]; - float supX = *(float*)&ScriptParams[4]; - float supY = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[4]; - supX = *(float*)&ScriptParams[2]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[5]; - supY = *(float*)&ScriptParams[3]; - } - CCranes::ActivateCrane(infX, supX, infY, supY, - *(float*)&ScriptParams[6], *(float*)&ScriptParams[7], *(float*)&ScriptParams[8], - DEGTORAD(*(float*)&ScriptParams[9]), false, false, - *(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); - return 0; - } - case COMMAND_DEACTIVATE_CRANE: - { - CollectParameters(&m_nIp, 2); - CCranes::DeActivateCrane(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); - return 0; - } - case COMMAND_SET_MAX_WANTED_LEVEL: - { - CollectParameters(&m_nIp, 1); - CWanted::SetMaximumWantedLevel(ScriptParams[0]); - return 0; - } - /* Debug commands? - case COMMAND_SAVE_VAR_INT: - case COMMAND_SAVE_VAR_FLOAT: - */ - case COMMAND_IS_CAR_IN_AIR_PROPER: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->m_nCollisionRecords == 0); - return 0; - } - default: - script_assert(0); - } - return -1; -} - -int8 CRunningScript::ProcessCommands500To599(int32 command) -{ - switch (command) { - case COMMAND_IS_CAR_UPSIDEDOWN: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->GetUp().z <= -0.97f); - return 0; - } - case COMMAND_GET_PLAYER_CHAR: - { - CollectParameters(&m_nIp, 1); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_CANCEL_OVERRIDE_RESTART: - CRestart::CancelOverrideRestart(); - return 0; - case COMMAND_SET_POLICE_IGNORE_PLAYER: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - if (ScriptParams[1]) { - pPed->m_pWanted->m_bIgnoredByCops = true; - CWorld::StopAllLawEnforcersInTheirTracks(); - } - else { - pPed->m_pWanted->m_bIgnoredByCops = false; - } - return 0; - } - case COMMAND_ADD_PAGER_MESSAGE_WITH_NUMBER: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 4); - CUserDisplay::Pager.AddMessageWithNumber(text, ScriptParams[0], -1, -1, -1, -1, -1, - ScriptParams[1], ScriptParams[2], ScriptParams[3]); - return 0; - } - case COMMAND_START_KILL_FRENZY: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 8); - CDarkel::StartFrenzy((eWeaponType)ScriptParams[0], ScriptParams[1], ScriptParams[2], - ScriptParams[3], text, ScriptParams[4], ScriptParams[5], - ScriptParams[6], ScriptParams[7] != 0, false); - return 0; - } - case COMMAND_READ_KILL_FRENZY_STATUS: - { - ScriptParams[0] = CDarkel::ReadStatus(); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SQRT: - { - CollectParameters(&m_nIp, 1); - *(float*)&ScriptParams[0] = Sqrt(*(float*)&ScriptParams[0]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_2D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_2D: - case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_2D: - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D: - case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D: - LocatePlayerCarCommand(command, &m_nIp); - return 0; - case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_2D: - case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_2D: - case COMMAND_LOCATE_CHAR_IN_CAR_CAR_2D: - case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D: - case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D: - case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D: - LocateCharCarCommand(command, &m_nIp); - return 0; - case COMMAND_GENERATE_RANDOM_FLOAT_IN_RANGE: - CollectParameters(&m_nIp, 2); - *(float*)&ScriptParams[0] = CGeneral::GetRandomNumberInRange(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_GENERATE_RANDOM_INT_IN_RANGE: - CollectParameters(&m_nIp, 2); - ScriptParams[0] = CGeneral::GetRandomNumberInRange(ScriptParams[0], ScriptParams[1]); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_LOCK_CAR_DOORS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->m_nDoorLock = (eCarLock)ScriptParams[1]; - return 0; - } - case COMMAND_EXPLODE_CAR: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->BlowUpCar(nil); - return 0; - } - case COMMAND_ADD_EXPLOSION: - CollectParameters(&m_nIp, 4); - CExplosion::AddExplosion(nil, nil, (eExplosionType)ScriptParams[3], *(CVector*)&ScriptParams[0], 0); - return 0; - - case COMMAND_IS_CAR_UPRIGHT: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->GetUp().z >= 0.0f); - return 0; - } - case COMMAND_TURN_CHAR_TO_FACE_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); - CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; - CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); - CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); - float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; - if (angle > TWOPI) - angle -= TWOPI; - if (!pVehicle) { - pSourcePed->m_fRotationCur = angle; - pSourcePed->m_fRotationDest = angle; - pSourcePed->SetHeading(angle); - } - return 0; - } - case COMMAND_TURN_CHAR_TO_FACE_PLAYER: - { - CollectParameters(&m_nIp, 2); - CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - CPed* pTargetPed = CWorld::Players[ScriptParams[1]].m_pPed; - CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; - CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); - CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); - float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; - if (angle > TWOPI) - angle -= TWOPI; - if (!pVehicle) { - pSourcePed->m_fRotationCur = angle; - pSourcePed->m_fRotationDest = angle; - pSourcePed->SetHeading(angle); - } - return 0; - } - case COMMAND_TURN_PLAYER_TO_FACE_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; - CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); - CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; - CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); - CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); - float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; - if (angle > TWOPI) - angle -= TWOPI; - if (!pVehicle) { - pSourcePed->m_fRotationCur = angle; - pSourcePed->m_fRotationDest = angle; - pSourcePed->SetHeading(angle); - } - return 0; - } - case COMMAND_SET_CHAR_OBJ_GOTO_COORD_ON_FOOT: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVector target; - target.x = *(float*)&ScriptParams[1]; - target.y = *(float*)&ScriptParams[2]; - target.z = CWorld::FindGroundZForCoord(target.x, target.y); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, target); - return 0; - } - /* Not implemented*/ - //case COMMAND_SET_CHAR_OBJ_GOTO_COORD_IN_CAR: - case COMMAND_CREATE_PICKUP: - { - CollectParameters(&m_nIp, 5); - int16 model = ScriptParams[0]; - if (model < 0) - model = CTheScripts::UsedObjectArray[-model].index; - CVector pos = *(CVector*)&ScriptParams[2]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CPickups::GenerateNewOne(pos, model, ScriptParams[1], 0); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_HAS_PICKUP_BEEN_COLLECTED: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CPickups::IsPickUpPickedUp(ScriptParams[0]) != 0); - return 0; - case COMMAND_REMOVE_PICKUP: - CollectParameters(&m_nIp, 1); - CPickups::RemovePickUp(ScriptParams[0]); - return 0; - case COMMAND_SET_TAXI_LIGHTS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); - ((CAutomobile*)pVehicle)->SetTaxiLight(ScriptParams[1] != 0); - return 0; - } - case COMMAND_PRINT_BIG_Q: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 2); - CMessages::AddBigMessageQ(text, ScriptParams[0], ScriptParams[1] - 1); - return 0; - } - case COMMAND_PRINT_WITH_NUMBER_BIG_Q: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 3); - CMessages::AddBigMessageWithNumberQ(text, ScriptParams[1], ScriptParams[2] - 1, - ScriptParams[0], -1, -1, -1, -1, -1); - return 0; - } - case COMMAND_SET_GARAGE: - { - CollectParameters(&m_nIp, 7); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], 0); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_GARAGE_WITH_CAR_MODEL: - { - CollectParameters(&m_nIp, 8); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], ScriptParams[7]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_TARGET_CAR_FOR_MISSION_GARAGE: - { - CollectParameters(&m_nIp, 2); - CVehicle* pTarget; - if (ScriptParams[1] >= 0) { - pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - } - else { - pTarget = nil; - } - CGarages::SetTargetCarForMissonGarage(ScriptParams[0], pTarget); - return 0; - } - case COMMAND_IS_CAR_IN_MISSION_GARAGE: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CGarages::HasCarBeenDroppedOffYet(ScriptParams[0])); - return 0; - case COMMAND_SET_FREE_BOMBS: - CollectParameters(&m_nIp, 1); - CGarages::SetFreeBombs(ScriptParams[0] != 0); - return 0; -#ifdef GTA_PS2 - case COMMAND_SET_POWERPOINT: - { - CollectParameters(&m_nIp, 7); - float f1 = *(float*)&ScriptParams[0]; - float f2 = *(float*)&ScriptParams[1]; - float f3 = *(float*)&ScriptParams[2]; - float f4 = *(float*)&ScriptParams[3]; - float f5 = *(float*)&ScriptParams[4]; - float f6 = *(float*)&ScriptParams[5]; - float temp; - - if (f1 > f4) { - temp = f1; - f1 = f4; - f4 = temp; - } - - if (f2 > f5) { - temp = f2; - f2 = f5; - f5 = temp; - } - - if (f3 > f6) { - temp = f3; - f3 = f6; - f6 = temp; - } - - CPowerPoints::GenerateNewOne(f1, f2, f3, f4, f5, f6, *(uint8*)&ScriptParams[6]); - - return 0; - } -#endif // GTA_PS2 - case COMMAND_SET_ALL_TAXI_LIGHTS: - CollectParameters(&m_nIp, 1); - CAutomobile::SetAllTaxiLights(ScriptParams[0] != 0); - return 0; - case COMMAND_IS_CAR_ARMED_WITH_ANY_BOMB: - { - CollectParameters(&m_nIp, 1); - CAutomobile* pCar = (CAutomobile*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pCar); - script_assert(pCar->m_vehType == VEHICLE_TYPE_CAR); - UpdateCompareFlag(pCar->m_bombType != 0); //TODO: enum - return 0; - } - case COMMAND_APPLY_BRAKES_TO_PLAYERS_CAR: - CollectParameters(&m_nIp, 2); - CPad::GetPad(ScriptParams[0])->bApplyBrakes = (ScriptParams[1] != 0); - return 0; - case COMMAND_SET_PLAYER_HEALTH: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - pPed->m_fHealth = ScriptParams[1]; - return 0; - } - case COMMAND_SET_CHAR_HEALTH: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - if (ScriptParams[1]) { - pPed->m_fHealth = ScriptParams[1]; - } - else if (pPed->bInVehicle) { - pPed->SetDead(); - if (!pPed->IsPlayer()) - pPed->FlagToDestroyWhenNextProcessed(); - } - else { - pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - } - return 0; - } - case COMMAND_SET_CAR_HEALTH: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->m_fHealth = ScriptParams[1]; - return 0; - } - case COMMAND_GET_PLAYER_HEALTH: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - ScriptParams[0] = pPed->m_fHealth; // correct cast float to int - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_CHAR_HEALTH: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - ScriptParams[0] = pPed->m_fHealth; // correct cast float to int - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_CAR_HEALTH: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - ScriptParams[0] = pVehicle->m_fHealth; // correct cast float to int - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_IS_CAR_ARMED_WITH_BOMB: - { - CollectParameters(&m_nIp, 2); - CAutomobile* pCar = (CAutomobile*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pCar); - script_assert(pCar->m_vehType == VEHICLE_TYPE_CAR); - UpdateCompareFlag(pCar->m_bombType == ScriptParams[1]); //TODO: enum - return 0; - } - case COMMAND_CHANGE_CAR_COLOUR: - { - CollectParameters(&m_nIp, 3); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - if (ScriptParams[1] >= 256 || ScriptParams[2] >= 256) - debug("CHANGE_CAR_COLOUR - Colours must be less than %d", 256); - pVehicle->m_currentColour1 = ScriptParams[1]; - pVehicle->m_currentColour2 = ScriptParams[2]; - return 0; - } - case COMMAND_SWITCH_PED_ROADS_ON: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ThePaths.SwitchPedRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, false); - return 0; - } - case COMMAND_SWITCH_PED_ROADS_OFF: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ThePaths.SwitchPedRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, true); - return 0; - } - case COMMAND_CHAR_LOOK_AT_CHAR_ALWAYS: - { - CollectParameters(&m_nIp, 2); - CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pSourcePed); - CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pTargetPed); - pSourcePed->SetLookFlag(pTargetPed, true); - pSourcePed->SetLookTimer(60000); - return 0; - } - case COMMAND_CHAR_LOOK_AT_PLAYER_ALWAYS: - { - CollectParameters(&m_nIp, 2); - CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pSourcePed); - CPed* pTargetPed = CWorld::Players[ScriptParams[1]].m_pPed; - script_assert(pTargetPed); - pSourcePed->SetLookFlag(pTargetPed, true); - pSourcePed->SetLookTimer(60000); - return 0; - } - case COMMAND_PLAYER_LOOK_AT_CHAR_ALWAYS: - { - CollectParameters(&m_nIp, 2); - CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pSourcePed); - CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pTargetPed); - pSourcePed->SetLookFlag(pTargetPed, true); - pSourcePed->SetLookTimer(60000); - return 0; - } - case COMMAND_STOP_CHAR_LOOKING: - { - CollectParameters(&m_nIp, 1); - CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pSourcePed); - pSourcePed->ClearLookFlag(); - pSourcePed->bKeepTryingToLook = false; - if (pSourcePed->GetPedState() == PED_LOOK_HEADING || pSourcePed->GetPedState() == PED_LOOK_ENTITY) - pSourcePed->RestorePreviousState(); - return 0; - } - case COMMAND_STOP_PLAYER_LOOKING: - { - CollectParameters(&m_nIp, 1); - CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pSourcePed); - pSourcePed->ClearLookFlag(); - pSourcePed->bKeepTryingToLook = false; - if (pSourcePed->GetPedState() == PED_LOOK_HEADING || pSourcePed->GetPedState() == PED_LOOK_ENTITY) - pSourcePed->RestorePreviousState(); - return 0; - } - case COMMAND_SWITCH_HELICOPTER: - CollectParameters(&m_nIp, 1); - CHeli::ActivateHeli(ScriptParams[0] != 0); - return 0; - - //case COMMAND_SET_GANG_ATTITUDE: - //case COMMAND_SET_GANG_GANG_ATTITUDE: - //case COMMAND_SET_GANG_PLAYER_ATTITUDE: - //case COMMAND_SET_GANG_PED_MODELS: - case COMMAND_SET_GANG_CAR_MODEL: - CollectParameters(&m_nIp, 2); - CGangs::SetGangVehicleModel(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_SET_GANG_WEAPONS: - CollectParameters(&m_nIp, 3); - CGangs::SetGangWeapons(ScriptParams[0], (eWeaponType)ScriptParams[1], (eWeaponType)ScriptParams[2]); - return 0; - case COMMAND_SET_CHAR_OBJ_RUN_TO_AREA: - { - CollectParameters(&m_nIp, 5); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - float infX = *(float*)&ScriptParams[1]; - float infY = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[1]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[2]; - } - CVector pos; - pos.x = (infX + supX) / 2; - pos.y = (infY + supY) / 2; - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float radius = Max(pos.x - infX, pos.y - infY); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_RUN_TO_AREA, pos, radius); - return 0; - } - case COMMAND_SET_CHAR_OBJ_RUN_TO_COORD: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVector pos; - pos.x = *(float*)&ScriptParams[1]; - pos.y = *(float*)&ScriptParams[2]; - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_RUN_TO_AREA, pos); - return 0; - } - case COMMAND_IS_PLAYER_TOUCHING_OBJECT_ON_FOOT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); - bool isTouching = false; - if (pPed->bInVehicle) - isTouching = false; - else if (pPed->GetHasCollidedWith(pObject)) - isTouching = true; - UpdateCompareFlag(isTouching); - return 0; - } - case COMMAND_IS_CHAR_TOUCHING_OBJECT_ON_FOOT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); - bool isTouching = false; - if (pPed->InVehicle()) - isTouching = false; - else if (pPed->GetHasCollidedWith(pObject)) - isTouching = true; - UpdateCompareFlag(isTouching); - return 0; - } - case COMMAND_LOAD_SPECIAL_CHARACTER: - { - CollectParameters(&m_nIp, 1); - char name[16]; - strncpy(name, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - name[i] = tolower(name[i]); - CStreaming::RequestSpecialChar(ScriptParams[0] - 1, name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); - m_nIp += KEY_LENGTH_IN_SCRIPT; - return 0; - } - case COMMAND_HAS_SPECIAL_CHARACTER_LOADED: - { - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CStreaming::HasSpecialCharLoaded(ScriptParams[0] - 1)); - return 0; - } - case COMMAND_FLASH_CAR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bHasBlip = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_FLASH_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bHasBlip = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_FLASH_OBJECT: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - pObject->bHasBlip = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_IS_PLAYER_IN_REMOTE_MODE: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CWorld::Players[ScriptParams[0]].IsPlayerInRemoteMode()); - return 0; - case COMMAND_ARM_CAR_WITH_BOMB: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); - ((CAutomobile*)pVehicle)->m_bombType = ScriptParams[1]; - ((CAutomobile*)pVehicle)->m_pBombRigger = FindPlayerPed(); - return 0; - } - case COMMAND_SET_CHAR_PERSONALITY: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->SetPedStats((ePedStats)ScriptParams[1]); - return 0; - } - case COMMAND_SET_CUTSCENE_OFFSET: - CollectParameters(&m_nIp, 3); - CCutsceneMgr::SetCutsceneOffset(*(CVector*)&ScriptParams[0]); - return 0; - case COMMAND_SET_ANIM_GROUP_FOR_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->m_animGroup = (AssocGroupId)ScriptParams[1]; - return 0; - } - case COMMAND_SET_ANIM_GROUP_FOR_PLAYER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - pPed->m_animGroup = (AssocGroupId)ScriptParams[1]; - return 0; - } - case COMMAND_REQUEST_MODEL: - { - CollectParameters(&m_nIp, 1); - int model = ScriptParams[0]; - if (model < 0) - model = CTheScripts::UsedObjectArray[-model].index; - CStreaming::RequestModel(model, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_NOFADE | STREAMFLAGS_SCRIPTOWNED); - return 0; - } - case COMMAND_HAS_MODEL_LOADED: - { - CollectParameters(&m_nIp, 1); - int model = ScriptParams[0]; - if (model < 0) - model = CTheScripts::UsedObjectArray[-model].index; - UpdateCompareFlag(CStreaming::HasModelLoaded(model)); - return 0; - } - case COMMAND_MARK_MODEL_AS_NO_LONGER_NEEDED: - { - CollectParameters(&m_nIp, 1); - int model = ScriptParams[0]; - if (model < 0) - model = CTheScripts::UsedObjectArray[-model].index; - CStreaming::SetMissionDoesntRequireModel(model); - return 0; - } - case COMMAND_GRAB_PHONE: - { - CollectParameters(&m_nIp, 2); - ScriptParams[0] = gPhoneInfo.GrabPhone(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_REPEATED_PHONE_MESSAGE: - { - CollectParameters(&m_nIp, 1); - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text, nil, nil, nil, nil, nil); - return 0; - } - case COMMAND_SET_PHONE_MESSAGE: - { - CollectParameters(&m_nIp, 1); - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text, nil, nil, nil, nil, nil); - return 0; - } - case COMMAND_HAS_PHONE_DISPLAYED_MESSAGE: - { - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(gPhoneInfo.HasMessageBeenDisplayed(ScriptParams[0])); - return 0; - } - case COMMAND_TURN_PHONE_OFF: - { - CollectParameters(&m_nIp, 1); - gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], nil, nil, nil, nil, nil, nil); - return 0; - } - case COMMAND_DRAW_CORONA: - { - CollectParameters(&m_nIp, 9); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CCoronas::RegisterCorona((uintptr)this + m_nIp, ScriptParams[6], ScriptParams[7], ScriptParams[8], - 255, pos, *(float*)&ScriptParams[3], 150.0f, ScriptParams[4], ScriptParams[5], 1, 0, 0, 0.0f); - return 0; - } - case COMMAND_DRAW_LIGHT: - { - CollectParameters(&m_nIp, 6); - CVector pos = *(CVector*)&ScriptParams[0]; - CVector unused(0.0f, 0.0f, 0.0f); - CPointLights::AddLight(0, *(CVector*)&ScriptParams[0], CVector(0.0f, 0.0f, 0.0f), 12.0f, - ScriptParams[3] / 255.0f, ScriptParams[4] / 255.0f, ScriptParams[5] / 255.0f, 0, true); - return 0; - } - case COMMAND_STORE_WEATHER: - CWeather::StoreWeatherState(); - return 0; - case COMMAND_RESTORE_WEATHER: - CWeather::RestoreWeatherState(); - return 0; - case COMMAND_STORE_CLOCK: - CClock::StoreClock(); - return 0; - case COMMAND_RESTORE_CLOCK: - CClock::RestoreClock(); - return 0; - case COMMAND_RESTART_CRITICAL_MISSION: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CRestart::OverrideNextRestart(pos, *(float*)&ScriptParams[3]); - if (CWorld::Players[CWorld::PlayerInFocus].m_WBState != WBSTATE_PLAYING) - printf("RESTART_CRITICAL_MISSION - Player state is not PLAYING\n"); - CWorld::Players[CWorld::PlayerInFocus].PlayerFailedCriticalMission(); - return 0; - } - case COMMAND_IS_PLAYER_PLAYING: - { - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_PLAYING); - return 0; - } - //case COMMAND_SET_COLL_OBJ_NO_OBJ: - default: - script_assert(0); - } - return -1; -} - -int8 CRunningScript::ProcessCommands600To699(int32 command) -{ - switch (command){ - /* Collective commands are not implemented until LCS. - case COMMAND_SET_COLL_OBJ_WAIT_ON_FOOT: - case COMMAND_SET_COLL_OBJ_FLEE_ON_FOOT_TILL_SAFE: - case COMMAND_SET_COLL_OBJ_GUARD_SPOT: - case COMMAND_SET_COLL_OBJ_GUARD_AREA: - case COMMAND_SET_COLL_OBJ_WAIT_IN_CAR: - case COMMAND_SET_COLL_OBJ_KILL_CHAR_ON_FOOT: - case COMMAND_SET_COLL_OBJ_KILL_PLAYER_ON_FOOT: - case COMMAND_SET_COLL_OBJ_KILL_CHAR_ANY_MEANS: - case COMMAND_SET_COLL_OBJ_KILL_PLAYER_ANY_MEANS: - case COMMAND_SET_COLL_OBJ_FLEE_CHAR_ON_FOOT_TILL_SAFE: - case COMMAND_SET_COLL_OBJ_FLEE_PLAYER_ON_FOOT_TILL_SAFE: - case COMMAND_SET_COLL_OBJ_FLEE_CHAR_ON_FOOT_ALWAYS: - case COMMAND_SET_COLL_OBJ_FLEE_PLAYER_ON_FOOT_ALWAYS: - case COMMAND_SET_COLL_OBJ_GOTO_CHAR_ON_FOOT: - case COMMAND_SET_COLL_OBJ_GOTO_PLAYER_ON_FOOT: - case COMMAND_SET_COLL_OBJ_LEAVE_CAR: - case COMMAND_SET_COLL_OBJ_ENTER_CAR_AS_PASSENGER: - case COMMAND_SET_COLL_OBJ_ENTER_CAR_AS_DRIVER: - case COMMAND_SET_COLL_OBJ_FOLLOW_CAR_IN_CAR: - case COMMAND_SET_COLL_OBJ_FIRE_AT_OBJECT_FROM_VEHICLE: - case COMMAND_SET_COLL_OBJ_DESTROY_OBJECT: - case COMMAND_SET_COLL_OBJ_DESTROY_CAR: - case COMMAND_SET_COLL_OBJ_GOTO_AREA_ON_FOOT: - case COMMAND_SET_COLL_OBJ_GOTO_AREA_IN_CAR: - case COMMAND_SET_COLL_OBJ_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: - case COMMAND_SET_COLL_OBJ_GUARD_ATTACK: - case COMMAND_SET_COLL_OBJ_FOLLOW_ROUTE: - case COMMAND_SET_COLL_OBJ_GOTO_COORD_ON_FOOT: - case COMMAND_SET_COLL_OBJ_GOTO_COORD_IN_CAR: - case COMMAND_SET_COLL_OBJ_RUN_TO_AREA: - case COMMAND_SET_COLL_OBJ_RUN_TO_COORD: - case COMMAND_ADD_PEDS_IN_AREA_TO_COLL: - case COMMAND_ADD_PEDS_IN_VEHICLE_TO_COLL: - case COMMAND_CLEAR_COLL: - case COMMAND_IS_COLL_IN_CARS: - case COMMAND_LOCATE_COLL_ANY_MEANS_2D: - case COMMAND_LOCATE_COLL_ON_FOOT_2D: - case COMMAND_LOCATE_COLL_IN_CAR_2D: - case COMMAND_LOCATE_STOPPED_COLL_ANY_MEANS_2D: - case COMMAND_LOCATE_STOPPED_COLL_ON_FOOT_2D: - case COMMAND_LOCATE_STOPPED_COLL_IN_CAR_2D: - case COMMAND_LOCATE_COLL_ANY_MEANS_CHAR_2D: - case COMMAND_LOCATE_COLL_ON_FOOT_CHAR_2D: - case COMMAND_LOCATE_COLL_IN_CAR_CHAR_2D: - case COMMAND_LOCATE_COLL_ANY_MEANS_CAR_2D: - case COMMAND_LOCATE_COLL_ON_FOOT_CAR_2D: - case COMMAND_LOCATE_COLL_IN_CAR_CAR_2D: - case COMMAND_LOCATE_COLL_ANY_MEANS_PLAYER_2D: - case COMMAND_LOCATE_COLL_ON_FOOT_PLAYER_2D: - case COMMAND_LOCATE_COLL_IN_CAR_PLAYER_2D: - case COMMAND_IS_COLL_IN_AREA_2D: - case COMMAND_IS_COLL_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_COLL_IN_AREA_IN_CAR_2D: - case COMMAND_IS_COLL_STOPPED_IN_AREA_2D: - case COMMAND_IS_COLL_STOPPED_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_COLL_STOPPED_IN_AREA_IN_CAR_2D: - case COMMAND_GET_NUMBER_OF_PEDS_IN_COLL: - */ - case COMMAND_SET_CHAR_HEED_THREATS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bRespondsToThreats = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_PLAYER_HEED_THREATS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - pPed->bRespondsToThreats = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_GET_CONTROLLER_MODE: -#if defined(GTA_PC) && !defined(DETECT_PAD_INPUT_SWITCH) - ScriptParams[0] = 0; -#else - ScriptParams[0] = CPad::IsAffectedByController ? CPad::GetPad(0)->Mode : 0; -#endif - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_SET_CAN_RESPRAY_CAR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); - ((CAutomobile*)pVehicle)->bFixedColour = (ScriptParams[1] == 0); - return 0; - } - case COMMAND_IS_TAXI: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - int mi = pVehicle->GetModelIndex(); - UpdateCompareFlag(mi == MI_TAXI || mi == MI_CABBIE || mi == MI_BORGNINE); - return 0; - } - case COMMAND_UNLOAD_SPECIAL_CHARACTER: - CollectParameters(&m_nIp, 1); - CStreaming::SetMissionDoesntRequireSpecialChar(ScriptParams[0] - 1); - return 0; - case COMMAND_RESET_NUM_OF_MODELS_KILLED_BY_PLAYER: - CDarkel::ResetModelsKilledByPlayer(); - return 0; - case COMMAND_GET_NUM_OF_MODELS_KILLED_BY_PLAYER: - CollectParameters(&m_nIp, 1); - ScriptParams[0] = CDarkel::QueryModelsKilledByPlayer(ScriptParams[0]); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_ACTIVATE_GARAGE: - CollectParameters(&m_nIp, 1); - CGarages::ActivateGarage(ScriptParams[0]); - return 0; - case COMMAND_SWITCH_TAXI_TIMER: - { - CollectParameters(&m_nIp, 1); - if (ScriptParams[0] != 0){ - CWorld::Players[CWorld::PlayerInFocus].m_nUnusedTaxiTimer = CTimer::GetTimeInMilliseconds(); - CWorld::Players[CWorld::PlayerInFocus].m_bUnusedTaxiThing = true; - }else{ - CWorld::Players[CWorld::PlayerInFocus].m_bUnusedTaxiThing = false; - } - return 0; - } - case COMMAND_CREATE_OBJECT_NO_OFFSET: - { - CollectParameters(&m_nIp, 4); - int mi = ScriptParams[0] >= 0 ? ScriptParams[0] : CTheScripts::UsedObjectArray[-ScriptParams[0]].index; - CObject* pObj = new CObject(mi, false); -; pObj->ObjectCreatedBy = MISSION_OBJECT; - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - pObj->SetPosition(pos); - pObj->SetOrientation(0.0f, 0.0f, 0.0f); - pObj->GetMatrix().UpdateRW(); - pObj->UpdateRwFrame(); - CTheScripts::ClearSpaceForMissionEntity(pos, pObj); - CWorld::Add(pObj); - ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObj); - StoreParameters(&m_nIp, 1); - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_OBJECT); - return 0; - } - case COMMAND_IS_BOAT: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); - return 0; - } - case COMMAND_SET_CHAR_OBJ_GOTO_AREA_ANY_MEANS: - { - CollectParameters(&m_nIp, 5); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - float infX = *(float*)&ScriptParams[1]; - float infY = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[1]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[2]; - } - CVector pos; - pos.x = (infX + supX) / 2; - pos.y = (infY + supY) / 2; - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float radius = Max(pos.x - infX, pos.y - infY); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS, pos, radius); - return 0; - } - //case COMMAND_SET_COLL_OBJ_GOTO_AREA_ANY_MEANS: - case COMMAND_IS_PLAYER_STOPPED: - { - CollectParameters(&m_nIp, 1); - CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; - UpdateCompareFlag(CTheScripts::IsPlayerStopped(pPlayer)); - return 0; - } - case COMMAND_IS_CHAR_STOPPED: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - UpdateCompareFlag(CTheScripts::IsPedStopped(pPed)); - return 0; - } - case COMMAND_MESSAGE_WAIT: - CollectParameters(&m_nIp, 2); - m_nWakeTime = CTimer::GetTimeInMilliseconds() + ScriptParams[0]; - if (ScriptParams[1] != 0) - m_bSkipWakeTime = true; - return 1; - case COMMAND_ADD_PARTICLE_EFFECT: - { - CollectParameters(&m_nIp, 5); - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CParticleObject::AddObject(ScriptParams[0], pos, ScriptParams[4] != 0); - return 0; - } - case COMMAND_SWITCH_WIDESCREEN: - CollectParameters(&m_nIp, 1); - if (ScriptParams[0] != 0) - TheCamera.SetWideScreenOn(); - else - TheCamera.SetWideScreenOff(); - return 0; - case COMMAND_ADD_SPRITE_BLIP_FOR_CAR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int id = CRadar::SetEntityBlip(BLIP_CAR, ScriptParams[0], 0, BLIP_DISPLAY_BOTH); - CRadar::SetBlipSprite(id, ScriptParams[1]); - ScriptParams[0] = id; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_SPRITE_BLIP_FOR_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int id = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], 1, BLIP_DISPLAY_BOTH); - CRadar::SetBlipSprite(id, ScriptParams[1]); - ScriptParams[0] = id; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_SPRITE_BLIP_FOR_OBJECT: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int id = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], 6, BLIP_DISPLAY_BOTH); - CRadar::SetBlipSprite(id, ScriptParams[1]); - ScriptParams[0] = id; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_SPRITE_BLIP_FOR_CONTACT_POINT: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int id = CRadar::SetCoordBlip(BLIP_CONTACT_POINT, pos, 2, BLIP_DISPLAY_BOTH); - CRadar::SetBlipSprite(id, ScriptParams[3]); - ScriptParams[0] = id; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_SPRITE_BLIP_FOR_COORD: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int id = CRadar::SetCoordBlip(BLIP_COORD, pos, 5, BLIP_DISPLAY_BOTH); - CRadar::SetBlipSprite(id, ScriptParams[3]); - ScriptParams[0] = id; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CHAR_ONLY_DAMAGED_BY_PLAYER: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bOnlyDamagedByPlayer = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_CAR_ONLY_DAMAGED_BY_PLAYER: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bOnlyDamagedByPlayer = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_CHAR_PROOFS: - { - CollectParameters(&m_nIp, 6); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bBulletProof = (ScriptParams[1] != 0); - pPed->bFireProof = (ScriptParams[2] != 0); - pPed->bExplosionProof = (ScriptParams[3] != 0); - pPed->bCollisionProof = (ScriptParams[4] != 0); - pPed->bMeleeProof = (ScriptParams[5] != 0); - return 0; - } - case COMMAND_SET_CAR_PROOFS: - { - CollectParameters(&m_nIp, 6); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bBulletProof = (ScriptParams[1] != 0); - pVehicle->bFireProof = (ScriptParams[2] != 0); - pVehicle->bExplosionProof = (ScriptParams[3] != 0); - pVehicle->bCollisionProof = (ScriptParams[4] != 0); - pVehicle->bMeleeProof = (ScriptParams[5] != 0); - return 0; - } - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_2D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_3D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: - PlayerInAngledAreaCheckCommand(command, &m_nIp); - return 0; - case COMMAND_DEACTIVATE_GARAGE: - CollectParameters(&m_nIp, 1); - CGarages::DeActivateGarage(ScriptParams[0]); - return 0; - case COMMAND_GET_NUMBER_OF_CARS_COLLECTED_BY_GARAGE: - CollectParameters(&m_nIp, 1); - ScriptParams[0] = CGarages::QueryCarsCollected(ScriptParams[0]); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_HAS_CAR_BEEN_TAKEN_TO_GARAGE: - CollectParameters(&m_nIp, 2); - UpdateCompareFlag(CGarages::HasThisCarBeenCollected(ScriptParams[0], ScriptParams[1] - 1)); - return 0; - default: - script_assert(0); - } - return -1; -} - -int8 CRunningScript::ProcessCommands700To799(int32 command) -{ - switch (command){ - case COMMAND_SET_SWAT_REQUIRED: - CollectParameters(&m_nIp, 1); - FindPlayerPed()->m_pWanted->m_bSwatRequired = (ScriptParams[0] != 0); - return 0; - case COMMAND_SET_FBI_REQUIRED: - CollectParameters(&m_nIp, 1); - FindPlayerPed()->m_pWanted->m_bFbiRequired = (ScriptParams[0] != 0); - return 0; - case COMMAND_SET_ARMY_REQUIRED: - CollectParameters(&m_nIp, 1); - FindPlayerPed()->m_pWanted->m_bArmyRequired = (ScriptParams[0] != 0); - return 0; - case COMMAND_IS_CAR_IN_WATER: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - UpdateCompareFlag(pVehicle && pVehicle->bIsInWater); - return 0; - } - case COMMAND_GET_CLOSEST_CHAR_NODE: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CPathNode* pNode = &ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, 1, 999999.9f)]; - *(CVector*)&ScriptParams[0] = pNode->GetPosition(); - StoreParameters(&m_nIp, 3); - return 0; - } - case COMMAND_GET_CLOSEST_CAR_NODE: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CPathNode* pNode = &ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f)]; - *(CVector*)&ScriptParams[0] = pNode->GetPosition(); - StoreParameters(&m_nIp, 3); - return 0; - } - case COMMAND_CAR_GOTO_COORDINATES_ACCURATE: - { - CollectParameters(&m_nIp, 4); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - pos.z += pVehicle->GetDistanceFromCentreOfMassToBaseOfModel(); - if (CCarCtrl::JoinCarWithRoadSystemGotoCoors(pVehicle, pos, false)) - pVehicle->AutoPilot.m_nCarMission = MISSION_GOTO_COORDS_STRAIGHT_ACCURATE; - else - pVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_ACCURATE; - pVehicle->SetStatus(STATUS_PHYSICS); - pVehicle->bEngineOn = true; - pVehicle->AutoPilot.m_nCruiseSpeed = Max(6, pVehicle->AutoPilot.m_nCruiseSpeed); - pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds(); - return 0; - } - case COMMAND_START_PACMAN_RACE: - CollectParameters(&m_nIp, 1); - CPacManPickups::StartPacManRace(ScriptParams[0]); - return 0; - case COMMAND_START_PACMAN_RECORD: - CPacManPickups::StartPacManRecord(); - return 0; - case COMMAND_GET_NUMBER_OF_POWER_PILLS_EATEN: - ScriptParams[0] = CPacManPickups::QueryPowerPillsEatenInRace(); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_CLEAR_PACMAN: - CPacManPickups::CleanUpPacManStuff(); - return 0; - case COMMAND_START_PACMAN_SCRAMBLE: - { - CollectParameters(&m_nIp, 5); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CPacManPickups::StartPacManScramble(pos, *(float*)&ScriptParams[3], ScriptParams[4]); - return 0; - } - case COMMAND_GET_NUMBER_OF_POWER_PILLS_CARRIED: - ScriptParams[0] = CPacManPickups::QueryPowerPillsCarriedByPlayer(); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_CLEAR_NUMBER_OF_POWER_PILLS_CARRIED: - CPacManPickups::ResetPowerPillsCarriedByPlayer(); - return 0; - case COMMAND_IS_CAR_ON_SCREEN: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(TheCamera.IsSphereVisible(pVehicle->GetBoundCentre(), pVehicle->GetBoundRadius())); - return 0; - } - case COMMAND_IS_CHAR_ON_SCREEN: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(TheCamera.IsSphereVisible(pPed->GetBoundCentre(), pPed->GetBoundRadius())); - return 0; - } - case COMMAND_IS_OBJECT_ON_SCREEN: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - UpdateCompareFlag(TheCamera.IsSphereVisible(pObject->GetBoundCentre(), pObject->GetBoundRadius())); - return 0; - } - case COMMAND_GOSUB_FILE: - { - CollectParameters(&m_nIp, 2); - script_assert(m_nStackPointer < MAX_STACK_DEPTH); - m_anStack[m_nStackPointer++] = m_nIp; - SetIP(ScriptParams[0]); - // ScriptParams[1] == filename - return 0; - } - case COMMAND_GET_GROUND_Z_FOR_3D_COORD: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - bool success; - *(float*)&ScriptParams[0] = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &success); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_START_SCRIPT_FIRE: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - ScriptParams[0] = gFireManager.StartScriptFire(pos, nil, 0.8f, 1); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_IS_SCRIPT_FIRE_EXTINGUISHED: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(gFireManager.IsScriptFireExtinguish(ScriptParams[0])); - return 0; - case COMMAND_REMOVE_SCRIPT_FIRE: - CollectParameters(&m_nIp, 1); - gFireManager.RemoveScriptFire(ScriptParams[0]); - return 0; - case COMMAND_SET_COMEDY_CONTROLS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bComedyControls = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_BOAT_GOTO_COORDS: - { - CollectParameters(&m_nIp, 4); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); - CBoat* pBoat = (CBoat*)pVehicle; - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &pos.z, false); - pBoat->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_ASTHECROWSWIMS; - pBoat->AutoPilot.m_vecDestinationCoors = pos; - pBoat->SetStatus(STATUS_PHYSICS); - pBoat->AutoPilot.m_nCruiseSpeed = Max(6, pBoat->AutoPilot.m_nCruiseSpeed); - pBoat->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds(); - return 0; - } - case COMMAND_BOAT_STOP: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); - CBoat* pBoat = (CBoat*)pVehicle; - pBoat->AutoPilot.m_nCarMission = MISSION_NONE; - pBoat->SetStatus(STATUS_PHYSICS); - pBoat->bEngineOn = false; - pBoat->AutoPilot.m_nCruiseSpeed = 0; - return 0; - } - case COMMAND_IS_PLAYER_SHOOTING_IN_AREA: - { - CollectParameters(&m_nIp, 6); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - float x1 = *(float*)&ScriptParams[1]; - float y1 = *(float*)&ScriptParams[2]; - float x2 = *(float*)&ScriptParams[3]; - float y2 = *(float*)&ScriptParams[4]; - UpdateCompareFlag(pPed->bIsShooting && pPed->IsWithinArea(x1, y1, x2, y2)); - if (ScriptParams[5]) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) - CTheScripts::DrawDebugSquare(x1, y1, x2, y2); - return 0; - } - case COMMAND_IS_CHAR_SHOOTING_IN_AREA: - { - CollectParameters(&m_nIp, 6); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - float x1 = *(float*)&ScriptParams[1]; - float y1 = *(float*)&ScriptParams[2]; - float x2 = *(float*)&ScriptParams[3]; - float y2 = *(float*)&ScriptParams[4]; - UpdateCompareFlag(pPed->bIsShooting && pPed->IsWithinArea(x1, y1, x2, y2)); - if (ScriptParams[5]) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) - CTheScripts::DrawDebugSquare(x1, y1, x2, y2); - return 0; - } - case COMMAND_IS_CURRENT_PLAYER_WEAPON: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - UpdateCompareFlag(ScriptParams[1] == pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType); - return 0; - } - case COMMAND_IS_CURRENT_CHAR_WEAPON: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(ScriptParams[1] == pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType); - return 0; - } - case COMMAND_CLEAR_NUMBER_OF_POWER_PILLS_EATEN: - CPacManPickups::ResetPowerPillsEatenInRace(); - return 0; - case COMMAND_ADD_POWER_PILL: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CPacManPickups::GenerateOnePMPickUp(pos); - return 0; - } - case COMMAND_SET_BOAT_CRUISE_SPEED: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); - CBoat* pBoat = (CBoat*)pVehicle; - pBoat->AutoPilot.m_nCruiseSpeed = *(float*)&ScriptParams[1]; - return 0; - } - case COMMAND_GET_RANDOM_CHAR_IN_AREA: - { - CollectParameters(&m_nIp, 4); - int ped_handle = -1; - CVector pos = FindPlayerCoors(); - float x1 = *(float*)&ScriptParams[0]; - float y1 = *(float*)&ScriptParams[1]; - float x2 = *(float*)&ScriptParams[2]; - float y2 = *(float*)&ScriptParams[3]; - int i = CPools::GetPedPool()->GetSize(); - while (--i && ped_handle == -1){ - CPed* pPed = CPools::GetPedPool()->GetSlot(i); - if (!pPed) - continue; - if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) - continue; - if (pPed->CharCreatedBy != RANDOM_CHAR) - continue; - if (!pPed->IsPedInControl()) - continue; - if (pPed->bRemoveFromWorld) - continue; - if (pPed->bFadeOut) - continue; - if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) - continue; - if (!ThisIsAValidRandomPed(pPed->m_nPedType)) - continue; - if (pPed->bIsLeader || pPed->m_leader) - continue; - if (!pPed->IsWithinArea(x1, y1, x2, y2)) - continue; - if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) - continue; - if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) - continue; - ped_handle = CPools::GetPedPool()->GetIndex(pPed); - CTheScripts::LastRandomPedId = ped_handle; - pPed->CharCreatedBy = MISSION_CHAR; - pPed->bRespondsToThreats = false; - ++CPopulation::ms_nTotalMissionPeds; - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); - } - ScriptParams[0] = ped_handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_RANDOM_CHAR_IN_ZONE: - { - char zone[KEY_LENGTH_IN_SCRIPT]; - strncpy(zone, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone); - if (nZone != -1) - m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(nZone); - int ped_handle = -1; - CVector pos = FindPlayerCoors(); - int i = CPools::GetPedPool()->GetSize(); - while (--i && ped_handle == -1) { - CPed* pPed = CPools::GetPedPool()->GetSlot(i); - if (!pPed) - continue; - if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) - continue; - if (pPed->CharCreatedBy != RANDOM_CHAR) - continue; - if (!pPed->IsPedInControl()) - continue; - if (pPed->bRemoveFromWorld) - continue; - if (pPed->bFadeOut) - continue; - if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) - continue; - if (!ThisIsAValidRandomPed(pPed->m_nPedType)) - continue; - if (pPed->bIsLeader || pPed->m_leader) - continue; - if (!CTheZones::PointLiesWithinZone(&pPed->GetPosition(), pZone)) - continue; - if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) - continue; - if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) - continue; - ped_handle = CPools::GetPedPool()->GetIndex(pPed); - CTheScripts::LastRandomPedId = ped_handle; - pPed->CharCreatedBy = MISSION_CHAR; - pPed->bRespondsToThreats = false; - ++CPopulation::ms_nTotalMissionPeds; - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); - } - ScriptParams[0] = ped_handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_IS_PLAYER_IN_TAXI: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->IsTaxi()); - return 0; - } - case COMMAND_IS_PLAYER_SHOOTING: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - UpdateCompareFlag(pPed->bIsShooting); - return 0; - } - case COMMAND_IS_CHAR_SHOOTING: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(pPed->bIsShooting); - return 0; - } - case COMMAND_CREATE_MONEY_PICKUP: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_MONEY, PICKUP_MONEY, ScriptParams[3]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CHAR_ACCURACY: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->m_wepAccuracy = ScriptParams[1]; - return 0; - } - case COMMAND_GET_CAR_SPEED: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - *(float*)&ScriptParams[0] = pVehicle->GetSpeed().Magnitude() * GAME_SPEED_TO_METERS_PER_SECOND; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_LOAD_CUTSCENE: - { - char name[KEY_LENGTH_IN_SCRIPT]; - strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CCutsceneMgr::LoadCutsceneData(name); - return 0; - } - case COMMAND_CREATE_CUTSCENE_OBJECT: - { - CollectParameters(&m_nIp, 1); - CCutsceneObject* pCutObj = CCutsceneMgr::CreateCutsceneObject(ScriptParams[0]); - ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pCutObj); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CUTSCENE_ANIM: - { - CollectParameters(&m_nIp, 1); - char name[KEY_LENGTH_IN_SCRIPT]; - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CCutsceneMgr::SetCutsceneAnim(name, pObject); - return 0; - } - case COMMAND_START_CUTSCENE: - CCutsceneMgr::ms_cutsceneLoadStatus = 1; - return 0; - case COMMAND_GET_CUTSCENE_TIME: - ScriptParams[0] = CCutsceneMgr::GetCutsceneTimeInMilleseconds(); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_HAS_CUTSCENE_FINISHED: - UpdateCompareFlag(CCutsceneMgr::HasCutsceneFinished()); - return 0; - case COMMAND_CLEAR_CUTSCENE: - CCutsceneMgr::DeleteCutsceneData(); - return 0; - case COMMAND_RESTORE_CAMERA_JUMPCUT: - TheCamera.RestoreWithJumpCut(); - return 0; - case COMMAND_CREATE_COLLECTABLE1: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - CPickups::GenerateNewOne(pos, MI_COLLECTABLE1, PICKUP_COLLECTABLE1, 0); - return 0; - } - case COMMAND_SET_COLLECTABLE1_TOTAL: - CollectParameters(&m_nIp, 1); - CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages = ScriptParams[0]; - return 0; - case COMMAND_IS_PROJECTILE_IN_AREA: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - UpdateCompareFlag(CProjectileInfo::IsProjectileInRange(infX, supX, infY, supY, infZ, supZ, false)); - if (CTheScripts::DbgFlag) - CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); - return 0; - } - case COMMAND_DESTROY_PROJECTILES_IN_AREA: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - UpdateCompareFlag(CProjectileInfo::IsProjectileInRange(infX, supX, infY, supY, infZ, supZ, true)); - if (CTheScripts::DbgFlag) - CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); - return 0; - } - case COMMAND_DROP_MINE: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - CPickups::GenerateNewOne(pos, MI_CARMINE, PICKUP_MINE_INACTIVE, 0); - return 0; - } - case COMMAND_DROP_NAUTICAL_MINE: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - CPickups::GenerateNewOne(pos, MI_NAUTICALMINE, PICKUP_MINE_INACTIVE, 0); - return 0; - } - case COMMAND_IS_CHAR_MODEL: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(ScriptParams[1] == pPed->GetModelIndex()); - return 0; - } - case COMMAND_LOAD_SPECIAL_MODEL: - { - CollectParameters(&m_nIp, 1); - char name[KEY_LENGTH_IN_SCRIPT]; - strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - name[i] = tolower(name[i]); - CStreaming::RequestSpecialModel(ScriptParams[0], name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); - m_nIp += KEY_LENGTH_IN_SCRIPT; - return 0; - } - case COMMAND_CREATE_CUTSCENE_HEAD: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CCutsceneHead* pCutHead = CCutsceneMgr::AddCutsceneHead(pObject, ScriptParams[1]); - ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pCutHead); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CUTSCENE_HEAD_ANIM: - { - CollectParameters(&m_nIp, 1); - CObject* pCutHead = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pCutHead); - char name[KEY_LENGTH_IN_SCRIPT]; - strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CTimer::Stop(); - CCutsceneMgr::SetHeadAnim(name, pCutHead); - CTimer::Update(); - return 0; - } - case COMMAND_SIN: - CollectParameters(&m_nIp, 1); - *(float*)&ScriptParams[0] = Sin(DEGTORAD(*(float*)&ScriptParams[0])); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_COS: - CollectParameters(&m_nIp, 1); - *(float*)&ScriptParams[0] = Cos(DEGTORAD(*(float*)&ScriptParams[0])); - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_GET_CAR_FORWARD_X: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - float forwardX = pVehicle->GetForward().x / pVehicle->GetForward().Magnitude2D(); - *(float*)&ScriptParams[0] = forwardX; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_CAR_FORWARD_Y: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - float forwardY = pVehicle->GetForward().y / pVehicle->GetForward().Magnitude2D(); - *(float*)&ScriptParams[0] = forwardY; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_CHANGE_GARAGE_TYPE: - CollectParameters(&m_nIp, 2); - CGarages::ChangeGarageType(ScriptParams[0], (eGarageType)ScriptParams[1], 0); - return 0; - case COMMAND_ACTIVATE_CRUSHER_CRANE: - { - CollectParameters(&m_nIp, 10); - float infX = *(float*)&ScriptParams[2]; - float infY = *(float*)&ScriptParams[3]; - float supX = *(float*)&ScriptParams[4]; - float supY = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[4]; - supX = *(float*)&ScriptParams[2]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[5]; - supY = *(float*)&ScriptParams[3]; - } - CCranes::ActivateCrane(infX, supX, infY, supY, - *(float*)&ScriptParams[6], *(float*)&ScriptParams[7], *(float*)&ScriptParams[8], - DEGTORAD(*(float*)&ScriptParams[9]), true, false, - *(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); - return 0; - } - case COMMAND_PRINT_WITH_2_NUMBERS: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 4); - CMessages::AddMessageWithNumber(text, ScriptParams[2], ScriptParams[3], ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_2_NUMBERS_NOW: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 4); - CMessages::AddMessageJumpQWithNumber(text, ScriptParams[2], ScriptParams[3], ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_2_NUMBERS_SOON: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 4); - CMessages::AddMessageSoonWithNumber(text, ScriptParams[2], ScriptParams[3], ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_3_NUMBERS: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 5); - CMessages::AddMessageWithNumber(text, ScriptParams[3], ScriptParams[4], ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_3_NUMBERS_NOW: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 5); - CMessages::AddMessageJumpQWithNumber(text, ScriptParams[3], ScriptParams[4], ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_3_NUMBERS_SOON: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 5); - CMessages::AddMessageSoonWithNumber(text, ScriptParams[3], ScriptParams[4], ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_4_NUMBERS: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 6); - CMessages::AddMessageWithNumber(text, ScriptParams[4], ScriptParams[5], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_4_NUMBERS_NOW: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 6); - CMessages::AddMessageJumpQWithNumber(text, ScriptParams[4], ScriptParams[5], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_4_NUMBERS_SOON: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 6); - CMessages::AddMessageSoonWithNumber(text, ScriptParams[4], ScriptParams[5], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_5_NUMBERS: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 7); - CMessages::AddMessageWithNumber(text, ScriptParams[5], ScriptParams[6], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); - return 0; - } - case COMMAND_PRINT_WITH_5_NUMBERS_NOW: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 7); - CMessages::AddMessageJumpQWithNumber(text, ScriptParams[5], ScriptParams[6], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); - return 0; - } - case COMMAND_PRINT_WITH_5_NUMBERS_SOON: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 7); - CMessages::AddMessageSoonWithNumber(text, ScriptParams[5], ScriptParams[6], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); - return 0; - } - case COMMAND_PRINT_WITH_6_NUMBERS: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 8); - CMessages::AddMessageWithNumber(text, ScriptParams[6], ScriptParams[7], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); - return 0; - } - case COMMAND_PRINT_WITH_6_NUMBERS_NOW: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 8); - CMessages::AddMessageJumpQWithNumber(text, ScriptParams[6], ScriptParams[7], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); - return 0; - } - case COMMAND_PRINT_WITH_6_NUMBERS_SOON: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 8); - CMessages::AddMessageSoonWithNumber(text, ScriptParams[6], ScriptParams[7], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FOLLOW_CHAR_IN_FORMATION: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FOLLOW_CHAR_IN_FORMATION, pTargetPed); - pPed->SetFormation((eFormation)ScriptParams[2]); - return 0; - } - case COMMAND_PLAYER_MADE_PROGRESS: - CollectParameters(&m_nIp, 1); - CStats::ProgressMade += ScriptParams[0]; - return 0; - case COMMAND_SET_PROGRESS_TOTAL: - CollectParameters(&m_nIp, 1); - CStats::TotalProgressInGame = ScriptParams[0]; - return 0; - case COMMAND_REGISTER_JUMP_DISTANCE: - CollectParameters(&m_nIp, 1); - CStats::MaximumJumpDistance = Max(CStats::MaximumJumpDistance, *(float*)&ScriptParams[0]); - return 0; - case COMMAND_REGISTER_JUMP_HEIGHT: - CollectParameters(&m_nIp, 1); - CStats::MaximumJumpHeight = Max(CStats::MaximumJumpHeight, *(float*)&ScriptParams[0]); - return 0; - case COMMAND_REGISTER_JUMP_FLIPS: - CollectParameters(&m_nIp, 1); - CStats::MaximumJumpFlips = Max(CStats::MaximumJumpFlips, ScriptParams[0]); - return 0; - case COMMAND_REGISTER_JUMP_SPINS: - CollectParameters(&m_nIp, 1); - CStats::MaximumJumpSpins = Max(CStats::MaximumJumpSpins, ScriptParams[0]); - return 0; - case COMMAND_REGISTER_JUMP_STUNT: - CollectParameters(&m_nIp, 1); - CStats::BestStuntJump = Max(CStats::BestStuntJump, ScriptParams[0]); - return 0; - case COMMAND_REGISTER_UNIQUE_JUMP_FOUND: - ++CStats::NumberOfUniqueJumpsFound; - return 0; - case COMMAND_SET_UNIQUE_JUMPS_TOTAL: - CollectParameters(&m_nIp, 1); - CStats::TotalNumberOfUniqueJumps = ScriptParams[0]; - return 0; - case COMMAND_REGISTER_PASSENGER_DROPPED_OFF_TAXI: - ++CStats::PassengersDroppedOffWithTaxi; - return 0; - case COMMAND_REGISTER_MONEY_MADE_TAXI: - CollectParameters(&m_nIp, 1); - CStats::MoneyMadeWithTaxi += ScriptParams[0]; - return 0; - case COMMAND_REGISTER_MISSION_GIVEN: - ++CStats::MissionsGiven; - return 0; - case COMMAND_REGISTER_MISSION_PASSED: - { - char name[KEY_LENGTH_IN_SCRIPT]; - strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - m_nIp += KEY_LENGTH_IN_SCRIPT; - strncpy(CStats::LastMissionPassedName, name, KEY_LENGTH_IN_SCRIPT); - ++CStats::MissionsPassed; - CStats::CheckPointReachedSuccessfully(); - return 0; - } - case COMMAND_SET_CHAR_RUNNING: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bIsRunning = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_REMOVE_ALL_SCRIPT_FIRES: - gFireManager.RemoveAllScriptFires(); - return 0; - case COMMAND_IS_FIRST_CAR_COLOUR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->m_currentColour1 == ScriptParams[1]); - return 0; - } - case COMMAND_IS_SECOND_CAR_COLOUR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->m_currentColour2 == ScriptParams[1]); - return 0; - } - case COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_WEAPON: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - if (!pPed) - printf("HAS_CHAR_BEEN_DAMAGED_BY_WEAPON - Character doesn't exist\n"); - UpdateCompareFlag(pPed && pPed->m_lastWepDam == ScriptParams[1]); - return 0; - } - case COMMAND_HAS_CAR_BEEN_DAMAGED_BY_WEAPON: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - if (!pVehicle) - printf("HAS_CAR_BEEN_DAMAGED_BY_WEAPON - Vehicle doesn't exist\n"); - UpdateCompareFlag(pVehicle && pVehicle->m_nLastWeaponDamage == ScriptParams[1]); - return 0; - } - case COMMAND_IS_CHAR_IN_CHARS_GROUP: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - CPed* pLeader = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pPed); - script_assert(pLeader); - UpdateCompareFlag(pPed->m_leader == pLeader); - return 0; - } - default: - script_assert(0); - } - return -1; -} -int8 CRunningScript::ProcessCommands800To899(int32 command) -{ - CMatrix tmp_matrix; - switch (command) { - case COMMAND_IS_CHAR_IN_PLAYERS_GROUP: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - CPed* pLeader = CWorld::Players[ScriptParams[1]].m_pPed; - script_assert(pPed); - script_assert(pLeader); - UpdateCompareFlag(pPed->m_leader == pLeader); - return 0; - } - case COMMAND_EXPLODE_CHAR_HEAD: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - if (pPed->m_nPedState == PED_DRIVING) { - pPed->SetDead(); - if (!pPed->IsPlayer()) - pPed->FlagToDestroyWhenNextProcessed(); - } - else if (CGame::nastyGame && pPed->IsPedInControl()) { - pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, pPed->GetNodePosition(PED_HEAD), true); - } - else { - pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - } - return 0; - } - case COMMAND_EXPLODE_PLAYER_HEAD: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - if (CGame::nastyGame) { - pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, pPed->GetNodePosition(PED_HEAD), true); - } - else { - pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - } - return 0; - } - case COMMAND_ANCHOR_BOAT: - { - CollectParameters(&m_nIp, 2); - CBoat* pBoat = (CBoat*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pBoat && pBoat->m_vehType == VEHICLE_TYPE_BOAT); - pBoat->m_bIsAnchored = (ScriptParams[1] == 0); - return 0; - } - case COMMAND_SET_ZONE_GROUP: - { - char zone[KEY_LENGTH_IN_SCRIPT]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CollectParameters(&m_nIp, 2); - int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); - if (zone_id < 0) { - printf("Couldn't find zone - %s\n", zone); - return 0; - } - CTheZones::SetPedGroup(zone_id, ScriptParams[0], ScriptParams[1]); - return 0; - } - case COMMAND_START_CAR_FIRE: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - ScriptParams[0] = gFireManager.StartScriptFire(pVehicle->GetPosition(), pVehicle, 0.8f, 1); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_START_CHAR_FIRE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - ScriptParams[0] = gFireManager.StartScriptFire(pPed->GetPosition(), pPed, 0.8f, 1); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_AREA: - { - CollectParameters(&m_nIp, 5); - int handle = -1; - uint32 i = CPools::GetVehiclePool()->GetSize(); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float supX = *(float*)&ScriptParams[2]; - float supY = *(float*)&ScriptParams[3]; - while (i--) { - CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); - if (!pVehicle) - continue; - if (ScriptParams[4] != pVehicle->GetModelIndex() && ScriptParams[4] >= 0) - continue; - if (pVehicle->VehicleCreatedBy != RANDOM_VEHICLE) - continue; - if (!pVehicle->IsWithinArea(infX, infY, supX, supY)) - continue; - handle = CPools::GetVehiclePool()->GetIndex(pVehicle); - pVehicle->VehicleCreatedBy = MISSION_VEHICLE; - ++CCarCtrl::NumMissionCars; - --CCarCtrl::NumRandomCars; - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); - } - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_ZONE: - { - char zone[KEY_LENGTH_IN_SCRIPT]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); - int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); - if (zone_id != -1) - m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(zone_id); - CollectParameters(&m_nIp, 1); - int handle = -1; - uint32 i = CPools::GetVehiclePool()->GetSize(); - while (i--) { - CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); - if (!pVehicle) - continue; - if (ScriptParams[0] != pVehicle->GetModelIndex() && ScriptParams[0] >= 0) - continue; - if (pVehicle->VehicleCreatedBy != RANDOM_VEHICLE) - continue; - if (!CTheZones::PointLiesWithinZone(&pVehicle->GetPosition(), pZone)) - continue; - handle = CPools::GetVehiclePool()->GetIndex(pVehicle); - pVehicle->VehicleCreatedBy = MISSION_VEHICLE; - ++CCarCtrl::NumMissionCars; - --CCarCtrl::NumRandomCars; - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); - } - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_HAS_RESPRAY_HAPPENED: - { - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CGarages::HasResprayHappened(ScriptParams[0])); - return 0; - } - case COMMAND_SET_CAMERA_ZOOM: - { - CollectParameters(&m_nIp, 1); - if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FOLLOWPED) - TheCamera.SetZoomValueFollowPedScript(ScriptParams[0]); - else if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING) - TheCamera.SetZoomValueCamStringScript(ScriptParams[0]); - return 0; - } - case COMMAND_CREATE_PICKUP_WITH_AMMO: - { - CollectParameters(&m_nIp, 6); - int16 model = ScriptParams[0]; - if (model < 0) - model = CTheScripts::UsedObjectArray[-model].index; - CVector pos = *(CVector*)&ScriptParams[3]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CPickups::GenerateNewOne(pos, model, ScriptParams[1], ScriptParams[2]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CAR_RAM_CAR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CCarAI::TellCarToRamOtherCar(pVehicle, pTarget); - return 0; - } - case COMMAND_SET_CAR_BLOCK_CAR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CCarAI::TellCarToBlockOtherCar(pVehicle, pTarget); - return 0; - } - case COMMAND_SET_CHAR_OBJ_CATCH_TRAIN: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_CATCH_TRAIN); - return 0; - } - //case COMMAND_SET_COLL_OBJ_CATCH_TRAIN: - case COMMAND_SET_PLAYER_NEVER_GETS_TIRED: - { - CollectParameters(&m_nIp, 2); - CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; - pPlayer->m_bInfiniteSprint = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_PLAYER_FAST_RELOAD: - { - CollectParameters(&m_nIp, 2); - CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; - pPlayer->m_bFastReload = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_CHAR_BLEEDING: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bPedIsBleeding = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_CAR_FUNNY_SUSPENSION: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - // no action - return 0; - } - case COMMAND_SET_CAR_BIG_WHEELS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); - CAutomobile* pCar = (CAutomobile*)pVehicle; - pCar->bBigWheels = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_FREE_RESPRAYS: - CollectParameters(&m_nIp, 1); - CGarages::SetFreeResprays(ScriptParams[0] != 0); - return 0; - case COMMAND_SET_PLAYER_VISIBLE: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - pPed->bIsVisible = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_CHAR_VISIBLE: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bIsVisible = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_SET_CAR_VISIBLE: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bIsVisible = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_IS_AREA_OCCUPIED: - { - CollectParameters(&m_nIp, 11); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - int16 total; - CWorld::FindObjectsIntersectingCube(CVector(infX, infY, infZ), CVector(supX, supY, supZ), &total, 2, nil, - !!ScriptParams[6], !!ScriptParams[7], !!ScriptParams[8], !!ScriptParams[9], !!ScriptParams[10]); - UpdateCompareFlag(total > 0); - return 0; - } - case COMMAND_START_DRUG_RUN: - CPlane::CreateIncomingCesna(); - return 0; - case COMMAND_HAS_DRUG_RUN_BEEN_COMPLETED: - UpdateCompareFlag(CPlane::HasCesnaLanded()); - return 0; - case COMMAND_HAS_DRUG_PLANE_BEEN_SHOT_DOWN: - UpdateCompareFlag(CPlane::HasCesnaBeenDestroyed()); - return 0; - case COMMAND_SAVE_PLAYER_FROM_FIRES: - CollectParameters(&m_nIp, 1); - gFireManager.ExtinguishPoint(CWorld::Players[ScriptParams[0]].GetPos(), 3.0f); - return 0; - case COMMAND_DISPLAY_TEXT: - { - CollectParameters(&m_nIp, 2); - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtX = *(float*)&ScriptParams[0]; - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtY = *(float*)&ScriptParams[1]; - uint16 len = CMessages::GetWideStringLength(text); - for (uint16 i = 0; i < len; i++) - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_Text[i] = text[i]; - for (uint16 i = len; i < SCRIPT_TEXT_MAX_LENGTH; i++) - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_Text[i] = 0; - ++CTheScripts::NumberOfIntroTextLinesThisFrame; - return 0; - } - case COMMAND_SET_TEXT_SCALE: - { - CollectParameters(&m_nIp, 2); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fScaleX = *(float*)&ScriptParams[0]; - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fScaleY = *(float*)&ScriptParams[1]; - return 0; - } - case COMMAND_SET_TEXT_COLOUR: - { - CollectParameters(&m_nIp, 4); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_sColor = - CRGBA(ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3]); - return 0; - } - case COMMAND_SET_TEXT_JUSTIFY: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bJustify = (ScriptParams[0] != 0); - return 0; - } - case COMMAND_SET_TEXT_CENTRE: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bCentered = (ScriptParams[0] != 0); - return 0; - } - case COMMAND_SET_TEXT_WRAPX: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fWrapX = *(float*)&ScriptParams[0]; - return 0; - } - case COMMAND_SET_TEXT_CENTRE_SIZE: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fCenterSize = *(float*)&ScriptParams[0]; - return 0; - } - case COMMAND_SET_TEXT_BACKGROUND: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bBackground = (ScriptParams[0] != 0); - return 0; - } - case COMMAND_SET_TEXT_BACKGROUND_COLOUR: - { - CollectParameters(&m_nIp, 4); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_sBackgroundColor = - CRGBA(ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3]); - return 0; - } - case COMMAND_SET_TEXT_BACKGROUND_ONLY_TEXT: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bBackgroundOnly = (ScriptParams[0] != 0); - return 0; - } - case COMMAND_SET_TEXT_PROPORTIONAL: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bTextProportional = (ScriptParams[0] != 0); - return 0; - } - case COMMAND_SET_TEXT_FONT: - { - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_nFont = ScriptParams[0]; - return 0; - } - case COMMAND_INDUSTRIAL_PASSED: - CStats::IndustrialPassed = true; - DMAudio.PlayRadioAnnouncement(STREAMED_SOUND_ANNOUNCE_COMMERCIAL_OPEN); - return 0; - case COMMAND_COMMERCIAL_PASSED: - CStats::CommercialPassed = true; - DMAudio.PlayRadioAnnouncement(STREAMED_SOUND_ANNOUNCE_SUBURBAN_OPEN); - return 0; - case COMMAND_SUBURBAN_PASSED: - CStats::SuburbanPassed = true; - return 0; - case COMMAND_ROTATE_OBJECT: - { - CollectParameters(&m_nIp, 4); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - float heading = LimitAngleOnCircle( - RADTODEG(Atan2(-pObject->GetForward().x, pObject->GetForward().y))); - float headingTarget = *(float*)&ScriptParams[1]; -#ifdef FIX_BUGS - float rotateBy = *(float*)&ScriptParams[2] * CTimer::GetTimeStepFix(); -#else - float rotateBy = *(float*)&ScriptParams[2]; -#endif - if (headingTarget == heading) { // using direct comparasion here is fine - UpdateCompareFlag(true); - return 0; - } - float angleClockwise = LimitAngleOnCircle(headingTarget - heading); - float angleCounterclockwise = LimitAngleOnCircle(heading - headingTarget); - float newHeading; - if (angleClockwise < angleCounterclockwise) - newHeading = rotateBy < angleClockwise ? heading + rotateBy : headingTarget; - else - newHeading = rotateBy < angleCounterclockwise ? heading - rotateBy : headingTarget; - bool obstacleInPath = false; - if (ScriptParams[3]) { - CVector pos = pObject->GetPosition(); - tmp_matrix.SetRotateZ(DEGTORAD(newHeading)); - tmp_matrix.GetPosition() += pos; - CColModel* pColModel = pObject->GetColModel(); - CVector cp1 = tmp_matrix * pColModel->boundingBox.min; - CVector cp2 = tmp_matrix * CVector(pColModel->boundingBox.max.x, pColModel->boundingBox.min.y, pColModel->boundingBox.min.z); - CVector cp3 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.max.y, pColModel->boundingBox.min.z); - CVector cp4 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.min.y, pColModel->boundingBox.max.z); - int16 collisions; - CWorld::FindObjectsIntersectingAngledCollisionBox(pColModel->boundingBox, tmp_matrix, pos, - Min(cp1.x, Min(cp2.x, Min(cp3.x, cp4.x))), - Min(cp1.y, Min(cp2.y, Min(cp3.y, cp4.y))), - Max(cp1.x, Max(cp2.x, Max(cp3.x, cp4.x))), - Max(cp1.y, Max(cp2.y, Max(cp3.y, cp4.y))), - &collisions, 2, nil, false, true, true, false, false); - if (collisions > 0) - obstacleInPath = true; - } - if (obstacleInPath) { - UpdateCompareFlag(true); - return 0; - } - pObject->SetHeading(DEGTORAD(newHeading)); - pObject->GetMatrix().UpdateRW(); - pObject->UpdateRwFrame(); - UpdateCompareFlag(newHeading == headingTarget); // using direct comparasion here is fine - return 0; - } - case COMMAND_SLIDE_OBJECT: - { - CollectParameters(&m_nIp, 8); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CVector pos = pObject->GetPosition(); - CVector posTarget = *(CVector*)&ScriptParams[1]; -#ifdef FIX_BUGS - CVector slideBy = *(CVector*)&ScriptParams[4] * CTimer::GetTimeStepFix(); -#else - CVector slideBy = *(CVector*)&ScriptParams[4]; -#endif - if (posTarget == pos) { // using direct comparasion here is fine - UpdateCompareFlag(true); - return 0; - } - CVector posDiff = pos - posTarget; - CVector newPosition; - if (posDiff.x < 0) - newPosition.x = -posDiff.x < slideBy.x ? posTarget.x : pos.x + slideBy.x; - else - newPosition.x = posDiff.x < slideBy.x ? posTarget.x : pos.x - slideBy.x; - if (posDiff.y < 0) - newPosition.y = -posDiff.y < slideBy.y ? posTarget.y : pos.y + slideBy.y; - else - newPosition.y = posDiff.y < slideBy.y ? posTarget.y : pos.y - slideBy.y; - if (posDiff.z < 0) - newPosition.z = -posDiff.z < slideBy.z ? posTarget.z : pos.z + slideBy.z; - else - newPosition.z = posDiff.z < slideBy.z ? posTarget.z : pos.z - slideBy.z; - bool obstacleInPath = false; - if (ScriptParams[7]) { - tmp_matrix = pObject->GetMatrix(); - tmp_matrix.GetPosition() = newPosition; - CColModel* pColModel = pObject->GetColModel(); - CVector cp1 = tmp_matrix * pColModel->boundingBox.min; - CVector cp2 = tmp_matrix * CVector(pColModel->boundingBox.max.x, pColModel->boundingBox.min.y, pColModel->boundingBox.min.z); - CVector cp3 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.max.y, pColModel->boundingBox.min.z); - CVector cp4 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.min.y, pColModel->boundingBox.max.z); - int16 collisions; - CWorld::FindObjectsIntersectingAngledCollisionBox(pColModel->boundingBox, tmp_matrix, newPosition, - Min(cp1.x, Min(cp2.x, Min(cp3.x, cp4.x))), - Min(cp1.y, Min(cp2.y, Min(cp3.y, cp4.y))), - Max(cp1.x, Max(cp2.x, Max(cp3.x, cp4.x))), - Max(cp1.y, Max(cp2.y, Max(cp3.y, cp4.y))), - &collisions, 2, nil, false, true, true, false, false); - if (collisions > 0) - obstacleInPath = true; - } - if (obstacleInPath) { - UpdateCompareFlag(true); - return 0; - } - pObject->Teleport(newPosition); - UpdateCompareFlag(newPosition == posTarget); // using direct comparasion here is fine - return 0; - } - case COMMAND_REMOVE_CHAR_ELEGANTLY: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - if (pPed && pPed->CharCreatedBy == MISSION_CHAR){ - CWorld::RemoveReferencesToDeletedObject(pPed); - if (pPed->bInVehicle){ - if (pPed->m_pMyVehicle){ - if (pPed == pPed->m_pMyVehicle->pDriver){ - pPed->m_pMyVehicle->RemoveDriver(); - pPed->m_pMyVehicle->SetStatus(STATUS_ABANDONED); - if (pPed->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - pPed->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED; - if (pPed->m_nPedType == PEDTYPE_COP && pPed->m_pMyVehicle->IsLawEnforcementVehicle()) - pPed->m_pMyVehicle->ChangeLawEnforcerState(0); - }else{ - pPed->m_pMyVehicle->RemovePassenger(pPed); - } - } - delete pPed; - --CPopulation::ms_nTotalMissionPeds; - }else{ - pPed->CharCreatedBy = RANDOM_CHAR; - pPed->bRespondsToThreats = true; - pPed->bScriptObjectiveCompleted = false; - pPed->ClearLeader(); - --CPopulation::ms_nTotalMissionPeds; - pPed->bFadeOut = true; - } - } - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); - return 0; - } - case COMMAND_SET_CHAR_STAY_IN_SAME_PLACE: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bKindaStayInSamePlace = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_IS_NASTY_GAME: - UpdateCompareFlag(CGame::nastyGame); - return 0; - case COMMAND_UNDRESS_CHAR: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - char name[KEY_LENGTH_IN_SCRIPT]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, name); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - name[i] = tolower(name[i]); - int mi = pPed->GetModelIndex(); - pPed->DeleteRwObject(); - if (pPed->IsPlayer()) - mi = 0; - CStreaming::RequestSpecialModel(mi, name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CWorld::Remove(pPed); - return 0; - } - case COMMAND_DRESS_CHAR: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - int mi = pPed->GetModelIndex(); - pPed->m_modelIndex = -1; - pPed->SetModelIndex(mi); - CWorld::Add(pPed); - return 0; - } - case COMMAND_START_CHASE_SCENE: - CollectParameters(&m_nIp, 1); - CTimer::Suspend(); - CStreaming::DeleteAllRwObjects(); - CRecordDataForChase::StartChaseScene(*(float*)&ScriptParams[0]); - CTimer::Resume(); - return 0; - case COMMAND_STOP_CHASE_SCENE: - CRecordDataForChase::CleanUpChaseScene(); - return 0; - case COMMAND_IS_EXPLOSION_IN_AREA: - { - CollectParameters(&m_nIp, 7); - float infX = *(float*)&ScriptParams[1]; - float infY = *(float*)&ScriptParams[2]; - float infZ = *(float*)&ScriptParams[3]; - float supX = *(float*)&ScriptParams[4]; - float supY = *(float*)&ScriptParams[5]; - float supZ = *(float*)&ScriptParams[6]; - if (infX > supX) { - infX = *(float*)&ScriptParams[4]; - supX = *(float*)&ScriptParams[1]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[5]; - supY = *(float*)&ScriptParams[2]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[6]; - supZ = *(float*)&ScriptParams[3]; - } - UpdateCompareFlag(CExplosion::TestForExplosionInArea((eExplosionType)ScriptParams[0], - infX, supX, infY, supY, infZ, supZ)); - return 0; - } - case COMMAND_IS_EXPLOSION_IN_ZONE: - { - CollectParameters(&m_nIp, 1); - char zone[KEY_LENGTH_IN_SCRIPT]; - CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); - int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); - if (zone_id != -1) - m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(zone_id); - UpdateCompareFlag(CExplosion::TestForExplosionInArea((eExplosionType)ScriptParams[0], - pZone->minx, pZone->maxx, pZone->miny, pZone->maxy, pZone->minz, pZone->maxz)); - return 0; - } - case COMMAND_START_DRUG_DROP_OFF: - CPlane::CreateDropOffCesna(); - return 0; - case COMMAND_HAS_DROP_OFF_PLANE_BEEN_SHOT_DOWN: - UpdateCompareFlag(CPlane::HasDropOffCesnaBeenShotDown()); - return 0; - case COMMAND_FIND_DROP_OFF_PLANE_COORDINATES: - { - CVector pos = CPlane::FindDropOffCesnaCoordinates(); - *(CVector*)&ScriptParams[0] = pos; - StoreParameters(&m_nIp, 3); - return 0; - } - case COMMAND_CREATE_FLOATING_PACKAGE: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; - ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_FLOATPACKAGE1, PICKUP_FLOATINGPACKAGE, 0); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_PLACE_OBJECT_RELATIVE_TO_CAR: - { - CollectParameters(&m_nIp, 5); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pVehicle); - CVector offset = *(CVector*)&ScriptParams[2]; - CPhysical::PlacePhysicalRelativeToOtherPhysical(pVehicle, pObject, offset); - return 0; - } - case COMMAND_MAKE_OBJECT_TARGETTABLE: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CPlayerPed* pPlayerPed = CWorld::Players[CWorld::PlayerInFocus].m_pPed; - script_assert(pPlayerPed); - pPlayerPed->MakeObjectTargettable(ScriptParams[0]); - return 0; - } - case COMMAND_ADD_ARMOUR_TO_PLAYER: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPlayerPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPlayerPed); - pPlayerPed->m_fArmour = clamp(pPlayerPed->m_fArmour + ScriptParams[1], 0.0f, 100.0f); - return 0; - } - case COMMAND_ADD_ARMOUR_TO_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->m_fArmour = clamp(pPed->m_fArmour + ScriptParams[1], 0.0f, 100.0f); - return 0; - } - case COMMAND_OPEN_GARAGE: - { - CollectParameters(&m_nIp, 1); - CGarages::OpenGarage(ScriptParams[0]); - return 0; - } - case COMMAND_CLOSE_GARAGE: - { - CollectParameters(&m_nIp, 1); - CGarages::CloseGarage(ScriptParams[0]); - return 0; - } - case COMMAND_WARP_CHAR_FROM_CAR_TO_COORD: - { - CollectParameters(&m_nIp, 4); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - if (pPed->bInVehicle){ - if (pPed->m_pMyVehicle->bIsBus) - pPed->bRenderPedInCar = true; - if (pPed->m_pMyVehicle->pDriver == pPed){ - pPed->m_pMyVehicle->RemoveDriver(); - pPed->m_pMyVehicle->SetStatus(STATUS_ABANDONED); - pPed->m_pMyVehicle->bEngineOn = false; - pPed->m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; - }else{ - pPed->m_pMyVehicle->RemovePassenger(pPed); - } - pPed->m_pMyVehicle->SetMoveSpeed(0.0f, 0.0f, -0.00001f); - pPed->m_pMyVehicle->SetTurnSpeed(0.0f, 0.0f, 0.0f); - } - pPed->bInVehicle = false; - pPed->m_pMyVehicle = nil; - pPed->SetPedState(PED_IDLE); - pPed->m_nLastPedState = PED_NONE; - pPed->bUsesCollision = true; - pPed->SetMoveSpeed(0.0f, 0.0f, 0.0f); - pPed->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType)->m_nModelId); - pPed->RemoveInCarAnims(); - if (pPed->m_pVehicleAnim) - pPed->m_pVehicleAnim->blendDelta = -1000.0f; - pPed->m_pVehicleAnim = nil; - pPed->RestartNonPartialAnims(); - pPed->SetMoveState(PEDMOVE_NONE); - CAnimManager::BlendAnimation(pPed->GetClump(), pPed->m_animGroup, ANIM_IDLE_STANCE, 100.0f); - pos.z += pPed->GetDistanceFromCentreOfMassToBaseOfModel(); - pPed->Teleport(pos); - CTheScripts::ClearSpaceForMissionEntity(pos, pPed); - return 0; - } - case COMMAND_SET_VISIBILITY_OF_CLOSEST_OBJECT_OF_TYPE: - { - CollectParameters(&m_nIp, 6); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float range = *(float*)&ScriptParams[3]; - int mi = ScriptParams[4] < 0 ? CTheScripts::UsedObjectArray[-ScriptParams[4]].index : ScriptParams[4]; - int16 total; - CEntity* apEntities[16]; - CWorld::FindObjectsOfTypeInRange(mi, pos, range, true, &total, 16, apEntities, true, false, false, true, true); - if (total == 0) - CWorld::FindObjectsOfTypeInRangeSectorList(mi, CWorld::GetBigBuildingList(LEVEL_GENERIC), pos, range, true, &total, 16, apEntities); - if (total == 0) - CWorld::FindObjectsOfTypeInRangeSectorList(mi, CWorld::GetBigBuildingList(CTheZones::FindZoneForPoint(pos)), pos, range, true, &total, 16, apEntities); - CEntity* pClosestEntity = nil; - float min_dist = 2.0f * range; - for (int i = 0; i < total; i++) { - float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); - if (dist < min_dist) { - min_dist = dist; - pClosestEntity = apEntities[i]; - } - } - if (pClosestEntity) { - pClosestEntity->bIsVisible = (ScriptParams[5] != 0); - CTheScripts::AddToInvisibilitySwapArray(pClosestEntity, ScriptParams[5] != 0); - } - return 0; - } - case COMMAND_HAS_CHAR_SPOTTED_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - UpdateCompareFlag(pPed->OurPedCanSeeThisOne(pTarget)); - return 0; - } - case COMMAND_SET_CHAR_OBJ_HAIL_TAXI: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_HAIL_TAXI); - return 0; - } - case COMMAND_HAS_OBJECT_BEEN_DAMAGED: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - UpdateCompareFlag(pObject->bRenderDamaged || !pObject->bIsVisible); - return 0; - } - case COMMAND_START_KILL_FRENZY_HEADSHOT: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 8); - CDarkel::StartFrenzy((eWeaponType)ScriptParams[0], ScriptParams[1], ScriptParams[2], - ScriptParams[3], text, ScriptParams[4], ScriptParams[5], - ScriptParams[6], ScriptParams[7] != 0, true); - return 0; - } - case COMMAND_ACTIVATE_MILITARY_CRANE: - { - CollectParameters(&m_nIp, 10); - float infX = *(float*)&ScriptParams[2]; - float infY = *(float*)&ScriptParams[3]; - float supX = *(float*)&ScriptParams[4]; - float supY = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[4]; - supX = *(float*)&ScriptParams[2]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[5]; - supY = *(float*)&ScriptParams[3]; - } - CCranes::ActivateCrane(infX, supX, infY, supY, - *(float*)&ScriptParams[6], *(float*)&ScriptParams[7], *(float*)&ScriptParams[8], - DEGTORAD(*(float*)&ScriptParams[9]), false, true, - *(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); - return 0; - } - case COMMAND_WARP_PLAYER_INTO_CAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pVehicle); - pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicle); - pPed->WarpPedIntoCar(pVehicle); - return 0; - } - case COMMAND_WARP_CHAR_INTO_CAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pVehicle); - pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicle); - pPed->WarpPedIntoCar(pVehicle); - return 0; - } - //case COMMAND_SWITCH_CAR_RADIO: - //case COMMAND_SET_AUDIO_STREAM: - case COMMAND_PRINT_WITH_2_NUMBERS_BIG: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 4); - CMessages::AddBigMessageWithNumber(text, ScriptParams[2], ScriptParams[3] - 1, ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_3_NUMBERS_BIG: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 5); - CMessages::AddBigMessageWithNumber(text, ScriptParams[3], ScriptParams[4] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_4_NUMBERS_BIG: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 6); - CMessages::AddBigMessageWithNumber(text, ScriptParams[4], ScriptParams[5] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); - return 0; - } - case COMMAND_PRINT_WITH_5_NUMBERS_BIG: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 7); - CMessages::AddBigMessageWithNumber(text, ScriptParams[5], ScriptParams[6] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); - return 0; - } - case COMMAND_PRINT_WITH_6_NUMBERS_BIG: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 8); - CMessages::AddBigMessageWithNumber(text, ScriptParams[6], ScriptParams[7] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); - return 0; - } - case COMMAND_SET_CHAR_WAIT_STATE: - { - CollectParameters(&m_nIp, 3); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->SetWaitState((eWaitState)ScriptParams[1], ScriptParams[2] >= 0 ? &ScriptParams[2] : nil); - return 0; - } - case COMMAND_SET_CAMERA_BEHIND_PLAYER: - TheCamera.SetCameraDirectlyBehindForFollowPed_CamOnAString(); - return 0; - case COMMAND_SET_MOTION_BLUR: - CollectParameters(&m_nIp, 1); - TheCamera.SetMotionBlur(0, 0, 0, 0, ScriptParams[0]); - return 0; - case COMMAND_PRINT_STRING_IN_STRING: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* string = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 2); - CMessages::AddMessageWithString(text, ScriptParams[0], ScriptParams[1], string); - return 0; - } - case COMMAND_CREATE_RANDOM_CHAR: - { - CollectParameters(&m_nIp, 3); - CZoneInfo zoneinfo; - CTheZones::GetZoneInfoForTimeOfDay(&CWorld::Players[CWorld::PlayerInFocus].GetPos(), &zoneinfo); - int mi; - ePedType pedtype = PEDTYPE_COP; - int attempt = 0; - while (pedtype != PEDTYPE_CIVMALE && pedtype != PEDTYPE_CIVFEMALE && attempt < 5) { - mi = CPopulation::ChooseCivilianOccupation(zoneinfo.pedGroup); - if (CModelInfo::GetModelInfo(mi)->GetRwObject()) - pedtype = ((CPedModelInfo*)(CModelInfo::GetModelInfo(mi)))->m_pedType; - attempt++; - } - if (!CModelInfo::GetModelInfo(mi)->GetRwObject()) { - mi = MI_MALE01; - pedtype = ((CPedModelInfo*)(CModelInfo::GetModelInfo(mi)))->m_pedType; - } - CPed* ped = new CCivilianPed(pedtype, mi); - ped->CharCreatedBy = MISSION_CHAR; - ped->bRespondsToThreats = false; - ped->bAllowMedicsToReviveMe = false; - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - pos.z += 1.0f; - ped->SetPosition(pos); - ped->SetOrientation(0.0f, 0.0f, 0.0f); - CTheScripts::ClearSpaceForMissionEntity(pos, ped); - CWorld::Add(ped); - ped->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pos); - CPopulation::ms_nTotalMissionPeds++; - ScriptParams[0] = CPools::GetPedPool()->GetIndex(ped); - StoreParameters(&m_nIp, 1); - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); - return 0; - } - case COMMAND_SET_CHAR_OBJ_STEAL_ANY_CAR: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_STEAL_ANY_CAR); - return 0; - } - case COMMAND_SET_2_REPEATED_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, nil, nil, nil, nil); - return 0; - } - case COMMAND_SET_2_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, nil, nil, nil, nil); - return 0; - } - case COMMAND_SET_3_REPEATED_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, nil, nil, nil); - return 0; - } - case COMMAND_SET_3_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, nil, nil, nil); - return 0; - } - case COMMAND_SET_4_REPEATED_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, text4, nil, nil); - return 0; - } - case COMMAND_SET_4_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, text4, nil, nil); - return 0; - } - case COMMAND_IS_SNIPER_BULLET_IN_AREA: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - UpdateCompareFlag(CBulletInfo::TestForSniperBullet(infX, supX, infY, supY, infZ, supZ)); - return 0; - } - case COMMAND_GIVE_PLAYER_DETONATOR: - CGarages::GivePlayerDetonator(); - return 0; - //case COMMAND_SET_COLL_OBJ_STEAL_ANY_CAR: - case COMMAND_SET_OBJECT_VELOCITY: - { - CollectParameters(&m_nIp, 4); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - pObject->SetMoveSpeed(*(CVector*)&ScriptParams[1] * METERS_PER_SECOND_TO_GAME_SPEED); - return 0; - } - case COMMAND_SET_OBJECT_COLLISION: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - pObject->bUsesCollision = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_IS_ICECREAM_JINGLE_ON: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - // Adding this check to correspond to command name. - // All original game scripts always assume that the vehicle is actually Mr. Whoopee, - // but maybe there are mods that use it as "is alarm activated"? - script_assert(pVehicle->GetModelIndex() == MI_MRWHOOP); - UpdateCompareFlag(pVehicle->m_bSirenOrAlarm); - return 0; - } - default: - script_assert(0); - } - return -1; -} - -int8 CRunningScript::ProcessCommands900To999(int32 command) -{ - char str[52]; - char onscreen_str[KEY_LENGTH_IN_SCRIPT]; - switch (command) { - case COMMAND_PRINT_STRING_IN_STRING_NOW: - { - wchar* source = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* pstr = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CollectParameters(&m_nIp, 2); - CMessages::AddMessageJumpQWithString(source, ScriptParams[0], ScriptParams[1], pstr); - return 0; - } - //case COMMAND_PRINT_STRING_IN_STRING_SOON: - case COMMAND_SET_5_REPEATED_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, text4, text5, nil); - return 0; - } - case COMMAND_SET_5_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, text4, text5, nil); - return 0; - } - case COMMAND_SET_6_REPEATED_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text6 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, text4, text5, text6); - return 0; - } - case COMMAND_SET_6_PHONE_MESSAGES: - { - CollectParameters(&m_nIp, 1); - wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - wchar* text6 = CTheScripts::GetTextByKeyFromScript(&m_nIp); - gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, text4, text5, text6); - return 0; - } - case COMMAND_IS_POINT_OBSCURED_BY_A_MISSION_ENTITY: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0] - *(float*)&ScriptParams[3]; - float supX = *(float*)&ScriptParams[0] + *(float*)&ScriptParams[3]; - float infY = *(float*)&ScriptParams[1] - *(float*)&ScriptParams[4]; - float supY = *(float*)&ScriptParams[1] + *(float*)&ScriptParams[4]; - float infZ = *(float*)&ScriptParams[2] - *(float*)&ScriptParams[5]; - float supZ = *(float*)&ScriptParams[2] + *(float*)&ScriptParams[5]; - if (infX > supX) { - float tmp = infX; - infX = supX; - supX = tmp; - } - if (infY > supY) { - float tmp = infY; - infY = supY; - supY = tmp; - } - if (infZ > supZ) { - float tmp = infZ; - infZ = supZ; - supZ = tmp; - } - int16 total; - CWorld::FindMissionEntitiesIntersectingCube(CVector(infX, infY, infZ), CVector(supX, supY, supZ), &total, 2, nil, true, true, true); - UpdateCompareFlag(total > 0); - return 0; - } - case COMMAND_LOAD_ALL_MODELS_NOW: - CTimer::Stop(); - CStreaming::LoadAllRequestedModels(false); - CTimer::Update(); - return 0; - case COMMAND_ADD_TO_OBJECT_VELOCITY: - { - CollectParameters(&m_nIp, 4); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - pObject->SetMoveSpeed(pObject->GetMoveSpeed() + METERS_PER_SECOND_TO_GAME_SPEED * *(CVector*)&ScriptParams[1]); - return 0; - } - case COMMAND_DRAW_SPRITE: - { - CollectParameters(&m_nIp, 9); - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_bIsUsed = true; - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_nTextureId = ScriptParams[0] - 1; - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sRect = CRect( - *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], *(float*)&ScriptParams[1] + *(float*)&ScriptParams[3], *(float*)&ScriptParams[2] + *(float*)&ScriptParams[4]); - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sColor = CRGBA(ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8]); - CTheScripts::NumberOfIntroRectanglesThisFrame++; - return 0; - } - case COMMAND_DRAW_RECT: - { - CollectParameters(&m_nIp, 8); - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_bIsUsed = true; - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_nTextureId = -1; - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sRect = CRect( - *(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[0] + *(float*)&ScriptParams[2], *(float*)&ScriptParams[1] + *(float*)&ScriptParams[3]); - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sColor = CRGBA(ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7]); - CTheScripts::NumberOfIntroRectanglesThisFrame++; - return 0; - } - case COMMAND_LOAD_SPRITE: - { - CollectParameters(&m_nIp, 1); - strncpy(str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - str[i] = tolower(str[i]); - m_nIp += KEY_LENGTH_IN_SCRIPT; - int slot = CTxdStore::FindTxdSlot("script"); - CTxdStore::PushCurrentTxd(); - CTxdStore::SetCurrentTxd(slot); - CTheScripts::ScriptSprites[ScriptParams[0] - 1].SetTexture(str); - CTxdStore::PopCurrentTxd(); - return 0; - } - case COMMAND_LOAD_TEXTURE_DICTIONARY: - { - strcpy(str, "models\\"); - strncpy(str + sizeof("models\\"), (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - strcat(str, ".txd"); - m_nIp += KEY_LENGTH_IN_SCRIPT; - int slot = CTxdStore::FindTxdSlot("script"); - if (slot == -1) - slot = CTxdStore::AddTxdSlot("script"); - CTxdStore::LoadTxd(slot, str); - CTxdStore::AddRef(slot); - return 0; - } - case COMMAND_REMOVE_TEXTURE_DICTIONARY: - { - for (int i = 0; i < ARRAY_SIZE(CTheScripts::ScriptSprites); i++) - CTheScripts::ScriptSprites[i].Delete(); - CTxdStore::RemoveTxd(CTxdStore::FindTxdSlot("script")); - return 0; - } - case COMMAND_SET_OBJECT_DYNAMIC: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - if (ScriptParams[1]) { - if (pObject->bIsStatic) { - pObject->SetIsStatic(false); - pObject->AddToMovingList(); - } - } - else { - if (!pObject->bIsStatic) { - pObject->SetIsStatic(true); - pObject->RemoveFromMovingList(); - } - } - return 0; - } - case COMMAND_SET_CHAR_ANIM_SPEED: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CAnimBlendAssociation* pAssoc = RpAnimBlendClumpGetFirstAssociation(pPed->GetClump()); - if (pAssoc) - pAssoc->speed = *(float*)&ScriptParams[1]; - return 0; - } - case COMMAND_PLAY_MISSION_PASSED_TUNE: - { - CollectParameters(&m_nIp, 1); - DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND); - DMAudio.PlayFrontEndTrack(ScriptParams[0] + STREAMED_SOUND_MISSION_COMPLETED - 1, 0); - return 0; - } - case COMMAND_CLEAR_AREA: - { - CollectParameters(&m_nIp, 5); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CWorld::ClearExcitingStuffFromArea(pos, *(float*)&ScriptParams[3], ScriptParams[4]); - return 0; - } - case COMMAND_FREEZE_ONSCREEN_TIMER: - CollectParameters(&m_nIp, 1); - CUserDisplay::OnscnTimer.m_bDisabled = ScriptParams[0] != 0; - return 0; - case COMMAND_SWITCH_CAR_SIREN: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->m_bSirenOrAlarm = ScriptParams[1] != 0; - return 0; - } - case COMMAND_SWITCH_PED_ROADS_ON_ANGLED: - { - CollectParameters(&m_nIp, 7); - ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], - *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 0, 1); - return 0; - } - case COMMAND_SWITCH_PED_ROADS_OFF_ANGLED: - CollectParameters(&m_nIp, 7); - ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], - *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 0, 0); - return 0; - case COMMAND_SWITCH_ROADS_ON_ANGLED: - CollectParameters(&m_nIp, 7); - ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], - *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 1, 1); - return 0; - case COMMAND_SWITCH_ROADS_OFF_ANGLED: - CollectParameters(&m_nIp, 7); - ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], - *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 1, 0); - return 0; - case COMMAND_SET_CAR_WATERTIGHT: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); - CAutomobile* pCar = (CAutomobile*)pVehicle; - pCar->bWaterTight = ScriptParams[1] != 0; - return 0; - } - case COMMAND_ADD_MOVING_PARTICLE_EFFECT: - { - CollectParameters(&m_nIp, 12); - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float size = Max(0.0f, *(float*)&ScriptParams[7]); - eParticleObjectType type = (eParticleObjectType)ScriptParams[0]; - RwRGBA color; - if (type == POBJECT_SMOKE_TRAIL){ - color.alpha = -1; - color.red = ScriptParams[8]; - color.green = ScriptParams[9]; - color.blue = ScriptParams[10]; - }else{ - color.alpha = color.red = color.blue = color.green = 0; - } - CVector target = *(CVector*)&ScriptParams[4]; - CParticleObject::AddObject(type, pos, target, size, ScriptParams[11], color, 1); - return 0; - } - case COMMAND_SET_CHAR_CANT_BE_DRAGGED_OUT: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bDontDragMeOutCar = ScriptParams[1] != 0; - return 0; - } - case COMMAND_TURN_CAR_TO_FACE_COORD: - { - CollectParameters(&m_nIp, 3); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - const CVector& pos = pVehicle->GetPosition(); - float heading = CGeneral::GetATanOfXY(pos.y - *(float*)&ScriptParams[2], pos.x - *(float*)&ScriptParams[1]) + HALFPI; - if (heading > TWOPI) - heading -= TWOPI; - pVehicle->SetHeading(heading); - return 0; - } - case COMMAND_IS_CRANE_LIFTING_CAR: - { - CollectParameters(&m_nIp, 3); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[2]); - UpdateCompareFlag(CCranes::IsThisCarPickedUp(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], pVehicle)); - return 0; - } - case COMMAND_DRAW_SPHERE: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - C3dMarkers::PlaceMarkerSet((uintptr)this + m_nIp, MARKERTYPE_CYLINDER, pos, *(float*)&ScriptParams[3], - SPHERE_MARKER_R, SPHERE_MARKER_G, SPHERE_MARKER_B, SPHERE_MARKER_A, - SPHERE_MARKER_PULSE_PERIOD, SPHERE_MARKER_PULSE_FRACTION, 0); - return 0; - } - case COMMAND_SET_CAR_STATUS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->SetStatus((eEntityStatus)ScriptParams[1]); - return 0; - } - case COMMAND_IS_CHAR_MALE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(pPed->m_nPedType != PEDTYPE_CIVFEMALE && pPed->m_nPedType != PEDTYPE_PROSTITUTE); - return 0; - } - case COMMAND_SCRIPT_NAME: - { - strncpy(str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - str[i] = tolower(str[i]); - m_nIp += KEY_LENGTH_IN_SCRIPT; - strncpy(m_abScriptName, str, KEY_LENGTH_IN_SCRIPT); - return 0; - } - case COMMAND_CHANGE_GARAGE_TYPE_WITH_CAR_MODEL: - { - CollectParameters(&m_nIp, 3); - CGarages::ChangeGarageType(ScriptParams[0], (eGarageType)ScriptParams[1], ScriptParams[2]); - return 0; - } - case COMMAND_FIND_DRUG_PLANE_COORDINATES: - *(CVector*)&ScriptParams[0] = CPlane::FindDrugPlaneCoordinates(); - StoreParameters(&m_nIp, 3); - return 0; - case COMMAND_SAVE_INT_TO_DEBUG_FILE: - // TODO: implement something here - CollectParameters(&m_nIp, 1); - return 0; - case COMMAND_SAVE_FLOAT_TO_DEBUG_FILE: - CollectParameters(&m_nIp, 1); - return 0; - case COMMAND_SAVE_NEWLINE_TO_DEBUG_FILE: - return 0; - case COMMAND_POLICE_RADIO_MESSAGE: - CollectParameters(&m_nIp, 3); - DMAudio.PlaySuspectLastSeen(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2]); - return 0; - case COMMAND_SET_CAR_STRONG: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bTakeLessDamage = ScriptParams[1] != 0; - return 0; - } - case COMMAND_REMOVE_ROUTE: - CollectParameters(&m_nIp, 1); - CRouteNode::RemoveRoute(ScriptParams[0]); - return 0; - case COMMAND_SWITCH_RUBBISH: - CollectParameters(&m_nIp, 1); - CRubbish::SetVisibility(ScriptParams[0] != 0);; - return 0; - case COMMAND_REMOVE_PARTICLE_EFFECTS_IN_AREA: - { - CollectParameters(&m_nIp, 6); - float x1 = *(float*)&ScriptParams[0]; - float y1 = *(float*)&ScriptParams[1]; - float z1 = *(float*)&ScriptParams[2]; - float x2 = *(float*)&ScriptParams[3]; - float y2 = *(float*)&ScriptParams[4]; - float z2 = *(float*)&ScriptParams[5]; - CParticleObject* tmp = CParticleObject::pCloseListHead; - while (tmp) { - CParticleObject* next = tmp->m_pNext; - if (tmp->IsWithinArea(x1, y1, z1, x2, y2, z2)) - tmp->RemoveObject(); - tmp = next; - } - tmp = CParticleObject::pFarListHead; - while (tmp) { - CParticleObject* next = tmp->m_pNext; - if (tmp->IsWithinArea(x1, y1, z1, x2, y2, z2)) - tmp->RemoveObject(); - tmp = next; - } - return 0; - } - case COMMAND_SWITCH_STREAMING: - CollectParameters(&m_nIp, 1); - CStreaming::ms_disableStreaming = ScriptParams[0] == 0; - return 0; - case COMMAND_IS_GARAGE_OPEN: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CGarages::IsGarageOpen(ScriptParams[0])); - return 0; - case COMMAND_IS_GARAGE_CLOSED: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CGarages::IsGarageClosed(ScriptParams[0])); - return 0; - case COMMAND_START_CATALINA_HELI: - CHeli::StartCatalinaFlyBy(); - return 0; - case COMMAND_CATALINA_HELI_TAKE_OFF: - CHeli::CatalinaTakeOff(); - return 0; - case COMMAND_REMOVE_CATALINA_HELI: - CHeli::RemoveCatalinaHeli(); - return 0; - case COMMAND_HAS_CATALINA_HELI_BEEN_SHOT_DOWN: - UpdateCompareFlag(CHeli::HasCatalinaBeenShotDown()); - return 0; - case COMMAND_SWAP_NEAREST_BUILDING_MODEL: - { - CollectParameters(&m_nIp, 6); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float radius = *(float*)&ScriptParams[3]; - int mi1 = ScriptParams[4] >= 0 ? ScriptParams[4] : CTheScripts::UsedObjectArray[-ScriptParams[4]].index; - int mi2 = ScriptParams[5] >= 0 ? ScriptParams[5] : CTheScripts::UsedObjectArray[-ScriptParams[5]].index; - int16 total; - CEntity* apEntities[16]; - CWorld::FindObjectsOfTypeInRange(mi1, pos, radius, true, &total, 16, apEntities, true, false, false, false, false); - if (total == 0) - CWorld::FindObjectsOfTypeInRangeSectorList(mi1, CWorld::GetBigBuildingList(LEVEL_GENERIC), pos, radius, true, &total, 16, apEntities); - if (total == 0) - CWorld::FindObjectsOfTypeInRangeSectorList(mi1, CWorld::GetBigBuildingList(CTheZones::FindZoneForPoint(pos)), pos, radius, true, &total, 16, apEntities); - CEntity* pClosestEntity = nil; - float min_dist = 2.0f * radius; - for (int i = 0; i < total; i++) { - float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); - if (dist < min_dist) { - min_dist = dist; - pClosestEntity = apEntities[i]; - } - } - if (!pClosestEntity) { - printf("Failed to find building\n"); - return 0; - } - CBuilding* pReplacedBuilding = ((CBuilding*)pClosestEntity); - pReplacedBuilding->ReplaceWithNewModel(mi2); - CTheScripts::AddToBuildingSwapArray(pReplacedBuilding, mi1, mi2); - return 0; - } - case COMMAND_SWITCH_WORLD_PROCESSING: - CollectParameters(&m_nIp, 1); - CWorld::bProcessCutsceneOnly = ScriptParams[0] == 0; - return 0; - case COMMAND_REMOVE_ALL_PLAYER_WEAPONS: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - pPed->ClearWeapons(); - return 0; - } - case COMMAND_GRAB_CATALINA_HELI: - { - CHeli* pHeli = CHeli::FindPointerToCatalinasHeli(); - ScriptParams[0] = pHeli ? CPools::GetVehiclePool()->GetIndex(pHeli) : -1; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_CLEAR_AREA_OF_CARS: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - CWorld::ClearCarsFromArea(infX, infY, infZ, supX, supY, supZ); - return 0; - } - case COMMAND_SET_ROTATING_GARAGE_DOOR: - CollectParameters(&m_nIp, 1); - CGarages::SetGarageDoorToRotate(ScriptParams[0]); - return 0; - case COMMAND_ADD_SPHERE: - { - CollectParameters(&m_nIp, 4); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float radius = *(float*)&ScriptParams[3]; - CTheScripts::GetActualScriptSphereIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CTheScripts::AddScriptSphere((uintptr)this + m_nIp, pos, radius); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_REMOVE_SPHERE: - CollectParameters(&m_nIp, 1); - CTheScripts::RemoveScriptSphere(ScriptParams[0]); - return 0; - case COMMAND_CATALINA_HELI_FLY_AWAY: - CHeli::MakeCatalinaHeliFlyAway(); - return 0; - case COMMAND_SET_EVERYONE_IGNORE_PLAYER: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - if (ScriptParams[1]) { - pPed->m_pWanted->m_bIgnoredByEveryone = true; - CWorld::StopAllLawEnforcersInTheirTracks(); - } - else { - pPed->m_pWanted->m_bIgnoredByEveryone = false; - } - return 0; - } - case COMMAND_STORE_CAR_CHAR_IS_IN_NO_SAVE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = pPed->bInVehicle ? pPed->m_pMyVehicle : nil; - ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_STORE_CAR_PLAYER_IS_IN_NO_SAVE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CVehicle* pVehicle = pPed->bInVehicle ? pPed->m_pMyVehicle : nil; - ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_IS_PHONE_DISPLAYING_MESSAGE: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(gPhoneInfo.IsMessageBeingDisplayed(ScriptParams[0])); - return 0; - case COMMAND_DISPLAY_ONSCREEN_TIMER_WITH_STRING: - { - script_assert(CTheScripts::ScriptSpace[m_nIp++] == ARGUMENT_GLOBALVAR); - uint16 var = CTheScripts::Read2BytesFromScript(&m_nIp); - wchar* text = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); // ??? - strncpy(onscreen_str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CUserDisplay::OnscnTimer.AddClock(var, onscreen_str); - return 0; - } - case COMMAND_DISPLAY_ONSCREEN_COUNTER_WITH_STRING: - { - script_assert(CTheScripts::ScriptSpace[m_nIp++] == ARGUMENT_GLOBALVAR); - uint16 var = CTheScripts::Read2BytesFromScript(&m_nIp); - CollectParameters(&m_nIp, 1); - wchar* text = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); // ??? - strncpy(onscreen_str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - m_nIp += KEY_LENGTH_IN_SCRIPT; - CUserDisplay::OnscnTimer.AddCounter(var, ScriptParams[0], onscreen_str); - return 0; - } - case COMMAND_CREATE_RANDOM_CAR_FOR_CAR_PARK: - { - CollectParameters(&m_nIp, 4); - if (CCarCtrl::NumRandomCars >= 30) - return 0; - int attempts; - int model = -1; - int index = CGeneral::GetRandomNumberInRange(0, 50); - for (attempts = 0; attempts < 50; attempts++) { - if (model != -1) - break; - model = CStreaming::ms_vehiclesLoaded[index]; - if (model == -1) - continue; - // desperatly want to believe this was inlined :| - CBaseModelInfo* pInfo = CModelInfo::GetModelInfo(model); - script_assert(pInfo->GetModelType() == MITYPE_VEHICLE); - CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)pInfo; - if (pVehicleInfo->m_vehicleType == VEHICLE_TYPE_CAR) { - switch (model) { - case MI_LANDSTAL: - case MI_LINERUN: - case MI_FIRETRUCK: - case MI_TRASH: - case MI_STRETCH: - case MI_MULE: - case MI_AMBULAN: - case MI_FBICAR: - case MI_MRWHOOP: - case MI_BFINJECT: - case MI_CORPSE: - case MI_POLICE: - case MI_ENFORCER: - case MI_SECURICA: - case MI_PREDATOR: - case MI_BUS: - case MI_RHINO: - case MI_BARRACKS: - case MI_TRAIN: - case MI_CHOPPER: - case MI_DODO: - case MI_COACH: - case MI_RCBANDIT: - case MI_BELLYUP: - case MI_MRWONGS: - case MI_MAFIA: - case MI_YARDIE: - case MI_YAKUZA: - case MI_DIABLOS: - case MI_COLUMB: - case MI_HOODS: - case MI_AIRTRAIN: - case MI_DEADDODO: - case MI_SPEEDER: - case MI_REEFER: - case MI_PANLANT: - case MI_FLATBED: - case MI_YANKEE: - case MI_ESCAPE: - case MI_BORGNINE: - case MI_TOYZ: - case MI_GHOST: - case MI_MIAMI_RCBARON: - case MI_MIAMI_RCRAIDER: - model = -1; - break; - case MI_IDAHO: - case MI_STINGER: - case MI_PEREN: - case MI_SENTINEL: - case MI_PATRIOT: - case MI_MANANA: - case MI_INFERNUS: - case MI_BLISTA: - case MI_PONY: - case MI_CHEETAH: - case MI_MOONBEAM: - case MI_ESPERANT: - case MI_TAXI: - case MI_KURUMA: - case MI_BOBCAT: - case MI_BANSHEE: - case MI_CABBIE: - case MI_STALLION: - case MI_RUMPO: - case 151: - case 152: - case 153: - break; - default: - printf("CREATE_RANDOM_CAR_FOR_CAR_PARK - Unknown car model %d\n", CStreaming::ms_vehiclesLoaded[index]); - model = -1; - break; - } - } - else - model = -1; - if (++index >= 50) - index = 0; - } - if (model == -1) - return 0; - CVehicle* car; - if (!CModelInfo::IsBikeModel(model)) - car = new CAutomobile(model, RANDOM_VEHICLE); - CVector pos = *(CVector*)&ScriptParams[0]; - pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel(); - car->SetPosition(pos); - car->SetHeading(DEGTORAD(*(float*)&ScriptParams[3])); - CTheScripts::ClearSpaceForMissionEntity(pos, car); - car->SetStatus(STATUS_ABANDONED); - car->bIsLocked = false; - car->bIsCarParkVehicle = true; - CCarCtrl::JoinCarWithRoadSystem(car); - car->AutoPilot.m_nCarMission = MISSION_NONE; - car->AutoPilot.m_nTempAction = TEMPACT_NONE; - car->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; - car->AutoPilot.m_nCruiseSpeed = car->AutoPilot.m_fMaxTrafficSpeed = 9.0f; - car->AutoPilot.m_nCurrentLane = car->AutoPilot.m_nNextLane = 0; - car->bEngineOn = false; - car->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pos); - CWorld::Add(car); - return 0; - } - case COMMAND_IS_COLLISION_IN_MEMORY: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CCollision::ms_collisionInMemory == ScriptParams[0]); - return 0; - case COMMAND_SET_WANTED_MULTIPLIER: - CollectParameters(&m_nIp, 1); - FindPlayerPed()->m_pWanted->m_fCrimeSensitivity = *(float*)&ScriptParams[0]; - return 0; - case COMMAND_SET_CAMERA_IN_FRONT_OF_PLAYER: - TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString(); - return 0; - case COMMAND_IS_CAR_VISIBLY_DAMAGED: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(pVehicle->bIsDamaged); - return 0; - } - case COMMAND_DOES_OBJECT_EXIST: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CPools::GetObjectPool()->GetAt(ScriptParams[0])); - return 0; - case COMMAND_LOAD_SCENE: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - CTimer::Stop(); - CStreaming::LoadScene(pos); - CTimer::Update(); - return 0; - } - case COMMAND_ADD_STUCK_CAR_CHECK: - { - CollectParameters(&m_nIp, 3); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CTheScripts::StuckCars.AddCarToCheck(ScriptParams[0], *(float*)&ScriptParams[1], ScriptParams[2]); - return 0; - } - case COMMAND_REMOVE_STUCK_CAR_CHECK: - { - CollectParameters(&m_nIp, 1); - CTheScripts::StuckCars.RemoveCarFromCheck(ScriptParams[0]); - return 0; - } - case COMMAND_IS_CAR_STUCK: - CollectParameters(&m_nIp, 1); - UpdateCompareFlag(CTheScripts::StuckCars.HasCarBeenStuckForAWhile(ScriptParams[0])); - return 0; - case COMMAND_LOAD_MISSION_AUDIO: - strncpy(str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - str[i] = tolower(str[i]); - m_nIp += KEY_LENGTH_IN_SCRIPT; - DMAudio.PreloadMissionAudio(str); - return 0; - case COMMAND_HAS_MISSION_AUDIO_LOADED: - UpdateCompareFlag(DMAudio.GetMissionAudioLoadingStatus() == 1); - return 0; - case COMMAND_PLAY_MISSION_AUDIO: - DMAudio.PlayLoadedMissionAudio(); - return 0; - case COMMAND_HAS_MISSION_AUDIO_FINISHED: - UpdateCompareFlag(DMAudio.IsMissionAudioSampleFinished()); - return 0; - case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - int node = ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f, true, true); - *(CVector*)&ScriptParams[0] = ThePaths.m_pathNodes[node].GetPosition(); - *(float*)&ScriptParams[3] = ThePaths.FindNodeOrientationForCarPlacement(node); - StoreParameters(&m_nIp, 4); - return 0; - } - case COMMAND_HAS_IMPORT_GARAGE_SLOT_BEEN_FILLED: - { - CollectParameters(&m_nIp, 2); - UpdateCompareFlag(CGarages::HasImportExportGarageCollectedThisCar(ScriptParams[0], ScriptParams[1] - 1)); - return 0; - } - case COMMAND_CLEAR_THIS_PRINT: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CMessages::ClearThisPrint(text); - return 0; - } - case COMMAND_CLEAR_THIS_BIG_PRINT: - { - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CMessages::ClearThisBigPrint(text); - return 0; - } - case COMMAND_SET_MISSION_AUDIO_POSITION: - { - CollectParameters(&m_nIp, 3); - CVector pos = *(CVector*)&ScriptParams[0]; - DMAudio.SetMissionAudioLocation(pos.x, pos.y, pos.z); - return 0; - } - case COMMAND_ACTIVATE_SAVE_MENU: - FrontEndMenuManager.m_bSaveMenuActive = true; - return 0; - case COMMAND_HAS_SAVE_GAME_FINISHED: - UpdateCompareFlag(!FrontEndMenuManager.m_bMenuActive); - return 0; - case COMMAND_NO_SPECIAL_CAMERA_FOR_THIS_GARAGE: - CollectParameters(&m_nIp, 1); - CGarages::SetLeaveCameraForThisGarage(ScriptParams[0]); - return 0; - case COMMAND_ADD_BLIP_FOR_PICKUP_OLD: - { - CollectParameters(&m_nIp, 3); - CObject* pObject = CPickups::aPickUps[CPickups::GetActualPickupIndex(ScriptParams[0])].m_pObject; - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - ScriptParams[0] = CRadar::SetEntityBlip(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(pObject), ScriptParams[1], (eBlipDisplay)ScriptParams[2]); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_BLIP_FOR_PICKUP: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPickups::aPickUps[CPickups::GetActualPickupIndex(ScriptParams[0])].m_pObject; - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetEntityBlip(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(pObject), 6, BLIP_DISPLAY_BOTH); - CRadar::ChangeBlipScale(handle, 3); - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_ADD_SPRITE_BLIP_FOR_PICKUP: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPickups::aPickUps[CPickups::GetActualPickupIndex(ScriptParams[0])].m_pObject; - CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); - int handle = CRadar::SetEntityBlip(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(pObject), 6, BLIP_DISPLAY_BOTH); - CRadar::SetBlipSprite(handle, ScriptParams[1]); - ScriptParams[0] = handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_PED_DENSITY_MULTIPLIER: - CollectParameters(&m_nIp, 1); - CPopulation::PedDensityMultiplier = *(float*)&ScriptParams[0]; - return 0; - case COMMAND_FORCE_RANDOM_PED_TYPE: - CollectParameters(&m_nIp, 1); - CPopulation::m_AllRandomPedsThisType = ScriptParams[0]; - return 0; - case COMMAND_SET_TEXT_DRAW_BEFORE_FADE: - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bTextBeforeFade = ScriptParams[0] != 0; - return 0; - case COMMAND_GET_COLLECTABLE1S_COLLECTED: - ScriptParams[0] = CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages; - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_REGISTER_EL_BURRO_TIME: - CollectParameters(&m_nIp, 1); - CStats::RegisterElBurroTime(ScriptParams[0]); - return 0; - case COMMAND_SET_SPRITES_DRAW_BEFORE_FADE: - CollectParameters(&m_nIp, 1); - CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_bBeforeFade = ScriptParams[0] != 0; - return 0; - case COMMAND_SET_TEXT_RIGHT_JUSTIFY: - CollectParameters(&m_nIp, 1); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bRightJustify = ScriptParams[0] != 0; - return 0; - case COMMAND_PRINT_HELP: - { - if (CCamera::m_bUseMouse3rdPerson && ( - strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "HELP15", 7) == 0 || - strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "GUN_2A", 7) == 0 || - strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "GUN_3A", 7) == 0 || - strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "GUN_4A", 7) == 0)) { - m_nIp += KEY_LENGTH_IN_SCRIPT; - return 0; - } - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CHud::SetHelpMessage(text, false); - return 0; - } - case COMMAND_CLEAR_HELP: - CHud::SetHelpMessage(nil, false); - return 0; - case COMMAND_FLASH_HUD_OBJECT: - CollectParameters(&m_nIp, 1); - CHud::m_ItemToFlash = ScriptParams[0]; - return 0; - default: - script_assert(0); - } - return -1; -} - -int8 CRunningScript::ProcessCommands1000To1099(int32 command) -{ -#ifdef GTA_PS2 - char tmp[48]; -#endif - switch (command) { - //case COMMAND_FLASH_RADAR_BLIP: - case COMMAND_IS_CHAR_IN_CONTROL: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - UpdateCompareFlag(pPed->IsPedInControl()); - return 0; - } - case COMMAND_SET_GENERATE_CARS_AROUND_CAMERA: - CollectParameters(&m_nIp, 1); - CCarCtrl::bCarsGeneratedAroundCamera = (ScriptParams[0] != 0); - return 0; - case COMMAND_CLEAR_SMALL_PRINTS: - CMessages::ClearSmallMessagesOnly(); - return 0; - case COMMAND_HAS_MILITARY_CRANE_COLLECTED_ALL_CARS: - UpdateCompareFlag(CCranes::HaveAllCarsBeenCollectedByMilitaryCrane()); - return 0; - case COMMAND_SET_UPSIDEDOWN_CAR_NOT_DAMAGED: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); - CAutomobile* pCar = (CAutomobile*)pVehicle; - pCar->bNotDamagedUpsideDown = (ScriptParams[1] != 0); - return 0; - } - case COMMAND_CAN_PLAYER_START_MISSION: - { - CollectParameters(&m_nIp, 1); - CPlayerPed* pPlayerPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPlayerPed); - UpdateCompareFlag(pPlayerPed->IsPedInControl() || pPlayerPed->m_nPedState == PED_DRIVING); - return 0; - } - case COMMAND_MAKE_PLAYER_SAFE_FOR_CUTSCENE: - { - CollectParameters(&m_nIp, 1); -#ifdef MISSION_REPLAY - AllowMissionReplay = 0; - SaveGameForPause(3); -#endif - CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; - CPad::GetPad(ScriptParams[0])->SetDisablePlayerControls(PLAYERCONTROL_CUTSCENE); - pPlayerInfo->MakePlayerSafe(true); - CCutsceneMgr::StartCutsceneProcessing(); - return 0; - } - case COMMAND_USE_TEXT_COMMANDS: - CollectParameters(&m_nIp, 1); - CTheScripts::UseTextCommands = (ScriptParams[0] != 0) ? 2 : 1; - return 0; - case COMMAND_SET_THREAT_FOR_PED_TYPE: - CollectParameters(&m_nIp, 2); - CPedType::AddThreat(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_CLEAR_THREAT_FOR_PED_TYPE: - CollectParameters(&m_nIp, 2); - CPedType::RemoveThreat(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_GET_CAR_COLOURS: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - ScriptParams[0] = pVehicle->m_currentColour1; - ScriptParams[1] = pVehicle->m_currentColour2; - StoreParameters(&m_nIp, 2); - return 0; - } - case COMMAND_SET_ALL_CARS_CAN_BE_DAMAGED: - CollectParameters(&m_nIp, 1); - CWorld::SetAllCarsCanBeDamaged(ScriptParams[0] != 0); - if (!ScriptParams[0]) - CWorld::ExtinguishAllCarFiresInArea(FindPlayerCoors(), 4000.0f); - return 0; - case COMMAND_SET_CAR_CAN_BE_DAMAGED: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - pVehicle->bCanBeDamaged = ScriptParams[1] != 0; - if (!ScriptParams[1]) - pVehicle->ExtinguishCarFire(); - return 0; - } - //case COMMAND_MAKE_PLAYER_UNSAFE: - case COMMAND_LOAD_COLLISION: - { - CollectParameters(&m_nIp, 1); - CTimer::Stop(); - CGame::currLevel = (eLevelName)ScriptParams[0]; - ISLAND_LOADING_IS(LOW) - { - CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); - CStreaming::RemoveUnusedBuildings(CGame::currLevel); - } - CCollision::SortOutCollisionAfterLoad(); - ISLAND_LOADING_ISNT(HIGH) - { - CStreaming::RequestIslands(CGame::currLevel); - CStreaming::LoadAllRequestedModels(true); - } - CTimer::Update(); - return 0; - } - case COMMAND_GET_BODY_CAST_HEALTH: - ScriptParams[0] = CObject::nBodyCastHealth; - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_SET_CHARS_CHATTING: - { - CollectParameters(&m_nIp, 3); - CPed* pPed1 = CPools::GetPedPool()->GetAt(ScriptParams[0]); - CPed* pPed2 = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pPed1 && pPed2); - pPed1->SetChat(pPed2, ScriptParams[2]); - pPed2->SetChat(pPed1, ScriptParams[2]); - return 0; - } - //case COMMAND_MAKE_PLAYER_SAFE: - case COMMAND_SET_CAR_STAYS_IN_CURRENT_LEVEL: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - if (ScriptParams[1]) - pVehicle->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pVehicle->GetPosition()); - else - pVehicle->m_nZoneLevel = LEVEL_GENERIC; - return 0; - } - case COMMAND_SET_CHAR_STAYS_IN_CURRENT_LEVEL: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - if (ScriptParams[1]) - pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); - else - pPed->m_nZoneLevel = LEVEL_GENERIC; - return 0; - } - case COMMAND_REGISTER_4X4_ONE_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4OneTime(ScriptParams[0]); - return 0; - case COMMAND_REGISTER_4X4_TWO_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4TwoTime(ScriptParams[0]); - return 0; - case COMMAND_REGISTER_4X4_THREE_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4ThreeTime(ScriptParams[0]); - return 0; - case COMMAND_REGISTER_4X4_MAYHEM_TIME: - CollectParameters(&m_nIp, 1); - CStats::Register4x4MayhemTime(ScriptParams[0]); - return 0; - case COMMAND_REGISTER_LIFE_SAVED: - CStats::AnotherLifeSavedWithAmbulance(); - return 0; - case COMMAND_REGISTER_CRIMINAL_CAUGHT: - CStats::AnotherCriminalCaught(); - return 0; - case COMMAND_REGISTER_AMBULANCE_LEVEL: - CollectParameters(&m_nIp, 1); - CStats::RegisterLevelAmbulanceMission(ScriptParams[0]); - return 0; - case COMMAND_REGISTER_FIRE_EXTINGUISHED: - CStats::AnotherFireExtinguished(); - return 0; - case COMMAND_TURN_PHONE_ON: - CollectParameters(&m_nIp, 1); - gPhoneInfo.m_aPhones[ScriptParams[0]].m_nState = PHONE_STATE_9; - return 0; - case COMMAND_REGISTER_LONGEST_DODO_FLIGHT: - CollectParameters(&m_nIp, 1); - CStats::RegisterLongestFlightInDodo(ScriptParams[0]); - return 0; - case COMMAND_REGISTER_DEFUSE_BOMB_TIME: - CollectParameters(&m_nIp, 1); - CStats::RegisterTimeTakenDefuseMission(ScriptParams[0]); - return 0; - case COMMAND_SET_TOTAL_NUMBER_OF_KILL_FRENZIES: - CollectParameters(&m_nIp, 1); - CStats::SetTotalNumberKillFrenzies(ScriptParams[0]); - return 0; - case COMMAND_BLOW_UP_RC_BUGGY: - CWorld::Players[CWorld::PlayerInFocus].BlowUpRCBuggy(); - return 0; - case COMMAND_REMOVE_CAR_FROM_CHASE: - CollectParameters(&m_nIp, 1); - CRecordDataForChase::RemoveCarFromChase(ScriptParams[0]); - return 0; - case COMMAND_IS_FRENCH_GAME: - UpdateCompareFlag(CGame::frenchGame); - return 0; - case COMMAND_IS_GERMAN_GAME: - UpdateCompareFlag(CGame::germanGame); - return 0; - case COMMAND_CLEAR_MISSION_AUDIO: - DMAudio.ClearMissionAudio(); - return 0; - case COMMAND_SET_FADE_IN_AFTER_NEXT_ARREST: - CollectParameters(&m_nIp, 1); - CRestart::bFadeInAfterNextArrest = !!ScriptParams[0]; - return 0; - case COMMAND_SET_FADE_IN_AFTER_NEXT_DEATH: - CollectParameters(&m_nIp, 1); - CRestart::bFadeInAfterNextDeath = !!ScriptParams[0]; - return 0; - case COMMAND_SET_GANG_PED_MODEL_PREFERENCE: - CollectParameters(&m_nIp, 2); - CGangs::SetGangPedModelOverride(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_SET_CHAR_USE_PEDNODE_SEEK: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - if (ScriptParams[1]) - pPed->m_pNextPathNode = nil; - pPed->bUsePedNodeSeek = !!ScriptParams[1]; - return 0; - } - case COMMAND_SWITCH_VEHICLE_WEAPONS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->bGunSwitchedOff = !ScriptParams[1]; - return 0; - } - case COMMAND_SET_GET_OUT_OF_JAIL_FREE: - CollectParameters(&m_nIp, 2); - CWorld::Players[ScriptParams[0]].m_bGetOutOfJailFree = !!ScriptParams[1]; - return 0; - case COMMAND_SET_FREE_HEALTH_CARE: - CollectParameters(&m_nIp, 2); - CWorld::Players[ScriptParams[0]].m_bGetOutOfHospitalFree = !!ScriptParams[1]; - return 0; - case COMMAND_IS_CAR_DOOR_CLOSED: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - UpdateCompareFlag(!pVehicle->IsDoorMissing((eDoors)ScriptParams[1]) && pVehicle->IsDoorClosed((eDoors)ScriptParams[1])); - return 0; - } - case COMMAND_LOAD_AND_LAUNCH_MISSION: - return 0; - case COMMAND_LOAD_AND_LAUNCH_MISSION_INTERNAL: - { - CollectParameters(&m_nIp, 1); -#ifdef MISSION_REPLAY - missionRetryScriptIndex = ScriptParams[0]; - if (missionRetryScriptIndex == 19) - CStats::LastMissionPassedName[0] = '\0'; -#endif - CTimer::Suspend(); - int offset = CTheScripts::MultiScriptArray[ScriptParams[0]]; - CFileMgr::ChangeDir("\\"); - int handle = CFileMgr::OpenFile("data\\main.scm", "rb"); - CFileMgr::Seek(handle, offset, 0); - CFileMgr::Read(handle, (const char*)&CTheScripts::ScriptSpace[SIZE_MAIN_SCRIPT], SIZE_MISSION_SCRIPT); - CFileMgr::CloseFile(handle); - CRunningScript* pMissionScript = CTheScripts::StartNewScript(SIZE_MAIN_SCRIPT); - CTimer::Resume(); - pMissionScript->m_bIsMissionScript = true; - pMissionScript->m_bMissionFlag = true; - CTheScripts::bAlreadyRunningAMissionScript = true; - return 0; - } - case COMMAND_SET_OBJECT_DRAW_LAST: - { - CollectParameters(&m_nIp, 2); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - pObject->bDrawLast = !!ScriptParams[1]; - return 0; - } - case COMMAND_GET_AMMO_IN_PLAYER_WEAPON: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CWeapon* pWeaponSlot = &pPed->m_weapons[ScriptParams[1]]; - if (pWeaponSlot->m_eWeaponType == (eWeaponType)ScriptParams[1]) - ScriptParams[0] = pWeaponSlot->m_nAmmoTotal; - else - ScriptParams[0] = 0; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_AMMO_IN_CHAR_WEAPON: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CWeapon* pWeaponSlot = &pPed->m_weapons[ScriptParams[1]]; - if (pWeaponSlot->m_eWeaponType == (eWeaponType)ScriptParams[1]) - ScriptParams[0] = pWeaponSlot->m_nAmmoTotal; - else - ScriptParams[0] = 0; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_REGISTER_KILL_FRENZY_PASSED: - CStats::AnotherKillFrenzyPassed(); - return 0; - case COMMAND_SET_CHAR_SAY: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - switch (ScriptParams[1]) { - case SCRIPT_SOUND_CHUNKY_RUN_SHOUT: - pPed->Say(SOUND_PED_FLEE_RUN); - break; - case SCRIPT_SOUND_SECURITY_GUARD_AWAY_SHOUT: - pPed->Say(SOUND_PED_FLEE_RUN); - break; - case SCRIPT_SOUND_SWAT_PED_SHOUT: - pPed->Say(SOUND_PED_PURSUIT_SWAT); - break; - case SCRIPT_SOUND_AMMUNATION_CHAT_1: - pPed->Say(SOUND_AMMUNATION_WELCOME_1); - break; - case SCRIPT_SOUND_AMMUNATION_CHAT_2: - pPed->Say(SOUND_AMMUNATION_WELCOME_2); - break; - case SCRIPT_SOUND_AMMUNATION_CHAT_3: - pPed->Say(SOUND_AMMUNATION_WELCOME_3); - break; - default: - break; - } - return 0; - } - case COMMAND_SET_NEAR_CLIP: - CollectParameters(&m_nIp, 1); - TheCamera.SetNearClipScript(*(float*)&ScriptParams[0]); - return 0; - case COMMAND_SET_RADIO_CHANNEL: - CollectParameters(&m_nIp, 2); - DMAudio.SetRadioChannel(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_OVERRIDE_HOSPITAL_LEVEL: - CollectParameters(&m_nIp, 1); - CRestart::OverrideHospitalLevel = ScriptParams[0]; - return 0; - case COMMAND_OVERRIDE_POLICE_STATION_LEVEL: - CollectParameters(&m_nIp, 1); - CRestart::OverridePoliceStationLevel = ScriptParams[0]; - return 0; - case COMMAND_FORCE_RAIN: - CollectParameters(&m_nIp, 1); - CWeather::bScriptsForceRain = !!ScriptParams[0]; - return 0; - case COMMAND_DOES_GARAGE_CONTAIN_CAR: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pVehicle); - UpdateCompareFlag(CGarages::IsThisCarWithinGarageArea(ScriptParams[0], pVehicle)); - return 0; - } - case COMMAND_SET_CAR_TRACTION: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - float fTraction = *(float*)&ScriptParams[1]; - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR || pVehicle->m_vehType == VEHICLE_TYPE_BIKE); - if (pVehicle->m_vehType == VEHICLE_TYPE_CAR) - ((CAutomobile*)pVehicle)->m_fTraction = fTraction; - else - // this is certainly not a boat, trane, heli or plane field - //((CBike*)pVehicle)->m_fTraction = fTraction; - *(float*)(((char*)pVehicle) + 1088) = fTraction; - return 0; - } - case COMMAND_ARE_MEASUREMENTS_IN_METRES: -#ifdef USE_MEASUREMENTS_IN_METERS - UpdateCompareFlag(true); -#else - UpdateCompareFlag(false) -#endif - return 0; - case COMMAND_CONVERT_METRES_TO_FEET: - { - CollectParameters(&m_nIp, 1); - float fMeterValue = *(float*)&ScriptParams[0]; - float fFeetValue = fMeterValue / METERS_IN_FOOT; - *(float*)&ScriptParams[0] = fFeetValue; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_MARK_ROADS_BETWEEN_LEVELS: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ThePaths.MarkRoadsBetweenLevelsInArea(infX, supX, infY, supY, infZ, supZ); - return 0; - } - case COMMAND_MARK_PED_ROADS_BETWEEN_LEVELS: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - ThePaths.PedMarkRoadsBetweenLevelsInArea(infX, supX, infY, supY, infZ, supZ); - return 0; - } - case COMMAND_SET_CAR_AVOID_LEVEL_TRANSITIONS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->AutoPilot.m_bStayInCurrentLevel = !!ScriptParams[1]; - return 0; - } - case COMMAND_SET_CHAR_AVOID_LEVEL_TRANSITIONS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pPed); - // not implemented - return 0; - } - case COMMAND_IS_THREAT_FOR_PED_TYPE: - CollectParameters(&m_nIp, 2); - UpdateCompareFlag(CPedType::IsThreat(ScriptParams[0], ScriptParams[1])); - return 0; - case COMMAND_CLEAR_AREA_OF_CHARS: - { - CollectParameters(&m_nIp, 6); - float infX = *(float*)&ScriptParams[0]; - float infY = *(float*)&ScriptParams[1]; - float infZ = *(float*)&ScriptParams[2]; - float supX = *(float*)&ScriptParams[3]; - float supY = *(float*)&ScriptParams[4]; - float supZ = *(float*)&ScriptParams[5]; - if (infX > supX) { - infX = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[0]; - } - if (infY > supY) { - infY = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[1]; - } - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[2]; - } - CWorld::ClearPedsFromArea(infX, infY, infZ, supX, supY, supZ); - return 0; - } - case COMMAND_SET_TOTAL_NUMBER_OF_MISSIONS: - CollectParameters(&m_nIp, 1); - CStats::SetTotalNumberMissions(ScriptParams[0]); - return 0; - case COMMAND_CONVERT_METRES_TO_FEET_INT: - CollectParameters(&m_nIp, 1); - ScriptParams[0] *= FEET_IN_METER; - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_REGISTER_FASTEST_TIME: - CollectParameters(&m_nIp, 2); - CStats::RegisterFastestTime(ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_REGISTER_HIGHEST_SCORE: - CollectParameters(&m_nIp, 2); - CStats::RegisterHighestScore(ScriptParams[0], ScriptParams[1]); - return 0; - //case COMMAND_WARP_CHAR_INTO_CAR_AS_PASSENGER: - //case COMMAND_IS_CAR_PASSENGER_SEAT_FREE: - case COMMAND_GET_CHAR_IN_CAR_PASSENGER_SEAT: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(ScriptParams[1] >= 0 && ScriptParams[1] < ARRAY_SIZE(pVehicle->pPassengers)); - CPed* pPassenger = pVehicle->pPassengers[ScriptParams[1]]; - ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPassenger); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CHAR_IS_CHRIS_CRIMINAL: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bChrisCriminal = !!ScriptParams[1]; - return 0; - } - case COMMAND_START_CREDITS: - CCredits::Start(); - return 0; - case COMMAND_STOP_CREDITS: - CCredits::Stop(); - return 0; - case COMMAND_ARE_CREDITS_FINISHED: - UpdateCompareFlag(CCredits::AreCreditsDone()); - return 0; - case COMMAND_CREATE_SINGLE_PARTICLE: - CollectParameters(&m_nIp, 8); - CParticle::AddParticle((tParticleType)ScriptParams[0], *(CVector*)&ScriptParams[1], - *(CVector*)&ScriptParams[4], nil, *(float*)&ScriptParams[7], 0, 0, 0, 0); - return 0; - case COMMAND_SET_CHAR_IGNORE_LEVEL_TRANSITIONS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - if (ScriptParams[1]) - pPed->m_nZoneLevel = LEVEL_IGNORE; - else - pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); - return 0; - } - case COMMAND_GET_CHASE_CAR: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CRecordDataForChase::TurnChaseCarIntoScriptCar(ScriptParams[0]); - ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); - StoreParameters(&m_nIp, 1); - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CAR); - return 0; - } - case COMMAND_START_BOAT_FOAM_ANIMATION: - CSpecialParticleStuff::StartBoatFoamAnimation(); - return 0; - case COMMAND_UPDATE_BOAT_FOAM_ANIMATION: - { - CollectParameters(&m_nIp, 1); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CSpecialParticleStuff::UpdateBoatFoamAnimation(&pObject->GetMatrix()); - return 0; - } - case COMMAND_SET_MUSIC_DOES_FADE: - CollectParameters(&m_nIp, 1); - TheCamera.m_bIgnoreFadingStuffForMusic = (ScriptParams[0] == 0); - return 0; - case COMMAND_SET_INTRO_IS_PLAYING: - CollectParameters(&m_nIp, 1); - if (ScriptParams[0]) { - CGame::playingIntro = true; - CStreaming::RemoveCurrentZonesModels(); - } else { - CGame::playingIntro = false; - DMAudio.ChangeMusicMode(MUSICMODE_GAME); - int mi; - CModelInfo::GetModelInfo("bridgefukb", &mi); - CStreaming::RequestModel(mi, STREAMFLAGS_DEPENDENCY); - CStreaming::LoadAllRequestedModels(false); - } - return 0; - case COMMAND_SET_PLAYER_HOOKER: - { - CollectParameters(&m_nIp, 2); - CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; - if (ScriptParams[1] < 0) { - pPlayerInfo->m_pHooker = nil; - pPlayerInfo->m_nNextSexFrequencyUpdateTime = 0; - pPlayerInfo->m_nNextSexMoneyUpdateTime = 0; - } else { - CPed* pHooker = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pHooker); - pPlayerInfo->m_pHooker = (CCivilianPed*)pHooker; - pPlayerInfo->m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; - pPlayerInfo->m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; - } - return 0; - } - case COMMAND_PLAY_END_OF_GAME_TUNE: - DMAudio.PlayPreloadedCutSceneMusic(); - return 0; - case COMMAND_STOP_END_OF_GAME_TUNE: - DMAudio.StopCutSceneMusic(); - DMAudio.ChangeMusicMode(MUSICMODE_GAME); - return 0; - case COMMAND_GET_CAR_MODEL: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - ScriptParams[0] = pVehicle->GetModelIndex(); - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_IS_PLAYER_SITTING_IN_CAR: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pVehicle); - UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING && pPed->m_pMyVehicle == pVehicle); - return 0; - } - case COMMAND_IS_PLAYER_SITTING_IN_ANY_CAR: - { - CollectParameters(&m_nIp, 1); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING); - return 0; - } - case COMMAND_SET_SCRIPT_FIRE_AUDIO: - CollectParameters(&m_nIp, 2); - gFireManager.SetScriptFireAudio(ScriptParams[0], !!ScriptParams[1]); - return 0; - case COMMAND_ARE_ANY_CAR_CHEATS_ACTIVATED: - UpdateCompareFlag(CVehicle::bAllDodosCheat || CVehicle::bCheat3); - return 0; - case COMMAND_SET_CHAR_SUFFERS_CRITICAL_HITS: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->bNoCriticalHits = (ScriptParams[0] == 0); - return 0; - } - case COMMAND_IS_PLAYER_LIFTING_A_PHONE: - { - CollectParameters(&m_nIp, 1); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - UpdateCompareFlag(pPed->GetPedState() == PED_MAKE_CALL); - return 0; - } - case COMMAND_IS_CHAR_SITTING_IN_CAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pVehicle); - UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING && pPed->m_pMyVehicle == pVehicle); - return 0; - } - case COMMAND_IS_CHAR_SITTING_IN_ANY_CAR: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING); - return 0; - } - case COMMAND_IS_PLAYER_ON_FOOT: - { - CollectParameters(&m_nIp, 1); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - UpdateCompareFlag(!pPed->bInVehicle && pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && - pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER); - return 0; - } - case COMMAND_IS_CHAR_ON_FOOT: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(!pPed->bInVehicle && pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && - pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER); - return 0; - } -#ifndef GTA_PS2 - default: - script_assert(0); - } - return -1; -} - -int8 CRunningScript::ProcessCommands1100To1199(int32 command) -{ - char tmp[48]; - switch (command) { -#endif - case COMMAND_LOAD_COLLISION_WITH_SCREEN: - CollectParameters(&m_nIp, 1); - CTimer::Stop(); - CGame::currLevel = (eLevelName)ScriptParams[0]; - if (CGame::currLevel != CCollision::ms_collisionInMemory) { - ISLAND_LOADING_IS(LOW) - { - DMAudio.SetEffectsFadeVol(0); - CPad::StopPadsShaking(); - CCollision::LoadCollisionScreen(CGame::currLevel); - DMAudio.Service(); - } - CPopulation::DealWithZoneChange(CCollision::ms_collisionInMemory, CGame::currLevel, false); - - ISLAND_LOADING_IS(LOW) - { - CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); - CStreaming::RemoveUnusedBuildings(CGame::currLevel); - } - CCollision::SortOutCollisionAfterLoad(); - - ISLAND_LOADING_ISNT(HIGH) - CStreaming::RequestIslands(CGame::currLevel); - - ISLAND_LOADING_IS(LOW) - CStreaming::RequestBigBuildings(CGame::currLevel); - - ISLAND_LOADING_ISNT(HIGH) - CStreaming::LoadAllRequestedModels(true); - - ISLAND_LOADING_IS(LOW) - DMAudio.SetEffectsFadeVol(127); - } - CTimer::Update(); - return 0; - case COMMAND_LOAD_SPLASH_SCREEN: - CTheScripts::ReadTextLabelFromScript(&m_nIp, tmp); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - tmp[i] = tolower(tmp[i]); - m_nIp += 8; - LoadSplash(tmp); - return 0; - case COMMAND_SET_CAR_IGNORE_LEVEL_TRANSITIONS: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - if (ScriptParams[1]) - pVehicle->m_nZoneLevel = LEVEL_IGNORE; - else - pVehicle->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pVehicle->GetPosition()); - return 0; - } - case COMMAND_MAKE_CRAIGS_CAR_A_BIT_STRONGER: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); - CAutomobile* pCar = (CAutomobile*)pVehicle; - pCar->bMoreResistantToDamage = ScriptParams[1]; - return 0; - } - case COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CCarCtrl::JoinCarWithRoadSystemGotoCoors(pVehicle, FindPlayerCoors(), false); - return 0; - } - case COMMAND_LOAD_END_OF_GAME_TUNE: - DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE); - printf("Start preload end of game audio\n"); - DMAudio.PreloadCutSceneMusic(STREAMED_SOUND_GAME_COMPLETED); - printf("End preload end of game audio\n"); - return 0; - case COMMAND_ENABLE_PLAYER_CONTROL_CAMERA: - CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_CAMERA); - return 0; -#ifndef GTA_PS2 - // To be precise, on PS2 previous handlers were in 1000-1099 function - // These are "beta" VC commands (with bugs) - case COMMAND_SET_OBJECT_ROTATION: - { - CollectParameters(&m_nIp, 4); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CWorld::Remove(pObject); - pObject->SetOrientation( - DEGTORAD(*(float*)&ScriptParams[1]), - DEGTORAD(*(float*)&ScriptParams[2]), - DEGTORAD(*(float*)&ScriptParams[3])); - pObject->GetMatrix().UpdateRW(); - pObject->UpdateRwFrame(); - CWorld::Add(pObject); - return 0; - } - case COMMAND_GET_DEBUG_CAMERA_COORDINATES: - *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Source; - StoreParameters(&m_nIp, 3); - return 0; - case COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR: - *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Front; - StoreParameters(&m_nIp, 3); - return 0; - case COMMAND_IS_PLAYER_TARGETTING_ANY_CHAR: - { - CollectParameters(&m_nIp, 1); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CEntity* pTarget = pPed->m_pPointGunAt; - UpdateCompareFlag(pTarget && pTarget->IsPed()); - return 0; - } - case COMMAND_IS_PLAYER_TARGETTING_CHAR: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CPed* pTestedPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pTestedPed); - CEntity* pTarget = pPed->m_pPointGunAt; - UpdateCompareFlag(pTarget && pTarget->IsPed() && pTarget == pTestedPed); - return 0; - } - case COMMAND_IS_PLAYER_TARGETTING_OBJECT: - { - CollectParameters(&m_nIp, 2); - CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - CObject* pTestedObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); - script_assert(pTestedObject); - CEntity* pTarget = pPed->m_pPointGunAt; - UpdateCompareFlag(pTarget && pTarget->IsObject() && pTarget == pTestedObject); - return 0; - } - case COMMAND_TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME: - { - CTheScripts::ReadTextLabelFromScript(&m_nIp, tmp); - for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) - tmp[i] = tolower(tmp[i]); - m_nIp += 8; - CRunningScript* pScript = CTheScripts::pActiveScripts; - while (pScript) { - CRunningScript* pNext = pScript->next; - if (strcmp(pScript->m_abScriptName, tmp) == 0) { - pScript->RemoveScriptFromList(&CTheScripts::pActiveScripts); - pScript->AddScriptToList(&CTheScripts::pIdleScripts); - } - pScript = pNext; - } - return 0; - } - case COMMAND_DISPLAY_TEXT_WITH_NUMBER: - { - CollectParameters(&m_nIp, 2); - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtX = *(float*)&ScriptParams[0]; - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtY = *(float*)&ScriptParams[1]; - CollectParameters(&m_nIp, 1); - CMessages::InsertNumberInString(text, ScriptParams[0], -1, -1, -1, -1, -1, - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame++].m_Text); - return 0; - } - case COMMAND_DISPLAY_TEXT_WITH_2_NUMBERS: - { - CollectParameters(&m_nIp, 2); - wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtX = *(float*)&ScriptParams[0]; - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtY = *(float*)&ScriptParams[1]; - CollectParameters(&m_nIp, 2); - CMessages::InsertNumberInString(text, ScriptParams[0], ScriptParams[1], -1, -1, -1, -1, - CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame++].m_Text); - return 0; - } - case COMMAND_FAIL_CURRENT_MISSION: - CTheScripts::FailCurrentMission = 2; - return 0; - case COMMAND_GET_CLOSEST_OBJECT_OF_TYPE: - { - CollectParameters(&m_nIp, 5); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float range = *(float*)&ScriptParams[3]; - int mi = ScriptParams[4] < 0 ? CTheScripts::UsedObjectArray[-ScriptParams[4]].index : ScriptParams[4]; - int16 total; - CEntity* apEntities[16]; - CWorld::FindObjectsOfTypeInRange(mi, pos, range, true, &total, 16, apEntities, false, false, false, true, true); - CEntity* pClosestEntity = nil; - float min_dist = 2.0f * range; - for (int i = 0; i < total; i++) { - float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); - if (dist < min_dist) { - min_dist = dist; - pClosestEntity = apEntities[i]; - } - } - if (pClosestEntity && pClosestEntity->IsDummy()) { - CPopulation::ConvertToRealObject((CDummyObject*)pClosestEntity); - CWorld::FindObjectsOfTypeInRange(mi, pos, range, true, &total, 16, apEntities, false, false, false, true, true); - pClosestEntity = nil; - float min_dist = 2.0f * range; - for (int i = 0; i < total; i++) { - float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); - if (dist < min_dist) { - min_dist = dist; - pClosestEntity = apEntities[i]; - } - } - if (pClosestEntity->IsDummy()) - pClosestEntity = nil; - } - if (pClosestEntity) { - script_assert(pClosestEntity->IsObject()); - CObject* pObject = (CObject*)pClosestEntity; - pObject->ObjectCreatedBy = MISSION_OBJECT; - ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObject); - } else { - ScriptParams[0] = -1; - } - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_PLACE_OBJECT_RELATIVE_TO_OBJECT: - { - CollectParameters(&m_nIp, 5); - CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); - script_assert(pObject); - CObject* pTarget = CPools::GetObjectPool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CVector offset = *(CVector*)&ScriptParams[2]; - CPhysical::PlacePhysicalRelativeToOtherPhysical(pTarget, pObject, offset); - return 0; - } - case COMMAND_SET_ALL_OCCUPANTS_OF_CAR_LEAVE_CAR: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - if (pVehicle->pDriver) { - pVehicle->pDriver->bScriptObjectiveCompleted = false; - pVehicle->pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, pVehicle); - } - for (int i = 0; i < ARRAY_SIZE(pVehicle->pPassengers); i++) - { - if (pVehicle->pPassengers[i]) { - pVehicle->pPassengers[i]->bScriptObjectiveCompleted = false; - pVehicle->pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_CAR, pVehicle); - } - } - return 0; - } - case COMMAND_SET_INTERPOLATION_PARAMETERS: - CollectParameters(&m_nIp, 2); - TheCamera.SetParametersForScriptInterpolation(*(float*)&ScriptParams[0], 50.0f - *(float*)&ScriptParams[0], ScriptParams[1]); - return 0; - case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_TOWARDS_POINT: - { - CollectParameters(&m_nIp, 5); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float destX = *(float*)&ScriptParams[3]; - float destY = *(float*)&ScriptParams[4]; - int32 nid = ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f, true, true); - CPathNode* pNode = &ThePaths.m_pathNodes[nid]; - *(CVector*)&ScriptParams[0] = pNode->GetPosition(); - *(float*)&ScriptParams[3] = ThePaths.FindNodeOrientationForCarPlacementFacingDestination(nid, destX, destY, true); - StoreParameters(&m_nIp, 4); - return 0; - } - case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_AWAY_POINT: - { - CollectParameters(&m_nIp, 5); - CVector pos = *(CVector*)&ScriptParams[0]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - float destX = *(float*)&ScriptParams[3]; - float destY = *(float*)&ScriptParams[4]; - int32 nid = ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f, true, true); - CPathNode* pNode = &ThePaths.m_pathNodes[nid]; - *(CVector*)&ScriptParams[0] = pNode->GetPosition(); - *(float*)&ScriptParams[3] = ThePaths.FindNodeOrientationForCarPlacementFacingDestination(nid, destX, destY, false); - StoreParameters(&m_nIp, 4); - return 0; - } - case COMMAND_GET_DEBUG_CAMERA_POINT_AT: - *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Source + TheCamera.Cams[2].Front; - StoreParameters(&m_nIp, 3); - return 0; - case COMMAND_ATTACH_CHAR_TO_CAR: - // empty implementation - return 0; - case COMMAND_DETACH_CHAR_FROM_CAR: - // empty implementation - return 0; - case COMMAND_SET_CAR_CHANGE_LANE: // for some reason changed in SA - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->AutoPilot.m_bStayInFastLane = !ScriptParams[1]; - return 0; - } - case COMMAND_CLEAR_CHAR_LAST_WEAPON_DAMAGE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - pPed->m_lastWepDam = -1; - return 0; - } - case COMMAND_CLEAR_CAR_LAST_WEAPON_DAMAGE: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - pVehicle->m_nLastWeaponDamage = -1; - return 0; - } - case COMMAND_GET_RANDOM_COP_IN_AREA: - { - CollectParameters(&m_nIp, 4); - int ped_handle = -1; - CVector pos = FindPlayerCoors(); - float x1 = *(float*)&ScriptParams[0]; - float y1 = *(float*)&ScriptParams[1]; - float x2 = *(float*)&ScriptParams[2]; - float y2 = *(float*)&ScriptParams[3]; - int i = CPools::GetPedPool()->GetSize(); - while (--i && ped_handle == -1) { - CPed* pPed = CPools::GetPedPool()->GetSlot(i); - if (!pPed) - continue; - if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) - continue; - if (pPed->m_nPedType != PEDTYPE_COP) - continue; - if (pPed->CharCreatedBy != RANDOM_CHAR) - continue; - if (!pPed->IsPedInControl() && pPed->GetPedState() != PED_DRIVING) - continue; - if (pPed->bRemoveFromWorld) - continue; - if (pPed->bFadeOut) - continue; - if (pPed->bIsLeader || pPed->m_leader) - continue; - if (!pPed->IsWithinArea(x1, y1, x2, y2)) - continue; - if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) - continue; - if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) - continue; - ped_handle = CPools::GetPedPool()->GetIndex(pPed); - CTheScripts::LastRandomPedId = ped_handle; - pPed->CharCreatedBy = MISSION_CHAR; - pPed->bRespondsToThreats = false; - ++CPopulation::ms_nTotalMissionPeds; - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); - } - ScriptParams[0] = ped_handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_RANDOM_COP_IN_ZONE: - { - char zone[KEY_LENGTH_IN_SCRIPT]; - strncpy(zone, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); - int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone); - if (nZone != -1) - m_nIp += KEY_LENGTH_IN_SCRIPT; - CZone* pZone = CTheZones::GetZone(nZone); - int ped_handle = -1; - CVector pos = FindPlayerCoors(); - int i = CPools::GetPedPool()->GetSize(); - while (--i && ped_handle == -1) { - CPed* pPed = CPools::GetPedPool()->GetSlot(i); - if (!pPed) - continue; - if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) - continue; - if (pPed->m_nPedType != PEDTYPE_COP) - continue; - if (pPed->CharCreatedBy != RANDOM_CHAR) - continue; - if (!pPed->IsPedInControl() && pPed->GetPedState() != PED_DRIVING) - continue; - if (pPed->bRemoveFromWorld) - continue; - if (pPed->bFadeOut) - continue; - if (pPed->bIsLeader || pPed->m_leader) - continue; - if (!CTheZones::PointLiesWithinZone(&pPed->GetPosition(), pZone)) - continue; - if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) - continue; - if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) - continue; - ped_handle = CPools::GetPedPool()->GetIndex(pPed); - CTheScripts::LastRandomPedId = ped_handle; - pPed->CharCreatedBy = MISSION_CHAR; - pPed->bRespondsToThreats = false; - ++CPopulation::ms_nTotalMissionPeds; - if (m_bIsMissionScript) - CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); - } - ScriptParams[0] = ped_handle; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_SET_CHAR_OBJ_FLEE_CAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pVehicle); - pPed->bScriptObjectiveCompleted = false; - pPed->SetObjective(OBJECTIVE_FLEE_CAR, pVehicle); - return 0; - } - case COMMAND_GET_DRIVER_OF_CAR: - { - CollectParameters(&m_nIp, 1); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CPed* pDriver = pVehicle->pDriver; - if (pDriver) - ScriptParams[0] = CPools::GetPedPool()->GetIndex(pDriver); - else - ScriptParams[0] = -1; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_NUMBER_OF_FOLLOWERS: - { - CollectParameters(&m_nIp, 1); - CPed* pLeader = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pLeader); - int total = 0; - int i = CPools::GetPedPool()->GetSize(); - while (--i) { - CPed* pPed = CPools::GetPedPool()->GetSlot(i); - if (!pPed) - continue; - if (pPed->m_leader == pLeader) - total++; - } - ScriptParams[0] = total; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GIVE_REMOTE_CONTROLLED_MODEL_TO_PLAYER: - { - CollectParameters(&m_nIp, 6); - CVector pos = *(CVector*)&ScriptParams[1]; - if (pos.z <= MAP_Z_LOW_LIMIT) - pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); - CRemote::GivePlayerRemoteControlledCar(pos.x, pos.y, pos.z, DEGTORAD(*(float*)&ScriptParams[4]), ScriptParams[5]); - return 0; - } - case COMMAND_GET_CURRENT_PLAYER_WEAPON: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - ScriptParams[0] = pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_GET_CURRENT_CHAR_WEAPON: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - ScriptParams[0] = pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType; - StoreParameters(&m_nIp, 1); - return 0; - } - case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_2D: - case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_2D: - case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_2D: - case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D: - case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D: - case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D: - LocateCharObjectCommand(command, &m_nIp); - return 0; - case COMMAND_SET_CAR_HANDBRAKE_TURN_LEFT: // this will be changed in final VC version to a more general SET_TEMP_ACTION - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKETURNLEFT; - pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; - return 0; - } - case COMMAND_SET_CAR_HANDBRAKE_TURN_RIGHT: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKETURNRIGHT; - pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; - return 0; - } - case COMMAND_SET_CAR_HANDBRAKE_STOP: - { - CollectParameters(&m_nIp, 2); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - pVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKESTRAIGHT; - pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; - return 0; - } - case COMMAND_IS_CHAR_ON_ANY_BIKE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(pPed->bInVehicle&& pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE); - return 0; - } - case COMMAND_LOCATE_SNIPER_BULLET_2D: - case COMMAND_LOCATE_SNIPER_BULLET_3D: - LocateSniperBulletCommand(command, &m_nIp); - return 0; - case COMMAND_GET_NUMBER_OF_SEATS_IN_MODEL: - CollectParameters(&m_nIp, 1); - ScriptParams[0] = CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(ScriptParams[0]) + 1; - StoreParameters(&m_nIp, 1); - return 0; - case COMMAND_IS_PLAYER_ON_ANY_BIKE: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; - script_assert(pPed); - UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE); - return 0; - } - case COMMAND_IS_CHAR_LYING_DOWN: - { - CollectParameters(&m_nIp, 1); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - UpdateCompareFlag(pPed->bFallenDown); - return 0; - } - case COMMAND_CAN_CHAR_SEE_DEAD_CHAR: - { - CollectParameters(&m_nIp, 2); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - int pedtype = ScriptParams[1]; - bool can = false; - for (int i = 0; i < pPed->m_numNearPeds; i++) { - CPed* pTestPed = pPed->m_nearPeds[i]; - if (pTestPed->m_fHealth <= 0.0f && pTestPed->m_nPedType == pedtype && pPed->OurPedCanSeeThisOne(pTestPed)) - can = true; - } - UpdateCompareFlag(can); - return 0; - } - case COMMAND_SET_ENTER_CAR_RANGE_MULTIPLIER: - CollectParameters(&m_nIp, 1); -#ifdef FIX_BUGS - CPed::nEnterCarRangeMultiplier = *(float*)&ScriptParams[0]; -#else - CPed::nEnterCarRangeMultiplier = (float)ScriptParams[0]; -#endif - return 0; -#endif -#ifndef GTA3_1_1_PATCH - case COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER: - CollectParameters(&m_nIp, 1); -#ifdef FIX_BUGS - CPed::nThreatReactionRangeMultiplier = *(float*)&ScriptParams[0]; -#else - CPed::nThreatReactionRangeMultiplier = (float)ScriptParams[0]; -#endif - return 0; -#endif - default: - script_assert(0); - } - return -1; -} - -int32 CTheScripts::GetNewUniqueScriptSphereIndex(int32 index) -{ - if (ScriptSphereArray[index].m_Index >= UINT16_MAX - 1) - ScriptSphereArray[index].m_Index = 1; - else - ScriptSphereArray[index].m_Index++; - return (uint16)index | ScriptSphereArray[index].m_Index << 16; -} - -int32 CTheScripts::GetActualScriptSphereIndex(int32 index) -{ - if (index == -1) - return -1; - uint16 check = (uint32)index >> 16; - uint16 array_idx = index & (0xFFFF); - script_assert(array_idx < ARRAY_SIZE(ScriptSphereArray)); - if (check != ScriptSphereArray[array_idx].m_Index) - return -1; - return array_idx; -} - -void CTheScripts::DrawScriptSpheres() -{ - for (int i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++) { - if (ScriptSphereArray[i].m_bInUse) - C3dMarkers::PlaceMarkerSet(ScriptSphereArray[i].m_Id, MARKERTYPE_CYLINDER, ScriptSphereArray[i].m_vecCenter, ScriptSphereArray[i].m_fRadius, - SPHERE_MARKER_R, SPHERE_MARKER_G, SPHERE_MARKER_B, SPHERE_MARKER_A, SPHERE_MARKER_PULSE_PERIOD, SPHERE_MARKER_PULSE_FRACTION, 0); - } -} - -int32 CTheScripts::AddScriptSphere(int32 id, CVector pos, float radius) -{ - int16 i = 0; - for (i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++) { - if (!ScriptSphereArray[i].m_bInUse) - break; - } -#ifdef FIX_BUGS - if (i == MAX_NUM_SCRIPT_SPHERES) - return -1; -#endif - ScriptSphereArray[i].m_bInUse = true; - ScriptSphereArray[i].m_Id = id; - ScriptSphereArray[i].m_vecCenter = pos; - ScriptSphereArray[i].m_fRadius = radius; - return GetNewUniqueScriptSphereIndex(i); -} - -void CTheScripts::RemoveScriptSphere(int32 index) -{ - index = GetActualScriptSphereIndex(index); - if (index == -1) - return; - ScriptSphereArray[index].m_bInUse = false; - ScriptSphereArray[index].m_Id = 0; -} - -void CTheScripts::AddToBuildingSwapArray(CBuilding* pBuilding, int32 old_model, int32 new_model) -{ - int i = 0; - bool found = false; - while (i < MAX_NUM_BUILDING_SWAPS && !found) { - if (BuildingSwapArray[i].m_pBuilding == pBuilding) - found = true; - else - i++; - } - if (found) { - if (BuildingSwapArray[i].m_nOldModel == new_model) { - BuildingSwapArray[i].m_pBuilding = nil; - BuildingSwapArray[i].m_nOldModel = BuildingSwapArray[i].m_nNewModel = -1; - } - else { - BuildingSwapArray[i].m_nNewModel = new_model; - } - } - else { - i = 0; - while (i < MAX_NUM_BUILDING_SWAPS && !found) { - if (BuildingSwapArray[i].m_pBuilding == nil) - found = true; - else - i++; - } - if (found) { - BuildingSwapArray[i].m_pBuilding = pBuilding; - BuildingSwapArray[i].m_nNewModel = new_model; - BuildingSwapArray[i].m_nOldModel = old_model; - } - } -} - -void CTheScripts::AddToInvisibilitySwapArray(CEntity* pEntity, bool remove) -{ - int i = 0; - bool found = false; - while (i < MAX_NUM_INVISIBILITY_SETTINGS && !found) { - if (InvisibilitySettingArray[i] == pEntity) - found = true; - else - i++; - } - if (found) { - if (remove) - InvisibilitySettingArray[i] = nil; - } - else if (!remove) { - i = 0; - while (i < MAX_NUM_INVISIBILITY_SETTINGS && !found) { - if (InvisibilitySettingArray[i] == nil) - found = true; - else - i++; - } - if (found) - InvisibilitySettingArray[i] = pEntity; - } -} - -void CTheScripts::UndoBuildingSwaps() -{ - for (int i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { - if (BuildingSwapArray[i].m_pBuilding) { - BuildingSwapArray[i].m_pBuilding->ReplaceWithNewModel(BuildingSwapArray[i].m_nOldModel); - BuildingSwapArray[i].m_pBuilding = nil; - BuildingSwapArray[i].m_nOldModel = BuildingSwapArray[i].m_nNewModel = -1; - } - } -} - -void CTheScripts::UndoEntityInvisibilitySettings() -{ - for (int i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) { - if (InvisibilitySettingArray[i]) { - InvisibilitySettingArray[i]->bIsVisible = true; - InvisibilitySettingArray[i] = nil; - } - } -} - -void CRunningScript::UpdateCompareFlag(bool flag) -{ - if (m_bNotFlag) - flag = !flag; - if (m_nAndOrState == ANDOR_NONE) { - m_bCondResult = flag; - return; - } - if (m_nAndOrState >= ANDS_1 && m_nAndOrState <= ANDS_8) { - m_bCondResult &= flag; - if (m_nAndOrState == ANDS_1) { - m_nAndOrState = ANDOR_NONE; - return; - } - } - else if (m_nAndOrState >= ORS_1 && m_nAndOrState <= ORS_8) { - m_bCondResult |= flag; - if (m_nAndOrState == ORS_1) { - m_nAndOrState = ANDOR_NONE; - return; - } - } - else { - return; - } - m_nAndOrState--; -} - -void CRunningScript::LocatePlayerCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug, decided = false; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_PLAYER_ANY_MEANS_3D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_3D: - case COMMAND_LOCATE_PLAYER_IN_CAR_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 8 : 6); - CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; - switch (command) { - case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_2D: - case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_2D: - case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_2D: - case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D: - if (!CTheScripts::IsPlayerStopped(pPlayerInfo)) { - result = false; - decided = true; - } - break; - default: - break; - } - X = *(float*)&ScriptParams[1]; - Y = *(float*)&ScriptParams[2]; - if (b3D) { - Z = *(float*)&ScriptParams[3]; - dX = *(float*)&ScriptParams[4]; - dY = *(float*)&ScriptParams[5]; - dZ = *(float*)&ScriptParams[6]; - debug = ScriptParams[7]; - } else { - dX = *(float*)&ScriptParams[3]; - dY = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - if (!decided) { - CVector pos = pPlayerInfo->GetPos(); - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_LOCATE_PLAYER_ANY_MEANS_2D: - case COMMAND_LOCATE_PLAYER_ANY_MEANS_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_2D: - case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D: - result = true; - break; - case COMMAND_LOCATE_PLAYER_ON_FOOT_2D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_2D: - case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D: - result = !pPlayerInfo->m_pPed->bInVehicle; - break; - case COMMAND_LOCATE_PLAYER_IN_CAR_2D: - case COMMAND_LOCATE_PLAYER_IN_CAR_3D: - case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_2D: - case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D: - result = pPlayerInfo->m_pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocatePlayerCharCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_3D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_3D: - case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 6 : 5); - CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CVector pos = pPlayerInfo->GetPos(); - if (pTarget->bInVehicle) { - X = pTarget->m_pMyVehicle->GetPosition().x; - Y = pTarget->m_pMyVehicle->GetPosition().y; - Z = pTarget->m_pMyVehicle->GetPosition().z; - } else { - X = pTarget->GetPosition().x; - Y = pTarget->GetPosition().y; - Z = pTarget->GetPosition().z; - } - dX = *(float*)&ScriptParams[2]; - dY = *(float*)&ScriptParams[3]; - if (b3D) { - dZ = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - else { - debug = ScriptParams[4]; - } - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } - else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_2D: - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_3D: - result = true; - break; - case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_2D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_3D: - result = !pPlayerInfo->m_pPed->bInVehicle; - break; - case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_2D: - case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_3D: - result = pPlayerInfo->m_pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - UpdateCompareFlag(result); - if (debug) -#ifdef FIX_BUGS - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); -#else - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dX, b3D ? Z : MAP_Z_LOW_LIMIT); -#endif - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocatePlayerCarCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D: - case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 6 : 5); - CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; - CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CVector pos = pPlayerInfo->GetPos(); - X = pTarget->GetPosition().x; - Y = pTarget->GetPosition().y; - Z = pTarget->GetPosition().z; - dX = *(float*)&ScriptParams[2]; - dY = *(float*)&ScriptParams[3]; - if (b3D) { - dZ = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - else { - debug = ScriptParams[4]; - } - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } - else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_2D: - case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D: - result = true; - break; - case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_2D: - case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D: - result = !pPlayerInfo->m_pPed->bInVehicle; - break; - case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_2D: - case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D: - result = pPlayerInfo->m_pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocateCharCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug, decided = false; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_3D: - case COMMAND_LOCATE_CHAR_ON_FOOT_3D: - case COMMAND_LOCATE_CHAR_IN_CAR_3D: - case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D: - case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D: - case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 8 : 6); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); - switch (command) { - case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_2D: - case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D: - case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_2D: - case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D: - case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_2D: - case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D: - if (!CTheScripts::IsPedStopped(pPed)) { - result = false; - decided = true; - } - break; - default: - break; - } - X = *(float*)&ScriptParams[1]; - Y = *(float*)&ScriptParams[2]; - if (b3D) { - Z = *(float*)&ScriptParams[3]; - dX = *(float*)&ScriptParams[4]; - dY = *(float*)&ScriptParams[5]; - dZ = *(float*)&ScriptParams[6]; - debug = ScriptParams[7]; - } - else { - dX = *(float*)&ScriptParams[3]; - dY = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - if (!decided) { - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } - else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_2D: - case COMMAND_LOCATE_CHAR_ANY_MEANS_3D: - case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_2D: - case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D: - result = true; - break; - case COMMAND_LOCATE_CHAR_ON_FOOT_2D: - case COMMAND_LOCATE_CHAR_ON_FOOT_3D: - case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_2D: - case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D: - result = !pPed->bInVehicle; - break; - case COMMAND_LOCATE_CHAR_IN_CAR_2D: - case COMMAND_LOCATE_CHAR_IN_CAR_3D: - case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_2D: - case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D: - result = pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocateCharCharCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_3D: - case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_3D: - case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 6 : 5); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); - if (pTarget->bInVehicle) { - X = pTarget->m_pMyVehicle->GetPosition().x; - Y = pTarget->m_pMyVehicle->GetPosition().y; - Z = pTarget->m_pMyVehicle->GetPosition().z; - } - else { - X = pTarget->GetPosition().x; - Y = pTarget->GetPosition().y; - Z = pTarget->GetPosition().z; - } - dX = *(float*)&ScriptParams[2]; - dY = *(float*)&ScriptParams[3]; - if (b3D) { - dZ = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - else { - debug = ScriptParams[4]; - } - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } - else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_2D: - case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_3D: - result = true; - break; - case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_2D: - case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_3D: - result = !pPed->bInVehicle; - break; - case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_2D: - case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_3D: - result = pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - UpdateCompareFlag(result); - if (debug) -#ifdef FIX_BUGS - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); -#else - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dX, b3D ? Z : MAP_Z_LOW_LIMIT); -#endif - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocateCharCarCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D: - case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D: - case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 6 : 5); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); - X = pTarget->GetPosition().x; - Y = pTarget->GetPosition().y; - Z = pTarget->GetPosition().z; - dX = *(float*)&ScriptParams[2]; - dY = *(float*)&ScriptParams[3]; - if (b3D) { - dZ = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - else { - debug = ScriptParams[4]; - } - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } - else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_2D: - case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D: - result = true; - break; - case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_2D: - case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D: - result = !pPed->bInVehicle; - break; - case COMMAND_LOCATE_CHAR_IN_CAR_CAR_2D: - case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D: - result = pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocateCharObjectCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D: - case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D: - case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 6 : 5); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CObject* pTarget = CPools::GetObjectPool()->GetAt(ScriptParams[1]); - script_assert(pTarget); - CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); - X = pTarget->GetPosition().x; - Y = pTarget->GetPosition().y; - Z = pTarget->GetPosition().z; - dX = *(float*)&ScriptParams[2]; - dY = *(float*)&ScriptParams[3]; - if (b3D) { - dZ = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - else { - debug = ScriptParams[4]; - } - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } - else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_2D: - case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D: - result = true; - break; - case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_2D: - case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D: - result = !pPed->bInVehicle; - break; - case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_2D: - case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D: - result = pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocateCarCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug, decided = false; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_CAR_3D: - case COMMAND_LOCATE_STOPPED_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 8 : 6); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CVector pos = pVehicle->GetPosition(); - switch (command) { - case COMMAND_LOCATE_STOPPED_CAR_2D: - case COMMAND_LOCATE_STOPPED_CAR_3D: - if (!CTheScripts::IsVehicleStopped(pVehicle)) { - result = false; - decided = true; - } - break; - default: - break; - } - X = *(float*)&ScriptParams[1]; - Y = *(float*)&ScriptParams[2]; - if (b3D) { - Z = *(float*)&ScriptParams[3]; - dX = *(float*)&ScriptParams[4]; - dY = *(float*)&ScriptParams[5]; - dZ = *(float*)&ScriptParams[6]; - debug = ScriptParams[7]; - } - else { - dX = *(float*)&ScriptParams[3]; - dY = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - if (!decided) { - result = false; - bool in_area; - if (b3D) { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y && - Z - dZ <= pos.z && - Z + dZ >= pos.z; - } - else { - in_area = X - dX <= pos.x && - X + dX >= pos.x && - Y - dY <= pos.y && - Y + dY >= pos.y; - } - result = in_area; - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::LocateSniperBulletCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug; - float X, Y, Z, dX, dY, dZ; - switch (command) { - case COMMAND_LOCATE_SNIPER_BULLET_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 7 : 5); - X = *(float*)&ScriptParams[0]; - Y = *(float*)&ScriptParams[1]; - if (b3D) { - Z = *(float*)&ScriptParams[2]; - dX = *(float*)&ScriptParams[3]; - dY = *(float*)&ScriptParams[4]; - dZ = *(float*)&ScriptParams[5]; - debug = ScriptParams[6]; - } - else { - dX = *(float*)&ScriptParams[2]; - dY = *(float*)&ScriptParams[3]; - debug = ScriptParams[4]; - } - result = CBulletInfo::TestForSniperBullet(X - dX, X + dX, Y - dY, Y + dY, b3D ? Z - dZ : -1000.0f, b3D ? Z + dZ : 1000.0f); - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); - else - CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); - } -} - -void CRunningScript::PlayerInAreaCheckCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug, decided = false; - float infX, infY, infZ, supX, supY, supZ; - switch (command) { - case COMMAND_IS_PLAYER_IN_AREA_3D: - case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 8 : 6); - CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; - switch (command) { - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_2D: - if (!CTheScripts::IsPlayerStopped(pPlayerInfo)) { - result = false; - decided = true; - } - break; - default: - break; - } - infX = *(float*)&ScriptParams[1]; - infY = *(float*)&ScriptParams[2]; - if (b3D) { - infZ = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[6]; - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[6]; - supZ = *(float*)&ScriptParams[3]; - } - debug = ScriptParams[7]; - } - else { - supX = *(float*)&ScriptParams[3]; - supY = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - if (infX > supX) { - float tmp = infX; - infX = supX; - supX = tmp; - } - if (infY > supY) { - float tmp = infY; - infY = supY; - supY = tmp; - } - if (!decided) { - CVector pos = pPlayerInfo->GetPos(); - result = false; - bool in_area; - if (b3D) { - in_area = infX <= pos.x && - supX >= pos.x && - infY <= pos.y && - supY >= pos.y && - infZ <= pos.z && - supZ >= pos.z; - } - else { - in_area = infX <= pos.x && - supX >= pos.x && - infY <= pos.y && - supY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_IS_PLAYER_IN_AREA_2D: - case COMMAND_IS_PLAYER_IN_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: - result = true; - break; - case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: - result = !pPlayerInfo->m_pPed->bInVehicle; - break; - case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: - result = pPlayerInfo->m_pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, infX, infY, supX, supY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); - else - CTheScripts::DrawDebugSquare(infX, infY, supX, supY); - } -} - -void CRunningScript::PlayerInAngledAreaCheckCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug, decided = false; - float infX, infY, infZ, supX, supY, supZ, side2length; - switch (command) { - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_3D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 9 : 7); - CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; - switch (command) { - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_2D: - if (!CTheScripts::IsPlayerStopped(pPlayerInfo)) { - result = false; - decided = true; - } - break; - default: - break; - } - infX = *(float*)&ScriptParams[1]; - infY = *(float*)&ScriptParams[2]; - if (b3D) { - infZ = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[6]; - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[6]; - supZ = *(float*)&ScriptParams[3]; - } - side2length = *(float*)&ScriptParams[7]; - debug = ScriptParams[8]; - } - else { - supX = *(float*)&ScriptParams[3]; - supY = *(float*)&ScriptParams[4]; - side2length = *(float*)&ScriptParams[5]; - debug = ScriptParams[6]; - } - float initAngle = CGeneral::GetRadianAngleBetweenPoints(infX, infY, supX, supY) + HALFPI; - while (initAngle < 0.0f) - initAngle += TWOPI; - while (initAngle > TWOPI) - initAngle -= TWOPI; - // it looks like the idea is to use a rectangle using the diagonal of the rectangle as - // the side of new rectangle, with "length" being the length of second side - float rotatedSupX = supX + side2length * sin(initAngle); - float rotatedSupY = supY - side2length * cos(initAngle); - float rotatedInfX = infX + side2length * sin(initAngle); - float rotatedInfY = infY - side2length * cos(initAngle); - float side1X = supX - infX; - float side1Y = supY - infY; - float side1Length = CVector2D(side1X, side1Y).Magnitude(); - float side2X = rotatedInfX - infX; - float side2Y = rotatedInfY - infY; - float side2Length = CVector2D(side2X, side2Y).Magnitude(); // == side2length? - if (!decided) { - CVector pos = pPlayerInfo->GetPos(); - result = false; - float X = pos.x - infX; - float Y = pos.y - infY; - float positionAlongSide1 = X * side1X / side1Length + Y * side1Y / side1Length; - bool in_area = false; - if (positionAlongSide1 >= 0.0f && positionAlongSide1 <= side1Length) { - float positionAlongSide2 = X * side2X / side2Length + Y * side2Y / side2Length; - if (positionAlongSide2 >= 0.0f && positionAlongSide2 <= side2Length) { - in_area = !b3D || pos.z >= infZ && pos.z <= supZ; - } - } - - if (in_area) { - switch (command) { - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_2D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: - result = true; - break; - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: - result = !pPlayerInfo->m_pPed->bInVehicle; - break; - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_3D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_2D: - case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: - result = pPlayerInfo->m_pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantAngledArea((uintptr)this + m_nIp, infX, infY, supX, supY, - rotatedSupX, rotatedSupY, rotatedInfX, rotatedInfY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugAngledCube(infX, infY, infZ, supX, supY, supZ, - rotatedSupX, rotatedSupY, rotatedInfX, rotatedInfY); - else - CTheScripts::DrawDebugAngledSquare(infX, infY, supX, supY, - rotatedSupX, rotatedSupY, rotatedInfX, rotatedInfY); - } -} - -void CRunningScript::CharInAreaCheckCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug, decided = false; - float infX, infY, infZ, supX, supY, supZ; - switch (command) { - case COMMAND_IS_CHAR_IN_AREA_3D: - case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_CHAR_IN_AREA_IN_CAR_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 8 : 6); - CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); - script_assert(pPed); - CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); - switch (command) { - case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_2D: - if (!CTheScripts::IsPedStopped(pPed)) { - result = false; - decided = true; - } - break; - default: - break; - } - infX = *(float*)&ScriptParams[1]; - infY = *(float*)&ScriptParams[2]; - if (b3D) { - infZ = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[6]; - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[6]; - supZ = *(float*)&ScriptParams[3]; - } - debug = ScriptParams[7]; - } - else { - supX = *(float*)&ScriptParams[3]; - supY = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - if (infX > supX) { - float tmp = infX; - infX = supX; - supX = tmp; - } - if (infY > supY) { - float tmp = infY; - infY = supY; - supY = tmp; - } - if (!decided) { - result = false; - bool in_area; - if (b3D) { - in_area = infX <= pos.x && - supX >= pos.x && - infY <= pos.y && - supY >= pos.y && - infZ <= pos.z && - supZ >= pos.z; - } - else { - in_area = infX <= pos.x && - supX >= pos.x && - infY <= pos.y && - supY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_IS_CHAR_IN_AREA_2D: - case COMMAND_IS_CHAR_IN_AREA_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: - result = true; - break; - case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: - result = !pPed->bInVehicle; - break; - case COMMAND_IS_CHAR_IN_AREA_IN_CAR_2D: - case COMMAND_IS_CHAR_IN_AREA_IN_CAR_3D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_2D: - case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: - result = pPed->bInVehicle; - break; - default: - script_assert(false); - break; - } - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, infX, infY, supX, supY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); - else - CTheScripts::DrawDebugSquare(infX, infY, supX, supY); - } -} - -void CRunningScript::CarInAreaCheckCommand(int32 command, uint32* pIp) -{ - bool b3D, result, debug, decided = false; - float infX, infY, infZ, supX, supY, supZ; - switch (command) { - case COMMAND_IS_CAR_IN_AREA_3D: - case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: - b3D = true; - break; - default: - b3D = false; - break; - } - CollectParameters(pIp, b3D ? 8 : 6); - CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); - script_assert(pVehicle); - CVector pos = pVehicle->GetPosition(); - switch (command) { - case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: - case COMMAND_IS_CAR_STOPPED_IN_AREA_2D: - if (!CTheScripts::IsVehicleStopped(pVehicle)) { - result = false; - decided = true; - } - break; - default: - break; - } - infX = *(float*)&ScriptParams[1]; - infY = *(float*)&ScriptParams[2]; - if (b3D) { - infZ = *(float*)&ScriptParams[3]; - supX = *(float*)&ScriptParams[4]; - supY = *(float*)&ScriptParams[5]; - supZ = *(float*)&ScriptParams[6]; - if (infZ > supZ) { - infZ = *(float*)&ScriptParams[6]; - supZ = *(float*)&ScriptParams[3]; - } - debug = ScriptParams[7]; - } - else { - supX = *(float*)&ScriptParams[3]; - supY = *(float*)&ScriptParams[4]; - debug = ScriptParams[5]; - } - if (infX > supX) { - float tmp = infX; - infX = supX; - supX = tmp; - } - if (infY > supY) { - float tmp = infY; - infY = supY; - supY = tmp; - } - if (!decided) { - result = false; - bool in_area; - if (b3D) { - in_area = infX <= pos.x && - supX >= pos.x && - infY <= pos.y && - supY >= pos.y && - infZ <= pos.z && - supZ >= pos.z; - } - else { - in_area = infX <= pos.x && - supX >= pos.x && - infY <= pos.y && - supY >= pos.y; - } - if (in_area) { - switch (command) { - case COMMAND_IS_CAR_IN_AREA_2D: - case COMMAND_IS_CAR_IN_AREA_3D: - case COMMAND_IS_CAR_STOPPED_IN_AREA_2D: - case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: - result = true; - break; - default: - script_assert(false); - break; - } - } - } - UpdateCompareFlag(result); - if (debug) - CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, infX, infY, supX, supY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); - if (CTheScripts::DbgFlag) { - if (b3D) - CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); - else - CTheScripts::DrawDebugSquare(infX, infY, supX, supY); - } -} - -void CRunningScript::DoDeatharrestCheck() -{ - if (!m_bDeatharrestEnabled) - return; - if (!CTheScripts::IsPlayerOnAMission()) - return; - CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus]; - if (!pPlayer->IsRestartingAfterDeath() && !pPlayer->IsRestartingAfterArrest() && !CTheScripts::UpsideDownCars.AreAnyCarsUpsideDown()) - return; -#ifdef MISSION_REPLAY - if (AllowMissionReplay != 0) - return; - if (CanAllowMissionReplay()) - AllowMissionReplay = 1; -#endif - script_assert(m_nStackPointer > 0); - while (m_nStackPointer > 1) - --m_nStackPointer; - m_nIp = m_anStack[--m_nStackPointer]; - int16 messageId; - if (pPlayer->IsRestartingAfterDeath()) - messageId = 0; - else if (pPlayer->IsRestartingAfterArrest()) - messageId = 5; - else - messageId = 10; - messageId += CGeneral::GetRandomNumberInRange(0, 5); - bool found = false; - for (int16 contact = 0; !found && contact < MAX_NUM_CONTACTS; contact++) { - int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact]; - if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) { - messageId += CTheScripts::BaseBriefIdForContact[contact]; - found = true; - } - } - if (!found) - messageId = 8001; - char tmp[16]; - sprintf(tmp, "%d", messageId); - CMessages::ClearSmallMessagesOnly(); - wchar* text = TheText.Get(tmp); - // ...and do nothing about it - *(int32*)&CTheScripts::ScriptSpace[CTheScripts::OnAMissionFlag] = 0; - m_bDeatharrestExecuted = true; - m_nWakeTime = 0; -} - -int16 CRunningScript::GetPadState(uint16 pad, uint16 button) -{ - CPad* pPad = CPad::GetPad(pad); - switch (button) { - case 0: return pPad->NewState.LeftStickX; - case 1: return pPad->NewState.LeftStickY; - case 2: return pPad->NewState.RightStickX; - case 3: return pPad->NewState.RightStickY; - case 4: return pPad->NewState.LeftShoulder1; - case 5: return pPad->NewState.LeftShoulder2; - case 6: return pPad->NewState.RightShoulder1; - case 7: return pPad->NewState.RightShoulder2; - case 8: return pPad->NewState.DPadUp; - case 9: return pPad->NewState.DPadDown; - case 10: return pPad->NewState.DPadLeft; - case 11: return pPad->NewState.DPadRight; - case 12: return pPad->NewState.Start; - case 13: return pPad->NewState.Select; - case 14: return pPad->NewState.Square; - case 15: return pPad->NewState.Triangle; - case 16: return pPad->NewState.Cross; - case 17: return pPad->NewState.Circle; - case 18: return pPad->NewState.LeftShock; - case 19: return pPad->NewState.RightShock; - default: break; - } - return 0; -} - -void CTheScripts::PrintListSizes() -{ - int active = 0; - int idle = 0; - - for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext()) - active++; - for (CRunningScript* pScript = pIdleScripts; pScript; pScript = pScript->GetNext()) - idle++; - - debug("active: %d, idle: %d", active, idle); -} - -uint32 DbgLineColour = 0x0000FFFF; // r = 0, g = 0, b = 255, a = 255 - -void CTheScripts::DrawDebugSquare(float infX, float infY, float supX, float supY) -{ - CColPoint tmpCP; - CEntity* tmpEP; - CVector p1, p2, p3, p4; - p1 = CVector(infX, infY, -1000.0f); - CWorld::ProcessVerticalLine(p1, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p1.z = 2.0f + tmpCP.point.z; - p2 = CVector(supX, supY, -1000.0f); - CWorld::ProcessVerticalLine(p2, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p2.z = 2.0f + tmpCP.point.z; - p3 = CVector(infX, supY, -1000.0f); - CWorld::ProcessVerticalLine(p3, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p3.z = 2.0f + tmpCP.point.z; - p4 = CVector(supX, infY, -1000.0f); - CWorld::ProcessVerticalLine(p4, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p4.z = 2.0f + tmpCP.point.z; - CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(p3.x, p3.y, p3.z, p4.x, p4.y, p4.z, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(p4.x, p4.y, p4.z, p1.x, p1.y, p1.z, DbgLineColour, DbgLineColour); -} - -void CTheScripts::DrawDebugAngledSquare(float infX, float infY, float supX, float supY, float rotSupX, float rotSupY, float rotInfX, float rotInfY) -{ - CColPoint tmpCP; - CEntity* tmpEP; - CVector p1, p2, p3, p4; - p1 = CVector(infX, infY, -1000.0f); - CWorld::ProcessVerticalLine(p1, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p1.z = 2.0f + tmpCP.point.z; - p2 = CVector(supX, supY, -1000.0f); - CWorld::ProcessVerticalLine(p2, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p2.z = 2.0f + tmpCP.point.z; - p3 = CVector(rotSupX, rotSupY, -1000.0f); - CWorld::ProcessVerticalLine(p3, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p3.z = 2.0f + tmpCP.point.z; - p4 = CVector(rotInfX, rotInfY, -1000.0f); - CWorld::ProcessVerticalLine(p4, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); - p4.z = 2.0f + tmpCP.point.z; - CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(p3.x, p3.y, p3.z, p4.x, p4.y, p4.z, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(p4.x, p4.y, p4.z, p1.x, p1.y, p1.z, DbgLineColour, DbgLineColour); -} - -void CTheScripts::DrawDebugCube(float infX, float infY, float infZ, float supX, float supY, float supZ) -{ - CTheScripts::ScriptDebugLine3D(infX, infY, infZ, supX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, infY, infZ, supX, supY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, supY, infZ, infX, supY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(infX, supY, infZ, infX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(infX, infY, supZ, supX, infY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, infY, supZ, supX, supY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, supY, supZ, infX, supY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(infX, supY, supZ, infX, infY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(infX, infY, supZ, infX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, infY, supZ, supX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, supY, supZ, supX, supY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(infX, supY, supZ, infX, supY, infZ, DbgLineColour, DbgLineColour); -} - -void CTheScripts::DrawDebugAngledCube(float infX, float infY, float infZ, float supX, float supY, float supZ, float rotSupX, float rotSupY, float rotInfX, float rotInfY) -{ - CTheScripts::ScriptDebugLine3D(infX, infY, infZ, supX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, infY, infZ, rotSupX, rotSupY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(rotSupX, rotSupY, infZ, rotInfX, rotInfY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(rotInfX, rotInfY, infZ, infX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(infX, infY, supZ, supX, infY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, infY, supZ, rotSupX, rotSupY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(rotSupX, rotSupY, rotInfX, rotInfY, supY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(rotInfX, rotInfY, supZ, infX, infY, supZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(infX, infY, supZ, infX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(supX, infY, supZ, supX, infY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(rotSupX, rotSupY, supZ, rotSupX, rotSupY, infZ, DbgLineColour, DbgLineColour); - CTheScripts::ScriptDebugLine3D(rotInfX, rotInfY, supZ, rotInfX, rotInfY, infZ, DbgLineColour, DbgLineColour); -} - -void CTheScripts::ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, uint32 col, uint32 col2) -{ - if (NumScriptDebugLines >= MAX_NUM_STORED_LINES) - return; - aStoredLines[NumScriptDebugLines].vecInf = CVector(x1, y1, z1); - aStoredLines[NumScriptDebugLines].vecSup = CVector(x2, y2, z2); - aStoredLines[NumScriptDebugLines].color1 = col; - aStoredLines[NumScriptDebugLines++].color2 = col2; -} - -void CTheScripts::RenderTheScriptDebugLines() -{ - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)1); - for (int i = 0; i < NumScriptDebugLines; i++) { - CLines::RenderLineWithClipping( - aStoredLines[i].vecInf.x, - aStoredLines[i].vecInf.y, - aStoredLines[i].vecInf.z, - aStoredLines[i].vecSup.x, - aStoredLines[i].vecSup.y, - aStoredLines[i].vecSup.z, - aStoredLines[i].color1, - aStoredLines[i].color2); - } - NumScriptDebugLines = 0; - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)0); -} - -#define SCRIPT_DATA_SIZE sizeof(CTheScripts::OnAMissionFlag) + sizeof(CTheScripts::BaseBriefIdForContact) + sizeof(CTheScripts::OnAMissionForContactFlag) +\ - sizeof(CTheScripts::CollectiveArray) + 4 * sizeof(uint32) * MAX_NUM_BUILDING_SWAPS + 2 * sizeof(uint32) * MAX_NUM_INVISIBILITY_SETTINGS + 5 * sizeof(uint32) - -void CTheScripts::SaveAllScripts(uint8* buf, uint32* size) -{ -INITSAVEBUF - uint32 varSpace = GetSizeOfVariableSpace(); - uint32 runningScripts = 0; - for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext()) - runningScripts++; - *size = CRunningScript::nSaveStructSize * runningScripts + varSpace + SCRIPT_DATA_SIZE + SAVE_HEADER_SIZE + 3 * sizeof(uint32); - WriteSaveHeader(buf, 'S', 'C', 'R', '\0', *size - SAVE_HEADER_SIZE); - WriteSaveBuf(buf, varSpace); - for (uint32 i = 0; i < varSpace; i++) - WriteSaveBuf(buf, ScriptSpace[i]); -#ifdef CHECK_STRUCT_SIZES - static_assert(SCRIPT_DATA_SIZE == 968, "CTheScripts::SaveAllScripts"); -#endif - uint32 script_data_size = SCRIPT_DATA_SIZE; - WriteSaveBuf(buf, script_data_size); - WriteSaveBuf(buf, OnAMissionFlag); - for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) { - WriteSaveBuf(buf, OnAMissionForContactFlag[i]); - WriteSaveBuf(buf, BaseBriefIdForContact[i]); - } - for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++) - WriteSaveBuf(buf, CollectiveArray[i]); - WriteSaveBuf(buf, NextFreeCollectiveIndex); - for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { - CBuilding* pBuilding = BuildingSwapArray[i].m_pBuilding; - uint32 type, handle; - if (!pBuilding) { - type = 0; - handle = 0; - } else if (pBuilding->GetIsATreadable()) { - type = 1; - handle = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pBuilding) + 1; - } else { - type = 2; - handle = CPools::GetBuildingPool()->GetJustIndex(pBuilding) + 1; - } - WriteSaveBuf(buf, type); - WriteSaveBuf(buf, handle); - WriteSaveBuf(buf, BuildingSwapArray[i].m_nNewModel); - WriteSaveBuf(buf, BuildingSwapArray[i].m_nOldModel); - } - for (uint32 i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) { - CEntity* pEntity = InvisibilitySettingArray[i]; - uint32 type, handle; - if (!pEntity) { - type = 0; - handle = 0; - } else { - switch (pEntity->GetType()) { - case ENTITY_TYPE_BUILDING: - if (((CBuilding*)pEntity)->GetIsATreadable()) { - type = 1; - handle = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pEntity) + 1; - } else { - type = 2; - handle = CPools::GetBuildingPool()->GetJustIndex((CBuilding*)pEntity) + 1; - } - break; - case ENTITY_TYPE_OBJECT: - type = 3; - handle = CPools::GetObjectPool()->GetJustIndex((CObject*)pEntity) + 1; - break; - case ENTITY_TYPE_DUMMY: - type = 4; - handle = CPools::GetDummyPool()->GetJustIndex((CDummy*)pEntity) + 1; - default: break; - } - } - WriteSaveBuf(buf, type); - WriteSaveBuf(buf, handle); - } - WriteSaveBuf(buf, bUsingAMultiScriptFile); - WriteSaveBuf(buf, (uint8)0); - WriteSaveBuf(buf, (uint16)0); - WriteSaveBuf(buf, MainScriptSize); - WriteSaveBuf(buf, LargestMissionScriptSize); - WriteSaveBuf(buf, NumberOfMissionScripts); - WriteSaveBuf(buf, (uint16)0); - WriteSaveBuf(buf, runningScripts); - for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext()) - pScript->Save(buf); -VALIDATESAVEBUF(*size) -} - -void CTheScripts::LoadAllScripts(uint8* buf, uint32 size) -{ - Init(); -INITSAVEBUF - CheckSaveHeader(buf, 'S', 'C', 'R', '\0', size - SAVE_HEADER_SIZE); - uint32 varSpace = ReadSaveBuf(buf); - for (uint32 i = 0; i < varSpace; i++) - ScriptSpace[i] = ReadSaveBuf(buf); - script_assert(ReadSaveBuf(buf) == SCRIPT_DATA_SIZE); - OnAMissionFlag = ReadSaveBuf(buf); - for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) { - OnAMissionForContactFlag[i] = ReadSaveBuf(buf); - BaseBriefIdForContact[i] = ReadSaveBuf(buf); - } - for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++) - CollectiveArray[i] = ReadSaveBuf(buf); - NextFreeCollectiveIndex = ReadSaveBuf(buf); - for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { - uint32 type = ReadSaveBuf(buf); - uint32 handle = ReadSaveBuf(buf); - switch (type) { - case 0: - BuildingSwapArray[i].m_pBuilding = nil; - break; - case 1: - BuildingSwapArray[i].m_pBuilding = CPools::GetTreadablePool()->GetSlot(handle - 1); - break; - case 2: - BuildingSwapArray[i].m_pBuilding = CPools::GetBuildingPool()->GetSlot(handle - 1); - break; - default: - script_assert(false); - } - BuildingSwapArray[i].m_nNewModel = ReadSaveBuf(buf); - BuildingSwapArray[i].m_nOldModel = ReadSaveBuf(buf); - if (BuildingSwapArray[i].m_pBuilding) - BuildingSwapArray[i].m_pBuilding->ReplaceWithNewModel(BuildingSwapArray[i].m_nNewModel); - } - for (uint32 i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) { - uint32 type = ReadSaveBuf(buf); - uint32 handle = ReadSaveBuf(buf); - switch (type) { - case 0: - InvisibilitySettingArray[i] = nil; - break; - case 1: - InvisibilitySettingArray[i] = CPools::GetTreadablePool()->GetSlot(handle - 1); - break; - case 2: - InvisibilitySettingArray[i] = CPools::GetBuildingPool()->GetSlot(handle - 1); - break; - case 3: - InvisibilitySettingArray[i] = CPools::GetObjectPool()->GetSlot(handle - 1); - break; - case 4: - InvisibilitySettingArray[i] = CPools::GetDummyPool()->GetSlot(handle - 1); - break; - default: - script_assert(false); - } - if (InvisibilitySettingArray[i]) - InvisibilitySettingArray[i]->bIsVisible = false; - } - script_assert(ReadSaveBuf(buf) == bUsingAMultiScriptFile); - ReadSaveBuf(buf); - ReadSaveBuf(buf); - script_assert(ReadSaveBuf(buf) == MainScriptSize); - script_assert(ReadSaveBuf(buf) == LargestMissionScriptSize); - script_assert(ReadSaveBuf(buf) == NumberOfMissionScripts); - ReadSaveBuf(buf); - uint32 runningScripts = ReadSaveBuf(buf); - for (uint32 i = 0; i < runningScripts; i++) - StartNewScript(0)->Load(buf); -VALIDATESAVEBUF(size) -} - -#undef SCRIPT_DATA_SIZE - -void CTheScripts::ClearSpaceForMissionEntity(const CVector& pos, CEntity* pEntity) -{ - static CColPoint aTempColPoints[MAX_COLLISION_POINTS]; - int16 entities = 0; - CEntity* aEntities[16]; - CWorld::FindObjectsKindaColliding(pos, pEntity->GetBoundRadius(), false, &entities, 16, aEntities, false, true, true, false, false); - if (entities <= 0) - return; - for (uint16 i = 0; i < entities; i++) { - if (aEntities[i] != pEntity && aEntities[i]->IsPed() && ((CPed*)aEntities[i])->bInVehicle) - aEntities[i] = nil; - } - for (uint16 i = 0; i < entities; i++) { - if (aEntities[i] == pEntity || !aEntities[i]) - continue; - CEntity* pFound = aEntities[i]; - int cols; - if (pEntity->GetColModel()->numLines <= 0) - cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(), - pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints, nil, nil); - else { - float lines[4]; - lines[0] = lines[1] = lines[2] = lines[3] = 1.0f; - CColPoint tmp[4]; - cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(), - pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints,tmp, lines); - } - if (cols <= 0) - continue; - switch (pFound->GetType()) { - case ENTITY_TYPE_VEHICLE: - { - printf("Will try to delete a vehicle where a mission entity should be\n"); - CVehicle* pVehicle = (CVehicle*)pFound; - if (pVehicle->bIsLocked || !pVehicle->CanBeDeleted()) - break; - if (pVehicle->pDriver) { - CPopulation::RemovePed(pVehicle->pDriver); - pVehicle->pDriver = nil; - } - for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++) { - if (pVehicle->pPassengers[i]) { - CPopulation::RemovePed(pVehicle->pPassengers[i]); - pVehicle->pPassengers[i] = 0; - pVehicle->m_nNumPassengers--; - } - } - CCarCtrl::RemoveFromInterestingVehicleList(pVehicle); - CWorld::Remove(pVehicle); - delete pVehicle; - break; - } - case ENTITY_TYPE_PED: - { - CPed* pPed = (CPed*)pFound; - if (pPed->IsPlayer() || !pPed->CanBeDeleted()) - break; - CPopulation::RemovePed(pPed); - printf("Deleted a ped where a mission entity should be\n"); - break; - } - default: break; - } - } -} - -void CTheScripts::HighlightImportantArea(uint32 id, float x1, float y1, float x2, float y2, float z) -{ - float infX, infY, supX, supY; - if (x1 < x2) { - infX = x1; - supX = x2; - } else { - infX = x2; - supX = x1; - } - if (y1 < y2) { - infY = y1; - supY = y2; - } - else { - infY = y2; - supY = y1; - } - CVector center; - center.x = (infX + supX) / 2; - center.y = (infY + supY) / 2; - center.z = (z <= MAP_Z_LOW_LIMIT) ? CWorld::FindGroundZForCoord(center.x, center.y) : z; - CShadows::RenderIndicatorShadow(id, 2, gpGoalTex, ¢er, supX - center.x, 0.0f, 0.0f, center.y - supY, 0); -} - -void CTheScripts::HighlightImportantAngledArea(uint32 id, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float z) -{ - float infX, infY, supX, supY, X, Y; - X = (x1 + x2) / 2; - Y = (y1 + y2) / 2; - supX = infX = X; - supY = infY = Y; - X = (x2 + x3) / 2; - Y = (y2 + y3) / 2; - infX = Min(infX, X); - supX = Max(supX, X); - infY = Min(infY, Y); - supY = Max(supY, Y); - X = (x3 + x4) / 2; - Y = (y3 + y4) / 2; - infX = Min(infX, X); - supX = Max(supX, X); - infY = Min(infY, Y); - supY = Max(supY, Y); - X = (x4 + x1) / 2; - Y = (y4 + y1) / 2; - infX = Min(infX, X); - supX = Max(supX, X); - infY = Min(infY, Y); - supY = Max(supY, Y); - CVector center; - center.x = (infX + supX) / 2; - center.y = (infY + supY) / 2; - center.z = (z <= MAP_Z_LOW_LIMIT) ? CWorld::FindGroundZForCoord(center.x, center.y) : z; - CShadows::RenderIndicatorShadow(id, 2, gpGoalTex, ¢er, supX - center.x, 0.0f, 0.0f, center.y - supY, 0); -} - -bool CTheScripts::IsPedStopped(CPed* pPed) -{ - if (pPed->bInVehicle) - return IsVehicleStopped(pPed->m_pMyVehicle); - return pPed->m_nMoveState == eMoveState::PEDMOVE_NONE || pPed->m_nMoveState == eMoveState::PEDMOVE_STILL; -} - -bool CTheScripts::IsPlayerStopped(CPlayerInfo* pPlayer) -{ - CPed* pPed = pPlayer->m_pPed; - if (pPed->bInVehicle) - return IsVehicleStopped(pPed->m_pMyVehicle); - if (RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_RUN_STOP) || - RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_RUN_STOP_R) || - RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_JUMP_LAUNCH) || - RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_JUMP_GLIDE)) - return false; - return pPed->m_nMoveState == eMoveState::PEDMOVE_NONE || pPed->m_nMoveState == eMoveState::PEDMOVE_STILL; -} - -bool CTheScripts::IsVehicleStopped(CVehicle* pVehicle) -{ - return 0.01f * CTimer::GetTimeStep() >= pVehicle->m_fDistanceTravelled; -} - -void CTheScripts::CleanUpThisPed(CPed* pPed) -{ - if (!pPed) - return; - if (pPed->CharCreatedBy != MISSION_CHAR) - return; - pPed->CharCreatedBy = RANDOM_CHAR; - if (pPed->m_nPedType == PEDTYPE_PROSTITUTE) - pPed->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 30000; - if (pPed->bInVehicle) { - if (pPed->m_pMyVehicle->pDriver == pPed) { - if (pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_CAR) { - CCarCtrl::JoinCarWithRoadSystem(pPed->m_pMyVehicle); - pPed->m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; - } - } - else { - if (pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_CAR) { - pPed->SetObjective(OBJECTIVE_LEAVE_CAR, pPed->m_pMyVehicle); - pPed->bWanderPathAfterExitingCar = true; - } - } - } - bool flees = false; - PedState state; - eMoveState ms; - if (pPed->m_nPedState == PED_FLEE_ENTITY || pPed->m_nPedState == PED_FLEE_POS) { - ms = pPed->m_nMoveState; - state = pPed->m_nPedState; - flees = true; - } - pPed->ClearObjective(); - pPed->bRespondsToThreats = true; - pPed->bScriptObjectiveCompleted = false; - pPed->ClearLeader(); - if (pPed->IsPedInControl()) - pPed->SetWanderPath(CGeneral::GetRandomNumber() & 7); - if (flees) { - pPed->m_nPedState = state; - pPed->SetMoveState(ms); - } - --CPopulation::ms_nTotalMissionPeds; -} - -void CTheScripts::CleanUpThisVehicle(CVehicle* pVehicle) -{ - if (!pVehicle) - return; - if (pVehicle->VehicleCreatedBy != MISSION_VEHICLE) - return; - pVehicle->bIsLocked = false; - CCarCtrl::RemoveFromInterestingVehicleList(pVehicle); - pVehicle->VehicleCreatedBy = RANDOM_VEHICLE; - ++CCarCtrl::NumRandomCars; - --CCarCtrl::NumMissionCars; -} - -void CTheScripts::CleanUpThisObject(CObject* pObject) -{ - if (!pObject) - return; - if (pObject->ObjectCreatedBy != MISSION_OBJECT) - return; - pObject->ObjectCreatedBy = TEMP_OBJECT; - pObject->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000; - pObject->m_nRefModelIndex = -1; - pObject->bUseVehicleColours = false; - ++CObject::nNoTempObjects; -} - -void CTheScripts::ReadObjectNamesFromScript() -{ - int32 varSpace = GetSizeOfVariableSpace(); - uint32 ip = varSpace + 8; - NumberOfUsedObjects = Read2BytesFromScript(&ip); - ip += 2; - for (uint16 i = 0; i < NumberOfUsedObjects; i++) { - for (int j = 0; j < USED_OBJECT_NAME_LENGTH; j++) - UsedObjectArray[i].name[j] = ScriptSpace[ip++]; - UsedObjectArray[i].index = 0; - } -} - -void CTheScripts::UpdateObjectIndices() -{ - char name[USED_OBJECT_NAME_LENGTH]; - char error[112]; - for (int i = 1; i < NumberOfUsedObjects; i++) { - bool found = false; - for (int j = 0; j < MODELINFOSIZE && !found; j++) { - CBaseModelInfo* pModel = CModelInfo::GetModelInfo(j); - if (!pModel) - continue; - strcpy(name, pModel->GetName()); -#ifdef FIX_BUGS - for (int k = 0; k < USED_OBJECT_NAME_LENGTH && name[k]; k++) -#else - for (int k = 0; k < USED_OBJECT_NAME_LENGTH; k++) -#endif - name[k] = toupper(name[k]); - if (strcmp(name, UsedObjectArray[i].name) == 0) { - found = true; - UsedObjectArray[i].index = j; - } - } - if (!found) { - sprintf(error, "CTheScripts::UpdateObjectIndices - Couldn't find %s", UsedObjectArray[i].name); - debug("%s\n", error); - } - } -} - -void CTheScripts::ReadMultiScriptFileOffsetsFromScript() -{ - int32 varSpace = GetSizeOfVariableSpace(); - uint32 ip = varSpace + 3; - int32 objectSize = Read4BytesFromScript(&ip); - ip = objectSize + 8; - MainScriptSize = Read4BytesFromScript(&ip); - LargestMissionScriptSize = Read4BytesFromScript(&ip); - NumberOfMissionScripts = Read2BytesFromScript(&ip); - ip += 2; - for (int i = 0; i < NumberOfMissionScripts; i++) { - MultiScriptArray[i] = Read4BytesFromScript(&ip); - } -} void CRunningScript::Save(uint8*& buf) { diff --git a/src/control/Script.h b/src/control/Script.h index c9e92129..12f3233f 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -13,6 +13,29 @@ class CPlayerInfo; class CRunningScript; +extern int32 ScriptParams[32]; + +void FlushLog(); +#define script_assert(_Expression) FlushLog(); assert(_Expression); + +#define PICKUP_PLACEMENT_OFFSET 0.5f +#define PED_FIND_Z_OFFSET 5.0f + +#define SPHERE_MARKER_R 0 +#define SPHERE_MARKER_G 128 +#define SPHERE_MARKER_B 255 +#define SPHERE_MARKER_A 128 +#define SPHERE_MARKER_PULSE_PERIOD 2048 +#define SPHERE_MARKER_PULSE_FRACTION 0.1f + +#ifdef USE_PRECISE_MEASUREMENT_CONVERTION +#define METERS_IN_FOOT 0.3048f +#define FEET_IN_METER 3.28084f +#else +#define METERS_IN_FOOT 0.3f +#define FEET_IN_METER 3.33f +#endif + #define KEY_LENGTH_IN_SCRIPT 8 struct intro_script_rectangle diff --git a/src/control/Script2.cpp b/src/control/Script2.cpp new file mode 100644 index 00000000..62b9af93 --- /dev/null +++ b/src/control/Script2.cpp @@ -0,0 +1,1549 @@ +#include "common.h" + +#include "Script.h" +#include "ScriptCommands.h" + +#include "Camera.h" +#include "CarCtrl.h" +#include "CarGen.h" +#include "CivilianPed.h" +#include "CopPed.h" +#include "Cranes.h" +#include "DMAudio.h" +#include "EmergencyPed.h" +#include "Garages.h" +#include "General.h" +#include "Messages.h" +#include "Pad.h" +#include "PedRoutes.h" +#include "Pools.h" +#include "Population.h" +#include "Radar.h" +#include "Restart.h" +#include "Shadows.h" +#include "User.h" +#include "Wanted.h" +#include "WaterLevel.h" +#include "Weather.h" +#include "World.h" +#include "Zones.h" + +int8 CRunningScript::ProcessCommands300To399(int32 command) +{ + switch (command) { + /* Not implemented. + case COMMAND_SET_CHAR_INVINCIBLE: + case COMMAND_SET_PLAYER_INVINCIBLE: + case COMMAND_SET_CHAR_GRAPHIC_TYPE: + case COMMAND_SET_PLAYER_GRAPHIC_TYPE: + */ + case COMMAND_HAS_PLAYER_BEEN_ARRESTED: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_BUSTED); + return 0; + /* Not implemented. + case COMMAND_STOP_CHAR_DRIVING: + case COMMAND_KILL_CHAR: + case COMMAND_SET_FAVOURITE_CAR_MODEL_FOR_CHAR: + case COMMAND_SET_CHAR_OCCUPATION: + */ + case COMMAND_CHANGE_CAR_LOCK: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->m_nDoorLock = (eCarLock)ScriptParams[1]; + return 0; + } + case COMMAND_SHAKE_CAM_WITH_POINT: + CollectParameters(&m_nIp, 4); + TheCamera.CamShake(ScriptParams[0] / 1000.0f, + *(float*)&ScriptParams[1], + *(float*)&ScriptParams[2], + *(float*)&ScriptParams[3]); + return 0; + case COMMAND_IS_CAR_MODEL: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->GetModelIndex() == ScriptParams[1]); + return 0; + } + /* Not implemented. + case COMMAND_IS_CAR_REMAP: + case COMMAND_HAS_CAR_JUST_SUNK: + case COMMAND_SET_CAR_NO_COLLIDE: + */ + case COMMAND_IS_CAR_DEAD_IN_AREA_2D: + { + CollectParameters(&m_nIp, 6); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + float x1 = *(float*)&ScriptParams[1]; + float y1 = *(float*)&ScriptParams[2]; + float x2 = *(float*)&ScriptParams[3]; + float y2 = *(float*)&ScriptParams[4]; + UpdateCompareFlag(pVehicle->GetStatus() == STATUS_WRECKED && + pVehicle->IsWithinArea(x1, y1, x2, y2)); + if (ScriptParams[5]) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugSquare(x1, y1, x2, y2); + return 0; + } + case COMMAND_IS_CAR_DEAD_IN_AREA_3D: + { + CollectParameters(&m_nIp, 8); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + float x1 = *(float*)&ScriptParams[1]; + float y1 = *(float*)&ScriptParams[2]; + float z1 = *(float*)&ScriptParams[3]; + float x2 = *(float*)&ScriptParams[4]; + float y2 = *(float*)&ScriptParams[5]; + float z2 = *(float*)&ScriptParams[6]; + UpdateCompareFlag(pVehicle->GetStatus() == STATUS_WRECKED && + pVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2)); + if (ScriptParams[7]) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, (z1 + z2) / 2); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2); + return 0; + } + /* Not implemented. + case COMMAND_IS_TRAILER_ATTACHED: + case COMMAND_IS_CAR_ON_TRAILER: + case COMMAND_HAS_CAR_GOT_WEAPON: + case COMMAND_PARK: + case COMMAND_HAS_PARK_FINISHED: + case COMMAND_KILL_ALL_PASSENGERS: + case COMMAND_SET_CAR_BULLETPROOF: + case COMMAND_SET_CAR_FLAMEPROOF: + case COMMAND_SET_CAR_ROCKETPROOF: + case COMMAND_IS_CARBOMB_ACTIVE: + case COMMAND_GIVE_CAR_ALARM: + case COMMAND_PUT_CAR_ON_TRAILER: + */ + case COMMAND_IS_CAR_CRUSHED: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CGarages::HasCarBeenCrushed(ScriptParams[0])); + return 0; + /* Not implemented. + case COMMAND_CREATE_GANG_CAR: + */ + case COMMAND_CREATE_CAR_GENERATOR: + CollectParameters(&m_nIp, 12); + ScriptParams[0] = CTheCarGenerators::CreateCarGenerator( + *(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], *(float*)&ScriptParams[3], + ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], + ScriptParams[8], ScriptParams[9], ScriptParams[10], ScriptParams[11]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_SWITCH_CAR_GENERATOR: + { + CollectParameters(&m_nIp, 2); + CCarGenerator* pCarGen = &CTheCarGenerators::CarGeneratorArray[ScriptParams[0]]; + if (ScriptParams[1] == 0){ + pCarGen->SwitchOff(); + }else if (ScriptParams[1] <= 100){ + pCarGen->SwitchOn(); + pCarGen->SetUsesRemaining(ScriptParams[1]); + }else{ + pCarGen->SwitchOn(); + } + return 0; + } + case COMMAND_ADD_PAGER_MESSAGE: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 3); + CUserDisplay::Pager.AddMessage(text, ScriptParams[0], ScriptParams[1], ScriptParams[2]); + return 0; + } + case COMMAND_DISPLAY_ONSCREEN_TIMER: + { + script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); + m_nIp++; + CUserDisplay::OnscnTimer.AddClock((uint16)CTheScripts::Read2BytesFromScript(&m_nIp), nil); + return 0; + } + case COMMAND_CLEAR_ONSCREEN_TIMER: + { + script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); + m_nIp++; + CUserDisplay::OnscnTimer.ClearClock((uint16)CTheScripts::Read2BytesFromScript(&m_nIp)); + return 0; + } + case COMMAND_DISPLAY_ONSCREEN_COUNTER: + { + script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); + m_nIp++; + uint16 counter = CTheScripts::Read2BytesFromScript(&m_nIp); + CollectParameters(&m_nIp, 1); + CUserDisplay::OnscnTimer.AddCounter(counter, ScriptParams[0], nil); + return 0; + } + case COMMAND_CLEAR_ONSCREEN_COUNTER: + { + script_assert(CTheScripts::ScriptSpace[m_nIp] == ARGUMENT_GLOBALVAR); + m_nIp++; + CUserDisplay::OnscnTimer.ClearCounter((uint16)CTheScripts::Read2BytesFromScript(&m_nIp)); + return 0; + } + case COMMAND_SET_ZONE_CAR_INFO: + { + char label[12]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, label); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CollectParameters(&m_nIp, 16); + int zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + if (zone < 0) { + debug("Couldn't find zone - %s\n", label); + return 0; + } + CTheZones::SetZoneCarInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], + ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], 0, 0, + ScriptParams[9], ScriptParams[10], ScriptParams[11], ScriptParams[12], + ScriptParams[13], ScriptParams[14], ScriptParams[15]); + return 0; + } + /* Not implemented. + case COMMAND_IS_CHAR_IN_GANG_ZONE: + */ + case COMMAND_IS_CHAR_IN_ZONE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + char label[12]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, label); + int zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + if (zone != -1) + m_nIp += KEY_LENGTH_IN_SCRIPT; + CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); + UpdateCompareFlag(CTheZones::PointLiesWithinZone(&pos, CTheZones::GetZone(zone))); + return 0; + } + case COMMAND_SET_CAR_DENSITY: + { + char label[12]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, label); + int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + m_nIp += 8; + CollectParameters(&m_nIp, 2); + if (zone < 0) { + debug("Couldn't find zone - %s\n", label); + return 0; + } + CTheZones::SetCarDensity(zone, ScriptParams[0], ScriptParams[1]); + return 0; + } + case COMMAND_SET_PED_DENSITY: + { + char label[12]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, label); + int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CollectParameters(&m_nIp, 2); + if (zone < 0) { + debug("Couldn't find zone - %s\n", label); + return 0; + } + CTheZones::SetPedDensity(zone, ScriptParams[0], ScriptParams[1]); + return 0; + } + case COMMAND_POINT_CAMERA_AT_PLAYER: + { + CollectParameters(&m_nIp, 3); + // ScriptParams[0] is unused. + TheCamera.TakeControl(nil, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT); + return 0; + } + case COMMAND_POINT_CAMERA_AT_CAR: + { + CollectParameters(&m_nIp, 3); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + TheCamera.TakeControl(pVehicle, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT); + return 0; + } + case COMMAND_POINT_CAMERA_AT_CHAR: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + TheCamera.TakeControl(pPed, ScriptParams[1], ScriptParams[2], CAMCONTROL_SCRIPT); + return 0; + } + case COMMAND_RESTORE_CAMERA: + TheCamera.Restore(); + return 0; + case COMMAND_SHAKE_PAD: + CPad::GetPad(ScriptParams[0])->StartShake(ScriptParams[1], ScriptParams[2]); + return 0; + case COMMAND_SET_ZONE_PED_INFO: + { + char label[12]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, label); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CollectParameters(&m_nIp, 10); + int16 zone = CTheZones::FindZoneByLabelAndReturnIndex(label); + if (zone < 0) { + debug("Couldn't find zone - %s\n", label); + return 0; + } + CTheZones::SetZonePedInfo(zone, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], + ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8], 0, 0, ScriptParams[9]); + return 0; + } + case COMMAND_SET_TIME_SCALE: + CollectParameters(&m_nIp, 1); + CTimer::SetTimeScale(*(float*)&ScriptParams[0]); + return 0; + case COMMAND_IS_CAR_IN_AIR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle && pVehicle->IsCar()); + CAutomobile* pCar = (CAutomobile*)pVehicle; + UpdateCompareFlag(pCar->GetAllWheelsOffGround()); + return 0; + } + case COMMAND_SET_FIXED_CAMERA_POSITION: + { + CollectParameters(&m_nIp, 6); + TheCamera.SetCamPositionForFixedMode( + CVector(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2]), + CVector(*(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5])); + return 0; + } + case COMMAND_POINT_CAMERA_AT_POINT: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + TheCamera.TakeControlNoEntity(pos, ScriptParams[3], CAMCONTROL_SCRIPT); + return 0; + } + case COMMAND_ADD_BLIP_FOR_CAR_OLD: + { + CollectParameters(&m_nIp, 3); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + // Useless call. + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CRadar::SetEntityBlip(BLIP_CAR, ScriptParams[0], ScriptParams[1], (eBlipDisplay)ScriptParams[2]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_BLIP_FOR_CHAR_OLD: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + // Useless call. + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], ScriptParams[1], (eBlipDisplay)ScriptParams[2]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_BLIP_FOR_OBJECT_OLD: + { + CollectParameters(&m_nIp, 3); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + // Useless call. + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], ScriptParams[1], (eBlipDisplay)ScriptParams[2]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_REMOVE_BLIP: + CollectParameters(&m_nIp, 1); + CRadar::ClearBlip(ScriptParams[0]); + return 0; + case COMMAND_CHANGE_BLIP_COLOUR: + CollectParameters(&m_nIp, 2); + CRadar::ChangeBlipColour(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_DIM_BLIP: + CollectParameters(&m_nIp, 2); + CRadar::ChangeBlipBrightness(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_ADD_BLIP_FOR_COORD_OLD: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + // Useless call + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CRadar::SetCoordBlip(BLIP_COORD, pos, ScriptParams[3], (eBlipDisplay)ScriptParams[4]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CHANGE_BLIP_SCALE: + CollectParameters(&m_nIp, 2); + CRadar::ChangeBlipScale(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_SET_FADING_COLOUR: + CollectParameters(&m_nIp, 3); + TheCamera.SetFadeColour(ScriptParams[0], ScriptParams[1], ScriptParams[2]); + return 0; + case COMMAND_DO_FADE: + CollectParameters(&m_nIp, 2); + TheCamera.Fade(ScriptParams[0] / 1000.0f, ScriptParams[1]); + return 0; + case COMMAND_GET_FADING_STATUS: + UpdateCompareFlag(TheCamera.GetFading()); + return 0; + case COMMAND_ADD_HOSPITAL_RESTART: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + float angle = *(float*)&ScriptParams[3]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRestart::AddHospitalRestartPoint(pos, angle); + return 0; + } + case COMMAND_ADD_POLICE_RESTART: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + float angle = *(float*)&ScriptParams[3]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRestart::AddPoliceRestartPoint(pos, angle); + return 0; + } + case COMMAND_OVERRIDE_NEXT_RESTART: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + float angle = *(float*)&ScriptParams[3]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRestart::OverrideNextRestart(pos, angle); + return 0; + } + case COMMAND_DRAW_SHADOW: + { + CollectParameters(&m_nIp, 10); + CVector pos = *(CVector*)&ScriptParams[1]; + float angle = *(float*)&ScriptParams[4]; + float length = *(float*)&ScriptParams[5]; + float x, y; + if (angle != 0.0f){ + y = cos(angle) * length; + x = sin(angle) * length; + }else{ + y = length; + x = 0.0f; + } + float frontX = -x; + float frontY = y; + float sideX = y; + float sideY = x; + /* Not very nicely named intermediate variables. */ + CShadows::StoreShadowToBeRendered(ScriptParams[0], &pos, frontX, frontY, sideX, sideY, + ScriptParams[6], ScriptParams[7], ScriptParams[8], ScriptParams[9]); + return 0; + } + case COMMAND_GET_PLAYER_HEADING: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + float angle = pPed->bInVehicle ? pPed->m_pMyVehicle->GetForward().Heading() : pPed->GetForward().Heading(); + *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_PLAYER_HEADING: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + if (pPed->bInVehicle){ + // Is script_assertion required? + return 0; + } + pPed->m_fRotationDest = pPed->m_fRotationCur = DEGTORAD(*(float*)&ScriptParams[1]); + pPed->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); + return 0; + } + case COMMAND_GET_CHAR_HEADING: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + float angle = pPed->bInVehicle ? pPed->m_pMyVehicle->GetForward().Heading() : pPed->GetForward().Heading(); + *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CHAR_HEADING: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + if (pPed->bInVehicle) { + // Is script_assertion required? + return 0; + } + pPed->m_fRotationDest = pPed->m_fRotationCur = DEGTORAD(*(float*)&ScriptParams[1]); + pPed->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); + return 0; + } + case COMMAND_GET_CAR_HEADING: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + float angle = pVehicle->GetForward().Heading(); + *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CAR_HEADING: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); + return 0; + } + case COMMAND_GET_OBJECT_HEADING: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + float angle = pObject->GetForward().Heading(); + *(float*)&ScriptParams[0] = CGeneral::LimitAngle(RADTODEG(angle)); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_OBJECT_HEADING: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CWorld::Remove(pObject); + pObject->SetHeading(DEGTORAD(*(float*)&ScriptParams[1])); + pObject->GetMatrix().UpdateRW(); + pObject->UpdateRwFrame(); + CWorld::Add(pObject); + return 0; + } + case COMMAND_IS_PLAYER_TOUCHING_OBJECT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + script_assert(pObject); + CPhysical* pEntityToTest = pPed->bInVehicle ? (CPhysical*)pPed->m_pMyVehicle : pPed; + UpdateCompareFlag(pEntityToTest->GetHasCollidedWith(pObject)); + return 0; + } + case COMMAND_IS_CHAR_TOUCHING_OBJECT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + script_assert(pObject); + CPhysical* pEntityToTest = pPed->bInVehicle ? (CPhysical*)pPed->m_pMyVehicle : pPed; + UpdateCompareFlag(pEntityToTest->GetHasCollidedWith(pObject)); + return 0; + } + case COMMAND_SET_PLAYER_AMMO: + { + CollectParameters(&m_nIp, 3); + CWorld::Players[0].m_pPed->SetAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]); + return 0; + } + case COMMAND_SET_CHAR_AMMO: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + pPed->SetAmmo((eWeaponType)ScriptParams[1], ScriptParams[2]); + return 0; + } + /* Not implemented. + case COMMAND_SET_CAR_AMMO: + case COMMAND_LOAD_CAMERA_SPLINE: + case COMMAND_MOVE_CAMERA_ALONG_SPLINE: + case COMMAND_GET_CAMERA_POSITION_ALONG_SPLINE: + */ + case COMMAND_DECLARE_MISSION_FLAG: + CTheScripts::OnAMissionFlag = (uint16)CTheScripts::Read2BytesFromScript(&++m_nIp); + return 0; + case COMMAND_DECLARE_MISSION_FLAG_FOR_CONTACT: + CollectParameters(&m_nIp, 1); + CTheScripts::OnAMissionForContactFlag[ScriptParams[0]] = (uint16)CTheScripts::Read2BytesFromScript(&++m_nIp); + return 0; + case COMMAND_DECLARE_BASE_BRIEF_ID_FOR_CONTACT: + CollectParameters(&m_nIp, 2); + CTheScripts::BaseBriefIdForContact[ScriptParams[0]] = ScriptParams[1]; + return 0; + case COMMAND_IS_PLAYER_HEALTH_GREATER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + UpdateCompareFlag(pPed->m_fHealth > ScriptParams[1]); + return 0; + } + case COMMAND_IS_CHAR_HEALTH_GREATER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(pPed->m_fHealth > ScriptParams[1]); + return 0; + } + case COMMAND_IS_CAR_HEALTH_GREATER: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->m_fHealth > ScriptParams[1]); + return 0; + } + case COMMAND_ADD_BLIP_FOR_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + // Useless call. + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int handle = CRadar::SetEntityBlip(BLIP_CAR, ScriptParams[0], 0, BLIP_DISPLAY_BOTH); + CRadar::ChangeBlipScale(handle, 3); + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_BLIP_FOR_CHAR: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + // Useless call. + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int handle = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], 1, BLIP_DISPLAY_BOTH); + CRadar::ChangeBlipScale(handle, 3); + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_BLIP_FOR_OBJECT: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + // Useless call. + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int handle = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], 6, BLIP_DISPLAY_BOTH); + CRadar::ChangeBlipScale(handle, 3); + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_BLIP_FOR_CONTACT_POINT: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + // Useless call + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int handle = CRadar::SetCoordBlip(BLIP_CONTACT_POINT, pos, 2, BLIP_DISPLAY_BOTH); + CRadar::ChangeBlipScale(handle, 3); + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_BLIP_FOR_COORD: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + // Useless call + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int handle = CRadar::SetCoordBlip(BLIP_COORD, pos, 5, BLIP_DISPLAY_BOTH); + CRadar::ChangeBlipScale(handle, 3); + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CHANGE_BLIP_DISPLAY: + CollectParameters(&m_nIp, 2); + CRadar::ChangeBlipDisplay(ScriptParams[0], (eBlipDisplay)ScriptParams[1]); + return 0; + case COMMAND_ADD_ONE_OFF_SOUND: + { + CollectParameters(&m_nIp, 4); + switch (ScriptParams[3]) { + case SCRIPT_SOUND_EVIDENCE_PICKUP: + DMAudio.PlayFrontEndSound(SOUND_EVIDENCE_PICKUP, 0); + return 0; + case SCRIPT_SOUND_UNLOAD_GOLD: + DMAudio.PlayFrontEndSound(SOUND_UNLOAD_GOLD, 0); + return 0; + case SCRIPT_SOUND_PART_MISSION_COMPLETE: + DMAudio.PlayFrontEndSound(SOUND_PART_MISSION_COMPLETE, 0); + return 0; + case SCRIPT_SOUND_RACE_START_3: + DMAudio.PlayFrontEndSound(SOUND_RACE_START_3, 0); + return 0; + case SCRIPT_SOUND_RACE_START_2: + DMAudio.PlayFrontEndSound(SOUND_RACE_START_2, 0); + return 0; + case SCRIPT_SOUND_RACE_START_1: + DMAudio.PlayFrontEndSound(SOUND_RACE_START_1, 0); + return 0; + case SCRIPT_SOUND_RACE_START_GO: + DMAudio.PlayFrontEndSound(SOUND_RACE_START_GO, 0); + return 0; + default: + break; + } +#ifdef FIX_BUGS + /* BUG: if audio is not initialized, this object will not be freed. */ + if (!DMAudio.IsAudioInitialised()) + return 0; +#endif + cAudioScriptObject* obj = new cAudioScriptObject(); + obj->Posn = *(CVector*)&ScriptParams[0]; + obj->AudioId = ScriptParams[3]; + obj->AudioEntity = AEHANDLE_NONE; + DMAudio.CreateOneShotScriptObject(obj); + return 0; + } + case COMMAND_ADD_CONTINUOUS_SOUND: + { + CollectParameters(&m_nIp, 4); + cAudioScriptObject* obj = new cAudioScriptObject(); + obj->Posn = *(CVector*)&ScriptParams[0]; + obj->AudioId = ScriptParams[3]; + obj->AudioEntity = DMAudio.CreateLoopingScriptObject(obj); + ScriptParams[0] = CPools::GetAudioScriptObjectPool()->GetIndex(obj); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_REMOVE_SOUND: + { + CollectParameters(&m_nIp, 1); + cAudioScriptObject* obj = CPools::GetAudioScriptObjectPool()->GetAt(ScriptParams[0]); + if (!obj){ + debug("REMOVE_SOUND - Sound doesn't exist\n"); + return 0; + } + DMAudio.DestroyLoopingScriptObject(obj->AudioEntity); + delete obj; + return 0; + } + case COMMAND_IS_CAR_STUCK_ON_ROOF: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(CTheScripts::UpsideDownCars.HasCarBeenUpsideDownForAWhile(ScriptParams[0])); + return 0; + } + default: + script_assert(0); + } + return -1; +} + +int8 CRunningScript::ProcessCommands400To499(int32 command) +{ + switch (command) { + case COMMAND_ADD_UPSIDEDOWN_CAR_CHECK: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CTheScripts::UpsideDownCars.AddCarToCheck(ScriptParams[0]); + return 0; + } + case COMMAND_REMOVE_UPSIDEDOWN_CAR_CHECK: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CTheScripts::UpsideDownCars.RemoveCarFromCheck(ScriptParams[0]); + return 0; + } + case COMMAND_SET_CHAR_OBJ_WAIT_ON_FOOT: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_WAIT_ON_FOOT); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FLEE_ON_FOOT_TILL_SAFE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE); + return 0; + } + case COMMAND_SET_CHAR_OBJ_GUARD_SPOT: + { + CollectParameters(&m_nIp, 4); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GUARD_SPOT, pos); + return 0; + } + case COMMAND_SET_CHAR_OBJ_GUARD_AREA: + { + CollectParameters(&m_nIp, 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + float infX = *(float*)&ScriptParams[1]; + float infY = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + if (infX > supX){ + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[1]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[2]; + } + CVector pos; + pos.x = (infX + supX) / 2; + pos.y = (infY + supY) / 2; + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = Max(pos.x - infX, pos.y - infY); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GUARD_SPOT, pos, radius); + return 0; + } + case COMMAND_SET_CHAR_OBJ_WAIT_IN_CAR: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_WAIT_IN_CAR); + return 0; + } + case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: + PlayerInAreaCheckCommand(command, &m_nIp); + return 0; + case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_CHAR_IN_AREA_IN_CAR_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_2D: + case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_CHAR_IN_AREA_IN_CAR_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: + CharInAreaCheckCommand(command, &m_nIp); + return 0; + case COMMAND_IS_CAR_STOPPED_IN_AREA_2D: + case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: + CarInAreaCheckCommand(command, &m_nIp); + return 0; + case COMMAND_LOCATE_CAR_2D: + case COMMAND_LOCATE_STOPPED_CAR_2D: + case COMMAND_LOCATE_CAR_3D: + case COMMAND_LOCATE_STOPPED_CAR_3D: + LocateCarCommand(command, &m_nIp); + return 0; + case COMMAND_GIVE_WEAPON_TO_PLAYER: + { + CollectParameters(&m_nIp, 3); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + pPed->m_nSelectedWepSlot = pPed->GiveWeapon((eWeaponType)ScriptParams[1], ScriptParams[2]); + return 0; + } + case COMMAND_GIVE_WEAPON_TO_CHAR: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->SetCurrentWeapon(pPed->GiveWeapon((eWeaponType)ScriptParams[1], ScriptParams[2])); + if (pPed->bInVehicle) + pPed->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType)->m_nModelId); + return 0; + } + /* Not implemented */ + //case COMMAND_GIVE_WEAPON_TO_CAR: + case COMMAND_SET_PLAYER_CONTROL: + { + CollectParameters(&m_nIp, 2); + CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; + if (ScriptParams[1]){ + if (CGame::playingIntro || CTheScripts::DelayMakingPlayerUnsafeThisTime){ + CTheScripts::CountdownToMakePlayerUnsafe = 50; + if (CTheScripts::DelayMakingPlayerUnsafeThisTime) + CTheScripts::DelayMakingPlayerUnsafeThisTime--; + }else{ + pPlayer->MakePlayerSafe(false); + } + }else{ + pPlayer->MakePlayerSafe(true); + if (strcmp(m_abScriptName, "camera") == 0){ + pPlayer->m_pPed->SetMoveSpeed(0.0f, 0.0f, 0.0f); + pPlayer->m_pPed->SetTurnSpeed(0.0f, 0.0f, 0.0f); + CAnimManager::BlendAnimation((RpClump*)pPlayer->m_pPed->m_rwObject, pPlayer->m_pPed->m_animGroup, ANIM_IDLE_STANCE, 1000.0f); + } + } + return 0; + } + case COMMAND_FORCE_WEATHER: + CollectParameters(&m_nIp, 1); + CWeather::ForceWeather(ScriptParams[0]); + return 0; + case COMMAND_FORCE_WEATHER_NOW: + CollectParameters(&m_nIp, 1); + CWeather::ForceWeatherNow(ScriptParams[0]); + return 0; + case COMMAND_RELEASE_WEATHER: + CWeather::ReleaseWeather(); + return 0; + case COMMAND_SET_CURRENT_PLAYER_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++){ + if (pPed->m_weapons[i].m_eWeaponType == ScriptParams[1]) + pPed->m_nSelectedWepSlot = i; + } + return 0; + } + case COMMAND_SET_CURRENT_CHAR_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + for (int i = 0; i < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; i++) { + if (pPed->m_weapons[i].m_eWeaponType == ScriptParams[1]) + pPed->SetCurrentWeapon(i); + } + return 0; + } + /* Not implemented */ + //case COMMAND_SET_CURRENT_CAR_WEAPON: + case COMMAND_GET_OBJECT_COORDINATES: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + *(CVector*)&ScriptParams[0] = pObject->GetPosition(); + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_SET_OBJECT_COORDINATES: + { + CollectParameters(&m_nIp, 4); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pObject->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, pObject); + return 0; + } + case COMMAND_GET_GAME_TIMER: + ScriptParams[0] = CTimer::GetTimeInMilliseconds(); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_TURN_CHAR_TO_FACE_COORD: + { + CollectParameters(&m_nIp, 4); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle; + CVector pos; + if (pPed->bInVehicle) + pVehicle = pPed->m_pMyVehicle; + else + pVehicle = nil; + if (pVehicle) + pos = pVehicle->GetPosition(); + else + pos = pPed->GetPosition(); + float heading = CGeneral::GetATanOfXY(pos.x - *(float*)&ScriptParams[1], pos.y - *(float*)&ScriptParams[2]); + heading += HALFPI; + if (heading > TWOPI) + heading -= TWOPI; + if (!pVehicle){ + pPed->m_fRotationCur = heading; + pPed->m_fRotationDest = heading; + pPed->SetHeading(heading); + } + return 0; + } + case COMMAND_TURN_PLAYER_TO_FACE_COORD: + { + CollectParameters(&m_nIp, 4); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CVehicle* pVehicle; + CVector pos; + if (pPed->bInVehicle) + pVehicle = pPed->m_pMyVehicle; + else + pVehicle = nil; + if (pVehicle) + pos = pVehicle->GetPosition(); + else + pos = pPed->GetPosition(); + float heading = CGeneral::GetATanOfXY(pos.x - *(float*)&ScriptParams[1], pos.y - *(float*)&ScriptParams[2]); + heading += HALFPI; + if (heading > TWOPI) + heading -= TWOPI; + if (!pVehicle) { + pPed->m_fRotationCur = heading; + pPed->m_fRotationDest = heading; + pPed->SetHeading(heading); + } + return 0; + } + case COMMAND_STORE_WANTED_LEVEL: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + ScriptParams[0] = pPed->m_pWanted->m_nWantedLevel; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_CAR_STOPPED: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(CTheScripts::IsVehicleStopped(pVehicle)); + return 0; + } + case COMMAND_MARK_CHAR_AS_NO_LONGER_NEEDED: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CTheScripts::CleanUpThisPed(pPed); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_MARK_CAR_AS_NO_LONGER_NEEDED: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + CTheScripts::CleanUpThisVehicle(pVehicle); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); + return 0; + } + case COMMAND_MARK_OBJECT_AS_NO_LONGER_NEEDED: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + CTheScripts::CleanUpThisObject(pObject); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); + return 0; + } + case COMMAND_DONT_REMOVE_CHAR: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_DONT_REMOVE_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CAR); + return 0; + } + case COMMAND_DONT_REMOVE_OBJECT: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_OBJECT); + return 0; + } + case COMMAND_CREATE_CHAR_AS_PASSENGER: + { + CollectParameters(&m_nIp, 4); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + switch (ScriptParams[2]) { + case MI_COP: + if (ScriptParams[1] == PEDTYPE_COP) + ScriptParams[2] = COP_STREET; + break; + case MI_SWAT: + if (ScriptParams[1] == PEDTYPE_COP) + ScriptParams[2] = COP_SWAT; + break; + case MI_FBI: + if (ScriptParams[1] == PEDTYPE_COP) + ScriptParams[2] = COP_FBI; + break; + case MI_ARMY: + if (ScriptParams[1] == PEDTYPE_COP) + ScriptParams[2] = COP_ARMY; + break; + case MI_MEDIC: + if (ScriptParams[1] == PEDTYPE_EMERGENCY) + ScriptParams[2] = PEDTYPE_EMERGENCY; + break; + case MI_FIREMAN: + if (ScriptParams[1] == PEDTYPE_FIREMAN) + ScriptParams[2] = PEDTYPE_FIREMAN; + break; + default: + break; + } + CPed* pPed; + if (ScriptParams[1] == PEDTYPE_COP) + pPed = new CCopPed((eCopType)ScriptParams[2]); + else if (ScriptParams[1] == PEDTYPE_EMERGENCY || ScriptParams[1] == PEDTYPE_FIREMAN) + pPed = new CEmergencyPed(ScriptParams[2]); + else + pPed = new CCivilianPed((ePedType)ScriptParams[1], ScriptParams[2]); + pPed->CharCreatedBy = MISSION_CHAR; + pPed->bRespondsToThreats = false; + pPed->bAllowMedicsToReviveMe = false; + pPed->SetPosition(pVehicle->GetPosition()); + pPed->SetOrientation(0.0f, 0.0f, 0.0f); + pPed->SetPedState(PED_DRIVING); + CPopulation::ms_nTotalMissionPeds++; + if (ScriptParams[3] >= 0) + pVehicle->AddPassenger(pPed, ScriptParams[3]); + else + pVehicle->AddPassenger(pPed); + pPed->m_pMyVehicle = pVehicle; + pPed->m_pMyVehicle->RegisterReference((CEntity**)&pPed->m_pMyVehicle); + pPed->bInVehicle = true; + pPed->SetPedState(PED_DRIVING); + pVehicle->SetStatus(STATUS_PHYSICS); + pPed->bUsesCollision = false; +#ifdef FIX_BUGS + AnimationId anim = pVehicle->GetDriverAnim(); +#else + AnimationId anim = pVehicle->bLowVehicle ? ANIM_CAR_LSIT : ANIM_CAR_SIT; +#endif + pPed->m_pVehicleAnim = CAnimManager::BlendAnimation(pPed->GetClump(), ASSOCGRP_STD, anim, 100.0f); + pPed->StopNonPartialAnims(); + pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); + CWorld::Add(pPed); + ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_SET_CHAR_OBJ_KILL_CHAR_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_KILL_PLAYER_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_KILL_CHAR_ANY_MEANS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_KILL_PLAYER_ANY_MEANS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FLEE_CHAR_ON_FOOT_TILL_SAFE: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FLEE_PLAYER_ON_FOOT_TILL_SAFE: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FLEE_CHAR_ON_FOOT_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FLEE_PLAYER_ON_FOOT_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_GOTO_CHAR_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_GOTO_PLAYER_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_LEAVE_CAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_LEAVE_CAR, pVehicle); + return 0; + } + case COMMAND_SET_CHAR_OBJ_ENTER_CAR_AS_PASSENGER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, pVehicle); + return 0; + } + case COMMAND_SET_CHAR_OBJ_ENTER_CAR_AS_DRIVER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicle); + return 0; + } + /* Not implemented. + case COMMAND_SET_CHAR_OBJ_FOLLOW_CAR_IN_CAR: + case COMMAND_SET_CHAR_OBJ_FIRE_AT_OBJECT_FROM_VEHICLE: + case COMMAND_SET_CHAR_OBJ_DESTROY_OBJECT: + */ + case COMMAND_SET_CHAR_OBJ_DESTROY_CAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_DESTROY_CAR, pVehicle); + return 0; + } + case COMMAND_SET_CHAR_OBJ_GOTO_AREA_ON_FOOT: + { + CollectParameters(&m_nIp, 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + float infX = *(float*)&ScriptParams[1]; + float infY = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[1]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[2]; + } + CVector pos; + pos.x = (infX + supX) / 2; + pos.y = (infY + supY) / 2; + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = Max(pos.x - infX, pos.y - infY); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, pos, radius); + return 0; + } + /* Not implemented. + case COMMAND_SET_CHAR_OBJ_GOTO_AREA_IN_CAR: + case COMMAND_SET_CHAR_OBJ_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: + case COMMAND_SET_CHAR_OBJ_GUARD_ATTACK: + */ + case COMMAND_SET_CHAR_AS_LEADER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + pPed->SetObjective(OBJECTIVE_SET_LEADER, pTarget); + return 0; + } + case COMMAND_SET_PLAYER_AS_LEADER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CWorld::Players[ScriptParams[1]].m_pPed; + pPed->SetObjective(OBJECTIVE_SET_LEADER, pTarget); + return 0; + } + case COMMAND_LEAVE_GROUP: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->ClearLeader(); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FOLLOW_ROUTE: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FOLLOW_ROUTE, ScriptParams[1], ScriptParams[2]); + return 0; + } + case COMMAND_ADD_ROUTE_POINT: + { + CollectParameters(&m_nIp, 4); + CRouteNode::AddRoutePoint(ScriptParams[0], *(CVector*)&ScriptParams[1]); + return 0; + } + case COMMAND_PRINT_WITH_NUMBER_BIG: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 3); + CMessages::AddBigMessageWithNumber(text, ScriptParams[1], ScriptParams[2] - 1, ScriptParams[0], -1, -1, -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_NUMBER: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 3); + CMessages::AddMessageWithNumber(text, ScriptParams[1], ScriptParams[2], ScriptParams[0], -1, -1, -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_NUMBER_NOW: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 3); + CMessages::AddMessageJumpQWithNumber(text, ScriptParams[1], ScriptParams[2], ScriptParams[0], -1, -1, -1, -1, -1); + return 0; + } + /* Not implemented. + case COMMAND_PRINT_WITH_NUMBER_SOON: + */ + case COMMAND_SWITCH_ROADS_ON: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX){ + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY){ + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ){ + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.SwitchRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, false); + return 0; + } + case COMMAND_SWITCH_ROADS_OFF: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.SwitchRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, true); + return 0; + } + case COMMAND_GET_NUMBER_OF_PASSENGERS: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + ScriptParams[0] = pVehicle->m_nNumPassengers; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_MAXIMUM_NUMBER_OF_PASSENGERS: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + ScriptParams[0] = pVehicle->m_nNumMaxPassengers; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CAR_DENSITY_MULTIPLIER: + { + CollectParameters(&m_nIp, 1); + CCarCtrl::CarDensityMultiplier = *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SET_CAR_HEAVY: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bIsHeavy = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_CLEAR_CHAR_THREAT_SEARCH: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->m_fearFlags = 0; + return 0; + } + case COMMAND_ACTIVATE_CRANE: + { + CollectParameters(&m_nIp, 10); + float infX = *(float*)&ScriptParams[2]; + float infY = *(float*)&ScriptParams[3]; + float supX = *(float*)&ScriptParams[4]; + float supY = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[4]; + supX = *(float*)&ScriptParams[2]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[5]; + supY = *(float*)&ScriptParams[3]; + } + CCranes::ActivateCrane(infX, supX, infY, supY, + *(float*)&ScriptParams[6], *(float*)&ScriptParams[7], *(float*)&ScriptParams[8], + DEGTORAD(*(float*)&ScriptParams[9]), false, false, + *(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + return 0; + } + case COMMAND_DEACTIVATE_CRANE: + { + CollectParameters(&m_nIp, 2); + CCranes::DeActivateCrane(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + return 0; + } + case COMMAND_SET_MAX_WANTED_LEVEL: + { + CollectParameters(&m_nIp, 1); + CWanted::SetMaximumWantedLevel(ScriptParams[0]); + return 0; + } + /* Debug commands? + case COMMAND_SAVE_VAR_INT: + case COMMAND_SAVE_VAR_FLOAT: + */ + case COMMAND_IS_CAR_IN_AIR_PROPER: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->m_nCollisionRecords == 0); + return 0; + } + default: + script_assert(0); + } + return -1; +} diff --git a/src/control/Script3.cpp b/src/control/Script3.cpp new file mode 100644 index 00000000..c0112d06 --- /dev/null +++ b/src/control/Script3.cpp @@ -0,0 +1,2082 @@ +#include "common.h" + +#include "Script.h" +#include "ScriptCommands.h" + +#include "Boat.h" +#include "CarCtrl.h" +#include "Clock.h" +#include "Coronas.h" +#include "Cranes.h" +#include "CutsceneMgr.h" +#include "Darkel.h" +#include "Explosion.h" +#include "Fire.h" +#include "General.h" +#include "Garages.h" +#include "Heli.h" +#include "Messages.h" +#include "Pad.h" +#include "ParticleObject.h" +#include "Phones.h" +#include "Pickups.h" +#include "PointLights.h" +#include "Population.h" +#include "Pools.h" +#include "ProjectileInfo.h" +#include "Radar.h" +#include "Restart.h" +#include "Stats.h" +#include "Streaming.h" +#include "User.h" +#include "WaterLevel.h" +#include "Weather.h" +#include "Zones.h" + +int8 CRunningScript::ProcessCommands500To599(int32 command) +{ + switch (command) { + case COMMAND_IS_CAR_UPSIDEDOWN: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->GetUp().z <= -0.97f); + return 0; + } + case COMMAND_GET_PLAYER_CHAR: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPed); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CANCEL_OVERRIDE_RESTART: + CRestart::CancelOverrideRestart(); + return 0; + case COMMAND_SET_POLICE_IGNORE_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + if (ScriptParams[1]) { + pPed->m_pWanted->m_bIgnoredByCops = true; + CWorld::StopAllLawEnforcersInTheirTracks(); + } + else { + pPed->m_pWanted->m_bIgnoredByCops = false; + } + return 0; + } + case COMMAND_ADD_PAGER_MESSAGE_WITH_NUMBER: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 4); + CUserDisplay::Pager.AddMessageWithNumber(text, ScriptParams[0], -1, -1, -1, -1, -1, + ScriptParams[1], ScriptParams[2], ScriptParams[3]); + return 0; + } + case COMMAND_START_KILL_FRENZY: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 8); + CDarkel::StartFrenzy((eWeaponType)ScriptParams[0], ScriptParams[1], ScriptParams[2], + ScriptParams[3], text, ScriptParams[4], ScriptParams[5], + ScriptParams[6], ScriptParams[7] != 0, false); + return 0; + } + case COMMAND_READ_KILL_FRENZY_STATUS: + { + ScriptParams[0] = CDarkel::ReadStatus(); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SQRT: + { + CollectParameters(&m_nIp, 1); + *(float*)&ScriptParams[0] = Sqrt(*(float*)&ScriptParams[0]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_2D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_2D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_2D: + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D: + LocatePlayerCarCommand(command, &m_nIp); + return 0; + case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_2D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_2D: + case COMMAND_LOCATE_CHAR_IN_CAR_CAR_2D: + case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D: + case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D: + LocateCharCarCommand(command, &m_nIp); + return 0; + case COMMAND_GENERATE_RANDOM_FLOAT_IN_RANGE: + CollectParameters(&m_nIp, 2); + *(float*)&ScriptParams[0] = CGeneral::GetRandomNumberInRange(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_GENERATE_RANDOM_INT_IN_RANGE: + CollectParameters(&m_nIp, 2); + ScriptParams[0] = CGeneral::GetRandomNumberInRange(ScriptParams[0], ScriptParams[1]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_LOCK_CAR_DOORS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->m_nDoorLock = (eCarLock)ScriptParams[1]; + return 0; + } + case COMMAND_EXPLODE_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->BlowUpCar(nil); + return 0; + } + case COMMAND_ADD_EXPLOSION: + CollectParameters(&m_nIp, 4); + CExplosion::AddExplosion(nil, nil, (eExplosionType)ScriptParams[3], *(CVector*)&ScriptParams[0], 0); + return 0; + + case COMMAND_IS_CAR_UPRIGHT: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->GetUp().z >= 0.0f); + return 0; + } + case COMMAND_TURN_CHAR_TO_FACE_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; + CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); + CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); + float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; + if (angle > TWOPI) + angle -= TWOPI; + if (!pVehicle) { + pSourcePed->m_fRotationCur = angle; + pSourcePed->m_fRotationDest = angle; + pSourcePed->SetHeading(angle); + } + return 0; + } + case COMMAND_TURN_CHAR_TO_FACE_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CPed* pTargetPed = CWorld::Players[ScriptParams[1]].m_pPed; + CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; + CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); + CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); + float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; + if (angle > TWOPI) + angle -= TWOPI; + if (!pVehicle) { + pSourcePed->m_fRotationCur = angle; + pSourcePed->m_fRotationDest = angle; + pSourcePed->SetHeading(angle); + } + return 0; + } + case COMMAND_TURN_PLAYER_TO_FACE_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + CVehicle* pVehicle = pSourcePed->bInVehicle ? pSourcePed->m_pMyVehicle : nil; + CVector2D sourcePos = pSourcePed->bInVehicle ? pVehicle->GetPosition() : pSourcePed->GetPosition(); + CVector2D targetPos = pTargetPed->bInVehicle ? pTargetPed->m_pMyVehicle->GetPosition() : pTargetPed->GetPosition(); + float angle = CGeneral::GetATanOfXY(sourcePos.x - targetPos.x, sourcePos.y - targetPos.y) + HALFPI; + if (angle > TWOPI) + angle -= TWOPI; + if (!pVehicle) { + pSourcePed->m_fRotationCur = angle; + pSourcePed->m_fRotationDest = angle; + pSourcePed->SetHeading(angle); + } + return 0; + } + case COMMAND_SET_CHAR_OBJ_GOTO_COORD_ON_FOOT: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVector target; + target.x = *(float*)&ScriptParams[1]; + target.y = *(float*)&ScriptParams[2]; + target.z = CWorld::FindGroundZForCoord(target.x, target.y); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GOTO_AREA_ON_FOOT, target); + return 0; + } + /* Not implemented*/ + //case COMMAND_SET_CHAR_OBJ_GOTO_COORD_IN_CAR: + case COMMAND_CREATE_PICKUP: + { + CollectParameters(&m_nIp, 5); + int16 model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + CVector pos = *(CVector*)&ScriptParams[2]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CPickups::GenerateNewOne(pos, model, ScriptParams[1], 0); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_HAS_PICKUP_BEEN_COLLECTED: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CPickups::IsPickUpPickedUp(ScriptParams[0]) != 0); + return 0; + case COMMAND_REMOVE_PICKUP: + CollectParameters(&m_nIp, 1); + CPickups::RemovePickUp(ScriptParams[0]); + return 0; + case COMMAND_SET_TAXI_LIGHTS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + ((CAutomobile*)pVehicle)->SetTaxiLight(ScriptParams[1] != 0); + return 0; + } + case COMMAND_PRINT_BIG_Q: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 2); + CMessages::AddBigMessageQ(text, ScriptParams[0], ScriptParams[1] - 1); + return 0; + } + case COMMAND_PRINT_WITH_NUMBER_BIG_Q: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 3); + CMessages::AddBigMessageWithNumberQ(text, ScriptParams[1], ScriptParams[2] - 1, + ScriptParams[0], -1, -1, -1, -1, -1); + return 0; + } + case COMMAND_SET_GARAGE: + { + CollectParameters(&m_nIp, 7); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], 0); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_GARAGE_WITH_CAR_MODEL: + { + CollectParameters(&m_nIp, 8); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], ScriptParams[7]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_TARGET_CAR_FOR_MISSION_GARAGE: + { + CollectParameters(&m_nIp, 2); + CVehicle* pTarget; + if (ScriptParams[1] >= 0) { + pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + } + else { + pTarget = nil; + } + CGarages::SetTargetCarForMissonGarage(ScriptParams[0], pTarget); + return 0; + } + case COMMAND_IS_CAR_IN_MISSION_GARAGE: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CGarages::HasCarBeenDroppedOffYet(ScriptParams[0])); + return 0; + case COMMAND_SET_FREE_BOMBS: + CollectParameters(&m_nIp, 1); + CGarages::SetFreeBombs(ScriptParams[0] != 0); + return 0; +#ifdef GTA_PS2 + case COMMAND_SET_POWERPOINT: + { + CollectParameters(&m_nIp, 7); + float f1 = *(float*)&ScriptParams[0]; + float f2 = *(float*)&ScriptParams[1]; + float f3 = *(float*)&ScriptParams[2]; + float f4 = *(float*)&ScriptParams[3]; + float f5 = *(float*)&ScriptParams[4]; + float f6 = *(float*)&ScriptParams[5]; + float temp; + + if (f1 > f4) { + temp = f1; + f1 = f4; + f4 = temp; + } + + if (f2 > f5) { + temp = f2; + f2 = f5; + f5 = temp; + } + + if (f3 > f6) { + temp = f3; + f3 = f6; + f6 = temp; + } + + CPowerPoints::GenerateNewOne(f1, f2, f3, f4, f5, f6, *(uint8*)&ScriptParams[6]); + + return 0; + } +#endif // GTA_PS2 + case COMMAND_SET_ALL_TAXI_LIGHTS: + CollectParameters(&m_nIp, 1); + CAutomobile::SetAllTaxiLights(ScriptParams[0] != 0); + return 0; + case COMMAND_IS_CAR_ARMED_WITH_ANY_BOMB: + { + CollectParameters(&m_nIp, 1); + CAutomobile* pCar = (CAutomobile*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pCar); + script_assert(pCar->m_vehType == VEHICLE_TYPE_CAR); + UpdateCompareFlag(pCar->m_bombType != 0); //TODO: enum + return 0; + } + case COMMAND_APPLY_BRAKES_TO_PLAYERS_CAR: + CollectParameters(&m_nIp, 2); + CPad::GetPad(ScriptParams[0])->bApplyBrakes = (ScriptParams[1] != 0); + return 0; + case COMMAND_SET_PLAYER_HEALTH: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + pPed->m_fHealth = ScriptParams[1]; + return 0; + } + case COMMAND_SET_CHAR_HEALTH: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + if (ScriptParams[1]) { + pPed->m_fHealth = ScriptParams[1]; + } + else if (pPed->bInVehicle) { + pPed->SetDead(); + if (!pPed->IsPlayer()) + pPed->FlagToDestroyWhenNextProcessed(); + } + else { + pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } + return 0; + } + case COMMAND_SET_CAR_HEALTH: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->m_fHealth = ScriptParams[1]; + return 0; + } + case COMMAND_GET_PLAYER_HEALTH: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + ScriptParams[0] = pPed->m_fHealth; // correct cast float to int + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_CHAR_HEALTH: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + ScriptParams[0] = pPed->m_fHealth; // correct cast float to int + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_CAR_HEALTH: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + ScriptParams[0] = pVehicle->m_fHealth; // correct cast float to int + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_CAR_ARMED_WITH_BOMB: + { + CollectParameters(&m_nIp, 2); + CAutomobile* pCar = (CAutomobile*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pCar); + script_assert(pCar->m_vehType == VEHICLE_TYPE_CAR); + UpdateCompareFlag(pCar->m_bombType == ScriptParams[1]); //TODO: enum + return 0; + } + case COMMAND_CHANGE_CAR_COLOUR: + { + CollectParameters(&m_nIp, 3); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + if (ScriptParams[1] >= 256 || ScriptParams[2] >= 256) + debug("CHANGE_CAR_COLOUR - Colours must be less than %d", 256); + pVehicle->m_currentColour1 = ScriptParams[1]; + pVehicle->m_currentColour2 = ScriptParams[2]; + return 0; + } + case COMMAND_SWITCH_PED_ROADS_ON: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.SwitchPedRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, false); + return 0; + } + case COMMAND_SWITCH_PED_ROADS_OFF: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.SwitchPedRoadsOffInArea(infX, supX, infY, supY, infZ, supZ, true); + return 0; + } + case COMMAND_CHAR_LOOK_AT_CHAR_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pSourcePed); + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pTargetPed); + pSourcePed->SetLookFlag(pTargetPed, true); + pSourcePed->SetLookTimer(60000); + return 0; + } + case COMMAND_CHAR_LOOK_AT_PLAYER_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pSourcePed); + CPed* pTargetPed = CWorld::Players[ScriptParams[1]].m_pPed; + script_assert(pTargetPed); + pSourcePed->SetLookFlag(pTargetPed, true); + pSourcePed->SetLookTimer(60000); + return 0; + } + case COMMAND_PLAYER_LOOK_AT_CHAR_ALWAYS: + { + CollectParameters(&m_nIp, 2); + CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pSourcePed); + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pTargetPed); + pSourcePed->SetLookFlag(pTargetPed, true); + pSourcePed->SetLookTimer(60000); + return 0; + } + case COMMAND_STOP_CHAR_LOOKING: + { + CollectParameters(&m_nIp, 1); + CPed* pSourcePed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pSourcePed); + pSourcePed->ClearLookFlag(); + pSourcePed->bKeepTryingToLook = false; + if (pSourcePed->GetPedState() == PED_LOOK_HEADING || pSourcePed->GetPedState() == PED_LOOK_ENTITY) + pSourcePed->RestorePreviousState(); + return 0; + } + case COMMAND_STOP_PLAYER_LOOKING: + { + CollectParameters(&m_nIp, 1); + CPed* pSourcePed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pSourcePed); + pSourcePed->ClearLookFlag(); + pSourcePed->bKeepTryingToLook = false; + if (pSourcePed->GetPedState() == PED_LOOK_HEADING || pSourcePed->GetPedState() == PED_LOOK_ENTITY) + pSourcePed->RestorePreviousState(); + return 0; + } + case COMMAND_SWITCH_HELICOPTER: + CollectParameters(&m_nIp, 1); + CHeli::ActivateHeli(ScriptParams[0] != 0); + return 0; + + //case COMMAND_SET_GANG_ATTITUDE: + //case COMMAND_SET_GANG_GANG_ATTITUDE: + //case COMMAND_SET_GANG_PLAYER_ATTITUDE: + //case COMMAND_SET_GANG_PED_MODELS: + case COMMAND_SET_GANG_CAR_MODEL: + CollectParameters(&m_nIp, 2); + CGangs::SetGangVehicleModel(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_SET_GANG_WEAPONS: + CollectParameters(&m_nIp, 3); + CGangs::SetGangWeapons(ScriptParams[0], (eWeaponType)ScriptParams[1], (eWeaponType)ScriptParams[2]); + return 0; + case COMMAND_SET_CHAR_OBJ_RUN_TO_AREA: + { + CollectParameters(&m_nIp, 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + float infX = *(float*)&ScriptParams[1]; + float infY = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[1]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[2]; + } + CVector pos; + pos.x = (infX + supX) / 2; + pos.y = (infY + supY) / 2; + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = Max(pos.x - infX, pos.y - infY); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_RUN_TO_AREA, pos, radius); + return 0; + } + case COMMAND_SET_CHAR_OBJ_RUN_TO_COORD: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVector pos; + pos.x = *(float*)&ScriptParams[1]; + pos.y = *(float*)&ScriptParams[2]; + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_RUN_TO_AREA, pos); + return 0; + } + case COMMAND_IS_PLAYER_TOUCHING_OBJECT_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + bool isTouching = false; + if (pPed->bInVehicle) + isTouching = false; + else if (pPed->GetHasCollidedWith(pObject)) + isTouching = true; + UpdateCompareFlag(isTouching); + return 0; + } + case COMMAND_IS_CHAR_TOUCHING_OBJECT_ON_FOOT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + bool isTouching = false; + if (pPed->InVehicle()) + isTouching = false; + else if (pPed->GetHasCollidedWith(pObject)) + isTouching = true; + UpdateCompareFlag(isTouching); + return 0; + } + case COMMAND_LOAD_SPECIAL_CHARACTER: + { + CollectParameters(&m_nIp, 1); + char name[16]; + strncpy(name, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + name[i] = tolower(name[i]); + CStreaming::RequestSpecialChar(ScriptParams[0] - 1, name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); + m_nIp += KEY_LENGTH_IN_SCRIPT; + return 0; + } + case COMMAND_HAS_SPECIAL_CHARACTER_LOADED: + { + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CStreaming::HasSpecialCharLoaded(ScriptParams[0] - 1)); + return 0; + } + case COMMAND_FLASH_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bHasBlip = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_FLASH_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bHasBlip = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_FLASH_OBJECT: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + pObject->bHasBlip = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_IS_PLAYER_IN_REMOTE_MODE: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CWorld::Players[ScriptParams[0]].IsPlayerInRemoteMode()); + return 0; + case COMMAND_ARM_CAR_WITH_BOMB: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + ((CAutomobile*)pVehicle)->m_bombType = ScriptParams[1]; + ((CAutomobile*)pVehicle)->m_pBombRigger = FindPlayerPed(); + return 0; + } + case COMMAND_SET_CHAR_PERSONALITY: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->SetPedStats((ePedStats)ScriptParams[1]); + return 0; + } + case COMMAND_SET_CUTSCENE_OFFSET: + CollectParameters(&m_nIp, 3); + CCutsceneMgr::SetCutsceneOffset(*(CVector*)&ScriptParams[0]); + return 0; + case COMMAND_SET_ANIM_GROUP_FOR_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->m_animGroup = (AssocGroupId)ScriptParams[1]; + return 0; + } + case COMMAND_SET_ANIM_GROUP_FOR_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + pPed->m_animGroup = (AssocGroupId)ScriptParams[1]; + return 0; + } + case COMMAND_REQUEST_MODEL: + { + CollectParameters(&m_nIp, 1); + int model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + CStreaming::RequestModel(model, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_NOFADE | STREAMFLAGS_SCRIPTOWNED); + return 0; + } + case COMMAND_HAS_MODEL_LOADED: + { + CollectParameters(&m_nIp, 1); + int model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + UpdateCompareFlag(CStreaming::HasModelLoaded(model)); + return 0; + } + case COMMAND_MARK_MODEL_AS_NO_LONGER_NEEDED: + { + CollectParameters(&m_nIp, 1); + int model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + CStreaming::SetMissionDoesntRequireModel(model); + return 0; + } + case COMMAND_GRAB_PHONE: + { + CollectParameters(&m_nIp, 2); + ScriptParams[0] = gPhoneInfo.GrabPhone(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_REPEATED_PHONE_MESSAGE: + { + CollectParameters(&m_nIp, 1); + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text, nil, nil, nil, nil, nil); + return 0; + } + case COMMAND_SET_PHONE_MESSAGE: + { + CollectParameters(&m_nIp, 1); + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text, nil, nil, nil, nil, nil); + return 0; + } + case COMMAND_HAS_PHONE_DISPLAYED_MESSAGE: + { + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(gPhoneInfo.HasMessageBeenDisplayed(ScriptParams[0])); + return 0; + } + case COMMAND_TURN_PHONE_OFF: + { + CollectParameters(&m_nIp, 1); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], nil, nil, nil, nil, nil, nil); + return 0; + } + case COMMAND_DRAW_CORONA: + { + CollectParameters(&m_nIp, 9); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CCoronas::RegisterCorona((uintptr)this + m_nIp, ScriptParams[6], ScriptParams[7], ScriptParams[8], + 255, pos, *(float*)&ScriptParams[3], 150.0f, ScriptParams[4], ScriptParams[5], 1, 0, 0, 0.0f); + return 0; + } + case COMMAND_DRAW_LIGHT: + { + CollectParameters(&m_nIp, 6); + CVector pos = *(CVector*)&ScriptParams[0]; + CVector unused(0.0f, 0.0f, 0.0f); + CPointLights::AddLight(0, *(CVector*)&ScriptParams[0], CVector(0.0f, 0.0f, 0.0f), 12.0f, + ScriptParams[3] / 255.0f, ScriptParams[4] / 255.0f, ScriptParams[5] / 255.0f, 0, true); + return 0; + } + case COMMAND_STORE_WEATHER: + CWeather::StoreWeatherState(); + return 0; + case COMMAND_RESTORE_WEATHER: + CWeather::RestoreWeatherState(); + return 0; + case COMMAND_STORE_CLOCK: + CClock::StoreClock(); + return 0; + case COMMAND_RESTORE_CLOCK: + CClock::RestoreClock(); + return 0; + case COMMAND_RESTART_CRITICAL_MISSION: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRestart::OverrideNextRestart(pos, *(float*)&ScriptParams[3]); + if (CWorld::Players[CWorld::PlayerInFocus].m_WBState != WBSTATE_PLAYING) + printf("RESTART_CRITICAL_MISSION - Player state is not PLAYING\n"); + CWorld::Players[CWorld::PlayerInFocus].PlayerFailedCriticalMission(); + return 0; + } + case COMMAND_IS_PLAYER_PLAYING: + { + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CWorld::Players[ScriptParams[0]].m_WBState == WBSTATE_PLAYING); + return 0; + } + //case COMMAND_SET_COLL_OBJ_NO_OBJ: + default: + script_assert(0); + } + return -1; +} + +int8 CRunningScript::ProcessCommands600To699(int32 command) +{ + switch (command){ + /* Collective commands are not implemented until LCS. + case COMMAND_SET_COLL_OBJ_WAIT_ON_FOOT: + case COMMAND_SET_COLL_OBJ_FLEE_ON_FOOT_TILL_SAFE: + case COMMAND_SET_COLL_OBJ_GUARD_SPOT: + case COMMAND_SET_COLL_OBJ_GUARD_AREA: + case COMMAND_SET_COLL_OBJ_WAIT_IN_CAR: + case COMMAND_SET_COLL_OBJ_KILL_CHAR_ON_FOOT: + case COMMAND_SET_COLL_OBJ_KILL_PLAYER_ON_FOOT: + case COMMAND_SET_COLL_OBJ_KILL_CHAR_ANY_MEANS: + case COMMAND_SET_COLL_OBJ_KILL_PLAYER_ANY_MEANS: + case COMMAND_SET_COLL_OBJ_FLEE_CHAR_ON_FOOT_TILL_SAFE: + case COMMAND_SET_COLL_OBJ_FLEE_PLAYER_ON_FOOT_TILL_SAFE: + case COMMAND_SET_COLL_OBJ_FLEE_CHAR_ON_FOOT_ALWAYS: + case COMMAND_SET_COLL_OBJ_FLEE_PLAYER_ON_FOOT_ALWAYS: + case COMMAND_SET_COLL_OBJ_GOTO_CHAR_ON_FOOT: + case COMMAND_SET_COLL_OBJ_GOTO_PLAYER_ON_FOOT: + case COMMAND_SET_COLL_OBJ_LEAVE_CAR: + case COMMAND_SET_COLL_OBJ_ENTER_CAR_AS_PASSENGER: + case COMMAND_SET_COLL_OBJ_ENTER_CAR_AS_DRIVER: + case COMMAND_SET_COLL_OBJ_FOLLOW_CAR_IN_CAR: + case COMMAND_SET_COLL_OBJ_FIRE_AT_OBJECT_FROM_VEHICLE: + case COMMAND_SET_COLL_OBJ_DESTROY_OBJECT: + case COMMAND_SET_COLL_OBJ_DESTROY_CAR: + case COMMAND_SET_COLL_OBJ_GOTO_AREA_ON_FOOT: + case COMMAND_SET_COLL_OBJ_GOTO_AREA_IN_CAR: + case COMMAND_SET_COLL_OBJ_FOLLOW_CAR_ON_FOOT_WITH_OFFSET: + case COMMAND_SET_COLL_OBJ_GUARD_ATTACK: + case COMMAND_SET_COLL_OBJ_FOLLOW_ROUTE: + case COMMAND_SET_COLL_OBJ_GOTO_COORD_ON_FOOT: + case COMMAND_SET_COLL_OBJ_GOTO_COORD_IN_CAR: + case COMMAND_SET_COLL_OBJ_RUN_TO_AREA: + case COMMAND_SET_COLL_OBJ_RUN_TO_COORD: + case COMMAND_ADD_PEDS_IN_AREA_TO_COLL: + case COMMAND_ADD_PEDS_IN_VEHICLE_TO_COLL: + case COMMAND_CLEAR_COLL: + case COMMAND_IS_COLL_IN_CARS: + case COMMAND_LOCATE_COLL_ANY_MEANS_2D: + case COMMAND_LOCATE_COLL_ON_FOOT_2D: + case COMMAND_LOCATE_COLL_IN_CAR_2D: + case COMMAND_LOCATE_STOPPED_COLL_ANY_MEANS_2D: + case COMMAND_LOCATE_STOPPED_COLL_ON_FOOT_2D: + case COMMAND_LOCATE_STOPPED_COLL_IN_CAR_2D: + case COMMAND_LOCATE_COLL_ANY_MEANS_CHAR_2D: + case COMMAND_LOCATE_COLL_ON_FOOT_CHAR_2D: + case COMMAND_LOCATE_COLL_IN_CAR_CHAR_2D: + case COMMAND_LOCATE_COLL_ANY_MEANS_CAR_2D: + case COMMAND_LOCATE_COLL_ON_FOOT_CAR_2D: + case COMMAND_LOCATE_COLL_IN_CAR_CAR_2D: + case COMMAND_LOCATE_COLL_ANY_MEANS_PLAYER_2D: + case COMMAND_LOCATE_COLL_ON_FOOT_PLAYER_2D: + case COMMAND_LOCATE_COLL_IN_CAR_PLAYER_2D: + case COMMAND_IS_COLL_IN_AREA_2D: + case COMMAND_IS_COLL_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_COLL_IN_AREA_IN_CAR_2D: + case COMMAND_IS_COLL_STOPPED_IN_AREA_2D: + case COMMAND_IS_COLL_STOPPED_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_COLL_STOPPED_IN_AREA_IN_CAR_2D: + case COMMAND_GET_NUMBER_OF_PEDS_IN_COLL: + */ + case COMMAND_SET_CHAR_HEED_THREATS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bRespondsToThreats = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_PLAYER_HEED_THREATS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + pPed->bRespondsToThreats = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_GET_CONTROLLER_MODE: +#if defined(GTA_PC) && !defined(DETECT_PAD_INPUT_SWITCH) + ScriptParams[0] = 0; +#else + ScriptParams[0] = CPad::IsAffectedByController ? CPad::GetPad(0)->Mode : 0; +#endif + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_SET_CAN_RESPRAY_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + ((CAutomobile*)pVehicle)->bFixedColour = (ScriptParams[1] == 0); + return 0; + } + case COMMAND_IS_TAXI: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + int mi = pVehicle->GetModelIndex(); + UpdateCompareFlag(mi == MI_TAXI || mi == MI_CABBIE || mi == MI_BORGNINE); + return 0; + } + case COMMAND_UNLOAD_SPECIAL_CHARACTER: + CollectParameters(&m_nIp, 1); + CStreaming::SetMissionDoesntRequireSpecialChar(ScriptParams[0] - 1); + return 0; + case COMMAND_RESET_NUM_OF_MODELS_KILLED_BY_PLAYER: + CDarkel::ResetModelsKilledByPlayer(); + return 0; + case COMMAND_GET_NUM_OF_MODELS_KILLED_BY_PLAYER: + CollectParameters(&m_nIp, 1); + ScriptParams[0] = CDarkel::QueryModelsKilledByPlayer(ScriptParams[0]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_ACTIVATE_GARAGE: + CollectParameters(&m_nIp, 1); + CGarages::ActivateGarage(ScriptParams[0]); + return 0; + case COMMAND_SWITCH_TAXI_TIMER: + { + CollectParameters(&m_nIp, 1); + if (ScriptParams[0] != 0){ + CWorld::Players[CWorld::PlayerInFocus].m_nUnusedTaxiTimer = CTimer::GetTimeInMilliseconds(); + CWorld::Players[CWorld::PlayerInFocus].m_bUnusedTaxiThing = true; + }else{ + CWorld::Players[CWorld::PlayerInFocus].m_bUnusedTaxiThing = false; + } + return 0; + } + case COMMAND_CREATE_OBJECT_NO_OFFSET: + { + CollectParameters(&m_nIp, 4); + int mi = ScriptParams[0] >= 0 ? ScriptParams[0] : CTheScripts::UsedObjectArray[-ScriptParams[0]].index; + CObject* pObj = new CObject(mi, false); +; pObj->ObjectCreatedBy = MISSION_OBJECT; + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pObj->SetPosition(pos); + pObj->SetOrientation(0.0f, 0.0f, 0.0f); + pObj->GetMatrix().UpdateRW(); + pObj->UpdateRwFrame(); + CTheScripts::ClearSpaceForMissionEntity(pos, pObj); + CWorld::Add(pObj); + ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObj); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_OBJECT); + return 0; + } + case COMMAND_IS_BOAT: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); + return 0; + } + case COMMAND_SET_CHAR_OBJ_GOTO_AREA_ANY_MEANS: + { + CollectParameters(&m_nIp, 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + float infX = *(float*)&ScriptParams[1]; + float infY = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[1]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[2]; + } + CVector pos; + pos.x = (infX + supX) / 2; + pos.y = (infY + supY) / 2; + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = Max(pos.x - infX, pos.y - infY); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_GOTO_AREA_ANY_MEANS, pos, radius); + return 0; + } + //case COMMAND_SET_COLL_OBJ_GOTO_AREA_ANY_MEANS: + case COMMAND_IS_PLAYER_STOPPED: + { + CollectParameters(&m_nIp, 1); + CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; + UpdateCompareFlag(CTheScripts::IsPlayerStopped(pPlayer)); + return 0; + } + case COMMAND_IS_CHAR_STOPPED: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + UpdateCompareFlag(CTheScripts::IsPedStopped(pPed)); + return 0; + } + case COMMAND_MESSAGE_WAIT: + CollectParameters(&m_nIp, 2); + m_nWakeTime = CTimer::GetTimeInMilliseconds() + ScriptParams[0]; + if (ScriptParams[1] != 0) + m_bSkipWakeTime = true; + return 1; + case COMMAND_ADD_PARTICLE_EFFECT: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CParticleObject::AddObject(ScriptParams[0], pos, ScriptParams[4] != 0); + return 0; + } + case COMMAND_SWITCH_WIDESCREEN: + CollectParameters(&m_nIp, 1); + if (ScriptParams[0] != 0) + TheCamera.SetWideScreenOn(); + else + TheCamera.SetWideScreenOff(); + return 0; + case COMMAND_ADD_SPRITE_BLIP_FOR_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int id = CRadar::SetEntityBlip(BLIP_CAR, ScriptParams[0], 0, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(id, ScriptParams[1]); + ScriptParams[0] = id; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_SPRITE_BLIP_FOR_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int id = CRadar::SetEntityBlip(BLIP_CHAR, ScriptParams[0], 1, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(id, ScriptParams[1]); + ScriptParams[0] = id; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_SPRITE_BLIP_FOR_OBJECT: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int id = CRadar::SetEntityBlip(BLIP_OBJECT, ScriptParams[0], 6, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(id, ScriptParams[1]); + ScriptParams[0] = id; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_SPRITE_BLIP_FOR_CONTACT_POINT: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int id = CRadar::SetCoordBlip(BLIP_CONTACT_POINT, pos, 2, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(id, ScriptParams[3]); + ScriptParams[0] = id; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_SPRITE_BLIP_FOR_COORD: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int id = CRadar::SetCoordBlip(BLIP_COORD, pos, 5, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(id, ScriptParams[3]); + ScriptParams[0] = id; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CHAR_ONLY_DAMAGED_BY_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bOnlyDamagedByPlayer = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_CAR_ONLY_DAMAGED_BY_PLAYER: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bOnlyDamagedByPlayer = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_CHAR_PROOFS: + { + CollectParameters(&m_nIp, 6); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bBulletProof = (ScriptParams[1] != 0); + pPed->bFireProof = (ScriptParams[2] != 0); + pPed->bExplosionProof = (ScriptParams[3] != 0); + pPed->bCollisionProof = (ScriptParams[4] != 0); + pPed->bMeleeProof = (ScriptParams[5] != 0); + return 0; + } + case COMMAND_SET_CAR_PROOFS: + { + CollectParameters(&m_nIp, 6); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bBulletProof = (ScriptParams[1] != 0); + pVehicle->bFireProof = (ScriptParams[2] != 0); + pVehicle->bExplosionProof = (ScriptParams[3] != 0); + pVehicle->bCollisionProof = (ScriptParams[4] != 0); + pVehicle->bMeleeProof = (ScriptParams[5] != 0); + return 0; + } + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_2D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_3D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: + PlayerInAngledAreaCheckCommand(command, &m_nIp); + return 0; + case COMMAND_DEACTIVATE_GARAGE: + CollectParameters(&m_nIp, 1); + CGarages::DeActivateGarage(ScriptParams[0]); + return 0; + case COMMAND_GET_NUMBER_OF_CARS_COLLECTED_BY_GARAGE: + CollectParameters(&m_nIp, 1); + ScriptParams[0] = CGarages::QueryCarsCollected(ScriptParams[0]); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_HAS_CAR_BEEN_TAKEN_TO_GARAGE: + CollectParameters(&m_nIp, 2); + UpdateCompareFlag(CGarages::HasThisCarBeenCollected(ScriptParams[0], ScriptParams[1] - 1)); + return 0; + default: + script_assert(0); + } + return -1; +} + +int8 CRunningScript::ProcessCommands700To799(int32 command) +{ + switch (command){ + case COMMAND_SET_SWAT_REQUIRED: + CollectParameters(&m_nIp, 1); + FindPlayerPed()->m_pWanted->m_bSwatRequired = (ScriptParams[0] != 0); + return 0; + case COMMAND_SET_FBI_REQUIRED: + CollectParameters(&m_nIp, 1); + FindPlayerPed()->m_pWanted->m_bFbiRequired = (ScriptParams[0] != 0); + return 0; + case COMMAND_SET_ARMY_REQUIRED: + CollectParameters(&m_nIp, 1); + FindPlayerPed()->m_pWanted->m_bArmyRequired = (ScriptParams[0] != 0); + return 0; + case COMMAND_IS_CAR_IN_WATER: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + UpdateCompareFlag(pVehicle && pVehicle->bIsInWater); + return 0; + } + case COMMAND_GET_CLOSEST_CHAR_NODE: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CPathNode* pNode = &ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, 1, 999999.9f)]; + *(CVector*)&ScriptParams[0] = pNode->GetPosition(); + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_GET_CLOSEST_CAR_NODE: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CPathNode* pNode = &ThePaths.m_pathNodes[ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f)]; + *(CVector*)&ScriptParams[0] = pNode->GetPosition(); + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_CAR_GOTO_COORDINATES_ACCURATE: + { + CollectParameters(&m_nIp, 4); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += pVehicle->GetDistanceFromCentreOfMassToBaseOfModel(); + if (CCarCtrl::JoinCarWithRoadSystemGotoCoors(pVehicle, pos, false)) + pVehicle->AutoPilot.m_nCarMission = MISSION_GOTO_COORDS_STRAIGHT_ACCURATE; + else + pVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_ACCURATE; + pVehicle->SetStatus(STATUS_PHYSICS); + pVehicle->bEngineOn = true; + pVehicle->AutoPilot.m_nCruiseSpeed = Max(6, pVehicle->AutoPilot.m_nCruiseSpeed); + pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds(); + return 0; + } + case COMMAND_START_PACMAN_RACE: + CollectParameters(&m_nIp, 1); + CPacManPickups::StartPacManRace(ScriptParams[0]); + return 0; + case COMMAND_START_PACMAN_RECORD: + CPacManPickups::StartPacManRecord(); + return 0; + case COMMAND_GET_NUMBER_OF_POWER_PILLS_EATEN: + ScriptParams[0] = CPacManPickups::QueryPowerPillsEatenInRace(); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_CLEAR_PACMAN: + CPacManPickups::CleanUpPacManStuff(); + return 0; + case COMMAND_START_PACMAN_SCRAMBLE: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CPacManPickups::StartPacManScramble(pos, *(float*)&ScriptParams[3], ScriptParams[4]); + return 0; + } + case COMMAND_GET_NUMBER_OF_POWER_PILLS_CARRIED: + ScriptParams[0] = CPacManPickups::QueryPowerPillsCarriedByPlayer(); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_CLEAR_NUMBER_OF_POWER_PILLS_CARRIED: + CPacManPickups::ResetPowerPillsCarriedByPlayer(); + return 0; + case COMMAND_IS_CAR_ON_SCREEN: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(TheCamera.IsSphereVisible(pVehicle->GetBoundCentre(), pVehicle->GetBoundRadius())); + return 0; + } + case COMMAND_IS_CHAR_ON_SCREEN: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(TheCamera.IsSphereVisible(pPed->GetBoundCentre(), pPed->GetBoundRadius())); + return 0; + } + case COMMAND_IS_OBJECT_ON_SCREEN: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + UpdateCompareFlag(TheCamera.IsSphereVisible(pObject->GetBoundCentre(), pObject->GetBoundRadius())); + return 0; + } + case COMMAND_GOSUB_FILE: + { + CollectParameters(&m_nIp, 2); + script_assert(m_nStackPointer < MAX_STACK_DEPTH); + m_anStack[m_nStackPointer++] = m_nIp; + SetIP(ScriptParams[0]); + // ScriptParams[1] == filename + return 0; + } + case COMMAND_GET_GROUND_Z_FOR_3D_COORD: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + bool success; + *(float*)&ScriptParams[0] = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &success); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_START_SCRIPT_FIRE: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + ScriptParams[0] = gFireManager.StartScriptFire(pos, nil, 0.8f, 1); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_SCRIPT_FIRE_EXTINGUISHED: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(gFireManager.IsScriptFireExtinguish(ScriptParams[0])); + return 0; + case COMMAND_REMOVE_SCRIPT_FIRE: + CollectParameters(&m_nIp, 1); + gFireManager.RemoveScriptFire(ScriptParams[0]); + return 0; + case COMMAND_SET_COMEDY_CONTROLS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bComedyControls = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_BOAT_GOTO_COORDS: + { + CollectParameters(&m_nIp, 4); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); + CBoat* pBoat = (CBoat*)pVehicle; + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + CWaterLevel::GetWaterLevel(pos.x, pos.y, pos.z, &pos.z, false); + pBoat->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_ASTHECROWSWIMS; + pBoat->AutoPilot.m_vecDestinationCoors = pos; + pBoat->SetStatus(STATUS_PHYSICS); + pBoat->AutoPilot.m_nCruiseSpeed = Max(6, pBoat->AutoPilot.m_nCruiseSpeed); + pBoat->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds(); + return 0; + } + case COMMAND_BOAT_STOP: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); + CBoat* pBoat = (CBoat*)pVehicle; + pBoat->AutoPilot.m_nCarMission = MISSION_NONE; + pBoat->SetStatus(STATUS_PHYSICS); + pBoat->bEngineOn = false; + pBoat->AutoPilot.m_nCruiseSpeed = 0; + return 0; + } + case COMMAND_IS_PLAYER_SHOOTING_IN_AREA: + { + CollectParameters(&m_nIp, 6); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + float x1 = *(float*)&ScriptParams[1]; + float y1 = *(float*)&ScriptParams[2]; + float x2 = *(float*)&ScriptParams[3]; + float y2 = *(float*)&ScriptParams[4]; + UpdateCompareFlag(pPed->bIsShooting && pPed->IsWithinArea(x1, y1, x2, y2)); + if (ScriptParams[5]) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugSquare(x1, y1, x2, y2); + return 0; + } + case COMMAND_IS_CHAR_SHOOTING_IN_AREA: + { + CollectParameters(&m_nIp, 6); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + float x1 = *(float*)&ScriptParams[1]; + float y1 = *(float*)&ScriptParams[2]; + float x2 = *(float*)&ScriptParams[3]; + float y2 = *(float*)&ScriptParams[4]; + UpdateCompareFlag(pPed->bIsShooting && pPed->IsWithinArea(x1, y1, x2, y2)); + if (ScriptParams[5]) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, x1, y1, x2, y2, MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugSquare(x1, y1, x2, y2); + return 0; + } + case COMMAND_IS_CURRENT_PLAYER_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + UpdateCompareFlag(ScriptParams[1] == pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType); + return 0; + } + case COMMAND_IS_CURRENT_CHAR_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(ScriptParams[1] == pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType); + return 0; + } + case COMMAND_CLEAR_NUMBER_OF_POWER_PILLS_EATEN: + CPacManPickups::ResetPowerPillsEatenInRace(); + return 0; + case COMMAND_ADD_POWER_PILL: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CPacManPickups::GenerateOnePMPickUp(pos); + return 0; + } + case COMMAND_SET_BOAT_CRUISE_SPEED: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_BOAT); + CBoat* pBoat = (CBoat*)pVehicle; + pBoat->AutoPilot.m_nCruiseSpeed = *(float*)&ScriptParams[1]; + return 0; + } + case COMMAND_GET_RANDOM_CHAR_IN_AREA: + { + CollectParameters(&m_nIp, 4); + int ped_handle = -1; + CVector pos = FindPlayerCoors(); + float x1 = *(float*)&ScriptParams[0]; + float y1 = *(float*)&ScriptParams[1]; + float x2 = *(float*)&ScriptParams[2]; + float y2 = *(float*)&ScriptParams[3]; + int i = CPools::GetPedPool()->GetSize(); + while (--i && ped_handle == -1){ + CPed* pPed = CPools::GetPedPool()->GetSlot(i); + if (!pPed) + continue; + if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) + continue; + if (pPed->CharCreatedBy != RANDOM_CHAR) + continue; + if (!pPed->IsPedInControl()) + continue; + if (pPed->bRemoveFromWorld) + continue; + if (pPed->bFadeOut) + continue; + if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) + continue; + if (!ThisIsAValidRandomPed(pPed->m_nPedType)) + continue; + if (pPed->bIsLeader || pPed->m_leader) + continue; + if (!pPed->IsWithinArea(x1, y1, x2, y2)) + continue; + if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) + continue; + if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) + continue; + ped_handle = CPools::GetPedPool()->GetIndex(pPed); + CTheScripts::LastRandomPedId = ped_handle; + pPed->CharCreatedBy = MISSION_CHAR; + pPed->bRespondsToThreats = false; + ++CPopulation::ms_nTotalMissionPeds; + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + } + ScriptParams[0] = ped_handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_RANDOM_CHAR_IN_ZONE: + { + char zone[KEY_LENGTH_IN_SCRIPT]; + strncpy(zone, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone); + if (nZone != -1) + m_nIp += KEY_LENGTH_IN_SCRIPT; + CZone* pZone = CTheZones::GetZone(nZone); + int ped_handle = -1; + CVector pos = FindPlayerCoors(); + int i = CPools::GetPedPool()->GetSize(); + while (--i && ped_handle == -1) { + CPed* pPed = CPools::GetPedPool()->GetSlot(i); + if (!pPed) + continue; + if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) + continue; + if (pPed->CharCreatedBy != RANDOM_CHAR) + continue; + if (!pPed->IsPedInControl()) + continue; + if (pPed->bRemoveFromWorld) + continue; + if (pPed->bFadeOut) + continue; + if (pPed->GetModelIndex() == MI_SCUM_WOM || pPed->GetModelIndex() == MI_SCUM_MAN) + continue; + if (!ThisIsAValidRandomPed(pPed->m_nPedType)) + continue; + if (pPed->bIsLeader || pPed->m_leader) + continue; + if (!CTheZones::PointLiesWithinZone(&pPed->GetPosition(), pZone)) + continue; + if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) + continue; + if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) + continue; + ped_handle = CPools::GetPedPool()->GetIndex(pPed); + CTheScripts::LastRandomPedId = ped_handle; + pPed->CharCreatedBy = MISSION_CHAR; + pPed->bRespondsToThreats = false; + ++CPopulation::ms_nTotalMissionPeds; + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + } + ScriptParams[0] = ped_handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_PLAYER_IN_TAXI: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->IsTaxi()); + return 0; + } + case COMMAND_IS_PLAYER_SHOOTING: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + UpdateCompareFlag(pPed->bIsShooting); + return 0; + } + case COMMAND_IS_CHAR_SHOOTING: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(pPed->bIsShooting); + return 0; + } + case COMMAND_CREATE_MONEY_PICKUP: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_MONEY, PICKUP_MONEY, ScriptParams[3]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CHAR_ACCURACY: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->m_wepAccuracy = ScriptParams[1]; + return 0; + } + case COMMAND_GET_CAR_SPEED: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + *(float*)&ScriptParams[0] = pVehicle->GetSpeed().Magnitude() * GAME_SPEED_TO_METERS_PER_SECOND; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_LOAD_CUTSCENE: + { + char name[KEY_LENGTH_IN_SCRIPT]; + strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CCutsceneMgr::LoadCutsceneData(name); + return 0; + } + case COMMAND_CREATE_CUTSCENE_OBJECT: + { + CollectParameters(&m_nIp, 1); + CCutsceneObject* pCutObj = CCutsceneMgr::CreateCutsceneObject(ScriptParams[0]); + ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pCutObj); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CUTSCENE_ANIM: + { + CollectParameters(&m_nIp, 1); + char name[KEY_LENGTH_IN_SCRIPT]; + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CCutsceneMgr::SetCutsceneAnim(name, pObject); + return 0; + } + case COMMAND_START_CUTSCENE: + CCutsceneMgr::ms_cutsceneLoadStatus = 1; + return 0; + case COMMAND_GET_CUTSCENE_TIME: + ScriptParams[0] = CCutsceneMgr::GetCutsceneTimeInMilleseconds(); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_HAS_CUTSCENE_FINISHED: + UpdateCompareFlag(CCutsceneMgr::HasCutsceneFinished()); + return 0; + case COMMAND_CLEAR_CUTSCENE: + CCutsceneMgr::DeleteCutsceneData(); + return 0; + case COMMAND_RESTORE_CAMERA_JUMPCUT: + TheCamera.RestoreWithJumpCut(); + return 0; + case COMMAND_CREATE_COLLECTABLE1: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + CPickups::GenerateNewOne(pos, MI_COLLECTABLE1, PICKUP_COLLECTABLE1, 0); + return 0; + } + case COMMAND_SET_COLLECTABLE1_TOTAL: + CollectParameters(&m_nIp, 1); + CWorld::Players[CWorld::PlayerInFocus].m_nTotalPackages = ScriptParams[0]; + return 0; + case COMMAND_IS_PROJECTILE_IN_AREA: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + UpdateCompareFlag(CProjectileInfo::IsProjectileInRange(infX, supX, infY, supY, infZ, supZ, false)); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); + return 0; + } + case COMMAND_DESTROY_PROJECTILES_IN_AREA: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + UpdateCompareFlag(CProjectileInfo::IsProjectileInRange(infX, supX, infY, supY, infZ, supZ, true)); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); + return 0; + } + case COMMAND_DROP_MINE: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + CPickups::GenerateNewOne(pos, MI_CARMINE, PICKUP_MINE_INACTIVE, 0); + return 0; + } + case COMMAND_DROP_NAUTICAL_MINE: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + CPickups::GenerateNewOne(pos, MI_NAUTICALMINE, PICKUP_MINE_INACTIVE, 0); + return 0; + } + case COMMAND_IS_CHAR_MODEL: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(ScriptParams[1] == pPed->GetModelIndex()); + return 0; + } + case COMMAND_LOAD_SPECIAL_MODEL: + { + CollectParameters(&m_nIp, 1); + char name[KEY_LENGTH_IN_SCRIPT]; + strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + name[i] = tolower(name[i]); + CStreaming::RequestSpecialModel(ScriptParams[0], name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); + m_nIp += KEY_LENGTH_IN_SCRIPT; + return 0; + } + case COMMAND_CREATE_CUTSCENE_HEAD: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CCutsceneHead* pCutHead = CCutsceneMgr::AddCutsceneHead(pObject, ScriptParams[1]); + ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pCutHead); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CUTSCENE_HEAD_ANIM: + { + CollectParameters(&m_nIp, 1); + CObject* pCutHead = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pCutHead); + char name[KEY_LENGTH_IN_SCRIPT]; + strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CTimer::Stop(); + CCutsceneMgr::SetHeadAnim(name, pCutHead); + CTimer::Update(); + return 0; + } + case COMMAND_SIN: + CollectParameters(&m_nIp, 1); + *(float*)&ScriptParams[0] = Sin(DEGTORAD(*(float*)&ScriptParams[0])); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_COS: + CollectParameters(&m_nIp, 1); + *(float*)&ScriptParams[0] = Cos(DEGTORAD(*(float*)&ScriptParams[0])); + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_GET_CAR_FORWARD_X: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + float forwardX = pVehicle->GetForward().x / pVehicle->GetForward().Magnitude2D(); + *(float*)&ScriptParams[0] = forwardX; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_CAR_FORWARD_Y: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + float forwardY = pVehicle->GetForward().y / pVehicle->GetForward().Magnitude2D(); + *(float*)&ScriptParams[0] = forwardY; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CHANGE_GARAGE_TYPE: + CollectParameters(&m_nIp, 2); + CGarages::ChangeGarageType(ScriptParams[0], (eGarageType)ScriptParams[1], 0); + return 0; + case COMMAND_ACTIVATE_CRUSHER_CRANE: + { + CollectParameters(&m_nIp, 10); + float infX = *(float*)&ScriptParams[2]; + float infY = *(float*)&ScriptParams[3]; + float supX = *(float*)&ScriptParams[4]; + float supY = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[4]; + supX = *(float*)&ScriptParams[2]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[5]; + supY = *(float*)&ScriptParams[3]; + } + CCranes::ActivateCrane(infX, supX, infY, supY, + *(float*)&ScriptParams[6], *(float*)&ScriptParams[7], *(float*)&ScriptParams[8], + DEGTORAD(*(float*)&ScriptParams[9]), true, false, + *(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + return 0; + } + case COMMAND_PRINT_WITH_2_NUMBERS: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 4); + CMessages::AddMessageWithNumber(text, ScriptParams[2], ScriptParams[3], ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_2_NUMBERS_NOW: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 4); + CMessages::AddMessageJumpQWithNumber(text, ScriptParams[2], ScriptParams[3], ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_2_NUMBERS_SOON: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 4); + CMessages::AddMessageSoonWithNumber(text, ScriptParams[2], ScriptParams[3], ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_3_NUMBERS: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 5); + CMessages::AddMessageWithNumber(text, ScriptParams[3], ScriptParams[4], ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_3_NUMBERS_NOW: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 5); + CMessages::AddMessageJumpQWithNumber(text, ScriptParams[3], ScriptParams[4], ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_3_NUMBERS_SOON: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 5); + CMessages::AddMessageSoonWithNumber(text, ScriptParams[3], ScriptParams[4], ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_4_NUMBERS: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 6); + CMessages::AddMessageWithNumber(text, ScriptParams[4], ScriptParams[5], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_4_NUMBERS_NOW: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 6); + CMessages::AddMessageJumpQWithNumber(text, ScriptParams[4], ScriptParams[5], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_4_NUMBERS_SOON: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 6); + CMessages::AddMessageSoonWithNumber(text, ScriptParams[4], ScriptParams[5], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_5_NUMBERS: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 7); + CMessages::AddMessageWithNumber(text, ScriptParams[5], ScriptParams[6], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); + return 0; + } + case COMMAND_PRINT_WITH_5_NUMBERS_NOW: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 7); + CMessages::AddMessageJumpQWithNumber(text, ScriptParams[5], ScriptParams[6], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); + return 0; + } + case COMMAND_PRINT_WITH_5_NUMBERS_SOON: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 7); + CMessages::AddMessageSoonWithNumber(text, ScriptParams[5], ScriptParams[6], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); + return 0; + } + case COMMAND_PRINT_WITH_6_NUMBERS: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 8); + CMessages::AddMessageWithNumber(text, ScriptParams[6], ScriptParams[7], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); + return 0; + } + case COMMAND_PRINT_WITH_6_NUMBERS_NOW: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 8); + CMessages::AddMessageJumpQWithNumber(text, ScriptParams[6], ScriptParams[7], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); + return 0; + } + case COMMAND_PRINT_WITH_6_NUMBERS_SOON: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 8); + CMessages::AddMessageSoonWithNumber(text, ScriptParams[6], ScriptParams[7], ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FOLLOW_CHAR_IN_FORMATION: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTargetPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FOLLOW_CHAR_IN_FORMATION, pTargetPed); + pPed->SetFormation((eFormation)ScriptParams[2]); + return 0; + } + case COMMAND_PLAYER_MADE_PROGRESS: + CollectParameters(&m_nIp, 1); + CStats::ProgressMade += ScriptParams[0]; + return 0; + case COMMAND_SET_PROGRESS_TOTAL: + CollectParameters(&m_nIp, 1); + CStats::TotalProgressInGame = ScriptParams[0]; + return 0; + case COMMAND_REGISTER_JUMP_DISTANCE: + CollectParameters(&m_nIp, 1); + CStats::MaximumJumpDistance = Max(CStats::MaximumJumpDistance, *(float*)&ScriptParams[0]); + return 0; + case COMMAND_REGISTER_JUMP_HEIGHT: + CollectParameters(&m_nIp, 1); + CStats::MaximumJumpHeight = Max(CStats::MaximumJumpHeight, *(float*)&ScriptParams[0]); + return 0; + case COMMAND_REGISTER_JUMP_FLIPS: + CollectParameters(&m_nIp, 1); + CStats::MaximumJumpFlips = Max(CStats::MaximumJumpFlips, ScriptParams[0]); + return 0; + case COMMAND_REGISTER_JUMP_SPINS: + CollectParameters(&m_nIp, 1); + CStats::MaximumJumpSpins = Max(CStats::MaximumJumpSpins, ScriptParams[0]); + return 0; + case COMMAND_REGISTER_JUMP_STUNT: + CollectParameters(&m_nIp, 1); + CStats::BestStuntJump = Max(CStats::BestStuntJump, ScriptParams[0]); + return 0; + case COMMAND_REGISTER_UNIQUE_JUMP_FOUND: + ++CStats::NumberOfUniqueJumpsFound; + return 0; + case COMMAND_SET_UNIQUE_JUMPS_TOTAL: + CollectParameters(&m_nIp, 1); + CStats::TotalNumberOfUniqueJumps = ScriptParams[0]; + return 0; + case COMMAND_REGISTER_PASSENGER_DROPPED_OFF_TAXI: + ++CStats::PassengersDroppedOffWithTaxi; + return 0; + case COMMAND_REGISTER_MONEY_MADE_TAXI: + CollectParameters(&m_nIp, 1); + CStats::MoneyMadeWithTaxi += ScriptParams[0]; + return 0; + case COMMAND_REGISTER_MISSION_GIVEN: + ++CStats::MissionsGiven; + return 0; + case COMMAND_REGISTER_MISSION_PASSED: + { + char name[KEY_LENGTH_IN_SCRIPT]; + strncpy(name, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + m_nIp += KEY_LENGTH_IN_SCRIPT; + strncpy(CStats::LastMissionPassedName, name, KEY_LENGTH_IN_SCRIPT); + ++CStats::MissionsPassed; + CStats::CheckPointReachedSuccessfully(); + return 0; + } + case COMMAND_SET_CHAR_RUNNING: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bIsRunning = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_REMOVE_ALL_SCRIPT_FIRES: + gFireManager.RemoveAllScriptFires(); + return 0; + case COMMAND_IS_FIRST_CAR_COLOUR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->m_currentColour1 == ScriptParams[1]); + return 0; + } + case COMMAND_IS_SECOND_CAR_COLOUR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->m_currentColour2 == ScriptParams[1]); + return 0; + } + case COMMAND_HAS_CHAR_BEEN_DAMAGED_BY_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + if (!pPed) + printf("HAS_CHAR_BEEN_DAMAGED_BY_WEAPON - Character doesn't exist\n"); + UpdateCompareFlag(pPed && pPed->m_lastWepDam == ScriptParams[1]); + return 0; + } + case COMMAND_HAS_CAR_BEEN_DAMAGED_BY_WEAPON: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + if (!pVehicle) + printf("HAS_CAR_BEEN_DAMAGED_BY_WEAPON - Vehicle doesn't exist\n"); + UpdateCompareFlag(pVehicle && pVehicle->m_nLastWeaponDamage == ScriptParams[1]); + return 0; + } + case COMMAND_IS_CHAR_IN_CHARS_GROUP: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CPed* pLeader = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pPed); + script_assert(pLeader); + UpdateCompareFlag(pPed->m_leader == pLeader); + return 0; + } + default: + script_assert(0); + } + return -1; +} diff --git a/src/control/Script4.cpp b/src/control/Script4.cpp new file mode 100644 index 00000000..f5fb9781 --- /dev/null +++ b/src/control/Script4.cpp @@ -0,0 +1,2027 @@ +#include "common.h" + +#include "Script.h" +#include "ScriptCommands.h" + +#include "AnimBlendAssociation.h" +#include "BulletInfo.h" +#include "CarAI.h" +#include "CarCtrl.h" +#include "CivilianPed.h" +#include "Cranes.h" +#include "DMAudio.h" +#include "Darkel.h" +#include "Explosion.h" +#include "Fire.h" +#include "Frontend.h" +#include "Garages.h" +#include "General.h" +#include "Heli.h" +#include "Hud.h" +#include "Messages.h" +#include "ParticleObject.h" +#include "PedRoutes.h" +#include "Phones.h" +#include "Pickups.h" +#include "Plane.h" +#include "Pools.h" +#include "Population.h" +#include "Radar.h" +#include "Record.h" +#include "RpAnimBlend.h" +#include "Rubbish.h" +#include "SpecialFX.h" +#include "Stats.h" +#include "Streaming.h" +#include "TxdStore.h" +#include "User.h" +#include "WaterLevel.h" +#include "World.h" +#include "Zones.h" + +int8 CRunningScript::ProcessCommands800To899(int32 command) +{ + CMatrix tmp_matrix; + switch (command) { + case COMMAND_IS_CHAR_IN_PLAYERS_GROUP: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CPed* pLeader = CWorld::Players[ScriptParams[1]].m_pPed; + script_assert(pPed); + script_assert(pLeader); + UpdateCompareFlag(pPed->m_leader == pLeader); + return 0; + } + case COMMAND_EXPLODE_CHAR_HEAD: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + if (pPed->m_nPedState == PED_DRIVING) { + pPed->SetDead(); + if (!pPed->IsPlayer()) + pPed->FlagToDestroyWhenNextProcessed(); + } + else if (CGame::nastyGame && pPed->IsPedInControl()) { + pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, pPed->GetNodePosition(PED_HEAD), true); + } + else { + pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } + return 0; + } + case COMMAND_EXPLODE_PLAYER_HEAD: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + if (CGame::nastyGame) { + pPed->ApplyHeadShot(WEAPONTYPE_SNIPERRIFLE, pPed->GetNodePosition(PED_HEAD), true); + } + else { + pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + } + return 0; + } + case COMMAND_ANCHOR_BOAT: + { + CollectParameters(&m_nIp, 2); + CBoat* pBoat = (CBoat*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pBoat && pBoat->m_vehType == VEHICLE_TYPE_BOAT); + pBoat->m_bIsAnchored = (ScriptParams[1] == 0); + return 0; + } + case COMMAND_SET_ZONE_GROUP: + { + char zone[KEY_LENGTH_IN_SCRIPT]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CollectParameters(&m_nIp, 2); + int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); + if (zone_id < 0) { + printf("Couldn't find zone - %s\n", zone); + return 0; + } + CTheZones::SetPedGroup(zone_id, ScriptParams[0], ScriptParams[1]); + return 0; + } + case COMMAND_START_CAR_FIRE: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + ScriptParams[0] = gFireManager.StartScriptFire(pVehicle->GetPosition(), pVehicle, 0.8f, 1); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_START_CHAR_FIRE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + ScriptParams[0] = gFireManager.StartScriptFire(pPed->GetPosition(), pPed, 0.8f, 1); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_AREA: + { + CollectParameters(&m_nIp, 5); + int handle = -1; + uint32 i = CPools::GetVehiclePool()->GetSize(); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float supX = *(float*)&ScriptParams[2]; + float supY = *(float*)&ScriptParams[3]; + while (i--) { + CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); + if (!pVehicle) + continue; + if (ScriptParams[4] != pVehicle->GetModelIndex() && ScriptParams[4] >= 0) + continue; + if (pVehicle->VehicleCreatedBy != RANDOM_VEHICLE) + continue; + if (!pVehicle->IsWithinArea(infX, infY, supX, supY)) + continue; + handle = CPools::GetVehiclePool()->GetIndex(pVehicle); + pVehicle->VehicleCreatedBy = MISSION_VEHICLE; + ++CCarCtrl::NumMissionCars; + --CCarCtrl::NumRandomCars; + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); + } + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_RANDOM_CAR_OF_TYPE_IN_ZONE: + { + char zone[KEY_LENGTH_IN_SCRIPT]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); + int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); + if (zone_id != -1) + m_nIp += KEY_LENGTH_IN_SCRIPT; + CZone* pZone = CTheZones::GetZone(zone_id); + CollectParameters(&m_nIp, 1); + int handle = -1; + uint32 i = CPools::GetVehiclePool()->GetSize(); + while (i--) { + CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); + if (!pVehicle) + continue; + if (ScriptParams[0] != pVehicle->GetModelIndex() && ScriptParams[0] >= 0) + continue; + if (pVehicle->VehicleCreatedBy != RANDOM_VEHICLE) + continue; + if (!CTheZones::PointLiesWithinZone(&pVehicle->GetPosition(), pZone)) + continue; + handle = CPools::GetVehiclePool()->GetIndex(pVehicle); + pVehicle->VehicleCreatedBy = MISSION_VEHICLE; + ++CCarCtrl::NumMissionCars; + --CCarCtrl::NumRandomCars; + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(handle, CLEANUP_CAR); + } + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_HAS_RESPRAY_HAPPENED: + { + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CGarages::HasResprayHappened(ScriptParams[0])); + return 0; + } + case COMMAND_SET_CAMERA_ZOOM: + { + CollectParameters(&m_nIp, 1); + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_FOLLOWPED) + TheCamera.SetZoomValueFollowPedScript(ScriptParams[0]); + else if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_CAM_ON_A_STRING) + TheCamera.SetZoomValueCamStringScript(ScriptParams[0]); + return 0; + } + case COMMAND_CREATE_PICKUP_WITH_AMMO: + { + CollectParameters(&m_nIp, 6); + int16 model = ScriptParams[0]; + if (model < 0) + model = CTheScripts::UsedObjectArray[-model].index; + CVector pos = *(CVector*)&ScriptParams[3]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + CPickups::GetActualPickupIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CPickups::GenerateNewOne(pos, model, ScriptParams[1], ScriptParams[2]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CAR_RAM_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CCarAI::TellCarToRamOtherCar(pVehicle, pTarget); + return 0; + } + case COMMAND_SET_CAR_BLOCK_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CCarAI::TellCarToBlockOtherCar(pVehicle, pTarget); + return 0; + } + case COMMAND_SET_CHAR_OBJ_CATCH_TRAIN: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_CATCH_TRAIN); + return 0; + } + //case COMMAND_SET_COLL_OBJ_CATCH_TRAIN: + case COMMAND_SET_PLAYER_NEVER_GETS_TIRED: + { + CollectParameters(&m_nIp, 2); + CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; + pPlayer->m_bInfiniteSprint = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_PLAYER_FAST_RELOAD: + { + CollectParameters(&m_nIp, 2); + CPlayerInfo* pPlayer = &CWorld::Players[ScriptParams[0]]; + pPlayer->m_bFastReload = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_CHAR_BLEEDING: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bPedIsBleeding = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_CAR_FUNNY_SUSPENSION: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + // no action + return 0; + } + case COMMAND_SET_CAR_BIG_WHEELS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + CAutomobile* pCar = (CAutomobile*)pVehicle; + pCar->bBigWheels = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_FREE_RESPRAYS: + CollectParameters(&m_nIp, 1); + CGarages::SetFreeResprays(ScriptParams[0] != 0); + return 0; + case COMMAND_SET_PLAYER_VISIBLE: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + pPed->bIsVisible = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_CHAR_VISIBLE: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bIsVisible = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_SET_CAR_VISIBLE: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bIsVisible = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_IS_AREA_OCCUPIED: + { + CollectParameters(&m_nIp, 11); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + int16 total; + CWorld::FindObjectsIntersectingCube(CVector(infX, infY, infZ), CVector(supX, supY, supZ), &total, 2, nil, + !!ScriptParams[6], !!ScriptParams[7], !!ScriptParams[8], !!ScriptParams[9], !!ScriptParams[10]); + UpdateCompareFlag(total > 0); + return 0; + } + case COMMAND_START_DRUG_RUN: + CPlane::CreateIncomingCesna(); + return 0; + case COMMAND_HAS_DRUG_RUN_BEEN_COMPLETED: + UpdateCompareFlag(CPlane::HasCesnaLanded()); + return 0; + case COMMAND_HAS_DRUG_PLANE_BEEN_SHOT_DOWN: + UpdateCompareFlag(CPlane::HasCesnaBeenDestroyed()); + return 0; + case COMMAND_SAVE_PLAYER_FROM_FIRES: + CollectParameters(&m_nIp, 1); + gFireManager.ExtinguishPoint(CWorld::Players[ScriptParams[0]].GetPos(), 3.0f); + return 0; + case COMMAND_DISPLAY_TEXT: + { + CollectParameters(&m_nIp, 2); + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtX = *(float*)&ScriptParams[0]; + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtY = *(float*)&ScriptParams[1]; + uint16 len = CMessages::GetWideStringLength(text); + for (uint16 i = 0; i < len; i++) + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_Text[i] = text[i]; + for (uint16 i = len; i < SCRIPT_TEXT_MAX_LENGTH; i++) + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_Text[i] = 0; + ++CTheScripts::NumberOfIntroTextLinesThisFrame; + return 0; + } + case COMMAND_SET_TEXT_SCALE: + { + CollectParameters(&m_nIp, 2); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fScaleX = *(float*)&ScriptParams[0]; + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fScaleY = *(float*)&ScriptParams[1]; + return 0; + } + case COMMAND_SET_TEXT_COLOUR: + { + CollectParameters(&m_nIp, 4); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_sColor = + CRGBA(ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3]); + return 0; + } + case COMMAND_SET_TEXT_JUSTIFY: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bJustify = (ScriptParams[0] != 0); + return 0; + } + case COMMAND_SET_TEXT_CENTRE: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bCentered = (ScriptParams[0] != 0); + return 0; + } + case COMMAND_SET_TEXT_WRAPX: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fWrapX = *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SET_TEXT_CENTRE_SIZE: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fCenterSize = *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SET_TEXT_BACKGROUND: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bBackground = (ScriptParams[0] != 0); + return 0; + } + case COMMAND_SET_TEXT_BACKGROUND_COLOUR: + { + CollectParameters(&m_nIp, 4); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_sBackgroundColor = + CRGBA(ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3]); + return 0; + } + case COMMAND_SET_TEXT_BACKGROUND_ONLY_TEXT: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bBackgroundOnly = (ScriptParams[0] != 0); + return 0; + } + case COMMAND_SET_TEXT_PROPORTIONAL: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bTextProportional = (ScriptParams[0] != 0); + return 0; + } + case COMMAND_SET_TEXT_FONT: + { + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_nFont = ScriptParams[0]; + return 0; + } + case COMMAND_INDUSTRIAL_PASSED: + CStats::IndustrialPassed = true; + DMAudio.PlayRadioAnnouncement(STREAMED_SOUND_ANNOUNCE_COMMERCIAL_OPEN); + return 0; + case COMMAND_COMMERCIAL_PASSED: + CStats::CommercialPassed = true; + DMAudio.PlayRadioAnnouncement(STREAMED_SOUND_ANNOUNCE_SUBURBAN_OPEN); + return 0; + case COMMAND_SUBURBAN_PASSED: + CStats::SuburbanPassed = true; + return 0; + case COMMAND_ROTATE_OBJECT: + { + CollectParameters(&m_nIp, 4); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + float heading = LimitAngleOnCircle( + RADTODEG(Atan2(-pObject->GetForward().x, pObject->GetForward().y))); + float headingTarget = *(float*)&ScriptParams[1]; +#ifdef FIX_BUGS + float rotateBy = *(float*)&ScriptParams[2] * CTimer::GetTimeStepFix(); +#else + float rotateBy = *(float*)&ScriptParams[2]; +#endif + if (headingTarget == heading) { // using direct comparasion here is fine + UpdateCompareFlag(true); + return 0; + } + float angleClockwise = LimitAngleOnCircle(headingTarget - heading); + float angleCounterclockwise = LimitAngleOnCircle(heading - headingTarget); + float newHeading; + if (angleClockwise < angleCounterclockwise) + newHeading = rotateBy < angleClockwise ? heading + rotateBy : headingTarget; + else + newHeading = rotateBy < angleCounterclockwise ? heading - rotateBy : headingTarget; + bool obstacleInPath = false; + if (ScriptParams[3]) { + CVector pos = pObject->GetPosition(); + tmp_matrix.SetRotateZ(DEGTORAD(newHeading)); + tmp_matrix.GetPosition() += pos; + CColModel* pColModel = pObject->GetColModel(); + CVector cp1 = tmp_matrix * pColModel->boundingBox.min; + CVector cp2 = tmp_matrix * CVector(pColModel->boundingBox.max.x, pColModel->boundingBox.min.y, pColModel->boundingBox.min.z); + CVector cp3 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.max.y, pColModel->boundingBox.min.z); + CVector cp4 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.min.y, pColModel->boundingBox.max.z); + int16 collisions; + CWorld::FindObjectsIntersectingAngledCollisionBox(pColModel->boundingBox, tmp_matrix, pos, + Min(cp1.x, Min(cp2.x, Min(cp3.x, cp4.x))), + Min(cp1.y, Min(cp2.y, Min(cp3.y, cp4.y))), + Max(cp1.x, Max(cp2.x, Max(cp3.x, cp4.x))), + Max(cp1.y, Max(cp2.y, Max(cp3.y, cp4.y))), + &collisions, 2, nil, false, true, true, false, false); + if (collisions > 0) + obstacleInPath = true; + } + if (obstacleInPath) { + UpdateCompareFlag(true); + return 0; + } + pObject->SetHeading(DEGTORAD(newHeading)); + pObject->GetMatrix().UpdateRW(); + pObject->UpdateRwFrame(); + UpdateCompareFlag(newHeading == headingTarget); // using direct comparasion here is fine + return 0; + } + case COMMAND_SLIDE_OBJECT: + { + CollectParameters(&m_nIp, 8); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CVector pos = pObject->GetPosition(); + CVector posTarget = *(CVector*)&ScriptParams[1]; +#ifdef FIX_BUGS + CVector slideBy = *(CVector*)&ScriptParams[4] * CTimer::GetTimeStepFix(); +#else + CVector slideBy = *(CVector*)&ScriptParams[4]; +#endif + if (posTarget == pos) { // using direct comparasion here is fine + UpdateCompareFlag(true); + return 0; + } + CVector posDiff = pos - posTarget; + CVector newPosition; + if (posDiff.x < 0) + newPosition.x = -posDiff.x < slideBy.x ? posTarget.x : pos.x + slideBy.x; + else + newPosition.x = posDiff.x < slideBy.x ? posTarget.x : pos.x - slideBy.x; + if (posDiff.y < 0) + newPosition.y = -posDiff.y < slideBy.y ? posTarget.y : pos.y + slideBy.y; + else + newPosition.y = posDiff.y < slideBy.y ? posTarget.y : pos.y - slideBy.y; + if (posDiff.z < 0) + newPosition.z = -posDiff.z < slideBy.z ? posTarget.z : pos.z + slideBy.z; + else + newPosition.z = posDiff.z < slideBy.z ? posTarget.z : pos.z - slideBy.z; + bool obstacleInPath = false; + if (ScriptParams[7]) { + tmp_matrix = pObject->GetMatrix(); + tmp_matrix.GetPosition() = newPosition; + CColModel* pColModel = pObject->GetColModel(); + CVector cp1 = tmp_matrix * pColModel->boundingBox.min; + CVector cp2 = tmp_matrix * CVector(pColModel->boundingBox.max.x, pColModel->boundingBox.min.y, pColModel->boundingBox.min.z); + CVector cp3 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.max.y, pColModel->boundingBox.min.z); + CVector cp4 = tmp_matrix * CVector(pColModel->boundingBox.min.x, pColModel->boundingBox.min.y, pColModel->boundingBox.max.z); + int16 collisions; + CWorld::FindObjectsIntersectingAngledCollisionBox(pColModel->boundingBox, tmp_matrix, newPosition, + Min(cp1.x, Min(cp2.x, Min(cp3.x, cp4.x))), + Min(cp1.y, Min(cp2.y, Min(cp3.y, cp4.y))), + Max(cp1.x, Max(cp2.x, Max(cp3.x, cp4.x))), + Max(cp1.y, Max(cp2.y, Max(cp3.y, cp4.y))), + &collisions, 2, nil, false, true, true, false, false); + if (collisions > 0) + obstacleInPath = true; + } + if (obstacleInPath) { + UpdateCompareFlag(true); + return 0; + } + pObject->Teleport(newPosition); + UpdateCompareFlag(newPosition == posTarget); // using direct comparasion here is fine + return 0; + } + case COMMAND_REMOVE_CHAR_ELEGANTLY: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + if (pPed && pPed->CharCreatedBy == MISSION_CHAR){ + CWorld::RemoveReferencesToDeletedObject(pPed); + if (pPed->bInVehicle){ + if (pPed->m_pMyVehicle){ + if (pPed == pPed->m_pMyVehicle->pDriver){ + pPed->m_pMyVehicle->RemoveDriver(); + pPed->m_pMyVehicle->SetStatus(STATUS_ABANDONED); + if (pPed->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + pPed->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED; + if (pPed->m_nPedType == PEDTYPE_COP && pPed->m_pMyVehicle->IsLawEnforcementVehicle()) + pPed->m_pMyVehicle->ChangeLawEnforcerState(0); + }else{ + pPed->m_pMyVehicle->RemovePassenger(pPed); + } + } + delete pPed; + --CPopulation::ms_nTotalMissionPeds; + }else{ + pPed->CharCreatedBy = RANDOM_CHAR; + pPed->bRespondsToThreats = true; + pPed->bScriptObjectiveCompleted = false; + pPed->ClearLeader(); + --CPopulation::ms_nTotalMissionPeds; + pPed->bFadeOut = true; + } + } + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_SET_CHAR_STAY_IN_SAME_PLACE: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bKindaStayInSamePlace = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_IS_NASTY_GAME: + UpdateCompareFlag(CGame::nastyGame); + return 0; + case COMMAND_UNDRESS_CHAR: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + char name[KEY_LENGTH_IN_SCRIPT]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, name); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + name[i] = tolower(name[i]); + int mi = pPed->GetModelIndex(); + pPed->DeleteRwObject(); + if (pPed->IsPlayer()) + mi = 0; + CStreaming::RequestSpecialModel(mi, name, STREAMFLAGS_DEPENDENCY | STREAMFLAGS_SCRIPTOWNED); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CWorld::Remove(pPed); + return 0; + } + case COMMAND_DRESS_CHAR: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + int mi = pPed->GetModelIndex(); + pPed->m_modelIndex = -1; + pPed->SetModelIndex(mi); + CWorld::Add(pPed); + return 0; + } + case COMMAND_START_CHASE_SCENE: + CollectParameters(&m_nIp, 1); + CTimer::Suspend(); + CStreaming::DeleteAllRwObjects(); + CRecordDataForChase::StartChaseScene(*(float*)&ScriptParams[0]); + CTimer::Resume(); + return 0; + case COMMAND_STOP_CHASE_SCENE: + CRecordDataForChase::CleanUpChaseScene(); + return 0; + case COMMAND_IS_EXPLOSION_IN_AREA: + { + CollectParameters(&m_nIp, 7); + float infX = *(float*)&ScriptParams[1]; + float infY = *(float*)&ScriptParams[2]; + float infZ = *(float*)&ScriptParams[3]; + float supX = *(float*)&ScriptParams[4]; + float supY = *(float*)&ScriptParams[5]; + float supZ = *(float*)&ScriptParams[6]; + if (infX > supX) { + infX = *(float*)&ScriptParams[4]; + supX = *(float*)&ScriptParams[1]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[5]; + supY = *(float*)&ScriptParams[2]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[6]; + supZ = *(float*)&ScriptParams[3]; + } + UpdateCompareFlag(CExplosion::TestForExplosionInArea((eExplosionType)ScriptParams[0], + infX, supX, infY, supY, infZ, supZ)); + return 0; + } + case COMMAND_IS_EXPLOSION_IN_ZONE: + { + CollectParameters(&m_nIp, 1); + char zone[KEY_LENGTH_IN_SCRIPT]; + CTheScripts::ReadTextLabelFromScript(&m_nIp, zone); + int zone_id = CTheZones::FindZoneByLabelAndReturnIndex(zone); + if (zone_id != -1) + m_nIp += KEY_LENGTH_IN_SCRIPT; + CZone* pZone = CTheZones::GetZone(zone_id); + UpdateCompareFlag(CExplosion::TestForExplosionInArea((eExplosionType)ScriptParams[0], + pZone->minx, pZone->maxx, pZone->miny, pZone->maxy, pZone->minz, pZone->maxz)); + return 0; + } + case COMMAND_START_DRUG_DROP_OFF: + CPlane::CreateDropOffCesna(); + return 0; + case COMMAND_HAS_DROP_OFF_PLANE_BEEN_SHOT_DOWN: + UpdateCompareFlag(CPlane::HasDropOffCesnaBeenShotDown()); + return 0; + case COMMAND_FIND_DROP_OFF_PLANE_COORDINATES: + { + CVector pos = CPlane::FindDropOffCesnaCoordinates(); + *(CVector*)&ScriptParams[0] = pos; + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_CREATE_FLOATING_PACKAGE: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y) + PICKUP_PLACEMENT_OFFSET; + ScriptParams[0] = CPickups::GenerateNewOne(pos, MI_FLOATPACKAGE1, PICKUP_FLOATINGPACKAGE, 0); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_PLACE_OBJECT_RELATIVE_TO_CAR: + { + CollectParameters(&m_nIp, 5); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pVehicle); + CVector offset = *(CVector*)&ScriptParams[2]; + CPhysical::PlacePhysicalRelativeToOtherPhysical(pVehicle, pObject, offset); + return 0; + } + case COMMAND_MAKE_OBJECT_TARGETTABLE: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CPlayerPed* pPlayerPed = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + script_assert(pPlayerPed); + pPlayerPed->MakeObjectTargettable(ScriptParams[0]); + return 0; + } + case COMMAND_ADD_ARMOUR_TO_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPlayerPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPlayerPed); + pPlayerPed->m_fArmour = clamp(pPlayerPed->m_fArmour + ScriptParams[1], 0.0f, 100.0f); + return 0; + } + case COMMAND_ADD_ARMOUR_TO_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->m_fArmour = clamp(pPed->m_fArmour + ScriptParams[1], 0.0f, 100.0f); + return 0; + } + case COMMAND_OPEN_GARAGE: + { + CollectParameters(&m_nIp, 1); + CGarages::OpenGarage(ScriptParams[0]); + return 0; + } + case COMMAND_CLOSE_GARAGE: + { + CollectParameters(&m_nIp, 1); + CGarages::CloseGarage(ScriptParams[0]); + return 0; + } + case COMMAND_WARP_CHAR_FROM_CAR_TO_COORD: + { + CollectParameters(&m_nIp, 4); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + if (pPed->bInVehicle){ + if (pPed->m_pMyVehicle->bIsBus) + pPed->bRenderPedInCar = true; + if (pPed->m_pMyVehicle->pDriver == pPed){ + pPed->m_pMyVehicle->RemoveDriver(); + pPed->m_pMyVehicle->SetStatus(STATUS_ABANDONED); + pPed->m_pMyVehicle->bEngineOn = false; + pPed->m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 0; + }else{ + pPed->m_pMyVehicle->RemovePassenger(pPed); + } + pPed->m_pMyVehicle->SetMoveSpeed(0.0f, 0.0f, -0.00001f); + pPed->m_pMyVehicle->SetTurnSpeed(0.0f, 0.0f, 0.0f); + } + pPed->bInVehicle = false; + pPed->m_pMyVehicle = nil; + pPed->SetPedState(PED_IDLE); + pPed->m_nLastPedState = PED_NONE; + pPed->bUsesCollision = true; + pPed->SetMoveSpeed(0.0f, 0.0f, 0.0f); + pPed->AddWeaponModel(CWeaponInfo::GetWeaponInfo(pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType)->m_nModelId); + pPed->RemoveInCarAnims(); + if (pPed->m_pVehicleAnim) + pPed->m_pVehicleAnim->blendDelta = -1000.0f; + pPed->m_pVehicleAnim = nil; + pPed->RestartNonPartialAnims(); + pPed->SetMoveState(PEDMOVE_NONE); + CAnimManager::BlendAnimation(pPed->GetClump(), pPed->m_animGroup, ANIM_IDLE_STANCE, 100.0f); + pos.z += pPed->GetDistanceFromCentreOfMassToBaseOfModel(); + pPed->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, pPed); + return 0; + } + case COMMAND_SET_VISIBILITY_OF_CLOSEST_OBJECT_OF_TYPE: + { + CollectParameters(&m_nIp, 6); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float range = *(float*)&ScriptParams[3]; + int mi = ScriptParams[4] < 0 ? CTheScripts::UsedObjectArray[-ScriptParams[4]].index : ScriptParams[4]; + int16 total; + CEntity* apEntities[16]; + CWorld::FindObjectsOfTypeInRange(mi, pos, range, true, &total, 16, apEntities, true, false, false, true, true); + if (total == 0) + CWorld::FindObjectsOfTypeInRangeSectorList(mi, CWorld::GetBigBuildingList(LEVEL_GENERIC), pos, range, true, &total, 16, apEntities); + if (total == 0) + CWorld::FindObjectsOfTypeInRangeSectorList(mi, CWorld::GetBigBuildingList(CTheZones::FindZoneForPoint(pos)), pos, range, true, &total, 16, apEntities); + CEntity* pClosestEntity = nil; + float min_dist = 2.0f * range; + for (int i = 0; i < total; i++) { + float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); + if (dist < min_dist) { + min_dist = dist; + pClosestEntity = apEntities[i]; + } + } + if (pClosestEntity) { + pClosestEntity->bIsVisible = (ScriptParams[5] != 0); + CTheScripts::AddToInvisibilitySwapArray(pClosestEntity, ScriptParams[5] != 0); + } + return 0; + } + case COMMAND_HAS_CHAR_SPOTTED_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + UpdateCompareFlag(pPed->OurPedCanSeeThisOne(pTarget)); + return 0; + } + case COMMAND_SET_CHAR_OBJ_HAIL_TAXI: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_HAIL_TAXI); + return 0; + } + case COMMAND_HAS_OBJECT_BEEN_DAMAGED: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + UpdateCompareFlag(pObject->bRenderDamaged || !pObject->bIsVisible); + return 0; + } + case COMMAND_START_KILL_FRENZY_HEADSHOT: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 8); + CDarkel::StartFrenzy((eWeaponType)ScriptParams[0], ScriptParams[1], ScriptParams[2], + ScriptParams[3], text, ScriptParams[4], ScriptParams[5], + ScriptParams[6], ScriptParams[7] != 0, true); + return 0; + } + case COMMAND_ACTIVATE_MILITARY_CRANE: + { + CollectParameters(&m_nIp, 10); + float infX = *(float*)&ScriptParams[2]; + float infY = *(float*)&ScriptParams[3]; + float supX = *(float*)&ScriptParams[4]; + float supY = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[4]; + supX = *(float*)&ScriptParams[2]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[5]; + supY = *(float*)&ScriptParams[3]; + } + CCranes::ActivateCrane(infX, supX, infY, supY, + *(float*)&ScriptParams[6], *(float*)&ScriptParams[7], *(float*)&ScriptParams[8], + DEGTORAD(*(float*)&ScriptParams[9]), false, true, + *(float*)&ScriptParams[0], *(float*)&ScriptParams[1]); + return 0; + } + case COMMAND_WARP_PLAYER_INTO_CAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pVehicle); + pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicle); + pPed->WarpPedIntoCar(pVehicle); + return 0; + } + case COMMAND_WARP_CHAR_INTO_CAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pVehicle); + pPed->SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, pVehicle); + pPed->WarpPedIntoCar(pVehicle); + return 0; + } + //case COMMAND_SWITCH_CAR_RADIO: + //case COMMAND_SET_AUDIO_STREAM: + case COMMAND_PRINT_WITH_2_NUMBERS_BIG: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 4); + CMessages::AddBigMessageWithNumber(text, ScriptParams[2], ScriptParams[3] - 1, ScriptParams[0], ScriptParams[1], -1, -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_3_NUMBERS_BIG: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 5); + CMessages::AddBigMessageWithNumber(text, ScriptParams[3], ScriptParams[4] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], -1, -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_4_NUMBERS_BIG: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 6); + CMessages::AddBigMessageWithNumber(text, ScriptParams[4], ScriptParams[5] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], -1, -1); + return 0; + } + case COMMAND_PRINT_WITH_5_NUMBERS_BIG: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 7); + CMessages::AddBigMessageWithNumber(text, ScriptParams[5], ScriptParams[6] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], -1); + return 0; + } + case COMMAND_PRINT_WITH_6_NUMBERS_BIG: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 8); + CMessages::AddBigMessageWithNumber(text, ScriptParams[6], ScriptParams[7] - 1, ScriptParams[0], ScriptParams[1], ScriptParams[2], ScriptParams[3], ScriptParams[4], ScriptParams[5]); + return 0; + } + case COMMAND_SET_CHAR_WAIT_STATE: + { + CollectParameters(&m_nIp, 3); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->SetWaitState((eWaitState)ScriptParams[1], ScriptParams[2] >= 0 ? &ScriptParams[2] : nil); + return 0; + } + case COMMAND_SET_CAMERA_BEHIND_PLAYER: + TheCamera.SetCameraDirectlyBehindForFollowPed_CamOnAString(); + return 0; + case COMMAND_SET_MOTION_BLUR: + CollectParameters(&m_nIp, 1); + TheCamera.SetMotionBlur(0, 0, 0, 0, ScriptParams[0]); + return 0; + case COMMAND_PRINT_STRING_IN_STRING: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* string = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 2); + CMessages::AddMessageWithString(text, ScriptParams[0], ScriptParams[1], string); + return 0; + } + case COMMAND_CREATE_RANDOM_CHAR: + { + CollectParameters(&m_nIp, 3); + CZoneInfo zoneinfo; + CTheZones::GetZoneInfoForTimeOfDay(&CWorld::Players[CWorld::PlayerInFocus].GetPos(), &zoneinfo); + int mi; + ePedType pedtype = PEDTYPE_COP; + int attempt = 0; + while (pedtype != PEDTYPE_CIVMALE && pedtype != PEDTYPE_CIVFEMALE && attempt < 5) { + mi = CPopulation::ChooseCivilianOccupation(zoneinfo.pedGroup); + if (CModelInfo::GetModelInfo(mi)->GetRwObject()) + pedtype = ((CPedModelInfo*)(CModelInfo::GetModelInfo(mi)))->m_pedType; + attempt++; + } + if (!CModelInfo::GetModelInfo(mi)->GetRwObject()) { + mi = MI_MALE01; + pedtype = ((CPedModelInfo*)(CModelInfo::GetModelInfo(mi)))->m_pedType; + } + CPed* ped = new CCivilianPed(pedtype, mi); + ped->CharCreatedBy = MISSION_CHAR; + ped->bRespondsToThreats = false; + ped->bAllowMedicsToReviveMe = false; + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += 1.0f; + ped->SetPosition(pos); + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CTheScripts::ClearSpaceForMissionEntity(pos, ped); + CWorld::Add(ped); + ped->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pos); + CPopulation::ms_nTotalMissionPeds++; + ScriptParams[0] = CPools::GetPedPool()->GetIndex(ped); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_SET_CHAR_OBJ_STEAL_ANY_CAR: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_STEAL_ANY_CAR); + return 0; + } + case COMMAND_SET_2_REPEATED_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, nil, nil, nil, nil); + return 0; + } + case COMMAND_SET_2_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, nil, nil, nil, nil); + return 0; + } + case COMMAND_SET_3_REPEATED_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, nil, nil, nil); + return 0; + } + case COMMAND_SET_3_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, nil, nil, nil); + return 0; + } + case COMMAND_SET_4_REPEATED_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, text4, nil, nil); + return 0; + } + case COMMAND_SET_4_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, text4, nil, nil); + return 0; + } + case COMMAND_IS_SNIPER_BULLET_IN_AREA: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + UpdateCompareFlag(CBulletInfo::TestForSniperBullet(infX, supX, infY, supY, infZ, supZ)); + return 0; + } + case COMMAND_GIVE_PLAYER_DETONATOR: + CGarages::GivePlayerDetonator(); + return 0; + //case COMMAND_SET_COLL_OBJ_STEAL_ANY_CAR: + case COMMAND_SET_OBJECT_VELOCITY: + { + CollectParameters(&m_nIp, 4); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + pObject->SetMoveSpeed(*(CVector*)&ScriptParams[1] * METERS_PER_SECOND_TO_GAME_SPEED); + return 0; + } + case COMMAND_SET_OBJECT_COLLISION: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + pObject->bUsesCollision = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_IS_ICECREAM_JINGLE_ON: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + // Adding this check to correspond to command name. + // All original game scripts always assume that the vehicle is actually Mr. Whoopee, + // but maybe there are mods that use it as "is alarm activated"? + script_assert(pVehicle->GetModelIndex() == MI_MRWHOOP); + UpdateCompareFlag(pVehicle->m_bSirenOrAlarm); + return 0; + } + default: + script_assert(0); + } + return -1; +} + +int8 CRunningScript::ProcessCommands900To999(int32 command) +{ + char str[52]; + char onscreen_str[KEY_LENGTH_IN_SCRIPT]; + switch (command) { + case COMMAND_PRINT_STRING_IN_STRING_NOW: + { + wchar* source = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* pstr = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CollectParameters(&m_nIp, 2); + CMessages::AddMessageJumpQWithString(source, ScriptParams[0], ScriptParams[1], pstr); + return 0; + } + //case COMMAND_PRINT_STRING_IN_STRING_SOON: + case COMMAND_SET_5_REPEATED_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, text4, text5, nil); + return 0; + } + case COMMAND_SET_5_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, text4, text5, nil); + return 0; + } + case COMMAND_SET_6_REPEATED_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text6 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_Repeatedly(ScriptParams[0], text1, text2, text3, text4, text5, text6); + return 0; + } + case COMMAND_SET_6_PHONE_MESSAGES: + { + CollectParameters(&m_nIp, 1); + wchar* text1 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text2 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text3 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text4 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text5 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + wchar* text6 = CTheScripts::GetTextByKeyFromScript(&m_nIp); + gPhoneInfo.SetPhoneMessage_JustOnce(ScriptParams[0], text1, text2, text3, text4, text5, text6); + return 0; + } + case COMMAND_IS_POINT_OBSCURED_BY_A_MISSION_ENTITY: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0] - *(float*)&ScriptParams[3]; + float supX = *(float*)&ScriptParams[0] + *(float*)&ScriptParams[3]; + float infY = *(float*)&ScriptParams[1] - *(float*)&ScriptParams[4]; + float supY = *(float*)&ScriptParams[1] + *(float*)&ScriptParams[4]; + float infZ = *(float*)&ScriptParams[2] - *(float*)&ScriptParams[5]; + float supZ = *(float*)&ScriptParams[2] + *(float*)&ScriptParams[5]; + if (infX > supX) { + float tmp = infX; + infX = supX; + supX = tmp; + } + if (infY > supY) { + float tmp = infY; + infY = supY; + supY = tmp; + } + if (infZ > supZ) { + float tmp = infZ; + infZ = supZ; + supZ = tmp; + } + int16 total; + CWorld::FindMissionEntitiesIntersectingCube(CVector(infX, infY, infZ), CVector(supX, supY, supZ), &total, 2, nil, true, true, true); + UpdateCompareFlag(total > 0); + return 0; + } + case COMMAND_LOAD_ALL_MODELS_NOW: + CTimer::Stop(); + CStreaming::LoadAllRequestedModels(false); + CTimer::Update(); + return 0; + case COMMAND_ADD_TO_OBJECT_VELOCITY: + { + CollectParameters(&m_nIp, 4); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + pObject->SetMoveSpeed(pObject->GetMoveSpeed() + METERS_PER_SECOND_TO_GAME_SPEED * *(CVector*)&ScriptParams[1]); + return 0; + } + case COMMAND_DRAW_SPRITE: + { + CollectParameters(&m_nIp, 9); + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_bIsUsed = true; + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_nTextureId = ScriptParams[0] - 1; + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sRect = CRect( + *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], *(float*)&ScriptParams[1] + *(float*)&ScriptParams[3], *(float*)&ScriptParams[2] + *(float*)&ScriptParams[4]); + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sColor = CRGBA(ScriptParams[5], ScriptParams[6], ScriptParams[7], ScriptParams[8]); + CTheScripts::NumberOfIntroRectanglesThisFrame++; + return 0; + } + case COMMAND_DRAW_RECT: + { + CollectParameters(&m_nIp, 8); + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_bIsUsed = true; + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_nTextureId = -1; + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sRect = CRect( + *(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[0] + *(float*)&ScriptParams[2], *(float*)&ScriptParams[1] + *(float*)&ScriptParams[3]); + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_sColor = CRGBA(ScriptParams[4], ScriptParams[5], ScriptParams[6], ScriptParams[7]); + CTheScripts::NumberOfIntroRectanglesThisFrame++; + return 0; + } + case COMMAND_LOAD_SPRITE: + { + CollectParameters(&m_nIp, 1); + strncpy(str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + str[i] = tolower(str[i]); + m_nIp += KEY_LENGTH_IN_SCRIPT; + int slot = CTxdStore::FindTxdSlot("script"); + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(slot); + CTheScripts::ScriptSprites[ScriptParams[0] - 1].SetTexture(str); + CTxdStore::PopCurrentTxd(); + return 0; + } + case COMMAND_LOAD_TEXTURE_DICTIONARY: + { + strcpy(str, "models\\"); + strncpy(str + sizeof("models\\"), (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + strcat(str, ".txd"); + m_nIp += KEY_LENGTH_IN_SCRIPT; + int slot = CTxdStore::FindTxdSlot("script"); + if (slot == -1) + slot = CTxdStore::AddTxdSlot("script"); + CTxdStore::LoadTxd(slot, str); + CTxdStore::AddRef(slot); + return 0; + } + case COMMAND_REMOVE_TEXTURE_DICTIONARY: + { + for (int i = 0; i < ARRAY_SIZE(CTheScripts::ScriptSprites); i++) + CTheScripts::ScriptSprites[i].Delete(); + CTxdStore::RemoveTxd(CTxdStore::FindTxdSlot("script")); + return 0; + } + case COMMAND_SET_OBJECT_DYNAMIC: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + if (ScriptParams[1]) { + if (pObject->bIsStatic) { + pObject->SetIsStatic(false); + pObject->AddToMovingList(); + } + } + else { + if (!pObject->bIsStatic) { + pObject->SetIsStatic(true); + pObject->RemoveFromMovingList(); + } + } + return 0; + } + case COMMAND_SET_CHAR_ANIM_SPEED: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CAnimBlendAssociation* pAssoc = RpAnimBlendClumpGetFirstAssociation(pPed->GetClump()); + if (pAssoc) + pAssoc->speed = *(float*)&ScriptParams[1]; + return 0; + } + case COMMAND_PLAY_MISSION_PASSED_TUNE: + { + CollectParameters(&m_nIp, 1); + DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND); + DMAudio.PlayFrontEndTrack(ScriptParams[0] + STREAMED_SOUND_MISSION_COMPLETED - 1, 0); + return 0; + } + case COMMAND_CLEAR_AREA: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CWorld::ClearExcitingStuffFromArea(pos, *(float*)&ScriptParams[3], ScriptParams[4]); + return 0; + } + case COMMAND_FREEZE_ONSCREEN_TIMER: + CollectParameters(&m_nIp, 1); + CUserDisplay::OnscnTimer.m_bDisabled = ScriptParams[0] != 0; + return 0; + case COMMAND_SWITCH_CAR_SIREN: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->m_bSirenOrAlarm = ScriptParams[1] != 0; + return 0; + } + case COMMAND_SWITCH_PED_ROADS_ON_ANGLED: + { + CollectParameters(&m_nIp, 7); + ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], + *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 0, 1); + return 0; + } + case COMMAND_SWITCH_PED_ROADS_OFF_ANGLED: + CollectParameters(&m_nIp, 7); + ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], + *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 0, 0); + return 0; + case COMMAND_SWITCH_ROADS_ON_ANGLED: + CollectParameters(&m_nIp, 7); + ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], + *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 1, 1); + return 0; + case COMMAND_SWITCH_ROADS_OFF_ANGLED: + CollectParameters(&m_nIp, 7); + ThePaths.SwitchRoadsInAngledArea(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2], + *(float*)&ScriptParams[3], *(float*)&ScriptParams[4], *(float*)&ScriptParams[5], *(float*)&ScriptParams[6], 1, 0); + return 0; + case COMMAND_SET_CAR_WATERTIGHT: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + CAutomobile* pCar = (CAutomobile*)pVehicle; + pCar->bWaterTight = ScriptParams[1] != 0; + return 0; + } + case COMMAND_ADD_MOVING_PARTICLE_EFFECT: + { + CollectParameters(&m_nIp, 12); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float size = Max(0.0f, *(float*)&ScriptParams[7]); + eParticleObjectType type = (eParticleObjectType)ScriptParams[0]; + RwRGBA color; + if (type == POBJECT_SMOKE_TRAIL){ + color.alpha = -1; + color.red = ScriptParams[8]; + color.green = ScriptParams[9]; + color.blue = ScriptParams[10]; + }else{ + color.alpha = color.red = color.blue = color.green = 0; + } + CVector target = *(CVector*)&ScriptParams[4]; + CParticleObject::AddObject(type, pos, target, size, ScriptParams[11], color, 1); + return 0; + } + case COMMAND_SET_CHAR_CANT_BE_DRAGGED_OUT: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bDontDragMeOutCar = ScriptParams[1] != 0; + return 0; + } + case COMMAND_TURN_CAR_TO_FACE_COORD: + { + CollectParameters(&m_nIp, 3); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + const CVector& pos = pVehicle->GetPosition(); + float heading = CGeneral::GetATanOfXY(pos.y - *(float*)&ScriptParams[2], pos.x - *(float*)&ScriptParams[1]) + HALFPI; + if (heading > TWOPI) + heading -= TWOPI; + pVehicle->SetHeading(heading); + return 0; + } + case COMMAND_IS_CRANE_LIFTING_CAR: + { + CollectParameters(&m_nIp, 3); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[2]); + UpdateCompareFlag(CCranes::IsThisCarPickedUp(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], pVehicle)); + return 0; + } + case COMMAND_DRAW_SPHERE: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + C3dMarkers::PlaceMarkerSet((uintptr)this + m_nIp, MARKERTYPE_CYLINDER, pos, *(float*)&ScriptParams[3], + SPHERE_MARKER_R, SPHERE_MARKER_G, SPHERE_MARKER_B, SPHERE_MARKER_A, + SPHERE_MARKER_PULSE_PERIOD, SPHERE_MARKER_PULSE_FRACTION, 0); + return 0; + } + case COMMAND_SET_CAR_STATUS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->SetStatus((eEntityStatus)ScriptParams[1]); + return 0; + } + case COMMAND_IS_CHAR_MALE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(pPed->m_nPedType != PEDTYPE_CIVFEMALE && pPed->m_nPedType != PEDTYPE_PROSTITUTE); + return 0; + } + case COMMAND_SCRIPT_NAME: + { + strncpy(str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + str[i] = tolower(str[i]); + m_nIp += KEY_LENGTH_IN_SCRIPT; + strncpy(m_abScriptName, str, KEY_LENGTH_IN_SCRIPT); + return 0; + } + case COMMAND_CHANGE_GARAGE_TYPE_WITH_CAR_MODEL: + { + CollectParameters(&m_nIp, 3); + CGarages::ChangeGarageType(ScriptParams[0], (eGarageType)ScriptParams[1], ScriptParams[2]); + return 0; + } + case COMMAND_FIND_DRUG_PLANE_COORDINATES: + *(CVector*)&ScriptParams[0] = CPlane::FindDrugPlaneCoordinates(); + StoreParameters(&m_nIp, 3); + return 0; + case COMMAND_SAVE_INT_TO_DEBUG_FILE: + // TODO: implement something here + CollectParameters(&m_nIp, 1); + return 0; + case COMMAND_SAVE_FLOAT_TO_DEBUG_FILE: + CollectParameters(&m_nIp, 1); + return 0; + case COMMAND_SAVE_NEWLINE_TO_DEBUG_FILE: + return 0; + case COMMAND_POLICE_RADIO_MESSAGE: + CollectParameters(&m_nIp, 3); + DMAudio.PlaySuspectLastSeen(*(float*)&ScriptParams[0], *(float*)&ScriptParams[1], *(float*)&ScriptParams[2]); + return 0; + case COMMAND_SET_CAR_STRONG: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bTakeLessDamage = ScriptParams[1] != 0; + return 0; + } + case COMMAND_REMOVE_ROUTE: + CollectParameters(&m_nIp, 1); + CRouteNode::RemoveRoute(ScriptParams[0]); + return 0; + case COMMAND_SWITCH_RUBBISH: + CollectParameters(&m_nIp, 1); + CRubbish::SetVisibility(ScriptParams[0] != 0);; + return 0; + case COMMAND_REMOVE_PARTICLE_EFFECTS_IN_AREA: + { + CollectParameters(&m_nIp, 6); + float x1 = *(float*)&ScriptParams[0]; + float y1 = *(float*)&ScriptParams[1]; + float z1 = *(float*)&ScriptParams[2]; + float x2 = *(float*)&ScriptParams[3]; + float y2 = *(float*)&ScriptParams[4]; + float z2 = *(float*)&ScriptParams[5]; + CParticleObject* tmp = CParticleObject::pCloseListHead; + while (tmp) { + CParticleObject* next = tmp->m_pNext; + if (tmp->IsWithinArea(x1, y1, z1, x2, y2, z2)) + tmp->RemoveObject(); + tmp = next; + } + tmp = CParticleObject::pFarListHead; + while (tmp) { + CParticleObject* next = tmp->m_pNext; + if (tmp->IsWithinArea(x1, y1, z1, x2, y2, z2)) + tmp->RemoveObject(); + tmp = next; + } + return 0; + } + case COMMAND_SWITCH_STREAMING: + CollectParameters(&m_nIp, 1); + CStreaming::ms_disableStreaming = ScriptParams[0] == 0; + return 0; + case COMMAND_IS_GARAGE_OPEN: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CGarages::IsGarageOpen(ScriptParams[0])); + return 0; + case COMMAND_IS_GARAGE_CLOSED: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CGarages::IsGarageClosed(ScriptParams[0])); + return 0; + case COMMAND_START_CATALINA_HELI: + CHeli::StartCatalinaFlyBy(); + return 0; + case COMMAND_CATALINA_HELI_TAKE_OFF: + CHeli::CatalinaTakeOff(); + return 0; + case COMMAND_REMOVE_CATALINA_HELI: + CHeli::RemoveCatalinaHeli(); + return 0; + case COMMAND_HAS_CATALINA_HELI_BEEN_SHOT_DOWN: + UpdateCompareFlag(CHeli::HasCatalinaBeenShotDown()); + return 0; + case COMMAND_SWAP_NEAREST_BUILDING_MODEL: + { + CollectParameters(&m_nIp, 6); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = *(float*)&ScriptParams[3]; + int mi1 = ScriptParams[4] >= 0 ? ScriptParams[4] : CTheScripts::UsedObjectArray[-ScriptParams[4]].index; + int mi2 = ScriptParams[5] >= 0 ? ScriptParams[5] : CTheScripts::UsedObjectArray[-ScriptParams[5]].index; + int16 total; + CEntity* apEntities[16]; + CWorld::FindObjectsOfTypeInRange(mi1, pos, radius, true, &total, 16, apEntities, true, false, false, false, false); + if (total == 0) + CWorld::FindObjectsOfTypeInRangeSectorList(mi1, CWorld::GetBigBuildingList(LEVEL_GENERIC), pos, radius, true, &total, 16, apEntities); + if (total == 0) + CWorld::FindObjectsOfTypeInRangeSectorList(mi1, CWorld::GetBigBuildingList(CTheZones::FindZoneForPoint(pos)), pos, radius, true, &total, 16, apEntities); + CEntity* pClosestEntity = nil; + float min_dist = 2.0f * radius; + for (int i = 0; i < total; i++) { + float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); + if (dist < min_dist) { + min_dist = dist; + pClosestEntity = apEntities[i]; + } + } + if (!pClosestEntity) { + printf("Failed to find building\n"); + return 0; + } + CBuilding* pReplacedBuilding = ((CBuilding*)pClosestEntity); + pReplacedBuilding->ReplaceWithNewModel(mi2); + CTheScripts::AddToBuildingSwapArray(pReplacedBuilding, mi1, mi2); + return 0; + } + case COMMAND_SWITCH_WORLD_PROCESSING: + CollectParameters(&m_nIp, 1); + CWorld::bProcessCutsceneOnly = ScriptParams[0] == 0; + return 0; + case COMMAND_REMOVE_ALL_PLAYER_WEAPONS: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + pPed->ClearWeapons(); + return 0; + } + case COMMAND_GRAB_CATALINA_HELI: + { + CHeli* pHeli = CHeli::FindPointerToCatalinasHeli(); + ScriptParams[0] = pHeli ? CPools::GetVehiclePool()->GetIndex(pHeli) : -1; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_CLEAR_AREA_OF_CARS: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + CWorld::ClearCarsFromArea(infX, infY, infZ, supX, supY, supZ); + return 0; + } + case COMMAND_SET_ROTATING_GARAGE_DOOR: + CollectParameters(&m_nIp, 1); + CGarages::SetGarageDoorToRotate(ScriptParams[0]); + return 0; + case COMMAND_ADD_SPHERE: + { + CollectParameters(&m_nIp, 4); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float radius = *(float*)&ScriptParams[3]; + CTheScripts::GetActualScriptSphereIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CTheScripts::AddScriptSphere((uintptr)this + m_nIp, pos, radius); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_REMOVE_SPHERE: + CollectParameters(&m_nIp, 1); + CTheScripts::RemoveScriptSphere(ScriptParams[0]); + return 0; + case COMMAND_CATALINA_HELI_FLY_AWAY: + CHeli::MakeCatalinaHeliFlyAway(); + return 0; + case COMMAND_SET_EVERYONE_IGNORE_PLAYER: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + if (ScriptParams[1]) { + pPed->m_pWanted->m_bIgnoredByEveryone = true; + CWorld::StopAllLawEnforcersInTheirTracks(); + } + else { + pPed->m_pWanted->m_bIgnoredByEveryone = false; + } + return 0; + } + case COMMAND_STORE_CAR_CHAR_IS_IN_NO_SAVE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = pPed->bInVehicle ? pPed->m_pMyVehicle : nil; + ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_STORE_CAR_PLAYER_IS_IN_NO_SAVE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CVehicle* pVehicle = pPed->bInVehicle ? pPed->m_pMyVehicle : nil; + ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_PHONE_DISPLAYING_MESSAGE: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(gPhoneInfo.IsMessageBeingDisplayed(ScriptParams[0])); + return 0; + case COMMAND_DISPLAY_ONSCREEN_TIMER_WITH_STRING: + { + script_assert(CTheScripts::ScriptSpace[m_nIp++] == ARGUMENT_GLOBALVAR); + uint16 var = CTheScripts::Read2BytesFromScript(&m_nIp); + wchar* text = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); // ??? + strncpy(onscreen_str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CUserDisplay::OnscnTimer.AddClock(var, onscreen_str); + return 0; + } + case COMMAND_DISPLAY_ONSCREEN_COUNTER_WITH_STRING: + { + script_assert(CTheScripts::ScriptSpace[m_nIp++] == ARGUMENT_GLOBALVAR); + uint16 var = CTheScripts::Read2BytesFromScript(&m_nIp); + CollectParameters(&m_nIp, 1); + wchar* text = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); // ??? + strncpy(onscreen_str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + m_nIp += KEY_LENGTH_IN_SCRIPT; + CUserDisplay::OnscnTimer.AddCounter(var, ScriptParams[0], onscreen_str); + return 0; + } + case COMMAND_CREATE_RANDOM_CAR_FOR_CAR_PARK: + { + CollectParameters(&m_nIp, 4); + if (CCarCtrl::NumRandomCars >= 30) + return 0; + int attempts; + int model = -1; + int index = CGeneral::GetRandomNumberInRange(0, 50); + for (attempts = 0; attempts < 50; attempts++) { + if (model != -1) + break; + model = CStreaming::ms_vehiclesLoaded[index]; + if (model == -1) + continue; + // desperatly want to believe this was inlined :| + CBaseModelInfo* pInfo = CModelInfo::GetModelInfo(model); + script_assert(pInfo->GetModelType() == MITYPE_VEHICLE); + CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)pInfo; + if (pVehicleInfo->m_vehicleType == VEHICLE_TYPE_CAR) { + switch (model) { + case MI_LANDSTAL: + case MI_LINERUN: + case MI_FIRETRUCK: + case MI_TRASH: + case MI_STRETCH: + case MI_MULE: + case MI_AMBULAN: + case MI_FBICAR: + case MI_MRWHOOP: + case MI_BFINJECT: + case MI_CORPSE: + case MI_POLICE: + case MI_ENFORCER: + case MI_SECURICA: + case MI_PREDATOR: + case MI_BUS: + case MI_RHINO: + case MI_BARRACKS: + case MI_TRAIN: + case MI_CHOPPER: + case MI_DODO: + case MI_COACH: + case MI_RCBANDIT: + case MI_BELLYUP: + case MI_MRWONGS: + case MI_MAFIA: + case MI_YARDIE: + case MI_YAKUZA: + case MI_DIABLOS: + case MI_COLUMB: + case MI_HOODS: + case MI_AIRTRAIN: + case MI_DEADDODO: + case MI_SPEEDER: + case MI_REEFER: + case MI_PANLANT: + case MI_FLATBED: + case MI_YANKEE: + case MI_ESCAPE: + case MI_BORGNINE: + case MI_TOYZ: + case MI_GHOST: + case MI_MIAMI_RCBARON: + case MI_MIAMI_RCRAIDER: + model = -1; + break; + case MI_IDAHO: + case MI_STINGER: + case MI_PEREN: + case MI_SENTINEL: + case MI_PATRIOT: + case MI_MANANA: + case MI_INFERNUS: + case MI_BLISTA: + case MI_PONY: + case MI_CHEETAH: + case MI_MOONBEAM: + case MI_ESPERANT: + case MI_TAXI: + case MI_KURUMA: + case MI_BOBCAT: + case MI_BANSHEE: + case MI_CABBIE: + case MI_STALLION: + case MI_RUMPO: + case 151: + case 152: + case 153: + break; + default: + printf("CREATE_RANDOM_CAR_FOR_CAR_PARK - Unknown car model %d\n", CStreaming::ms_vehiclesLoaded[index]); + model = -1; + break; + } + } + else + model = -1; + if (++index >= 50) + index = 0; + } + if (model == -1) + return 0; + CVehicle* car; + if (!CModelInfo::IsBikeModel(model)) + car = new CAutomobile(model, RANDOM_VEHICLE); + CVector pos = *(CVector*)&ScriptParams[0]; + pos.z += car->GetDistanceFromCentreOfMassToBaseOfModel(); + car->SetPosition(pos); + car->SetHeading(DEGTORAD(*(float*)&ScriptParams[3])); + CTheScripts::ClearSpaceForMissionEntity(pos, car); + car->SetStatus(STATUS_ABANDONED); + car->bIsLocked = false; + car->bIsCarParkVehicle = true; + CCarCtrl::JoinCarWithRoadSystem(car); + car->AutoPilot.m_nCarMission = MISSION_NONE; + car->AutoPilot.m_nTempAction = TEMPACT_NONE; + car->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; + car->AutoPilot.m_nCruiseSpeed = car->AutoPilot.m_fMaxTrafficSpeed = 9.0f; + car->AutoPilot.m_nCurrentLane = car->AutoPilot.m_nNextLane = 0; + car->bEngineOn = false; + car->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pos); + CWorld::Add(car); + return 0; + } + case COMMAND_IS_COLLISION_IN_MEMORY: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CCollision::ms_collisionInMemory == ScriptParams[0]); + return 0; + case COMMAND_SET_WANTED_MULTIPLIER: + CollectParameters(&m_nIp, 1); + FindPlayerPed()->m_pWanted->m_fCrimeSensitivity = *(float*)&ScriptParams[0]; + return 0; + case COMMAND_SET_CAMERA_IN_FRONT_OF_PLAYER: + TheCamera.SetCameraDirectlyInFrontForFollowPed_CamOnAString(); + return 0; + case COMMAND_IS_CAR_VISIBLY_DAMAGED: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(pVehicle->bIsDamaged); + return 0; + } + case COMMAND_DOES_OBJECT_EXIST: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CPools::GetObjectPool()->GetAt(ScriptParams[0])); + return 0; + case COMMAND_LOAD_SCENE: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + CTimer::Stop(); + CStreaming::LoadScene(pos); + CTimer::Update(); + return 0; + } + case COMMAND_ADD_STUCK_CAR_CHECK: + { + CollectParameters(&m_nIp, 3); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CTheScripts::StuckCars.AddCarToCheck(ScriptParams[0], *(float*)&ScriptParams[1], ScriptParams[2]); + return 0; + } + case COMMAND_REMOVE_STUCK_CAR_CHECK: + { + CollectParameters(&m_nIp, 1); + CTheScripts::StuckCars.RemoveCarFromCheck(ScriptParams[0]); + return 0; + } + case COMMAND_IS_CAR_STUCK: + CollectParameters(&m_nIp, 1); + UpdateCompareFlag(CTheScripts::StuckCars.HasCarBeenStuckForAWhile(ScriptParams[0])); + return 0; + case COMMAND_LOAD_MISSION_AUDIO: + strncpy(str, (char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + str[i] = tolower(str[i]); + m_nIp += KEY_LENGTH_IN_SCRIPT; + DMAudio.PreloadMissionAudio(str); + return 0; + case COMMAND_HAS_MISSION_AUDIO_LOADED: + UpdateCompareFlag(DMAudio.GetMissionAudioLoadingStatus() == 1); + return 0; + case COMMAND_PLAY_MISSION_AUDIO: + DMAudio.PlayLoadedMissionAudio(); + return 0; + case COMMAND_HAS_MISSION_AUDIO_FINISHED: + UpdateCompareFlag(DMAudio.IsMissionAudioSampleFinished()); + return 0; + case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + int node = ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f, true, true); + *(CVector*)&ScriptParams[0] = ThePaths.m_pathNodes[node].GetPosition(); + *(float*)&ScriptParams[3] = ThePaths.FindNodeOrientationForCarPlacement(node); + StoreParameters(&m_nIp, 4); + return 0; + } + case COMMAND_HAS_IMPORT_GARAGE_SLOT_BEEN_FILLED: + { + CollectParameters(&m_nIp, 2); + UpdateCompareFlag(CGarages::HasImportExportGarageCollectedThisCar(ScriptParams[0], ScriptParams[1] - 1)); + return 0; + } + case COMMAND_CLEAR_THIS_PRINT: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CMessages::ClearThisPrint(text); + return 0; + } + case COMMAND_CLEAR_THIS_BIG_PRINT: + { + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CMessages::ClearThisBigPrint(text); + return 0; + } + case COMMAND_SET_MISSION_AUDIO_POSITION: + { + CollectParameters(&m_nIp, 3); + CVector pos = *(CVector*)&ScriptParams[0]; + DMAudio.SetMissionAudioLocation(pos.x, pos.y, pos.z); + return 0; + } + case COMMAND_ACTIVATE_SAVE_MENU: + FrontEndMenuManager.m_bSaveMenuActive = true; + return 0; + case COMMAND_HAS_SAVE_GAME_FINISHED: + UpdateCompareFlag(!FrontEndMenuManager.m_bMenuActive); + return 0; + case COMMAND_NO_SPECIAL_CAMERA_FOR_THIS_GARAGE: + CollectParameters(&m_nIp, 1); + CGarages::SetLeaveCameraForThisGarage(ScriptParams[0]); + return 0; + case COMMAND_ADD_BLIP_FOR_PICKUP_OLD: + { + CollectParameters(&m_nIp, 3); + CObject* pObject = CPickups::aPickUps[CPickups::GetActualPickupIndex(ScriptParams[0])].m_pObject; + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + ScriptParams[0] = CRadar::SetEntityBlip(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(pObject), ScriptParams[1], (eBlipDisplay)ScriptParams[2]); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_BLIP_FOR_PICKUP: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPickups::aPickUps[CPickups::GetActualPickupIndex(ScriptParams[0])].m_pObject; + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int handle = CRadar::SetEntityBlip(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(pObject), 6, BLIP_DISPLAY_BOTH); + CRadar::ChangeBlipScale(handle, 3); + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_ADD_SPRITE_BLIP_FOR_PICKUP: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPickups::aPickUps[CPickups::GetActualPickupIndex(ScriptParams[0])].m_pObject; + CRadar::GetActualBlipArrayIndex(CollectNextParameterWithoutIncreasingPC(m_nIp)); + int handle = CRadar::SetEntityBlip(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(pObject), 6, BLIP_DISPLAY_BOTH); + CRadar::SetBlipSprite(handle, ScriptParams[1]); + ScriptParams[0] = handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_PED_DENSITY_MULTIPLIER: + CollectParameters(&m_nIp, 1); + CPopulation::PedDensityMultiplier = *(float*)&ScriptParams[0]; + return 0; + case COMMAND_FORCE_RANDOM_PED_TYPE: + CollectParameters(&m_nIp, 1); + CPopulation::m_AllRandomPedsThisType = ScriptParams[0]; + return 0; + case COMMAND_SET_TEXT_DRAW_BEFORE_FADE: + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bTextBeforeFade = ScriptParams[0] != 0; + return 0; + case COMMAND_GET_COLLECTABLE1S_COLLECTED: + ScriptParams[0] = CWorld::Players[CWorld::PlayerInFocus].m_nCollectedPackages; + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_REGISTER_EL_BURRO_TIME: + CollectParameters(&m_nIp, 1); + CStats::RegisterElBurroTime(ScriptParams[0]); + return 0; + case COMMAND_SET_SPRITES_DRAW_BEFORE_FADE: + CollectParameters(&m_nIp, 1); + CTheScripts::IntroRectangles[CTheScripts::NumberOfIntroRectanglesThisFrame].m_bBeforeFade = ScriptParams[0] != 0; + return 0; + case COMMAND_SET_TEXT_RIGHT_JUSTIFY: + CollectParameters(&m_nIp, 1); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_bRightJustify = ScriptParams[0] != 0; + return 0; + case COMMAND_PRINT_HELP: + { + if (CCamera::m_bUseMouse3rdPerson && ( + strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "HELP15", 7) == 0 || + strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "GUN_2A", 7) == 0 || + strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "GUN_3A", 7) == 0 || + strncmp((char*)&CTheScripts::ScriptSpace[m_nIp], "GUN_4A", 7) == 0)) { + m_nIp += KEY_LENGTH_IN_SCRIPT; + return 0; + } + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CHud::SetHelpMessage(text, false); + return 0; + } + case COMMAND_CLEAR_HELP: + CHud::SetHelpMessage(nil, false); + return 0; + case COMMAND_FLASH_HUD_OBJECT: + CollectParameters(&m_nIp, 1); + CHud::m_ItemToFlash = ScriptParams[0]; + return 0; + default: + script_assert(0); + } + return -1; +} diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp new file mode 100644 index 00000000..bada95ea --- /dev/null +++ b/src/control/Script5.cpp @@ -0,0 +1,2011 @@ +#include "common.h" + +#include "Script.h" +#include "ScriptCommands.h" + +#include "CarCtrl.h" +#include "BulletInfo.h" +#include "General.h" +#include "Lines.h" +#include "Messages.h" +#include "Pad.h" +#include "Pools.h" +#include "Population.h" +#include "RpAnimBlend.h" +#include "Shadows.h" +#include "SpecialFX.h" +#include "World.h" +#include "main.h" + +int32 CTheScripts::GetNewUniqueScriptSphereIndex(int32 index) +{ + if (ScriptSphereArray[index].m_Index >= UINT16_MAX - 1) + ScriptSphereArray[index].m_Index = 1; + else + ScriptSphereArray[index].m_Index++; + return (uint16)index | ScriptSphereArray[index].m_Index << 16; +} + +int32 CTheScripts::GetActualScriptSphereIndex(int32 index) +{ + if (index == -1) + return -1; + uint16 check = (uint32)index >> 16; + uint16 array_idx = index & (0xFFFF); + script_assert(array_idx < ARRAY_SIZE(ScriptSphereArray)); + if (check != ScriptSphereArray[array_idx].m_Index) + return -1; + return array_idx; +} + +void CTheScripts::DrawScriptSpheres() +{ + for (int i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++) { + if (ScriptSphereArray[i].m_bInUse) + C3dMarkers::PlaceMarkerSet(ScriptSphereArray[i].m_Id, MARKERTYPE_CYLINDER, ScriptSphereArray[i].m_vecCenter, ScriptSphereArray[i].m_fRadius, + SPHERE_MARKER_R, SPHERE_MARKER_G, SPHERE_MARKER_B, SPHERE_MARKER_A, SPHERE_MARKER_PULSE_PERIOD, SPHERE_MARKER_PULSE_FRACTION, 0); + } +} + +int32 CTheScripts::AddScriptSphere(int32 id, CVector pos, float radius) +{ + int16 i = 0; + for (i = 0; i < MAX_NUM_SCRIPT_SPHERES; i++) { + if (!ScriptSphereArray[i].m_bInUse) + break; + } +#ifdef FIX_BUGS + if (i == MAX_NUM_SCRIPT_SPHERES) + return -1; +#endif + ScriptSphereArray[i].m_bInUse = true; + ScriptSphereArray[i].m_Id = id; + ScriptSphereArray[i].m_vecCenter = pos; + ScriptSphereArray[i].m_fRadius = radius; + return GetNewUniqueScriptSphereIndex(i); +} + +void CTheScripts::RemoveScriptSphere(int32 index) +{ + index = GetActualScriptSphereIndex(index); + if (index == -1) + return; + ScriptSphereArray[index].m_bInUse = false; + ScriptSphereArray[index].m_Id = 0; +} + +void CTheScripts::AddToBuildingSwapArray(CBuilding* pBuilding, int32 old_model, int32 new_model) +{ + int i = 0; + bool found = false; + while (i < MAX_NUM_BUILDING_SWAPS && !found) { + if (BuildingSwapArray[i].m_pBuilding == pBuilding) + found = true; + else + i++; + } + if (found) { + if (BuildingSwapArray[i].m_nOldModel == new_model) { + BuildingSwapArray[i].m_pBuilding = nil; + BuildingSwapArray[i].m_nOldModel = BuildingSwapArray[i].m_nNewModel = -1; + } + else { + BuildingSwapArray[i].m_nNewModel = new_model; + } + } + else { + i = 0; + while (i < MAX_NUM_BUILDING_SWAPS && !found) { + if (BuildingSwapArray[i].m_pBuilding == nil) + found = true; + else + i++; + } + if (found) { + BuildingSwapArray[i].m_pBuilding = pBuilding; + BuildingSwapArray[i].m_nNewModel = new_model; + BuildingSwapArray[i].m_nOldModel = old_model; + } + } +} + +void CTheScripts::AddToInvisibilitySwapArray(CEntity* pEntity, bool remove) +{ + int i = 0; + bool found = false; + while (i < MAX_NUM_INVISIBILITY_SETTINGS && !found) { + if (InvisibilitySettingArray[i] == pEntity) + found = true; + else + i++; + } + if (found) { + if (remove) + InvisibilitySettingArray[i] = nil; + } + else if (!remove) { + i = 0; + while (i < MAX_NUM_INVISIBILITY_SETTINGS && !found) { + if (InvisibilitySettingArray[i] == nil) + found = true; + else + i++; + } + if (found) + InvisibilitySettingArray[i] = pEntity; + } +} + +void CTheScripts::UndoBuildingSwaps() +{ + for (int i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { + if (BuildingSwapArray[i].m_pBuilding) { + BuildingSwapArray[i].m_pBuilding->ReplaceWithNewModel(BuildingSwapArray[i].m_nOldModel); + BuildingSwapArray[i].m_pBuilding = nil; + BuildingSwapArray[i].m_nOldModel = BuildingSwapArray[i].m_nNewModel = -1; + } + } +} + +void CTheScripts::UndoEntityInvisibilitySettings() +{ + for (int i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) { + if (InvisibilitySettingArray[i]) { + InvisibilitySettingArray[i]->bIsVisible = true; + InvisibilitySettingArray[i] = nil; + } + } +} + + +void CRunningScript::UpdateCompareFlag(bool flag) +{ + if (m_bNotFlag) + flag = !flag; + if (m_nAndOrState == ANDOR_NONE) { + m_bCondResult = flag; + return; + } + if (m_nAndOrState >= ANDS_1 && m_nAndOrState <= ANDS_8) { + m_bCondResult &= flag; + if (m_nAndOrState == ANDS_1) { + m_nAndOrState = ANDOR_NONE; + return; + } + } + else if (m_nAndOrState >= ORS_1 && m_nAndOrState <= ORS_8) { + m_bCondResult |= flag; + if (m_nAndOrState == ORS_1) { + m_nAndOrState = ANDOR_NONE; + return; + } + } + else { + return; + } + m_nAndOrState--; +} + +void CRunningScript::LocatePlayerCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug, decided = false; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_PLAYER_ANY_MEANS_3D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_3D: + case COMMAND_LOCATE_PLAYER_IN_CAR_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 8 : 6); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + switch (command) { + case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_2D: + case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_2D: + case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_2D: + case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D: + if (!CTheScripts::IsPlayerStopped(pPlayerInfo)) { + result = false; + decided = true; + } + break; + default: + break; + } + X = *(float*)&ScriptParams[1]; + Y = *(float*)&ScriptParams[2]; + if (b3D) { + Z = *(float*)&ScriptParams[3]; + dX = *(float*)&ScriptParams[4]; + dY = *(float*)&ScriptParams[5]; + dZ = *(float*)&ScriptParams[6]; + debug = ScriptParams[7]; + } else { + dX = *(float*)&ScriptParams[3]; + dY = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + if (!decided) { + CVector pos = pPlayerInfo->GetPos(); + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_LOCATE_PLAYER_ANY_MEANS_2D: + case COMMAND_LOCATE_PLAYER_ANY_MEANS_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_2D: + case COMMAND_LOCATE_STOPPED_PLAYER_ANY_MEANS_3D: + result = true; + break; + case COMMAND_LOCATE_PLAYER_ON_FOOT_2D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_2D: + case COMMAND_LOCATE_STOPPED_PLAYER_ON_FOOT_3D: + result = !pPlayerInfo->m_pPed->bInVehicle; + break; + case COMMAND_LOCATE_PLAYER_IN_CAR_2D: + case COMMAND_LOCATE_PLAYER_IN_CAR_3D: + case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_2D: + case COMMAND_LOCATE_STOPPED_PLAYER_IN_CAR_3D: + result = pPlayerInfo->m_pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocatePlayerCharCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_3D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_3D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 6 : 5); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CVector pos = pPlayerInfo->GetPos(); + if (pTarget->bInVehicle) { + X = pTarget->m_pMyVehicle->GetPosition().x; + Y = pTarget->m_pMyVehicle->GetPosition().y; + Z = pTarget->m_pMyVehicle->GetPosition().z; + } else { + X = pTarget->GetPosition().x; + Y = pTarget->GetPosition().y; + Z = pTarget->GetPosition().z; + } + dX = *(float*)&ScriptParams[2]; + dY = *(float*)&ScriptParams[3]; + if (b3D) { + dZ = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + else { + debug = ScriptParams[4]; + } + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } + else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_2D: + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CHAR_3D: + result = true; + break; + case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_2D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CHAR_3D: + result = !pPlayerInfo->m_pPed->bInVehicle; + break; + case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_2D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CHAR_3D: + result = pPlayerInfo->m_pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + UpdateCompareFlag(result); + if (debug) +#ifdef FIX_BUGS + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); +#else + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dX, b3D ? Z : MAP_Z_LOW_LIMIT); +#endif + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocatePlayerCarCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 6 : 5); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CVector pos = pPlayerInfo->GetPos(); + X = pTarget->GetPosition().x; + Y = pTarget->GetPosition().y; + Z = pTarget->GetPosition().z; + dX = *(float*)&ScriptParams[2]; + dY = *(float*)&ScriptParams[3]; + if (b3D) { + dZ = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + else { + debug = ScriptParams[4]; + } + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } + else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_2D: + case COMMAND_LOCATE_PLAYER_ANY_MEANS_CAR_3D: + result = true; + break; + case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_2D: + case COMMAND_LOCATE_PLAYER_ON_FOOT_CAR_3D: + result = !pPlayerInfo->m_pPed->bInVehicle; + break; + case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_2D: + case COMMAND_LOCATE_PLAYER_IN_CAR_CAR_3D: + result = pPlayerInfo->m_pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocateCharCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug, decided = false; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_3D: + case COMMAND_LOCATE_CHAR_ON_FOOT_3D: + case COMMAND_LOCATE_CHAR_IN_CAR_3D: + case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D: + case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D: + case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 8 : 6); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); + switch (command) { + case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_2D: + case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D: + case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_2D: + case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D: + case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_2D: + case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D: + if (!CTheScripts::IsPedStopped(pPed)) { + result = false; + decided = true; + } + break; + default: + break; + } + X = *(float*)&ScriptParams[1]; + Y = *(float*)&ScriptParams[2]; + if (b3D) { + Z = *(float*)&ScriptParams[3]; + dX = *(float*)&ScriptParams[4]; + dY = *(float*)&ScriptParams[5]; + dZ = *(float*)&ScriptParams[6]; + debug = ScriptParams[7]; + } + else { + dX = *(float*)&ScriptParams[3]; + dY = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + if (!decided) { + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } + else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_2D: + case COMMAND_LOCATE_CHAR_ANY_MEANS_3D: + case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_2D: + case COMMAND_LOCATE_STOPPED_CHAR_ANY_MEANS_3D: + result = true; + break; + case COMMAND_LOCATE_CHAR_ON_FOOT_2D: + case COMMAND_LOCATE_CHAR_ON_FOOT_3D: + case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_2D: + case COMMAND_LOCATE_STOPPED_CHAR_ON_FOOT_3D: + result = !pPed->bInVehicle; + break; + case COMMAND_LOCATE_CHAR_IN_CAR_2D: + case COMMAND_LOCATE_CHAR_IN_CAR_3D: + case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_2D: + case COMMAND_LOCATE_STOPPED_CHAR_IN_CAR_3D: + result = pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocateCharCharCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_3D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_3D: + case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 6 : 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CPed* pTarget = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); + if (pTarget->bInVehicle) { + X = pTarget->m_pMyVehicle->GetPosition().x; + Y = pTarget->m_pMyVehicle->GetPosition().y; + Z = pTarget->m_pMyVehicle->GetPosition().z; + } + else { + X = pTarget->GetPosition().x; + Y = pTarget->GetPosition().y; + Z = pTarget->GetPosition().z; + } + dX = *(float*)&ScriptParams[2]; + dY = *(float*)&ScriptParams[3]; + if (b3D) { + dZ = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + else { + debug = ScriptParams[4]; + } + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } + else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_2D: + case COMMAND_LOCATE_CHAR_ANY_MEANS_CHAR_3D: + result = true; + break; + case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_2D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CHAR_3D: + result = !pPed->bInVehicle; + break; + case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_2D: + case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_3D: + result = pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + UpdateCompareFlag(result); + if (debug) +#ifdef FIX_BUGS + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); +#else + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dX, b3D ? Z : MAP_Z_LOW_LIMIT); +#endif + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocateCharCarCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D: + case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 6 : 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pTarget = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); + X = pTarget->GetPosition().x; + Y = pTarget->GetPosition().y; + Z = pTarget->GetPosition().z; + dX = *(float*)&ScriptParams[2]; + dY = *(float*)&ScriptParams[3]; + if (b3D) { + dZ = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + else { + debug = ScriptParams[4]; + } + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } + else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_2D: + case COMMAND_LOCATE_CHAR_ANY_MEANS_CAR_3D: + result = true; + break; + case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_2D: + case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D: + result = !pPed->bInVehicle; + break; + case COMMAND_LOCATE_CHAR_IN_CAR_CAR_2D: + case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D: + result = pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocateCharObjectCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D: + case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D: + case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 6 : 5); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CObject* pTarget = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); + X = pTarget->GetPosition().x; + Y = pTarget->GetPosition().y; + Z = pTarget->GetPosition().z; + dX = *(float*)&ScriptParams[2]; + dY = *(float*)&ScriptParams[3]; + if (b3D) { + dZ = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + else { + debug = ScriptParams[4]; + } + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } + else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_2D: + case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D: + result = true; + break; + case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_2D: + case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D: + result = !pPed->bInVehicle; + break; + case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_2D: + case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D: + result = pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocateCarCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug, decided = false; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_CAR_3D: + case COMMAND_LOCATE_STOPPED_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 8 : 6); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CVector pos = pVehicle->GetPosition(); + switch (command) { + case COMMAND_LOCATE_STOPPED_CAR_2D: + case COMMAND_LOCATE_STOPPED_CAR_3D: + if (!CTheScripts::IsVehicleStopped(pVehicle)) { + result = false; + decided = true; + } + break; + default: + break; + } + X = *(float*)&ScriptParams[1]; + Y = *(float*)&ScriptParams[2]; + if (b3D) { + Z = *(float*)&ScriptParams[3]; + dX = *(float*)&ScriptParams[4]; + dY = *(float*)&ScriptParams[5]; + dZ = *(float*)&ScriptParams[6]; + debug = ScriptParams[7]; + } + else { + dX = *(float*)&ScriptParams[3]; + dY = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + if (!decided) { + result = false; + bool in_area; + if (b3D) { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y && + Z - dZ <= pos.z && + Z + dZ >= pos.z; + } + else { + in_area = X - dX <= pos.x && + X + dX >= pos.x && + Y - dY <= pos.y && + Y + dY >= pos.y; + } + result = in_area; + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::LocateSniperBulletCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug; + float X, Y, Z, dX, dY, dZ; + switch (command) { + case COMMAND_LOCATE_SNIPER_BULLET_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 7 : 5); + X = *(float*)&ScriptParams[0]; + Y = *(float*)&ScriptParams[1]; + if (b3D) { + Z = *(float*)&ScriptParams[2]; + dX = *(float*)&ScriptParams[3]; + dY = *(float*)&ScriptParams[4]; + dZ = *(float*)&ScriptParams[5]; + debug = ScriptParams[6]; + } + else { + dX = *(float*)&ScriptParams[2]; + dY = *(float*)&ScriptParams[3]; + debug = ScriptParams[4]; + } + result = CBulletInfo::TestForSniperBullet(X - dX, X + dX, Y - dY, Y + dY, b3D ? Z - dZ : -1000.0f, b3D ? Z + dZ : 1000.0f); + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, X - dX, Y - dY, X + dX, Y + dY, b3D ? Z : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(X - dX, Y - dY, Z - dZ, X + dX, Y + dY, Z + dZ); + else + CTheScripts::DrawDebugSquare(X - dX, Y - dY, X + dX, Y + dY); + } +} + +void CRunningScript::PlayerInAreaCheckCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug, decided = false; + float infX, infY, infZ, supX, supY, supZ; + switch (command) { + case COMMAND_IS_PLAYER_IN_AREA_3D: + case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 8 : 6); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + switch (command) { + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_2D: + if (!CTheScripts::IsPlayerStopped(pPlayerInfo)) { + result = false; + decided = true; + } + break; + default: + break; + } + infX = *(float*)&ScriptParams[1]; + infY = *(float*)&ScriptParams[2]; + if (b3D) { + infZ = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[6]; + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[6]; + supZ = *(float*)&ScriptParams[3]; + } + debug = ScriptParams[7]; + } + else { + supX = *(float*)&ScriptParams[3]; + supY = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + if (infX > supX) { + float tmp = infX; + infX = supX; + supX = tmp; + } + if (infY > supY) { + float tmp = infY; + infY = supY; + supY = tmp; + } + if (!decided) { + CVector pos = pPlayerInfo->GetPos(); + result = false; + bool in_area; + if (b3D) { + in_area = infX <= pos.x && + supX >= pos.x && + infY <= pos.y && + supY >= pos.y && + infZ <= pos.z && + supZ >= pos.z; + } + else { + in_area = infX <= pos.x && + supX >= pos.x && + infY <= pos.y && + supY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_IS_PLAYER_IN_AREA_2D: + case COMMAND_IS_PLAYER_IN_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_3D: + result = true; + break; + case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_ON_FOOT_3D: + result = !pPlayerInfo->m_pPed->bInVehicle; + break; + case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_IN_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_AREA_IN_CAR_3D: + result = pPlayerInfo->m_pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, infX, infY, supX, supY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); + else + CTheScripts::DrawDebugSquare(infX, infY, supX, supY); + } +} + +void CRunningScript::PlayerInAngledAreaCheckCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug, decided = false; + float infX, infY, infZ, supX, supY, supZ, side2length; + switch (command) { + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_3D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 9 : 7); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + switch (command) { + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_2D: + if (!CTheScripts::IsPlayerStopped(pPlayerInfo)) { + result = false; + decided = true; + } + break; + default: + break; + } + infX = *(float*)&ScriptParams[1]; + infY = *(float*)&ScriptParams[2]; + if (b3D) { + infZ = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[6]; + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[6]; + supZ = *(float*)&ScriptParams[3]; + } + side2length = *(float*)&ScriptParams[7]; + debug = ScriptParams[8]; + } + else { + supX = *(float*)&ScriptParams[3]; + supY = *(float*)&ScriptParams[4]; + side2length = *(float*)&ScriptParams[5]; + debug = ScriptParams[6]; + } + float initAngle = CGeneral::GetRadianAngleBetweenPoints(infX, infY, supX, supY) + HALFPI; + while (initAngle < 0.0f) + initAngle += TWOPI; + while (initAngle > TWOPI) + initAngle -= TWOPI; + // it looks like the idea is to use a rectangle using the diagonal of the rectangle as + // the side of new rectangle, with "length" being the length of second side + float rotatedSupX = supX + side2length * sin(initAngle); + float rotatedSupY = supY - side2length * cos(initAngle); + float rotatedInfX = infX + side2length * sin(initAngle); + float rotatedInfY = infY - side2length * cos(initAngle); + float side1X = supX - infX; + float side1Y = supY - infY; + float side1Length = CVector2D(side1X, side1Y).Magnitude(); + float side2X = rotatedInfX - infX; + float side2Y = rotatedInfY - infY; + float side2Length = CVector2D(side2X, side2Y).Magnitude(); // == side2length? + if (!decided) { + CVector pos = pPlayerInfo->GetPos(); + result = false; + float X = pos.x - infX; + float Y = pos.y - infY; + float positionAlongSide1 = X * side1X / side1Length + Y * side1Y / side1Length; + bool in_area = false; + if (positionAlongSide1 >= 0.0f && positionAlongSide1 <= side1Length) { + float positionAlongSide2 = X * side2X / side2Length + Y * side2Y / side2Length; + if (positionAlongSide2 >= 0.0f && positionAlongSide2 <= side2Length) { + in_area = !b3D || pos.z >= infZ && pos.z <= supZ; + } + } + + if (in_area) { + switch (command) { + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_2D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_3D: + result = true; + break; + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_ON_FOOT_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_ON_FOOT_3D: + result = !pPlayerInfo->m_pPed->bInVehicle; + break; + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_IN_ANGLED_AREA_IN_CAR_3D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_2D: + case COMMAND_IS_PLAYER_STOPPED_IN_ANGLED_AREA_IN_CAR_3D: + result = pPlayerInfo->m_pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantAngledArea((uintptr)this + m_nIp, infX, infY, supX, supY, + rotatedSupX, rotatedSupY, rotatedInfX, rotatedInfY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugAngledCube(infX, infY, infZ, supX, supY, supZ, + rotatedSupX, rotatedSupY, rotatedInfX, rotatedInfY); + else + CTheScripts::DrawDebugAngledSquare(infX, infY, supX, supY, + rotatedSupX, rotatedSupY, rotatedInfX, rotatedInfY); + } +} + +void CRunningScript::CharInAreaCheckCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug, decided = false; + float infX, infY, infZ, supX, supY, supZ; + switch (command) { + case COMMAND_IS_CHAR_IN_AREA_3D: + case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_CHAR_IN_AREA_IN_CAR_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 8 : 6); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVector pos = pPed->bInVehicle ? pPed->m_pMyVehicle->GetPosition() : pPed->GetPosition(); + switch (command) { + case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_2D: + if (!CTheScripts::IsPedStopped(pPed)) { + result = false; + decided = true; + } + break; + default: + break; + } + infX = *(float*)&ScriptParams[1]; + infY = *(float*)&ScriptParams[2]; + if (b3D) { + infZ = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[6]; + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[6]; + supZ = *(float*)&ScriptParams[3]; + } + debug = ScriptParams[7]; + } + else { + supX = *(float*)&ScriptParams[3]; + supY = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + if (infX > supX) { + float tmp = infX; + infX = supX; + supX = tmp; + } + if (infY > supY) { + float tmp = infY; + infY = supY; + supY = tmp; + } + if (!decided) { + result = false; + bool in_area; + if (b3D) { + in_area = infX <= pos.x && + supX >= pos.x && + infY <= pos.y && + supY >= pos.y && + infZ <= pos.z && + supZ >= pos.z; + } + else { + in_area = infX <= pos.x && + supX >= pos.x && + infY <= pos.y && + supY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_IS_CHAR_IN_AREA_2D: + case COMMAND_IS_CHAR_IN_AREA_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_3D: + result = true; + break; + case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_CHAR_IN_AREA_ON_FOOT_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_ON_FOOT_3D: + result = !pPed->bInVehicle; + break; + case COMMAND_IS_CHAR_IN_AREA_IN_CAR_2D: + case COMMAND_IS_CHAR_IN_AREA_IN_CAR_3D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_2D: + case COMMAND_IS_CHAR_STOPPED_IN_AREA_IN_CAR_3D: + result = pPed->bInVehicle; + break; + default: + script_assert(false); + break; + } + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, infX, infY, supX, supY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); + else + CTheScripts::DrawDebugSquare(infX, infY, supX, supY); + } +} + +void CRunningScript::CarInAreaCheckCommand(int32 command, uint32* pIp) +{ + bool b3D, result, debug, decided = false; + float infX, infY, infZ, supX, supY, supZ; + switch (command) { + case COMMAND_IS_CAR_IN_AREA_3D: + case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: + b3D = true; + break; + default: + b3D = false; + break; + } + CollectParameters(pIp, b3D ? 8 : 6); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CVector pos = pVehicle->GetPosition(); + switch (command) { + case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: + case COMMAND_IS_CAR_STOPPED_IN_AREA_2D: + if (!CTheScripts::IsVehicleStopped(pVehicle)) { + result = false; + decided = true; + } + break; + default: + break; + } + infX = *(float*)&ScriptParams[1]; + infY = *(float*)&ScriptParams[2]; + if (b3D) { + infZ = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[6]; + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[6]; + supZ = *(float*)&ScriptParams[3]; + } + debug = ScriptParams[7]; + } + else { + supX = *(float*)&ScriptParams[3]; + supY = *(float*)&ScriptParams[4]; + debug = ScriptParams[5]; + } + if (infX > supX) { + float tmp = infX; + infX = supX; + supX = tmp; + } + if (infY > supY) { + float tmp = infY; + infY = supY; + supY = tmp; + } + if (!decided) { + result = false; + bool in_area; + if (b3D) { + in_area = infX <= pos.x && + supX >= pos.x && + infY <= pos.y && + supY >= pos.y && + infZ <= pos.z && + supZ >= pos.z; + } + else { + in_area = infX <= pos.x && + supX >= pos.x && + infY <= pos.y && + supY >= pos.y; + } + if (in_area) { + switch (command) { + case COMMAND_IS_CAR_IN_AREA_2D: + case COMMAND_IS_CAR_IN_AREA_3D: + case COMMAND_IS_CAR_STOPPED_IN_AREA_2D: + case COMMAND_IS_CAR_STOPPED_IN_AREA_3D: + result = true; + break; + default: + script_assert(false); + break; + } + } + } + UpdateCompareFlag(result); + if (debug) + CTheScripts::HighlightImportantArea((uintptr)this + m_nIp, infX, infY, supX, supY, b3D ? (infZ + supZ) / 2 : MAP_Z_LOW_LIMIT); + if (CTheScripts::DbgFlag) { + if (b3D) + CTheScripts::DrawDebugCube(infX, infY, infZ, supX, supY, supZ); + else + CTheScripts::DrawDebugSquare(infX, infY, supX, supY); + } +} + +void CRunningScript::DoDeatharrestCheck() +{ + if (!m_bDeatharrestEnabled) + return; + if (!CTheScripts::IsPlayerOnAMission()) + return; + CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus]; + if (!pPlayer->IsRestartingAfterDeath() && !pPlayer->IsRestartingAfterArrest() && !CTheScripts::UpsideDownCars.AreAnyCarsUpsideDown()) + return; +#ifdef MISSION_REPLAY + if (AllowMissionReplay != 0) + return; + if (CanAllowMissionReplay()) + AllowMissionReplay = 1; +#endif + script_assert(m_nStackPointer > 0); + while (m_nStackPointer > 1) + --m_nStackPointer; + m_nIp = m_anStack[--m_nStackPointer]; + int16 messageId; + if (pPlayer->IsRestartingAfterDeath()) + messageId = 0; + else if (pPlayer->IsRestartingAfterArrest()) + messageId = 5; + else + messageId = 10; + messageId += CGeneral::GetRandomNumberInRange(0, 5); + bool found = false; + for (int16 contact = 0; !found && contact < MAX_NUM_CONTACTS; contact++) { + int contactFlagOffset = CTheScripts::OnAMissionForContactFlag[contact]; + if (contactFlagOffset && CTheScripts::ScriptSpace[contactFlagOffset] == 1) { + messageId += CTheScripts::BaseBriefIdForContact[contact]; + found = true; + } + } + if (!found) + messageId = 8001; + char tmp[16]; + sprintf(tmp, "%d", messageId); + CMessages::ClearSmallMessagesOnly(); + wchar* text = TheText.Get(tmp); + // ...and do nothing about it + *(int32*)&CTheScripts::ScriptSpace[CTheScripts::OnAMissionFlag] = 0; + m_bDeatharrestExecuted = true; + m_nWakeTime = 0; +} + +int16 CRunningScript::GetPadState(uint16 pad, uint16 button) +{ + CPad* pPad = CPad::GetPad(pad); + switch (button) { + case 0: return pPad->NewState.LeftStickX; + case 1: return pPad->NewState.LeftStickY; + case 2: return pPad->NewState.RightStickX; + case 3: return pPad->NewState.RightStickY; + case 4: return pPad->NewState.LeftShoulder1; + case 5: return pPad->NewState.LeftShoulder2; + case 6: return pPad->NewState.RightShoulder1; + case 7: return pPad->NewState.RightShoulder2; + case 8: return pPad->NewState.DPadUp; + case 9: return pPad->NewState.DPadDown; + case 10: return pPad->NewState.DPadLeft; + case 11: return pPad->NewState.DPadRight; + case 12: return pPad->NewState.Start; + case 13: return pPad->NewState.Select; + case 14: return pPad->NewState.Square; + case 15: return pPad->NewState.Triangle; + case 16: return pPad->NewState.Cross; + case 17: return pPad->NewState.Circle; + case 18: return pPad->NewState.LeftShock; + case 19: return pPad->NewState.RightShock; + default: break; + } + return 0; +} + + +void CTheScripts::PrintListSizes() +{ + int active = 0; + int idle = 0; + + for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext()) + active++; + for (CRunningScript* pScript = pIdleScripts; pScript; pScript = pScript->GetNext()) + idle++; + + debug("active: %d, idle: %d", active, idle); +} + +uint32 DbgLineColour = 0x0000FFFF; // r = 0, g = 0, b = 255, a = 255 + +void CTheScripts::DrawDebugSquare(float infX, float infY, float supX, float supY) +{ + CColPoint tmpCP; + CEntity* tmpEP; + CVector p1, p2, p3, p4; + p1 = CVector(infX, infY, -1000.0f); + CWorld::ProcessVerticalLine(p1, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p1.z = 2.0f + tmpCP.point.z; + p2 = CVector(supX, supY, -1000.0f); + CWorld::ProcessVerticalLine(p2, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p2.z = 2.0f + tmpCP.point.z; + p3 = CVector(infX, supY, -1000.0f); + CWorld::ProcessVerticalLine(p3, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p3.z = 2.0f + tmpCP.point.z; + p4 = CVector(supX, infY, -1000.0f); + CWorld::ProcessVerticalLine(p4, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p4.z = 2.0f + tmpCP.point.z; + CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(p3.x, p3.y, p3.z, p4.x, p4.y, p4.z, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(p4.x, p4.y, p4.z, p1.x, p1.y, p1.z, DbgLineColour, DbgLineColour); +} + +void CTheScripts::DrawDebugAngledSquare(float infX, float infY, float supX, float supY, float rotSupX, float rotSupY, float rotInfX, float rotInfY) +{ + CColPoint tmpCP; + CEntity* tmpEP; + CVector p1, p2, p3, p4; + p1 = CVector(infX, infY, -1000.0f); + CWorld::ProcessVerticalLine(p1, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p1.z = 2.0f + tmpCP.point.z; + p2 = CVector(supX, supY, -1000.0f); + CWorld::ProcessVerticalLine(p2, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p2.z = 2.0f + tmpCP.point.z; + p3 = CVector(rotSupX, rotSupY, -1000.0f); + CWorld::ProcessVerticalLine(p3, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p3.z = 2.0f + tmpCP.point.z; + p4 = CVector(rotInfX, rotInfY, -1000.0f); + CWorld::ProcessVerticalLine(p4, 1000.0f, tmpCP, tmpEP, true, false, false, false, true, false, nil); + p4.z = 2.0f + tmpCP.point.z; + CTheScripts::ScriptDebugLine3D(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(p2.x, p2.y, p2.z, p3.x, p3.y, p3.z, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(p3.x, p3.y, p3.z, p4.x, p4.y, p4.z, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(p4.x, p4.y, p4.z, p1.x, p1.y, p1.z, DbgLineColour, DbgLineColour); +} + +void CTheScripts::DrawDebugCube(float infX, float infY, float infZ, float supX, float supY, float supZ) +{ + CTheScripts::ScriptDebugLine3D(infX, infY, infZ, supX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, infY, infZ, supX, supY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, supY, infZ, infX, supY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(infX, supY, infZ, infX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(infX, infY, supZ, supX, infY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, infY, supZ, supX, supY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, supY, supZ, infX, supY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(infX, supY, supZ, infX, infY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(infX, infY, supZ, infX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, infY, supZ, supX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, supY, supZ, supX, supY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(infX, supY, supZ, infX, supY, infZ, DbgLineColour, DbgLineColour); +} + +void CTheScripts::DrawDebugAngledCube(float infX, float infY, float infZ, float supX, float supY, float supZ, float rotSupX, float rotSupY, float rotInfX, float rotInfY) +{ + CTheScripts::ScriptDebugLine3D(infX, infY, infZ, supX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, infY, infZ, rotSupX, rotSupY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(rotSupX, rotSupY, infZ, rotInfX, rotInfY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(rotInfX, rotInfY, infZ, infX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(infX, infY, supZ, supX, infY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, infY, supZ, rotSupX, rotSupY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(rotSupX, rotSupY, rotInfX, rotInfY, supY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(rotInfX, rotInfY, supZ, infX, infY, supZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(infX, infY, supZ, infX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(supX, infY, supZ, supX, infY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(rotSupX, rotSupY, supZ, rotSupX, rotSupY, infZ, DbgLineColour, DbgLineColour); + CTheScripts::ScriptDebugLine3D(rotInfX, rotInfY, supZ, rotInfX, rotInfY, infZ, DbgLineColour, DbgLineColour); +} + +void CTheScripts::ScriptDebugLine3D(float x1, float y1, float z1, float x2, float y2, float z2, uint32 col, uint32 col2) +{ + if (NumScriptDebugLines >= MAX_NUM_STORED_LINES) + return; + aStoredLines[NumScriptDebugLines].vecInf = CVector(x1, y1, z1); + aStoredLines[NumScriptDebugLines].vecSup = CVector(x2, y2, z2); + aStoredLines[NumScriptDebugLines].color1 = col; + aStoredLines[NumScriptDebugLines++].color2 = col2; +} + +void CTheScripts::RenderTheScriptDebugLines() +{ + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)1); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)1); + for (int i = 0; i < NumScriptDebugLines; i++) { + CLines::RenderLineWithClipping( + aStoredLines[i].vecInf.x, + aStoredLines[i].vecInf.y, + aStoredLines[i].vecInf.z, + aStoredLines[i].vecSup.x, + aStoredLines[i].vecSup.y, + aStoredLines[i].vecSup.z, + aStoredLines[i].color1, + aStoredLines[i].color2); + } + NumScriptDebugLines = 0; + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)0); +} + +#define SCRIPT_DATA_SIZE sizeof(CTheScripts::OnAMissionFlag) + sizeof(CTheScripts::BaseBriefIdForContact) + sizeof(CTheScripts::OnAMissionForContactFlag) +\ + sizeof(CTheScripts::CollectiveArray) + 4 * sizeof(uint32) * MAX_NUM_BUILDING_SWAPS + 2 * sizeof(uint32) * MAX_NUM_INVISIBILITY_SETTINGS + 5 * sizeof(uint32) + +void CTheScripts::SaveAllScripts(uint8* buf, uint32* size) +{ +INITSAVEBUF + uint32 varSpace = GetSizeOfVariableSpace(); + uint32 runningScripts = 0; + for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext()) + runningScripts++; + *size = CRunningScript::nSaveStructSize * runningScripts + varSpace + SCRIPT_DATA_SIZE + SAVE_HEADER_SIZE + 3 * sizeof(uint32); + WriteSaveHeader(buf, 'S', 'C', 'R', '\0', *size - SAVE_HEADER_SIZE); + WriteSaveBuf(buf, varSpace); + for (uint32 i = 0; i < varSpace; i++) + WriteSaveBuf(buf, ScriptSpace[i]); +#ifdef CHECK_STRUCT_SIZES + static_assert(SCRIPT_DATA_SIZE == 968, "CTheScripts::SaveAllScripts"); +#endif + uint32 script_data_size = SCRIPT_DATA_SIZE; + WriteSaveBuf(buf, script_data_size); + WriteSaveBuf(buf, OnAMissionFlag); + for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) { + WriteSaveBuf(buf, OnAMissionForContactFlag[i]); + WriteSaveBuf(buf, BaseBriefIdForContact[i]); + } + for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++) + WriteSaveBuf(buf, CollectiveArray[i]); + WriteSaveBuf(buf, NextFreeCollectiveIndex); + for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { + CBuilding* pBuilding = BuildingSwapArray[i].m_pBuilding; + uint32 type, handle; + if (!pBuilding) { + type = 0; + handle = 0; + } else if (pBuilding->GetIsATreadable()) { + type = 1; + handle = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pBuilding) + 1; + } else { + type = 2; + handle = CPools::GetBuildingPool()->GetJustIndex(pBuilding) + 1; + } + WriteSaveBuf(buf, type); + WriteSaveBuf(buf, handle); + WriteSaveBuf(buf, BuildingSwapArray[i].m_nNewModel); + WriteSaveBuf(buf, BuildingSwapArray[i].m_nOldModel); + } + for (uint32 i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) { + CEntity* pEntity = InvisibilitySettingArray[i]; + uint32 type, handle; + if (!pEntity) { + type = 0; + handle = 0; + } else { + switch (pEntity->GetType()) { + case ENTITY_TYPE_BUILDING: + if (((CBuilding*)pEntity)->GetIsATreadable()) { + type = 1; + handle = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pEntity) + 1; + } else { + type = 2; + handle = CPools::GetBuildingPool()->GetJustIndex((CBuilding*)pEntity) + 1; + } + break; + case ENTITY_TYPE_OBJECT: + type = 3; + handle = CPools::GetObjectPool()->GetJustIndex((CObject*)pEntity) + 1; + break; + case ENTITY_TYPE_DUMMY: + type = 4; + handle = CPools::GetDummyPool()->GetJustIndex((CDummy*)pEntity) + 1; + default: break; + } + } + WriteSaveBuf(buf, type); + WriteSaveBuf(buf, handle); + } + WriteSaveBuf(buf, bUsingAMultiScriptFile); + WriteSaveBuf(buf, (uint8)0); + WriteSaveBuf(buf, (uint16)0); + WriteSaveBuf(buf, MainScriptSize); + WriteSaveBuf(buf, LargestMissionScriptSize); + WriteSaveBuf(buf, NumberOfMissionScripts); + WriteSaveBuf(buf, (uint16)0); + WriteSaveBuf(buf, runningScripts); + for (CRunningScript* pScript = pActiveScripts; pScript; pScript = pScript->GetNext()) + pScript->Save(buf); +VALIDATESAVEBUF(*size) +} + +void CTheScripts::LoadAllScripts(uint8* buf, uint32 size) +{ + Init(); +INITSAVEBUF + CheckSaveHeader(buf, 'S', 'C', 'R', '\0', size - SAVE_HEADER_SIZE); + uint32 varSpace = ReadSaveBuf(buf); + for (uint32 i = 0; i < varSpace; i++) + ScriptSpace[i] = ReadSaveBuf(buf); + script_assert(ReadSaveBuf(buf) == SCRIPT_DATA_SIZE); + OnAMissionFlag = ReadSaveBuf(buf); + for (uint32 i = 0; i < MAX_NUM_CONTACTS; i++) { + OnAMissionForContactFlag[i] = ReadSaveBuf(buf); + BaseBriefIdForContact[i] = ReadSaveBuf(buf); + } + for (uint32 i = 0; i < MAX_NUM_COLLECTIVES; i++) + CollectiveArray[i] = ReadSaveBuf(buf); + NextFreeCollectiveIndex = ReadSaveBuf(buf); + for (uint32 i = 0; i < MAX_NUM_BUILDING_SWAPS; i++) { + uint32 type = ReadSaveBuf(buf); + uint32 handle = ReadSaveBuf(buf); + switch (type) { + case 0: + BuildingSwapArray[i].m_pBuilding = nil; + break; + case 1: + BuildingSwapArray[i].m_pBuilding = CPools::GetTreadablePool()->GetSlot(handle - 1); + break; + case 2: + BuildingSwapArray[i].m_pBuilding = CPools::GetBuildingPool()->GetSlot(handle - 1); + break; + default: + script_assert(false); + } + BuildingSwapArray[i].m_nNewModel = ReadSaveBuf(buf); + BuildingSwapArray[i].m_nOldModel = ReadSaveBuf(buf); + if (BuildingSwapArray[i].m_pBuilding) + BuildingSwapArray[i].m_pBuilding->ReplaceWithNewModel(BuildingSwapArray[i].m_nNewModel); + } + for (uint32 i = 0; i < MAX_NUM_INVISIBILITY_SETTINGS; i++) { + uint32 type = ReadSaveBuf(buf); + uint32 handle = ReadSaveBuf(buf); + switch (type) { + case 0: + InvisibilitySettingArray[i] = nil; + break; + case 1: + InvisibilitySettingArray[i] = CPools::GetTreadablePool()->GetSlot(handle - 1); + break; + case 2: + InvisibilitySettingArray[i] = CPools::GetBuildingPool()->GetSlot(handle - 1); + break; + case 3: + InvisibilitySettingArray[i] = CPools::GetObjectPool()->GetSlot(handle - 1); + break; + case 4: + InvisibilitySettingArray[i] = CPools::GetDummyPool()->GetSlot(handle - 1); + break; + default: + script_assert(false); + } + if (InvisibilitySettingArray[i]) + InvisibilitySettingArray[i]->bIsVisible = false; + } + script_assert(ReadSaveBuf(buf) == bUsingAMultiScriptFile); + ReadSaveBuf(buf); + ReadSaveBuf(buf); + script_assert(ReadSaveBuf(buf) == MainScriptSize); + script_assert(ReadSaveBuf(buf) == LargestMissionScriptSize); + script_assert(ReadSaveBuf(buf) == NumberOfMissionScripts); + ReadSaveBuf(buf); + uint32 runningScripts = ReadSaveBuf(buf); + for (uint32 i = 0; i < runningScripts; i++) + StartNewScript(0)->Load(buf); +VALIDATESAVEBUF(size) +} + +#undef SCRIPT_DATA_SIZE + +void CTheScripts::ClearSpaceForMissionEntity(const CVector& pos, CEntity* pEntity) +{ + static CColPoint aTempColPoints[MAX_COLLISION_POINTS]; + int16 entities = 0; + CEntity* aEntities[16]; + CWorld::FindObjectsKindaColliding(pos, pEntity->GetBoundRadius(), false, &entities, 16, aEntities, false, true, true, false, false); + if (entities <= 0) + return; + for (uint16 i = 0; i < entities; i++) { + if (aEntities[i] != pEntity && aEntities[i]->IsPed() && ((CPed*)aEntities[i])->bInVehicle) + aEntities[i] = nil; + } + for (uint16 i = 0; i < entities; i++) { + if (aEntities[i] == pEntity || !aEntities[i]) + continue; + CEntity* pFound = aEntities[i]; + int cols; + if (pEntity->GetColModel()->numLines <= 0) + cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(), + pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints, nil, nil); + else { + float lines[4]; + lines[0] = lines[1] = lines[2] = lines[3] = 1.0f; + CColPoint tmp[4]; + cols = CCollision::ProcessColModels(pEntity->GetMatrix(), *pEntity->GetColModel(), + pFound->GetMatrix(), *pFound->GetColModel(), aTempColPoints,tmp, lines); + } + if (cols <= 0) + continue; + switch (pFound->GetType()) { + case ENTITY_TYPE_VEHICLE: + { + printf("Will try to delete a vehicle where a mission entity should be\n"); + CVehicle* pVehicle = (CVehicle*)pFound; + if (pVehicle->bIsLocked || !pVehicle->CanBeDeleted()) + break; + if (pVehicle->pDriver) { + CPopulation::RemovePed(pVehicle->pDriver); + pVehicle->pDriver = nil; + } + for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++) { + if (pVehicle->pPassengers[i]) { + CPopulation::RemovePed(pVehicle->pPassengers[i]); + pVehicle->pPassengers[i] = 0; + pVehicle->m_nNumPassengers--; + } + } + CCarCtrl::RemoveFromInterestingVehicleList(pVehicle); + CWorld::Remove(pVehicle); + delete pVehicle; + break; + } + case ENTITY_TYPE_PED: + { + CPed* pPed = (CPed*)pFound; + if (pPed->IsPlayer() || !pPed->CanBeDeleted()) + break; + CPopulation::RemovePed(pPed); + printf("Deleted a ped where a mission entity should be\n"); + break; + } + default: break; + } + } +} + +void CTheScripts::HighlightImportantArea(uint32 id, float x1, float y1, float x2, float y2, float z) +{ + float infX, infY, supX, supY; + if (x1 < x2) { + infX = x1; + supX = x2; + } else { + infX = x2; + supX = x1; + } + if (y1 < y2) { + infY = y1; + supY = y2; + } + else { + infY = y2; + supY = y1; + } + CVector center; + center.x = (infX + supX) / 2; + center.y = (infY + supY) / 2; + center.z = (z <= MAP_Z_LOW_LIMIT) ? CWorld::FindGroundZForCoord(center.x, center.y) : z; + CShadows::RenderIndicatorShadow(id, 2, gpGoalTex, ¢er, supX - center.x, 0.0f, 0.0f, center.y - supY, 0); +} + +void CTheScripts::HighlightImportantAngledArea(uint32 id, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float z) +{ + float infX, infY, supX, supY, X, Y; + X = (x1 + x2) / 2; + Y = (y1 + y2) / 2; + supX = infX = X; + supY = infY = Y; + X = (x2 + x3) / 2; + Y = (y2 + y3) / 2; + infX = Min(infX, X); + supX = Max(supX, X); + infY = Min(infY, Y); + supY = Max(supY, Y); + X = (x3 + x4) / 2; + Y = (y3 + y4) / 2; + infX = Min(infX, X); + supX = Max(supX, X); + infY = Min(infY, Y); + supY = Max(supY, Y); + X = (x4 + x1) / 2; + Y = (y4 + y1) / 2; + infX = Min(infX, X); + supX = Max(supX, X); + infY = Min(infY, Y); + supY = Max(supY, Y); + CVector center; + center.x = (infX + supX) / 2; + center.y = (infY + supY) / 2; + center.z = (z <= MAP_Z_LOW_LIMIT) ? CWorld::FindGroundZForCoord(center.x, center.y) : z; + CShadows::RenderIndicatorShadow(id, 2, gpGoalTex, ¢er, supX - center.x, 0.0f, 0.0f, center.y - supY, 0); +} + +bool CTheScripts::IsPedStopped(CPed* pPed) +{ + if (pPed->bInVehicle) + return IsVehicleStopped(pPed->m_pMyVehicle); + return pPed->m_nMoveState == eMoveState::PEDMOVE_NONE || pPed->m_nMoveState == eMoveState::PEDMOVE_STILL; +} + +bool CTheScripts::IsPlayerStopped(CPlayerInfo* pPlayer) +{ + CPed* pPed = pPlayer->m_pPed; + if (pPed->bInVehicle) + return IsVehicleStopped(pPed->m_pMyVehicle); + if (RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_RUN_STOP) || + RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_RUN_STOP_R) || + RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_JUMP_LAUNCH) || + RpAnimBlendClumpGetAssociation(pPed->GetClump(), ANIM_JUMP_GLIDE)) + return false; + return pPed->m_nMoveState == eMoveState::PEDMOVE_NONE || pPed->m_nMoveState == eMoveState::PEDMOVE_STILL; +} + +bool CTheScripts::IsVehicleStopped(CVehicle* pVehicle) +{ + return 0.01f * CTimer::GetTimeStep() >= pVehicle->m_fDistanceTravelled; +} + +void CTheScripts::CleanUpThisPed(CPed* pPed) +{ + if (!pPed) + return; + if (pPed->CharCreatedBy != MISSION_CHAR) + return; + pPed->CharCreatedBy = RANDOM_CHAR; + if (pPed->m_nPedType == PEDTYPE_PROSTITUTE) + pPed->m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 30000; + if (pPed->bInVehicle) { + if (pPed->m_pMyVehicle->pDriver == pPed) { + if (pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_CAR) { + CCarCtrl::JoinCarWithRoadSystem(pPed->m_pMyVehicle); + pPed->m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; + } + } + else { + if (pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_CAR) { + pPed->SetObjective(OBJECTIVE_LEAVE_CAR, pPed->m_pMyVehicle); + pPed->bWanderPathAfterExitingCar = true; + } + } + } + bool flees = false; + PedState state; + eMoveState ms; + if (pPed->m_nPedState == PED_FLEE_ENTITY || pPed->m_nPedState == PED_FLEE_POS) { + ms = pPed->m_nMoveState; + state = pPed->m_nPedState; + flees = true; + } + pPed->ClearObjective(); + pPed->bRespondsToThreats = true; + pPed->bScriptObjectiveCompleted = false; + pPed->ClearLeader(); + if (pPed->IsPedInControl()) + pPed->SetWanderPath(CGeneral::GetRandomNumber() & 7); + if (flees) { + pPed->m_nPedState = state; + pPed->SetMoveState(ms); + } + --CPopulation::ms_nTotalMissionPeds; +} + +void CTheScripts::CleanUpThisVehicle(CVehicle* pVehicle) +{ + if (!pVehicle) + return; + if (pVehicle->VehicleCreatedBy != MISSION_VEHICLE) + return; + pVehicle->bIsLocked = false; + CCarCtrl::RemoveFromInterestingVehicleList(pVehicle); + pVehicle->VehicleCreatedBy = RANDOM_VEHICLE; + ++CCarCtrl::NumRandomCars; + --CCarCtrl::NumMissionCars; +} + +void CTheScripts::CleanUpThisObject(CObject* pObject) +{ + if (!pObject) + return; + if (pObject->ObjectCreatedBy != MISSION_OBJECT) + return; + pObject->ObjectCreatedBy = TEMP_OBJECT; + pObject->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 20000; + pObject->m_nRefModelIndex = -1; + pObject->bUseVehicleColours = false; + ++CObject::nNoTempObjects; +} + +void CTheScripts::ReadObjectNamesFromScript() +{ + int32 varSpace = GetSizeOfVariableSpace(); + uint32 ip = varSpace + 8; + NumberOfUsedObjects = Read2BytesFromScript(&ip); + ip += 2; + for (uint16 i = 0; i < NumberOfUsedObjects; i++) { + for (int j = 0; j < USED_OBJECT_NAME_LENGTH; j++) + UsedObjectArray[i].name[j] = ScriptSpace[ip++]; + UsedObjectArray[i].index = 0; + } +} + +void CTheScripts::UpdateObjectIndices() +{ + char name[USED_OBJECT_NAME_LENGTH]; + char error[112]; + for (int i = 1; i < NumberOfUsedObjects; i++) { + bool found = false; + for (int j = 0; j < MODELINFOSIZE && !found; j++) { + CBaseModelInfo* pModel = CModelInfo::GetModelInfo(j); + if (!pModel) + continue; + strcpy(name, pModel->GetName()); +#ifdef FIX_BUGS + for (int k = 0; k < USED_OBJECT_NAME_LENGTH && name[k]; k++) +#else + for (int k = 0; k < USED_OBJECT_NAME_LENGTH; k++) +#endif + name[k] = toupper(name[k]); + if (strcmp(name, UsedObjectArray[i].name) == 0) { + found = true; + UsedObjectArray[i].index = j; + } + } + if (!found) { + sprintf(error, "CTheScripts::UpdateObjectIndices - Couldn't find %s", UsedObjectArray[i].name); + debug("%s\n", error); + } + } +} + +void CTheScripts::ReadMultiScriptFileOffsetsFromScript() +{ + int32 varSpace = GetSizeOfVariableSpace(); + uint32 ip = varSpace + 3; + int32 objectSize = Read4BytesFromScript(&ip); + ip = objectSize + 8; + MainScriptSize = Read4BytesFromScript(&ip); + LargestMissionScriptSize = Read4BytesFromScript(&ip); + NumberOfMissionScripts = Read2BytesFromScript(&ip); + ip += 2; + for (int i = 0; i < NumberOfMissionScripts; i++) { + MultiScriptArray[i] = Read4BytesFromScript(&ip); + } +} diff --git a/src/control/Script6.cpp b/src/control/Script6.cpp new file mode 100644 index 00000000..ca6a1853 --- /dev/null +++ b/src/control/Script6.cpp @@ -0,0 +1,1343 @@ +#include "common.h" + +#include "Script.h" +#include "ScriptCommands.h" + +#include "CarCtrl.h" +#include "Cranes.h" +#include "Credits.h" +#include "CutsceneMgr.h" +#include "DMAudio.h" +#include "FileMgr.h" +#include "Fire.h" +#include "Frontend.h" +#include "Garages.h" +#include "General.h" +#ifdef MISSION_REPLAY +#include "GenericGameStorage.h" +#endif +#include "Messages.h" +#include "Pad.h" +#include "Particle.h" +#include "Phones.h" +#include "Population.h" +#include "Pools.h" +#include "Record.h" +#include "Remote.h" +#include "Restart.h" +#include "SpecialFX.h" +#include "Stats.h" +#include "Streaming.h" +#include "Weather.h" +#include "Zones.h" +#include "main.h" + +int8 CRunningScript::ProcessCommands1000To1099(int32 command) +{ +#ifdef GTA_PS2 + char tmp[48]; +#endif + switch (command) { + //case COMMAND_FLASH_RADAR_BLIP: + case COMMAND_IS_CHAR_IN_CONTROL: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + UpdateCompareFlag(pPed->IsPedInControl()); + return 0; + } + case COMMAND_SET_GENERATE_CARS_AROUND_CAMERA: + CollectParameters(&m_nIp, 1); + CCarCtrl::bCarsGeneratedAroundCamera = (ScriptParams[0] != 0); + return 0; + case COMMAND_CLEAR_SMALL_PRINTS: + CMessages::ClearSmallMessagesOnly(); + return 0; + case COMMAND_HAS_MILITARY_CRANE_COLLECTED_ALL_CARS: + UpdateCompareFlag(CCranes::HaveAllCarsBeenCollectedByMilitaryCrane()); + return 0; + case COMMAND_SET_UPSIDEDOWN_CAR_NOT_DAMAGED: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + CAutomobile* pCar = (CAutomobile*)pVehicle; + pCar->bNotDamagedUpsideDown = (ScriptParams[1] != 0); + return 0; + } + case COMMAND_CAN_PLAYER_START_MISSION: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPlayerPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPlayerPed); + UpdateCompareFlag(pPlayerPed->IsPedInControl() || pPlayerPed->m_nPedState == PED_DRIVING); + return 0; + } + case COMMAND_MAKE_PLAYER_SAFE_FOR_CUTSCENE: + { + CollectParameters(&m_nIp, 1); +#ifdef MISSION_REPLAY + AllowMissionReplay = 0; + SaveGameForPause(3); +#endif + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + CPad::GetPad(ScriptParams[0])->SetDisablePlayerControls(PLAYERCONTROL_CUTSCENE); + pPlayerInfo->MakePlayerSafe(true); + CCutsceneMgr::StartCutsceneProcessing(); + return 0; + } + case COMMAND_USE_TEXT_COMMANDS: + CollectParameters(&m_nIp, 1); + CTheScripts::UseTextCommands = (ScriptParams[0] != 0) ? 2 : 1; + return 0; + case COMMAND_SET_THREAT_FOR_PED_TYPE: + CollectParameters(&m_nIp, 2); + CPedType::AddThreat(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_CLEAR_THREAT_FOR_PED_TYPE: + CollectParameters(&m_nIp, 2); + CPedType::RemoveThreat(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_GET_CAR_COLOURS: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + ScriptParams[0] = pVehicle->m_currentColour1; + ScriptParams[1] = pVehicle->m_currentColour2; + StoreParameters(&m_nIp, 2); + return 0; + } + case COMMAND_SET_ALL_CARS_CAN_BE_DAMAGED: + CollectParameters(&m_nIp, 1); + CWorld::SetAllCarsCanBeDamaged(ScriptParams[0] != 0); + if (!ScriptParams[0]) + CWorld::ExtinguishAllCarFiresInArea(FindPlayerCoors(), 4000.0f); + return 0; + case COMMAND_SET_CAR_CAN_BE_DAMAGED: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + pVehicle->bCanBeDamaged = ScriptParams[1] != 0; + if (!ScriptParams[1]) + pVehicle->ExtinguishCarFire(); + return 0; + } + //case COMMAND_MAKE_PLAYER_UNSAFE: + case COMMAND_LOAD_COLLISION: + { + CollectParameters(&m_nIp, 1); + CTimer::Stop(); + CGame::currLevel = (eLevelName)ScriptParams[0]; + ISLAND_LOADING_IS(LOW) + { + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + } + CCollision::SortOutCollisionAfterLoad(); + ISLAND_LOADING_ISNT(HIGH) + { + CStreaming::RequestIslands(CGame::currLevel); + CStreaming::LoadAllRequestedModels(true); + } + CTimer::Update(); + return 0; + } + case COMMAND_GET_BODY_CAST_HEALTH: + ScriptParams[0] = CObject::nBodyCastHealth; + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_SET_CHARS_CHATTING: + { + CollectParameters(&m_nIp, 3); + CPed* pPed1 = CPools::GetPedPool()->GetAt(ScriptParams[0]); + CPed* pPed2 = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pPed1 && pPed2); + pPed1->SetChat(pPed2, ScriptParams[2]); + pPed2->SetChat(pPed1, ScriptParams[2]); + return 0; + } + //case COMMAND_MAKE_PLAYER_SAFE: + case COMMAND_SET_CAR_STAYS_IN_CURRENT_LEVEL: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + if (ScriptParams[1]) + pVehicle->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pVehicle->GetPosition()); + else + pVehicle->m_nZoneLevel = LEVEL_GENERIC; + return 0; + } + case COMMAND_SET_CHAR_STAYS_IN_CURRENT_LEVEL: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + if (ScriptParams[1]) + pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); + else + pPed->m_nZoneLevel = LEVEL_GENERIC; + return 0; + } + case COMMAND_REGISTER_4X4_ONE_TIME: + CollectParameters(&m_nIp, 1); + CStats::Register4x4OneTime(ScriptParams[0]); + return 0; + case COMMAND_REGISTER_4X4_TWO_TIME: + CollectParameters(&m_nIp, 1); + CStats::Register4x4TwoTime(ScriptParams[0]); + return 0; + case COMMAND_REGISTER_4X4_THREE_TIME: + CollectParameters(&m_nIp, 1); + CStats::Register4x4ThreeTime(ScriptParams[0]); + return 0; + case COMMAND_REGISTER_4X4_MAYHEM_TIME: + CollectParameters(&m_nIp, 1); + CStats::Register4x4MayhemTime(ScriptParams[0]); + return 0; + case COMMAND_REGISTER_LIFE_SAVED: + CStats::AnotherLifeSavedWithAmbulance(); + return 0; + case COMMAND_REGISTER_CRIMINAL_CAUGHT: + CStats::AnotherCriminalCaught(); + return 0; + case COMMAND_REGISTER_AMBULANCE_LEVEL: + CollectParameters(&m_nIp, 1); + CStats::RegisterLevelAmbulanceMission(ScriptParams[0]); + return 0; + case COMMAND_REGISTER_FIRE_EXTINGUISHED: + CStats::AnotherFireExtinguished(); + return 0; + case COMMAND_TURN_PHONE_ON: + CollectParameters(&m_nIp, 1); + gPhoneInfo.m_aPhones[ScriptParams[0]].m_nState = PHONE_STATE_9; + return 0; + case COMMAND_REGISTER_LONGEST_DODO_FLIGHT: + CollectParameters(&m_nIp, 1); + CStats::RegisterLongestFlightInDodo(ScriptParams[0]); + return 0; + case COMMAND_REGISTER_DEFUSE_BOMB_TIME: + CollectParameters(&m_nIp, 1); + CStats::RegisterTimeTakenDefuseMission(ScriptParams[0]); + return 0; + case COMMAND_SET_TOTAL_NUMBER_OF_KILL_FRENZIES: + CollectParameters(&m_nIp, 1); + CStats::SetTotalNumberKillFrenzies(ScriptParams[0]); + return 0; + case COMMAND_BLOW_UP_RC_BUGGY: + CWorld::Players[CWorld::PlayerInFocus].BlowUpRCBuggy(); + return 0; + case COMMAND_REMOVE_CAR_FROM_CHASE: + CollectParameters(&m_nIp, 1); + CRecordDataForChase::RemoveCarFromChase(ScriptParams[0]); + return 0; + case COMMAND_IS_FRENCH_GAME: + UpdateCompareFlag(CGame::frenchGame); + return 0; + case COMMAND_IS_GERMAN_GAME: + UpdateCompareFlag(CGame::germanGame); + return 0; + case COMMAND_CLEAR_MISSION_AUDIO: + DMAudio.ClearMissionAudio(); + return 0; + case COMMAND_SET_FADE_IN_AFTER_NEXT_ARREST: + CollectParameters(&m_nIp, 1); + CRestart::bFadeInAfterNextArrest = !!ScriptParams[0]; + return 0; + case COMMAND_SET_FADE_IN_AFTER_NEXT_DEATH: + CollectParameters(&m_nIp, 1); + CRestart::bFadeInAfterNextDeath = !!ScriptParams[0]; + return 0; + case COMMAND_SET_GANG_PED_MODEL_PREFERENCE: + CollectParameters(&m_nIp, 2); + CGangs::SetGangPedModelOverride(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_SET_CHAR_USE_PEDNODE_SEEK: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + if (ScriptParams[1]) + pPed->m_pNextPathNode = nil; + pPed->bUsePedNodeSeek = !!ScriptParams[1]; + return 0; + } + case COMMAND_SWITCH_VEHICLE_WEAPONS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->bGunSwitchedOff = !ScriptParams[1]; + return 0; + } + case COMMAND_SET_GET_OUT_OF_JAIL_FREE: + CollectParameters(&m_nIp, 2); + CWorld::Players[ScriptParams[0]].m_bGetOutOfJailFree = !!ScriptParams[1]; + return 0; + case COMMAND_SET_FREE_HEALTH_CARE: + CollectParameters(&m_nIp, 2); + CWorld::Players[ScriptParams[0]].m_bGetOutOfHospitalFree = !!ScriptParams[1]; + return 0; + case COMMAND_IS_CAR_DOOR_CLOSED: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + UpdateCompareFlag(!pVehicle->IsDoorMissing((eDoors)ScriptParams[1]) && pVehicle->IsDoorClosed((eDoors)ScriptParams[1])); + return 0; + } + case COMMAND_LOAD_AND_LAUNCH_MISSION: + return 0; + case COMMAND_LOAD_AND_LAUNCH_MISSION_INTERNAL: + { + CollectParameters(&m_nIp, 1); +#ifdef MISSION_REPLAY + missionRetryScriptIndex = ScriptParams[0]; + if (missionRetryScriptIndex == 19) + CStats::LastMissionPassedName[0] = '\0'; +#endif + CTimer::Suspend(); + int offset = CTheScripts::MultiScriptArray[ScriptParams[0]]; + CFileMgr::ChangeDir("\\"); + int handle = CFileMgr::OpenFile("data\\main.scm", "rb"); + CFileMgr::Seek(handle, offset, 0); + CFileMgr::Read(handle, (const char*)&CTheScripts::ScriptSpace[SIZE_MAIN_SCRIPT], SIZE_MISSION_SCRIPT); + CFileMgr::CloseFile(handle); + CRunningScript* pMissionScript = CTheScripts::StartNewScript(SIZE_MAIN_SCRIPT); + CTimer::Resume(); + pMissionScript->m_bIsMissionScript = true; + pMissionScript->m_bMissionFlag = true; + CTheScripts::bAlreadyRunningAMissionScript = true; + return 0; + } + case COMMAND_SET_OBJECT_DRAW_LAST: + { + CollectParameters(&m_nIp, 2); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + pObject->bDrawLast = !!ScriptParams[1]; + return 0; + } + case COMMAND_GET_AMMO_IN_PLAYER_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CWeapon* pWeaponSlot = &pPed->m_weapons[ScriptParams[1]]; + if (pWeaponSlot->m_eWeaponType == (eWeaponType)ScriptParams[1]) + ScriptParams[0] = pWeaponSlot->m_nAmmoTotal; + else + ScriptParams[0] = 0; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_AMMO_IN_CHAR_WEAPON: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CWeapon* pWeaponSlot = &pPed->m_weapons[ScriptParams[1]]; + if (pWeaponSlot->m_eWeaponType == (eWeaponType)ScriptParams[1]) + ScriptParams[0] = pWeaponSlot->m_nAmmoTotal; + else + ScriptParams[0] = 0; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_REGISTER_KILL_FRENZY_PASSED: + CStats::AnotherKillFrenzyPassed(); + return 0; + case COMMAND_SET_CHAR_SAY: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + switch (ScriptParams[1]) { + case SCRIPT_SOUND_CHUNKY_RUN_SHOUT: + pPed->Say(SOUND_PED_FLEE_RUN); + break; + case SCRIPT_SOUND_SECURITY_GUARD_AWAY_SHOUT: + pPed->Say(SOUND_PED_FLEE_RUN); + break; + case SCRIPT_SOUND_SWAT_PED_SHOUT: + pPed->Say(SOUND_PED_PURSUIT_SWAT); + break; + case SCRIPT_SOUND_AMMUNATION_CHAT_1: + pPed->Say(SOUND_AMMUNATION_WELCOME_1); + break; + case SCRIPT_SOUND_AMMUNATION_CHAT_2: + pPed->Say(SOUND_AMMUNATION_WELCOME_2); + break; + case SCRIPT_SOUND_AMMUNATION_CHAT_3: + pPed->Say(SOUND_AMMUNATION_WELCOME_3); + break; + default: + break; + } + return 0; + } + case COMMAND_SET_NEAR_CLIP: + CollectParameters(&m_nIp, 1); + TheCamera.SetNearClipScript(*(float*)&ScriptParams[0]); + return 0; + case COMMAND_SET_RADIO_CHANNEL: + CollectParameters(&m_nIp, 2); + DMAudio.SetRadioChannel(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_OVERRIDE_HOSPITAL_LEVEL: + CollectParameters(&m_nIp, 1); + CRestart::OverrideHospitalLevel = ScriptParams[0]; + return 0; + case COMMAND_OVERRIDE_POLICE_STATION_LEVEL: + CollectParameters(&m_nIp, 1); + CRestart::OverridePoliceStationLevel = ScriptParams[0]; + return 0; + case COMMAND_FORCE_RAIN: + CollectParameters(&m_nIp, 1); + CWeather::bScriptsForceRain = !!ScriptParams[0]; + return 0; + case COMMAND_DOES_GARAGE_CONTAIN_CAR: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pVehicle); + UpdateCompareFlag(CGarages::IsThisCarWithinGarageArea(ScriptParams[0], pVehicle)); + return 0; + } + case COMMAND_SET_CAR_TRACTION: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + float fTraction = *(float*)&ScriptParams[1]; + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR || pVehicle->m_vehType == VEHICLE_TYPE_BIKE); + if (pVehicle->m_vehType == VEHICLE_TYPE_CAR) + ((CAutomobile*)pVehicle)->m_fTraction = fTraction; + else + // this is certainly not a boat, trane, heli or plane field + //((CBike*)pVehicle)->m_fTraction = fTraction; + *(float*)(((char*)pVehicle) + 1088) = fTraction; + return 0; + } + case COMMAND_ARE_MEASUREMENTS_IN_METRES: +#ifdef USE_MEASUREMENTS_IN_METERS + UpdateCompareFlag(true); +#else + UpdateCompareFlag(false) +#endif + return 0; + case COMMAND_CONVERT_METRES_TO_FEET: + { + CollectParameters(&m_nIp, 1); + float fMeterValue = *(float*)&ScriptParams[0]; + float fFeetValue = fMeterValue / METERS_IN_FOOT; + *(float*)&ScriptParams[0] = fFeetValue; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_MARK_ROADS_BETWEEN_LEVELS: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.MarkRoadsBetweenLevelsInArea(infX, supX, infY, supY, infZ, supZ); + return 0; + } + case COMMAND_MARK_PED_ROADS_BETWEEN_LEVELS: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + ThePaths.PedMarkRoadsBetweenLevelsInArea(infX, supX, infY, supY, infZ, supZ); + return 0; + } + case COMMAND_SET_CAR_AVOID_LEVEL_TRANSITIONS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->AutoPilot.m_bStayInCurrentLevel = !!ScriptParams[1]; + return 0; + } + case COMMAND_SET_CHAR_AVOID_LEVEL_TRANSITIONS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pPed); + // not implemented + return 0; + } + case COMMAND_IS_THREAT_FOR_PED_TYPE: + CollectParameters(&m_nIp, 2); + UpdateCompareFlag(CPedType::IsThreat(ScriptParams[0], ScriptParams[1])); + return 0; + case COMMAND_CLEAR_AREA_OF_CHARS: + { + CollectParameters(&m_nIp, 6); + float infX = *(float*)&ScriptParams[0]; + float infY = *(float*)&ScriptParams[1]; + float infZ = *(float*)&ScriptParams[2]; + float supX = *(float*)&ScriptParams[3]; + float supY = *(float*)&ScriptParams[4]; + float supZ = *(float*)&ScriptParams[5]; + if (infX > supX) { + infX = *(float*)&ScriptParams[3]; + supX = *(float*)&ScriptParams[0]; + } + if (infY > supY) { + infY = *(float*)&ScriptParams[4]; + supY = *(float*)&ScriptParams[1]; + } + if (infZ > supZ) { + infZ = *(float*)&ScriptParams[5]; + supZ = *(float*)&ScriptParams[2]; + } + CWorld::ClearPedsFromArea(infX, infY, infZ, supX, supY, supZ); + return 0; + } + case COMMAND_SET_TOTAL_NUMBER_OF_MISSIONS: + CollectParameters(&m_nIp, 1); + CStats::SetTotalNumberMissions(ScriptParams[0]); + return 0; + case COMMAND_CONVERT_METRES_TO_FEET_INT: + CollectParameters(&m_nIp, 1); + ScriptParams[0] *= FEET_IN_METER; + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_REGISTER_FASTEST_TIME: + CollectParameters(&m_nIp, 2); + CStats::RegisterFastestTime(ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_REGISTER_HIGHEST_SCORE: + CollectParameters(&m_nIp, 2); + CStats::RegisterHighestScore(ScriptParams[0], ScriptParams[1]); + return 0; + //case COMMAND_WARP_CHAR_INTO_CAR_AS_PASSENGER: + //case COMMAND_IS_CAR_PASSENGER_SEAT_FREE: + case COMMAND_GET_CHAR_IN_CAR_PASSENGER_SEAT: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(ScriptParams[1] >= 0 && ScriptParams[1] < ARRAY_SIZE(pVehicle->pPassengers)); + CPed* pPassenger = pVehicle->pPassengers[ScriptParams[1]]; + ScriptParams[0] = CPools::GetPedPool()->GetIndex(pPassenger); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CHAR_IS_CHRIS_CRIMINAL: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bChrisCriminal = !!ScriptParams[1]; + return 0; + } + case COMMAND_START_CREDITS: + CCredits::Start(); + return 0; + case COMMAND_STOP_CREDITS: + CCredits::Stop(); + return 0; + case COMMAND_ARE_CREDITS_FINISHED: + UpdateCompareFlag(CCredits::AreCreditsDone()); + return 0; + case COMMAND_CREATE_SINGLE_PARTICLE: + CollectParameters(&m_nIp, 8); + CParticle::AddParticle((tParticleType)ScriptParams[0], *(CVector*)&ScriptParams[1], + *(CVector*)&ScriptParams[4], nil, *(float*)&ScriptParams[7], 0, 0, 0, 0); + return 0; + case COMMAND_SET_CHAR_IGNORE_LEVEL_TRANSITIONS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + if (ScriptParams[1]) + pPed->m_nZoneLevel = LEVEL_IGNORE; + else + pPed->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pPed->GetPosition()); + return 0; + } + case COMMAND_GET_CHASE_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CRecordDataForChase::TurnChaseCarIntoScriptCar(ScriptParams[0]); + ScriptParams[0] = CPools::GetVehiclePool()->GetIndex(pVehicle); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CAR); + return 0; + } + case COMMAND_START_BOAT_FOAM_ANIMATION: + CSpecialParticleStuff::StartBoatFoamAnimation(); + return 0; + case COMMAND_UPDATE_BOAT_FOAM_ANIMATION: + { + CollectParameters(&m_nIp, 1); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CSpecialParticleStuff::UpdateBoatFoamAnimation(&pObject->GetMatrix()); + return 0; + } + case COMMAND_SET_MUSIC_DOES_FADE: + CollectParameters(&m_nIp, 1); + TheCamera.m_bIgnoreFadingStuffForMusic = (ScriptParams[0] == 0); + return 0; + case COMMAND_SET_INTRO_IS_PLAYING: + CollectParameters(&m_nIp, 1); + if (ScriptParams[0]) { + CGame::playingIntro = true; + CStreaming::RemoveCurrentZonesModels(); + } else { + CGame::playingIntro = false; + DMAudio.ChangeMusicMode(MUSICMODE_GAME); + int mi; + CModelInfo::GetModelInfo("bridgefukb", &mi); + CStreaming::RequestModel(mi, STREAMFLAGS_DEPENDENCY); + CStreaming::LoadAllRequestedModels(false); + } + return 0; + case COMMAND_SET_PLAYER_HOOKER: + { + CollectParameters(&m_nIp, 2); + CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; + if (ScriptParams[1] < 0) { + pPlayerInfo->m_pHooker = nil; + pPlayerInfo->m_nNextSexFrequencyUpdateTime = 0; + pPlayerInfo->m_nNextSexMoneyUpdateTime = 0; + } else { + CPed* pHooker = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pHooker); + pPlayerInfo->m_pHooker = (CCivilianPed*)pHooker; + pPlayerInfo->m_nNextSexFrequencyUpdateTime = CTimer::GetTimeInMilliseconds() + 1000; + pPlayerInfo->m_nNextSexMoneyUpdateTime = CTimer::GetTimeInMilliseconds() + 3000; + } + return 0; + } + case COMMAND_PLAY_END_OF_GAME_TUNE: + DMAudio.PlayPreloadedCutSceneMusic(); + return 0; + case COMMAND_STOP_END_OF_GAME_TUNE: + DMAudio.StopCutSceneMusic(); + DMAudio.ChangeMusicMode(MUSICMODE_GAME); + return 0; + case COMMAND_GET_CAR_MODEL: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + ScriptParams[0] = pVehicle->GetModelIndex(); + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_IS_PLAYER_SITTING_IN_CAR: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pVehicle); + UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING && pPed->m_pMyVehicle == pVehicle); + return 0; + } + case COMMAND_IS_PLAYER_SITTING_IN_ANY_CAR: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING); + return 0; + } + case COMMAND_SET_SCRIPT_FIRE_AUDIO: + CollectParameters(&m_nIp, 2); + gFireManager.SetScriptFireAudio(ScriptParams[0], !!ScriptParams[1]); + return 0; + case COMMAND_ARE_ANY_CAR_CHEATS_ACTIVATED: + UpdateCompareFlag(CVehicle::bAllDodosCheat || CVehicle::bCheat3); + return 0; + case COMMAND_SET_CHAR_SUFFERS_CRITICAL_HITS: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->bNoCriticalHits = (ScriptParams[0] == 0); + return 0; + } + case COMMAND_IS_PLAYER_LIFTING_A_PHONE: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + UpdateCompareFlag(pPed->GetPedState() == PED_MAKE_CALL); + return 0; + } + case COMMAND_IS_CHAR_SITTING_IN_CAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pVehicle); + UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING && pPed->m_pMyVehicle == pVehicle); + return 0; + } + case COMMAND_IS_CHAR_SITTING_IN_ANY_CAR: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(pPed->GetPedState() == PED_DRIVING); + return 0; + } + case COMMAND_IS_PLAYER_ON_FOOT: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + UpdateCompareFlag(!pPed->bInVehicle && pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && + pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER); + return 0; + } + case COMMAND_IS_CHAR_ON_FOOT: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(!pPed->bInVehicle && pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && + pPed->m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER); + return 0; + } +#ifndef GTA_PS2 + default: + script_assert(0); + } + return -1; +} + +int8 CRunningScript::ProcessCommands1100To1199(int32 command) +{ + char tmp[48]; + switch (command) { +#endif + case COMMAND_LOAD_COLLISION_WITH_SCREEN: + CollectParameters(&m_nIp, 1); + CTimer::Stop(); + CGame::currLevel = (eLevelName)ScriptParams[0]; + if (CGame::currLevel != CCollision::ms_collisionInMemory) { + ISLAND_LOADING_IS(LOW) + { + DMAudio.SetEffectsFadeVol(0); + CPad::StopPadsShaking(); + CCollision::LoadCollisionScreen(CGame::currLevel); + DMAudio.Service(); + } + CPopulation::DealWithZoneChange(CCollision::ms_collisionInMemory, CGame::currLevel, false); + + ISLAND_LOADING_IS(LOW) + { + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + } + CCollision::SortOutCollisionAfterLoad(); + + ISLAND_LOADING_ISNT(HIGH) + CStreaming::RequestIslands(CGame::currLevel); + + ISLAND_LOADING_IS(LOW) + CStreaming::RequestBigBuildings(CGame::currLevel); + + ISLAND_LOADING_ISNT(HIGH) + CStreaming::LoadAllRequestedModels(true); + + ISLAND_LOADING_IS(LOW) + DMAudio.SetEffectsFadeVol(127); + } + CTimer::Update(); + return 0; + case COMMAND_LOAD_SPLASH_SCREEN: + CTheScripts::ReadTextLabelFromScript(&m_nIp, tmp); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + tmp[i] = tolower(tmp[i]); + m_nIp += 8; + LoadSplash(tmp); + return 0; + case COMMAND_SET_CAR_IGNORE_LEVEL_TRANSITIONS: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + if (ScriptParams[1]) + pVehicle->m_nZoneLevel = LEVEL_IGNORE; + else + pVehicle->m_nZoneLevel = CTheZones::GetLevelFromPosition(&pVehicle->GetPosition()); + return 0; + } + case COMMAND_MAKE_CRAIGS_CAR_A_BIT_STRONGER: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + script_assert(pVehicle->m_vehType == VEHICLE_TYPE_CAR); + CAutomobile* pCar = (CAutomobile*)pVehicle; + pCar->bMoreResistantToDamage = ScriptParams[1]; + return 0; + } + case COMMAND_SET_JAMES_CAR_ON_PATH_TO_PLAYER: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CCarCtrl::JoinCarWithRoadSystemGotoCoors(pVehicle, FindPlayerCoors(), false); + return 0; + } + case COMMAND_LOAD_END_OF_GAME_TUNE: + DMAudio.ChangeMusicMode(MUSICMODE_CUTSCENE); + printf("Start preload end of game audio\n"); + DMAudio.PreloadCutSceneMusic(STREAMED_SOUND_GAME_COMPLETED); + printf("End preload end of game audio\n"); + return 0; + case COMMAND_ENABLE_PLAYER_CONTROL_CAMERA: + CPad::GetPad(0)->SetEnablePlayerControls(PLAYERCONTROL_CAMERA); + return 0; +#ifndef GTA_PS2 + // To be precise, on PS2 previous handlers were in 1000-1099 function + // These are "beta" VC commands (with bugs) + case COMMAND_SET_OBJECT_ROTATION: + { + CollectParameters(&m_nIp, 4); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CWorld::Remove(pObject); + pObject->SetOrientation( + DEGTORAD(*(float*)&ScriptParams[1]), + DEGTORAD(*(float*)&ScriptParams[2]), + DEGTORAD(*(float*)&ScriptParams[3])); + pObject->GetMatrix().UpdateRW(); + pObject->UpdateRwFrame(); + CWorld::Add(pObject); + return 0; + } + case COMMAND_GET_DEBUG_CAMERA_COORDINATES: + *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Source; + StoreParameters(&m_nIp, 3); + return 0; + case COMMAND_GET_DEBUG_CAMERA_FRONT_VECTOR: + *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Front; + StoreParameters(&m_nIp, 3); + return 0; + case COMMAND_IS_PLAYER_TARGETTING_ANY_CHAR: + { + CollectParameters(&m_nIp, 1); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CEntity* pTarget = pPed->m_pPointGunAt; + UpdateCompareFlag(pTarget && pTarget->IsPed()); + return 0; + } + case COMMAND_IS_PLAYER_TARGETTING_CHAR: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CPed* pTestedPed = CPools::GetPedPool()->GetAt(ScriptParams[1]); + script_assert(pTestedPed); + CEntity* pTarget = pPed->m_pPointGunAt; + UpdateCompareFlag(pTarget && pTarget->IsPed() && pTarget == pTestedPed); + return 0; + } + case COMMAND_IS_PLAYER_TARGETTING_OBJECT: + { + CollectParameters(&m_nIp, 2); + CPlayerPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + CObject* pTestedObject = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + script_assert(pTestedObject); + CEntity* pTarget = pPed->m_pPointGunAt; + UpdateCompareFlag(pTarget && pTarget->IsObject() && pTarget == pTestedObject); + return 0; + } + case COMMAND_TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME: + { + CTheScripts::ReadTextLabelFromScript(&m_nIp, tmp); + for (int i = 0; i < KEY_LENGTH_IN_SCRIPT; i++) + tmp[i] = tolower(tmp[i]); + m_nIp += 8; + CRunningScript* pScript = CTheScripts::pActiveScripts; + while (pScript) { + CRunningScript* pNext = pScript->next; + if (strcmp(pScript->m_abScriptName, tmp) == 0) { + pScript->RemoveScriptFromList(&CTheScripts::pActiveScripts); + pScript->AddScriptToList(&CTheScripts::pIdleScripts); + } + pScript = pNext; + } + return 0; + } + case COMMAND_DISPLAY_TEXT_WITH_NUMBER: + { + CollectParameters(&m_nIp, 2); + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtX = *(float*)&ScriptParams[0]; + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtY = *(float*)&ScriptParams[1]; + CollectParameters(&m_nIp, 1); + CMessages::InsertNumberInString(text, ScriptParams[0], -1, -1, -1, -1, -1, + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame++].m_Text); + return 0; + } + case COMMAND_DISPLAY_TEXT_WITH_2_NUMBERS: + { + CollectParameters(&m_nIp, 2); + wchar* text = CTheScripts::GetTextByKeyFromScript(&m_nIp); + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtX = *(float*)&ScriptParams[0]; + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame].m_fAtY = *(float*)&ScriptParams[1]; + CollectParameters(&m_nIp, 2); + CMessages::InsertNumberInString(text, ScriptParams[0], ScriptParams[1], -1, -1, -1, -1, + CTheScripts::IntroTextLines[CTheScripts::NumberOfIntroTextLinesThisFrame++].m_Text); + return 0; + } + case COMMAND_FAIL_CURRENT_MISSION: + CTheScripts::FailCurrentMission = 2; + return 0; + case COMMAND_GET_CLOSEST_OBJECT_OF_TYPE: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float range = *(float*)&ScriptParams[3]; + int mi = ScriptParams[4] < 0 ? CTheScripts::UsedObjectArray[-ScriptParams[4]].index : ScriptParams[4]; + int16 total; + CEntity* apEntities[16]; + CWorld::FindObjectsOfTypeInRange(mi, pos, range, true, &total, 16, apEntities, false, false, false, true, true); + CEntity* pClosestEntity = nil; + float min_dist = 2.0f * range; + for (int i = 0; i < total; i++) { + float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); + if (dist < min_dist) { + min_dist = dist; + pClosestEntity = apEntities[i]; + } + } + if (pClosestEntity && pClosestEntity->IsDummy()) { + CPopulation::ConvertToRealObject((CDummyObject*)pClosestEntity); + CWorld::FindObjectsOfTypeInRange(mi, pos, range, true, &total, 16, apEntities, false, false, false, true, true); + pClosestEntity = nil; + float min_dist = 2.0f * range; + for (int i = 0; i < total; i++) { + float dist = (apEntities[i]->GetPosition() - pos).Magnitude(); + if (dist < min_dist) { + min_dist = dist; + pClosestEntity = apEntities[i]; + } + } + if (pClosestEntity->IsDummy()) + pClosestEntity = nil; + } + if (pClosestEntity) { + script_assert(pClosestEntity->IsObject()); + CObject* pObject = (CObject*)pClosestEntity; + pObject->ObjectCreatedBy = MISSION_OBJECT; + ScriptParams[0] = CPools::GetObjectPool()->GetIndex(pObject); + } else { + ScriptParams[0] = -1; + } + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_PLACE_OBJECT_RELATIVE_TO_OBJECT: + { + CollectParameters(&m_nIp, 5); + CObject* pObject = CPools::GetObjectPool()->GetAt(ScriptParams[0]); + script_assert(pObject); + CObject* pTarget = CPools::GetObjectPool()->GetAt(ScriptParams[1]); + script_assert(pTarget); + CVector offset = *(CVector*)&ScriptParams[2]; + CPhysical::PlacePhysicalRelativeToOtherPhysical(pTarget, pObject, offset); + return 0; + } + case COMMAND_SET_ALL_OCCUPANTS_OF_CAR_LEAVE_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + if (pVehicle->pDriver) { + pVehicle->pDriver->bScriptObjectiveCompleted = false; + pVehicle->pDriver->SetObjective(OBJECTIVE_LEAVE_CAR, pVehicle); + } + for (int i = 0; i < ARRAY_SIZE(pVehicle->pPassengers); i++) + { + if (pVehicle->pPassengers[i]) { + pVehicle->pPassengers[i]->bScriptObjectiveCompleted = false; + pVehicle->pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_CAR, pVehicle); + } + } + return 0; + } + case COMMAND_SET_INTERPOLATION_PARAMETERS: + CollectParameters(&m_nIp, 2); + TheCamera.SetParametersForScriptInterpolation(*(float*)&ScriptParams[0], 50.0f - *(float*)&ScriptParams[0], ScriptParams[1]); + return 0; + case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_TOWARDS_POINT: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float destX = *(float*)&ScriptParams[3]; + float destY = *(float*)&ScriptParams[4]; + int32 nid = ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f, true, true); + CPathNode* pNode = &ThePaths.m_pathNodes[nid]; + *(CVector*)&ScriptParams[0] = pNode->GetPosition(); + *(float*)&ScriptParams[3] = ThePaths.FindNodeOrientationForCarPlacementFacingDestination(nid, destX, destY, true); + StoreParameters(&m_nIp, 4); + return 0; + } + case COMMAND_GET_CLOSEST_CAR_NODE_WITH_HEADING_AWAY_POINT: + { + CollectParameters(&m_nIp, 5); + CVector pos = *(CVector*)&ScriptParams[0]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + float destX = *(float*)&ScriptParams[3]; + float destY = *(float*)&ScriptParams[4]; + int32 nid = ThePaths.FindNodeClosestToCoors(pos, 0, 999999.9f, true, true); + CPathNode* pNode = &ThePaths.m_pathNodes[nid]; + *(CVector*)&ScriptParams[0] = pNode->GetPosition(); + *(float*)&ScriptParams[3] = ThePaths.FindNodeOrientationForCarPlacementFacingDestination(nid, destX, destY, false); + StoreParameters(&m_nIp, 4); + return 0; + } + case COMMAND_GET_DEBUG_CAMERA_POINT_AT: + *(CVector*)&ScriptParams[0] = TheCamera.Cams[2].Source + TheCamera.Cams[2].Front; + StoreParameters(&m_nIp, 3); + return 0; + case COMMAND_ATTACH_CHAR_TO_CAR: + // empty implementation + return 0; + case COMMAND_DETACH_CHAR_FROM_CAR: + // empty implementation + return 0; + case COMMAND_SET_CAR_CHANGE_LANE: // for some reason changed in SA + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->AutoPilot.m_bStayInFastLane = !ScriptParams[1]; + return 0; + } + case COMMAND_CLEAR_CHAR_LAST_WEAPON_DAMAGE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + pPed->m_lastWepDam = -1; + return 0; + } + case COMMAND_CLEAR_CAR_LAST_WEAPON_DAMAGE: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + pVehicle->m_nLastWeaponDamage = -1; + return 0; + } + case COMMAND_GET_RANDOM_COP_IN_AREA: + { + CollectParameters(&m_nIp, 4); + int ped_handle = -1; + CVector pos = FindPlayerCoors(); + float x1 = *(float*)&ScriptParams[0]; + float y1 = *(float*)&ScriptParams[1]; + float x2 = *(float*)&ScriptParams[2]; + float y2 = *(float*)&ScriptParams[3]; + int i = CPools::GetPedPool()->GetSize(); + while (--i && ped_handle == -1) { + CPed* pPed = CPools::GetPedPool()->GetSlot(i); + if (!pPed) + continue; + if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) + continue; + if (pPed->m_nPedType != PEDTYPE_COP) + continue; + if (pPed->CharCreatedBy != RANDOM_CHAR) + continue; + if (!pPed->IsPedInControl() && pPed->GetPedState() != PED_DRIVING) + continue; + if (pPed->bRemoveFromWorld) + continue; + if (pPed->bFadeOut) + continue; + if (pPed->bIsLeader || pPed->m_leader) + continue; + if (!pPed->IsWithinArea(x1, y1, x2, y2)) + continue; + if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) + continue; + if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) + continue; + ped_handle = CPools::GetPedPool()->GetIndex(pPed); + CTheScripts::LastRandomPedId = ped_handle; + pPed->CharCreatedBy = MISSION_CHAR; + pPed->bRespondsToThreats = false; + ++CPopulation::ms_nTotalMissionPeds; + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + } + ScriptParams[0] = ped_handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_RANDOM_COP_IN_ZONE: + { + char zone[KEY_LENGTH_IN_SCRIPT]; + strncpy(zone, (const char*)&CTheScripts::ScriptSpace[m_nIp], KEY_LENGTH_IN_SCRIPT); + int nZone = CTheZones::FindZoneByLabelAndReturnIndex(zone); + if (nZone != -1) + m_nIp += KEY_LENGTH_IN_SCRIPT; + CZone* pZone = CTheZones::GetZone(nZone); + int ped_handle = -1; + CVector pos = FindPlayerCoors(); + int i = CPools::GetPedPool()->GetSize(); + while (--i && ped_handle == -1) { + CPed* pPed = CPools::GetPedPool()->GetSlot(i); + if (!pPed) + continue; + if (CTheScripts::LastRandomPedId == CPools::GetPedPool()->GetIndex(pPed)) + continue; + if (pPed->m_nPedType != PEDTYPE_COP) + continue; + if (pPed->CharCreatedBy != RANDOM_CHAR) + continue; + if (!pPed->IsPedInControl() && pPed->GetPedState() != PED_DRIVING) + continue; + if (pPed->bRemoveFromWorld) + continue; + if (pPed->bFadeOut) + continue; + if (pPed->bIsLeader || pPed->m_leader) + continue; + if (!CTheZones::PointLiesWithinZone(&pPed->GetPosition(), pZone)) + continue; + if (pos.z - PED_FIND_Z_OFFSET > pPed->GetPosition().z) + continue; + if (pos.z + PED_FIND_Z_OFFSET < pPed->GetPosition().z) + continue; + ped_handle = CPools::GetPedPool()->GetIndex(pPed); + CTheScripts::LastRandomPedId = ped_handle; + pPed->CharCreatedBy = MISSION_CHAR; + pPed->bRespondsToThreats = false; + ++CPopulation::ms_nTotalMissionPeds; + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ped_handle, CLEANUP_CHAR); + } + ScriptParams[0] = ped_handle; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_SET_CHAR_OBJ_FLEE_CAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[1]); + script_assert(pVehicle); + pPed->bScriptObjectiveCompleted = false; + pPed->SetObjective(OBJECTIVE_FLEE_CAR, pVehicle); + return 0; + } + case COMMAND_GET_DRIVER_OF_CAR: + { + CollectParameters(&m_nIp, 1); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + CPed* pDriver = pVehicle->pDriver; + if (pDriver) + ScriptParams[0] = CPools::GetPedPool()->GetIndex(pDriver); + else + ScriptParams[0] = -1; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_NUMBER_OF_FOLLOWERS: + { + CollectParameters(&m_nIp, 1); + CPed* pLeader = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pLeader); + int total = 0; + int i = CPools::GetPedPool()->GetSize(); + while (--i) { + CPed* pPed = CPools::GetPedPool()->GetSlot(i); + if (!pPed) + continue; + if (pPed->m_leader == pLeader) + total++; + } + ScriptParams[0] = total; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GIVE_REMOTE_CONTROLLED_MODEL_TO_PLAYER: + { + CollectParameters(&m_nIp, 6); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= MAP_Z_LOW_LIMIT) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + CRemote::GivePlayerRemoteControlledCar(pos.x, pos.y, pos.z, DEGTORAD(*(float*)&ScriptParams[4]), ScriptParams[5]); + return 0; + } + case COMMAND_GET_CURRENT_PLAYER_WEAPON: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + ScriptParams[0] = pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_GET_CURRENT_CHAR_WEAPON: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + ScriptParams[0] = pPed->m_weapons[pPed->m_currentWeapon].m_eWeaponType; + StoreParameters(&m_nIp, 1); + return 0; + } + case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_2D: + case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_2D: + case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_2D: + case COMMAND_LOCATE_CHAR_ANY_MEANS_OBJECT_3D: + case COMMAND_LOCATE_CHAR_ON_FOOT_OBJECT_3D: + case COMMAND_LOCATE_CHAR_IN_CAR_OBJECT_3D: + LocateCharObjectCommand(command, &m_nIp); + return 0; + case COMMAND_SET_CAR_HANDBRAKE_TURN_LEFT: // this will be changed in final VC version to a more general SET_TEMP_ACTION + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKETURNLEFT; + pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; + return 0; + } + case COMMAND_SET_CAR_HANDBRAKE_TURN_RIGHT: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKETURNRIGHT; + pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; + return 0; + } + case COMMAND_SET_CAR_HANDBRAKE_STOP: + { + CollectParameters(&m_nIp, 2); + CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); + script_assert(pVehicle); + pVehicle->AutoPilot.m_nTempAction = TEMPACT_HANDBRAKESTRAIGHT; + pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + ScriptParams[1]; + return 0; + } + case COMMAND_IS_CHAR_ON_ANY_BIKE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(pPed->bInVehicle&& pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE); + return 0; + } + case COMMAND_LOCATE_SNIPER_BULLET_2D: + case COMMAND_LOCATE_SNIPER_BULLET_3D: + LocateSniperBulletCommand(command, &m_nIp); + return 0; + case COMMAND_GET_NUMBER_OF_SEATS_IN_MODEL: + CollectParameters(&m_nIp, 1); + ScriptParams[0] = CVehicleModelInfo::GetMaximumNumberOfPassengersFromNumberOfDoors(ScriptParams[0]) + 1; + StoreParameters(&m_nIp, 1); + return 0; + case COMMAND_IS_PLAYER_ON_ANY_BIKE: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CWorld::Players[ScriptParams[0]].m_pPed; + script_assert(pPed); + UpdateCompareFlag(pPed->bInVehicle && pPed->m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE); + return 0; + } + case COMMAND_IS_CHAR_LYING_DOWN: + { + CollectParameters(&m_nIp, 1); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + UpdateCompareFlag(pPed->bFallenDown); + return 0; + } + case COMMAND_CAN_CHAR_SEE_DEAD_CHAR: + { + CollectParameters(&m_nIp, 2); + CPed* pPed = CPools::GetPedPool()->GetAt(ScriptParams[0]); + script_assert(pPed); + int pedtype = ScriptParams[1]; + bool can = false; + for (int i = 0; i < pPed->m_numNearPeds; i++) { + CPed* pTestPed = pPed->m_nearPeds[i]; + if (pTestPed->m_fHealth <= 0.0f && pTestPed->m_nPedType == pedtype && pPed->OurPedCanSeeThisOne(pTestPed)) + can = true; + } + UpdateCompareFlag(can); + return 0; + } + case COMMAND_SET_ENTER_CAR_RANGE_MULTIPLIER: + CollectParameters(&m_nIp, 1); +#ifdef FIX_BUGS + CPed::nEnterCarRangeMultiplier = *(float*)&ScriptParams[0]; +#else + CPed::nEnterCarRangeMultiplier = (float)ScriptParams[0]; +#endif + return 0; +#endif +#ifndef GTA3_1_1_PATCH + case COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER: + CollectParameters(&m_nIp, 1); +#ifdef FIX_BUGS + CPed::nThreatReactionRangeMultiplier = *(float*)&ScriptParams[0]; +#else + CPed::nThreatReactionRangeMultiplier = (float)ScriptParams[0]; +#endif + return 0; +#endif + default: + script_assert(0); + } + return -1; +} From 70d8bdc0879c341f2d020544ef3b807bdee89833 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 24 Nov 2020 15:20:41 +0100 Subject: [PATCH 081/129] rename badly named camera variable --- src/core/Camera.cpp | 6 +++--- src/core/Camera.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 13d03213..56225fed 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -123,7 +123,7 @@ CCamera::Init(void) Cams[0].Mode = CCam::MODE_FOLLOWPED; Cams[1].Mode = CCam::MODE_FOLLOWPED; unknown = 0; - m_bJustJumpedOutOf1stPersonBecauseOfTarget = false; + m_bUnknown = false; ClearPlayerWeaponMode(); m_bInATunnelAndABigVehicle = false; m_iModeObbeCamIsInForCar = OBBE_INVALID; @@ -3398,10 +3398,10 @@ CCamera::Fade(float timeout, int16 direction) m_fTimeToFadeMusic = timeout; m_uiFadeTimeStartedMusic = CTimer::GetTimeInMilliseconds(); // Not on PS2 - if(!m_bJustJumpedOutOf1stPersonBecauseOfTarget && m_iMusicFadingDirection == FADE_OUT){ + if(!m_bUnknown && m_iMusicFadingDirection == FADE_OUT){ unknown++; if(unknown >= 2){ - m_bJustJumpedOutOf1stPersonBecauseOfTarget = true; + m_bUnknown = true; unknown = 0; }else m_bMoveCamToAvoidGeom = true; diff --git a/src/core/Camera.h b/src/core/Camera.h index dd78d952..0797db9b 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -348,7 +348,7 @@ public: bool m_bcutsceneFinished; bool m_bCullZoneChecksOn; bool m_bFirstPersonBeingUsed; - bool m_bJustJumpedOutOf1stPersonBecauseOfTarget; + bool m_bUnknown; bool m_bIdleOn; bool m_bInATunnelAndABigVehicle; bool m_bInitialNodeFound; From 88baa9ce5f22a788a1033040040185001a87f922 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 25 Nov 2020 20:03:44 +0100 Subject: [PATCH 082/129] implemented CMemoryHeap, not used or tested yet --- src/rw/MemoryHeap.cpp | 548 ++++++++++++++++++++++++++++++++++++++++++ src/rw/MemoryHeap.h | 188 +++++++++++++++ 2 files changed, 736 insertions(+) create mode 100644 src/rw/MemoryHeap.cpp create mode 100644 src/rw/MemoryHeap.h diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp new file mode 100644 index 00000000..d613a708 --- /dev/null +++ b/src/rw/MemoryHeap.cpp @@ -0,0 +1,548 @@ +#include "common.h" +#include "main.h" +#include "FileMgr.h" +#include "Timer.h" +#include "ModelInfo.h" +#include "Streaming.h" +#include "FileLoader.h" +#include "MemoryHeap.h" + +#ifdef USE_CUSTOM_ALLOCATOR + +#define MEMORYHEAP_ASSERT(cond) { if (!(cond)) { printf("ASSERT File:%s Line:%d\n", __FILE__, __LINE__); exit(1); } } +#define MEMORYHEAP_ASSERT_MESSAGE(cond, message) { if (!(cond)) { printf("ASSERT File:%s Line:%d:\n\t%s\n", __FILE__, __LINE__, message); exit(1); } } + +// registered pointers that we keep track of +void **gPtrList[4000]; +int32 numPtrs; +int32 gPosnInList; +// indices into the ptr list in here are free +CStack m_ptrListIndexStack; +// how much memory we've moved +uint32 memMoved; + +CMemoryHeap gMainHeap; + +void +CMemoryHeap::Init(uint32 total) +{ + MEMORYHEAP_ASSERT((total != 0xF) != 0); + + m_totalMemUsed = 0; + m_memUsed = nil; + m_currentMemID = MEMID_FREE; + m_blocksUsed = nil; + m_totalBlocksUsed = 0; + m_unkMemId = -1; + + uint8 *mem = (uint8*)malloc(total); + assert(((uintptr)mem & 0xF) == 0); + m_start = (HeapBlockDesc*)mem; + m_end = (HeapBlockDesc*)(mem + total - sizeof(HeapBlockDesc)); + m_start->m_memId = MEMID_FREE; + m_start->m_size = total - 2*sizeof(HeapBlockDesc); + m_end->m_memId = MEMID_ID1; + m_end->m_size = 0; + + m_freeList.m_last.m_size = INT_MAX; + m_freeList.Init(); + m_freeList.Insert(m_start); + + // TODO: figure out what these are and use sizeof + m_fixedSize[0].Init(0x10); + m_fixedSize[1].Init(0x20); + m_fixedSize[2].Init(0xE0); + m_fixedSize[3].Init(0x60); + m_fixedSize[4].Init(0x1C0); + m_fixedSize[5].Init(0x50); + + m_currentMemID = MEMID_FREE; // disable registration + m_memUsed = (uint32*)Malloc(NUM_MEMIDS * sizeof(uint32)); + m_blocksUsed = (uint32*)Malloc(NUM_MEMIDS * sizeof(uint32)); + RegisterMalloc(GetDescFromHeapPointer(m_memUsed)); + RegisterMalloc(GetDescFromHeapPointer(m_blocksUsed)); + + m_currentMemID = MEMID_ID1; + for(int i = 0; i < NUM_MEMIDS; i++){ + m_memUsed[i] = 0; + m_blocksUsed[i] = 0; + } +} + +void +CMemoryHeap::RegisterMalloc(HeapBlockDesc *block) +{ + block->m_memId = m_currentMemID; + if(m_currentMemID == MEMID_FREE) + return; + m_totalMemUsed += block->m_size + sizeof(HeapBlockDesc); + m_memUsed[m_currentMemID] += block->m_size + sizeof(HeapBlockDesc); + m_blocksUsed[m_currentMemID]++; + m_totalBlocksUsed++; +} + +void +CMemoryHeap::RegisterFree(HeapBlockDesc *block) +{ + if(block->m_memId == MEMID_FREE) + return; + m_totalMemUsed -= block->m_size + sizeof(HeapBlockDesc); + m_memUsed[m_currentMemID] -= block->m_size + sizeof(HeapBlockDesc); + m_blocksUsed[m_currentMemID]--; + m_totalBlocksUsed--; +} + +void* +CMemoryHeap::Malloc(uint32 size) +{ + static int recursion = 0; + + // weird way to round up + if((size & 0xF) != 0) + size = (size&~0xF) + 0x10; + + recursion++; + + // See if we can allocate from one of the fixed-size lists + for(int i = 0; i < NUM_FIXED_MEMBLOCKS; i++){ + CommonSize *list = &m_fixedSize[i]; + if(m_fixedSize[i].m_size == size){ + HeapBlockDesc *block = list->Malloc(); + if(block){ + RegisterMalloc(block); + recursion--; + return block->GetDataPointer(); + } + break; + } + } + + // now try the normal free list + HeapBlockDesc *next; + for(HeapBlockDesc *block = m_freeList.m_first.m_next; + block != &m_freeList.m_last; + block = next){ + MEMORYHEAP_ASSERT(block->m_memId == MEMID_FREE); + MEMORYHEAP_ASSERT_MESSAGE(block >= m_start && block <= m_end, "Block outside of memory"); + + // make sure block has maximum size + uint32 initialsize = block->m_size; + uint32 blocksize = CombineFreeBlocks(block); +#ifdef FIX_BUGS + // has to be done here because block can be moved + next = block->m_next; +#endif + if(initialsize != blocksize){ + block->RemoveHeapFreeBlock(); + HeapBlockDesc *pos = block->m_prev->FindSmallestFreeBlock(block->m_size); + block->InsertHeapFreeBlock(pos->m_prev); + } + if(block->m_size >= size){ + // got space to allocate from! + block->RemoveHeapFreeBlock(); + FillInBlockData(block, block->GetNextConsecutive(), size); + recursion--; + return block->GetDataPointer(); + } +#ifndef FIX_BUGS + next = block->m_next; +#endif + } + + // oh no, we're losing, try to free some stuff + static bool removeCollision = false; + static bool removeIslands = false; + static bool removeBigBuildings = false; + size_t initialMemoryUsed = CStreaming::ms_memoryUsed; + CStreaming::MakeSpaceFor(0xCFE800 - CStreaming::ms_memoryUsed); + if (recursion > 10) + CGame::TidyUpMemory(true, false); + else if (recursion > 6) + CGame::TidyUpMemory(false, true); + if (initialMemoryUsed == CStreaming::ms_memoryUsed && recursion > 11) { + if (!removeCollision && !CGame::playingIntro) { + CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_GENERIC); + removeCollision = true; + } + else if (!removeIslands && !CGame::playingIntro) { + CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + removeIslands = true; + } + else if (!removeBigBuildings) { + CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); + CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); + CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); + } + else { + LoadingScreen("NO MORE MEMORY", nil, nil); + LoadingScreen("NO MORE MEMORY", nil, nil); + } + CGame::TidyUpMemory(true, false); + } + void *mem = Malloc(size); + if (removeCollision) { + CTimer::Stop(); + // different on PS2 + CFileLoader::LoadCollisionFromDatFile(CCollision::ms_collisionInMemory); + removeCollision = false; + CTimer::Update(); + } + if (removeBigBuildings || removeIslands) { + CTimer::Stop(); + if (!CGame::playingIntro) + CStreaming::RequestBigBuildings(CGame::currLevel); + CStreaming::LoadAllRequestedModels(true); + removeBigBuildings = false; + removeIslands = false; + CTimer::Update(); + } + recursion--; + return mem; +} + +void* +CMemoryHeap::Realloc(void *ptr, uint32 size) +{ + if(ptr == nil) + return Malloc(size); + + // weird way to round up + if((size & 0xF) != 0) + size = (size&~0xF) + 0x10; + + HeapBlockDesc *block = GetDescFromHeapPointer(ptr); + +#ifdef FIX_BUGS + // better handling of size < block->m_size + if(size == 0){ + Free(ptr); + return nil; + } + if(block->m_size >= size){ + // shrink allocated block + RegisterFree(block); + PushMemId(block->m_memId); + FillInBlockData(block, block->GetNextConsecutive(), size); + PopMemId(); + return ptr; + } +#else + // not growing. just returning here is a bit cheap though + if(block->m_size >= size) + return ptr; +#endif + + // have to grow allocated block + HeapBlockDesc *next = block->GetNextConsecutive(); + MEMORYHEAP_ASSERT_MESSAGE(next >= m_start && next <= m_end, "Block outside of memory"); + if(next->m_memId == MEMID_FREE){ + // try to grow the current block + // make sure the next free block has maximum size + uint32 freespace = CombineFreeBlocks(next); + HeapBlockDesc *end = next->GetNextConsecutive(); + MEMORYHEAP_ASSERT_MESSAGE(end >= m_start && end <= m_end, "Block outside of memory"); + // why the sizeof here? + if(block->m_size + next->m_size + sizeof(HeapBlockDesc) >= size){ + // enough space to grow + next->RemoveHeapFreeBlock(); + RegisterFree(block); + PushMemId(block->m_memId); + FillInBlockData(block, next->GetNextConsecutive(), size); + PopMemId(); + return ptr; + } + } + + // can't grow the existing block, have to get a new one and copy + PushMemId(block->m_memId); + void *dst = Malloc(size); + PopMemId(); + memcpy(dst, ptr, block->m_size); + Free(ptr); + return dst; +} + +void +CMemoryHeap::Free(void *ptr) +{ + HeapBlockDesc *block = GetDescFromHeapPointer(ptr); + MEMORYHEAP_ASSERT_MESSAGE(block->m_memId != MEMID_FREE, "MemoryHeap corrupt"); + MEMORYHEAP_ASSERT(m_unkMemId == -1 || m_unkMemId == block->m_memId); + + RegisterFree(block); + CombineFreeBlocks(block); + FreeBlock(block); + if(block->m_ptrListIndex != -1){ + int32 idx = block->m_ptrListIndex; + gPtrList[idx] = nil; + m_ptrListIndexStack.push(idx); + } + block->m_ptrListIndex = -1; +} + +// allocate 'size' bytes from 'block' +void +CMemoryHeap::FillInBlockData(HeapBlockDesc *block, HeapBlockDesc *end, uint32 size) +{ + block->m_size = size; + block->m_ptrListIndex = -1; + HeapBlockDesc *remainder = block->GetNextConsecutive(); + MEMORYHEAP_ASSERT(remainder <= end); + + if(remainder < end-1){ + RegisterMalloc(block); + + // can fit another block in the remaining space + remainder->m_size = GetSizeBetweenBlocks(remainder, end); + remainder->m_memId = MEMID_FREE; + MEMORYHEAP_ASSERT(remainder->m_size != 0); + FreeBlock(remainder); + }else{ + // fully allocate this one + if(remainder < end) + // no gaps allowed + block->m_size = GetSizeBetweenBlocks(block, end); + RegisterMalloc(block); + } +} + +// Make sure free block has no other free blocks after it +uint32 +CMemoryHeap::CombineFreeBlocks(HeapBlockDesc *block) +{ + HeapBlockDesc *next = block->GetNextConsecutive(); + if(next->m_memId == MEMID_FREE) + return block->m_size; + // get rid of free blocks after this one and adjust size + for(; next->m_memId == MEMID_FREE; next = next->GetNextConsecutive()) + next->RemoveHeapFreeBlock(); + block->m_size = GetSizeBetweenBlocks(block, next); + return block->m_size; +} + +// Try to move all registered memory blocks into more optimal location +void +CMemoryHeap::TidyHeap(void) +{ + for(int i = 0; i < numPtrs; i++){ + if(gPtrList[i] == nil || *gPtrList[i] == nil) + continue; + HeapBlockDesc *newblock = WhereShouldMemoryMove(*gPtrList[i]); + if(newblock) + *gPtrList[i] = MoveHeapBlock(newblock, GetDescFromHeapPointer(*gPtrList[i])); + } +} + +// +void +CMemoryHeap::RegisterMemPointer(void *ptr) +{ + HeapBlockDesc *block = GetDescFromHeapPointer(*(void**)ptr); + + if(block->m_ptrListIndex != -1) + return; // already registered + + int index; + if(m_ptrListIndexStack.sp > 0){ + // re-use a previously free'd index + index = m_ptrListIndexStack.pop(); + }else{ + // have to find a new index + index = gPosnInList; + + void **pp = gPtrList[index]; + // we're replacing an old pointer here?? + if(pp && *pp && *pp != (void*)0xDDDDDDDD) + GetDescFromHeapPointer(*pp)->m_ptrListIndex = -1; + + gPosnInList++; + if(gPosnInList == 4000) + gPosnInList = 0; + if(numPtrs < 4000) + numPtrs++; + } + gPtrList[index] = (void**)ptr; + block->m_ptrListIndex = index; +} + +void* +CMemoryHeap::MoveMemory(void *ptr) +{ + HeapBlockDesc *newblock = WhereShouldMemoryMove(ptr); + if(newblock) + return MoveHeapBlock(newblock, GetDescFromHeapPointer(ptr)); + else + return ptr; +} + +HeapBlockDesc* +CMemoryHeap::WhereShouldMemoryMove(void *ptr) +{ + HeapBlockDesc *block = GetDescFromHeapPointer(ptr); + MEMORYHEAP_ASSERT(block->m_memId != MEMID_FREE); + + HeapBlockDesc *next = block->GetNextConsecutive(); + if(next->m_memId != MEMID_FREE) + return nil; + + // we want to move the block into another block + // such that the free space between this and the next block can be minimized + HeapBlockDesc *newblock = m_freeList.m_first.FindSmallestFreeBlock(block->m_size); + // size of free space wouldn't decrease, so return + if(newblock->m_size >= block->m_size + next->m_size) + return nil; + // size of free space wouldn't decrease enough + if(newblock->m_size >= 16 + 1.125f*block->m_size) // what are 16 and 1.125 here? sizeof(HeapBlockDesc)? + return nil; + return newblock; +} + +void* +CMemoryHeap::MoveHeapBlock(HeapBlockDesc *dst, HeapBlockDesc *src) +{ + PushMemId(src->m_memId); + dst->RemoveHeapFreeBlock(); + FillInBlockData(dst, dst->GetNextConsecutive(), src->m_size); + PopMemId(); + memcpy(dst->GetDataPointer(), src->GetDataPointer(), src->m_size); + memMoved += src->m_size; + dst->m_ptrListIndex = src->m_ptrListIndex; + src->m_ptrListIndex = -1; + Free(src->GetDataPointer()); + return dst->GetDataPointer(); +} + +uint32 +CMemoryHeap::GetMemoryUsed(int32 id) +{ + return m_memUsed[id]; +} + +uint32 +CMemoryHeap::GetBlocksUsed(int32 id) +{ + return m_blocksUsed[id]; +} + +void +CMemoryHeap::PopMemId(void) +{ + m_currentMemID = m_idStack.pop(); +} + +void +CMemoryHeap::PushMemId(int32 id) +{ + MEMORYHEAP_ASSERT(id != MEMID_FREE); + m_idStack.push(m_currentMemID); + m_currentMemID = id; +} + +void +CMemoryHeap::ParseHeap(void) +{ + char tmp[16]; + int fd = CFileMgr::OpenFileForWriting("heap.txt"); + CTimer::Stop(); + + // CMemoryHeap::IntegrityCheck(); + + uint32 addrQW = 0; + for(HeapBlockDesc *block = m_start; block < m_end; block = block->GetNextConsecutive()){ + char chr = '*'; // free + if(block->m_memId != MEMID_FREE) + chr = block->m_memId-MEMID_ID1 + 'A'; + int numQW = block->m_size>>4; + + if((addrQW & 0x3F) == 0){ + sprintf(tmp, "\n%5dK:", addrQW>>6); + CFileMgr::Write(fd, tmp, 8); + } + CFileMgr::Write(fd, "#", 1); // the descriptor, has to be 16 bytes!!!! + addrQW++; + + while(numQW--){ + if((addrQW & 0x3F) == 0){ + sprintf(tmp, "\n%5dK:", addrQW>>6); + CFileMgr::Write(fd, tmp, 8); + } + CFileMgr::Write(fd, &chr, 1); + addrQW++; + } + } + + CTimer::Update(); + CFileMgr::CloseFile(fd); +} + + +void +CommonSize::Init(uint32 size) +{ + m_freeList.Init(); + m_size = size; + m_failed = 0; + m_remaining = 0; +} + + + +void *pMemoryTop; + +void +InitMemoryMgr(void) +{ +#ifdef GTA_PS2 +#error "finish this" +#else + // randomly allocate 128mb + gMainHeap.Init(128*1024*1024); +#endif +} + +void* +MemoryMgrMalloc(uint32 size) +{ + void *mem = gMainHeap.Malloc(size); + if(mem > pMemoryTop) + pMemoryTop = mem; + return mem; +} + +void* +MemoryMgrRealloc(void *ptr, uint32 size) +{ + void *mem = gMainHeap.Realloc(ptr, size); + if(mem > pMemoryTop) + pMemoryTop = mem; + return mem; +} + +void* +MemoryMgrCalloc(uint32 num, uint32 size) +{ + void *mem = gMainHeap.Malloc(num*size); + if(mem > pMemoryTop) + pMemoryTop = mem; +#ifdef FIX_BUGS + memset(mem, 0, num*size); +#endif + return mem; +} + +void +MemoryMgrFree(void *ptr) +{ + gMainHeap.Free(ptr); +} + +RwMemoryFunctions memFuncs = { + MemoryMgrMalloc, + MemoryMgrFree, + MemoryMgrRealloc, + MemoryMgrCalloc +}; + +#endif diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h new file mode 100644 index 00000000..840e016a --- /dev/null +++ b/src/rw/MemoryHeap.h @@ -0,0 +1,188 @@ +#pragma once + +extern RwMemoryFunctions memFuncs; + +template +class CStack +{ +public: + T values[N]; + uint32 sp; + + CStack() : sp(0) {} + void push(const T& val) { values[sp++] = val; } + T& pop() { return values[sp--]; } +}; + + +struct HeapBlockDesc +{ + uint32 m_size; + int16 m_memId; + int16 m_ptrListIndex; + HeapBlockDesc *m_next; + HeapBlockDesc *m_prev; + + HeapBlockDesc *GetNextConsecutive(void) + { + return (HeapBlockDesc*)((uintptr)this + sizeof(HeapBlockDesc) + m_size); + } + + void *GetDataPointer(void) + { + return (void*)((uintptr)this + sizeof(HeapBlockDesc)); + } + + void RemoveHeapFreeBlock(void) + { + m_next->m_prev = m_prev; + m_prev->m_next = m_next; + } + + // after node + void InsertHeapFreeBlock(HeapBlockDesc *node) + { + m_next = node->m_next; + node->m_next->m_prev = this; + m_prev = node; + node->m_next = this; + } + + HeapBlockDesc *FindSmallestFreeBlock(uint32 size) + { + HeapBlockDesc *b; + for(b = m_next; b->m_size < size; b = b->m_next); + return b; + } +}; + +static_assert(sizeof(HeapBlockDesc) == 0x10, "HeapBlockDesc must have 0x10 size otherwise most of assumptions don't make sense"); + +struct HeapBlockList +{ + HeapBlockDesc m_first; + HeapBlockDesc m_last; + + void Init(void) + { + m_first.m_next = &m_last; + m_last.m_prev = &m_first; + } + + void Insert(HeapBlockDesc *node) + { + node->InsertHeapFreeBlock(&m_first); + } +}; + +struct CommonSize +{ + HeapBlockList m_freeList; + uint32 m_size; + uint32 m_failed; + uint32 m_remaining; + + void Init(uint32 size); + void Free(HeapBlockDesc *node) + { + m_freeList.Insert(node); + m_remaining++; + } + HeapBlockDesc *Malloc(void) + { + if(m_freeList.m_first.m_next == &m_freeList.m_last){ + m_failed++; + return nil; + } + HeapBlockDesc *block = m_freeList.m_first.m_next; + m_remaining--; + block->RemoveHeapFreeBlock(); + block->m_ptrListIndex = -1; + return block; + } +}; + +enum { + MEMID_FREE, + // IDs from LCS: + MEMID_ID1, // "Game" + MEMID_ID2, // "World" + MEMID_ID3, // "Animation" + MEMID_ID4, // "Pools" + MEMID_ID5, // "Default Models" + MEMID_ID6, // "Streaming" + MEMID_ID7, // "Streamed Models" + MEMID_ID8, // "Streamed LODs" + MEMID_ID9, // "Streamed Textures" + MEMID_ID10, // "Streamed Collision" + MEMID_ID11, // "Streamed Animation" + MEMID_ID12, // "Textures" + MEMID_ID13, // "Collision" + MEMID_ID14, // "PreAlloc" + MEMID_ID15, // "Game Process" + MEMID_ID16, // "Script" + MEMID_ID17, // "Cars" + MEMID_ID18, // "Render" + MEMID_ID19, // "Ped Attr" + + NUM_MEMIDS, + + NUM_FIXED_MEMBLOCKS = 6 +}; + +class CMemoryHeap +{ +public: + HeapBlockDesc *m_start; + HeapBlockDesc *m_end; + HeapBlockList m_freeList; + CommonSize m_fixedSize[NUM_FIXED_MEMBLOCKS]; + uint32 m_totalMemUsed; + CStack m_idStack; + uint32 m_currentMemID; + uint32 *m_memUsed; + uint32 m_totalBlocksUsed; + uint32 *m_blocksUsed; + uint32 m_unkMemId; + + CMemoryHeap(void) : m_start(nil) {} + void Init(uint32 total); + void RegisterMalloc(HeapBlockDesc *block); + void RegisterFree(HeapBlockDesc *block); + void *Malloc(uint32 size); + void *Realloc(void *ptr, uint32 size); + void Free(void *ptr); + void FillInBlockData(HeapBlockDesc *block, HeapBlockDesc *end, uint32 size); + uint32 CombineFreeBlocks(HeapBlockDesc *block); + void *MoveMemory(void *ptr); + HeapBlockDesc *WhereShouldMemoryMove(void *ptr); + void *MoveHeapBlock(HeapBlockDesc *dst, HeapBlockDesc *src); + void PopMemId(void); + void PushMemId(int32 id); + void RegisterMemPointer(void *ptr); + void TidyHeap(void); + uint32 GetMemoryUsed(int32 id); + uint32 GetBlocksUsed(int32 id); + + void ParseHeap(void); + + HeapBlockDesc *GetDescFromHeapPointer(void *block) + { + return (HeapBlockDesc*)((uintptr)block - sizeof(HeapBlockDesc)); + } + uint32 GetSizeBetweenBlocks(HeapBlockDesc *first, HeapBlockDesc *second) + { + return (uintptr)second - (uintptr)first - sizeof(HeapBlockDesc); + } + void FreeBlock(HeapBlockDesc *block){ + for(int i = 0; i < NUM_FIXED_MEMBLOCKS; i++){ + if(m_fixedSize[i].m_size == block->m_size){ + m_fixedSize[i].Free(block); + return; + } + } + HeapBlockDesc *it; + for(it = m_freeList.m_first.m_next; it->m_size < block->m_size; it = it->m_next); + block->InsertHeapFreeBlock(it->m_prev); + } +}; From 4ddc35634160da5779c46ab63a5b3d351af50b83 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 25 Nov 2020 22:49:50 +0100 Subject: [PATCH 083/129] memory heap starting to work --- src/core/main.cpp | 2 +- src/fakerw/fake.cpp | 32 ++++++++++++++++++++++++++++---- src/fakerw/rwplcore.h | 6 +++--- src/rw/MemoryHeap.cpp | 14 +++++++++++--- src/rw/MemoryHeap.h | 14 +++++++++++--- src/skel/glfw/glfw.cpp | 9 +++++++++ src/skel/win/win.cpp | 11 ++++++++++- vendor/librw | 2 +- 8 files changed, 74 insertions(+), 16 deletions(-) diff --git a/src/core/main.cpp b/src/core/main.cpp index 843f0671..ea88de59 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -1601,7 +1601,7 @@ void SystemInit() mwInit(); #endif -#ifdef GTA_PS2 +#ifdef USE_CUSTOM_ALLOCATOR InitMemoryMgr(); #endif diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 64a37421..39606335 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -16,9 +16,14 @@ using namespace rw; RwUInt8 RwObjectGetType(const RwObject *obj) { return obj->type; } -void *RwMalloc(size_t size) { return malloc(size); } -void *RwCalloc(size_t numObj, size_t sizeObj) { return calloc(numObj, sizeObj); } -void RwFree(void *mem) { free(mem); } +void *RwMalloc(size_t size) { return engine->memfuncs.rwmalloc(size, 0); } +void *RwCalloc(size_t numObj, size_t sizeObj) { + void *mem = RwMalloc(numObj*sizeObj); + if(mem) + memset(mem, 0, numObj*sizeObj); + return mem; +} +void RwFree(void *mem) { engine->memfuncs.rwfree(mem); } //RwReal RwV3dNormalize(RwV3d * out, const RwV3d * in); @@ -536,8 +541,27 @@ RwBool RwRenderStateSet(RwRenderState state, void *value) } } +static rw::MemoryFunctions gMemfuncs; +static void *(*real_malloc)(size_t size); +static void *(*real_realloc)(void *mem, size_t newSize); +static void *mallocWrap(size_t sz, uint32 hint) { if(sz == 0) return nil; return real_malloc(sz); } +static void *reallocWrap(void *p, size_t sz, uint32 hint) { return real_realloc(p, sz); } + + // WARNING: unused parameters -RwBool RwEngineInit(RwMemoryFunctions *memFuncs, RwUInt32 initFlags, RwUInt32 resArenaSize) { Engine::init(); return true; } +RwBool RwEngineInit(RwMemoryFunctions *memFuncs, RwUInt32 initFlags, RwUInt32 resArenaSize) { + if(memFuncs){ + real_malloc = memFuncs->rwmalloc; + real_realloc = memFuncs->rwrealloc; + gMemfuncs.rwmalloc = mallocWrap; + gMemfuncs.rwrealloc = reallocWrap; + gMemfuncs.rwfree = memFuncs->rwfree; + Engine::init(&gMemfuncs); + }else{ + Engine::init(nil); + } + return true; +} // TODO: this is platform dependent RwBool RwEngineOpen(RwEngineOpenParams *initParams) { static EngineOpenParams openParams; diff --git a/src/fakerw/rwplcore.h b/src/fakerw/rwplcore.h index 79c745b6..511f7678 100644 --- a/src/fakerw/rwplcore.h +++ b/src/fakerw/rwplcore.h @@ -141,15 +141,15 @@ RwUInt8 RwObjectGetType(const RwObject *obj); *********************************************** */ -struct RwMemoryFunctions; -/* +struct RwMemoryFunctions { + // NB: from RW 3.6 on the allocating functions take + // a hint parameter! void *(*rwmalloc)(size_t size); void (*rwfree)(void *mem); void *(*rwrealloc)(void *mem, size_t newSize); void *(*rwcalloc)(size_t numObj, size_t sizeObj); }; -*/ void *RwMalloc(size_t size); void RwFree(void *mem); diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp index d613a708..2a484df4 100644 --- a/src/rw/MemoryHeap.cpp +++ b/src/rw/MemoryHeap.cpp @@ -9,8 +9,11 @@ #ifdef USE_CUSTOM_ALLOCATOR -#define MEMORYHEAP_ASSERT(cond) { if (!(cond)) { printf("ASSERT File:%s Line:%d\n", __FILE__, __LINE__); exit(1); } } -#define MEMORYHEAP_ASSERT_MESSAGE(cond, message) { if (!(cond)) { printf("ASSERT File:%s Line:%d:\n\t%s\n", __FILE__, __LINE__, message); exit(1); } } +//#define MEMORYHEAP_ASSERT(cond) { if (!(cond)) { printf("ASSERT File:%s Line:%d\n", __FILE__, __LINE__); exit(1); } } +//#define MEMORYHEAP_ASSERT_MESSAGE(cond, message) { if (!(cond)) { printf("ASSERT File:%s Line:%d:\n\t%s\n", __FILE__, __LINE__, message); exit(1); } } + +#define MEMORYHEAP_ASSERT(cond) assert(cond) +#define MEMORYHEAP_ASSERT_MESSAGE(cond, message) assert(cond) // registered pointers that we keep track of void **gPtrList[4000]; @@ -272,6 +275,7 @@ CMemoryHeap::Free(void *ptr) MEMORYHEAP_ASSERT(m_unkMemId == -1 || m_unkMemId == block->m_memId); RegisterFree(block); + block->m_memId = MEMID_FREE; CombineFreeBlocks(block); FreeBlock(block); if(block->m_ptrListIndex != -1){ @@ -313,7 +317,7 @@ uint32 CMemoryHeap::CombineFreeBlocks(HeapBlockDesc *block) { HeapBlockDesc *next = block->GetNextConsecutive(); - if(next->m_memId == MEMID_FREE) + if(next->m_memId != MEMID_FREE) return block->m_size; // get rid of free blocks after this one and adjust size for(; next->m_memId == MEMID_FREE; next = next->GetNextConsecutive()) @@ -535,6 +539,10 @@ MemoryMgrCalloc(uint32 num, uint32 size) void MemoryMgrFree(void *ptr) { +#ifdef FIX_BUGS + // i don't suppose this is handled by RW? + if(ptr == nil) return; +#endif gMainHeap.Free(ptr); } diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h index 840e016a..3f6fb5a0 100644 --- a/src/rw/MemoryHeap.h +++ b/src/rw/MemoryHeap.h @@ -1,6 +1,12 @@ #pragma once +// some windows shit +#ifdef MoveMemory +#undef MoveMemory +#endif + extern RwMemoryFunctions memFuncs; +void InitMemoryMgr(void); template class CStack @@ -56,7 +62,10 @@ struct HeapBlockDesc } }; +#ifdef USE_CUSTOM_ALLOCATOR +// TODO: figure something out for 64 bit pointers static_assert(sizeof(HeapBlockDesc) == 0x10, "HeapBlockDesc must have 0x10 size otherwise most of assumptions don't make sense"); +#endif struct HeapBlockList { @@ -181,8 +190,7 @@ public: return; } } - HeapBlockDesc *it; - for(it = m_freeList.m_first.m_next; it->m_size < block->m_size; it = it->m_next); - block->InsertHeapFreeBlock(it->m_prev); + HeapBlockDesc *b = m_freeList.m_first.FindSmallestFreeBlock(block->m_size); + block->InsertHeapFreeBlock(b->m_prev); } }; diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 982e8641..2722a4df 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -40,6 +40,7 @@ #include "Sprite2d.h" #include "AnimViewer.h" #include "Font.h" +#include "MemoryHeap.h" #define MAX_SUBSYSTEMS (16) @@ -277,7 +278,11 @@ psMouseSetPos(RwV2d *pos) RwMemoryFunctions* psGetMemoryFunctions(void) { +#ifdef USE_CUSTOM_ALLOCATOR + return &memFuncs; +#else return nil; +#endif } /* @@ -1461,6 +1466,10 @@ main(int argc, char *argv[]) RwV2d pos; RwInt32 i; +#ifdef USE_CUSTOM_ALLOCATOR + InitMemoryMgr(); +#endif + #ifndef _WIN32 struct sigaction act; act.sa_sigaction = terminateHandler; diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 9effaa31..b4897d67 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -97,6 +97,7 @@ static psGlobalType PsGlobal; #include "Sprite2d.h" #include "AnimViewer.h" #include "Font.h" +#include "MemoryHeap.h" VALIDATE_SIZE(psGlobalType, 0x28); @@ -304,7 +305,11 @@ psMouseSetPos(RwV2d *pos) RwMemoryFunctions* psGetMemoryFunctions(void) { +#ifdef USE_CUSTOM_ALLOCATOR + return &memFuncs; +#else return nil; +#endif } /* @@ -2006,7 +2011,11 @@ WinMain(HINSTANCE instance, RwChar **argv; SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE); -#if 0 +#ifdef USE_CUSTOM_ALLOCATOR + InitMemoryMgr(); +#endif + +#if 1 // TODO: make this an option somewhere AllocConsole(); freopen("CONIN$", "r", stdin); diff --git a/vendor/librw b/vendor/librw index d9def88c..e8990d5b 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit d9def88c46a742c6bc74bf79021c0f8838480df4 +Subproject commit e8990d5b3d50be72594f93dcc42d749f29761516 From 491274f188c953ae0528248a7fcbe25fb78701f7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 26 Nov 2020 18:11:55 +0200 Subject: [PATCH 084/129] CStreaming::PrintStreamingBufferState --- src/core/Streaming.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++ src/core/Streaming.h | 2 + 2 files changed, 89 insertions(+) diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index e9a7af88..77d1773b 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -33,6 +33,7 @@ #endif #include "main.h" #include "Frontend.h" +#include "Font.h" bool CStreaming::ms_disableStreaming; bool CStreaming::ms_bLoadingBigModel; @@ -289,6 +290,11 @@ CStreaming::Shutdown(void) } } +#ifndef MASTER +uint64 timeProcessingTXD; +uint64 timeProcessingDFF; +#endif + void CStreaming::Update(void) { @@ -296,6 +302,11 @@ CStreaming::Update(void) CStreamingInfo *si, *prev; bool requestedSubway = false; +#ifndef MASTER + timeProcessingTXD = 0; + timeProcessingDFF = 0; +#endif + UpdateMemoryUsed(); if(ms_channelError != -1){ @@ -331,6 +342,14 @@ CStreaming::Update(void) LoadRequestedModels(); +#ifndef MASTER + if (CPad::GetPad(1)->GetLeftShoulder1JustDown() && CPad::GetPad(1)->GetRightShoulder1() && CPad::GetPad(1)->GetRightShoulder2()) + PrintStreamingBufferState(); + + // TODO: PrintRequestList + //if (CPad::GetPad(1)->GetLeftShoulder2JustDown() && CPad::GetPad(1)->GetRightShoulder1() && CPad::GetPad(1)->GetRightShoulder2()) + // PrintRequestList(); +#endif for(si = ms_endRequestedList.m_prev; si != &ms_startRequestedList; si = prev){ prev = si->m_prev; @@ -2636,3 +2655,71 @@ CStreaming::UpdateForAnimViewer(void) CStreaming::RetryLoadFile(CStreaming::ms_channelError); } } + + +void +CStreaming::PrintStreamingBufferState() +{ + char str[128]; + wchar wstr[128]; + uint32 offset, size; + + CTimer::Stop(); + int i = 0; + while (i < NUMSTREAMINFO) { + while (true) { + int j = 0; + DoRWStuffStartOfFrame(50, 50, 50, 0, 0, 0, 255); + CPad::UpdatePads(); + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); + DefinedState(); + + CRect unusedRect(0, 0, RsGlobal.maximumWidth, RsGlobal.maximumHeight); + CRGBA unusedColor(255, 255, 255, 255); + CFont::SetFontStyle(FONT_BANK); + CFont::SetBackgroundOff(); + CFont::SetWrapx(DEFAULT_SCREEN_WIDTH); + CFont::SetScale(0.5f, 0.75f); + CFont::SetCentreOff(); + CFont::SetCentreSize(DEFAULT_SCREEN_WIDTH); + CFont::SetJustifyOff(); + CFont::SetColor(CRGBA(200, 200, 200, 200)); + CFont::SetBackGroundOnlyTextOff(); + int modelIndex = i; + if (modelIndex < NUMSTREAMINFO) { + int y = 24; + for ( ; j < 34 && modelIndex < NUMSTREAMINFO; modelIndex++) { + CStreamingInfo *streamingInfo = &ms_aInfoForModel[modelIndex]; + CBaseModelInfo *modelInfo = CModelInfo::GetModelInfo(modelIndex); + if (streamingInfo->m_loadState != STREAMSTATE_LOADED || !streamingInfo->GetCdPosnAndSize(offset, size)) + continue; + + if (modelIndex >= STREAM_OFFSET_TXD) + sprintf(str, "txd %s, refs %d, size %dK, flags 0x%x", CTxdStore::GetTxdName(modelIndex - STREAM_OFFSET_TXD), + CTxdStore::GetNumRefs(modelIndex - STREAM_OFFSET_TXD), 2 * size, streamingInfo->m_flags); + else + sprintf(str, "model %d,%s, refs%d, size%dK, flags%x", modelIndex, modelInfo->GetName(), modelInfo->GetNumRefs(), 2 * size, + streamingInfo->m_flags); + AsciiToUnicode(str, wstr); + CFont::PrintString(24.0f, y, wstr); + y += 12; + j++; + } + } + + if (CPad::GetPad(1)->GetCrossJustDown()) + i = modelIndex; + + if (!CPad::GetPad(1)->GetTriangleJustDown()) + break; + + i = 0; + CFont::DrawFonts(); + DoRWStuffEndOfFrame(); + } + CFont::DrawFonts(); + DoRWStuffEndOfFrame(); + } + CTimer::Update(); +} \ No newline at end of file diff --git a/src/core/Streaming.h b/src/core/Streaming.h index 0b2ff124..ee9183a5 100644 --- a/src/core/Streaming.h +++ b/src/core/Streaming.h @@ -188,4 +188,6 @@ public: static void MemoryCardLoad(uint8 *buffer, uint32 length); static void UpdateForAnimViewer(void); + + static void PrintStreamingBufferState(); }; From d857758c167ee06840ec806524191e95ff37f98a Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 26 Nov 2020 16:47:19 +0100 Subject: [PATCH 085/129] start using CMemoryHeap --- src/animation/AnimBlendAssociation.cpp | 2 +- src/animation/AnimBlendClumpData.cpp | 2 +- src/animation/AnimBlendSequence.cpp | 12 + src/collision/ColModel.cpp | 6 + src/core/CdStream.cpp | 1 + src/core/FileLoader.cpp | 11 + src/core/Game.cpp | 111 ++++++++- src/core/Pools.cpp | 19 ++ src/core/Streaming.cpp | 41 ++- src/core/World.cpp | 3 + src/core/main.cpp | 329 +++++++++++++++++-------- src/core/templates.h | 16 +- src/entities/Entity.cpp | 5 + src/modelinfo/ModelIndices.cpp | 2 +- src/render/WaterLevel.cpp | 5 + src/rw/MemoryHeap.cpp | 88 ++++++- src/rw/MemoryHeap.h | 98 +++++--- src/rw/RwHelper.cpp | 39 --- src/rw/RwHelper.h | 3 - src/rw/VisibilityPlugins.cpp | 87 +++++-- src/skel/skeleton.cpp | 5 + src/vehicles/Plane.cpp | 5 +- 22 files changed, 652 insertions(+), 238 deletions(-) diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp index 8c99b694..61d7d69c 100644 --- a/src/animation/AnimBlendAssociation.cpp +++ b/src/animation/AnimBlendAssociation.cpp @@ -5,7 +5,7 @@ #include "RpAnimBlend.h" #include "AnimManager.h" #include "AnimBlendAssociation.h" -#include "RwHelper.h" +#include "MemoryHeap.h" CAnimBlendAssociation::CAnimBlendAssociation(void) { diff --git a/src/animation/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp index d40e8357..fd2a58de 100644 --- a/src/animation/AnimBlendClumpData.cpp +++ b/src/animation/AnimBlendClumpData.cpp @@ -1,7 +1,7 @@ #include "common.h" #include "AnimBlendClumpData.h" -#include "RwHelper.h" +#include "MemoryHeap.h" CAnimBlendClumpData::CAnimBlendClumpData(void) diff --git a/src/animation/AnimBlendSequence.cpp b/src/animation/AnimBlendSequence.cpp index d35fbc46..5a2fa605 100644 --- a/src/animation/AnimBlendSequence.cpp +++ b/src/animation/AnimBlendSequence.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "AnimBlendSequence.h" +#include "MemoryHeap.h" CAnimBlendSequence::CAnimBlendSequence(void) { @@ -70,6 +71,8 @@ CAnimBlendSequence::Uncompress(void) if(numFrames == 0) return; + PUSH_MEMID(MEMID_ANIMATION); + float rotScale = 1.0f/4096.0f; float timeScale = 1.0f/60.0f; float transScale = 1.0f/128.0f; @@ -105,8 +108,12 @@ CAnimBlendSequence::Uncompress(void) } keyFrames = newKfs; } + REGISTER_MEMPTR(&keyFrames); + RwFree(keyFramesCompressed); keyFramesCompressed = nil; + + POP_MEMID(); } void @@ -117,6 +124,8 @@ CAnimBlendSequence::CompressKeyframes(void) if(numFrames == 0) return; + PUSH_MEMID(MEMID_ANIMATION); + float rotScale = 4096.0f; float timeScale = 60.0f; float transScale = 128.0f; @@ -152,6 +161,9 @@ CAnimBlendSequence::CompressKeyframes(void) } keyFramesCompressed = newKfs; } + REGISTER_MEMPTR(&keyFramesCompressed); + + POP_MEMID(); } void diff --git a/src/collision/ColModel.cpp b/src/collision/ColModel.cpp index 650e6958..fb90e7dd 100644 --- a/src/collision/ColModel.cpp +++ b/src/collision/ColModel.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "ColModel.h" #include "Game.h" +#include "MemoryHeap.h" CColModel::CColModel(void) { @@ -48,10 +49,15 @@ CColModel::RemoveCollisionVolumes(void) void CColModel::CalculateTrianglePlanes(void) { + PUSH_MEMID(MEMID_COLLISION); + // HACK: allocate space for one more element to stuff the link pointer into trianglePlanes = (CColTrianglePlane*)RwMalloc(sizeof(CColTrianglePlane) * (numTriangles+1)); + REGISTER_MEMPTR(&trianglePlanes); for(int i = 0; i < numTriangles; i++) trianglePlanes[i].Set(vertices, triangles[i]); + + POP_MEMID(); } void diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index 1d39aa52..a1235930 100644 --- a/src/core/CdStream.cpp +++ b/src/core/CdStream.cpp @@ -5,6 +5,7 @@ #include "CdStream.h" #include "rwcore.h" #include "RwHelper.h" +#include "MemoryHeap.h" #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index f46b6134..88a99fa9 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -24,6 +24,7 @@ #include "ZoneCull.h" #include "CdStream.h" #include "FileLoader.h" +#include "MemoryHeap.h" char CFileLoader::ms_line[256]; @@ -71,11 +72,13 @@ CFileLoader::LoadLevel(const char *filename) if(strncmp(line, "IMAGEPATH", 9) == 0){ RwImageSetPath(line + 10); }else if(strncmp(line, "TEXDICTION", 10) == 0){ + PUSH_MEMID(MEMID_TEXTURES); strcpy(txdname, line+11); LoadingScreenLoadingFile(txdname); RwTexDictionary *txd = LoadTexDictionary(txdname); AddTexDictionaries(savedTxd, txd); RwTexDictionaryDestroy(txd); + POP_MEMID(); }else if(strncmp(line, "COLFILE", 7) == 0){ int level; sscanf(line+8, "%d", &level); @@ -94,12 +97,16 @@ CFileLoader::LoadLevel(const char *filename) LoadObjectTypes(line + 4); }else if(strncmp(line, "IPL", 3) == 0){ if(!objectsLoaded){ + PUSH_MEMID(MEMID_DEF_MODELS); CModelInfo::ConstructMloClumps(); + POP_MEMID(); CObjectData::Initialise("DATA\\OBJECT.DAT"); objectsLoaded = true; } + PUSH_MEMID(MEMID_WORLD); LoadingScreenLoadingFile(line + 4); LoadScene(line + 4); + POP_MEMID(); }else if(strncmp(line, "MAPZONE", 7) == 0){ LoadingScreenLoadingFile(line + 8); LoadMapZones(line + 8); @@ -188,6 +195,8 @@ CFileLoader::LoadCollisionFile(const char *filename) CBaseModelInfo *mi; ColHeader header; + PUSH_MEMID(MEMID_COLLISION); + debug("Loading collision file %s\n", filename); fd = CFileMgr::OpenFile(filename, "rb"); @@ -211,6 +220,8 @@ CFileLoader::LoadCollisionFile(const char *filename) } CFileMgr::CloseFile(fd); + + POP_MEMID(); } void diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 1283ecd1..d22a7184 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -90,6 +90,7 @@ #include "custompipes.h" #include "screendroplets.h" #include "crossplatform.h" +#include "MemoryHeap.h" eLevelName CGame::currLevel; bool CGame::bDemoMode = true; @@ -327,21 +328,35 @@ CGame::FinalShutdown(void) bool CGame::Initialise(const char* datFile) { +#ifdef GTA_PS2 + // TODO: upload VU0 collision code here +#else ResetLoadingScreenBar(); strcpy(aDatFile, datFile); - CPools::Initialise(); + CPools::Initialise(); // done in CWorld on PS2 CIniFile::LoadIniFile(); +#endif + currLevel = LEVEL_INDUSTRIAL; + + PUSH_MEMID(MEMID_TEXTURES); LoadingScreen("Loading the Game", "Loading generic textures", GetRandomSplashScreen()); gameTxdSlot = CTxdStore::AddTxdSlot("generic"); CTxdStore::Create(gameTxdSlot); CTxdStore::AddRef(gameTxdSlot); + LoadingScreen("Loading the Game", "Loading particles", nil); int particleTxdSlot = CTxdStore::AddTxdSlot("particle"); CTxdStore::LoadTxd(particleTxdSlot, "MODELS/PARTICLE.TXD"); CTxdStore::AddRef(particleTxdSlot); CTxdStore::SetCurrentTxd(gameTxdSlot); LoadingScreen("Loading the Game", "Setup game variables", nil); + POP_MEMID(); + +#ifdef GTA_PS2 + CDma::SyncChannel(0, true); +#endif + CGameLogic::InitAtStartOfGame(); CReferences::Init(); TheCamera.Init(); @@ -361,20 +376,41 @@ bool CGame::Initialise(const char* datFile) CMessages::ClearAllMessagesDisplayedByGame(); CRecordDataForGame::Init(); CRestart::Initialise(); + + PUSH_MEMID(MEMID_WORLD); CWorld::Initialise(); + POP_MEMID(); + + PUSH_MEMID(MEMID_TEXTURES); CParticle::Initialise(); -#ifdef PS2 + POP_MEMID(); + +#ifdef GTA_PS2 gStartX = -180.0f; gStartY = 180.0f; gStartZ = 14.0f; #endif + + PUSH_MEMID(MEMID_ANIMATION); CAnimManager::Initialise(); CCutsceneMgr::Initialise(); + POP_MEMID(); + + PUSH_MEMID(MEMID_CARS); CCarCtrl::Init(); + POP_MEMID(); + +#ifndef GTA_PS2 InitModelIndices(); +#endif + + PUSH_MEMID(MEMID_DEF_MODELS); CModelInfo::Initialise(); +#ifndef GTA_PS2 + // probably moved before LoadLevel for multiplayer maps? CPickups::Init(); CTheCarGenerators::Init(); +#endif CdStreamAddImage("MODELS\\GTA3.IMG"); CFileLoader::LoadLevel("DATA\\DEFAULT.DAT"); CFileLoader::LoadLevel(datFile); @@ -386,17 +422,23 @@ bool CGame::Initialise(const char* datFile) CVehicleModelInfo::LoadVehicleColours(); CVehicleModelInfo::LoadEnvironmentMaps(); CTheZones::PostZoneCreation(); + POP_MEMID(); + LoadingScreen("Loading the Game", "Setup paths", GetRandomSplashScreen()); ThePaths.PreparePathData(); + // done elsewhere on PS2 for (int i = 0; i < NUMPLAYERS; i++) CWorld::Players[i].Clear(); CWorld::Players[0].LoadPlayerSkin(); TestModelIndices(); + // + LoadingScreen("Loading the Game", "Setup water", nil); CWaterLevel::Initialise("DATA\\WATER.DAT"); TheConsole.Init(); CDraw::SetFOV(120.0f); CDraw::ms_fLODDistance = 500.0f; + LoadingScreen("Loading the Game", "Setup streaming", nil); CStreaming::Init(); CStreaming::LoadInitialVehicles(); @@ -404,8 +446,12 @@ bool CGame::Initialise(const char* datFile) CStreaming::RequestBigBuildings(LEVEL_GENERIC); CStreaming::LoadAllRequestedModels(false); printf("Streaming uses %zuK of its memory", CStreaming::ms_memoryUsed / 1024); // original modifier was %d + LoadingScreen("Loading the Game", "Load animations", GetRandomSplashScreen()); + PUSH_MEMID(MEMID_ANIMATION); CAnimManager::LoadAnimFiles(); + POP_MEMID(); + CPed::Initialise(); CRouteNode::Initialise(); CEventList::Initialise(); @@ -414,13 +460,16 @@ bool CGame::Initialise(const char* datFile) #endif LoadingScreen("Loading the Game", "Find big buildings", nil); CRenderer::Init(); + LoadingScreen("Loading the Game", "Setup game variables", nil); CRadar::Initialise(); CRadar::LoadTextures(); CWeapon::InitialiseWeapons(); + LoadingScreen("Loading the Game", "Setup traffic lights", nil); CTrafficLights::ScanForLightsOnMap(); CRoadBlocks::Init(); + LoadingScreen("Loading the Game", "Setup game variables", nil); CPopulation::Initialise(); CWorld::PlayerInFocus = 0; @@ -431,26 +480,48 @@ bool CGame::Initialise(const char* datFile) CAntennas::Init(); CGlass::Init(); gPhoneInfo.Initialise(); +#ifndef GTA_PS2 CSceneEdit::Initialise(); +#endif + LoadingScreen("Loading the Game", "Load scripts", nil); + PUSH_MEMID(MEMID_SCRIPT); CTheScripts::Init(); CGangs::Initialise(); + POP_MEMID(); + LoadingScreen("Loading the Game", "Setup game variables", nil); +#ifdef GTA_PS2 + CTimer::Initialise(); +#endif CClock::Initialise(1000); +#ifdef GTA_PS2 + CTheCarGenerators::Init(); +#endif CHeli::InitHelis(); CCranes::InitCranes(); CMovingThings::Init(); CDarkel::Init(); CStats::Init(); +#ifdef GTA_PS2 + CPickups::Init(); +#endif CPacManPickups::Init(); + // CGarages::Init(); here on PS2 instead CRubbish::Init(); CClouds::Init(); +#ifdef GTA_PS2 + CRemote::Init(); +#endif CSpecialFX::Init(); CWaterCannons::Init(); CBridge::Init(); CGarages::Init(); + LoadingScreen("Loading the Game", "Position dynamic objects", nil); CWorld::RepositionCertainDynamicObjects(); + // CCullZones::ResolveVisibilities(); on PS2 here instead + LoadingScreen("Loading the Game", "Initialise vehicle paths", nil); CCullZones::ResolveVisibilities(); CTrain::InitTrains(); @@ -458,6 +529,7 @@ bool CGame::Initialise(const char* datFile) CCredits::Init(); CRecordDataForChase::Init(); CReplay::Init(); + #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) { @@ -469,6 +541,7 @@ bool CGame::Initialise(const char* datFile) #ifdef PS2_MENU } #endif + LoadingScreen("Loading the Game", "Load scene", nil); CModelInfo::RemoveColModelsFromOtherLevels(currLevel); CCollision::ms_collisionInMemory = currLevel; @@ -550,7 +623,7 @@ void CGame::ReInitGameObjectVariables(void) CWorld::bDoingCarCollisions = false; CHud::ReInitialise(); CRadar::Initialise(); -#ifdef PS2 +#ifdef GTA_PS2 gStartX = -180.0f; gStartY = 180.0f; gStartZ = 14.0f; @@ -573,15 +646,19 @@ void CGame::ReInitGameObjectVariables(void) CWorld::Players[i].Clear(); CWorld::PlayerInFocus = 0; -#ifdef PS2 +#ifdef GTA_PS2 CWeaponEffects::Init(); CSkidmarks::Init(); #endif CAntennas::Init(); CGlass::Init(); gPhoneInfo.Initialise(); + + PUSH_MEMID(MEMID_SCRIPT); CTheScripts::Init(); CGangs::Initialise(); + POP_MEMID(); + CTimer::Initialise(); CClock::Initialise(1000); CTheCarGenerators::Init(); @@ -592,7 +669,7 @@ void CGame::ReInitGameObjectVariables(void) CPickups::Init(); CPacManPickups::Init(); CGarages::Init(); -#ifdef PS2 +#ifdef GTA_PS2 CClouds::Init(); CRemote::Init(); #endif @@ -807,7 +884,7 @@ void CGame::InitialiseWhenRestarting(void) void CGame::Process(void) { CPad::UpdatePads(); -#ifdef GTA_PS2 +#ifdef USE_CUSTOM_ALLOCATOR ProcessTidyUpMemory(); #endif TheCamera.SetMotionBlurAlpha(0); @@ -817,8 +894,12 @@ void CGame::Process(void) DebugMenuProcess(); #endif CCutsceneMgr::Update(); + + PUSH_MEMID(MEMID_FRONTEND); if (!CCutsceneMgr::IsCutsceneProcessing() && !CTimer::GetIsCodePaused()) FrontEndMenuManager.Process(); + POP_MEMID(); + CStreaming::Update(); if (!CTimer::GetIsPaused()) { @@ -831,7 +912,11 @@ void CGame::Process(void) CPad::DoCheats(); CClock::Update(); CWeather::Update(); + + PUSH_MEMID(MEMID_SCRIPT); CTheScripts::Process(); + POP_MEMID(); + CCollision::Update(); CTrain::UpdateTrains(); CPlane::UpdatePlanes(); @@ -855,7 +940,11 @@ void CGame::Process(void) CWaterCannons::Update(); CUserDisplay::Process(); CReplay::Update(); + + PUSH_MEMID(MEMID_WORLD); CWorld::Process(); + POP_MEMID(); + gAccidentManager.Update(); CPacManPickups::Update(); CPickups::Update(); @@ -876,33 +965,35 @@ void CGame::Process(void) gPhoneInfo.Update(); if (!CReplay::IsPlayingBack()) { + PUSH_MEMID(MEMID_CARS); CCarCtrl::GenerateRandomCars(); CRoadBlocks::GenerateRoadBlocks(); CCarCtrl::RemoveDistantCars(); + POP_MEMID(); } } -#ifdef PS2 +#ifdef GTA_PS2 CMemCheck::DoTest(); #endif } void CGame::DrasticTidyUpMemory(bool) { -#ifdef PS2 +#ifdef USE_CUSTOM_ALLOCATOR // meow #endif } void CGame::TidyUpMemory(bool, bool) { -#ifdef PS2 +#ifdef USE_CUSTOM_ALLOCATOR // meow #endif } void CGame::ProcessTidyUpMemory(void) { -#ifdef PS2 +#ifdef USE_CUSTOM_ALLOCATOR // meow #endif } diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp index bd0814d0..79841c14 100644 --- a/src/core/Pools.cpp +++ b/src/core/Pools.cpp @@ -12,6 +12,7 @@ #include "Streaming.h" #include "Wanted.h" #include "World.h" +#include "MemoryHeap.h" CCPtrNodePool *CPools::ms_pPtrNodePool; CEntryInfoNodePool *CPools::ms_pEntryInfoNodePool; @@ -23,18 +24,36 @@ CObjectPool *CPools::ms_pObjectPool; CDummyPool *CPools::ms_pDummyPool; CAudioScriptObjectPool *CPools::ms_pAudioScriptObjectPool; +#ifdef GTA_PS2 // or USE_CUSTOM_ALLOCATOR +#define CHECKMEM(msg) CMemCheck::AllocateMemCheckBlock(msg) +#else +#define CHECKMEM(msg) +#endif + void CPools::Initialise(void) { + PUSH_MEMID(MEMID_POOLS); + CHECKMEM("before pools"); ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES); + CHECKMEM("after CPtrNodePool"); ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS); + CHECKMEM("after CEntryInfoNodePool"); ms_pPedPool = new CPedPool(NUMPEDS); + CHECKMEM("after CPedPool"); ms_pVehiclePool = new CVehiclePool(NUMVEHICLES); + CHECKMEM("after CVehiclePool"); ms_pBuildingPool = new CBuildingPool(NUMBUILDINGS); + CHECKMEM("after CBuildingPool"); ms_pTreadablePool = new CTreadablePool(NUMTREADABLES); + CHECKMEM("after CTreadablePool"); ms_pObjectPool = new CObjectPool(NUMOBJECTS); + CHECKMEM("after CObjectPool"); ms_pDummyPool = new CDummyPool(NUMDUMMIES); + CHECKMEM("after CDummyPool"); ms_pAudioScriptObjectPool = new CAudioScriptObjectPool(NUMAUDIOSCRIPTOBJECTS); + CHECKMEM("after pools"); + POP_MEMID(); } void diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index e9a7af88..8f1a8891 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -33,6 +33,7 @@ #endif #include "main.h" #include "Frontend.h" +#include "MemoryHeap.h" bool CStreaming::ms_disableStreaming; bool CStreaming::ms_bLoadingBigModel; @@ -470,8 +471,10 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) // Set Txd to use CTxdStore::AddRef(mi->GetTxdSlot()); - CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); + PUSH_MEMID(MEMID_STREAM_MODELS); + CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); +// TODO(USE_CUSTOM_ALLOCATOR): register mem pointers if(mi->IsSimple()){ success = CFileLoader::LoadAtomicFile(stream, streamId); } else if (mi->GetModelType() == MITYPE_VEHICLE) { @@ -483,6 +486,7 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) }else{ success = CFileLoader::LoadClumpFile(stream, streamId); } + POP_MEMID(); UpdateMemoryUsed(); // Txd no longer needed unless we only read part of the file @@ -506,12 +510,14 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) return false; } + PUSH_MEMID(MEMID_STREAM_TEXUTRES); if(ms_bLoadingBigModel || cdsize > 200){ success = CTxdStore::StartLoadTxd(streamId - STREAM_OFFSET_TXD, stream); if(success) ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_STARTED; }else success = CTxdStore::LoadTxd(streamId - STREAM_OFFSET_TXD, stream); + POP_MEMID(); UpdateMemoryUsed(); if(!success){ @@ -561,7 +567,9 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) // Mark objects as loaded if(ms_aInfoForModel[streamId].m_loadState != STREAMSTATE_STARTED){ ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; +#ifndef USE_CUSTOM_ALLOCATOR ms_memoryUsed += ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; +#endif } endTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); @@ -600,32 +608,40 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId) if(streamId < STREAM_OFFSET_TXD){ // Model +// TODO(USE_CUSTOM_ALLOCATOR): register pointers mi = CModelInfo::GetModelInfo(streamId); + PUSH_MEMID(MEMID_STREAM_MODELS); CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); success = CFileLoader::FinishLoadClumpFile(stream, streamId); if(success) success = AddToLoadedVehiclesList(streamId); + POP_MEMID(); mi->RemoveRef(); CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot()); }else{ // Txd CTxdStore::AddRef(streamId - STREAM_OFFSET_TXD); + PUSH_MEMID(MEMID_STREAM_TEXUTRES); success = CTxdStore::FinishLoadTxd(streamId - STREAM_OFFSET_TXD, stream); + POP_MEMID(); CTxdStore::RemoveRefWithoutDelete(streamId - STREAM_OFFSET_TXD); } RwStreamClose(stream, &mem); - ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; + + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; // only done if success on PS2 +#ifndef USE_CUSTOM_ALLOCATOR ms_memoryUsed += ms_aInfoForModel[streamId].GetCdSize() * CDSTREAM_SECTOR_SIZE; +#endif if(!success){ RemoveModel(streamId); ReRequestModel(streamId); - UpdateMemoryUsed(); + UpdateMemoryUsed(); // directly after pop on PS2 return false; } - UpdateMemoryUsed(); + UpdateMemoryUsed(); // directly after pop on PS2 endTime = CTimer::GetCurrentTimeInCycles() / CTimer::GetCyclesPerMillisecond(); timeDiff = endTime - startTime; @@ -858,7 +874,11 @@ CStreaming::RemoveModel(int32 id) CModelInfo::GetModelInfo(id)->DeleteRwObject(); else CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); +#ifdef USE_CUSTOM_ALLOCATOR + UpdateMemoryUsed(); +#else ms_memoryUsed -= ms_aInfoForModel[id].GetCdSize()*CDSTREAM_SECTOR_SIZE; +#endif } if(ms_aInfoForModel[id].m_next){ @@ -880,6 +900,9 @@ CStreaming::RemoveModel(int32 id) RpClumpGtaCancelStream(); else CTxdStore::RemoveTxd(id - STREAM_OFFSET_TXD); +#ifdef USE_CUSTOM_ALLOCATOR + UpdateMemoryUsed(); +#endif } ms_aInfoForModel[id].m_loadState = STREAMSTATE_NOTLOADED; @@ -2044,19 +2067,25 @@ CStreaming::FlushRequestList(void) void CStreaming::ImGonnaUseStreamingMemory(void) { - // empty + PUSH_MEMID(MEMID_STREAM); } void CStreaming::IHaveUsedStreamingMemory(void) { + POP_MEMID(); UpdateMemoryUsed(); } void CStreaming::UpdateMemoryUsed(void) { - // empty +#ifdef USE_CUSTOM_ALLOCATOR + ms_memoryUsed = + gMainHeap.GetMemoryUsed(MEMID_STREAM) + + gMainHeap.GetMemoryUsed(MEMID_STREAM_MODELS) + + gMainHeap.GetMemoryUsed(MEMID_STREAM_TEXUTRES); +#endif } #define STREAM_DIST 80.0f diff --git a/src/core/World.cpp b/src/core/World.cpp index d65d57dd..33c2f1c1 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -53,6 +53,9 @@ bool CWorld::bIncludeCarTyres; void CWorld::Initialise() { +#ifdef GTA_PS2 + CPools::Initialise(); +#endif pIgnoreEntity = nil; bDoingCarCollisions = false; bSecondShift = false; diff --git a/src/core/main.cpp b/src/core/main.cpp index ea88de59..d34eb8f3 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -67,6 +67,7 @@ #include "custompipes.h" #include "screendroplets.h" #include "frontendoption.h" +#include "MemoryHeap.h" GlobalScene Scene; @@ -109,6 +110,15 @@ void TheGame(void); void DebugMenuPopulate(void); #endif + +#ifdef GTA_PS2 +#define WANT_TO_LOAD TheMemoryCard.m_bWantToLoad +#define FOUND_GAME_TO_LOAD TheMemoryCard.b_FoundRecentSavedGameWantToLoad +#else +#define WANT_TO_LOAD FrontEndMenuManager.m_bWantToLoad +#define FOUND_GAME_TO_LOAD b_FoundRecentSavedGameWantToLoad +#endif + void ValidateVersion() { @@ -772,6 +782,170 @@ tZonePrint ZonePrint[] = }; #ifndef MASTER + +void +PrintMemoryUsage(void) +{ +// little hack +if(CPools::GetPtrNodePool() == nil) +return; + + // Style taken from LCS, modified for III +// CFont::SetFontStyle(FONT_PAGER); + CFont::SetFontStyle(FONT_BANK); + CFont::SetBackgroundOff(); + CFont::SetWrapx(640.0f); +// CFont::SetScale(0.5f, 0.75f); + CFont::SetScale(0.4f, 0.75f); + CFont::SetCentreOff(); + CFont::SetCentreSize(640.0f); + CFont::SetJustifyOff(); + CFont::SetPropOn(); + CFont::SetColor(CRGBA(200, 200, 200, 200)); + CFont::SetBackGroundOnlyTextOff(); + CFont::SetDropShadowPosition(0); + + float y; + +#ifdef USE_CUSTOM_ALLOCATOR + y = 24.0f; + sprintf(gString, "Total: %d blocks, %d bytes", gMainHeap.m_totalBlocksUsed, gMainHeap.m_totalMemUsed); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Game: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_GAME), gMainHeap.GetMemoryUsed(MEMID_GAME)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "World: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_WORLD), gMainHeap.GetMemoryUsed(MEMID_WORLD)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Render: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_RENDER), gMainHeap.GetMemoryUsed(MEMID_RENDER)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Render List: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_RENDERLIST), gMainHeap.GetMemoryUsed(MEMID_RENDERLIST)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Default Models: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_DEF_MODELS), gMainHeap.GetMemoryUsed(MEMID_DEF_MODELS)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Textures: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_TEXTURES), gMainHeap.GetMemoryUsed(MEMID_TEXTURES)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Streaming: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_STREAM), gMainHeap.GetMemoryUsed(MEMID_STREAM)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Streamed Models: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_STREAM_MODELS), gMainHeap.GetMemoryUsed(MEMID_STREAM_MODELS)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Streamed Textures: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_STREAM_TEXUTRES), gMainHeap.GetMemoryUsed(MEMID_STREAM_TEXUTRES)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Animation: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_ANIMATION), gMainHeap.GetMemoryUsed(MEMID_ANIMATION)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Pools: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_POOLS), gMainHeap.GetMemoryUsed(MEMID_POOLS)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Collision: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_COLLISION), gMainHeap.GetMemoryUsed(MEMID_COLLISION)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Game Process: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_GAME_PROCESS), gMainHeap.GetMemoryUsed(MEMID_GAME_PROCESS)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Script: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_SCRIPT), gMainHeap.GetMemoryUsed(MEMID_SCRIPT)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Cars: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_CARS), gMainHeap.GetMemoryUsed(MEMID_CARS)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Frontend: %d blocks, %d bytes", gMainHeap.GetBlocksUsed(MEMID_FRONTEND), gMainHeap.GetMemoryUsed(MEMID_FRONTEND)); + AsciiToUnicode(gString, gUString); + CFont::PrintString(24.0f, y, gUString); + y += 12.0f; +#endif + + y = 132.0f; + AsciiToUnicode("Pools usage:", gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "PtrNode: %d/%d", CPools::GetPtrNodePool()->GetNoOfUsedSpaces(), CPools::GetPtrNodePool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "EntryInfoNode: %d/%d", CPools::GetEntryInfoNodePool()->GetNoOfUsedSpaces(), CPools::GetEntryInfoNodePool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Ped: %d/%d", CPools::GetPedPool()->GetNoOfUsedSpaces(), CPools::GetPedPool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Vehicle: %d/%d", CPools::GetVehiclePool()->GetNoOfUsedSpaces(), CPools::GetVehiclePool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Building: %d/%d", CPools::GetBuildingPool()->GetNoOfUsedSpaces(), CPools::GetBuildingPool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Treadable: %d/%d", CPools::GetTreadablePool()->GetNoOfUsedSpaces(), CPools::GetTreadablePool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Object: %d/%d", CPools::GetObjectPool()->GetNoOfUsedSpaces(), CPools::GetObjectPool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "Dummy: %d/%d", CPools::GetDummyPool()->GetNoOfUsedSpaces(), CPools::GetDummyPool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; + + sprintf(gString, "AudioScriptObjects: %d/%d", CPools::GetAudioScriptObjectPool()->GetNoOfUsedSpaces(), CPools::GetAudioScriptObjectPool()->GetSize()); + AsciiToUnicode(gString, gUString); + CFont::PrintString(400.0f, y, gUString); + y += 12.0f; +} + void DisplayGameDebugText() { @@ -785,6 +959,7 @@ DisplayGameDebugText() } #endif +// PrintMemoryUsage(); // TODO: put this somewhere else char str[200]; wchar ustr[200]; @@ -1001,13 +1176,9 @@ RenderMenus(void) { if (FrontEndMenuManager.m_bMenuActive) { -#ifdef PS2 - gMainHeap.PushMemId(_TODOCONST(17)); -#endif + PUSH_MEMID(MEMID_FRONTEND); FrontEndMenuManager.DrawFrontEnd(); -#ifdef PS2 - gMainHeap.PopMemId(); -#endif + POP_MEMID(); } } @@ -1046,24 +1217,29 @@ Idle(void *arg) CPad::UpdatePads(); FrontEndMenuManager.Process(); } else { + PUSH_MEMID(MEMID_GAME_PROCESS); CPointLights::InitPerFrame(); tbStartTimer(0, "CGame::Process"); CGame::Process(); tbEndTimer("CGame::Process"); + POP_MEMID(); + tbStartTimer(0, "DMAudio.Service"); DMAudio.Service(); - tbEndTimer("DMAudio.Service"); } if (RsGlobal.quit) return; #else + + PUSH_MEMID(MEMID_GAME_PROCESS); CPointLights::InitPerFrame(); tbStartTimer(0, "CGame::Process"); CGame::Process(); tbEndTimer("CGame::Process"); + POP_MEMID(); tbStartTimer(0, "DMAudio.Service"); DMAudio.Service(); @@ -1071,21 +1247,12 @@ Idle(void *arg) #endif if(CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()){ -#ifdef PS2_MENU - TheMemoryCard.m_bWantToLoad = false; + WANT_TO_LOAD = false; FrontEndMenuManager.m_bWantToRestart = true; -#else - FrontEndMenuManager.m_bWantToRestart = true; - FrontEndMenuManager.m_bWantToLoad = false; -#endif return; } -#ifdef PS2_MENU - if ( FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad ) -#else - if(FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad) -#endif + if(FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD) { return; } @@ -1095,6 +1262,8 @@ Idle(void *arg) if(arg == nil) return; + PUSH_MEMID(MEMID_RENDER); + if((!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu) && TheCamera.GetScreenFadeStatus() != FADE_2) { @@ -1107,6 +1276,8 @@ Idle(void *arg) RsMouseSetPos(&pos); } #endif + + PUSH_MEMID(MEMID_RENDERLIST); tbStartTimer(0, "CnstrRenderList"); CRenderer::ConstructRenderList(); tbEndTimer("CnstrRenderList"); @@ -1114,6 +1285,7 @@ Idle(void *arg) tbStartTimer(0, "PreRender"); CRenderer::PreRender(); tbEndTimer("PreRender"); + POP_MEMID(); #ifdef FIX_BUGS RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); // TODO: temp? this fixes OpenGL render but there should be a better place for this @@ -1124,12 +1296,12 @@ Idle(void *arg) if(CWeather::LightningFlash && !CCullZones::CamNoRain()){ if(!DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255)) - return; + goto popret; }else{ if(!DoRWStuffStartOfFrame_Horizon(CTimeCycle::GetSkyTopRed(), CTimeCycle::GetSkyTopGreen(), CTimeCycle::GetSkyTopBlue(), CTimeCycle::GetSkyBottomRed(), CTimeCycle::GetSkyBottomGreen(), CTimeCycle::GetSkyBottomBlue(), 255)) - return; + goto popret; } DefinedState(); @@ -1176,7 +1348,7 @@ Idle(void *arg) CVisibilityPlugins::SetRenderWareCamera(Scene.camera); RwCameraClear(Scene.camera, &gColourTop, rwCAMERACLEARZ); if(!RsCameraBeginUpdate(Scene.camera)) - return; + goto popret; } #ifdef PS2_SAVE_DIALOG @@ -1189,7 +1361,7 @@ Idle(void *arg) #ifdef PS2_MENU if ( TheMemoryCard.m_bWantToLoad ) - return; + goto popret; #endif tbStartTimer(0, "DoFade"); @@ -1208,8 +1380,13 @@ Idle(void *arg) DoRWStuffEndOfFrame(); + POP_MEMID(); // MEMID_RENDER + if(g_SlowMode) ProcessSlowMode(); + return; + +popret: POP_MEMID(); // MEMID_RENDER } void @@ -1375,14 +1552,13 @@ TheModelViewer(void) } #endif -#ifdef PS2 + +#ifdef GTA_PS2 void TheGame(void) { printf("Into TheGame!!!\n"); -#ifdef GTA_PS2 - gMainHeap.PushMemId(_TODOCONST(1)); -#endif + PUSH_MEMID(MEMID_GAME); // NB: not popped CTimer::Initialise(); @@ -1420,77 +1596,49 @@ void TheGame(void) while (true) { -#ifdef PS2 - if (TheMemoryCard.m_bWantToLoad) -#else - if (FrontEndMenuManager.m_bWantToLoad) -#endif + if (WANT_TO_LOAD) { Const char *splash1 = GetLevelSplashScreen(CGame::currLevel); LoadSplash(splash1); } -#ifdef PS2 - TheMemoryCard.m_bWantToLoad = false; -#else - FrontEndMenuManager.m_bWantToLoad = false; -#endif + WANT_TO_LOAD = false; CTimer::Update(); -#ifdef PS2 - while (!(FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad)) -#else - while (!(FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad)) -#endif + while (!(FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD)) { CSprite2d::InitPerFrame(); CFont::InitPerFrame(); -#ifdef GTA_PS2 - gMainHeap.PushMemId(_TODOCONST(12)); -#endif - CPointLights::NumLights = 0; + PUSH_MEMID(MEMID_GAME_PROCESS) + CPointLights::InitPerFrame(); CGame::Process(); -#ifdef GTA_PS2 - gMainHeap.PopMemId(); -#endif + POP_MEMID(); DMAudio.Service(); if (CGame::bDemoMode && CTimer::GetTimeInMilliseconds() > (3*60 + 30)*1000 && !CCutsceneMgr::IsCutsceneProcessing()) { -#ifdef PS2 - TheMemoryCard.m_bWantToLoad = false; -#else - FrontEndMenuManager.m_bWantToLoad = false; -#endif + WANT_TO_LOAD = false; FrontEndMenuManager.m_bWantToRestart = true; break; } -#ifdef PS2 - if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad) -#else - if (FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad) -#endif + if (FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD) break; SetLightsWithTimeOfDayColour(Scene.world); -#ifdef GTA_PS2 - gMainHeap.PushMemId(_TODOCONST(15)); -#endif + + PUSH_MEMID(MEMID_RENDER); if (!FrontEndMenuManager.m_bMenuActive || FrontEndMenuManager.m_bRenderGameInMenu == true && TheCamera.GetScreenFadeStatus() != FADE_2 ) { -#ifdef GTA_PS2 - gMainHeap.PushMemId(_TODOCONST(11)); -#endif + + PUSH_MEMID(MEMID_RENDERLIST); CRenderer::ConstructRenderList(); CRenderer::PreRender(); -#ifdef GTA_PS2 - gMainHeap.PopMemId(); -#endif + POP_MEMID(); if (CWeather::LightningFlash && !CCullZones::CamNoRain()) DoRWStuffStartOfFrame_Horizon(255, 255, 255, 255, 255, 255, 255); @@ -1522,15 +1670,9 @@ void TheGame(void) RenderMenus(); -#ifdef PS2 - if (TheMemoryCard.m_bWantToLoad) -#else - if (FrontEndMenuManager.m_bWantToLoad) -#endif + if (WANT_TO_LOAD) { -#ifdef GTA_PS2 - gMainHeap.PopMemId(); -#endif + POP_MEMID(); // MEMID_RENDER break; } @@ -1547,9 +1689,7 @@ void TheGame(void) CTimer::Update(); -#ifdef GTA_PS2 - gMainHeap.PopMemId(); -#endif + POP_MEMID(): // MEMID_RENDER if (g_SlowMode) ProcessSlowMode(); @@ -1561,24 +1701,12 @@ void TheGame(void) CGame::ShutDownForRestart(); CTimer::Stop(); -#ifdef PS2 - if (FrontEndMenuManager.m_bWantToRestart || TheMemoryCard.b_FoundRecentSavedGameWantToLoad) -#else - if (FrontEndMenuManager.m_bWantToRestart || b_FoundRecentSavedGameWantToLoad) -#endif + if (FrontEndMenuManager.m_bWantToRestart || FOUND_GAME_TO_LOAD) { -#ifdef PS2 - if (TheMemoryCard.b_FoundRecentSavedGameWantToLoad) -#else - if (b_FoundRecentSavedGameWantToLoad) -#endif + if (FOUND_GAME_TO_LOAD) { FrontEndMenuManager.m_bWantToRestart = true; -#ifdef PS2 - TheMemoryCard.m_bWantToLoad = true; -#else - FrontEndMenuManager.m_bWantToLoad = true; -#endif + WANT_TO_LOAD = true; } CGame::InitialiseWhenRestarting(); @@ -1718,7 +1846,7 @@ void SystemInit() // #endif -#ifdef PS2 +#ifdef GTA_PS2 TheMemoryCard.Init(); #endif } @@ -1747,7 +1875,7 @@ void GameInit() #endif CdStreamInit(MAX_CDCHANNELS); -#ifdef PS2 +#ifdef GTA_PS2 Initialise3D(); //no params #else //TODO @@ -1861,14 +1989,11 @@ void GameInit() CSprite2d::SetRecipNearClip(); CTxdStore::Initialise(); -#ifdef GTA_PS2 - gMainHeap.PushMemId(_TODOCONST(9)); -#endif + + PUSH_MEMID(MEMID_TEXTURES); CFont::Initialise(); CHud::Initialise(); -#ifdef GTA_PS2 - gMainHeap.PopMemId(); -#endif + POP_MEMID(); ValidateVersion(); @@ -1896,7 +2021,7 @@ main(int argc, char *argv[]) SystemInit(); -#ifdef PS2 +#ifdef GTA_PS2 int32 r = TheMemoryCard.CheckCardStateAtGameStartUp(CARD_ONE); if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT diff --git a/src/core/templates.h b/src/core/templates.h index 4f7b8490..86239664 100644 --- a/src/core/templates.h +++ b/src/core/templates.h @@ -46,8 +46,8 @@ class CPool public: CPool(int size){ // TODO: use new here - m_entries = (U*)malloc(sizeof(U)*size); - m_flags = (Flags*)malloc(sizeof(Flags)*size); + m_entries = (U*)new uint8[sizeof(U)*size]; + m_flags = (Flags*)new uint8[sizeof(Flags)*size]; m_size = size; m_allocPtr = 0; for(int i = 0; i < size; i++){ @@ -61,8 +61,8 @@ public: } void Flush() { if (m_size > 0) { - free(m_entries); - free(m_flags); + delete[] (uint8*)m_entries; + delete[] (uint8*)m_flags; m_entries = nil; m_flags = nil; m_size = 0; @@ -141,8 +141,8 @@ public: } bool IsFreeSlot(int i) { return !!m_flags[i].free; } void ClearStorage(uint8 *&flags, U *&entries){ - free(flags); - free(entries); + delete[] (uint8*)flags; + delete[] (uint8*)entries; flags = nil; entries = nil; } @@ -156,8 +156,8 @@ public: debug("CopyBack:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ } void Store(uint8 *&flags, U *&entries){ - flags = (uint8*)malloc(sizeof(uint8)*m_size); - entries = (U*)malloc(sizeof(U)*m_size); + flags = (uint8*)new uint8[sizeof(uint8)*m_size]; + entries = (U*)new uint8[sizeof(U)*m_size]; memcpy(flags, m_flags, sizeof(uint8)*m_size); memcpy(entries, m_entries, sizeof(U)*m_size); debug("Stored:%d (/%d)\n", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */ diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index 5e3204b2..476439fa 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -28,6 +28,7 @@ #include "Bones.h" #include "Debug.h" #include "Renderer.h" +#include "MemoryHeap.h" int gBuildings; @@ -274,7 +275,11 @@ CEntity::CreateRwObject(void) CBaseModelInfo *mi; mi = CModelInfo::GetModelInfo(m_modelIndex); + + PUSH_MEMID(MEMID_WORLD); m_rwObject = mi->CreateInstance(); + POP_MEMID(); + if(m_rwObject){ if(IsBuilding()) gBuildings++; diff --git a/src/modelinfo/ModelIndices.cpp b/src/modelinfo/ModelIndices.cpp index 056c3733..98c7fb38 100644 --- a/src/modelinfo/ModelIndices.cpp +++ b/src/modelinfo/ModelIndices.cpp @@ -3,7 +3,7 @@ #include "General.h" #include "ModelIndices.h" -#define X(name, var) int16 var; +#define X(name, var) int16 var = -1; MODELINDICES #undef X diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index 6133b1d7..ecfccc90 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -21,6 +21,7 @@ #include "RenderBuffer.h" #include #include "WaterLevel.h" +#include "MemoryHeap.h" float TEXTURE_ADDU; @@ -1157,6 +1158,8 @@ CWaterLevel::AllocateBoatWakeArray() { CStreaming::MakeSpaceFor(14 * CDSTREAM_SECTOR_SIZE); + PUSH_MEMID(MEMID_STREAM); + ASSERT(ms_pWavyAtomic != NULL ); RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); @@ -1230,6 +1233,8 @@ CWaterLevel::AllocateBoatWakeArray() RpGeometryUnlock(apGeomArray[geom]); } } + + POP_MEMID(); } void diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp index 2a484df4..2cf173b6 100644 --- a/src/rw/MemoryHeap.cpp +++ b/src/rw/MemoryHeap.cpp @@ -44,7 +44,7 @@ CMemoryHeap::Init(uint32 total) m_end = (HeapBlockDesc*)(mem + total - sizeof(HeapBlockDesc)); m_start->m_memId = MEMID_FREE; m_start->m_size = total - 2*sizeof(HeapBlockDesc); - m_end->m_memId = MEMID_ID1; + m_end->m_memId = MEMID_GAME; m_end->m_size = 0; m_freeList.m_last.m_size = INT_MAX; @@ -65,7 +65,7 @@ CMemoryHeap::Init(uint32 total) RegisterMalloc(GetDescFromHeapPointer(m_memUsed)); RegisterMalloc(GetDescFromHeapPointer(m_blocksUsed)); - m_currentMemID = MEMID_ID1; + m_currentMemID = MEMID_GAME; for(int i = 0; i < NUM_MEMIDS; i++){ m_memUsed[i] = 0; m_blocksUsed[i] = 0; @@ -90,8 +90,8 @@ CMemoryHeap::RegisterFree(HeapBlockDesc *block) if(block->m_memId == MEMID_FREE) return; m_totalMemUsed -= block->m_size + sizeof(HeapBlockDesc); - m_memUsed[m_currentMemID] -= block->m_size + sizeof(HeapBlockDesc); - m_blocksUsed[m_currentMemID]--; + m_memUsed[block->m_memId] -= block->m_size + sizeof(HeapBlockDesc); + m_blocksUsed[block->m_memId]--; m_totalBlocksUsed--; } @@ -433,13 +433,16 @@ CMemoryHeap::GetBlocksUsed(int32 id) void CMemoryHeap::PopMemId(void) { + assert(m_idStack.sp > 0); m_currentMemID = m_idStack.pop(); + assert(m_currentMemID != MEMID_FREE); } void CMemoryHeap::PushMemId(int32 id) { MEMORYHEAP_ASSERT(id != MEMID_FREE); + assert(m_idStack.sp < 16); m_idStack.push(m_currentMemID); m_currentMemID = id; } @@ -457,7 +460,7 @@ CMemoryHeap::ParseHeap(void) for(HeapBlockDesc *block = m_start; block < m_end; block = block->GetNextConsecutive()){ char chr = '*'; // free if(block->m_memId != MEMID_FREE) - chr = block->m_memId-MEMID_ID1 + 'A'; + chr = block->m_memId-1 + 'A'; int numQW = block->m_size>>4; if((addrQW & 0x3F) == 0){ @@ -506,10 +509,31 @@ InitMemoryMgr(void) #endif } + +RwMemoryFunctions memFuncs = { + MemoryMgrMalloc, + MemoryMgrFree, + MemoryMgrRealloc, + MemoryMgrCalloc +}; + +#ifdef USE_CUSTOM_ALLOCATOR +// game seems to be using heap directly here, but this is nicer +void *operator new(size_t sz) { return MemoryMgrMalloc(sz); } +void *operator new[](size_t sz) { return MemoryMgrMalloc(sz); } +void operator delete(void *ptr) noexcept { MemoryMgrFree(ptr); } +void operator delete[](void *ptr) noexcept { MemoryMgrFree(ptr); } +#endif +#endif + void* MemoryMgrMalloc(uint32 size) { +#ifdef USE_CUSTOM_ALLOCATOR void *mem = gMainHeap.Malloc(size); +#else + void *mem = malloc(size); +#endif if(mem > pMemoryTop) pMemoryTop = mem; return mem; @@ -518,7 +542,11 @@ MemoryMgrMalloc(uint32 size) void* MemoryMgrRealloc(void *ptr, uint32 size) { +#ifdef USE_CUSTOM_ALLOCATOR void *mem = gMainHeap.Realloc(ptr, size); +#else + void *mem = realloc(ptr, size); +#endif if(mem > pMemoryTop) pMemoryTop = mem; return mem; @@ -527,7 +555,11 @@ MemoryMgrRealloc(void *ptr, uint32 size) void* MemoryMgrCalloc(uint32 num, uint32 size) { +#ifdef USE_CUSTOM_ALLOCATOR void *mem = gMainHeap.Malloc(num*size); +#else + void *mem = calloc(num, size); +#endif if(mem > pMemoryTop) pMemoryTop = mem; #ifdef FIX_BUGS @@ -539,18 +571,52 @@ MemoryMgrCalloc(uint32 num, uint32 size) void MemoryMgrFree(void *ptr) { +#ifdef USE_CUSTOM_ALLOCATOR #ifdef FIX_BUGS // i don't suppose this is handled by RW? if(ptr == nil) return; #endif gMainHeap.Free(ptr); +#else + free(ptr); +#endif } -RwMemoryFunctions memFuncs = { - MemoryMgrMalloc, - MemoryMgrFree, - MemoryMgrRealloc, - MemoryMgrCalloc -}; +void * +RwMallocAlign(RwUInt32 size, RwUInt32 align) +{ +#ifdef FIX_BUGS + uintptr ptralign = align-1; + void *mem = (void *)MemoryMgrMalloc(size + sizeof(uintptr) + ptralign); + ASSERT(mem != nil); + + void *addr = (void *)((((uintptr)mem) + sizeof(uintptr) + ptralign) & ~ptralign); + + ASSERT(addr != nil); +#else + void *mem = (void *)MemoryMgrMalloc(size + align); + + ASSERT(mem != nil); + + void *addr = (void *)((((uintptr)mem) + align) & ~(align - 1)); + + ASSERT(addr != nil); #endif + + *(((void **)addr) - 1) = mem; + + return addr; +} + +void +RwFreeAlign(void *mem) +{ + ASSERT(mem != nil); + + void *addr = *(((void **)mem) - 1); + + ASSERT(addr != nil); + + MemoryMgrFree(addr); +} diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h index 3f6fb5a0..22e13617 100644 --- a/src/rw/MemoryHeap.h +++ b/src/rw/MemoryHeap.h @@ -5,9 +5,75 @@ #undef MoveMemory #endif +#ifdef USE_CUSTOM_ALLOCATOR +#define PUSH_MEMID(id) gMainHeap.PushMemId(id) +#define POP_MEMID() gMainHeap.PopMemId() +#define REGISTER_MEMPTR(ptr) gMainHeap.RegisterMemPointer(ptr) +#else +#define PUSH_MEMID(id) +#define POP_MEMID() +#define REGISTER_MEMPTR(ptr) +#endif + +enum { + MEMID_FREE, + // IDs from LCS: +/* + MEMID_GAME = 1, // "Game" + MEMID_WORLD = 2, // "World" + MEMID_ANIMATION = 3, // "Animation" + MEMID_POOLS = 4, // "Pools" + MEMID_DEF_MODELS = 5, // "Default Models" + MEMID_STREAM = 6, // "Streaming" + MEMID_STREAM_MODELS = 7, // "Streamed Models" + MEMID_STREAM_LODS = 8, // "Streamed LODs" + MEMID_STREAM_TEXUTRES = 9, // "Streamed Textures" + MEMID_STREAM_COLLISION = 10, // "Streamed Collision" + MEMID_STREAM_ANIMATION = 11, // "Streamed Animation" + MEMID_TEXTURES = 12, // "Textures" + MEMID_COLLISION = 13, // "Collision" + MEMID_PRE_ALLOC = 14, // "PreAlloc" + MEMID_GAME_PROCESS = 15, // "Game Process" + MEMID_SCRIPT = 16, // "Script" + MEMID_CARS = 17, // "Cars" + MEMID_RENDER = 18, // "Render" + MEMID_PED_ATTR = 19, // "Ped Attr" +*/ + // III: + MEMID_GAME = 1, // "Game" + MEMID_WORLD = 2, // "World" + MEMID_ANIMATION = 3, // "Animation" + MEMID_POOLS = 4, // "Pools" + MEMID_DEF_MODELS = 5, // "Default Models" + MEMID_STREAM = 6, // "Streaming" + MEMID_STREAM_MODELS = 7, // "Streamed Models" (instance) + MEMID_STREAM_TEXUTRES = 8, // "Streamed Textures" + MEMID_TEXTURES = 9, // "Textures" + MEMID_COLLISION = 10, // "Collision" + MEMID_RENDERLIST = 11, // ? + MEMID_GAME_PROCESS = 12, // "Game Process" + MEMID_SCRIPT = 13, // "Script" + MEMID_CARS = 14, // "Cars" + MEMID_RENDER = 15, // "Render" + MEMID_FRONTEND = 17, // ? + + NUM_MEMIDS, + + NUM_FIXED_MEMBLOCKS = 6 +}; + extern RwMemoryFunctions memFuncs; void InitMemoryMgr(void); +void *MemoryMgrMalloc(uint32 size); +void *MemoryMgrRealloc(void *ptr, uint32 size); +void *MemoryMgrCalloc(uint32 num, uint32 size); +void MemoryMgrFree(void *ptr); + +void *RwMallocAlign(RwUInt32 size, RwUInt32 align); +void RwFreeAlign(void *mem); + + template class CStack { @@ -17,7 +83,7 @@ public: CStack() : sp(0) {} void push(const T& val) { values[sp++] = val; } - T& pop() { return values[sp--]; } + T& pop() { return values[--sp]; } }; @@ -111,34 +177,6 @@ struct CommonSize } }; -enum { - MEMID_FREE, - // IDs from LCS: - MEMID_ID1, // "Game" - MEMID_ID2, // "World" - MEMID_ID3, // "Animation" - MEMID_ID4, // "Pools" - MEMID_ID5, // "Default Models" - MEMID_ID6, // "Streaming" - MEMID_ID7, // "Streamed Models" - MEMID_ID8, // "Streamed LODs" - MEMID_ID9, // "Streamed Textures" - MEMID_ID10, // "Streamed Collision" - MEMID_ID11, // "Streamed Animation" - MEMID_ID12, // "Textures" - MEMID_ID13, // "Collision" - MEMID_ID14, // "PreAlloc" - MEMID_ID15, // "Game Process" - MEMID_ID16, // "Script" - MEMID_ID17, // "Cars" - MEMID_ID18, // "Render" - MEMID_ID19, // "Ped Attr" - - NUM_MEMIDS, - - NUM_FIXED_MEMBLOCKS = 6 -}; - class CMemoryHeap { public: @@ -194,3 +232,5 @@ public: block->InsertHeapFreeBlock(b->m_prev); } }; + +extern CMemoryHeap gMainHeap; diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index 0069934f..ee370c37 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -64,45 +64,6 @@ void FlushObrsPrintfs() #endif } -void * -RwMallocAlign(RwUInt32 size, RwUInt32 align) -{ -#ifdef FIX_BUGS - uintptr ptralign = align-1; - void *mem = (void *)malloc(size + sizeof(uintptr) + ptralign); - - ASSERT(mem != nil); - - void *addr = (void *)((((uintptr)mem) + sizeof(uintptr) + ptralign) & ~ptralign); - - ASSERT(addr != nil); -#else - void *mem = (void *)malloc(size + align); - - ASSERT(mem != nil); - - void *addr = (void *)((((uintptr)mem) + align) & ~(align - 1)); - - ASSERT(addr != nil); -#endif - - *(((void **)addr) - 1) = mem; - - return addr; -} - -void -RwFreeAlign(void *mem) -{ - ASSERT(mem != nil); - - void *addr = *(((void **)mem) - 1); - - ASSERT(addr != nil); - - free(addr); -} - void DefinedState(void) { diff --git a/src/rw/RwHelper.h b/src/rw/RwHelper.h index 523a7732..ed9b03ab 100644 --- a/src/rw/RwHelper.h +++ b/src/rw/RwHelper.h @@ -2,9 +2,6 @@ extern bool gPS2alphaTest; -void *RwMallocAlign(RwUInt32 size, RwUInt32 align); -void RwFreeAlign(void *mem); - void OpenCharsetSafe(); void CreateDebugFont(); void DestroyDebugFont(); diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 3f10d12a..68775c72 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -10,6 +10,7 @@ #include "VisibilityPlugins.h" #include "World.h" #include "custompipes.h" +#include "MemoryHeap.h" CLinkList CVisibilityPlugins::m_alphaList; CLinkList CVisibilityPlugins::m_alphaEntityList; @@ -30,6 +31,41 @@ float CVisibilityPlugins::ms_pedLod0Dist; float CVisibilityPlugins::ms_pedLod1Dist; float CVisibilityPlugins::ms_pedFadeDist; +#ifdef GTA_PS2 +void +rpDefaultGeometryInstance(RpGeometry *geo, void *atomic, int unk) +{ + // TODO + // this function seems to delete the original geometry data + // and only keep the instanced data + AtomicDefaultRenderCallBack((RpAtomic*)atomic); +} + +RpAtomic* +PreInstanceRenderCB(RpAtomic *atomic) +{ + RpGeometry *geo = RpAtomicGetGeometry(atomic); + if(RpGeometryGetTriangles(geo)){ + PUSH_MEMID(MEMID_STREAM_MODELS); + rpDefaultGeometryInstance(geo, atomic, 1); + POP_MEMID(); + }else + AtomicDefaultRenderCallBack(atomic); + return atomic; +} +#define RENDERCALLBACK PreInstanceRenderCB +#else +RpAtomic* +DefaultRenderCB_pushid(RpAtomic *atomic) +{ + PUSH_MEMID(MEMID_STREAM_MODELS); + AtomicDefaultRenderCallBack(atomic); + POP_MEMID(); + return atomic; +} +#define RENDERCALLBACK DefaultRenderCB_pushid +#endif + void CVisibilityPlugins::Initialise(void) { @@ -132,7 +168,7 @@ CVisibilityPlugins::RenderAlphaAtomics(void) for(node = m_alphaList.tail.prev; node != &m_alphaList.head; node = node->prev) - AtomicDefaultRenderCallBack(node->item.atomic); + RENDERCALLBACK(node->item.atomic); } void @@ -201,7 +237,7 @@ CVisibilityPlugins::RenderWheelAtomicCB(RpAtomic *atomic) if(lodatm){ if(RpAtomicGetGeometry(lodatm) != RpAtomicGetGeometry(atomic)) RpAtomicSetGeometry(atomic, RpAtomicGetGeometry(lodatm), rpATOMICSAMEBOUNDINGSPHERE); - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -218,7 +254,7 @@ CVisibilityPlugins::RenderObjNormalAtomic(RpAtomic *atomic) len = RwV3dLength(&view); if(RwV3dDotProduct(&view, RwMatrixGetUp(m)) < -0.3f*len && len > 8.0f) return atomic; - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); return atomic; } @@ -232,7 +268,7 @@ CVisibilityPlugins::RenderAlphaAtomic(RpAtomic *atomic, int alpha) flags = RpGeometryGetFlags(geo); RpGeometrySetFlags(geo, flags | rpGEOMETRYMODULATEMATERIALCOLOR); RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)alpha); - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)255); RpGeometrySetFlags(geo, flags); return atomic; @@ -250,7 +286,7 @@ CVisibilityPlugins::RenderFadingAtomic(RpAtomic *atomic, float camdist) lodatm = mi->GetAtomicFromDistance(camdist - FADE_DISTANCE); if(mi->m_additive){ RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); }else{ fadefactor = (mi->GetLargestLodDistance() - (camdist - FADE_DISTANCE))/FADE_DISTANCE; @@ -258,7 +294,7 @@ CVisibilityPlugins::RenderFadingAtomic(RpAtomic *atomic, float camdist) fadefactor = 1.0f; alpha = mi->m_alpha * fadefactor; if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else{ RpGeometry *geo = RpAtomicGetGeometry(lodatm); uint32 flags = RpGeometryGetFlags(geo); @@ -266,7 +302,7 @@ CVisibilityPlugins::RenderFadingAtomic(RpAtomic *atomic, float camdist) RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)alpha); if(geo != RpAtomicGetGeometry(atomic)) RpAtomicSetGeometry(atomic, geo, rpATOMICSAMEBOUNDINGSPHERE); // originally 5 (mistake?) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); RpGeometryForAllMaterials(geo, SetAlphaCB, (void*)255); RpGeometrySetFlags(geo, flags); } @@ -293,7 +329,7 @@ CVisibilityPlugins::RenderVehicleHiDetailCB(RpAtomic *atomic) if(dot > 0.0f && ((flags & ATOMIC_FLAG_ANGLECULL) || 0.1f*distsq < dot*dot)) return atomic; } - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -318,10 +354,10 @@ CVisibilityPlugins::RenderVehicleHiDetailAlphaCB(RpAtomic *atomic) if(flags & ATOMIC_FLAG_DRAWLAST){ // sort before clump if(!InsertAtomicIntoSortedList(atomic, distsq - 0.0001f)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); }else{ if(!InsertAtomicIntoSortedList(atomic, distsq + dot)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } } return atomic; @@ -344,7 +380,7 @@ CVisibilityPlugins::RenderVehicleHiDetailCB_BigVehicle(RpAtomic *atomic) if(dot > 0.0f) return atomic; } - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -367,7 +403,7 @@ CVisibilityPlugins::RenderVehicleHiDetailAlphaCB_BigVehicle(RpAtomic *atomic) return atomic; if(!InsertAtomicIntoSortedList(atomic, distsq + dot)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -381,7 +417,7 @@ CVisibilityPlugins::RenderVehicleHiDetailCB_Boat(RpAtomic *atomic) clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic)); distsq = GetDistanceSquaredFromCamera(clumpframe); if(distsq < ms_bigVehicleLod1Dist) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); return atomic; } @@ -403,7 +439,7 @@ CVisibilityPlugins::RenderVehicleLowDetailCB_BigVehicle(RpAtomic *atomic) if(dot > 0.0f) return atomic; } - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -427,7 +463,7 @@ CVisibilityPlugins::RenderVehicleLowDetailAlphaCB_BigVehicle(RpAtomic *atomic) return atomic; if(!InsertAtomicIntoSortedList(atomic, distsq + dot)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -444,7 +480,7 @@ CVisibilityPlugins::RenderVehicleReallyLowDetailCB(RpAtomic *atomic) if(dist >= ms_vehicleLod0Dist){ alpha = GetClumpAlpha(clump); if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else RenderAlphaAtomic(atomic, alpha); } @@ -461,7 +497,7 @@ CVisibilityPlugins::RenderVehicleReallyLowDetailCB_BigVehicle(RpAtomic *atomic) clumpframe = RpClumpGetFrame(RpAtomicGetClump(atomic)); distsq = GetDistanceSquaredFromCamera(clumpframe); if(distsq >= ms_bigVehicleLod1Dist) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); return atomic; } @@ -482,7 +518,7 @@ CVisibilityPlugins::RenderTrainHiDetailCB(RpAtomic *atomic) if(dot > 0.0f && ((flags & ATOMIC_FLAG_ANGLECULL) || 0.1f*distsq < dot*dot)) return atomic; } - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } return atomic; } @@ -507,10 +543,10 @@ CVisibilityPlugins::RenderTrainHiDetailAlphaCB(RpAtomic *atomic) if(flags & ATOMIC_FLAG_DRAWLAST){ // sort before clump if(!InsertAtomicIntoSortedList(atomic, distsq - 0.0001f)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); }else{ if(!InsertAtomicIntoSortedList(atomic, distsq + dot)) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); } } return atomic; @@ -521,7 +557,7 @@ CVisibilityPlugins::RenderPlayerCB(RpAtomic *atomic) { if(CWorld::Players[0].m_pSkinTexture) RpGeometryForAllMaterials(RpAtomicGetGeometry(atomic), SetTextureCB, CWorld::Players[0].m_pSkinTexture); - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); return atomic; } @@ -537,7 +573,7 @@ CVisibilityPlugins::RenderPedLowDetailCB(RpAtomic *atomic) if(dist >= ms_pedLod0Dist){ alpha = GetClumpAlpha(clump); if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else RenderAlphaAtomic(atomic, alpha); } @@ -556,7 +592,7 @@ CVisibilityPlugins::RenderPedHiDetailCB(RpAtomic *atomic) if(dist < ms_pedLod0Dist){ alpha = GetClumpAlpha(clump); if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else RenderAlphaAtomic(atomic, alpha); } @@ -575,7 +611,7 @@ CVisibilityPlugins::RenderPedCB(RpAtomic *atomic) if(RwV3dDotProduct(&cam2atm, &cam2atm) < ms_pedLod1Dist){ alpha = GetClumpAlpha(RpAtomicGetClump(atomic)); if(alpha == 255) - AtomicDefaultRenderCallBack(atomic); + RENDERCALLBACK(atomic); else RenderAlphaAtomic(atomic, alpha); } @@ -775,12 +811,11 @@ CVisibilityPlugins::GetAtomicId(RpAtomic *atomic) return ATOMICEXT(atomic)->flags; } -// This is rather useless, but whatever void CVisibilityPlugins::SetAtomicRenderCallback(RpAtomic *atomic, RpAtomicCallBackRender cb) { if(cb == nil) - cb = AtomicDefaultRenderCallBack; // not necessary + cb = RENDERCALLBACK; RpAtomicSetRenderCallBack(atomic, cb); } diff --git a/src/skel/skeleton.cpp b/src/skel/skeleton.cpp index 4780316a..3166093e 100644 --- a/src/skel/skeleton.cpp +++ b/src/skel/skeleton.cpp @@ -10,6 +10,7 @@ #include "skeleton.h" #include "platform.h" +#include "MemoryHeap.h" @@ -307,6 +308,8 @@ RsRwInitialize(void *displayID) { RwEngineOpenParams openParams; + PUSH_MEMID(MEMID_RENDER); // NB: not popped on failed return + /* * Start RenderWare... */ @@ -374,6 +377,8 @@ RsRwInitialize(void *displayID) RwTextureSetMipmapping(FALSE); RwTextureSetAutoMipmapping(FALSE); + POP_MEMID(); + return TRUE; } diff --git a/src/vehicles/Plane.cpp b/src/vehicles/Plane.cpp index 1a6f1a88..532be938 100644 --- a/src/vehicles/Plane.cpp +++ b/src/vehicles/Plane.cpp @@ -15,6 +15,7 @@ #include "World.h" #include "HandlingMgr.h" #include "Plane.h" +#include "MemoryHeap.h" CPlaneNode *pPathNodes; CPlaneNode *pPath2Nodes; @@ -551,9 +552,11 @@ CPlane::ProcessControl(void) if(m_rwObject && RwObjectGetType(m_rwObject) == rpCLUMP){ DeleteRwObject(); if(mi->m_planeLodId != -1){ + PUSH_MEMID(MEMID_WORLD); m_rwObject = CModelInfo::GetModelInfo(mi->m_planeLodId)->CreateInstance(); + POP_MEMID(); if(m_rwObject) - m_matrix.Attach(RwFrameGetMatrix(RpAtomicGetFrame((RpAtomic*)m_rwObject))); + m_matrix.AttachRW(RwFrameGetMatrix(RpAtomicGetFrame((RpAtomic*)m_rwObject))); } } }else if(CStreaming::HasModelLoaded(GetModelIndex())){ From 8c275c3e01059beb60fcdeb9bc599c762d949eab Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 27 Nov 2020 00:37:09 +0300 Subject: [PATCH 086/129] Update README.md --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 4ee3d2e9..ec9cedc7 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,18 @@ such that we have a working game at all times. ## Preparing the environment for building -- Clone the repo using the argument `--recursive`. -- Point GTA_III_RE_DIR environment variable to GTA3 root folder. -- Run premake - - On Windows: one of the `premake-vsXXXX.cmd` variants on root folder - - On Linux: proceed to [Building on Linux](https://github.com/GTAmodding/re3/wiki/Building-on-Linux). -- There are various settings at the very bottom of [config.h](https://github.com/GTAmodding/re3/tree/master/src/core/config.h), you may want to take a look there. i.e. FIX_BUGS define fixes the bugs we've come across. -- **If you use 64-bit D3D9**: We don't ship 64-bit Dx9 SDK. You need to download it from Microsoft if you don't have it(although it should come pre-installed after some Windows version) +You may want to point GTA_III_RE_DIR environment variable to GTA3 root folder if you want executable to be moved there via post-build script. +- For Linux, proceed: [Building on Linux](https://github.com/GTAmodding/re3/wiki/Building-on-Linux) +- For FreeBSD, proceed: [Building on FreeBSD](https://github.com/GTAmodding/re3/wiki/Building-on-FreeBSD) +- For Windows, assuming you have Visual Studio: + - Clone the repo using the argument `--recursive`. + - Run one of the `premake-vsXXXX.cmd` variants on root folder. + - Open the project via Visual Studio + +**If you use 64-bit D3D9**: We don't ship 64-bit Dx9 SDK. You need to download it from Microsoft if you don't have it(although it should come pre-installed after some Windows version) + +There are various settings at the very bottom of [config.h](https://github.com/GTAmodding/re3/tree/master/src/core/config.h), you may want to take a look there. i.e. FIX_BUGS define fixes the bugs we've come across. > :information_source: **If you choose OpenAL on Windows** You must read [Running OpenAL build on Windows](https://github.com/GTAmodding/re3/wiki/Running-OpenAL-build-on-Windows). From f50a53e2907bcadd5c89781c4d9c025a45c8a113 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Fri, 27 Nov 2020 19:18:51 +0300 Subject: [PATCH 087/129] fix garages --- src/control/Garages.cpp | 10 +++++----- vendor/ogg | 2 +- vendor/opus | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 5a04285f..fc8f84f2 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -1260,9 +1260,9 @@ bool CGarage::IsPlayerOutsideGarage() bool CGarage::IsEntityTouching3D(CEntity * pEntity) { float radius = pEntity->GetBoundRadius(); - if (pEntity->GetPosition().x - radius < m_fX1 || pEntity->GetPosition().x + radius > m_fX2 || - pEntity->GetPosition().y - radius < m_fY1 || pEntity->GetPosition().y + radius > m_fY2 || - pEntity->GetPosition().z - radius < m_fZ1 || pEntity->GetPosition().z + radius > m_fZ2) + if (m_fX1 - radius > pEntity->GetPosition().x || m_fX2 + radius < pEntity->GetPosition().x || + m_fY1 - radius > pEntity->GetPosition().y || m_fY2 + radius < pEntity->GetPosition().y || + m_fZ1 - radius > pEntity->GetPosition().z || m_fZ2 + radius < pEntity->GetPosition().z) return false; CColModel* pColModel = pEntity->GetColModel(); for (int i = 0; i < pColModel->numSpheres; i++) { @@ -1271,9 +1271,9 @@ bool CGarage::IsEntityTouching3D(CEntity * pEntity) if (pos.x + radius > m_fX1 && pos.x - radius < m_fX2 && pos.y + radius > m_fY1 && pos.y - radius < m_fY2 && pos.z + radius > m_fZ1 && pos.z - radius < m_fZ2) - return false; + return true; } - return true; + return false; } bool CGarage::EntityHasASphereWayOutsideGarage(CEntity * pEntity, float fMargin) diff --git a/vendor/ogg b/vendor/ogg index 36f969bb..31bd3f27 160000 --- a/vendor/ogg +++ b/vendor/ogg @@ -1 +1 @@ -Subproject commit 36f969bb37559345ee03796ed625a9abd42c6db9 +Subproject commit 31bd3f2707fb7dbae539a7093ba1fc4b2b37d84e diff --git a/vendor/opus b/vendor/opus index 034c1b61..841d57b8 160000 --- a/vendor/opus +++ b/vendor/opus @@ -1 +1 @@ -Subproject commit 034c1b61a250457649d788bbf983b3f0fb63f02e +Subproject commit 841d57b82a516ccc6e90d1d4aee8d4a7f0d00010 From 18d0fd2e48ab093b953f26b67b769a2d8ab67040 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 28 Nov 2020 15:13:06 +0200 Subject: [PATCH 088/129] Add multisampling to librw --- src/core/config.h | 1 - src/fakerw/fake.cpp | 3 +++ src/fakerw/rwcore.h | 2 ++ src/skel/glfw/glfw.cpp | 5 ++++- vendor/librw | 2 +- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/core/config.h b/src/core/config.h index 6433a258..ead9b787 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -353,5 +353,4 @@ enum Config { #ifdef LIBRW // these are not supported with librw yet -# undef MULTISAMPLING #endif diff --git a/src/fakerw/fake.cpp b/src/fakerw/fake.cpp index 39606335..2e04aed2 100644 --- a/src/fakerw/fake.cpp +++ b/src/fakerw/fake.cpp @@ -601,6 +601,9 @@ void RwD3D8EngineSetRefreshRate(RwUInt32 refreshRate) {} RwBool RwD3D8DeviceSupportsDXTTexture(void) { return true; } +void RwD3D8EngineSetMultiSamplingLevels(RwUInt32 level) { Engine::setMultiSamplingLevels(level); } +RwUInt32 RwD3D8EngineGetMaxMultiSamplingLevels(void) { return Engine::getMaxMultiSamplingLevels(); } + RpMaterial *RpMaterialCreate(void) { return Material::create(); } RwBool RpMaterialDestroy(RpMaterial *material) { material->destroy(); return true; } diff --git a/src/fakerw/rwcore.h b/src/fakerw/rwcore.h index 31bc5541..e5d21865 100644 --- a/src/fakerw/rwcore.h +++ b/src/fakerw/rwcore.h @@ -411,3 +411,5 @@ RwFrame *RwCameraGetFrame(const RwCamera *camera); void RwD3D8EngineSetRefreshRate(RwUInt32 refreshRate); RwBool RwD3D8DeviceSupportsDXTTexture(void); +void RwD3D8EngineSetMultiSamplingLevels(RwUInt32 level); +RwUInt32 RwD3D8EngineGetMaxMultiSamplingLevels(void); diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 2722a4df..617fee18 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -833,7 +833,10 @@ psSelectDevice() PSGLOBAL(fullScreen) = !FrontEndMenuManager.m_nPrefsWindowed; #endif - + +#ifdef MULTISAMPLING + RwD3D8EngineSetMultiSamplingLevels(1 << FrontEndMenuManager.m_nPrefsMSAALevel); +#endif return TRUE; } diff --git a/vendor/librw b/vendor/librw index e8990d5b..2066cf66 160000 --- a/vendor/librw +++ b/vendor/librw @@ -1 +1 @@ -Subproject commit e8990d5b3d50be72594f93dcc42d749f29761516 +Subproject commit 2066cf6634383e056cd5dda105e87f8da04b1ed8 From ad48b9cde01522938590aab444bb09275ff5359d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 28 Nov 2020 16:29:45 +0200 Subject: [PATCH 089/129] Make texture conversion work a bit faster --- src/core/config.h | 1 + src/rw/TexRead.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/core/config.h b/src/core/config.h index ead9b787..99c5f6ef 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -233,6 +233,7 @@ enum Config { #define PS2_ALPHA_TEST // emulate ps2 alpha test #define IMPROVED_VIDEOMODE // save and load videomode parameters instead of a magic number #define DISABLE_LOADING_SCREEN // disable the loading screen which vastly improves the loading time +#define DISABLE_VSYNC_ON_TEXTURE_CONVERSION // make texture conversion work faster by disabling vsync //#define USE_TEXTURE_POOL #ifdef LIBRW //#define EXTENDED_COLOURFILTER // more options for colour filter (replaces mblur) diff --git a/src/rw/TexRead.cpp b/src/rw/TexRead.cpp index 72d2ae17..7403ae1d 100644 --- a/src/rw/TexRead.cpp +++ b/src/rw/TexRead.cpp @@ -18,6 +18,7 @@ #include "Sprite2d.h" #include "Text.h" #include "RwHelper.h" +#include "Frontend.h" #endif //GTA_PC float texLoadTime; @@ -357,6 +358,15 @@ CreateTxdImageForVideoCard() // so let's hope that is the case for all rw::gl3::needToReadBackTextures = true; #endif + +#ifdef DISABLE_VSYNC_ON_TEXTURE_CONVERSION + // let's disable vsync and frame limiter to speed up texture conversion + // (actually we probably don't need to disable frame limiter in here, but let's do it just in case =P) + int8 vsyncState = CMenuManager::m_PrefsVsync; + int8 frameLimiterState = CMenuManager::m_PrefsFrameLimiter; + CMenuManager::m_PrefsVsync = 0; + CMenuManager::m_PrefsFrameLimiter = 0; +#endif int32 i; for (i = 0; i < TXDSTORESIZE; i++) { @@ -411,6 +421,12 @@ CreateTxdImageForVideoCard() } } +#ifdef DISABLE_VSYNC_ON_TEXTURE_CONVERSION + // restore vsync and frame limiter states + CMenuManager::m_PrefsVsync = vsyncState; + CMenuManager::m_PrefsFrameLimiter = frameLimiterState; +#endif + RwStreamClose(img, nil); delete []buf; From a8035b64662e9b9fe6689ec60e5087ff95bc2672 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 28 Nov 2020 16:16:15 +0100 Subject: [PATCH 090/129] moved some stuff to MemoryMgr --- src/animation/AnimBlendAssociation.cpp | 2 +- src/animation/AnimBlendClumpData.cpp | 2 +- src/core/CdStream.cpp | 2 +- src/core/CdStreamPosix.cpp | 2 +- src/core/Streaming.cpp | 1 + src/render/PlayerSkin.cpp | 1 + src/rw/MemoryHeap.cpp | 125 ------------------------ src/rw/MemoryHeap.h | 12 --- src/rw/MemoryMgr.cpp | 130 +++++++++++++++++++++++++ src/rw/MemoryMgr.h | 12 +++ src/skel/glfw/glfw.cpp | 2 +- src/skel/win/win.cpp | 2 +- 12 files changed, 150 insertions(+), 143 deletions(-) create mode 100644 src/rw/MemoryMgr.cpp create mode 100644 src/rw/MemoryMgr.h diff --git a/src/animation/AnimBlendAssociation.cpp b/src/animation/AnimBlendAssociation.cpp index 61d7d69c..b03571b0 100644 --- a/src/animation/AnimBlendAssociation.cpp +++ b/src/animation/AnimBlendAssociation.cpp @@ -5,7 +5,7 @@ #include "RpAnimBlend.h" #include "AnimManager.h" #include "AnimBlendAssociation.h" -#include "MemoryHeap.h" +#include "MemoryMgr.h" CAnimBlendAssociation::CAnimBlendAssociation(void) { diff --git a/src/animation/AnimBlendClumpData.cpp b/src/animation/AnimBlendClumpData.cpp index fd2a58de..92515427 100644 --- a/src/animation/AnimBlendClumpData.cpp +++ b/src/animation/AnimBlendClumpData.cpp @@ -1,7 +1,7 @@ #include "common.h" #include "AnimBlendClumpData.h" -#include "MemoryHeap.h" +#include "MemoryMgr.h" CAnimBlendClumpData::CAnimBlendClumpData(void) diff --git a/src/core/CdStream.cpp b/src/core/CdStream.cpp index a1235930..f987dea5 100644 --- a/src/core/CdStream.cpp +++ b/src/core/CdStream.cpp @@ -5,7 +5,7 @@ #include "CdStream.h" #include "rwcore.h" #include "RwHelper.h" -#include "MemoryHeap.h" +#include "MemoryMgr.h" #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index 35a90a74..0854d850 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -16,7 +16,7 @@ #include "CdStream.h" #include "rwcore.h" -#include "RwHelper.h" +#include "MemoryMgr.h" #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index 628d4923..a28fe39d 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -34,6 +34,7 @@ #include "main.h" #include "Frontend.h" #include "Font.h" +#include "MemoryMgr.h" #include "MemoryHeap.h" bool CStreaming::ms_disableStreaming; diff --git a/src/render/PlayerSkin.cpp b/src/render/PlayerSkin.cpp index d66f7ce4..f0fae45a 100644 --- a/src/render/PlayerSkin.cpp +++ b/src/render/PlayerSkin.cpp @@ -14,6 +14,7 @@ #include "RwHelper.h" #include "Timer.h" #include "Lights.h" +#include "MemoryMgr.h" RpClump *gpPlayerClump; float gOldFov; diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp index 2cf173b6..0b333ce1 100644 --- a/src/rw/MemoryHeap.cpp +++ b/src/rw/MemoryHeap.cpp @@ -494,129 +494,4 @@ CommonSize::Init(uint32 size) m_remaining = 0; } - - -void *pMemoryTop; - -void -InitMemoryMgr(void) -{ -#ifdef GTA_PS2 -#error "finish this" -#else - // randomly allocate 128mb - gMainHeap.Init(128*1024*1024); #endif -} - - -RwMemoryFunctions memFuncs = { - MemoryMgrMalloc, - MemoryMgrFree, - MemoryMgrRealloc, - MemoryMgrCalloc -}; - -#ifdef USE_CUSTOM_ALLOCATOR -// game seems to be using heap directly here, but this is nicer -void *operator new(size_t sz) { return MemoryMgrMalloc(sz); } -void *operator new[](size_t sz) { return MemoryMgrMalloc(sz); } -void operator delete(void *ptr) noexcept { MemoryMgrFree(ptr); } -void operator delete[](void *ptr) noexcept { MemoryMgrFree(ptr); } -#endif -#endif - -void* -MemoryMgrMalloc(uint32 size) -{ -#ifdef USE_CUSTOM_ALLOCATOR - void *mem = gMainHeap.Malloc(size); -#else - void *mem = malloc(size); -#endif - if(mem > pMemoryTop) - pMemoryTop = mem; - return mem; -} - -void* -MemoryMgrRealloc(void *ptr, uint32 size) -{ -#ifdef USE_CUSTOM_ALLOCATOR - void *mem = gMainHeap.Realloc(ptr, size); -#else - void *mem = realloc(ptr, size); -#endif - if(mem > pMemoryTop) - pMemoryTop = mem; - return mem; -} - -void* -MemoryMgrCalloc(uint32 num, uint32 size) -{ -#ifdef USE_CUSTOM_ALLOCATOR - void *mem = gMainHeap.Malloc(num*size); -#else - void *mem = calloc(num, size); -#endif - if(mem > pMemoryTop) - pMemoryTop = mem; -#ifdef FIX_BUGS - memset(mem, 0, num*size); -#endif - return mem; -} - -void -MemoryMgrFree(void *ptr) -{ -#ifdef USE_CUSTOM_ALLOCATOR -#ifdef FIX_BUGS - // i don't suppose this is handled by RW? - if(ptr == nil) return; -#endif - gMainHeap.Free(ptr); -#else - free(ptr); -#endif -} - -void * -RwMallocAlign(RwUInt32 size, RwUInt32 align) -{ -#ifdef FIX_BUGS - uintptr ptralign = align-1; - void *mem = (void *)MemoryMgrMalloc(size + sizeof(uintptr) + ptralign); - - ASSERT(mem != nil); - - void *addr = (void *)((((uintptr)mem) + sizeof(uintptr) + ptralign) & ~ptralign); - - ASSERT(addr != nil); -#else - void *mem = (void *)MemoryMgrMalloc(size + align); - - ASSERT(mem != nil); - - void *addr = (void *)((((uintptr)mem) + align) & ~(align - 1)); - - ASSERT(addr != nil); -#endif - - *(((void **)addr) - 1) = mem; - - return addr; -} - -void -RwFreeAlign(void *mem) -{ - ASSERT(mem != nil); - - void *addr = *(((void **)mem) - 1); - - ASSERT(addr != nil); - - MemoryMgrFree(addr); -} diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h index 22e13617..484cbfab 100644 --- a/src/rw/MemoryHeap.h +++ b/src/rw/MemoryHeap.h @@ -62,18 +62,6 @@ enum { NUM_FIXED_MEMBLOCKS = 6 }; -extern RwMemoryFunctions memFuncs; -void InitMemoryMgr(void); - -void *MemoryMgrMalloc(uint32 size); -void *MemoryMgrRealloc(void *ptr, uint32 size); -void *MemoryMgrCalloc(uint32 num, uint32 size); -void MemoryMgrFree(void *ptr); - -void *RwMallocAlign(RwUInt32 size, RwUInt32 align); -void RwFreeAlign(void *mem); - - template class CStack { diff --git a/src/rw/MemoryMgr.cpp b/src/rw/MemoryMgr.cpp new file mode 100644 index 00000000..ef0ecbdf --- /dev/null +++ b/src/rw/MemoryMgr.cpp @@ -0,0 +1,130 @@ +#include "common.h" +#include "MemoryHeap.h" +#include "MemoryMgr.h" + + +void *pMemoryTop; + +void +InitMemoryMgr(void) +{ +#ifdef USE_CUSTOM_ALLOCATOR +#ifdef GTA_PS2 +#error "finish this" +#else + // randomly allocate 128mb + gMainHeap.Init(128*1024*1024); +#endif +#endif +} + + +RwMemoryFunctions memFuncs = { + MemoryMgrMalloc, + MemoryMgrFree, + MemoryMgrRealloc, + MemoryMgrCalloc +}; + +#ifdef USE_CUSTOM_ALLOCATOR +// game seems to be using heap directly here, but this is nicer +void *operator new(size_t sz) { return MemoryMgrMalloc(sz); } +void *operator new[](size_t sz) { return MemoryMgrMalloc(sz); } +void operator delete(void *ptr) noexcept { MemoryMgrFree(ptr); } +void operator delete[](void *ptr) noexcept { MemoryMgrFree(ptr); } +#endif + +void* +MemoryMgrMalloc(size_t size) +{ +#ifdef USE_CUSTOM_ALLOCATOR + void *mem = gMainHeap.Malloc(size); +#else + void *mem = malloc(size); +#endif + if(mem > pMemoryTop) + pMemoryTop = mem; + return mem; +} + +void* +MemoryMgrRealloc(void *ptr, size_t size) +{ +#ifdef USE_CUSTOM_ALLOCATOR + void *mem = gMainHeap.Realloc(ptr, size); +#else + void *mem = realloc(ptr, size); +#endif + if(mem > pMemoryTop) + pMemoryTop = mem; + return mem; +} + +void* +MemoryMgrCalloc(size_t num, size_t size) +{ +#ifdef USE_CUSTOM_ALLOCATOR + void *mem = gMainHeap.Malloc(num*size); +#else + void *mem = calloc(num, size); +#endif + if(mem > pMemoryTop) + pMemoryTop = mem; +#ifdef FIX_BUGS + memset(mem, 0, num*size); +#endif + return mem; +} + +void +MemoryMgrFree(void *ptr) +{ +#ifdef USE_CUSTOM_ALLOCATOR +#ifdef FIX_BUGS + // i don't suppose this is handled by RW? + if(ptr == nil) return; +#endif + gMainHeap.Free(ptr); +#else + free(ptr); +#endif +} + +void * +RwMallocAlign(RwUInt32 size, RwUInt32 align) +{ +#ifdef FIX_BUGS + uintptr ptralign = align-1; + void *mem = (void *)MemoryMgrMalloc(size + sizeof(uintptr) + ptralign); + + ASSERT(mem != nil); + + void *addr = (void *)((((uintptr)mem) + sizeof(uintptr) + ptralign) & ~ptralign); + + ASSERT(addr != nil); +#else + void *mem = (void *)MemoryMgrMalloc(size + align); + + ASSERT(mem != nil); + + void *addr = (void *)((((uintptr)mem) + align) & ~(align - 1)); + + ASSERT(addr != nil); +#endif + + *(((void **)addr) - 1) = mem; + + return addr; +} + +void +RwFreeAlign(void *mem) +{ + ASSERT(mem != nil); + + void *addr = *(((void **)mem) - 1); + + ASSERT(addr != nil); + + MemoryMgrFree(addr); +} diff --git a/src/rw/MemoryMgr.h b/src/rw/MemoryMgr.h new file mode 100644 index 00000000..e2962806 --- /dev/null +++ b/src/rw/MemoryMgr.h @@ -0,0 +1,12 @@ +#pragma once + +extern RwMemoryFunctions memFuncs; +void InitMemoryMgr(void); + +void *MemoryMgrMalloc(size_t size); +void *MemoryMgrRealloc(void *ptr, size_t size); +void *MemoryMgrCalloc(size_t num, size_t size); +void MemoryMgrFree(void *ptr); + +void *RwMallocAlign(RwUInt32 size, RwUInt32 align); +void RwFreeAlign(void *mem); diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 2722a4df..0bde1282 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -40,7 +40,7 @@ #include "Sprite2d.h" #include "AnimViewer.h" #include "Font.h" -#include "MemoryHeap.h" +#include "MemoryMgr.h" #define MAX_SUBSYSTEMS (16) diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index b4897d67..5f6d662c 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -97,7 +97,7 @@ static psGlobalType PsGlobal; #include "Sprite2d.h" #include "AnimViewer.h" #include "Font.h" -#include "MemoryHeap.h" +#include "MemoryMgr.h" VALIDATE_SIZE(psGlobalType, 0x28); From b1a431a740c9bde92e9169c041909cebfa705ae5 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sat, 28 Nov 2020 17:57:10 +0100 Subject: [PATCH 091/129] add -console cmdline arg instead of #if 0/1 --- src/skel/glfw/glfw.cpp | 14 ++++++++------ src/skel/win/win.cpp | 18 ++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 617fee18..c4a3cad1 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -1453,12 +1453,14 @@ WinMain(HINSTANCE instance, RwChar** argv; SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE); -#if 0 - // TODO: make this an option somewhere - AllocConsole(); - freopen("CONIN$", "r", stdin); - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); +#ifndef MASTER + if (strstr(cmdLine, "-console")) + { + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + } #endif #else diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index b4897d67..4dc8c3f0 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -2011,16 +2011,18 @@ WinMain(HINSTANCE instance, RwChar **argv; SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, nil, SPIF_SENDCHANGE); -#ifdef USE_CUSTOM_ALLOCATOR - InitMemoryMgr(); +#ifndef MASTER + if (strstr(cmdLine, "-console")) + { + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + } #endif -#if 1 - // TODO: make this an option somewhere - AllocConsole(); - freopen("CONIN$", "r", stdin); - freopen("CONOUT$", "w", stdout); - freopen("CONOUT$", "w", stderr); +#ifdef USE_CUSTOM_ALLOCATOR + InitMemoryMgr(); #endif /* From 52826966993a4d91afcbda44ee2e3c9966f9087d Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 29 Nov 2020 11:36:26 +0100 Subject: [PATCH 092/129] fix backface culling on vehicles --- src/render/Renderer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 83bd0d21..a0f66819 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -216,6 +216,7 @@ CRenderer::RenderOneNonRoad(CEntity *e) e->Render(); if(e->IsVehicle()){ + BACKFACE_CULLING_OFF; e->bImBeingRendered = true; CVisibilityPlugins::RenderAlphaAtomics(); e->bImBeingRendered = false; From 566282057abbc8e9d5f331c8125a38b00b39fee0 Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 29 Nov 2020 11:37:06 +0100 Subject: [PATCH 093/129] add debug script hotkey --- src/core/Frontend.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index b84b691d..318e5903 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -4157,12 +4157,22 @@ CMenuManager::ProcessButtonPresses(void) DoSettingsBeforeStartingAGame(); return; } + if (glfwGetKey(PSGLOBAL(window), GLFW_KEY_D) == GLFW_PRESS) { + scriptToLoad = 2; + DoSettingsBeforeStartingAGame(); + return; + } #elif defined _WIN32 if (GetAsyncKeyState('R') & 0x8000) { scriptToLoad = 1; DoSettingsBeforeStartingAGame(); return; } + if (GetAsyncKeyState('D') & 0x8000) { + scriptToLoad = 2; + DoSettingsBeforeStartingAGame(); + return; + } #endif } #endif From d5bc382cb51c5ef5af618377d190e6f34e893314 Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 29 Nov 2020 12:26:34 +0100 Subject: [PATCH 094/129] GTA_VERSION define and some config.h cleanup --- src/audio/sampman_miles.cpp | 16 ++++----- src/control/Script.cpp | 2 +- src/control/Script6.cpp | 2 +- src/control/ScriptCommands.h | 2 +- src/core/Cam.cpp | 4 +-- src/core/Camera.cpp | 8 ++--- src/core/Frontend.cpp | 14 ++++---- src/core/MenuScreensCustom.cpp | 2 +- src/core/Pad.cpp | 2 +- src/core/config.h | 26 ++++++++++----- src/entities/Physical.cpp | 2 +- src/modelinfo/VehicleModelInfo.cpp | 2 +- src/peds/CopPed.cpp | 2 +- src/render/2dEffect.h | 4 +-- src/render/Clouds.cpp | 10 +++--- src/render/Particle.cpp | 52 +++++++++++++++--------------- src/render/Rubbish.cpp | 8 ++--- src/render/Skidmarks.cpp | 6 ++-- src/skel/glfw/glfw.cpp | 4 +-- src/skel/win/win.cpp | 4 +-- src/vehicles/Vehicle.cpp | 2 +- src/weapons/WeaponEffects.cpp | 2 +- vendor/ogg | 2 +- vendor/opus | 2 +- vendor/opusfile | 2 +- 25 files changed, 96 insertions(+), 86 deletions(-) diff --git a/src/audio/sampman_miles.cpp b/src/audio/sampman_miles.cpp index 185e08d6..db38da64 100644 --- a/src/audio/sampman_miles.cpp +++ b/src/audio/sampman_miles.cpp @@ -65,7 +65,7 @@ uint32 _CurMP3Index; int32 _CurMP3Pos; bool _bIsMp3Active; -#if defined(GTA3_1_1_PATCH) || defined(GTA3_STEAM_PATCH) || defined(NO_CDCHECK) +#if GTA_VERSION >= GTA3_PC_11 || defined(NO_CDCHECK) bool _bUseHDDAudio; char _aHDDPath[MAX_PATH]; #endif @@ -1043,7 +1043,7 @@ cSampleManager::Initialise(void) if ( !m_bInitialised ) { -#if !defined(GTA3_STEAM_PATCH) && !defined(NO_CDCHECK) +#if GTA_VERSION < GTA3_PC_STEAM && !defined(NO_CDCHECK) FrontEndMenuManager.WaitForUserCD(); if ( FrontEndMenuManager.m_bQuitGameNoCD ) { @@ -1060,7 +1060,7 @@ cSampleManager::Initialise(void) } } -#if defined(GTA3_1_1_PATCH) || defined(GTA3_STEAM_PATCH) || defined(NO_CDCHECK) +#if GTA_VERSION >= GTA3_PC_11 || defined(NO_CDCHECK) // hddaudio /** Option for user to play audio files directly from hard disk. @@ -1297,17 +1297,17 @@ cSampleManager::Terminate(void) bool cSampleManager::CheckForAnAudioFileOnCD(void) { -#if !defined(GTA3_STEAM_PATCH) && !defined(NO_CDCHECK) +#if GTA_VERSION < GTA3_PC_STEAM && !defined(NO_CDCHECK) char filepath[MAX_PATH]; -#if defined(GTA3_1_1_PATCH) +#if GTA_VERSION >= GTA3_PC_11 if (_bUseHDDAudio) strcpy(filepath, _aHDDPath); else strcpy(filepath, m_szCDRomRootPath); #else strcpy(filepath, m_szCDRomRootPath); -#endif // #if defined(GTA3_1_1_PATCH) +#endif // #if GTA_VERSION >= GTA3_PC_11 strcat(filepath, StreamedNameTable[AudioManager.GetRandomNumber(1) % TOTAL_STREAMED_SOUNDS]); @@ -1324,13 +1324,13 @@ cSampleManager::CheckForAnAudioFileOnCD(void) #else return true; -#endif // #if !defined(GTA3_STEAM_PATCH) && !defined(NO_CDCHECK) +#endif // #if GTA_VERSION < GTA3_PC_STEAM && !defined(NO_CDCHECK) } char cSampleManager::GetCDAudioDriveLetter(void) { -#if defined(GTA3_1_1_PATCH) || defined(GTA3_STEAM_PATCH) || defined(NO_CDCHECK) +#if GTA_VERSION >= GTA3_PC_11 || defined(NO_CDCHECK) if (_bUseHDDAudio) { if ( strlen(_aHDDPath) != 0 ) diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 085c773a..dbd477e2 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -1273,7 +1273,7 @@ const tScriptCommandData commands[] = { REGISTER_COMMAND(COMMAND_IS_CHAR_LYING_DOWN, INPUT_ARGUMENTS(ARGTYPE_INT,), OUTPUT_ARGUMENTS(), true, -1, ""), REGISTER_COMMAND(COMMAND_CAN_CHAR_SEE_DEAD_CHAR, INPUT_ARGUMENTS(ARGTYPE_INT, ARGTYPE_INT,), OUTPUT_ARGUMENTS(), true, -1, ""), REGISTER_COMMAND(COMMAND_SET_ENTER_CAR_RANGE_MULTIPLIER, INPUT_ARGUMENTS(ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, -1, ""), -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 REGISTER_COMMAND(COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER, INPUT_ARGUMENTS(ARGTYPE_FLOAT,), OUTPUT_ARGUMENTS(), false, -1, ""), #endif #endif diff --git a/src/control/Script6.cpp b/src/control/Script6.cpp index ca6a1853..acd9e424 100644 --- a/src/control/Script6.cpp +++ b/src/control/Script6.cpp @@ -1326,7 +1326,7 @@ int8 CRunningScript::ProcessCommands1100To1199(int32 command) #endif return 0; #endif -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 case COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER: CollectParameters(&m_nIp, 1); #ifdef FIX_BUGS diff --git a/src/control/ScriptCommands.h b/src/control/ScriptCommands.h index 56908edb..b9067bea 100644 --- a/src/control/ScriptCommands.h +++ b/src/control/ScriptCommands.h @@ -1156,7 +1156,7 @@ enum { COMMAND_IS_CHAR_LYING_DOWN, COMMAND_CAN_CHAR_SEE_DEAD_CHAR, COMMAND_SET_ENTER_CAR_RANGE_MULTIPLIER, -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 COMMAND_SET_THREAT_REACTION_RANGE_MULTIPLIER, #endif #ifdef USE_ADVANCED_SCRIPT_DEBUG_OUTPUT diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 3e016667..0e1c9d9f 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -2570,7 +2570,7 @@ CCam::Process_M16_1stPerson(const CVector &CameraTarget, float, float, float) ResetStatics = false; } -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 ((CPed*)CamTargetEntity)->m_pedIK.GetComponentPosition(&HeadPos, PED_HEAD); Source = HeadPos; Source.z += 0.1f; @@ -2605,7 +2605,7 @@ CCam::Process_M16_1stPerson(const CVector &CameraTarget, float, float, float) if(Alpha > DEGTORAD(60.0f)) Alpha = DEGTORAD(60.0f); else if(Alpha < -DEGTORAD(89.5f)) Alpha = -DEGTORAD(89.5f); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 HeadPos.x = 0.0f; HeadPos.y = 0.0f; HeadPos.z = 0.0f; diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 56225fed..1e1aa722 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -74,7 +74,7 @@ bool bDidWeProcessAnyCinemaCam; CCamera::CCamera(void) { -#if defined(GTA3_1_1_PATCH) || defined(FIX_BUGS) +#if GTA_VERSION >= GTA3_PC_11 || defined(FIX_BUGS) m_fMouseAccelHorzntl = 0.0025f; m_fMouseAccelVertical = 0.003f; #endif @@ -88,7 +88,7 @@ CCamera::CCamera(float) void CCamera::Init(void) { -#if defined(GTA3_1_1_PATCH) || defined(FIX_BUGS) +#if GTA_VERSION >= GTA3_PC_11 || defined(FIX_BUGS) float fMouseAccelHorzntl = m_fMouseAccelHorzntl; float fMouseAccelVertical = m_fMouseAccelVertical; #endif @@ -104,7 +104,7 @@ CCamera::Init(void) memset(this, 0, sizeof(CCamera)); // getting rid of vtable, eh? #endif - #if defined(GTA3_1_1_PATCH) || defined(FIX_BUGS) + #if GTA_VERSION >= GTA3_PC_11 || defined(FIX_BUGS) m_fMouseAccelHorzntl = fMouseAccelHorzntl; m_fMouseAccelVertical = fMouseAccelVertical; #endif @@ -237,7 +237,7 @@ CCamera::Init(void) m_uiTransitionState = 0; m_uiTimeTransitionStart = 0; m_bLookingAtPlayer = true; -#if !defined(GTA3_1_1_PATCH) && !defined(FIX_BUGS) +#if GTA_VERSION < GTA3_PC_11 && !defined(FIX_BUGS) m_fMouseAccelHorzntl = 0.0025f; m_fMouseAccelVertical = 0.003f; #endif diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index 318e5903..5597b358 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -1009,7 +1009,7 @@ CMenuManager::Draw() CFont::SetCentreOff(); CFont::SetJustifyOn(); CFont::SetBackGroundOnlyTextOn(); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 #ifdef DRAW_MENU_VERSION_TEXT CFont::SetColor(CRGBA(235, 170, 50, FadeIn(255))); CFont::SetRightJustifyOn(); @@ -3538,7 +3538,7 @@ CMenuManager::LoadAllTextures() CTxdStore::LoadTxd(frontendTxdSlot, "MODELS/FRONTEND.TXD"); CTxdStore::AddRef(frontendTxdSlot); CTxdStore::SetCurrentTxd(frontendTxdSlot); -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 CStreaming::IHaveUsedStreamingMemory(); CTimer::Update(); #endif @@ -3568,7 +3568,7 @@ CMenuManager::LoadAllTextures() m_aMapSprites[i].SetAddressing(rwTEXTUREADDRESSBORDER); } #endif -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 CStreaming::IHaveUsedStreamingMemory(); CTimer::Update(); #endif @@ -3583,7 +3583,7 @@ CMenuManager::LoadSettings() int fileHandle = CFileMgr::OpenFile("gta3.set", "r"); int32 prevLang = m_PrefsLanguage; -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 CMBlur::BlurOn = (_dwOperatingSystemVersion != OS_WIN98); #else CMBlur::BlurOn = true; @@ -3882,7 +3882,7 @@ void CMenuManager::PrintStats() { int rowNum = ConstructStatLine(99999); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); #endif CFont::SetScale(MENU_X(MENU_TEXT_SIZE_X * 0.7), MENU_Y(MENU_TEXT_SIZE_Y * 0.9)); // second mulipliers are double, idk why @@ -4936,7 +4936,7 @@ CMenuManager::ProcessButtonPresses(void) m_PrefsUseWideScreen = false; m_PrefsShowSubtitles = true; m_nDisplayVideoMode = m_nPrefsVideoMode; -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 if (_dwOperatingSystemVersion == OS_WIN98) { CMBlur::BlurOn = false; CMBlur::MotionBlurClose(); @@ -5588,7 +5588,7 @@ CMenuManager::WaitForUserCD() CSprite2d *splash; char *splashscreen = nil; -#if (!(defined RANDOMSPLASH) && !(defined GTA3_1_1_PATCH)) +#if (!(defined RANDOMSPLASH) && GTA_VERSION < GTA3_PC_11) if (CGame::frenchGame || CGame::germanGame || !CGame::nastyGame) splashscreen = "mainsc2"; else diff --git a/src/core/MenuScreensCustom.cpp b/src/core/MenuScreensCustom.cpp index f8ff3acf..ae08f5f5 100644 --- a/src/core/MenuScreensCustom.cpp +++ b/src/core/MenuScreensCustom.cpp @@ -115,7 +115,7 @@ void RestoreDefGraphics(int8 action) { CMenuManager::m_PrefsVsync = true; CMenuManager::m_PrefsUseWideScreen = false; FrontEndMenuManager.m_nDisplayVideoMode = FrontEndMenuManager.m_nPrefsVideoMode; - #ifdef GTA3_1_1_PATCH + #if GTA_VERSION >= GTA3_PC_11 if (_dwOperatingSystemVersion == OS_WIN98) { CMBlur::BlurOn = false; CMBlur::MotionBlurClose(); diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index 9c6bdc98..b971f3ec 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -937,7 +937,7 @@ void CPad::AddToPCCheatString(char c) if ( !_CHEATCMP("GNIROOOOOB") ) SlowTimeCheat(); -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 // "TURTOISE" if ( !_CHEATCMP("ESIOTRUT") ) ArmourCheat(); diff --git a/src/core/config.h b/src/core/config.h index 99c5f6ef..5d528d50 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -135,10 +135,6 @@ enum Config { NUM_EXPLOSIONS = 48, }; -// We'll use this once we're ready to become independent of the game -// Use it to mark bugs in the code that will prevent the game from working then -//#define STANDALONE - // We don't expect to compile for PS2 or Xbox // but it might be interesting for documentation purposes #define GTA_PC @@ -165,6 +161,16 @@ enum Config { #define FINAL #endif +// Version defines +#define GTA3_PS2_140 300 +#define GTA3_PS2_160 301 +#define GTA3_PC_10 310 +#define GTA3_PC_11 311 +#define GTA3_PC_STEAM 312 +// TODO? maybe something for xbox or android? + +#define GTA_VERSION GTA3_PC_11 + // quality of life fixes that should also be in FINAL #define NASTY_GAME // nasty game for all languages #define NO_CDCHECK @@ -173,14 +179,18 @@ enum Config { #define DRAW_GAME_VERSION_TEXT #define DRAW_MENU_VERSION_TEXT +// Memory allocation and compression +// #define USE_CUSTOM_ALLOCATOR // use CMemoryHeap for allocation. use with care, not finished yet +//#define COMPRESSED_COL_VECTORS // use compressed vectors for collision vertices +//#define ANIM_COMPRESSION // only keep most recently used anims uncompressed + #if defined GTA_PS2 # define GTA_PS2_STUFF # define RANDOMSPLASH +# define USE_CUSTOM_ALLOCATOR # define VU_COLLISION # define ANIM_COMPRESSION #elif defined GTA_PC -# define GTA3_1_1_PATCH -//# define GTA3_STEAM_PATCH # ifdef GTA_PS2_STUFF # define USE_PS2_RAND # define RANDOMSPLASH // use random splash as on PS2 @@ -190,7 +200,7 @@ enum Config { #endif #ifdef VU_COLLISION -#define COMPRESSED_COL_VECTORS // current need compressed vectors in this code +#define COMPRESSED_COL_VECTORS // currently need compressed vectors in this code #endif #ifdef MASTER @@ -242,7 +252,7 @@ enum Config { #endif #ifndef EXTENDED_COLOURFILTER -#undef SCREEN_DROPLETS // we need the frontbuffer for this effect +#undef SCREEN_DROPLETS // we need the backbuffer for this effect #endif #ifndef EXTENDED_PIPELINES #undef SCREEN_DROPLETS // we need neo.txd diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 172bae3f..04cec96b 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -824,7 +824,7 @@ CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CV normalSpeed = DotProduct(speed, colpoint.normal); if(normalSpeed < 0.0f){ float minspeed = 1.3f*GRAVITY * CTimer::GetTimeStep(); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 if ((IsObject() || IsVehicle() && (GetUp().z < -0.3f || ((CVehicle*)this)->IsBike() && (GetStatus() == STATUS_ABANDONED || GetStatus() == STATUS_WRECKED))) && #else if((IsObject() || IsVehicle() && GetUp().z < -0.3f) && diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index 5b212f62..afda70d3 100644 --- a/src/modelinfo/VehicleModelInfo.cpp +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -962,7 +962,7 @@ CVehicleModelInfo::DeleteVehicleColourTextures(void) for(i = 0; i < 256; i++){ if(ms_colourTextureTable[i]){ RwTextureDestroy(ms_colourTextureTable[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 ms_colourTextureTable[i] = nil; #endif } diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index f289697e..d9f55559 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -667,7 +667,7 @@ CCopPed::ProcessControl(void) } if (bDuckAndCover) { -#if !defined(GTA3_1_1_PATCH) && !defined(VC_PED_PORTS) +#if GTA_VERSION < GTA3_PC_11 && !defined(VC_PED_PORTS) if (!bNotAllowedToDuck && Seek()) { SetMoveState(PEDMOVE_STILL); SetMoveAnim(); diff --git a/src/render/2dEffect.h b/src/render/2dEffect.h index 628d64c2..a8013b34 100644 --- a/src/render/2dEffect.h +++ b/src/render/2dEffect.h @@ -78,12 +78,12 @@ public: if(type == EFFECT_LIGHT){ if(light.corona) RwTextureDestroy(light.corona); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 light.corona = nil; #endif if(light.shadow) RwTextureDestroy(light.shadow); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 light.shadow = nil; #endif } diff --git a/src/render/Clouds.cpp b/src/render/Clouds.cpp index 05ddbcdc..161418b9 100644 --- a/src/render/Clouds.cpp +++ b/src/render/Clouds.cpp @@ -44,23 +44,23 @@ void CClouds::Shutdown(void) { RwTextureDestroy(gpCloudTex[0]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCloudTex[0] = nil; #endif RwTextureDestroy(gpCloudTex[1]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCloudTex[1] = nil; #endif RwTextureDestroy(gpCloudTex[2]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCloudTex[2] = nil; #endif RwTextureDestroy(gpCloudTex[3]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCloudTex[3] = nil; #endif RwTextureDestroy(gpCloudTex[4]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCloudTex[4] = nil; #endif } diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index acce946b..2b19486e 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -590,7 +590,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_SMOKE_FILES; i++ ) { RwTextureDestroy(gpSmokeTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpSmokeTex[i] = nil; #endif } @@ -598,7 +598,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_SMOKE2_FILES; i++ ) { RwTextureDestroy(gpSmoke2Tex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpSmoke2Tex[i] = nil; #endif } @@ -606,7 +606,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_RUBBER_FILES; i++ ) { RwTextureDestroy(gpRubberTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRubberTex[i] = nil; #endif } @@ -614,7 +614,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_RAINSPLASH_FILES; i++ ) { RwTextureDestroy(gpRainSplashTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRainSplashTex[i] = nil; #endif } @@ -622,7 +622,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_WATERSPRAY_FILES; i++ ) { RwTextureDestroy(gpWatersprayTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpWatersprayTex[i] = nil; #endif } @@ -630,7 +630,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_EXPLOSIONMEDIUM_FILES; i++ ) { RwTextureDestroy(gpExplosionMediumTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpExplosionMediumTex[i] = nil; #endif } @@ -638,7 +638,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_GUNFLASH_FILES; i++ ) { RwTextureDestroy(gpGunFlashTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpGunFlashTex[i] = nil; #endif } @@ -646,7 +646,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_RAINDROP_FILES; i++ ) { RwTextureDestroy(gpRainDropTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRainDropTex[i] = nil; #endif } @@ -654,7 +654,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_RAINSPLASHUP_FILES; i++ ) { RwTextureDestroy(gpRainSplashupTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRainSplashupTex[i] = nil; #endif } @@ -662,7 +662,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_BIRDFRONT_FILES; i++ ) { RwTextureDestroy(gpBirdfrontTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpBirdfrontTex[i] = nil; #endif } @@ -670,7 +670,7 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_CARDEBRIS_FILES; i++ ) { RwTextureDestroy(gpCarDebrisTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCarDebrisTex[i] = nil; #endif } @@ -678,78 +678,78 @@ void CParticle::Shutdown() for ( int32 i = 0; i < MAX_CARSPLASH_FILES; i++ ) { RwTextureDestroy(gpCarSplashTex[i]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCarSplashTex[i] = nil; #endif } RwTextureDestroy(gpFlame1Tex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpFlame1Tex = nil; #endif RwTextureDestroy(gpFlame5Tex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpFlame5Tex = nil; #endif RwTextureDestroy(gpRainDropSmallTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRainDropSmallTex = nil; #endif RwTextureDestroy(gpBloodTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpBloodTex = nil; #endif RwTextureDestroy(gpLeafTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpLeafTex = nil; #endif RwTextureDestroy(gpCloudTex1); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCloudTex1 = nil; #endif RwTextureDestroy(gpCloudTex4); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCloudTex4 = nil; #endif RwTextureDestroy(gpBloodSmallTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpBloodSmallTex = nil; #endif RwTextureDestroy(gpGungeTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpGungeTex = nil; #endif RwTextureDestroy(gpCollisionSmokeTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCollisionSmokeTex = nil; #endif RwTextureDestroy(gpBulletHitTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpBulletHitTex = nil; #endif RwTextureDestroy(gpGunShellTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpGunShellTex = nil; #endif RwTextureDestroy(gpWakeOldTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpWakeOldTex = nil; #endif RwTextureDestroy(gpPointlightTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpPointlightTex = nil; #endif diff --git a/src/render/Rubbish.cpp b/src/render/Rubbish.cpp index bfd50c07..18a20bc7 100644 --- a/src/render/Rubbish.cpp +++ b/src/render/Rubbish.cpp @@ -414,19 +414,19 @@ void CRubbish::Shutdown(void) { RwTextureDestroy(gpRubbishTexture[0]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRubbishTexture[0] = nil; #endif RwTextureDestroy(gpRubbishTexture[1]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRubbishTexture[1] = nil; #endif RwTextureDestroy(gpRubbishTexture[2]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRubbishTexture[2] = nil; #endif RwTextureDestroy(gpRubbishTexture[3]); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpRubbishTexture[3] = nil; #endif } diff --git a/src/render/Skidmarks.cpp b/src/render/Skidmarks.cpp index ad036d58..9e509b52 100644 --- a/src/render/Skidmarks.cpp +++ b/src/render/Skidmarks.cpp @@ -54,15 +54,15 @@ void CSkidmarks::Shutdown(void) { RwTextureDestroy(gpSkidTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpSkidTex = nil; #endif RwTextureDestroy(gpSkidBloodTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpSkidBloodTex = nil; #endif RwTextureDestroy(gpSkidMudTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpSkidMudTex = nil; #endif } diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 56877d37..cad84b8a 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -389,7 +389,7 @@ psInitialize(void) InitialiseLanguage(); -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION < GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif @@ -443,7 +443,7 @@ psInitialize(void) #ifndef PS2_MENU -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 5f6d662c..6d0c2d67 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -651,7 +651,7 @@ psInitialize(void) C_PcSave::SetSaveDirectory(_psGetUserFilesFolder()); InitialiseLanguage(); -#ifndef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif @@ -703,7 +703,7 @@ psInitialize(void) #ifndef PS2_MENU -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 FrontEndMenuManager.LoadSettings(); #endif diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index d2ca5a1a..9adcf148 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -405,7 +405,7 @@ CVehicle::FlyingControl(eFlightModel flightModel) else fThrust = fThrustVar * (CPad::GetPad(0)->GetAccelerate() - 2 * CPad::GetPad(0)->GetBrake()) / 255.0f + 0.95f; fThrust -= fRotorFallOff * DotProduct(m_vecMoveSpeed, GetUp()); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 if (fThrust > 0.9f && GetPosition().z > 80.0f) fThrust = 0.9f; #endif diff --git a/src/weapons/WeaponEffects.cpp b/src/weapons/WeaponEffects.cpp index 46195d2c..214ae9c7 100644 --- a/src/weapons/WeaponEffects.cpp +++ b/src/weapons/WeaponEffects.cpp @@ -46,7 +46,7 @@ void CWeaponEffects::Shutdown(void) { RwTextureDestroy(gpCrossHairTex); -#ifdef GTA3_1_1_PATCH +#if GTA_VERSION >= GTA3_PC_11 gpCrossHairTex = nil; #endif } diff --git a/vendor/ogg b/vendor/ogg index 31bd3f27..684c7377 160000 --- a/vendor/ogg +++ b/vendor/ogg @@ -1 +1 @@ -Subproject commit 31bd3f2707fb7dbae539a7093ba1fc4b2b37d84e +Subproject commit 684c73773e7e2683245ffd6aa75f04115b51123a diff --git a/vendor/opus b/vendor/opus index 841d57b8..6bae366f 160000 --- a/vendor/opus +++ b/vendor/opus @@ -1 +1 @@ -Subproject commit 841d57b82a516ccc6e90d1d4aee8d4a7f0d00010 +Subproject commit 6bae366f9fef25191fc812c430e8abd40a13a233 diff --git a/vendor/opusfile b/vendor/opusfile index 4174c26e..6452e838 160000 --- a/vendor/opusfile +++ b/vendor/opusfile @@ -1 +1 @@ -Subproject commit 4174c26e0aaab19d01afdea0a46f7f95fdc6b3e6 +Subproject commit 6452e838e68e8f4fc0b3599523c760ac6276ce89 From 8f05ccd6c4608172ae4c9a589d2b2c4ce915eb2c Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Mon, 30 Nov 2020 02:15:03 +0300 Subject: [PATCH 095/129] small garages revision + small template stuff --- src/control/Garages.cpp | 202 +++++++++++++++++++++------------------- src/control/Garages.h | 3 +- src/control/Phones.cpp | 2 +- src/control/Pickups.cpp | 2 +- src/control/Script3.cpp | 4 +- src/control/Script5.cpp | 12 +-- src/core/World.cpp | 8 ++ src/core/templates.h | 12 ++- src/vehicles/Cranes.cpp | 6 +- 9 files changed, 139 insertions(+), 112 deletions(-) diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index fc8f84f2..96391914 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -129,7 +129,7 @@ int32 CGarages::PoliceCarsCollected; CStoredCar CGarages::aCarsInSafeHouse1[NUM_GARAGE_STORED_CARS]; CStoredCar CGarages::aCarsInSafeHouse2[NUM_GARAGE_STORED_CARS]; CStoredCar CGarages::aCarsInSafeHouse3[NUM_GARAGE_STORED_CARS]; -int32 CGarages::AudioEntity = AEHANDLE_NONE; +int32 hGarages = AEHANDLE_NONE; CGarage CGarages::aGarages[NUM_GARAGES]; bool CGarages::bCamShouldBeOutisde; @@ -156,12 +156,12 @@ void CGarages::Init(void) aCarsInSafeHouse2[i].Init(); for (int i = 0; i < NUM_GARAGE_STORED_CARS; i++) aCarsInSafeHouse3[i].Init(); - AudioEntity = DMAudio.CreateEntity(AUDIOTYPE_GARAGE, (void*)1); - if (AudioEntity >= 0) - DMAudio.SetEntityStatus(AudioEntity, 1); + hGarages = DMAudio.CreateEntity(AUDIOTYPE_GARAGE, (void*)1); + if (hGarages >= 0) + DMAudio.SetEntityStatus(hGarages, 1); AddOne( - CRUSHER_GARAGE_X1, CRUSHER_GARAGE_Y1, CRUSHER_GARAGE_Z1, - CRUSHER_GARAGE_X2, CRUSHER_GARAGE_Y2, CRUSHER_GARAGE_Z2, + CVector(CRUSHER_GARAGE_X1, CRUSHER_GARAGE_Y1, CRUSHER_GARAGE_Z1), + CVector(CRUSHER_GARAGE_X2, CRUSHER_GARAGE_Y2, CRUSHER_GARAGE_Z2), GARAGE_CRUSHER, 0); } @@ -169,17 +169,17 @@ void CGarages::Init(void) void CGarages::Shutdown(void) { NumGarages = 0; - if (AudioEntity < 0) + if (hGarages < 0) return; - DMAudio.DestroyEntity(AudioEntity); - AudioEntity = AEHANDLE_NONE; + DMAudio.DestroyEntity(hGarages); + hGarages = AEHANDLE_NONE; } #endif void CGarages::Update(void) { static int GarageToBeTidied = 0; -#ifndef PS2 +#ifndef GTA_PS2 if (CReplay::IsPlayingBack()) return; #endif @@ -202,23 +202,23 @@ void CGarages::Update(void) aGarages[GarageToBeTidied].TidyUpGarage(); } -int16 CGarages::AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId) +int16 CGarages::AddOne(CVector p1, CVector p2, eGarageType type, int32 targetId) { if (NumGarages >= NUM_GARAGES) { assert(0); return NumGarages++; } CGarage* pGarage = &aGarages[NumGarages]; - pGarage->m_fX1 = Min(X1, X2); - pGarage->m_fX2 = Max(X1, X2); - pGarage->m_fY1 = Min(Y1, Y2); - pGarage->m_fY2 = Max(Y1, Y2); - pGarage->m_fZ1 = Min(Z1, Z2); - pGarage->m_fZ2 = Max(Z1, Z2); + pGarage->m_fX1 = Min(p1.x, p2.x); + pGarage->m_fX2 = Max(p1.x, p2.x); + pGarage->m_fY1 = Min(p1.y, p2.y); + pGarage->m_fY2 = Max(p1.y, p2.y); + pGarage->m_fZ1 = Min(p1.z, p2.z); + pGarage->m_fZ2 = Max(p1.z, p2.z); pGarage->m_pDoor1 = nil; pGarage->m_pDoor2 = nil; - pGarage->m_fDoor1Z = Z1; - pGarage->m_fDoor2Z = Z1; + pGarage->m_fDoor1Z = p1.z; + pGarage->m_fDoor2Z = p1.z; pGarage->m_eGarageType = type; pGarage->m_bRecreateDoorOnNextRefresh = false; pGarage->m_bRotatedDoor = false; @@ -368,7 +368,7 @@ void CGarage::Update() if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_RESPRAY; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); CStats::CheckPointReachedSuccessfully(); } UpdateDoorsHeight(); @@ -464,7 +464,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENEDCONTAINSCAR; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -510,7 +510,7 @@ void CGarage::Update() if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_SETUP_BOMB; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); } UpdateDoorsHeight(); break; @@ -575,7 +575,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENEDCONTAINSCAR; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -599,7 +599,8 @@ void CGarage::Update() } } else if (!FindPlayerVehicle() && m_pTarget && IsEntityEntirelyInside3D(m_pTarget, 0.0f) && - !IsAnyOtherCarTouchingGarage(m_pTarget) && IsEntityEntirelyOutside(FindPlayerPed(), 2.0f)) { + !IsAnyOtherCarTouchingGarage(m_pTarget) && IsEntityEntirelyOutside(FindPlayerPed(), 2.0f) && + !IsAnyOtherCarTouchingGarage(m_pTarget)) { CPad::GetPad(0)->SetDisablePlayerControls(PLAYERCONTROL_GARAGE); FindPlayerPed()->m_pWanted->m_bIgnoredByCops = true; m_eGarageState = GS_CLOSING; @@ -609,7 +610,7 @@ void CGarage::Update() case GS_CLOSING: m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); if (m_bClosingWithoutTargetCar) m_eGarageState = GS_FULLYCLOSED; else { @@ -639,7 +640,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -676,7 +677,7 @@ void CGarage::Update() m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); if (m_pTarget) { DestroyVehicleAndDriverAndPassengers(m_pTarget); m_pTarget = nil; @@ -723,7 +724,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -772,7 +773,7 @@ void CGarage::Update() m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); if (m_pTarget) { MarkThisCarAsCollectedForCraig(m_pTarget->GetModelIndex()); DestroyVehicleAndDriverAndPassengers(m_pTarget); @@ -812,7 +813,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -833,7 +834,7 @@ void CGarage::Update() m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); } if (!IsGarageEmpty()) m_eGarageState = GS_OPENING; @@ -844,7 +845,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -893,7 +894,7 @@ void CGarage::Update() m_pTarget = nil; m_eGarageState = GS_AFTERDROPOFF; m_nTimeToStartAction = CTimer::GetTimeInMilliseconds() + TIME_TO_CRUSH_CAR; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); } } else @@ -913,7 +914,7 @@ void CGarage::Update() m_fDoorPos = Min(HALFPI, m_fDoorPos + CTimer::GetTimeStep() * CRUSHER_CRANE_SPEED); if (m_fDoorPos == HALFPI) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateCrusherAngle(); break; @@ -945,7 +946,7 @@ void CGarage::Update() case GS_CLOSING: m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); if (m_bClosingWithoutTargetCar) m_eGarageState = GS_FULLYCLOSED; else { @@ -974,7 +975,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -994,7 +995,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -1014,7 +1015,7 @@ void CGarage::Update() m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); } UpdateDoorsHeight(); break; @@ -1022,7 +1023,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -1064,7 +1065,7 @@ void CGarage::Update() if (!IsPlayerOutsideGarage()) m_eGarageState = GS_OPENING; else if (m_fDoorPos == 0.0f) { - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); m_eGarageState = GS_FULLYCLOSED; switch (m_eGarageType) { case GARAGE_HIDEOUT_ONE: StoreAndRemoveCarsForThisHideout(CGarages::aCarsInSafeHouse1, MAX_STORED_CARS_IN_INDUSTRIAL); break; @@ -1111,7 +1112,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + HIDEOUT_DOOR_SPEED_COEFFICIENT * (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -1136,7 +1137,7 @@ void CGarage::Update() m_fDoorPos = Max(0.0f, m_fDoorPos - (m_bRotatedDoor ? ROTATED_DOOR_CLOSE_SPEED : DEFAULT_DOOR_CLOSE_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == 0.0f) { m_eGarageState = GS_FULLYCLOSED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_CLOSED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_CLOSED, 1.0f); } UpdateDoorsHeight(); break; @@ -1152,7 +1153,7 @@ void CGarage::Update() m_fDoorPos = Min(m_fDoorHeight, m_fDoorPos + (m_bRotatedDoor ? ROTATED_DOOR_OPEN_SPEED : DEFAULT_DOOR_OPEN_SPEED) * CTimer::GetTimeStep()); if (m_fDoorPos == m_fDoorHeight) { m_eGarageState = GS_OPENED; - DMAudio.PlayOneShot(CGarages::AudioEntity, SOUND_GARAGE_DOOR_OPENED, 1.0f); + DMAudio.PlayOneShot(hGarages, SOUND_GARAGE_DOOR_OPENED, 1.0f); } UpdateDoorsHeight(); break; @@ -1387,7 +1388,9 @@ void CGarage::RemoveCarsBlockingDoorNotInside() if (!pVehicle->bIsLocked && pVehicle->CanBeDeleted()) { CWorld::Remove(pVehicle); delete pVehicle; - return; // WHY? +#ifndef FIX_BUGS + return; // makes no sense +#endif } } } @@ -1405,35 +1408,33 @@ void CGarages::PrintMessages() CFont::SetFontStyle(FONT_LOCALE(FONT_BANK)); CFont::SetColor(CRGBA(0, 0, 0, 255)); -#if defined(PS2) || defined (FIX_BUGS) +#if defined(GTA_PS2) || defined (FIX_BUGS) float y_offset = SCREEN_HEIGHT / 3; // THIS is PS2 calculation #else float y_offset = SCREEN_HEIGHT / 2 - SCREEN_SCALE_Y(84.0f); // This is PC and results in text being written over some HUD elements #endif - if (MessageNumberInString2 < 0) { - if (MessageNumberInString < 0) { - CFont::PrintString(SCREEN_WIDTH / 2 - SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(2.0f), TheText.Get(MessageIDString)); - - CFont::SetColor(CRGBA(89, 115, 150, 255)); - CFont::PrintString(SCREEN_WIDTH / 2, y_offset, TheText.Get(MessageIDString)); - } - else { - CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, -1, -1, -1, -1, -1, gUString); - - CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); - - CFont::SetColor(CRGBA(89, 115, 150, 255)); - CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); - } - } - else { + if (MessageNumberInString2 >= 0) { CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, MessageNumberInString2, -1, -1, -1, -1, gUString); CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); CFont::SetColor(CRGBA(89, 115, 150, 255)); CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); } + else if (MessageNumberInString >= 0) { + CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, -1, -1, -1, -1, -1, gUString); + + CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(40.0f) + SCREEN_SCALE_Y(2.0f), gUString); + + CFont::SetColor(CRGBA(89, 115, 150, 255)); + CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); + } + else { + CFont::PrintString(SCREEN_WIDTH / 2 - SCREEN_SCALE_X(2.0f), y_offset - SCREEN_SCALE_Y(2.0f), TheText.Get(MessageIDString)); + + CFont::SetColor(CRGBA(89, 115, 150, 255)); + CFont::PrintString(SCREEN_WIDTH / 2, y_offset, TheText.Get(MessageIDString)); + } } } @@ -1508,41 +1509,54 @@ void CGarage::UpdateCrusherShake(float X, float Y) m_pDoor2->GetMatrix().GetPosition().y -= Y; } -// This is dumb but there is no way to avoid goto. What was there originally even? -static bool DoINeedToRefreshPointer(CEntity * pDoor, bool bIsDummy, uint8 nIndex) -{ - bool bNeedToFindDoorEntities = false; - if (pDoor) { - if (bIsDummy) { - if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex((CDummy*)pDoor))) - return true; - if (nIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)pDoor) & 0x7F)) - bNeedToFindDoorEntities = true; - if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex())) - return true; - } - else { - if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex((CObject*)pDoor))) - return true; - if (nIndex != (CPools::GetObjectPool()->GetIndex((CObject*)pDoor) & 0x7F)) - bNeedToFindDoorEntities = true; - if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex())) - return true; - } - } - return bNeedToFindDoorEntities; -} - void CGarage::RefreshDoorPointers(bool bCreate) { - bool bNeedToFindDoorEntities = true; - if (!bCreate && !m_bRecreateDoorOnNextRefresh) - bNeedToFindDoorEntities = false; + bool bNeedToFindDoorEntities = bCreate || m_bRecreateDoorOnNextRefresh; m_bRecreateDoorOnNextRefresh = false; - if (DoINeedToRefreshPointer(m_pDoor1, m_bDoor1IsDummy, m_bDoor1PoolIndex)) - bNeedToFindDoorEntities = true; - if (DoINeedToRefreshPointer(m_pDoor2, m_bDoor2IsDummy, m_bDoor2PoolIndex)) - bNeedToFindDoorEntities = true; + if (m_pDoor1) { + if (m_bDoor1IsDummy) { + if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor1))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor1PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor1) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor1->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + else { + if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor1))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor1PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor1) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor1->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + } + if (m_pDoor2) { + if (m_bDoor2IsDummy) { + if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor2))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor2PoolIndex != (CPools::GetDummyPool()->GetIndex((CDummy*)m_pDoor2) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor2->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + else { + if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor2))) + bNeedToFindDoorEntities = true; + else { + if (m_bDoor2PoolIndex != (CPools::GetObjectPool()->GetIndex((CObject*)m_pDoor2) & 0x7F)) + bNeedToFindDoorEntities = true; + if (!CGarages::IsModelIndexADoor(m_pDoor2->GetModelIndex())) + bNeedToFindDoorEntities = true; + } + } + } if (bNeedToFindDoorEntities) FindDoorsEntities(); } diff --git a/src/control/Garages.h b/src/control/Garages.h index 00020eb3..41b2afb7 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -198,7 +198,6 @@ class CGarages static CStoredCar aCarsInSafeHouse1[NUM_GARAGE_STORED_CARS]; static CStoredCar aCarsInSafeHouse2[NUM_GARAGE_STORED_CARS]; static CStoredCar aCarsInSafeHouse3[NUM_GARAGE_STORED_CARS]; - static int32 AudioEntity; static bool bCamShouldBeOutisde; public: @@ -208,7 +207,7 @@ public: #endif static void Update(void); - static int16 AddOne(float X1, float Y1, float Z1, float X2, float Y2, float Z2, eGarageType type, int32 targetId); + static int16 AddOne(CVector pos1, CVector pos2, eGarageType type, int32 targetId); static void ChangeGarageType(int16, eGarageType, int32); static void PrintMessages(void); static void TriggerMessage(const char* text, int16, uint16 time, int16); diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index ad29d4fb..c951e868 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -387,7 +387,7 @@ INITSAVEBUF // Convert entity pointer to building pool index while saving if (phone->m_pEntity) { - phone->m_pEntity = (CEntity*) (CPools::GetBuildingPool()->GetJustIndex((CBuilding*)phone->m_pEntity) + 1); + phone->m_pEntity = (CEntity*) (CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert((CBuilding*)phone->m_pEntity) + 1); } } VALIDATESAVEBUF(*size) diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 8951ed82..2503f5c8 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -1009,7 +1009,7 @@ INITSAVEBUF for (int32 i = 0; i < NUMPICKUPS; i++) { CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]); if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil) - buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex(buf_pickup->m_pObject) + 1); + buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(buf_pickup->m_pObject) + 1); } WriteSaveBuf(buf, CollectedPickUpIndex); diff --git a/src/control/Script3.cpp b/src/control/Script3.cpp index c0112d06..23ab453c 100644 --- a/src/control/Script3.cpp +++ b/src/control/Script3.cpp @@ -291,7 +291,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) infZ = *(float*)&ScriptParams[5]; supZ = *(float*)&ScriptParams[2]; } - ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], 0); + ScriptParams[0] = CGarages::AddOne(CVector(infX, infY, infZ), CVector(supX, supY, supZ), (eGarageType)ScriptParams[6], 0); StoreParameters(&m_nIp, 1); return 0; } @@ -316,7 +316,7 @@ int8 CRunningScript::ProcessCommands500To599(int32 command) infZ = *(float*)&ScriptParams[5]; supZ = *(float*)&ScriptParams[2]; } - ScriptParams[0] = CGarages::AddOne(infX, infY, infZ, supX, supY, supZ, (eGarageType)ScriptParams[6], ScriptParams[7]); + ScriptParams[0] = CGarages::AddOne(CVector(infX, infY, infZ), CVector(supX, supY, supZ), (eGarageType)ScriptParams[6], ScriptParams[7]); StoreParameters(&m_nIp, 1); return 0; } diff --git a/src/control/Script5.cpp b/src/control/Script5.cpp index bada95ea..164ca036 100644 --- a/src/control/Script5.cpp +++ b/src/control/Script5.cpp @@ -1604,10 +1604,10 @@ INITSAVEBUF handle = 0; } else if (pBuilding->GetIsATreadable()) { type = 1; - handle = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pBuilding) + 1; + handle = CPools::GetTreadablePool()->GetJustIndex_NoFreeAssert((CTreadable*)pBuilding) + 1; } else { type = 2; - handle = CPools::GetBuildingPool()->GetJustIndex(pBuilding) + 1; + handle = CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert(pBuilding) + 1; } WriteSaveBuf(buf, type); WriteSaveBuf(buf, handle); @@ -1625,19 +1625,19 @@ INITSAVEBUF case ENTITY_TYPE_BUILDING: if (((CBuilding*)pEntity)->GetIsATreadable()) { type = 1; - handle = CPools::GetTreadablePool()->GetJustIndex((CTreadable*)pEntity) + 1; + handle = CPools::GetTreadablePool()->GetJustIndex_NoFreeAssert((CTreadable*)pEntity) + 1; } else { type = 2; - handle = CPools::GetBuildingPool()->GetJustIndex((CBuilding*)pEntity) + 1; + handle = CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert((CBuilding*)pEntity) + 1; } break; case ENTITY_TYPE_OBJECT: type = 3; - handle = CPools::GetObjectPool()->GetJustIndex((CObject*)pEntity) + 1; + handle = CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)pEntity) + 1; break; case ENTITY_TYPE_DUMMY: type = 4; - handle = CPools::GetDummyPool()->GetJustIndex((CDummy*)pEntity) + 1; + handle = CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)pEntity) + 1; default: break; } } diff --git a/src/core/World.cpp b/src/core/World.cpp index 33c2f1c1..70388b38 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -1738,10 +1738,12 @@ CWorld::ShutDown(void) CWorld::Remove(pEntity); delete pEntity; } +#ifndef FIX_BUGS pSector->m_lists[ENTITYLIST_BUILDINGS].Flush(); pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].Flush(); pSector->m_lists[ENTITYLIST_DUMMIES].Flush(); pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].Flush(); +#endif } for(int32 i = 0; i < 4; i++) { for(CPtrNode *pNode = GetBigBuildingList((eLevelName)i).first; pNode; pNode = pNode->next) { @@ -1753,6 +1755,12 @@ CWorld::ShutDown(void) } for(int i = 0; i < NUMSECTORS_X * NUMSECTORS_Y; i++) { CSector *pSector = GetSector(i % NUMSECTORS_X, i / NUMSECTORS_Y); +#ifdef FIX_BUGS + pSector->m_lists[ENTITYLIST_BUILDINGS].Flush(); + pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].Flush(); + pSector->m_lists[ENTITYLIST_DUMMIES].Flush(); + pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].Flush(); +#endif if(pSector->m_lists[ENTITYLIST_BUILDINGS].first) { sprintf(gString, "Building list %d,%d not empty\n", i % NUMSECTORS_X, i / NUMSECTORS_Y); pSector->m_lists[ENTITYLIST_BUILDINGS].Flush(); diff --git a/src/core/templates.h b/src/core/templates.h index 86239664..166f865c 100644 --- a/src/core/templates.h +++ b/src/core/templates.h @@ -124,12 +124,18 @@ public: (T*)&m_entries[handle >> 8] : nil; } int GetIndex(T *entry){ - int i = GetJustIndex(entry); + int i = GetJustIndex_NoFreeAssert(entry); return m_flags[i].u + (i<<8); } int GetJustIndex(T *entry){ - // TODO: the cast is unsafe - return (int)((U*)entry - m_entries); + int index = GetJustIndex_NoFreeAssert(entry); + assert(!IsFreeSlot(index)); + return index; + } + int GetJustIndex_NoFreeAssert(T* entry){ + int index = ((U*)entry - m_entries); + assert((U*)entry == (U*)&m_entries[index]); // cast is unsafe - check required + return index; } int GetNoOfUsedSpaces(void) const{ int i; diff --git a/src/vehicles/Cranes.cpp b/src/vehicles/Cranes.cpp index 757974a6..564f493d 100644 --- a/src/vehicles/Cranes.cpp +++ b/src/vehicles/Cranes.cpp @@ -639,11 +639,11 @@ void CCranes::Save(uint8* buf, uint32* size) for (int i = 0; i < NUM_CRANES; i++) { CCrane *pCrane = WriteSaveBuf(buf, aCranes[i]); if (pCrane->m_pCraneEntity != nil) - pCrane->m_pCraneEntity = (CBuilding*)(CPools::GetBuildingPool()->GetJustIndex(pCrane->m_pCraneEntity) + 1); + pCrane->m_pCraneEntity = (CBuilding*)(CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert(pCrane->m_pCraneEntity) + 1); if (pCrane->m_pHook != nil) - pCrane->m_pHook = (CObject*)(CPools::GetObjectPool()->GetJustIndex(pCrane->m_pHook) + 1); + pCrane->m_pHook = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(pCrane->m_pHook) + 1); if (pCrane->m_pVehiclePickedUp != nil) - pCrane->m_pVehiclePickedUp = (CVehicle*)(CPools::GetVehiclePool()->GetJustIndex(pCrane->m_pVehiclePickedUp) + 1); + pCrane->m_pVehiclePickedUp = (CVehicle*)(CPools::GetVehiclePool()->GetJustIndex_NoFreeAssert(pCrane->m_pVehiclePickedUp) + 1); } VALIDATESAVEBUF(*size); From 4b9fb631fc1b250a1e353da2e319d49371573bcc Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 30 Nov 2020 23:44:58 +0100 Subject: [PATCH 096/129] added a few registered pointers and memory debug --- src/core/FileLoader.cpp | 5 +++++ src/core/Streaming.cpp | 44 ++++++++++++++++++++++++++++++++++++++--- src/core/main.cpp | 8 ++++++-- src/core/main.h | 4 ++++ src/core/re3.cpp | 11 +++++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index 88a99fa9..aeaede56 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -243,6 +243,7 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) buf += 44; if(model.numSpheres > 0){ model.spheres = (CColSphere*)RwMalloc(model.numSpheres*sizeof(CColSphere)); + REGISTER_MEMPTR(&model.spheres); for(i = 0; i < model.numSpheres; i++){ model.spheres[i].Set(*(float*)buf, *(CVector*)(buf+4), buf[16], buf[17]); buf += 20; @@ -254,6 +255,7 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) buf += 4; if(model.numLines > 0){ model.lines = (CColLine*)RwMalloc(model.numLines*sizeof(CColLine)); + REGISTER_MEMPTR(&model.lines); for(i = 0; i < model.numLines; i++){ model.lines[i].Set(*(CVector*)buf, *(CVector*)(buf+12)); buf += 24; @@ -265,6 +267,7 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) buf += 4; if(model.numBoxes > 0){ model.boxes = (CColBox*)RwMalloc(model.numBoxes*sizeof(CColBox)); + REGISTER_MEMPTR(&model.boxes); for(i = 0; i < model.numBoxes; i++){ model.boxes[i].Set(*(CVector*)buf, *(CVector*)(buf+12), buf[24], buf[25]); buf += 28; @@ -276,6 +279,7 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) buf += 4; if(numVertices > 0){ model.vertices = (CompressedVector*)RwMalloc(numVertices*sizeof(CompressedVector)); + REGISTER_MEMPTR(&model.vertices); for(i = 0; i < numVertices; i++){ model.vertices[i].Set(*(float*)buf, *(float*)(buf+4), *(float*)(buf+8)); if(Abs(*(float*)buf) >= 256.0f || @@ -291,6 +295,7 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) buf += 4; if(model.numTriangles > 0){ model.triangles = (CColTriangle*)RwMalloc(model.numTriangles*sizeof(CColTriangle)); + REGISTER_MEMPTR(&model.triangles); for(i = 0; i < model.numTriangles; i++){ model.triangles[i].Set(model.vertices, *(int32*)buf, *(int32*)(buf+4), *(int32*)(buf+8), buf[12], buf[13]); buf += 16; diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index a28fe39d..03b49fd6 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -458,6 +458,35 @@ CStreaming::LoadCdDirectory(const char *dirname, int n) CFileMgr::CloseFile(fd); } +#ifdef USE_CUSTOM_ALLOCATOR +RpAtomic* +RegisterAtomicMemPtrsCB(RpAtomic *atomic, void *data) +{ +#if THIS_IS_COMPATIBLE_WITH_GTA3_RW31 + // not quite sure what's going on here: + // gta3's RW 3.1 allocates separate memory for geometry data of RpGeometry. + // Is that a R* change? rpDefaultGeometryInstance also depends on it + RpGeometry *geo = RpAtomicGetGeometry(atomic); + if(geo->triangles) + REGISTER_MEMPTR(&geo->triangles); + if(geo->matList.materials) + REGISTER_MEMPTR(&geo->matList.materials); + if(geo->preLitLum) + REGISTER_MEMPTR(&geo->preLitLum); + if(geo->texCoords[0]) + REGISTER_MEMPTR(&geo->texCoords[0]); + if(geo->texCoords[1]) + REGISTER_MEMPTR(&geo->texCoords[1]); +#else + // normally RpGeometry is allocated in one block (excluding morph targets) + // so we don't really have allocated pointers in the struct. + // NB: in librw we actually do it in two allocations (geometry itself and data) + // so we could conceivably come up with something here +#endif + return atomic; +} +#endif + bool CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) { @@ -494,9 +523,11 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) PUSH_MEMID(MEMID_STREAM_MODELS); CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); -// TODO(USE_CUSTOM_ALLOCATOR): register mem pointers if(mi->IsSimple()){ success = CFileLoader::LoadAtomicFile(stream, streamId); +#ifdef USE_CUSTOM_ALLOCATOR + RegisterAtomicMemPtrsCB(((CSimpleModelInfo*)mi)->m_atomics[0], nil); +#endif } else if (mi->GetModelType() == MITYPE_VEHICLE) { // load vehicles in two parts CModelInfo::GetModelInfo(streamId)->AddRef(); @@ -505,6 +536,10 @@ CStreaming::ConvertBufferToObject(int8 *buf, int32 streamId) ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_STARTED; }else{ success = CFileLoader::LoadClumpFile(stream, streamId); +#ifdef USE_CUSTOM_ALLOCATOR + if(success) + RpClumpForAllAtomics((RpClump*)mi->GetRwObject(), RegisterAtomicMemPtrsCB, nil); +#endif } POP_MEMID(); UpdateMemoryUsed(); @@ -628,13 +663,16 @@ CStreaming::FinishLoadingLargeFile(int8 *buf, int32 streamId) if(streamId < STREAM_OFFSET_TXD){ // Model -// TODO(USE_CUSTOM_ALLOCATOR): register pointers mi = CModelInfo::GetModelInfo(streamId); PUSH_MEMID(MEMID_STREAM_MODELS); CTxdStore::SetCurrentTxd(mi->GetTxdSlot()); success = CFileLoader::FinishLoadClumpFile(stream, streamId); - if(success) + if(success){ +#ifdef USE_CUSTOM_ALLOCATOR + RpClumpForAllAtomics((RpClump*)mi->GetRwObject(), RegisterAtomicMemPtrsCB, nil); +#endif success = AddToLoadedVehiclesList(streamId); + } POP_MEMID(); mi->RemoveRef(); CTxdStore::RemoveRefWithoutDelete(mi->GetTxdSlot()); diff --git a/src/core/main.cpp b/src/core/main.cpp index d34eb8f3..102548b6 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -110,6 +110,9 @@ void TheGame(void); void DebugMenuPopulate(void); #endif +#ifndef FINAL +bool gbPrintMemoryUsage; +#endif #ifdef GTA_PS2 #define WANT_TO_LOAD TheMemoryCard.m_bWantToLoad @@ -957,9 +960,10 @@ DisplayGameDebugText() TWEAKBOOL(bDisplayPosn); TWEAKBOOL(bDisplayRate); } -#endif -// PrintMemoryUsage(); // TODO: put this somewhere else + if(gbPrintMemoryUsage) + PrintMemoryUsage(); +#endif char str[200]; wchar ustr[200]; diff --git a/src/core/main.h b/src/core/main.h index 13fff447..77fac46a 100644 --- a/src/core/main.h +++ b/src/core/main.h @@ -20,6 +20,10 @@ extern bool gbShowTimebars; #define gbShowTimebars false #endif +#ifndef FINAL +extern bool gbPrintMemoryUsage; +#endif + class CSprite2d; bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha); diff --git a/src/core/re3.cpp b/src/core/re3.cpp index ee747218..506b2714 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -29,6 +29,7 @@ #include "Script.h" #include "postfx.h" #include "custompipes.h" +#include "MemoryHeap.h" #ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS #include "FileMgr.h" @@ -383,6 +384,10 @@ SwitchToMission(void) } #endif +#ifdef USE_CUSTOM_ALLOCATOR +static void ParseHeap(void) { gMainHeap.ParseHeap(); } +#endif + static const char *carnames[] = { "landstal", "idaho", "stinger", "linerun", "peren", "sentinel", "patriot", "firetruk", "trash", "stretch", "manana", "infernus", "blista", "pony", "mule", "cheetah", "ambulan", "fbicar", "moonbeam", "esperant", "taxi", "kuruma", "bobcat", "mrwhoop", "bfinject", "corpse", "police", "enforcer", @@ -565,6 +570,12 @@ DebugMenuPopulate(void) DebugMenuAddVarBool8("Render", "Don't render Objects", &gbDontRenderObjects, nil); DebugMenuAddVarBool8("Render", "Don't Render Water", &gbDontRenderWater, nil); +#ifndef FINAL + DebugMenuAddVarBool8("Debug", "Print Memory Usage", &gbPrintMemoryUsage, nil); +#ifdef USE_CUSTOM_ALLOCATOR + DebugMenuAddCmd("Debug", "Parse Heap", ParseHeap); +#endif +#endif DebugMenuAddVarBool8("Debug", "Show cullzone debug stuff", &gbShowCullZoneDebugStuff, nil); DebugMenuAddVarBool8("Debug", "Disable zone cull", &gbDisableZoneCull, nil); From 2c59e1c8945a5c6de6415611d4f1dbc720790d73 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 00:22:57 +0100 Subject: [PATCH 097/129] some more GTA_VERSION --- src/core/FileLoader.cpp | 6 +++ src/core/Game.cpp | 101 +++++++++++++++++++++++++++++----------- src/core/World.cpp | 5 +- 3 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index aeaede56..b9d475b8 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -59,7 +59,13 @@ CFileLoader::LoadLevel(const char *filename) savedTxd = RwTexDictionaryCreate(); RwTexDictionarySetCurrent(savedTxd); } +#if GTA_VERSION <= GTA3_PS2_160 + CFileMgr::ChangeDir("\\DATA\\"); fd = CFileMgr::OpenFile(filename, "r"); + CFileMgr::ChangeDir("\\"); +#else + fd = CFileMgr::OpenFile(filename, "r"); +#endif assert(fd > 0); for(line = LoadLine(fd); line; line = LoadLine(fd)){ diff --git a/src/core/Game.cpp b/src/core/Game.cpp index d22a7184..7043a5b2 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -265,16 +265,19 @@ void CGame::ShutdownRenderWare(void) #endif } +// missing altogether on PS2 bool CGame::InitialiseOnceAfterRW(void) { +#if GTA_VERSION > GTA3_PS2_160 TheText.Load(); - DMAudio.Initialise(); + DMAudio.Initialise(); // before TheGame() on PS2 CTimer::Initialise(); CTempColModels::Initialise(); mod_HandlingManager.Initialise(); CSurfaceTable::Initialise("DATA\\SURFACE.DAT"); CPedStats::Initialise(); CTimeCycle::Initialise(); +#endif if ( DMAudio.GetNum3DProvidersAvailable() == 0 ) FrontEndMenuManager.m_nPrefsAudio3DProviderIndex = -1; @@ -330,10 +333,15 @@ bool CGame::Initialise(const char* datFile) { #ifdef GTA_PS2 // TODO: upload VU0 collision code here -#else +#endif + +#if GTA_VERSION > GTA3_PS2_160 ResetLoadingScreenBar(); strcpy(aDatFile, datFile); CPools::Initialise(); // done in CWorld on PS2 +#endif + +#ifndef GTA_PS2 CIniFile::LoadIniFile(); #endif @@ -367,13 +375,15 @@ bool CGame::Initialise(const char* datFile) CWeather::Init(); CCullZones::Init(); CCollision::Init(); -#ifdef PS2_MENU +#ifdef PS2_MENU // TODO: is this the right define? TheText.Load(); #endif CTheZones::Init(); CUserDisplay::Init(); CMessages::Init(); +#if GTA_VERSION > GTA3_PS2_160 CMessages::ClearAllMessagesDisplayedByGame(); +#endif CRecordDataForGame::Init(); CRestart::Initialise(); @@ -381,11 +391,17 @@ bool CGame::Initialise(const char* datFile) CWorld::Initialise(); POP_MEMID(); +#if GTA_VERSION <= GTA3_PS2_160 + mod_HandlingManager.Initialise(); + CSurfaceTable::Initialise("DATA\\SURFACE.DAT"); + CTempColModels::Initialise(); +#endif + PUSH_MEMID(MEMID_TEXTURES); CParticle::Initialise(); POP_MEMID(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 gStartX = -180.0f; gStartY = 180.0f; gStartZ = 14.0f; @@ -400,20 +416,31 @@ bool CGame::Initialise(const char* datFile) CCarCtrl::Init(); POP_MEMID(); -#ifndef GTA_PS2 +#if GTA_VERSION > GTA3_PS2_160 InitModelIndices(); #endif PUSH_MEMID(MEMID_DEF_MODELS); CModelInfo::Initialise(); -#ifndef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 + CPedStats::Initialise(); // InitialiseOnceAfterRW +#else // probably moved before LoadLevel for multiplayer maps? CPickups::Init(); CTheCarGenerators::Init(); #endif + +#ifndef GTA_PS2 // or GTA_VERSION? CdStreamAddImage("MODELS\\GTA3.IMG"); +#endif + +#if GTA_VERSION > GTA3_PS2_160 CFileLoader::LoadLevel("DATA\\DEFAULT.DAT"); CFileLoader::LoadLevel(datFile); +#else + CFileLoader::LoadLevel("GTA3.DAT"); +#endif + #ifdef EXTENDED_PIPELINES // for generic fallback CustomPipes::SetTxdFindCallback(); @@ -424,18 +451,25 @@ bool CGame::Initialise(const char* datFile) CTheZones::PostZoneCreation(); POP_MEMID(); +#if GTA_VERSION <= GTA3_PS2_160 + TestModelIndices(); +#endif LoadingScreen("Loading the Game", "Setup paths", GetRandomSplashScreen()); ThePaths.PreparePathData(); - // done elsewhere on PS2 +#if GTA_VERSION > GTA3_PS2_160 for (int i = 0; i < NUMPLAYERS; i++) CWorld::Players[i].Clear(); CWorld::Players[0].LoadPlayerSkin(); TestModelIndices(); - // +#endif LoadingScreen("Loading the Game", "Setup water", nil); CWaterLevel::Initialise("DATA\\WATER.DAT"); +#if GTA_VERSION <= GTA3_PS2_160 + CTimeCycle::Initialise(); // InitialiseOnceAfterRW +#else TheConsole.Init(); +#endif CDraw::SetFOV(120.0f); CDraw::ms_fLODDistance = 500.0f; @@ -472,6 +506,11 @@ bool CGame::Initialise(const char* datFile) LoadingScreen("Loading the Game", "Setup game variables", nil); CPopulation::Initialise(); +#if GTA_VERSION <= GTA3_PS2_160 + for (int i = 0; i < NUMPLAYERS; i++) + CWorld::Players[i].Clear(); +// CWorld::Players[0].LoadPlayerSkin(); // TODO: use a define for this +#endif CWorld::PlayerInFocus = 0; CCoronas::Init(); CShadows::Init(); @@ -480,7 +519,7 @@ bool CGame::Initialise(const char* datFile) CAntennas::Init(); CGlass::Init(); gPhoneInfo.Initialise(); -#ifndef GTA_PS2 +#ifndef GTA_PS2 // TODO: define for this CSceneEdit::Initialise(); #endif @@ -491,11 +530,11 @@ bool CGame::Initialise(const char* datFile) POP_MEMID(); LoadingScreen("Loading the Game", "Setup game variables", nil); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CTimer::Initialise(); #endif CClock::Initialise(1000); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CTheCarGenerators::Init(); #endif CHeli::InitHelis(); @@ -503,44 +542,52 @@ bool CGame::Initialise(const char* datFile) CMovingThings::Init(); CDarkel::Init(); CStats::Init(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CPickups::Init(); #endif CPacManPickups::Init(); - // CGarages::Init(); here on PS2 instead +#if GTA_VERSION <= GTA3_PS2_160 + CGarages::Init(); +#endif CRubbish::Init(); CClouds::Init(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CRemote::Init(); #endif CSpecialFX::Init(); CWaterCannons::Init(); CBridge::Init(); +#if GTA_VERSION > GTA3_PS2_160 CGarages::Init(); +#endif LoadingScreen("Loading the Game", "Position dynamic objects", nil); CWorld::RepositionCertainDynamicObjects(); - // CCullZones::ResolveVisibilities(); on PS2 here instead +#if GTA_VERSION <= GTA3_PS2_160 + CCullZones::ResolveVisibilities(); +#endif LoadingScreen("Loading the Game", "Initialise vehicle paths", nil); +#if GTA_VERSION > GTA3_PS2_160 CCullZones::ResolveVisibilities(); +#endif CTrain::InitTrains(); CPlane::InitPlanes(); CCredits::Init(); CRecordDataForChase::Init(); +#ifndef GTA_PS2 // TODO: define for that CReplay::Init(); +#endif #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) +#endif { -#endif - LoadingScreen("Loading the Game", "Start script", nil); - CTheScripts::StartTestScript(); - CTheScripts::Process(); - TheCamera.Process(); -#ifdef PS2_MENU + LoadingScreen("Loading the Game", "Start script", nil); + CTheScripts::StartTestScript(); + CTheScripts::Process(); + TheCamera.Process(); } -#endif LoadingScreen("Loading the Game", "Load scene", nil); CModelInfo::RemoveColModelsFromOtherLevels(currLevel); @@ -556,7 +603,7 @@ bool CGame::ShutDown(void) CPlane::Shutdown(); CTrain::Shutdown(); CSpecialFX::Shutdown(); -#ifndef PS2 +#if GTA_VERSION > GTA3_PS2_160 CGarages::Shutdown(); #endif CMovingThings::Shutdown(); @@ -597,7 +644,9 @@ bool CGame::ShutDown(void) CSkidmarks::Shutdown(); CWeaponEffects::Shutdown(); CParticle::Shutdown(); +#if GTA_VERSION > GTA3_PS2_160 CPools::ShutDown(); +#endif CTxdStore::RemoveTxdSlot(gameTxdSlot); CdStreamRemoveImages(); return true; @@ -623,7 +672,7 @@ void CGame::ReInitGameObjectVariables(void) CWorld::bDoingCarCollisions = false; CHud::ReInitialise(); CRadar::Initialise(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 gStartX = -180.0f; gStartY = 180.0f; gStartZ = 14.0f; @@ -646,7 +695,7 @@ void CGame::ReInitGameObjectVariables(void) CWorld::Players[i].Clear(); CWorld::PlayerInFocus = 0; -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CWeaponEffects::Init(); CSkidmarks::Init(); #endif @@ -669,7 +718,7 @@ void CGame::ReInitGameObjectVariables(void) CPickups::Init(); CPacManPickups::Init(); CGarages::Init(); -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CClouds::Init(); CRemote::Init(); #endif diff --git a/src/core/World.cpp b/src/core/World.cpp index 33c2f1c1..62d8d002 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -53,7 +53,7 @@ bool CWorld::bIncludeCarTyres; void CWorld::Initialise() { -#ifdef GTA_PS2 +#if GTA_VERSION <= GTA3_PS2_160 CPools::Initialise(); #endif pIgnoreEntity = nil; @@ -1783,6 +1783,9 @@ CWorld::ShutDown(void) } } ms_listMovingEntityPtrs.Flush(); +#if GTA_VERSION <= GTA3_PS2_160 + CPools::Shutdown(); +#endif } void From 6eb0fd52d7f36623ca78d6717fcbd64fd3e7ecd9 Mon Sep 17 00:00:00 2001 From: Zach Charo Date: Mon, 30 Nov 2020 19:08:15 -0600 Subject: [PATCH 098/129] Update Camera.cpp camdist multiplier is consitently between 1 and 1.4 on 16:9 aspect ratio On ultrawide, the cam dist multiplier jumps to anywhere between 2 and 3 The preferred distance generator for car objects is the cam dist multiplier * 120. Which puts cars that it's trying to generate outside of the allowed gen/draw distance for new car objects when on ultrawide. This means no new cars can spawn. This change caps the scaling for the generation distance a bit above what it would be for 16:9 and does not affect the LOD multiplier. --- src/core/Camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 1e1aa722..9281a20a 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -720,7 +720,7 @@ CCamera::Process(void) else LODDistMultiplier = 1.0f; // missing on PS2 - GenerationDistMultiplier = LODDistMultiplier; + GenerationDistMultiplier = 70.0f/CDraw::GetFOV() * fmin(CDraw::GetAspectRatio(),1.82f)/(4.0f/3.0f); LODDistMultiplier *= CRenderer::ms_lodDistScale; // From d6fab1bc53627d55391d10a557a9e0cbcd11ac6d Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 10:12:42 +0100 Subject: [PATCH 099/129] cam stuff --- src/core/Camera.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 9281a20a..cd748f09 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -94,9 +94,9 @@ CCamera::Init(void) #endif #ifdef PS2_MENU - if ( !TheMemoryCard.m_bWantToLoad && !FrontEndMenuManager.m_bWantToRestart ) { + if ( !TheMemoryCard.m_bWantToLoad && !FrontEndMenuManager.m_bWantToRestart ) #endif - + { #ifdef FIX_BUGS static const CCamera DummyCamera = CCamera(0.f); *this = DummyCamera; @@ -110,9 +110,7 @@ CCamera::Init(void) #endif m_pRwCamera = nil; -#ifdef PS2_MENU } -#endif m_1rstPersonRunCloseToAWall = false; m_fPositionAlongSpline = 0.0f; @@ -719,10 +717,14 @@ CCamera::Process(void) LODDistMultiplier = 70.0f/CDraw::GetFOV() * CDraw::GetAspectRatio()/(4.0f/3.0f); else LODDistMultiplier = 1.0f; - // missing on PS2 - GenerationDistMultiplier = 70.0f/CDraw::GetFOV() * fmin(CDraw::GetAspectRatio(),1.82f)/(4.0f/3.0f); +#if GTA_VERSION > GTA3_PS2_160 +#ifndef FIX_BUGS + // this seems problematic for very wide aspect ratios + // maybe just leaving it at 1.0 is the best thing to do + GenerationDistMultiplier = LODDistMultiplier; +#endif LODDistMultiplier *= CRenderer::ms_lodDistScale; - // +#endif // Keep track of speed if(m_bJustInitalised || m_bJust_Switched){ From b8bc54640d80db3d0c0a6392a0858d83a09e8304 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 17:24:56 +0100 Subject: [PATCH 100/129] fix cam-fix --- src/core/Camera.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index cd748f09..51876c93 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -717,12 +717,12 @@ CCamera::Process(void) LODDistMultiplier = 70.0f/CDraw::GetFOV() * CDraw::GetAspectRatio()/(4.0f/3.0f); else LODDistMultiplier = 1.0f; -#if GTA_VERSION > GTA3_PS2_160 -#ifndef FIX_BUGS - // this seems problematic for very wide aspect ratios - // maybe just leaving it at 1.0 is the best thing to do - GenerationDistMultiplier = LODDistMultiplier; +#ifdef FIX_BUGS + // from VC. to high values bug out spawns + LODDistMultiplier = Min(LODDistMultiplier, 2.2f); #endif +#if GTA_VERSION > GTA3_PS2_160 + GenerationDistMultiplier = LODDistMultiplier; LODDistMultiplier *= CRenderer::ms_lodDistScale; #endif From 83bbb631d1105502fb3c5b3af90578226ba35583 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 17:42:18 +0100 Subject: [PATCH 101/129] some more GTA_VERSIONs and CGame tidy-up (not much actual memory moving yet) --- src/animation/AnimBlendHierarchy.cpp | 11 ++ src/animation/AnimBlendHierarchy.h | 5 + src/animation/AnimBlendSequence.cpp | 21 ++++ src/animation/AnimBlendSequence.h | 5 + src/core/Game.cpp | 175 +++++++++++++++++++++++++-- src/core/main.cpp | 1 + src/rw/MemoryHeap.cpp | 2 +- src/rw/MemoryHeap.h | 1 + 8 files changed, 209 insertions(+), 12 deletions(-) diff --git a/src/animation/AnimBlendHierarchy.cpp b/src/animation/AnimBlendHierarchy.cpp index 67b19019..c7800de5 100644 --- a/src/animation/AnimBlendHierarchy.cpp +++ b/src/animation/AnimBlendHierarchy.cpp @@ -82,3 +82,14 @@ CAnimBlendHierarchy::RemoveUncompressedData(void) #endif compressed = 1; } + +#ifdef USE_CUSTOM_ALLOCATOR +void +CAnimBlendHierarchy::MoveMemory(bool onlyone) +{ + int i; + for(i = 0; i < numSequences; i++) + if(sequences[i].MoveMemory() && onlyone) + return; +} +#endif diff --git a/src/animation/AnimBlendHierarchy.h b/src/animation/AnimBlendHierarchy.h index 0144108d..e35b4925 100644 --- a/src/animation/AnimBlendHierarchy.h +++ b/src/animation/AnimBlendHierarchy.h @@ -2,6 +2,10 @@ #include "templates.h" +#ifdef MoveMemory +#undef MoveMemory // windows shit +#endif + class CAnimBlendSequence; // A collection of sequences @@ -23,6 +27,7 @@ public: void RemoveAnimSequences(void); void Uncompress(void); void RemoveUncompressedData(void); + void MoveMemory(bool onlyone = false); }; VALIDATE_SIZE(CAnimBlendHierarchy, 0x28); \ No newline at end of file diff --git a/src/animation/AnimBlendSequence.cpp b/src/animation/AnimBlendSequence.cpp index 5a2fa605..c958b71a 100644 --- a/src/animation/AnimBlendSequence.cpp +++ b/src/animation/AnimBlendSequence.cpp @@ -176,3 +176,24 @@ CAnimBlendSequence::RemoveUncompressedData(void) keyFrames = nil; } +#ifdef USE_CUSTOM_ALLOCATOR +bool +CAnimBlendSequence::MoveMemory(void) +{ + if(keyFrames){ + void *newaddr = gMainHeap.MoveMemory(keyFrames); + if(newaddr != keyFrames){ + keyFrames = newaddr; + return true; + } + }else if(keyFramesCompressed){ + void *newaddr = gMainHeap.MoveMemory(keyFramesCompressed); + if(newaddr != keyFramesCompressed){ + keyFramesCompressed = newaddr; + return true; + } + } + return false; +} +#endif + diff --git a/src/animation/AnimBlendSequence.h b/src/animation/AnimBlendSequence.h index e51e5aaa..c6e70f22 100644 --- a/src/animation/AnimBlendSequence.h +++ b/src/animation/AnimBlendSequence.h @@ -2,6 +2,10 @@ #include "Quaternion.h" +#ifdef MoveMemory +#undef MoveMemory // windows shit +#endif + // TODO: put them somewhere else? struct KeyFrame { CQuaternion rotation; @@ -53,6 +57,7 @@ public: void Uncompress(void); void CompressKeyframes(void); void RemoveUncompressedData(void); + bool MoveMemory(void); #ifdef PED_SKIN void SetBoneTag(int tag) { boneTag = tag; } diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 7043a5b2..262aa54a 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -167,6 +167,7 @@ void ReplaceAtomicPipeCallback(); #endif // PS2_ALPHA_TEST #endif // !LIBRW +// missing altogether on PS2, mostly done in GameInit there it seems bool CGame::InitialiseRenderWare(void) { @@ -233,6 +234,7 @@ CGame::InitialiseRenderWare(void) return (true); } +// missing altogether on PS2 void CGame::ShutdownRenderWare(void) { CMBlur::MotionBlurClose(); @@ -321,6 +323,7 @@ bool CGame::InitialiseOnceAfterRW(void) return true; } +// missing altogether on PS2 void CGame::FinalShutdown(void) { @@ -657,13 +660,11 @@ void CGame::ReInitGameObjectVariables(void) CGameLogic::InitAtStartOfGame(); #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) +#endif { -#endif - TheCamera.Init(); - TheCamera.SetRwCamera(Scene.camera); -#ifdef PS2_MENU + TheCamera.Init(); + TheCamera.SetRwCamera(Scene.camera); } -#endif CDebug::DebugInitTextBuffer(); CWeather::Init(); CUserDisplay::Init(); @@ -769,8 +770,10 @@ void CGame::ReloadIPLs(void) void CGame::ShutDownForRestart(void) { +#ifndef GTA_PS2 // TODO: right define CReplay::FinishPlayback(); CReplay::EmptyReplayBuffer(); +#endif DMAudio.DestroyAllGameCreatedEntities(); for (int i = 0; i < NUMPLAYERS; i++) @@ -788,7 +791,7 @@ void CGame::ShutDownForRestart(void) CRadar::RemoveRadarSections(); FrontEndMenuManager.UnloadTextures(); CParticleObject::RemoveAllParticleObjects(); -#ifndef PS2 +#if GTA_VERSION >= GTA3_PS2_160 CPedType::Shutdown(); CSpecialFX::Shutdown(); #endif @@ -974,7 +977,9 @@ void CGame::Process(void) CSkidmarks::Update(); CAntennas::Update(); CGlass::Update(); +#ifndef GTA_PS2 // TODO: define CSceneEdit::Update(); +#endif CEventList::Update(); CParticle::Update(); gFireManager.Update(); @@ -988,7 +993,9 @@ void CGame::Process(void) CMovingThings::Update(); CWaterCannons::Update(); CUserDisplay::Process(); +#ifndef GTA_PS2 // TODO: define CReplay::Update(); +#endif PUSH_MEMID(MEMID_WORLD); CWorld::Process(); @@ -1001,10 +1008,14 @@ void CGame::Process(void) CRubbish::Update(); CSpecialFX::Update(); CTimeCycle::Update(); +#ifndef GTA_PS2 // TODO: define if (CReplay::ShouldStandardCameraBeProcessed()) +#endif TheCamera.Process(); CCullZones::Update(); +#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) +#endif CGameLogic::Update(); CBridge::Update(); CCoronas::DoSunAndMoon(); @@ -1012,7 +1023,9 @@ void CGame::Process(void) CShadows::UpdateStaticShadows(); CShadows::UpdatePermanentShadows(); gPhoneInfo.Update(); +#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) +#endif { PUSH_MEMID(MEMID_CARS); CCarCtrl::GenerateRandomCars(); @@ -1026,23 +1039,163 @@ void CGame::Process(void) #endif } -void CGame::DrasticTidyUpMemory(bool) +int32 gNumMemMoved; + +RwTexture * +MoveTextureMemoryCB(RwTexture *texture, void *pData) +{ + // TODO + return texture; +} + +bool +TidyUpModelInfo(CBaseModelInfo *,bool) +{ + // TODO + return false; +} + +void CGame::DrasticTidyUpMemory(bool flushDraw) { #ifdef USE_CUSTOM_ALLOCATOR - // meow + bool removedCol = false; + + TidyUpMemory(true, flushDraw); + + if(gMainHeap.GetLargestFreeBlock() < 200000 && !playingIntro){ + CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + TidyUpMemory(true, flushDraw); + } + + if(gMainHeap.GetLargestFreeBlock() < 200000 && !playingIntro){ + CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_GENERIC); + TidyUpMemory(true, flushDraw); + removedCol = true; + } + + if(gMainHeap.GetLargestFreeBlock() < 200000 && !playingIntro){ + CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); + CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); + CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); + TidyUpMemory(true, flushDraw); + } + + if(removedCol){ + // different on PS2 + CFileLoader::LoadCollisionFromDatFile(CCollision::ms_collisionInMemory); + } + + if(!playingIntro) + CStreaming::RequestBigBuildings(currLevel); + + CStreaming::LoadAllRequestedModels(true); #endif } -void CGame::TidyUpMemory(bool, bool) +void CGame::TidyUpMemory(bool moveTextures, bool flushDraw) { #ifdef USE_CUSTOM_ALLOCATOR - // meow + printf("Largest free block before tidy %d\n", gMainHeap.GetLargestFreeBlock()); + + if(moveTextures){ + if(flushDraw){ +#ifdef GTA_PS2 + for(int i = 0; i < sweMaxFlips+1; i++){ +#else + for(int i = 0; i < 5; i++){ // probably more than needed +#endif + RwCameraBeginUpdate(Scene.camera); + RwCameraEndUpdate(Scene.camera); + RwCameraShowRaster(Scene.camera, nil, 0); + } + } + int fontSlot = CTxdStore::FindTxdSlot("fonts"); + + for(int i = 0; i < TXDSTORESIZE; i++){ + if(i == fontSlot || + CTxdStore::GetSlot(i) == nil) + continue; + RwTexDictionary *txd = CTxdStore::GetSlot(i)->texDict; + if(txd) + RwTexDictionaryForAllTextures(txd, MoveTextureMemoryCB, nil); + } + } + + // animations + for(int i = 0; i < NUMANIMATIONS; i++){ + CAnimBlendHierarchy *anim = CAnimManager::GetAnimation(i); + if(anim == nil) + continue; // cannot happen + anim->MoveMemory(); + } + + // model info + for(int i = 0; i < MODELINFOSIZE; i++){ + CBaseModelInfo *mi = CModelInfo::GetModelInfo(i); + if(mi == nil) + continue; + TidyUpModelInfo(mi, false); + } + + printf("Largest free block after tidy %d\n", gMainHeap.GetLargestFreeBlock()); #endif } void CGame::ProcessTidyUpMemory(void) { #ifdef USE_CUSTOM_ALLOCATOR - // meow + static int32 modelIndex = 0; + static int32 animIndex = 0; + static int32 txdIndex = 0; + bool txdReturn = false; + RwTexDictionary *txd = nil; + gNumMemMoved = 0; + + // model infos + for(int numCleanedUp = 0; numCleanedUp < 10; numCleanedUp++){ + CBaseModelInfo *mi; + do{ + mi = CModelInfo::GetModelInfo(modelIndex); + modelIndex++; + if(modelIndex >= MODELINFOSIZE) + modelIndex = 0; + }while(mi == nil); + + if(TidyUpModelInfo(mi, true)) + return; + } + + // tex dicts + for(int numCleanedUp = 0; numCleanedUp < 3; numCleanedUp++){ + if(gNumMemMoved > 80) + break; + + do{ +#ifdef FIX_BUGS + txd = nil; +#endif + if(CTxdStore::GetSlot(txdIndex)) + txd = CTxdStore::GetSlot(txdIndex)->texDict; + txdIndex++; + if(txdIndex >= TXDSTORESIZE) + txdIndex = 0; + }while(txd == nil); + + RwTexDictionaryForAllTextures(txd, MoveTextureMemoryCB, &txdReturn); + if(txdReturn) + return; + } + + // animations + CAnimBlendHierarchy *anim; + do{ + anim = CAnimManager::GetAnimation(animIndex); + animIndex++; + if(animIndex >= NUMANIMATIONS) + animIndex = 0; + }while(anim == nil); // always != nil + anim->MoveMemory(true); #endif } diff --git a/src/core/main.cpp b/src/core/main.cpp index 102548b6..fa16b6c2 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -415,6 +415,7 @@ PluginAttach(void) return TRUE; } +// rather different on PS2 static RwBool Initialise3D(void *param) { diff --git a/src/rw/MemoryHeap.cpp b/src/rw/MemoryHeap.cpp index 0b333ce1..469262d3 100644 --- a/src/rw/MemoryHeap.cpp +++ b/src/rw/MemoryHeap.cpp @@ -187,7 +187,7 @@ CMemoryHeap::Malloc(uint32 size) void *mem = Malloc(size); if (removeCollision) { CTimer::Stop(); - // different on PS2 + // TODO: different on PS2 CFileLoader::LoadCollisionFromDatFile(CCollision::ms_collisionInMemory); removeCollision = false; CTimer::Update(); diff --git a/src/rw/MemoryHeap.h b/src/rw/MemoryHeap.h index 484cbfab..23163c1c 100644 --- a/src/rw/MemoryHeap.h +++ b/src/rw/MemoryHeap.h @@ -198,6 +198,7 @@ public: void TidyHeap(void); uint32 GetMemoryUsed(int32 id); uint32 GetBlocksUsed(int32 id); + int32 GetLargestFreeBlock(void) { return m_freeList.m_last.m_prev->m_size; } void ParseHeap(void); From e33ab44b7d179a59887200fe6d22c15fa557c5e2 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 1 Dec 2020 22:08:05 +0200 Subject: [PATCH 102/129] Add GTA_REPLAY --- src/control/Pickups.cpp | 4 ++-- src/control/Replay.cpp | 3 ++- src/control/Replay.h | 33 ++++++++++++++++++++++----------- src/core/config.h | 1 + 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 2503f5c8..1b1c8cbc 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -353,11 +353,11 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId) m_pObject->GetMatrix().UpdateRW(); m_pObject->UpdateRwFrame(); - if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0) && waterLevel >= m_pObject->GetPosition().z) + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false) && waterLevel >= m_pObject->GetPosition().z) m_eType = PICKUP_FLOATINGPACKAGE_FLOATING; break; case PICKUP_FLOATINGPACKAGE_FLOATING: - if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, 0)) + if (CWaterLevel::GetWaterLevel(m_pObject->GetPosition().x, m_pObject->GetPosition().y, m_pObject->GetPosition().z + 5.0f, &waterLevel, false)) m_pObject->GetMatrix().GetPosition().z = waterLevel; m_pObject->GetMatrix().UpdateRW(); diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index f21703ac..757af0a9 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -1,5 +1,5 @@ #include "common.h" - +#ifdef GTA_REPLAY #include "AnimBlendAssociation.h" #include "Boat.h" #include "SpecialFX.h" @@ -1585,3 +1585,4 @@ void CReplay::Display() if (Mode == MODE_PLAYBACK) CFont::PrintString(SCREEN_SCALE_X(63.5f), SCREEN_SCALE_Y(30.0f), TheText.Get("REPLAY")); } +#endif diff --git a/src/control/Replay.h b/src/control/Replay.h index 66bee3bf..cb58a602 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -63,6 +63,12 @@ struct CStoredDetailedAnimationState void PlayReplayFromHD(void); +#ifdef GTA_REPLAY +#define REPLAY_STUB +#else +#define REPLAY_STUB {} +#endif + class CReplay { enum { @@ -273,20 +279,24 @@ private: #endif public: - static void Init(void); - static void DisableReplays(void); - static void EnableReplays(void); - static void Update(void); - static void FinishPlayback(void); - static void EmptyReplayBuffer(void); - static void Display(void); - static void TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene); - static void StreamAllNecessaryCarsAndPeds(void); - static bool ShouldStandardCameraBeProcessed(void); + static void Init(void) REPLAY_STUB; + static void DisableReplays(void) REPLAY_STUB; + static void EnableReplays(void) REPLAY_STUB; + static void Update(void) REPLAY_STUB; + static void FinishPlayback(void) REPLAY_STUB; + static void EmptyReplayBuffer(void) REPLAY_STUB; + static void Display(void) REPLAY_STUB; + static void TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene) REPLAY_STUB; + static void StreamAllNecessaryCarsAndPeds(void) REPLAY_STUB; +#ifndef GTA_REPLAY + static bool ShouldStandardCameraBeProcessed(void) { return true; } + static bool IsPlayingBack() { return false; } + static bool IsPlayingBackFromFile() { return false; } +#else + static bool ShouldStandardCameraBeProcessed(void); static bool IsPlayingBack() { return Mode == MODE_PLAYBACK; } static bool IsPlayingBackFromFile() { return bPlayingBackFromFile; } - private: static void RecordThisFrame(void); static void StorePedUpdate(CPed *ped, int id); @@ -314,4 +324,5 @@ private: /* Absolute nonsense, but how could this function end up being outside of class? */ friend void PlayReplayFromHD(void); +#endif }; diff --git a/src/core/config.h b/src/core/config.h index 5d528d50..07e91ee2 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -196,6 +196,7 @@ enum Config { # define RANDOMSPLASH // use random splash as on PS2 # define PS2_MATFX # endif +# define GTA_REPLAY #elif defined GTA_XBOX #endif From 4980386e9ab8020e3bde3447330f85d84adca3df Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 11:54:35 +0100 Subject: [PATCH 103/129] Spanish translation: adding new re3 strings. --- gamefiles/TEXT/spanish.gxt | Bin 246088 -> 251590 bytes utils/gxt/spanish.txt | 372 ++++++++++++++++++++++++++++++++++++- 2 files changed, 371 insertions(+), 1 deletion(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 0fdccce3bfe30dc99a4edc338caf0d27e57f44a2..06ad194a02f0603a501a4a55f0246e7ae17afbfa 100644 GIT binary patch delta 48641 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 delta 43782 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 Mzeih6(D#)8A0B8{^Z)<= diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index c0da2239..e7dc1537 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -8021,11 +8021,381 @@ Error al cargar el juego. El juego se reiniciará. RESTAURADO AJUSTE ORIGINAL [FET_RSC] -HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL HARDWARE NOT AVAILABLE - ORIGINAL SETTING RESTORED +HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL [CRED270] MIKE HONG +{ ======================================================================= } +{ ================= NEW STRINGS FROM THE iOS CONVERSION ================= } +{ ======================================================================= } + +[FEC_OFI] +Puedes arrastrar los botones y elementos de la interfaz. Toca dos veces cualquier botón para cambiar su tamaño. Toca dos veces la pantalla para volver al menú. + +[FEL_JPN] +JAPONÉS + +[MM_MARK] +MARKETING + +[MM_INV] +INVENCIBILIDAD + +[MM_MODE] +MODO DE MARKETING + +[MM_SLV] +PERMITIR SALTO DE NIVEL + +[MM_TUTS] +DESACTIVAR TUTORIALES + +[FET_RMS] +REINTENTAR MISIÓN + +[FESZ_RM] +¿REINTENTAR? + +[FET_CT7] +INVERTIR VISTA + +[FEA_OFF] +RADIO APAGADA + +[FEM_SL0] +Autoguardado sin usar + +[RM_KEY] +Leyenda + +[RM_TONI] +Toni Cipriani + +[RM_SALV] +Salvatore Leone + +[RM_RAY] +Ray Machowski + +[RM_KEN] +Kenji Kasen + +[RM_JOEY] +Joey Leone + +[RM_DON] +Donald Love + +[RM_EIG] +8 Ball + +[RM_ASU] +Asuka Kasen + +[RM_LUIG] +Club de Luigi + +[RM_CATA] +Catalina + +[RM_BPHO] +Diablos + +[RM_GPHO] +Jamaicanos + +[RM_RPHO] +Hoods + +[RM_SPRY] +Taller de pintura + +[RM_AMMU] +Ammu-Nation + +[RM_SAFE] +Piso franco + +[RM_BOMB] +Bombas + +[RM_G1] +Cártel colombiano + +[RM_G2] +Familia Leone + +[RM_G3] +Diablos + +[RM_G4] +Tríadas + +[RM_G5] +Yakuza + +[RM_G6] +Yardies + +[RM_G7] +Hoods del sur + +[SPLASH] +Toca para continuar + +[FEM_SL9] +Autoguardado sin usar + +[NEW_H1] +Toca el radar para acceder al mapa de la ciudad. Podrás ver tu objetivo así como los lugares importantes. + +[TUT_RAD] +Para cambiar la emisora de radio, desliza sobre el nombre de la emisora hacia la izquiera o a la derecha. + +[NEW_H2] +Para mirar alrededor, pulsa en el centro y desliza el dedo por la pantalla. + +{ EXTRA CREDIT STRINGS } + +[CRED345] +War Drum Studios + +[CRED346] +Thomas Williamson + +[CRED347] +Michael Owen + +[CRED348] +Morgan Hughes + +[CRED349] +Abner Williamson + +[RM_YOU] +Tu posición + +[RM_TARG] +Objetivo + +[RM_GANG] +Mostrar bandas + +[CNT_FOT] +a pie + +[CNT_LFT] +Izquierda + +[CNT_RHT] +Derecha + +[CNT_JMP] +Saltar + +[CNT_RUN] +Correr + +[CNT_SCP] +Mira + +[CNT_SHT] +Disparar + +[CNT_PCH] +Golpear + +[CNT_THR] +Lanzar + +[CNT_ZIN] +Acercar vista + +[CNT_ZOT] +Alejar vista + +[CNT_CAR] +en vehículo + +[CNT_ACL] +Acelerar + +[CNT_BRK] +Frenar + +[CNT_EEX] +Entrar/salir vehíc. + +[CNT_STC] +Disparar + +[CNT_HBK] +Freno de mano + +[CNT_HRN] +Claxon + +[CNT_RTL] +Girar a la izq. + +[CNT_RTR] +Girar a la der. + +[CNT_ATM] +Activar misión + +[CNT_MNU] +Menú + +[CNT_CAM] +Cámara + +[FED_HAP] +Vibración + +[FEL_KOR] +Coreano + +[FEM_CL7] +El archivo 7 no está en la nube + +[FEM_CL8] +El archivo 8 no está en la nube + +[FEM_NC] +La nube no está disponible + +[FEM_CSE] +Espacio vacío en la nube + +[FEH_RTE] +Valora GTA III + +[T_RATE] +Si te gusta jugar a GTA III, puntúalo. ~N~¡Gracias por tu apoyo! + +{ re3 updates } +{ new languages } +[FEL_JAP] +JAPONÉS + +[FEL_POL] +POLACO + +[FEL_RUS] +RUSO + +{ new display menus } +[FET_GRA] +AJUSTES GRÁFICOS + +[FED_MIP] +MIPMAPPING + +[FED_AAS] +SUAVIZADO DE BORDES + +[FED_FIL] +FILTRO DE TEXTURAS + +[FED_BIL] +BILINEAL + +[FED_TRL] +TRILINEAL + +[FED_WND] +VENTANA + +[FED_FLS] +PANTALLA COMPLETA + +[FEM_CSB] +BORDES EN CINEMÁTICAS + +[FEM_SCF] +FORMATO DE IMAGEN + +[FEM_ISL] +USO DE MEMORIA + +[FEM_LOW] +BAJO + +[FEM_MED] +MEDIO + +[FEM_HIG] +ALTO + +[FEM_2PR] +ALPHA TEST TIPO PS2 + +[FEC_FRC] +CÁMARA LIBRE + +{ Linux joy detection } +[FEC_JOD] +DETECTAR JOYSTICK + +[FEC_JPR] +Pulsa cualquier botón del joystick que quieras usar con el juego para seleccionarlo. + +[FEC_JDE] +Joystick detectado + +{ mission restart } +[FET_RMS] +REPETIR MISIÓN + +[FESZ_RM] +¿REINTENTAR? + +[FED_VPL] +FLUJO DE VEHÍCULOS + +[FED_PRM] +LUCES EN PEATONES + +[FED_RGL] +BRILLO DE CARRETERAS + +[FED_CLF] +FILTRO DE COLOR + +[FED_WLM] +MAPAS DE LUZ DEL MUNDO + +[FED_MBL] +DESENFOQ. MOVIMIENTO + +[FEM_SIM] +SIMPLE + +[FEM_NRM] +NORMAL + +[FEM_MOB] +MÓVIL + +[FED_MFX] +MATFX + +[FED_NEO] +NEO + +[FEM_PS2] +PS2 + +[FEM_XBX] +XBOX + +[FEC_IVP] +INVERTIR VERTICALIDAD MANDO + +{ end of file } + [DUMMY] THIS LABEL NEEDS TO BE HERE !!! AS THE LAST LABEL DOES NOT GET COMPILED \ No newline at end of file From 1a30d94523230fed15679861520881f903364f44 Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 16:00:41 +0100 Subject: [PATCH 104/129] Removing iOS strings as requested. --- gamefiles/TEXT/spanish.gxt | Bin 251590 -> 247600 bytes utils/gxt/spanish.txt | 249 ------------------------------------- 2 files changed, 249 deletions(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 06ad194a02f0603a501a4a55f0246e7ae17afbfa..13aa6f29f45fdf82b650babb011b8e31621bd602 100644 GIT binary patch delta 582 zcmX@MmVZMZKU;{mYotZ}Mm9OV%@+J8csJX~ws0;!qsGi+;5zx7<}#)Y?vu;3l#C?Y zm>Jw$o#VY+Tp3pAK-sn7{7U08BXAUti z+%uSg3u<7vk1vCp%jPm;A;!s5OgyBDz=r$8dpQO$G(p(`{yq#7oG0^{iivZ8{qGxZ z6cEJFWyc8grf%Q?G!66K%Tqd70 z6=QngGWnTlpVTL)DqmL@hEwt&2l~eQ`Z6%oxlish6XPp$gb4ZhGcXjmPu^#y$28A< z@;fst@nukr!Om_BNnqdj#s_=)PWCoWoV>%lg=v}lW;=^AW~Lao&4;Y{m?qz`ZDE?_ zygA8^jgiUDZF8BulKSK;X$Lm1Nf+SW%u~X`v{|OCfqnCq+89=*7w*kM&FwfL6!z&3`-J`7dYu^10==ez1I5)N2hadGd$LKA)~V=cFiGj7nzKp~J4ikxN&U zJQMWN6H1;nT{^AgSu>#P3R~78y4fpz^Ik+BD7l^KrF)gH9Te%W%BIKl={FMBN=`na z$CQyHV%lCeb85=w8CN5r!|WhzHcq!C`)@4j_iPJ zXO(1qxKN}ar8w+G^|tgcKfUjdJx~T#uDzp^KDv!}(K==&mSAzJ7?LpgXN}Y$= z@TEHMg!FABkVDv}AHTP~`9VFD?{3DSXc6ZR(KnR8Tkz=-B`;bYy}MTv{=R9`(IC$3 zSf@W7#7B3GrvIrtqQIetg7~c+tJ7};GWbEqrThH4zH_D4aH+^LyA(uL+}K{|*)QCj zQjh7=wH)h!{UW_6h&rWSFCa(R_#RqS;h-<1!QIk6^i6u*kI%KQZhA$yxuvYrMIYYA zyW{V+uW!nUJU|y_XjIT(Y{kECU%&GgN@o|kX|+hFTe8E5o>B5b=+G@CcTlfue!QjQ zT+dIG+O=}@tF_F=Ex9g{Em8*TWoW)r$$g>@wQVs=G-FD6(IeU$#((eFrXLUE4V`=2 zCRNlho2RWRQdn^5ebH8KDRj2Sk9L+DCT$rZboRu5=sc@WhV`%Pnn|TE2)pobDR5~+ zP=9kzT5q@}WKk&_b;W<$cUB+r>ZALYY3XSt58ROM4(in}t=qWoP1M14ONC-T(M^e6 z6W76q3VS(=*1!)op#vLR;;1hQ<9O&s(p{=$6D53Px9@O*i(V*A?Cg{AY#R zfj^SC*4=@ZG#G+JcPH>?72XBBRpBn+7ctdrV-~w>}(W~e>Mv+DJcV-`6s$UDA%-5dE z*EB4BAzw>PXM24*Ny9XRHAM!Msfu42cv?KGkd4uV&<)}_ja5;$v(ODgJ51wP6`D@w z&TEYij4*_tN=Fgs6m5f91h*r2Gq8~iHUoOBT2kAVv3xXFnuG$^vJw z9IPBHbHc;J(*va(Y>Ycb@SzEyDR9(B01a$rB24sejzy?>8wWu-6kB8kjebFj)6*wB z0$8#)+Yq8zcrQZ36eBW|^FL4BUtGhpJREMc9A1akq8 z;mL&_!e6e3f%0b zHP;9^EQ@X#6XeTq$pMvVP<1TtC3|T^G+zZfPr=H@a{|X=9KnLO<96ld9LC>C5pNos z^CU2lar{ow{YX6TI0Em=Rw#VHDZCiybT+MEn+eD>_&W|7d}yY5A(=a_tp(#eMB{K` z#(XSJvYe;?Z)^IGFt9$(HFXO6RI;A~}NPmcL;VvcG}tp>8h$*$4`5Hg78o*j_h zok@Llt{278j1dd}Ybnaor5GE;sN<^4l~nl{OLZB<QsoCX5s&H_oRT4-#&r37AeoDUBUGE26pC*u>e`jlUV3^BFkv zC#fuSJg%d6&&5^q5L{cXH;s*1D8C1MvA&(^96mEqP}_47V$Gn}-$?k4o{r%(ox=3<``6 zqnE&AF*SU4?oq;R&f~)#T+i}l>EeEJIlaaCm(S5VtQ=-}_%F#unv|62e~ zKii6car^a+xUDQ~%G1oWnZ%61mldHq(ddT-|FE%Sbs5P(P0b=h->^_V2g@uKiso5p} E0;5GbMgRZ+ diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index e7dc1537..22063c35 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -8026,255 +8026,6 @@ HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL [CRED270] MIKE HONG -{ ======================================================================= } -{ ================= NEW STRINGS FROM THE iOS CONVERSION ================= } -{ ======================================================================= } - -[FEC_OFI] -Puedes arrastrar los botones y elementos de la interfaz. Toca dos veces cualquier botón para cambiar su tamaño. Toca dos veces la pantalla para volver al menú. - -[FEL_JPN] -JAPONÉS - -[MM_MARK] -MARKETING - -[MM_INV] -INVENCIBILIDAD - -[MM_MODE] -MODO DE MARKETING - -[MM_SLV] -PERMITIR SALTO DE NIVEL - -[MM_TUTS] -DESACTIVAR TUTORIALES - -[FET_RMS] -REINTENTAR MISIÓN - -[FESZ_RM] -¿REINTENTAR? - -[FET_CT7] -INVERTIR VISTA - -[FEA_OFF] -RADIO APAGADA - -[FEM_SL0] -Autoguardado sin usar - -[RM_KEY] -Leyenda - -[RM_TONI] -Toni Cipriani - -[RM_SALV] -Salvatore Leone - -[RM_RAY] -Ray Machowski - -[RM_KEN] -Kenji Kasen - -[RM_JOEY] -Joey Leone - -[RM_DON] -Donald Love - -[RM_EIG] -8 Ball - -[RM_ASU] -Asuka Kasen - -[RM_LUIG] -Club de Luigi - -[RM_CATA] -Catalina - -[RM_BPHO] -Diablos - -[RM_GPHO] -Jamaicanos - -[RM_RPHO] -Hoods - -[RM_SPRY] -Taller de pintura - -[RM_AMMU] -Ammu-Nation - -[RM_SAFE] -Piso franco - -[RM_BOMB] -Bombas - -[RM_G1] -Cártel colombiano - -[RM_G2] -Familia Leone - -[RM_G3] -Diablos - -[RM_G4] -Tríadas - -[RM_G5] -Yakuza - -[RM_G6] -Yardies - -[RM_G7] -Hoods del sur - -[SPLASH] -Toca para continuar - -[FEM_SL9] -Autoguardado sin usar - -[NEW_H1] -Toca el radar para acceder al mapa de la ciudad. Podrás ver tu objetivo así como los lugares importantes. - -[TUT_RAD] -Para cambiar la emisora de radio, desliza sobre el nombre de la emisora hacia la izquiera o a la derecha. - -[NEW_H2] -Para mirar alrededor, pulsa en el centro y desliza el dedo por la pantalla. - -{ EXTRA CREDIT STRINGS } - -[CRED345] -War Drum Studios - -[CRED346] -Thomas Williamson - -[CRED347] -Michael Owen - -[CRED348] -Morgan Hughes - -[CRED349] -Abner Williamson - -[RM_YOU] -Tu posición - -[RM_TARG] -Objetivo - -[RM_GANG] -Mostrar bandas - -[CNT_FOT] -a pie - -[CNT_LFT] -Izquierda - -[CNT_RHT] -Derecha - -[CNT_JMP] -Saltar - -[CNT_RUN] -Correr - -[CNT_SCP] -Mira - -[CNT_SHT] -Disparar - -[CNT_PCH] -Golpear - -[CNT_THR] -Lanzar - -[CNT_ZIN] -Acercar vista - -[CNT_ZOT] -Alejar vista - -[CNT_CAR] -en vehículo - -[CNT_ACL] -Acelerar - -[CNT_BRK] -Frenar - -[CNT_EEX] -Entrar/salir vehíc. - -[CNT_STC] -Disparar - -[CNT_HBK] -Freno de mano - -[CNT_HRN] -Claxon - -[CNT_RTL] -Girar a la izq. - -[CNT_RTR] -Girar a la der. - -[CNT_ATM] -Activar misión - -[CNT_MNU] -Menú - -[CNT_CAM] -Cámara - -[FED_HAP] -Vibración - -[FEL_KOR] -Coreano - -[FEM_CL7] -El archivo 7 no está en la nube - -[FEM_CL8] -El archivo 8 no está en la nube - -[FEM_NC] -La nube no está disponible - -[FEM_CSE] -Espacio vacío en la nube - -[FEH_RTE] -Valora GTA III - -[T_RATE] -Si te gusta jugar a GTA III, puntúalo. ~N~¡Gracias por tu apoyo! - { re3 updates } { new languages } [FEL_JAP] From 9461998304219f91b3b24484d0cee5b5c5d4523c Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 23 Nov 2020 22:46:07 +0200 Subject: [PATCH 105/129] TexturePools --- src/core/Game.cpp | 3 + src/rw/RwHelper.cpp | 5 - src/rw/RwHelper.h | 2 - src/rw/TexturePools.cpp | 221 ++++++++++++++++++++++++++++++++++++++++ src/rw/TexturePools.h | 42 ++++++++ 5 files changed, 266 insertions(+), 7 deletions(-) create mode 100644 src/rw/TexturePools.cpp create mode 100644 src/rw/TexturePools.h diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 262aa54a..9a604757 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -91,6 +91,9 @@ #include "screendroplets.h" #include "crossplatform.h" #include "MemoryHeap.h" +#ifdef USE_TEXTURE_POOL +#include "TexturePools.h" +#endif eLevelName CGame::currLevel; bool CGame::bDemoMode = true; diff --git a/src/rw/RwHelper.cpp b/src/rw/RwHelper.cpp index ee370c37..e0133985 100644 --- a/src/rw/RwHelper.cpp +++ b/src/rw/RwHelper.cpp @@ -605,11 +605,6 @@ CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer) return (nil); } -#ifdef USE_TEXTURE_POOL -WRAPPER void _TexturePoolsInitialise() { EAXJMP(0x598B10); } -WRAPPER void _TexturePoolsShutdown() { EAXJMP(0x598B30); } -#endif - #ifdef LIBRW #include #include "VehicleModelInfo.h" diff --git a/src/rw/RwHelper.h b/src/rw/RwHelper.h index ed9b03ab..1a5f64b1 100644 --- a/src/rw/RwHelper.h +++ b/src/rw/RwHelper.h @@ -50,8 +50,6 @@ RwCamera *CameraCreate(RwInt32 width, RwBool zBuffer); -void _TexturePoolsInitialise(); -void _TexturePoolsShutdown(); RpAtomic *ConvertPlatformAtomic(RpAtomic *atomic, void *data); diff --git a/src/rw/TexturePools.cpp b/src/rw/TexturePools.cpp new file mode 100644 index 00000000..c2ba6cf9 --- /dev/null +++ b/src/rw/TexturePools.cpp @@ -0,0 +1,221 @@ +#ifndef LIBRW + +#include +#define WITHD3D +#include "common.h" +#include "TexturePools.h" + +// TODO: this needs to be integrated into RW + +extern "C" LPDIRECT3DDEVICE8 _RwD3DDevice; + +CTexturePool aTexturePools[12]; +CPaletteList PaletteList; +int numTexturePools; +int MaxPaletteIndex; +bool bUsePaletteIndex = true; + + +void +CTexturePool::Create(D3DFORMAT _Format, int _size, uint32 mipmapLevels, int32 numTextures) +{ + Format = _Format; + size = _size; + levels = mipmapLevels; + pTextures = new IDirect3DTexture8 *[numTextures]; + texturesMax = numTextures; + texturesNum = 0; + texturesUsed = 0; +} + +void +CTexturePool::Release() +{ + int i = 0; + while (i < texturesNum) { + pTextures[i]->Release(); + i++; + } + + delete[] pTextures; + + pTextures = nil; + texturesNum = 0; + texturesUsed = 0; +} + +IDirect3DTexture8 * +CTexturePool::FindTexture() +{ + if (texturesNum == 0) + return nil; + texturesUsed--; + return pTextures[--texturesNum]; +} + +bool +CTexturePool::AddTexture(IDirect3DTexture8 *texture) +{ + ++texturesUsed; + if (texturesNum >= texturesMax) + return false; + pTextures[texturesNum] = texture; + ++texturesNum; + return true; +} + +void +CTexturePool::Resize(int numTextures) +{ + if (numTextures == texturesMax) + return; + + IDirect3DTexture8 **newTextures = new IDirect3DTexture8 *[numTextures]; + + for (int i = 0; i < texturesNum && i < numTextures; i++) + newTextures[i] = pTextures[i]; + + if (numTextures < texturesNum) { + for (int i = numTextures; i < texturesNum; i++) + pTextures[i]->Release(); + } + delete[] pTextures; + pTextures = newTextures; + texturesMax = numTextures; +} + +void +CPaletteList::Alloc(int max) +{ + Data = new int[max]; + Max = max; + Num = 0; +} + +void +CPaletteList::Free() +{ + delete[] Data; + Data = nil; + Num = 0; +} + +int +CPaletteList::Find() +{ + if (Num == 0) + return -1; + return Data[--Num]; +} + +void +CPaletteList::Add(int item) +{ + if (Num < Max) + Data[Num++] = item; + else { + Resize(2 * Max); + Add(item); + } +} + +void +CPaletteList::Resize(int max) +{ + if (max == Max) + return; + + int *newData = new int[4 * max]; + for (int i = 0; i < Num && i < max; i++) + newData[i] = Data[i]; + delete[] Data; + Data = newData; + Max = max; +} + +HRESULT +CreateTexture(int width, int height, int levels, D3DFORMAT Format, IDirect3DTexture8 **texture) +{ + if (width == height) { + for (int i = 0; i < numTexturePools; i++) { + if (width != aTexturePools[i].GetSize() && levels == aTexturePools[i].levels && Format == aTexturePools[i].Format) + *texture = aTexturePools[i].FindTexture(); + } + } + if (*texture) + return D3D_OK; + else + return _RwD3DDevice->CreateTexture(width, height, levels, 0, Format, D3DPOOL_MANAGED, texture); +} + +void +ReleaseTexture(IDirect3DTexture8 *texture) +{ + int levels = 1; + if (texture->GetLevelCount() > 1) + levels = 0; + + D3DSURFACE_DESC SURFACE_DESC; + + texture->GetLevelDesc(0, &SURFACE_DESC); + + if (SURFACE_DESC.Width == SURFACE_DESC.Height) { + for (int i = 0; i < numTexturePools; i++) { + if (SURFACE_DESC.Width == aTexturePools[i].GetSize() && SURFACE_DESC.Format == aTexturePools[i].Format && levels == aTexturePools[i].levels) { + if (!aTexturePools[i].AddTexture(texture)) { + if (aTexturePools[i].texturesUsed > 3 * aTexturePools[i].texturesMax / 2) { + aTexturePools[i].Resize(2 * aTexturePools[i].texturesMax); + aTexturePools[i].texturesUsed--; + aTexturePools[i].AddTexture(texture); + } else { + texture->Release(); + } + } + return; + } + } + } + if (numTexturePools < 12 && bUsePaletteIndex && levels != 0 && SURFACE_DESC.Width == SURFACE_DESC.Height && + (SURFACE_DESC.Width == 64 || SURFACE_DESC.Width == 128 || SURFACE_DESC.Width == 256)) { + aTexturePools[numTexturePools].Create(SURFACE_DESC.Format, SURFACE_DESC.Width, 1, 16); + aTexturePools[numTexturePools].AddTexture(texture); + numTexturePools++; + } else + texture->Release(); +} + +int +FindAvailablePaletteIndex() +{ + int index = PaletteList.Find(); + if (index == -1) + index = MaxPaletteIndex++; + return index; +} + +void +AddAvailablePaletteIndex(int index) +{ + if (bUsePaletteIndex) + PaletteList.Add(index); +} + +void +_TexturePoolsInitialise() +{ + PaletteList.Alloc(100); + MaxPaletteIndex = 0; +} + +void +_TexturePoolsShutdown() +{ + for (int i = 0; i < numTexturePools; i++) + aTexturePools[i].Release(); + + numTexturePools = 0; + bUsePaletteIndex = false; + PaletteList.Free(); +} + +#endif // !LIBRW \ No newline at end of file diff --git a/src/rw/TexturePools.h b/src/rw/TexturePools.h new file mode 100644 index 00000000..75187432 --- /dev/null +++ b/src/rw/TexturePools.h @@ -0,0 +1,42 @@ +#pragma once + +class CTexturePool +{ +public: + D3DFORMAT Format; + int size; + uint32 levels; + int32 texturesMax; + int32 texturesUsed; + int32 texturesNum; + IDirect3DTexture8 **pTextures; + +public: + CTexturePool() {} + void Create(D3DFORMAT _Format, int size, uint32 mipmapLevels, int32 numTextures); + void Release(); + IDirect3DTexture8 *FindTexture(); + bool AddTexture(IDirect3DTexture8 *texture); + void Resize(int numTextures); +#ifdef FIX_BUGS + int GetSize() { return size; } +#else + float GetSize() { return size; } +#endif +}; + +class CPaletteList +{ + int Max; + int Num; + int *Data; +public: + void Alloc(int max); + void Free(); + int Find(); + void Add(int item); + void Resize(int max); +}; + +void _TexturePoolsInitialise(); +void _TexturePoolsShutdown(); \ No newline at end of file From 0b20fd7e77dafc34cf9eebc3ffd25318a7d81476 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 1 Dec 2020 22:35:53 +0200 Subject: [PATCH 106/129] Remove ifndef GTA_PS2 around replays --- src/core/Game.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 9a604757..6b9fd11f 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -581,9 +581,7 @@ bool CGame::Initialise(const char* datFile) CPlane::InitPlanes(); CCredits::Init(); CRecordDataForChase::Init(); -#ifndef GTA_PS2 // TODO: define for that CReplay::Init(); -#endif #ifdef PS2_MENU if ( !TheMemoryCard.m_bWantToLoad ) @@ -773,10 +771,8 @@ void CGame::ReloadIPLs(void) void CGame::ShutDownForRestart(void) { -#ifndef GTA_PS2 // TODO: right define CReplay::FinishPlayback(); CReplay::EmptyReplayBuffer(); -#endif DMAudio.DestroyAllGameCreatedEntities(); for (int i = 0; i < NUMPLAYERS; i++) @@ -996,9 +992,7 @@ void CGame::Process(void) CMovingThings::Update(); CWaterCannons::Update(); CUserDisplay::Process(); -#ifndef GTA_PS2 // TODO: define CReplay::Update(); -#endif PUSH_MEMID(MEMID_WORLD); CWorld::Process(); @@ -1011,14 +1005,10 @@ void CGame::Process(void) CRubbish::Update(); CSpecialFX::Update(); CTimeCycle::Update(); -#ifndef GTA_PS2 // TODO: define if (CReplay::ShouldStandardCameraBeProcessed()) -#endif TheCamera.Process(); CCullZones::Update(); -#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) -#endif CGameLogic::Update(); CBridge::Update(); CCoronas::DoSunAndMoon(); @@ -1026,9 +1016,7 @@ void CGame::Process(void) CShadows::UpdateStaticShadows(); CShadows::UpdatePermanentShadows(); gPhoneInfo.Update(); -#ifndef GTA_PS2 // TODO: define if (!CReplay::IsPlayingBack()) -#endif { PUSH_MEMID(MEMID_CARS); CCarCtrl::GenerateRandomCars(); From fda58fb1dfaba95c72f564d155560abd8d10b794 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Wed, 2 Dec 2020 02:34:51 +0300 Subject: [PATCH 107/129] added GTA_SCENE_EDIT --- src/control/SceneEdit.cpp | 3 ++- src/control/SceneEdit.h | 3 ++- src/core/Cam.cpp | 5 ++++- src/core/Camera.cpp | 2 ++ src/core/Camera.h | 2 ++ src/core/Game.cpp | 4 ++-- src/core/config.h | 1 + src/core/main.cpp | 2 ++ src/core/re3.cpp | 2 ++ 9 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/control/SceneEdit.cpp b/src/control/SceneEdit.cpp index 154fe603..8224c1d4 100644 --- a/src/control/SceneEdit.cpp +++ b/src/control/SceneEdit.cpp @@ -1,7 +1,7 @@ #include "common.h" #include "SceneEdit.h" - +#ifdef GTA_SCENE_EDIT #include "Automobile.h" #include "Camera.h" #include "CarCtrl.h" @@ -1096,3 +1096,4 @@ bool CSceneEdit::SelectWeapon(void) } return false; } +#endif diff --git a/src/control/SceneEdit.h b/src/control/SceneEdit.h index 6dcefa31..7c8fb98a 100644 --- a/src/control/SceneEdit.h +++ b/src/control/SceneEdit.h @@ -1,5 +1,5 @@ #pragma once - +#ifdef GTA_SCENE_EDIT class CPed; class CVehicle; @@ -93,3 +93,4 @@ public: static void SelectVehicle(void); static bool SelectWeapon(void); }; +#endif diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 0e1c9d9f..3913274a 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -263,9 +263,11 @@ CCam::Process(void) case MODE_FIGHT_CAM_RUNABOUT: Process_1rstPersonPedOnPC(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); break; +#ifdef GTA_SCENE_EDIT case MODE_EDITOR: Process_Editor(CameraTarget, TargetOrientation, SpeedVar, TargetSpeedVar); break; +#endif default: Source = CVector(0.0f, 0.0f, 0.0f); Front = CVector(0.0f, 1.0f, 0.0f); @@ -3919,6 +3921,7 @@ CCam::Process_Debug(const CVector&, float, float, float) } #endif +#ifdef GTA_SCENE_EDIT void CCam::Process_Editor(const CVector&, float, float, float) { @@ -3935,7 +3938,6 @@ CCam::Process_Editor(const CVector&, float, float, float) FOV = DefaultFOV; Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f; Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX()*1.5f) / 19.0f; - if(CamTargetEntity && CSceneEdit::m_bCameraFollowActor){ TargetCoors = CamTargetEntity->GetPosition(); }else if(CSceneEdit::m_bRecording){ @@ -3997,6 +3999,7 @@ CCam::Process_Editor(const CVector&, float, float, float) sprintf(str, "Look@: %f, Look@: %f, Look@: %f ", Front.x + Source.x, Front.y + Source.y, Front.z + Source.z); } } +#endif void CCam::Process_ModelView(const CVector &CameraTarget, float, float, float) diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 51876c93..f28fb450 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -1576,8 +1576,10 @@ CCamera::CamControl(void) switchByJumpCut = true; } } +#ifdef GTA_SCENE_EDIT if(CSceneEdit::m_bEditOn) ReqMode = CCam::MODE_EDITOR; +#endif if((m_uiTransitionState == 0 || switchByJumpCut) && ReqMode != Cams[ActiveCam].Mode){ if(switchByJumpCut){ diff --git a/src/core/Camera.h b/src/core/Camera.h index 0797db9b..ca1bd135 100644 --- a/src/core/Camera.h +++ b/src/core/Camera.h @@ -213,7 +213,9 @@ public: void PrintMode(void); void Process_Debug(const CVector&, float, float, float); +#ifdef GTA_SCENE_EDIT void Process_Editor(const CVector&, float, float, float); +#endif void Process_ModelView(const CVector &CameraTarget, float, float, float); void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float); void Process_FollowPedWithMouse(const CVector &CameraTarget, float TargetOrientation, float, float); diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 6b9fd11f..586b1469 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -525,7 +525,7 @@ bool CGame::Initialise(const char* datFile) CAntennas::Init(); CGlass::Init(); gPhoneInfo.Initialise(); -#ifndef GTA_PS2 // TODO: define for this +#ifdef GTA_SCENE_EDIT CSceneEdit::Initialise(); #endif @@ -976,7 +976,7 @@ void CGame::Process(void) CSkidmarks::Update(); CAntennas::Update(); CGlass::Update(); -#ifndef GTA_PS2 // TODO: define +#ifdef GTA_SCENE_EDIT CSceneEdit::Update(); #endif CEventList::Update(); diff --git a/src/core/config.h b/src/core/config.h index 07e91ee2..ccea1868 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -197,6 +197,7 @@ enum Config { # define PS2_MATFX # endif # define GTA_REPLAY +# define GTA_SCENE_EDIT #elif defined GTA_XBOX #endif diff --git a/src/core/main.cpp b/src/core/main.cpp index fa16b6c2..ebfa096a 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -1160,9 +1160,11 @@ Render2dStuff(void) MusicManager.DisplayRadioStationName(); TheConsole.Display(); +#ifdef GTA_SCENE_EDIT if(CSceneEdit::m_bEditOn) CSceneEdit::Draw(); else +#endif CHud::Draw(); CUserDisplay::OnscnTimer.ProcessForDisplay(); CMessages::Display(); diff --git a/src/core/re3.cpp b/src/core/re3.cpp index 506b2714..5974175a 100644 --- a/src/core/re3.cpp +++ b/src/core/re3.cpp @@ -580,7 +580,9 @@ DebugMenuPopulate(void) DebugMenuAddVarBool8("Debug", "Disable zone cull", &gbDisableZoneCull, nil); DebugMenuAddVarBool8("Debug", "pad 1 -> pad 2", &CPad::m_bMapPadOneToPadTwo, nil); +#ifdef GTA_SCENE_EDIT DebugMenuAddVarBool8("Debug", "Edit on", &CSceneEdit::m_bEditOn, nil); +#endif #ifdef MENU_MAP DebugMenuAddCmd("Debug", "Teleport to map waypoint", TeleportToWaypoint); #endif From 4b9f1680a376d1b9b968078e09dd76dc7404d645 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Wed, 2 Dec 2020 02:41:05 +0300 Subject: [PATCH 108/129] fast fix --- src/core/Cam.cpp | 1 + src/core/config.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 3913274a..08ebbafd 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -3938,6 +3938,7 @@ CCam::Process_Editor(const CVector&, float, float, float) FOV = DefaultFOV; Alpha += DEGTORAD(CPad::GetPad(1)->GetLeftStickY()) / 50.0f; Beta += DEGTORAD(CPad::GetPad(1)->GetLeftStickX()*1.5f) / 19.0f; + if(CamTargetEntity && CSceneEdit::m_bCameraFollowActor){ TargetCoors = CamTargetEntity->GetPosition(); }else if(CSceneEdit::m_bRecording){ diff --git a/src/core/config.h b/src/core/config.h index ccea1868..4e71224f 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -197,7 +197,7 @@ enum Config { # define PS2_MATFX # endif # define GTA_REPLAY -# define GTA_SCENE_EDIT +# define GTA_SCENE_EDIT #elif defined GTA_XBOX #endif From fba657ff0c77b343ac854a5aed16385a6c77492c Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 2 Dec 2020 10:38:27 +0100 Subject: [PATCH 109/129] better cam lod dist fix --- src/control/PathFind.cpp | 8 ++++++++ src/core/Camera.cpp | 14 +++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index ecd2d0cb..49e43c81 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -1649,10 +1649,18 @@ CPathFind::TestCoorsCloseness(CVector target, uint8 type, CVector start) DoPathSearch(type, start, -1, target, pNodeList, &DummyResult, 32, nil, &dist, 999999.88f, -1); else DoPathSearch(type, start, -1, target, nil, &DummyResult2, 0, nil, &dist, 50.0f, -1); +#ifdef FIX_BUGS + // dist has GenerationDistMultiplier as a factor, so our reference dist should have it too + if(type == PATH_CAR) + return dist < 160.0f*TheCamera.GenerationDistMultiplier; + else + return dist < 100.0f*TheCamera.GenerationDistMultiplier; +#else if(type == PATH_CAR) return dist < 160.0f; else return dist < 100.0f; +#endif } void diff --git a/src/core/Camera.cpp b/src/core/Camera.cpp index 51876c93..4baec2a4 100644 --- a/src/core/Camera.cpp +++ b/src/core/Camera.cpp @@ -713,14 +713,14 @@ CCamera::Process(void) DistanceToWater = CWaterLevel::CalcDistanceToWater(GetPosition().x, GetPosition().y); // LOD dist - if(!CCutsceneMgr::IsRunning() || CCutsceneMgr::UseLodMultiplier()) - LODDistMultiplier = 70.0f/CDraw::GetFOV() * CDraw::GetAspectRatio()/(4.0f/3.0f); - else - LODDistMultiplier = 1.0f; -#ifdef FIX_BUGS - // from VC. to high values bug out spawns - LODDistMultiplier = Min(LODDistMultiplier, 2.2f); + if(!CCutsceneMgr::IsRunning() || CCutsceneMgr::UseLodMultiplier()){ + LODDistMultiplier = 70.0f/CDraw::GetFOV(); +#ifndef FIX_BUGS + // makes no sense and gone in VC + LODDistMultiplier *= CDraw::GetAspectRatio()/(4.0f/3.0f); #endif + }else + LODDistMultiplier = 1.0f; #if GTA_VERSION > GTA3_PS2_160 GenerationDistMultiplier = LODDistMultiplier; LODDistMultiplier *= CRenderer::ms_lodDistScale; From 50bf0f27a00eec43c1b92a9a0ae81b5916442ba2 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 2 Dec 2020 12:58:29 +0100 Subject: [PATCH 110/129] rpDefaultGeometryInstance --- src/rw/VisibilityPlugins.cpp | 91 +++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 6 deletions(-) diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 68775c72..019a781e 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -31,14 +31,93 @@ float CVisibilityPlugins::ms_pedLod0Dist; float CVisibilityPlugins::ms_pedLod1Dist; float CVisibilityPlugins::ms_pedFadeDist; -#ifdef GTA_PS2 -void -rpDefaultGeometryInstance(RpGeometry *geo, void *atomic, int unk) +//#ifdef GTA_PS2 +#if 1 +// if wanted, delete the original geometry data after rendering +// and only keep the instanced data +bool +rpDefaultGeometryInstance(RpGeometry *geo, void *atomic, int del) { - // TODO - // this function seems to delete the original geometry data - // and only keep the instanced data +#if THIS_IS_COMPATIBLE_WITH_GTA3_RW31 + if(RpGeometryGetNumMorphTargets(geo) != 1) + return false; + + // this needs R*'s modification that geometry data is + // allocated separately from the geometry itself + geo->instanceFlags = rpGEOMETRYINSTANCE; AtomicDefaultRenderCallBack((RpAtomic*)atomic); + + if(!del) + return true; + + // New mesh without indices + RpMeshHeader *newheader = _rpMeshHeaderCreate(sizeof(RpMesh)*geo->mesh->numMeshes + sizeof(RpMeshHeader)); + newheader->numMeshes = geo->mesh->numMeshes; + newheader->serialNum = 1; + newheader->totalIndicesInMesh = 0; + newheader->firstMeshOffset = 0; + RpMesh *oldmesh = (RpMesh*)(geo->mesh+1); + RpMesh *newmesh = (RpMesh*)(newheader+1); + for(int i = 0; i < geo->mesh->numMeshes; i++){ + newmesh[i].indices = nil; + newmesh[i].numIndices = 0; + newmesh[i].material = oldmesh[i].material; + } + + geo->refCount++; + RpGeometryLock(geo, rpGEOMETRYLOCKPOLYGONS | rpGEOMETRYLOCKVERTICES | + rpGEOMETRYLOCKNORMALS | rpGEOMETRYLOCKPRELIGHT | + rpGEOMETRYLOCKTEXCOORDS1 | rpGEOMETRYLOCKTEXCOORDS2); + + // vertices and normals + RpMorphTarget *mt = RpGeometryGetMorphTarget(geo, 0); + if(mt->verts){ + RwFree(mt->verts); + mt->verts = nil; + mt->normals = nil; + } + geo->numVertices = 0; + + // triangles + for(int i = 0; i < RpGeometryGetNumTriangles(geo); i++){ + if(RpGeometryGetTriangles(geo)->matIndex == -1) + continue; + RpMaterialDestroy(_rpMaterialListGetMaterial(&geo->matList, RpGeometryGetTriangles(geo)->matIndex)); + } + if(RpGeometryGetTriangles(geo)){ + RwFree(RpGeometryGetTriangles(geo)); + geo->triangles = nil; + geo->numTriangles = 0; + } + + // tex coords + if(RpGeometryGetVertexTexCoords(geo, 1)){ + RwFree(RpGeometryGetVertexTexCoords(geo, 1)); + geo->texCoords[1] = nil; + } + if(RpGeometryGetVertexTexCoords(geo, 0)){ + RwFree(RpGeometryGetVertexTexCoords(geo, 0)); + geo->texCoords[0] = nil; + } + + // vertex colors + if(RpGeometryGetPreLightColors(geo)){ + RwFree(RpGeometryGetPreLightColors(geo)); + geo->preLitLum = nil; + } + + RpGeometryUnlock(geo); + + geo->instanceFlags = rpGEOMETRYPERSISTENT; + // BUG? don't we have to free the old mesh? + geo->mesh = newheader; + geo->refCount--; +#else + // We can do something for librw here actually, maybe later + AtomicDefaultRenderCallBack((RpAtomic*)atomic); +#endif + + return true; } RpAtomic* From 448ba9b7e86e93581df7813bb5250168b5813c72 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 2 Dec 2020 13:08:30 +0100 Subject: [PATCH 111/129] bla --- src/rw/VisibilityPlugins.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index 019a781e..f931019c 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -31,8 +31,7 @@ float CVisibilityPlugins::ms_pedLod0Dist; float CVisibilityPlugins::ms_pedLod1Dist; float CVisibilityPlugins::ms_pedFadeDist; -//#ifdef GTA_PS2 -#if 1 +#ifdef GTA_PS2 // maybe something else? // if wanted, delete the original geometry data after rendering // and only keep the instanced data bool From 3c24505990a9a71210b2328c366b43e6f2fd94bc Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 09:34:09 +0100 Subject: [PATCH 112/129] little fixes for animviewer --- src/core/AnimViewer.cpp | 10 +++++++++- src/core/Cam.cpp | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/core/AnimViewer.cpp b/src/core/AnimViewer.cpp index c8d8cb56..b8354d93 100644 --- a/src/core/AnimViewer.cpp +++ b/src/core/AnimViewer.cpp @@ -49,7 +49,7 @@ CAnimViewer::Render(void) { if (pTarget) { #ifdef FIX_BUGS #ifdef PED_SKIN - if(pTarget->IsPed()) + if(pTarget->IsPed() && IsClumpSkinned(pTarget->GetClump())) ((CPed*)pTarget)->UpdateRpHAnim(); #endif #endif @@ -100,6 +100,9 @@ CAnimViewer::Initialise(void) { CRadar::Initialise(); CRadar::LoadTextures(); CVehicleModelInfo::LoadVehicleColours(); +#ifdef FIX_BUGS + CVehicleModelInfo::LoadEnvironmentMaps(); +#endif CAnimManager::LoadAnimFiles(); CWorld::PlayerInFocus = 0; CWeapon::InitialiseWeapons(); @@ -294,7 +297,12 @@ CAnimViewer::Update(void) if (pTarget->IsVehicle() || pTarget->IsPed() || pTarget->IsObject()) { ((CPhysical*)pTarget)->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); } +#ifdef FIX_BUGS + // so we don't end up in the water + pTarget->GetMatrix().GetPosition().z = 10.0f; +#else pTarget->GetMatrix().GetPosition().z = 0.0f; +#endif if (modelInfo->GetModelType() == MITYPE_PED) { ((CPed*)pTarget)->bKindaStayInSamePlace = true; diff --git a/src/core/Cam.cpp b/src/core/Cam.cpp index 08ebbafd..b20e6db3 100644 --- a/src/core/Cam.cpp +++ b/src/core/Cam.cpp @@ -4014,6 +4014,12 @@ CCam::Process_ModelView(const CVector &CameraTarget, float, float, float) Distance += CPad::GetPad(0)->GetLeftStickY()/1000.0f; else Distance += CPad::GetPad(0)->GetLeftStickY() * ((Distance - 10.0f)/20.0f + 1.0f) / 1000.0f; +#ifdef IMPROVED_CAMERA + if(CPad::GetPad(0)->GetLeftMouse()){ + Distance += DEGTORAD(CPad::GetPad(0)->GetMouseY()/2.0f); + Angle += DEGTORAD(CPad::GetPad(0)->GetMouseX()/2.0f); + } +#endif if(Distance < 1.5f) Distance = 1.5f; From 13cefd329390c119126af6dcf0558ceb7c720e59 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:04:59 +0100 Subject: [PATCH 113/129] more PS2 stuff; memory movement done --- src/collision/TempColModels.cpp | 2 +- src/core/Game.cpp | 250 +++++++++++++++++++++++++++++++- src/core/World.cpp | 36 ++--- src/core/config.h | 10 +- src/modelinfo/BaseModelInfo.h | 4 +- src/modelinfo/SimpleModelInfo.h | 12 ++ src/vehicles/Heli.cpp | 9 ++ 7 files changed, 294 insertions(+), 29 deletions(-) diff --git a/src/collision/TempColModels.cpp b/src/collision/TempColModels.cpp index 849eb01e..dabb6ebb 100644 --- a/src/collision/TempColModels.cpp +++ b/src/collision/TempColModels.cpp @@ -40,7 +40,7 @@ CTempColModels::Initialise(void) colmodel.numSpheres = ARRAY_SIZE(sphrs);\ colmodel.spheres = sphrs;\ colmodel.level = LEVEL_GENERIC;\ - colmodel.ownsCollisionVolumes = false;\ + colmodel.ownsCollisionVolumes = false; int i; diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 586b1469..43e2248f 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -1032,17 +1032,261 @@ void CGame::Process(void) int32 gNumMemMoved; +bool +MoveMem(void **ptr) +{ + if(*ptr){ + gNumMemMoved++; + void *newPtr = gMainHeap.MoveMemory(*ptr); + if(*ptr != newPtr){ + *ptr = newPtr; + return true; + } + } + return false; +} + +typedef struct _SkyRasterExt _SkyRasterExt; +struct _SkyRasterExt +{ + RwInt32 dmaRefCount; /**< Internal use */ + RwInt32 dmaClrCount; /**< Internal use */ + + /* General texture setup register */ + RwUInt32 lsb; /**< Internal use */ + RwUInt32 msb; /**< Internal use */ + RwUInt32 palOffset; /**< Internal use */ + + /* K: a 12 bit 8.4 value in bottom bits */ + /* L: a 2 bit value in 12,13 */ + RwUInt16 mipmapKL; /**< Internal use */ + /* NOTE: This is left shifted two */ + RwUInt8 maxMipLevel; /**< Internal use */ + /* Is this texture to stay in the cache? */ + RwUInt8 bLocked; /**< Internal use */ + + /* Mipmap addresses */ + RwUInt32 miptbp1Lsb; /**< Internal use */ + RwUInt32 miptbp1Msb; /**< Internal use */ + RwUInt32 miptbp2Lsb; /**< Internal use */ + RwUInt32 miptbp2Msb; /**< Internal use */ + + /* Size in bytes in system memory for pixels */ + RwUInt32 sysMemSize; /**< Internal use */ + /* Size in bytes in system memory for palette */ + RwUInt32 sysMemPalSize; /**< Internal use */ + + /* Size in words in video memory for pixels + palette */ + RwUInt32 nTexCacheSize; /**< Internal use */ + + /* Should we cache packets for this raster */ + RwUInt8 cachePkts; /**< Internal use */ + RwUInt8 lockedMipLevel; /**< Currently locked mip level */ + RwUInt8 flags; /**< Bit 0 new format texture */ + /**< Bit 1 twiddled (->32) */ + /**< Bit 2 twiddled (->16) */ + RwUInt8 pad[1]; /**< Internal use */ +#if defined(GSB) && defined(GSPLUS) + RwUInt32 lsb3; /**< Internal use */ + RwUInt32 msb3; /**< Internal use */ + RwUInt32 miptbp3Lsb, miptbp3Msb; /**< Internal use */ + RwUInt32 miptbp4Lsb, miptbp4Msb; /**< Internal use */ +#endif /* defined(GSB) && defined(GSPLUS) */ +}; +uint32 skyRasterExt; +#define RASTEREXTFROMRASTER(raster) \ + ((_SkyRasterExt *)(((RwUInt8 *)(raster)) + skyRasterExt)) + + +// Some convenience structs +struct SkyDataPrefix +{ + uint32 pktSize1; + uint32 data; // pointer to data as read from TXD + uint32 pktSize2; + uint32 unused; +}; + +struct DMAGIFUpload +{ + uint32 tag1_qwc, tag1_addr; // dmaref + uint32 nop1, vif_direct1; + + uint32 giftag[4]; + uint32 gs_bitbltbuf[4]; + + uint32 tag2_qwc, tag2_addr; // dmaref + uint32 nop2, vif_direct2; +}; + +// This is very scary. it depends on the exact memory layout of the DMA chains and whatnot RwTexture * MoveTextureMemoryCB(RwTexture *texture, void *pData) { - // TODO +#ifdef GTA_PS2 + bool *pRet = (bool*)pData; + RwRaster *raster = RwTextureGetRaster(texture); + _SkyRasterExt *rasterExt = RASTEREXTFROMRASTER(raster); + if(raster->originalPixels == nil || // the raw data + raster->cpPixels == raster->originalPixels || // old format, can't handle it + rasterExt->dmaRefCount != 0 && rasterExt->dmaClrCount != 0) + return texture; + + // this is the allocated pointer we will move + SkyDataPrefix *prefix = (SkyDataPrefix*)raster->originalPixels; + DMAGIFUpload *uploads = (DMAGIFUpload*)(prefix+1); + + // We have 4qw for each upload, + // i.e. for each buffer width of mip levels, + // and the palette if there is one. + // NB: this code does NOT support mipmaps! + // so we assume two uploads (pixels and palette) + // + // each upload looks like this: + // (DMAcnt; NOP; VIF DIRECT(2)) + // giftag (1, A+D) + // GS_BITBLTBUF + // (DMAref->pixel data; NOP; VIF DIRECT(5)) + // the DMArefs are what we have to adjust + uintptr dataDiff, upload1Diff, upload2Diff, pixelDiff, paletteDiff; + dataDiff = prefix->data - (uintptr)raster->originalPixels; + upload1Diff = uploads[0].tag2_addr - (uintptr)raster->originalPixels; + if(raster->palette) + upload2Diff = uploads[1].tag2_addr - (uintptr)raster->originalPixels; + pixelDiff = (uintptr)raster->cpPixels - (uintptr)raster->originalPixels; + if(raster->palette) + paletteDiff = (uintptr)raster->palette - (uintptr)raster->originalPixels; + uint8 *newptr = (uint8*)gMainHeap.MoveMemory(raster->originalPixels); + if(newptr != raster->originalPixels){ + // adjust everything + prefix->data = (uintptr)newptr + dataDiff; + uploads[0].tag2_addr = (uintptr)newptr + upload1Diff; + if(raster->palette) + uploads[1].tag2_addr = (uintptr)newptr + upload2Diff; + raster->originalPixels = newptr; + raster->cpPixels = newptr + pixelDiff; + if(raster->palette) + raster->palette = newptr + paletteDiff; + + if(pRet){ + *pRet = true; + return nil; + } + } +#else + // nothing to do here really, everything should be in videomemory +#endif return texture; } bool -TidyUpModelInfo(CBaseModelInfo *,bool) +MoveAtomicMemory(RpAtomic *atomic, bool onlyOne) { - // TODO + RpGeometry *geo = RpAtomicGetGeometry(atomic); + +#if THIS_IS_COMPATIBLE_WITH_GTA3_RW31 + if(MoveMem((void**)&geo->triangles) && onlyOne) + return true; + if(MoveMem((void**)&geo->matList.materials) && onlyOne) + return true; + if(MoveMem((void**)&geo->preLitLum) && onlyOne) + return true; + if(MoveMem((void**)&geo->texCoords[0]) && onlyOne) + return true; + if(MoveMem((void**)&geo->texCoords[1]) && onlyOne) + return true; + + // verts and normals of morph target are allocated together + int vertDiff; + if(geo->morphTarget->normals) + vertDiff = geo->morphTarget->normals - geo->morphTarget->verts; + if(MoveMem((void**)&geo->morphTarget->verts)){ + if(geo->morphTarget->normals) + geo->morphTarget->normals = geo->morphTarget->verts + vertDiff; + if(onlyOne) + return true; + } + + RpMeshHeader *oldmesh = geo->mesh; + if(MoveMem((void**)&geo->mesh)){ + // index pointers are allocated together with meshes, + // have to relocate those too + RpMesh *mesh = (RpMesh*)(geo->mesh+1); + uintptr reloc = (uintptr)geo->mesh - (uintptr)oldmesh; + for(int i = 0; i < geo->mesh->numMeshes; i++) + mesh[i].indices = (RxVertexIndex*)((uintptr)mesh[i].indices + reloc); + if(onlyOne) + return true; + } +#else + // we could do something in librw here +#endif + return false; +} + +bool +MoveColModelMemory(CColModel &colModel, bool onlyOne) +{ +#if GTA_VERSION >= GTA3_PS2_160 + // hm...should probably only do this if ownsCollisionVolumes + // but it doesn't exist on PS2... + if(!colModel.ownsCollisionVolumes) + return false; +#endif + + if(MoveMem((void**)&colModel.spheres) && onlyOne) + return true; + if(MoveMem((void**)&colModel.lines) && onlyOne) + return true; + if(MoveMem((void**)&colModel.boxes) && onlyOne) + return true; + if(MoveMem((void**)&colModel.vertices) && onlyOne) + return true; + if(MoveMem((void**)&colModel.triangles) && onlyOne) + return true; + if(MoveMem((void**)&colModel.trianglePlanes) && onlyOne) + return true; + return false; +} + +RpAtomic* +MoveAtomicMemoryCB(RpAtomic *atomic, void *pData) +{ + bool *pRet = (bool*)pData; + if(pRet == nil) + MoveAtomicMemory(atomic, false); + else if(MoveAtomicMemory(atomic, true)){ + *pRet = true; + return nil; + } + return atomic; +} + +bool +TidyUpModelInfo(CBaseModelInfo *modelInfo, bool onlyone) +{ + if(modelInfo->GetColModel() && modelInfo->DoesOwnColModel()) + if(MoveColModelMemory(*modelInfo->GetColModel(), onlyone)) + return true; + + RwObject *rwobj = modelInfo->GetRwObject(); + if(RwObjectGetType(rwobj) == rpATOMIC) + if(MoveAtomicMemory((RpAtomic*)rwobj, onlyone)) + return true; + if(RwObjectGetType(rwobj) == rpCLUMP){ + bool ret = false; + if(onlyone) + RpClumpForAllAtomics((RpClump*)rwobj, MoveAtomicMemoryCB, &ret); + else + RpClumpForAllAtomics((RpClump*)rwobj, MoveAtomicMemoryCB, nil); + if(ret) + return true; + } + + if(modelInfo->GetModelType() == MITYPE_PED && ((CPedModelInfo*)modelInfo)->m_hitColModel) + if(MoveColModelMemory(*((CPedModelInfo*)modelInfo)->m_hitColModel, onlyone)) + return true; + return false; } diff --git a/src/core/World.cpp b/src/core/World.cpp index 844a4fb7..0bc564ff 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -922,24 +922,24 @@ CEntity * CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float radius, CEntity *entityToIgnore, bool ignoreSomeObjects) { - static CColModel sphereCol; + static CColModel OurColModel; - sphereCol.boundingSphere.center.x = 0.0f; - sphereCol.boundingSphere.center.y = 0.0f; - sphereCol.boundingSphere.center.z = 0.0f; - sphereCol.boundingSphere.radius = radius; - sphereCol.boundingBox.min.x = -radius; - sphereCol.boundingBox.min.y = -radius; - sphereCol.boundingBox.min.z = -radius; - sphereCol.boundingBox.max.x = radius; - sphereCol.boundingBox.max.y = radius; - sphereCol.boundingBox.max.z = radius; - sphereCol.numSpheres = 1; - sphereCol.spheres = &sphereCol.boundingSphere; - sphereCol.numLines = 0; - sphereCol.numBoxes = 0; - sphereCol.numTriangles = 0; - sphereCol.ownsCollisionVolumes = false; + OurColModel.boundingSphere.center.x = 0.0f; + OurColModel.boundingSphere.center.y = 0.0f; + OurColModel.boundingSphere.center.z = 0.0f; + OurColModel.boundingSphere.radius = radius; + OurColModel.boundingBox.min.x = -radius; + OurColModel.boundingBox.min.y = -radius; + OurColModel.boundingBox.min.z = -radius; + OurColModel.boundingBox.max.x = radius; + OurColModel.boundingBox.max.y = radius; + OurColModel.boundingBox.max.z = radius; + OurColModel.numSpheres = 1; + OurColModel.spheres = &OurColModel.boundingSphere; + OurColModel.numLines = 0; + OurColModel.numBoxes = 0; + OurColModel.numTriangles = 0; + OurColModel.ownsCollisionVolumes = false; CMatrix sphereMat; sphereMat.SetTranslate(spherePos); @@ -962,7 +962,7 @@ CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float rad if(e->GetBoundRadius() + radius > distance) { CColModel *eCol = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel(); int collidedSpheres = - CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(), *eCol, + CCollision::ProcessColModels(sphereMat, OurColModel, e->GetMatrix(), *eCol, gaTempSphereColPoints, nil, nil); if(collidedSpheres != 0 || diff --git a/src/core/config.h b/src/core/config.h index 4e71224f..ad0df2da 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -1,27 +1,27 @@ #pragma once enum Config { - NUMPLAYERS = 1, + NUMPLAYERS = 1, // 4 on PS2 NUMCDIMAGES = 12, // gta3.img duplicates (not used on PC) MAX_CDIMAGES = 8, // additional cdimages MAX_CDCHANNELS = 5, - MODELINFOSIZE = 5500, + MODELINFOSIZE = 5500, // 3150 on PS2 // TXDSTORESIZE = 850, TXDSTORESIZE = 1024, // for Xbox map EXTRADIRSIZE = 128, CUTSCENEDIRSIZE = 512, - SIMPLEMODELSIZE = 5000, + SIMPLEMODELSIZE = 5000, // 2910 on PS2 MLOMODELSIZE = 1, MLOINSTANCESIZE = 1, TIMEMODELSIZE = 30, CLUMPMODELSIZE = 5, PEDMODELSIZE = 90, - VEHICLEMODELSIZE = 120, + VEHICLEMODELSIZE = 120, // 70 on PS2 XTRACOMPSMODELSIZE = 2, - TWODFXSIZE = 2000, + TWODFXSIZE = 2000, // 1210 on PS2 MAXVEHICLESLOADED = 50, // 70 on mobile diff --git a/src/modelinfo/BaseModelInfo.h b/src/modelinfo/BaseModelInfo.h index 2505967b..4c274aaf 100644 --- a/src/modelinfo/BaseModelInfo.h +++ b/src/modelinfo/BaseModelInfo.h @@ -63,9 +63,9 @@ public: bool DoesOwnColModel(void) { return m_bOwnsColModel; } void DeleteCollisionModel(void); void ClearTexDictionary(void) { m_txdSlot = -1; } - short GetObjectID(void) { return m_objectId; } + int16 GetObjectID(void) { return m_objectId; } void SetObjectID(int16 id) { m_objectId = id; } - short GetTxdSlot(void) { return m_txdSlot; } + int16 GetTxdSlot(void) { return m_txdSlot; } void AddRef(void); void RemoveRef(void); void SetTexDictionary(const char *name); diff --git a/src/modelinfo/SimpleModelInfo.h b/src/modelinfo/SimpleModelInfo.h index ee63f24b..94e55a2f 100644 --- a/src/modelinfo/SimpleModelInfo.h +++ b/src/modelinfo/SimpleModelInfo.h @@ -11,6 +11,18 @@ public: float m_lodDistances[3]; uint8 m_numAtomics; uint8 m_alpha; + /* // For reference, PS2 has: + uint8 m_firstDamaged; + uint8 m_normalCull : 1; + uint8 m_isDamaged : 1; + uint8 m_isBigBuilding : 1; + uint8 m_noFade : 1; + uint8 m_drawLast : 1; + uint8 m_additive : 1; + uint8 m_isSubway : 1; + uint8 m_ignoreLight : 1; + // m_noZwrite is missing because not needed + */ uint16 m_firstDamaged : 2; // 0: no damage model // 1: 1 and 2 are damage models // 2: 2 is damage model diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index a8705524..7008818b 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -778,8 +778,10 @@ CHeli::InitHelis(void) for(i = 0; i < NUM_HELIS; i++) pHelis[i] = nil; +#if GTA_VERSION >= GTA3_PS2_160 ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_ESCAPE))->SetColModel(&CTempColModels::ms_colModelPed1); ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_CHOPPER))->SetColModel(&CTempColModels::ms_colModelPed1); +#endif } CHeli* @@ -789,6 +791,13 @@ GenerateHeli(bool catalina) CVector heliPos; int i; +#if GTA_VERSION < GTA3_PS2_160 + if(catalina) + ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_ESCAPE))->SetColModel(&CTempColModels::ms_colModelPed1); + else + ((CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_CHOPPER))->SetColModel(&CTempColModels::ms_colModelPed1); +#endif + if(catalina) heli = new CHeli(MI_ESCAPE, PERMANENT_VEHICLE); else From 955698d2d37688b86568ee9633cac64bcc01db17 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:05:28 +0100 Subject: [PATCH 114/129] kludge to prevent dodo unique jumps --- src/control/Script2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/control/Script2.cpp b/src/control/Script2.cpp index 62b9af93..9363cc7b 100644 --- a/src/control/Script2.cpp +++ b/src/control/Script2.cpp @@ -1539,7 +1539,8 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CollectParameters(&m_nIp, 1); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); script_assert(pVehicle); - UpdateCompareFlag(pVehicle->m_nCollisionRecords == 0); + bool usj_with_dodo = strcmp(m_abScriptName, "usj") == 0 && pVehicle->GetModelIndex() == MI_DODO; + UpdateCompareFlag(pVehicle->m_nCollisionRecords == 0 && !usj_with_dodo); return 0; } default: From a6c4d9b77cce5a7709e8ab23ab019e91ea0ab798 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:07:16 +0100 Subject: [PATCH 115/129] forgot to wrap in FIX_BUGS --- src/control/Script2.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/control/Script2.cpp b/src/control/Script2.cpp index 9363cc7b..562125c6 100644 --- a/src/control/Script2.cpp +++ b/src/control/Script2.cpp @@ -1539,8 +1539,13 @@ int8 CRunningScript::ProcessCommands400To499(int32 command) CollectParameters(&m_nIp, 1); CVehicle* pVehicle = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); script_assert(pVehicle); +#ifdef FIX_BUGS + // don't wanna get stuck in unique stunt jump cam forever bool usj_with_dodo = strcmp(m_abScriptName, "usj") == 0 && pVehicle->GetModelIndex() == MI_DODO; UpdateCompareFlag(pVehicle->m_nCollisionRecords == 0 && !usj_with_dodo); +#else + UpdateCompareFlag(pVehicle->m_nCollisionRecords == 0); +#endif return 0; } default: From a442ad198af051614e587ef0537842da9993f53d Mon Sep 17 00:00:00 2001 From: shfil Date: Thu, 3 Dec 2020 16:48:04 +0100 Subject: [PATCH 116/129] Fix discord invite --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ec9cedc7..56377cc0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # re3 [![Build status](https://ci.appveyor.com/api/projects/status/hyiwgegks122h8jg/branch/master?svg=true)](https://ci.appveyor.com/project/aap/re3/branch/master) - + | Platform | Debug | Release | |------------------|-------------|-------------| | Windows Direct3D9 | [![Download](https://api.bintray.com/packages/gtamodding/re3/Debug_win-x86-librw_d3d9-mss/images/download.svg)](https://bintray.com/gtamodding/re3/Debug_win-x86-librw_d3d9-mss/_latestVersion) | [![Download](https://api.bintray.com/packages/gtamodding/re3/Release_win-x86-librw_d3d9-mss/images/download.svg)](https://bintray.com/gtamodding/re3/Release_win-x86-librw_d3d9-mss/_latestVersion) | From 5bed7afd790c0d023b5ce31703f4edf6abded9f8 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:56:32 +0100 Subject: [PATCH 117/129] forgot some junk --- src/core/Game.cpp | 55 +++-------------------------------------------- 1 file changed, 3 insertions(+), 52 deletions(-) diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 43e2248f..dfc13bb2 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -1030,6 +1030,8 @@ void CGame::Process(void) #endif } +#ifdef USE_CUSTOM_ALLOCATOR + int32 gNumMemMoved; bool @@ -1046,58 +1048,6 @@ MoveMem(void **ptr) return false; } -typedef struct _SkyRasterExt _SkyRasterExt; -struct _SkyRasterExt -{ - RwInt32 dmaRefCount; /**< Internal use */ - RwInt32 dmaClrCount; /**< Internal use */ - - /* General texture setup register */ - RwUInt32 lsb; /**< Internal use */ - RwUInt32 msb; /**< Internal use */ - RwUInt32 palOffset; /**< Internal use */ - - /* K: a 12 bit 8.4 value in bottom bits */ - /* L: a 2 bit value in 12,13 */ - RwUInt16 mipmapKL; /**< Internal use */ - /* NOTE: This is left shifted two */ - RwUInt8 maxMipLevel; /**< Internal use */ - /* Is this texture to stay in the cache? */ - RwUInt8 bLocked; /**< Internal use */ - - /* Mipmap addresses */ - RwUInt32 miptbp1Lsb; /**< Internal use */ - RwUInt32 miptbp1Msb; /**< Internal use */ - RwUInt32 miptbp2Lsb; /**< Internal use */ - RwUInt32 miptbp2Msb; /**< Internal use */ - - /* Size in bytes in system memory for pixels */ - RwUInt32 sysMemSize; /**< Internal use */ - /* Size in bytes in system memory for palette */ - RwUInt32 sysMemPalSize; /**< Internal use */ - - /* Size in words in video memory for pixels + palette */ - RwUInt32 nTexCacheSize; /**< Internal use */ - - /* Should we cache packets for this raster */ - RwUInt8 cachePkts; /**< Internal use */ - RwUInt8 lockedMipLevel; /**< Currently locked mip level */ - RwUInt8 flags; /**< Bit 0 new format texture */ - /**< Bit 1 twiddled (->32) */ - /**< Bit 2 twiddled (->16) */ - RwUInt8 pad[1]; /**< Internal use */ -#if defined(GSB) && defined(GSPLUS) - RwUInt32 lsb3; /**< Internal use */ - RwUInt32 msb3; /**< Internal use */ - RwUInt32 miptbp3Lsb, miptbp3Msb; /**< Internal use */ - RwUInt32 miptbp4Lsb, miptbp4Msb; /**< Internal use */ -#endif /* defined(GSB) && defined(GSPLUS) */ -}; -uint32 skyRasterExt; -#define RASTEREXTFROMRASTER(raster) \ - ((_SkyRasterExt *)(((RwUInt8 *)(raster)) + skyRasterExt)) - - // Some convenience structs struct SkyDataPrefix { @@ -1289,6 +1239,7 @@ TidyUpModelInfo(CBaseModelInfo *modelInfo, bool onlyone) return false; } +#endif void CGame::DrasticTidyUpMemory(bool flushDraw) { From 9714a3776996d97e680cea575967a1d6041f5723 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 4 Dec 2020 01:12:58 +0100 Subject: [PATCH 118/129] bit more GTA_VERSION and GTA_PS2 --- src/core/Game.cpp | 47 +++++++++++++++++++++++------- src/core/main.cpp | 18 ++++++++---- src/modelinfo/VehicleModelInfo.cpp | 9 +++++- src/rw/VisibilityPlugins.cpp | 5 ++++ 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/core/Game.cpp b/src/core/Game.cpp index dfc13bb2..33302653 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -170,26 +170,39 @@ void ReplaceAtomicPipeCallback(); #endif // PS2_ALPHA_TEST #endif // !LIBRW -// missing altogether on PS2, mostly done in GameInit there it seems bool CGame::InitialiseRenderWare(void) { #ifdef USE_TEXTURE_POOL _TexturePoolsInitialise(); #endif - - CTxdStore::Initialise(); - CVisibilityPlugins::Initialise(); - + +#if GTA_VERSION > GTA3_PS2_160 + CTxdStore::Initialise(); // in GameInit on ps2 + CVisibilityPlugins::Initialise(); // in plugin attach on ps2 +#endif + + //InitialiseScene(Scene); // PS2 only, only clears Scene.camera + +#ifdef GTA_PS2 + RpSkySelectTrueTSClipper(TRUE); + RpSkySelectTrueTLClipper(TRUE); + + // PS2ManagerApplyDirectionalLightingCB() uploads the GTA lights + // directly without going through RpWorld and all that + SetupPS2ManagerDefaultLightingCallback(); + PreAllocateRwObjects(); +#endif + /* Create camera */ - Scene.camera = CameraCreate(RsGlobal.width, RsGlobal.height, TRUE); + Scene.camera = CameraCreate(SCREEN_WIDTH, SCREEN_HEIGHT, TRUE); ASSERT(Scene.camera != nil); if (!Scene.camera) { return (false); } - RwCameraSetFarClipPlane(Scene.camera, 2000.0f); + RwCameraSetFarClipPlane(Scene.camera, 2000.0f); // 250.0f on PS2 but who cares RwCameraSetNearClipPlane(Scene.camera, 0.9f); CameraSize(Scene.camera, nil, DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO); @@ -212,8 +225,12 @@ CGame::InitialiseRenderWare(void) /* Add the camera to the world */ RpWorldAddCamera(Scene.world, Scene.camera); LightsCreate(Scene.world); - - CreateDebugFont(); + +#if GTA_VERSION > GTA3_PS2_160 + CreateDebugFont(); // in GameInit on PS2 +#else + RwImageSetPath("textures"); +#endif #ifdef LIBRW #ifdef PS2_MATFX @@ -229,9 +246,16 @@ CGame::InitialiseRenderWare(void) ReplaceAtomicPipeCallback(); #endif // PS2_ALPHA_TEST #endif // LIBRW - + + +#if GTA_VERSION > GTA3_PS2_160 + // in GameInit on PS2 + PUSH_MEMID(MEMID_TEXTURES); CFont::Initialise(); CHud::Initialise(); + POP_MEMID(); +#endif + // TODO: define CPlayerSkin::Initialise(); return (true); @@ -247,7 +271,8 @@ void CGame::ShutdownRenderWare(void) for ( int32 i = 0; i < NUMPLAYERS; i++ ) CWorld::Players[i].DeletePlayerSkin(); - + + // TODO: define CPlayerSkin::Shutdown(); DestroyDebugFont(); diff --git a/src/core/main.cpp b/src/core/main.cpp index ebfa096a..54821979 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -114,7 +114,7 @@ void DebugMenuPopulate(void); bool gbPrintMemoryUsage; #endif -#ifdef GTA_PS2 +#ifdef PS2_MENU #define WANT_TO_LOAD TheMemoryCard.m_bWantToLoad #define FOUND_GAME_TO_LOAD TheMemoryCard.b_FoundRecentSavedGameWantToLoad #else @@ -415,7 +415,6 @@ PluginAttach(void) return TRUE; } -// rather different on PS2 static RwBool Initialise3D(void *param) { @@ -1766,7 +1765,7 @@ void SystemInit() #ifdef GTA_PS2 CFileMgr::InitCd(); - Char modulepath[256]; + char modulepath[256]; strcpy(modulepath, "cdrom0:\\"); strcat(modulepath, "SYSTEM\\"); @@ -1989,7 +1988,7 @@ void GameInit() CreateDebugFont(); #ifdef GTA_PS2 - AddIntcHandler(_TODOCONST(2), VBlankCounter, 0); + AddIntcHandler(INTC_VBLANK_S, VBlankCounter, 0); #endif CameraSize(Scene.camera, NULL, DEFAULT_VIEWWINDOW, DEFAULT_ASPECT_RATIO); @@ -2031,8 +2030,7 @@ main(int argc, char *argv[]) #ifdef GTA_PS2 int32 r = TheMemoryCard.CheckCardStateAtGameStartUp(CARD_ONE); - if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT - && r != CMemoryCard::ERR_OPENNOENTRY && r != CMemoryCard::ERR_NONE ) + if ( r == CMemoryCard::ERR_DIRNOENTRY || r == CMemoryCard::ERR_NOFORMAT ) { GameInit(); @@ -2042,6 +2040,8 @@ main(int argc, char *argv[]) CFont::Initialise(); FrontEndMenuManager.DrawMemoryCardStartUpMenus(); + }else if(r == CMemoryCard::ERR_OPENNOENTRY || r == CMemoryCard::ERR_NONE){ + // eh? } #endif @@ -2052,12 +2052,18 @@ main(int argc, char *argv[]) InitMPEGPlayer(); +#ifdef GTA_PAL PlayMPEG("cdrom0:\\MOVIES\\DMAPAL.PSS;1", false); if (CGame::frenchGame || CGame::germanGame) PlayMPEG("cdrom0:\\MOVIES\\INTROPAF.PSS;1", true); else PlayMPEG("cdrom0:\\MOVIES\\INTROPAL.PSS;1", true); +#else + PlayMPEG("cdrom0:\\MOVIES\\DMANTSC.PSS;1", false); + + PlayMPEG("cdrom0:\\MOVIES\\INTRNTSC.PSS;1", true); +#endif ShutdownMPEGPlayer(); diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index afda70d3..17754211 100644 --- a/src/modelinfo/VehicleModelInfo.cpp +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -998,6 +998,8 @@ CVehicleModelInfo::SetEnvironmentMapCB(RpMaterial *material, void *data) return material; } +bool initialised; + RpAtomic* CVehicleModelInfo::SetEnvironmentMapCB(RpAtomic *atomic, void *data) { @@ -1011,7 +1013,12 @@ CVehicleModelInfo::SetEnvironmentMapCB(RpAtomic *atomic, void *data) RpGeometryForAllMaterials(geo, SetEnvironmentMapCB, data); RpGeometrySetFlags(geo, RpGeometryGetFlags(geo) | rpGEOMETRYMODULATEMATERIALCOLOR); RpMatFXAtomicEnableEffects(atomic); - // PS2 sets of PS2Manager lighting CB here +#ifdef GTA_PS2 + if(!initialised){ + SetupPS2ManagerLightingCallback(RpAtomicGetInstancePipeline(atomic)); + initialised = true; + } +#endif } return atomic; } diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index f931019c..d81c97f2 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -819,6 +819,11 @@ CVisibilityPlugins::PluginAttach(void) ms_clumpPluginOffset = RpClumpRegisterPlugin(sizeof(ClumpExt), ID_VISIBILITYCLUMP, ClumpConstructor, ClumpDestructor, ClumpCopyConstructor); + +#if GTA_VERSION <= GTA3_PS2_16 + Initialise(); +#endif + return ms_atomicPluginOffset != -1 && ms_clumpPluginOffset != -1; } From 466eee84e76214a3300f3183f5025140c036e431 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 4 Dec 2020 10:23:04 +0100 Subject: [PATCH 119/129] typo --- src/rw/VisibilityPlugins.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rw/VisibilityPlugins.cpp b/src/rw/VisibilityPlugins.cpp index d81c97f2..b27d96c8 100644 --- a/src/rw/VisibilityPlugins.cpp +++ b/src/rw/VisibilityPlugins.cpp @@ -820,7 +820,7 @@ CVisibilityPlugins::PluginAttach(void) ID_VISIBILITYCLUMP, ClumpConstructor, ClumpDestructor, ClumpCopyConstructor); -#if GTA_VERSION <= GTA3_PS2_16 +#if GTA_VERSION <= GTA3_PS2_160 Initialise(); #endif From 28a942735cbcb329b572a20504b05d88e1364db6 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 5 Dec 2020 14:50:54 +0100 Subject: [PATCH 120/129] fix pMemoryTop --- src/rw/MemoryMgr.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/rw/MemoryMgr.cpp b/src/rw/MemoryMgr.cpp index ef0ecbdf..e2f6f144 100644 --- a/src/rw/MemoryMgr.cpp +++ b/src/rw/MemoryMgr.cpp @@ -3,7 +3,7 @@ #include "MemoryMgr.h" -void *pMemoryTop; +uint8 *pMemoryTop; void InitMemoryMgr(void) @@ -42,8 +42,8 @@ MemoryMgrMalloc(size_t size) #else void *mem = malloc(size); #endif - if(mem > pMemoryTop) - pMemoryTop = mem; + if((uint8*)mem + size > pMemoryTop) + pMemoryTop = (uint8*)mem + size ; return mem; } @@ -55,8 +55,8 @@ MemoryMgrRealloc(void *ptr, size_t size) #else void *mem = realloc(ptr, size); #endif - if(mem > pMemoryTop) - pMemoryTop = mem; + if((uint8*)mem + size > pMemoryTop) + pMemoryTop = (uint8*)mem + size ; return mem; } @@ -68,8 +68,8 @@ MemoryMgrCalloc(size_t num, size_t size) #else void *mem = calloc(num, size); #endif - if(mem > pMemoryTop) - pMemoryTop = mem; + if((uint8*)mem + size > pMemoryTop) + pMemoryTop = (uint8*)mem + size ; #ifdef FIX_BUGS memset(mem, 0, num*size); #endif From efb28b888d4ed89e1f8fc770a66ddfd7e03f4942 Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sat, 5 Dec 2020 22:26:45 +0300 Subject: [PATCH 121/129] fixed ANCHOR_BOAT --- src/control/Script4.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/Script4.cpp b/src/control/Script4.cpp index f5fb9781..78da2d96 100644 --- a/src/control/Script4.cpp +++ b/src/control/Script4.cpp @@ -89,7 +89,7 @@ int8 CRunningScript::ProcessCommands800To899(int32 command) CollectParameters(&m_nIp, 2); CBoat* pBoat = (CBoat*)CPools::GetVehiclePool()->GetAt(ScriptParams[0]); script_assert(pBoat && pBoat->m_vehType == VEHICLE_TYPE_BOAT); - pBoat->m_bIsAnchored = (ScriptParams[1] == 0); + pBoat->m_bIsAnchored = (ScriptParams[1] != 0); return 0; } case COMMAND_SET_ZONE_GROUP: From 14eb0cd286483dd14ac110658360ecd76199390c Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sun, 6 Dec 2020 15:27:42 +0300 Subject: [PATCH 122/129] fixed parenthesis --- src/control/Garages.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 96391914..33137c69 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -1046,8 +1046,8 @@ void CGarage::Update() // Close car doors either if player is far, or if he is in vehicle and garage is full, // or if player is very very far so that we can remove whatever is blocking garage door without him noticing if ((distance > SQR(DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_IN_CAR) || - !FindPlayerVehicle() && distance > SQR(DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_ON_FOOT) && - !IsAnyCarBlockingDoor())) + !FindPlayerVehicle() && distance > SQR(DISTANCE_TO_CLOSE_HIDEOUT_GARAGE_ON_FOOT)) && + !IsAnyCarBlockingDoor()) m_eGarageState = GS_CLOSING; else if (FindPlayerVehicle() && CountCarsWithCenterPointWithinGarage(FindPlayerVehicle()) >= From 3a66b178876498e02d7aa349b3b8c4754c42ba18 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 20:25:26 +0100 Subject: [PATCH 123/129] inttypes.h is part of the C++ standard, so prefix it --- src/extras/debugmenu.cpp | 2 +- src/extras/{inttypes.h => re3_inttypes.h} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/extras/{inttypes.h => re3_inttypes.h} (100%) diff --git a/src/extras/debugmenu.cpp b/src/extras/debugmenu.cpp index 3a4c4175..533b97f5 100644 --- a/src/extras/debugmenu.cpp +++ b/src/extras/debugmenu.cpp @@ -5,7 +5,7 @@ #include "ControllerConfig.h" #include "Timer.h" #include "rtcharse.h" -#include "inttypes.h" +#include "re3_inttypes.h" #include "debugmenu.h" #include diff --git a/src/extras/inttypes.h b/src/extras/re3_inttypes.h similarity index 100% rename from src/extras/inttypes.h rename to src/extras/re3_inttypes.h From 12d3893fe9454cac13d14c39abcb829fd43caabe Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 20:26:40 +0100 Subject: [PATCH 124/129] crossplatform is needed for casepath on non-Windows systems --- src/audio/oal/stream.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/audio/oal/stream.cpp b/src/audio/oal/stream.cpp index 3adb702a..90e90dd8 100644 --- a/src/audio/oal/stream.cpp +++ b/src/audio/oal/stream.cpp @@ -10,13 +10,15 @@ #ifdef _WIN32 #pragma comment( lib, "libsndfile-1.lib" ) #pragma comment( lib, "libmpg123-0.lib" ) -#else -#include "crossplatform.h" #endif #include #include #endif +#ifndef _WIN32 +#include "crossplatform.h" +#endif + #ifndef AUDIO_OPUS class CSndFile : public IDecoder { From 13de842236b6ddb3067ca4b275857f9df2b7f1ab Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 11:54:35 +0100 Subject: [PATCH 125/129] Spanish translation: adding new re3 strings. --- gamefiles/TEXT/spanish.gxt | Bin 247600 -> 251590 bytes utils/gxt/spanish.txt | 249 +++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 13aa6f29f45fdf82b650babb011b8e31621bd602..06ad194a02f0603a501a4a55f0246e7ae17afbfa 100644 GIT binary patch delta 3839 zcmb7GTWlOx8UANBNn2btO-$n01~SCTl{8IaJI;;L+1**s+A}+onXwZ`D%*AJBzEkz zSvzhWLAGfXiuw=;({`dLmFiHc$cU(9t5_5yNK_&~;-XTO7u1LHP^qm@L4^l|D!%`m zfL6!z&3`-J`7dYu^10==ez1I5)N2hadGd$LKA)~V=cFiGj7nzKp~J4ikxN&U zJQMWN6H1;nT{^AgSu>#P3R~78y4fpz^Ik+BD7l^KrF)gH9Te%W%BIKl={FMBN=`na z$CQyHV%lCeb85=w8CN5r!|WhzHcq!C`)@4j_iPJ zXO(1qxKN}ar8w+G^|tgcKfUjdJx~T#uDzp^KDv!}(K==&mSAzJ7?LpgXN}Y$= z@TEHMg!FABkVDv}AHTP~`9VFD?{3DSXc6ZR(KnR8Tkz=-B`;bYy}MTv{=R9`(IC$3 zSf@W7#7B3GrvIrtqQIetg7~c+tJ7};GWbEqrThH4zH_D4aH+^LyA(uL+}K{|*)QCj zQjh7=wH)h!{UW_6h&rWSFCa(R_#RqS;h-<1!QIk6^i6u*kI%KQZhA$yxuvYrMIYYA zyW{V+uW!nUJU|y_XjIT(Y{kECU%&GgN@o|kX|+hFTe8E5o>B5b=+G@CcTlfue!QjQ zT+dIG+O=}@tF_F=Ex9g{Em8*TWoW)r$$g>@wQVs=G-FD6(IeU$#((eFrXLUE4V`=2 zCRNlho2RWRQdn^5ebH8KDRj2Sk9L+DCT$rZboRu5=sc@WhV`%Pnn|TE2)pobDR5~+ zP=9kzT5q@}WKk&_b;W<$cUB+r>ZALYY3XSt58ROM4(in}t=qWoP1M14ONC-T(M^e6 z6W76q3VS(=*1!)op#vLR;;1hQ<9O&s(p{=$6D53Px9@O*i(V*A?Cg{AY#R zfj^SC*4=@ZG#G+JcPH>?72XBBRpBn+7ctdrV-~w>}(W~e>Mv+DJcV-`6s$UDA%-5dE z*EB4BAzw>PXM24*Ny9XRHAM!Msfu42cv?KGkd4uV&<)}_ja5;$v(ODgJ51wP6`D@w z&TEYij4*_tN=Fgs6m5f91h*r2Gq8~iHUoOBT2kAVv3xXFnuG$^vJw z9IPBHbHc;J(*va(Y>Ycb@SzEyDR9(B01a$rB24sejzy?>8wWu-6kB8kjebFj)6*wB z0$8#)+Yq8zcrQZ36eBW|^FL4BUtGhpJREMc9A1akq8 z;mL&_!e6e3f%0b zHP;9^EQ@X#6XeTq$pMvVP<1TtC3|T^G+zZfPr=H@a{|X=9KnLO<96ld9LC>C5pNos z^CU2lar{ow{YX6TI0Em=Rw#VHDZCiybT+MEn+eD>_&W|7d}yY5A(=a_tp(#eMB{K` z#(XSJvYe;?Z)^IGFt9$(HFXO6RI;A~}NPmcL;VvcG}tp>8h$*$4`5Hg78o*j_h zok@Llt{278j1dd}Ybnaor5GE;sN<^4l~nl{OLZB<QsoCX5s&H_oRT4-#&r37AeoDUBUGE26pC*u>e`jlUV3^BFkv zC#fuSJg%d6&&5^q5L{cXH;s*1D8C1MvA&(^96mEqP}_47V$Gn}-$?k4o{r%(ox=3<``6 zqnE&AF*SU4?oq;R&f~)#T+i}l>EeEJIlaaCm(S5VtQ=-}_%F#unv|62e~ zKii6car^a+xUDQ~%G1oWnZ%61mldHq(ddT-|FE%Sbs5P(P0b=h->^_V2g@uKiso5p} E0;5GbMgRZ+ delta 582 zcmX@MmVZMZKU;{mYotZ}Mm9OV%@+J8csJX~ws0;!qsGi+;5zx7<}#)Y?vu;3l#C?Y zm>Jw$o#VY+Tp3pAK-sn7{7U08BXAUti z+%uSg3u<7vk1vCp%jPm;A;!s5OgyBDz=r$8dpQO$G(p(`{yq#7oG0^{iivZ8{qGxZ z6cEJFWyc8grf%Q?G!66K%Tqd70 z6=QngGWnTlpVTL)DqmL@hEwt&2l~eQ`Z6%oxlish6XPp$gb4ZhGcXjmPu^#y$28A< z@;fst@nukr!Om_BNnqdj#s_=)PWCoWoV>%lg=v}lW;=^AW~Lao&4;Y{m?qz`ZDE?_ zygA8^jgiUDZF8BulKSK;X$Lm1Nf+SW%u~X`v{|OCfqnCq+89=*7w*kM&Fw Date: Sun, 29 Nov 2020 16:00:41 +0100 Subject: [PATCH 126/129] Removing iOS strings as requested. --- gamefiles/TEXT/spanish.gxt | Bin 251590 -> 247600 bytes utils/gxt/spanish.txt | 249 ------------------------------------- 2 files changed, 249 deletions(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 06ad194a02f0603a501a4a55f0246e7ae17afbfa..13aa6f29f45fdf82b650babb011b8e31621bd602 100644 GIT binary patch delta 582 zcmX@MmVZMZKU;{mYotZ}Mm9OV%@+J8csJX~ws0;!qsGi+;5zx7<}#)Y?vu;3l#C?Y zm>Jw$o#VY+Tp3pAK-sn7{7U08BXAUti z+%uSg3u<7vk1vCp%jPm;A;!s5OgyBDz=r$8dpQO$G(p(`{yq#7oG0^{iivZ8{qGxZ z6cEJFWyc8grf%Q?G!66K%Tqd70 z6=QngGWnTlpVTL)DqmL@hEwt&2l~eQ`Z6%oxlish6XPp$gb4ZhGcXjmPu^#y$28A< z@;fst@nukr!Om_BNnqdj#s_=)PWCoWoV>%lg=v}lW;=^AW~Lao&4;Y{m?qz`ZDE?_ zygA8^jgiUDZF8BulKSK;X$Lm1Nf+SW%u~X`v{|OCfqnCq+89=*7w*kM&FwfL6!z&3`-J`7dYu^10==ez1I5)N2hadGd$LKA)~V=cFiGj7nzKp~J4ikxN&U zJQMWN6H1;nT{^AgSu>#P3R~78y4fpz^Ik+BD7l^KrF)gH9Te%W%BIKl={FMBN=`na z$CQyHV%lCeb85=w8CN5r!|WhzHcq!C`)@4j_iPJ zXO(1qxKN}ar8w+G^|tgcKfUjdJx~T#uDzp^KDv!}(K==&mSAzJ7?LpgXN}Y$= z@TEHMg!FABkVDv}AHTP~`9VFD?{3DSXc6ZR(KnR8Tkz=-B`;bYy}MTv{=R9`(IC$3 zSf@W7#7B3GrvIrtqQIetg7~c+tJ7};GWbEqrThH4zH_D4aH+^LyA(uL+}K{|*)QCj zQjh7=wH)h!{UW_6h&rWSFCa(R_#RqS;h-<1!QIk6^i6u*kI%KQZhA$yxuvYrMIYYA zyW{V+uW!nUJU|y_XjIT(Y{kECU%&GgN@o|kX|+hFTe8E5o>B5b=+G@CcTlfue!QjQ zT+dIG+O=}@tF_F=Ex9g{Em8*TWoW)r$$g>@wQVs=G-FD6(IeU$#((eFrXLUE4V`=2 zCRNlho2RWRQdn^5ebH8KDRj2Sk9L+DCT$rZboRu5=sc@WhV`%Pnn|TE2)pobDR5~+ zP=9kzT5q@}WKk&_b;W<$cUB+r>ZALYY3XSt58ROM4(in}t=qWoP1M14ONC-T(M^e6 z6W76q3VS(=*1!)op#vLR;;1hQ<9O&s(p{=$6D53Px9@O*i(V*A?Cg{AY#R zfj^SC*4=@ZG#G+JcPH>?72XBBRpBn+7ctdrV-~w>}(W~e>Mv+DJcV-`6s$UDA%-5dE z*EB4BAzw>PXM24*Ny9XRHAM!Msfu42cv?KGkd4uV&<)}_ja5;$v(ODgJ51wP6`D@w z&TEYij4*_tN=Fgs6m5f91h*r2Gq8~iHUoOBT2kAVv3xXFnuG$^vJw z9IPBHbHc;J(*va(Y>Ycb@SzEyDR9(B01a$rB24sejzy?>8wWu-6kB8kjebFj)6*wB z0$8#)+Yq8zcrQZ36eBW|^FL4BUtGhpJREMc9A1akq8 z;mL&_!e6e3f%0b zHP;9^EQ@X#6XeTq$pMvVP<1TtC3|T^G+zZfPr=H@a{|X=9KnLO<96ld9LC>C5pNos z^CU2lar{ow{YX6TI0Em=Rw#VHDZCiybT+MEn+eD>_&W|7d}yY5A(=a_tp(#eMB{K` z#(XSJvYe;?Z)^IGFt9$(HFXO6RI;A~}NPmcL;VvcG}tp>8h$*$4`5Hg78o*j_h zok@Llt{278j1dd}Ybnaor5GE;sN<^4l~nl{OLZB<QsoCX5s&H_oRT4-#&r37AeoDUBUGE26pC*u>e`jlUV3^BFkv zC#fuSJg%d6&&5^q5L{cXH;s*1D8C1MvA&(^96mEqP}_47V$Gn}-$?k4o{r%(ox=3<``6 zqnE&AF*SU4?oq;R&f~)#T+i}l>EeEJIlaaCm(S5VtQ=-}_%F#unv|62e~ zKii6car^a+xUDQ~%G1oWnZ%61mldHq(ddT-|FE%Sbs5P(P0b=h->^_V2g@uKiso5p} E0;5GbMgRZ+ diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index e7dc1537..22063c35 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -8026,255 +8026,6 @@ HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL [CRED270] MIKE HONG -{ ======================================================================= } -{ ================= NEW STRINGS FROM THE iOS CONVERSION ================= } -{ ======================================================================= } - -[FEC_OFI] -Puedes arrastrar los botones y elementos de la interfaz. Toca dos veces cualquier botón para cambiar su tamaño. Toca dos veces la pantalla para volver al menú. - -[FEL_JPN] -JAPONÉS - -[MM_MARK] -MARKETING - -[MM_INV] -INVENCIBILIDAD - -[MM_MODE] -MODO DE MARKETING - -[MM_SLV] -PERMITIR SALTO DE NIVEL - -[MM_TUTS] -DESACTIVAR TUTORIALES - -[FET_RMS] -REINTENTAR MISIÓN - -[FESZ_RM] -¿REINTENTAR? - -[FET_CT7] -INVERTIR VISTA - -[FEA_OFF] -RADIO APAGADA - -[FEM_SL0] -Autoguardado sin usar - -[RM_KEY] -Leyenda - -[RM_TONI] -Toni Cipriani - -[RM_SALV] -Salvatore Leone - -[RM_RAY] -Ray Machowski - -[RM_KEN] -Kenji Kasen - -[RM_JOEY] -Joey Leone - -[RM_DON] -Donald Love - -[RM_EIG] -8 Ball - -[RM_ASU] -Asuka Kasen - -[RM_LUIG] -Club de Luigi - -[RM_CATA] -Catalina - -[RM_BPHO] -Diablos - -[RM_GPHO] -Jamaicanos - -[RM_RPHO] -Hoods - -[RM_SPRY] -Taller de pintura - -[RM_AMMU] -Ammu-Nation - -[RM_SAFE] -Piso franco - -[RM_BOMB] -Bombas - -[RM_G1] -Cártel colombiano - -[RM_G2] -Familia Leone - -[RM_G3] -Diablos - -[RM_G4] -Tríadas - -[RM_G5] -Yakuza - -[RM_G6] -Yardies - -[RM_G7] -Hoods del sur - -[SPLASH] -Toca para continuar - -[FEM_SL9] -Autoguardado sin usar - -[NEW_H1] -Toca el radar para acceder al mapa de la ciudad. Podrás ver tu objetivo así como los lugares importantes. - -[TUT_RAD] -Para cambiar la emisora de radio, desliza sobre el nombre de la emisora hacia la izquiera o a la derecha. - -[NEW_H2] -Para mirar alrededor, pulsa en el centro y desliza el dedo por la pantalla. - -{ EXTRA CREDIT STRINGS } - -[CRED345] -War Drum Studios - -[CRED346] -Thomas Williamson - -[CRED347] -Michael Owen - -[CRED348] -Morgan Hughes - -[CRED349] -Abner Williamson - -[RM_YOU] -Tu posición - -[RM_TARG] -Objetivo - -[RM_GANG] -Mostrar bandas - -[CNT_FOT] -a pie - -[CNT_LFT] -Izquierda - -[CNT_RHT] -Derecha - -[CNT_JMP] -Saltar - -[CNT_RUN] -Correr - -[CNT_SCP] -Mira - -[CNT_SHT] -Disparar - -[CNT_PCH] -Golpear - -[CNT_THR] -Lanzar - -[CNT_ZIN] -Acercar vista - -[CNT_ZOT] -Alejar vista - -[CNT_CAR] -en vehículo - -[CNT_ACL] -Acelerar - -[CNT_BRK] -Frenar - -[CNT_EEX] -Entrar/salir vehíc. - -[CNT_STC] -Disparar - -[CNT_HBK] -Freno de mano - -[CNT_HRN] -Claxon - -[CNT_RTL] -Girar a la izq. - -[CNT_RTR] -Girar a la der. - -[CNT_ATM] -Activar misión - -[CNT_MNU] -Menú - -[CNT_CAM] -Cámara - -[FED_HAP] -Vibración - -[FEL_KOR] -Coreano - -[FEM_CL7] -El archivo 7 no está en la nube - -[FEM_CL8] -El archivo 8 no está en la nube - -[FEM_NC] -La nube no está disponible - -[FEM_CSE] -Espacio vacío en la nube - -[FEH_RTE] -Valora GTA III - -[T_RATE] -Si te gusta jugar a GTA III, puntúalo. ~N~¡Gracias por tu apoyo! - { re3 updates } { new languages } [FEL_JAP] From c53a8b8c9de7d71910034e395f9c2353c19a35b2 Mon Sep 17 00:00:00 2001 From: IlDucci Date: Wed, 2 Dec 2020 17:02:19 +0100 Subject: [PATCH 127/129] Major editing and proofread of the official Spanish translation Alright, this is the big mother update. This commit includes a ton of changes and fixes to the original Spanish translation. Some have been taken from the iOS version (which was just a cleanup), others were done by myself. I've reorganized the entire file per missions and sections just so I could know where I was looking at. There's too much changes to list them, so here's the short version: - Retranslated and naturalized a lot of overly literal translations. - Fixed some uppercasing and lowercasing issues in the menus. - Shortened some subtitle translations that appear in a very short span of time so they are readable by the player. - This translation is European Spanish based, just like the original one and following Rockstar's policy up until GTAV. However, I tried to "neutralize" characters that are Latino American (El Burro, Catalina, Miguel, the Colombians...). If someone wants to do a fully Neutral Spanish translation, it should use a new file instead of overwriting this one in a translation war. --- gamefiles/TEXT/spanish.gxt | Bin 247600 -> 237250 bytes utils/gxt/spanish.txt | 13110 +++++++++++++++++++---------------- 2 files changed, 7211 insertions(+), 5899 deletions(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 13aa6f29f45fdf82b650babb011b8e31621bd602..9234eec9f86401185e88bd7f5008a474b50b5e8b 100644 GIT binary patch literal 237250 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

SL9jKy^%y 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

4(gG%M7cO=U6G; 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 Cv!w?B diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index 77bc957c..db38d036 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -8,10 +8,6 @@ abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789"$,.'-?!!SDBF [DEFNAM] Claude---------------------- -{ ============================================================================== } -{ ================= IN-MISSION WARNING MESSAGES FOR THE PLAYER ================= } -{ ============================================================================== } - [IN_VEH] ~g~¡Oye! ¡Vuelve al vehículo! @@ -48,19 +44,6 @@ Claude---------------------- [HEY9] ~g~¿Quieres que corra la voz por las calles? ¡Ve a ver al contacto! -[AWAY] -~r~¡Se ha pirado de aquí! - -[AWAY2] -~r~Se ha escapado. - -{ ========================================================================================== } -{ ================= HELP TEXTS (SEEN IN THE TOP LEFT CORNER OF THE SCREEN) ================= } -{ ========================================================================================== } - -[HELP1] -Detente en el centro de la señal azul. - [HELP2_A] Pulsa el ~h~botón /~w~ mientras corres para ~h~esprintar~w~. @@ -97,270 +80,116 @@ Pulsa y mantén el~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar~w~ con el f [HELP8_A] Pulsa el~h~ botón ~k~~PED_SNIPER_ZOOM_IN~ ~w~para ~h~acercar el zoom ~w~con el fusil y el ~h~botón ~k~~PED_SNIPER_ZOOM_OUT~~w~ para ~h~alejarlo~w~. -[HELP8_B] -Pulsa el ~h~botón ~k~~PED_SNIPER_ZOOM_IN~~w~ para ~h~acercar el zoom ~w~con el fusil y el ~h~botón ~k~~PED_SNIPER_ZOOM_OUT~~w~ para ~h~alejarlo~w~. - [HELP9_A] Pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar~w~ el fusil de francotirador. -[HELP9_B] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. - -[HELP9_C] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. - [HELP10] Esta insignia indica que la policía va a por ti. [HELP11] Cuantas más insignias tengas, más peligroso te considerarán. -[HELP12] -Entra en la señal azul para comenzar una misión. - [HELP13] Algunas veces tendrás que usar caminos no mostrados en el radar. -[HELP14] -Para conseguir un arma, pasa sobre ella. No puedes recogerlas estando dentro de un vehículo. - -[HELP15] -Cuando vayas a pie mantén pulsado el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para~h~ mirar atrás~w~. - -{ WANTED SYSTEM TUTORIAL } - -[WANT_A] -Sólo serás arrestado si estás en ~h~búsqueda y captura~w~. - -[WANT_B] -Tu ~h~grado de peligrosidad asignado a tu búsqueda y captura~w~ está representado por la hilera de estrellas en la parte superior derecha de la pantalla. - -[WANT_C] -Ahora tienes un ~h~grado de búsqueda y captura~w~ de uno... - -[WANT_D] -dos... - -[WANT_E] -tres... - -[WANT_F] -A medida que tu ~h~grado de búsqueda y captura~w~ vaya aumentando, te verás acosado por cuerpos policiales con una mayor potencia de fuego. - -[WANT_G] -Cuando seas ~h~''trincado''~w~ serás llevado a la comisaría de policía más cercana. - -[WANT_H] -Los polis requisarán todas tus armas y algo de tu dinero como soborno. - -[WANT_I] -Habrás fracasado en cualquier misión que estuvieses llevando a cabo. - -[WANT_J] -A medida que avances en el juego encontrarás formas de reducir tu grado de búsqueda y captura. - -[WANT_K] -Si estás en un coche, los ~h~TALLERES DE PINTURA~w~ te quitarán ~h~tu grado de búsqueda y captura~w~. - -[HEAL_A] -Tu ~h~salud ~w~está indicada en naranja en la parte superior derecha de la pantalla. - -[HEAL_B] -Cuando seas ~h~''liquidado''~w~ volverás al hospital más cercano. - -[HEAL_C] -Los doctores te quitarán tus armas y te cobrarán un dinero por remendarte. - -[HEAL_E] -A medida que avances en el juego encontrarás modos de curarte o de protegerte. - -{ WEAPON CONTROLS TUTORIAL } - -[GUN_1A] -Pulsa el ~h~botón ~k~~PED_CYCLE_WEAPON_RIGHT~~w~ y el ~h~botón ~k~~PED_CYCLE_WEAPON_LEFT~ ~w~para cambiar de arma. - -[GUN_2A] -¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... - -[GUN_2C] -¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... - -[GUN_2D] -¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... - -[GUN_3A] -Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. - -[GUN_3B] -Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. - -[GUN_4A] -Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~~w~, puedes caminar o correr y seguir teniendo en la mira a un objetivo. - -[GUN_4B] -Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~~w~, puedes caminar o correr y seguir teniendo en la mira a un objetivo. - -[GUN_5] -Puedes practicar disparando a estos blancos. Cuando hayas terminado puedes continuar la misión. - -{ OTHER HINTS } - -[BOMB] -Mete tu vehículo en la tienda de ~h~bombas~w~ para poner una. Coste: ~h~1.000$~w~. - -[SAVE1] -Pasa por la puerta para ~h~guardar la partida~w~. No podrás guardar durante una misión. - -[SAVE2] -Cualquier vehículo que dejes en este garaje se conservará al guardar la partida. - -[AMMU] -Entra a la tienda Ammu-Nation para comprar armas. - -[BRIDGE1] -Cuando el puente Callahan esté reparado podrás conducir hasta Staunton Island. - -[TUNNEL] -Cuando el túnel Porter esté abierto podrás conducir hasta Staunton Island. - [TIMER] Esta es una misión cronometrada, debes completarla antes de que el temporizador llegue a cero. +[MISTY1] +~r~¡Misty está para el arrastre! + +[OUT_VEH] +~g~¡Sal del vehículo! + [GARAGE] Mete el vehículo dentro del garaje y luego sal caminando. -[S_PROMP] -Cuando no estés en una misión, podrás ~h~guardar tu partida aquí~w~. Esto hará avanzar el tiempo seis horas. +[WANTED1] +~g~¡Despista a la poli! -[S_PROM2] -Puedes alojar un vehículo en el garaje de al lado al guardar tu partida. +[NODOORS] +~g~¡No son sardinas! Consigue un vehículo con suficientes asientos. -[SPRAY] -Mete tu vehículo en el taller de pintura para perder tu ~h~nivel de búsqueda~w~, ~h~reparar~w~ y~h~ repintar~w~ tu vehículo. Coste: ~h~1.000 dólares +[TRASH] +~g~¡Has dejado tu vehículo hecho unos zorros! ¡Haz que lo reparen! -[SPRAY1] -Mete tu vehículo en el taller de pintura para perder tu ~h~nivel de búsqueda~w~, ~h~reparar~w~ y~h~ repintar~w~ tu vehículo. Coste: ~h~1.000 dólares~w~. Esta vez es gratis. +[WRECKED] +~r~¡El vehículo está destrozado! -[LOOK_A] -Pulsa y mantén pulsado el ~h~botón ~k~~VEHICLE_LOOKLEFT~~w~ o el ~h~botón ~k~~VEHICLE_LOOKRIGHT~~w~ para mirar~h~ a la izquierda~w~ o ~h~a la derecha ~w~mientras te encuentres en un vehículo. Pulsa ambos para mirar~h~ atrás~w~. - -[CAM_A] -Pulsa el ~h~botón ~k~~CAMERA_CHANGE_VIEW_ALL_SITUATIONS~~w~ para cambiar la ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. - -[CAM_B] -Pulsa el ~h~botón de dirección hacia arriba ~w~y ~h~abajo ~w~para cambiar los modos de ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. - -[HORN1] -Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. - -[HORN2] -Pulsa el ~h~botón L1~w~ para tocar el ~h~claxon. - -[HORN3] -Pulsa el ~h~botón R1~w~ para tocar el ~h~claxon. +[HORN] +~g~Toca el claxon. [HORN4] Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. -[RADIO_A] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. +[NOMONEY] +~g~¡Necesitas más pasta! -[RADIO_B] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. +[OUTTIME] +~r~¡Demasiado lento, tío, demasiado lento! -[RADIO_C] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. +[SPOTTED] +~r~¡Te siguen la pista! -[RADIO_D] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. +[REWARD] +RECOMPENSA: $~1~ -[SIREN_1] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[GAMEOVR] +FIN DE LA PARTIDA -[SIREN_2] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[Z] +Valor del eje Z: ~1~ -[SIREN_3] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[M_FAIL] +¡MISIÓN FRACASADA! -[SIREN_4] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[M_PASS] +¡MISIÓN SUPERADA! $~1~ -[BOATIN1] -Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +[O_PASS] +¡TRABAJO ESPORÁDICO SUPERADO! -[BOATIN3] -Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +[O_FAIL] +¡TRABAJO ESPORÁDICO FRACASADO! -[BOATIN2] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. +[DEAD] +¡LIQUIDADO! -[BOATIN4] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. +[BUSTED] +¡TRINCADO! -[GREN_1] -Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[S_PROMP] +Cuando no estés en una misión, podrás ~h~guardar tu partida aquí~w~. Esto hará avanzar el tiempo seis horas. -[GREN_2] -Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[NUMBER] +~1~ -[GREN_3] -Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[SCORE] +~1~$ -[TUBE1] -Cuando el metro abra, podrás coger un tren hasta Staunton Island. +[LOADCAR] +CARGANDO VEHÍCULO... (PULSA EL BOTÓN L1 PARA CANCELAR) -[TUBE2] -Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al Aeropuerto Internacional Francis. +[CARSOFF] +Coches activados. -[TUBE_2] -Para subirte a un vagón, pulsa el ~h~botón Entrar al vehículo~w~. +[CARS_ON] +Coches desactivados. -[SPRAY_4] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[TEXTXYZ] +Escribiendo coordenadas al archivo... -[SPRAY_1] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[CHEATON] +Trucos ACTIVADOS -[L_TRN_1] -Puedes coger en tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. +[CHEATOF] +Trucos DESACTIVADOS -[L_TRN_2] -Puedes coger en tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. +[UZI_IN] +¡La Uzi ya está disponible en la tienda Ammu-Nation! -[S_TRN_1] -Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. - -[S_TRN_2] -Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. - -[RCHELP] -Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. - -[RCHELPA] -Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. - -[DRIVE_A] -Ten una Uzi seleccionada cuando entres en un vehículo, luego mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. - -[DRIVE_B] -Ten una Uzi seleccionada cuando entres en un vehículo, luego mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. - -[CRUSH] -Aparca en la zona señalada y sal de tu vehículo para que sea triturado. - -[GARAGE1] -~g~Sal del vehículo y aléjate caminando. - -[PBOAT_1] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. - -[PBOAT_2] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. - -{ ============================================================================================================================ } -{ ================= PAGER MESSAGES, INDICATING THAT THE PLAYER HAS UNLOCKED WEAPONS AND ITEMS IN ITS HIDEOUT ================= } -{ ============================================================================================================================ } +[IMPORT1] +Sal y espera a tu vehículo. [PAGEB1] Pistola ya disponible en tu guarida. @@ -395,122 +224,47 @@ Lanzacohetes ya disponible en tu guarida. [PAGEB11] Lanzallamas ya disponible en tu guarida. -[PAGEB12] -Soborno policial ya disponible en tu guarida. +[WANT_A] +Sólo serás arrestado si estás en ~h~búsqueda y captura~w~. -[PAGEB13] -Salud ya disponible en tu guarida. +[WANT_B] +Tu ~h~grado de peligrosidad asignado a tu búsqueda y captura~w~ está representado por la hilera de estrellas en la parte superior derecha de la pantalla. -[PAGEB14] -Adrenalina ya disponible en tu guarida. +[WANT_C] +Ahora tienes un ~h~grado de búsqueda y captura~w~ de uno... -{ ==================================================================================================================== } -{ ================= PAGER MESSAGES, INDICATING THAT GUNS HAVE BEEN UNLOCKED AT THE AMMU-NATION STORE ================= } -{ ==================================================================================================================== } +[WANT_D] +dos... -[COLT_IN] -¡La pistola ya está disponible en la tienda Ammu-Nation! +[WANT_E] +tres... -[UZI_IN] -¡La Uzi ya está disponible en la tienda Ammu-Nation! +[WANT_F] +A medida que tu ~h~grado de búsqueda y captura~w~ vaya aumentando, te verás acosado por cuerpos policiales con una mayor potencia de fuego. -{ ================================================================================================== } -{ ================= PAGER MESSAGES THAT APPEAR WHEN CERTAIN CAR SHOPS ARE UNLOCKED ================= } -{ ================================================================================================== } +[WANT_G] +Cuando seas ~h~''trincado''~w~ serás llevado a la comisaría de policía más cercana. -[IMPEXPP] -Garaje de Importación/Exportación, puerto de Portland. Requerimos varios vehículos; revisa nuestro tablón de notas para saber más. +[WANT_H] +Los polis requisarán todas tus armas y algo de tu dinero como soborno. -[VANHSTP] -¿Quieres abrir algún Securicar? Llévalo a nuestro garaje en el puerto de Portland. +[WANT_I] +Habrás fracasado en cualquier misión que estuvieses llevando a cabo. -[EMVHPUP] -Se compran vehículos de emergencia nuevos y usados a buen precio. Llévalos a la grúa que hay al noroeste del puerto de Portland. +[WANT_J] +A medida que avances en el juego encontrarás formas de reducir tu grado de búsqueda y captura. -{ =============================================================== } -{ ================= RAMPAGE SUBMISSIONS STRINGS ================= } -{ =============================================================== } +[WANT_K] +Si estás en un coche, los ~h~TALLERES DE PINTURA~w~ te quitarán ~h~tu grado de búsqueda y captura~w~. -[RAMPAGE] -¡MASACRE! +[HEAL_B] +Cuando seas ~h~''liquidado''~w~ volverás al hospital más cercano. -[RAMP_P] -¡MASACRE COMPLETADA! +[HEAL_C] +Los doctores te quitarán tus armas y te cobrarán un dinero por remendarte. -[RAMP_F] -MASACRE FALLIDA - -[RAMP_A] -¡TODAS LAS MASACRES COMPLETADAS! - -{ Pager messages } - -[PAGE_00] -. - -[PAGE_01] -¡Mata a ~1~ Diablos en 120 segundos! - -[PAGE_02] -¡Destruye ~1~ vehículos en 120 segundos! - -[PAGE_03] -¡Mata a ~1~ mafiosos en 120 segundos! - -[PAGE_04] -¡Mata a ~1~ Tríadas en 120 segundos! - -[PAGE_05] -¡Mata a ~1~ Tríadas en 120 segundos! - -[PAGE_06] -¡Destruye ~1~ vehículos en 120 segundos! - -[PAGE_07] -¡Revienta ~1~ cabezas jamaicanas en 120 segundos! - -[PAGE_08] -¡Quema a ~1~ yakuzas en 120 segundos! - -[PAGE_09] -¡Destruye ~1~ vehículos en 120 segundos! - -[PAGE_10] -¡Destruye ~1~ vehículos en 120 segundos! - -[PAGE_11] -¡Aniquila a ~1~ jamaicanos en 120 segundos! - -[PAGE_12] -¡Quema a ~1~ yakuzas en 120 segundos! - -[PAGE_13] -¡Vuela a ~1~ jamaicanos en 120 segundos! - -[PAGE_14] -¡Fríe a ~1~ colombianos en 120 segundos! - -[PAGE_15] -¡Machaca a ~1~ Hoods en 120 segundos! - -[PAGE_16] -¡Destruye ~1~ vehículos en 120 segundos! - -[PAGE_17] -¡Arrolla a ~1~ colombianos con un coche en 120 segundos! - -[PAGE_18] -¡Destruye ~1~ vehículos disparando desde otro en 120 segundos! - -[PAGE_19] -¡Revienta ~1~ cabezas colombianas en 120 segundos! - -[PAGE_20] -¡Decapita a ~1~ Hoods en 120 segundos! - -{ ======================================================== } -{ ================= PERCENTAGE BAR TEXTS ================= } -{ ======================================================== } +[HEAL_E] +A medida que avances en el juego encontrarás modos de curarte o de protegerte. [DAM] DAÑO: @@ -533,9 +287,23 @@ ESTADO DEL COCHE: [COLLECT] RECOGIDOS: -{ ================================================================================== } -{ ================= POSSIBLY MAP SCREEN INDICATIONS, MISSING IN PC ================= } -{ ================================================================================== } +[BOMB] +Mete tu vehículo en la tienda de ~h~bombas~w~ para poner una. Coste: ~h~1.000$~w~. + +[SAVE1] +Pasa por la puerta para ~h~guardar la partida~w~. No podrás guardar durante una misión. + +[SAVE2] +Cualquier vehículo que dejes en este garaje se conservará al guardar la partida. + +[AMMU] +Entra a la tienda Ammu-Nation para comprar armas. + +[BRIDGE1] +Cuando el puente Callahan esté reparado podrás conducir hasta Staunton Island. + +[TUNNEL] +Cuando el túnel Porter esté abierto podrás conducir hasta Staunton Island. [LUIGI] MISIONES DE LUIGI @@ -573,10 +341,6 @@ MISIONES DE JAMAICANOS [HOOD] MISIONES DE HOOD -{ =========================================================== } -{ ================= LIBERTY CITY AREA NAMES ================= } -{ =========================================================== } - [CITYZON] Liberty City @@ -679,453 +443,125 @@ Shoreside Vale [SUB_ZO3] Shoreside Vale -[TRAIN_1] -Estación Kurowski - -[TRAIN_2] -Estación Rothwell - -[TRAIN_3] -Estación Baillie - -[SUBWAY1] -Estación Portland - -[SUBWAY2] -Estación Rockford - -[SUBWAY3] -Estación Staunton sur - -[SUBWAY4] -Terminal Shoreside - -{ ================================================= } -{ ================= VEHICLE NAMES ================= } -{ ================================================= } - [CAR_1] Ambulancia -[AMBULAN] -Ambulancia - [CAR_2] Camión de bomberos -[FIRETRK] -Camión de bomberos - [CAR_3] Coche patrulla -[POLICAR] -Coche patrulla - [CAR_4] Enforcer -[ENFORCR] -Enforcer - [CAR_5] Barracks -[BARRCKS] -Barracks OL - [CAR_6] Rhino -[RHINO] -Rhino - [CAR_7] Coche del FBI -[FBICAR] -Coche del FBI - [CAR_8] Securicar -[SECURI] -Securicar - [CAR_9] Moonbeam -[MOONBM] -Moonbeam - [CAR_10] Coach -[COACH] -Coach - [CAR_11] Flatbed -[FLATBED] -Flatbed - [CAR_12] Linerunner -[LINERUN] -Linerunner - [CAR_13] Trashmaster -[TRASHM] -Trashmaster - [CAR_14] Patriot -[PATRIOT] -Patriot - [CAR_15] Mr. Whoopee -[WHOOPEE] -Mr. Whoopee - [CAR_16] Mule -[MULE] -Mule - [CAR_17] Yankee -[YANKEE] -Yankee - [CAR_18] Pony -[PONY] -Pony - [CAR_19] Bobcat -[BOBCAT] -Bobcat - [CAR_20] Rumpo -[RUMPO] -Rumpo - [CAR_21] Blista -[BLISTA] -Blista - [CAR_22] Dodo -[DODO] -Dodo - [CAR_23] Autobús -[BUS] -Autobús - [CAR_24] Sentinel -[SENTINL] -Sentinel - [CAR_25] Cheetah -[CHEETAH] -Cheetah - [CAR_26] Banshee -[BANSHEE] -Banshee - [CAR_27] Stinger -[STINGER] -Stinger - [CAR_28] Infernus -[INFERNS] -Infernus - [CAR_29] Esperanto -[ESPERAN] -Esperanto - [CAR_30] Kuruma -[KURUMA] -Kuruma - [CAR_31] Stretch -[STRETCH] -Stretch - [CAR_32] Perennial -[PEREN] -Perennial - [CAR_33] Landstalker -[LANDSTK] -Landstalker - [CAR_34] Mañana -[MANANA] -Mañana - [CAR_35] Idaho -[IDAHO] -Idaho - [CAR_36] Stallion -[STALION] -Stallion - [CAR_37] Taxi -[TAXI] -Taxi - [CAR_38] Cabbie -[CABBIE] -Cabbie - [CAR_39] Buggy -[BFINJC] -BF Injection - -[PREDATR] -Predator - -[TRAIN] -Tren - -[HELI] -Helicóptero - -[RCBANDT] -Bandit RC - -[BELLYUP] -Furgoneta de las Tríadas - -[MRWONGS] -Mr Wongs - -[MAFIACR] -Sentinel de la mafia - -[YARDICR] -Lobo jamaicano - -[YAKUZCR] -Stinger de la yakuza - -[DIABLCR] -Stallion de los Diablos - -[COLOMCR] -Cruiser del cártel - -[HOODSCR] -Rumpo XL de los hood - -[AEROPL] -Avioneta - -[SPEEDER] -Speeder - -[REEFER] -Reefer - -[PANLANT] -Panlantic - -[BORGNIN] -Borgnine - -[TOYZ] -TOYZ - -{ ======================================================= } -{ ================= RADIO STATION NAMES ================= } -{ ======================================================= } - -[FEA_FM0] -HEAD RADIO - -[HEAD] -Head Radio - -[FEA_FM1] -DOUBLE CLEF FM - -[DBL_CLF] -Double Clef FM - -[FEA_FM2] -K-JAH RADIO - -[K_JAH] -K-Jah Radio - -[FEA_FM3] -RISE FM - -[RISE] -Rise FM - -[FEA_FM4] -LIPS 106 - -[LIPS] -Lips 106 - -[FEA_FM5] -GAME FM - -[GAM_FM] -Game Radio FM - -[FEA_FM6] -MSX FM - -[MSX_FM] -MSX FM - -[FEA_FM7] -FLASHBACK 95.6 - -[FLASHB] -Flashback 95.6 - -[FEA_FM8] -CHATTERBOX FM - -[CHAT] -Chatterbox FM - -{ ============================================================================================================== } -{ ================= STRINGS RELATED TO GARAGES (BOMB SHOP, SPRAY SHOP, IMPORT/EXPORT, CRUSHER) ================= } -{ ============================================================================================================== } - -[GA_1] -¡Hala! ¡Demasiado peligroso para mi gusto! - -[GA_1A] -Vuelve cuando no estés tan ocupado... - -[GA_2] -He cambiado el motor y la mano de pintura. ¡La poli no te reconocerá! - -[GA_3] -¡Ya no es gratis! ¡La mano de pintura son 1.000 dólares! - -[GA_4] -Una bomba de coche vale 1.000 dólares. - -[GA_5] -Tu coche ya tiene una bomba instalada. - -[GA_6] -Apárcalo, prepáralo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! - -[GA_6B] -¡Apárcalo, prepáralo tocando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! - -[GA_7] -Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. - -[GA_7B] -Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. - -[GA_8] -Utiliza el detonador para activar la bomba. - -[GA_9] -Ha conseguido ~1~ de los 10 coches especiales. - -[GA_10] -Buen trabajo. Aquí tienes tus ~1~ dólares. - -[GA_11] -Ya tenemos este modelo. ¡No nos sirve para nada! - -[GA_12] -Bomba armada - -[GA_13] -Eres todo un profesional. Completa la lista y conseguirás una recompensa. - -[GA_14] -Ya están todos los coches. ¡Estupendo! Toma un detallito. - -[GA_15] -Espero que te guste el nuevo color. - -[GA_16] -Esta mano de pintura es gratuita. - -[GA_19] -No nos interesa ese modelo. - -[GA_20] -Tenemos de esos más de los que necesitamos. Lo siento, tío, no hay trato. - -[GA_21] -No puedes guardar más coches en este garaje. - -[CR_1] -La grúa no puede levantar este vehículo. - -{ ============================================================================================ } -{ ================= MESSAGES TO INDICATE THAT MISSIONS ARE NOT YET AVAILABLE ================= } -{ ============================================================================================ } +[LUIGIS] +Club de Luigi [GOAWAY] ~g~¡Ya estás en una misión! @@ -1169,71 +605,36 @@ La grúa no puede levantar este vehículo. [WRONGT3] ~g~Vuelve entre las 15:00 y las 00:00 para buscar trabajo. -{ ============================================================================ } -{ ================= SUBTITLES FOR THE AMMU-NATION SHOP CLERK ================= } -{ ============================================================================ } +[GUN_1A] +Pulsa el ~h~botón ~k~~PED_CYCLE_WEAPON_RIGHT~~w~ y el ~h~botón ~k~~PED_CYCLE_WEAPON_LEFT~ ~w~para cambiar de arma. -[AMMU_A] -Luigi dijo que necesitabas una pipa... +[GUN_2A] +¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... -[AMMU_B] -Joey me pidió que te armáramos... +[GUN_2C] +¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... -[AMMU_C] -Ve a la parte de atrás. Te dejé un nueve en el patio. +[GUN_2D] +¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... -[AMMU_D] -Tengo todo lo necesario para defender tu casa. +[GUN_3A] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. -[AMMU_E] -¿También quieres una licencia? +[GUN_3B] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. -[AMMU_F] -No necesito tu documentación, pareces de fiar. +[GUN_4A] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~~w~, puedes caminar o correr y seguir teniendo en la mira a un objetivo. -{ ==================================================================================================================== } -{ ==================================================================================================================== } -{ =============================================== SIDE MISSION STRINGS =============================================== } -{ ==================================================================================================================== } -{ ==================================================================================================================== } +[GUN_4B] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~~w~, puedes caminar o correr y seguir teniendo en la mira a un objetivo. -{ ==================================================================== } -{ ================= TAXI/CABBIE SIDE MISSION STRINGS ================= } -{ ==================================================================== } - -[TAXI_M] -'TAXISTA' - -[TSCORE2] -$~1~ - -[IN_ROW] -¡~1~ CONSECUTIVOS! $~1~ - -[TAXIH1] -Para cerca de un peatón señalado para recogerlo, luego condúcelo a su destino antes de que se acabe el tiempo. +[GUN_5] +Puedes practicar disparando a estos blancos. Cuando hayas terminado puedes continuar la misión. [TAXI1] ~g~Busca un cliente. -[TAXI2] -~r~¡Se te acabó el tiempo! - -[TAXI3] -~r~¡Tu pasajero ha salido corriendo! - -[TAXI4] -¡Carrera terminada! - -[TAXI5] -¡VIAJE RÁPIDO! - -[TAXI6] -Misión de taxi terminada - -[TAXI7] -~r~Tu coche está destrozado, haz que lo reparen. - [FARE1] ~g~Ve al ~w~club Sex Kitten Meeouch ~g~en el barrio rojo. @@ -1264,9 +665,6 @@ Misión de taxi terminada [FARE10] ~g~Ve a ~w~Punk Noodles ~g~en Chinatown. -[FARE11] -~g~Ve a la ~w~zona en obras~g~ de Fort Staunton. - [FARE12] ~g~Ve al ~w~estadio de fútbol ~g~en Aspatria. @@ -1300,9 +698,6 @@ Misión de taxi terminada [FARE22] ~g~Ve a la ~w~presa Cochrane~g~. -[FARE23] -~g~Ve al ~w~taller de importación/exportación~g~ en el distrito de la presa Cochrane. - [FARE24] ~g~Ve al ~w~hospital ~g~de Pike Creek. @@ -1315,22 +710,18 @@ Misión de taxi terminada [NEW_TAX] ¡MÁS GRANDES! ¡MÁS RÁPIDO! ¡MÁS DUROS! Los nuevos taxis Borgnine abren su negocio en Harwood. ¡Llame hoy al 555-BORGNINE! +[TSCORE2] +$~1~ + +[IN_ROW] +¡~1~ CONSECUTIVOS! $~1~ + [TTUTOR] Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. [TTUTOR2] Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. -{ ============================================================================= } -{ ================= AMBULANCE/PARAMEDIC SIDE MISSIONS STRINGS ================= } -{ ============================================================================= } - -[AMBUL_M] -'SANITARIO' - -[A_SAVES] -GENTE SALVADA: ~1~ - [ATUTOR2] ~g~Conduce a los pacientes hasta el hospital con mucho cuidado. Cada golpe reducirá sus posibilidades de supervivencia. @@ -1343,49 +734,6 @@ GENTE SALVADA: ~1~ [A_RANGE] ~g~La radio de la ambulancia está fuera de cobertura, ¡acércate a un hospital! -[A_COMP1] -¡Misiones de sanitario completadas! - -[A_CANC] -~r~¡Misión de sanitario cancelada! - -[A_COMP3] -¡Misiones de sanitario completadas! ¡Ahora no te cansarás al correr! - -[ATUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. - -[ATUTOR3] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. - -[ALEVEL] -Nivel de misión de sanitario: ~1~ - -[A_FAIL1] -Misión de sanitario terminada. - -[A_FAIL2] -~r~¡Tu falta de rapidez ha sido fatal para el paciente! - -[A_FAIL3] -~r~¡El paciente está muerto! - -[A_PASS] -¡Rescatado! - -[A_COMP2] -¡Nunca te cansarás! - -{ ============================================================================ } -{ ================= FIRE TRUCK/FIREMEN SIDE MISSIONS STRINGS ================= } -{ ============================================================================ } - -[FIRE_M] -'BOMBERO' - -[F_EXTIN] -INCENDIOS: - [FTUTOR] Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. @@ -1395,280 +743,17 @@ Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misi [F_PASS1] ¡Fuego apagado! -[F_FAIL1] -¡Misión del camión de bomberos terminada! - -[F_CANC] -~r~¡Misión del camión de bomberos cancelada! - [F_RANGE] ~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate a una estación de bomberos! -[F_FAIL2] -~r~¡Llegas demasiado tarde! - -[F_START] -~g~Informe de vehículo en llamas en: ~a~. Ve y extingue el fuego. - -{ ============================================================================== } -{ ================= POLICE CAR/VIGILANTE SIDE MISSIONS STRINGS ================= } -{ ============================================================================== } - -[COP_M] -'JUSTICIERO' - -[C_KILLS] -CRIMINALES ABATIDOS: ~1~ - -[LEGAL] -~g~¡Elimina la amenaza criminal! - [C_BREIF] ~g~Sospechoso visto por última vez en: ~a~. [C_RANGE] ~g~La radio de la policía está fuera de cobertura, ¡acércate a una comisaría! -[C_PASS] -¡AMENAZA ELIMINADA! - -[CTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. - -[CTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. - -[COPCART] -~g~Tienes ~1~ segundos para volver a un vehículo de la policía antes de que termine la misión. - -[C_FAIL] -¡Misión de justiciero terminada! - -[C_CANC] -~r~¡Misión de justiciero cancelada! - -[C_ESCP] -~r~¡El sospechoso ha escapado! - -[C_TIME] -~r~¡Tu trabajo como defensor de la ley ha terminado! - -[C_VIGIL] -¡PREMIO POR JUSTICIERO! - -{ ======================================================================== } -{ ================= CHECKPOINT RUN SIDE MISSIONS STRINGS ================= } -{ ======================================================================== } - -[T4X4_1] -'PATIO DE RECREO' - -[T4X4_1A] -~g~Tienes ~y~5 minutos~g~ para pasar por ~y~15~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. - -[T4X4_1B] -¡~1~ de 15! - -[T4X4_1C] -~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~20 SEGUNDOS~g~ adicionales. - -[T4X4_2] -'UN PASEO POR EL PARQUE' - -[T4X4_2A] -~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~12~g~ puntos de control! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. - -[T4X4_2B] -¡~1~ de 12! - -[T4X4_2C] -~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~10 SEGUNDOS~g~ adicionales. - -[T4X4_3] -'¡AGARRADO!' - -[T4X4_3A] -~g~Tienes ~y~5 minutos~g~ para pasar por ~y~20~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. - -[T4X4_3B] -~Y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~15 SEGUNDOS~g~ adicionales. - -[T4X4_3C] -¡~1~ de 20! - -[MM_1] -'CAOS EN EL APARCAMIENTO' - -[MM_1_A] -~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~20 puntos de control~g~ en el aparcamiento! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. - -[MM_1_B] -¡~1~ de 20! - -[MM_1_C] -~g~Tendrás 20 segundos, más ~y~5 SEGUNDOS~g~ por cada punto de control. ~g~El cronómetro comenzará ~y~INMEDIATAMENTE. - -[T4X4_F] -~r~¡Te has escapado! ¿Demasiado difícil para ti? - -{ ============================================================================ } -{ ================= RC CAR DESTRUCTION SIDE MISSIONS STRINGS ================= } -{ ============================================================================ } - -[RC1] -'DESTRUCCIÓN DE LOS DIABLOS' - -[RC2] -'LA MASACRE DE LA MAFIA' - -[RC3] -'CALAMIDAD EN EL CASINO' - -[RC4] -'EXTERMINIO DE RUMPOS' - -[RC_1] -¡Tienes 2 minutos para destruir todos los coches de los Diablos que puedas! - -[RC_2] -¡Tienes 2 minutos para destruir todos los coches de la mafia que puedas! - -[RC_3] -¡Tienes 2 minutos para destruir todos los coches de la yakuza que puedas! - -[RC_4] -¡Tienes 2 minutos para destruir todos los coches de los jamaicanos que puedas! - -[RC_5] -¡Tienes 2 minutos para destruir todos los coches de los Hood que puedas! - -[RC_6] -¡Tienes 2 minutos para destruir todos los coches del cártel que puedas! - -{ ==================================================================================================================== } -{ ==================================================================================================================== } -{ ================================================ MAIN STORY STRINGS ================================================ } -{ ==================================================================================================================== } -{ ==================================================================================================================== } - -{ ================================================== } -{ ================= OPENING SCENES ================= } -{ ================================================== } - -{ Catalina, colombiana } - -[BETRA_A] -Lo siento, cariño. - -[BETRA_B] -Soy una chica ambiciosa, ¿y tú? - -[BETRA_C] -Un Don Nadie. - -{ Newspaper clip. Only PAPER1 is used } - -[PAPER1] -CRIMINAL HERIDO DE BALA POR SU NOVIA Y CÓMPLICE; EL TRIBUNAL ENCUENTRA CULPABLE AL ATRACADOR CON UN VEREDICTO UNÁNIME. - -[PAPER2] -¡DIEZ AÑOS POR AMOR! - -[PAPER3] -* - -{ Cutscene where the Colombians kidnap the Old Oriental Gentlemen. Claude and 8-Ball escape from the van. } - -{ Libery City News broadcaster } - -[JAILB_V] -Hoy, Liberty City se ha visto conmocionada. - -[JAILB_A] -La policía y los servicios de emergencia lidian con las consecuencias - -[JAILB_B] -de un ataque devastador a un convoy policial ocurrido esta mañana. - -[JAILB_C] -No se ha informado de quiénes eran los prisioneros trasladados en el convoy - -[JAILB_D] -y ningún grupo ha reconocido la autoría. - -[JAILB_E] -El convoy abandonó las oficinas de la policía esta mañana - -[JAILB_F] -para hacer una transferencia de reos a la penitenciaría de Liberty. - -[JAILB_G] -El ataque se produjo en el puente Callahan, - -[JAILB_H] -dejando pocos testigos y al puente seriamente dañado. - -[JAILB_I] -Se cree que algunos de los convictos han perecido en la explosión - -[JAILB_J] -posterior al ataque inicial. - -[JAILB_W] -Pasadas las horas se hizo evidente que el ataque era obra de profesionales, - -[JAILB_K] -ya que la identificación de los prófugos se complicó - -[JAILB_L] -cuando piratas informáticos atacaron las bases de datos de la policía. - -[JAILB_O] -Con el retraso del proyecto del túnel Porter, - -[JAILB_P] -este desastre deja a Portland aislada del resto de la ciudad. - -[JAILB_M] -* - -[JAILB_N] -* - -[JAILB_X] -En una declaración realizada hoy previamente, - -{ Colombian thug } - -[JAILB_Q] -¡Vamos! - -[JAILB_R] -¡Señor pendejo! - -[JAILB_S] -No nos importará matarte. - -{ Police officer } - -[JAILB_T] -Os vais a arrepentir. - -{ Colombian thug } - -[JAILB_U] -Bien, bien, piérdete. - -{ ======================================================================= } -{ ================= MISSION: GIVE ME LIBERTY (NO OWNER) ================= } -{ ======================================================================= } - -{ TITLE } - -[EBAL] -'DAME LIBERTAD' - -{ 8-Ball } +[DODO_FT] +¡Volaste durante ~1~ segundos! [EBAL_A] Conozco un lugar en las afueras del barrio rojo donde podemos escondernos, @@ -1676,8 +761,6 @@ Conozco un lugar en las afueras del barrio rojo donde podemos escondernos, [EBAL_A1] pero mis manos están destrozadas, así que conduce tú, hermano. -{ Mission instructions } - [EBAL_1] Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. @@ -1690,52 +773,20 @@ Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de [EBAL_3] Este es el ~h~radar~w~. Utilízalo para recorrer la ciudad: ¡sigue el ~h~punto~w~ en el ~h~radar~w~ para encontrar el escondite! -{ 8-Ball } - -[EBAL_B] -Es aquí, ¡entremos y cambiémonos de ropa! - -{ 8-Ball } - [EBAL_D] Conozco a un tipo con contactos, se llama Luigi. [EBAL_D1] Somos viejos amigos, así que podremos buscarte curro. Vamos a verlo. -{ 8-Ball } - [EBAL_E] Venga, vamos a pasarnos por allí y te presentaré. -{ 8-Ball } - -[EBAL_G] -Este es el club de Luigi. Vamos a la parte de atrás, a la puerta de servicio. - -{ ============================================================================ } -{ ================= MISSION: LUIGI'S GIRLS (LUIGI GOTERELLI) ================= } -{ ============================================================================ } - -{ TITLE } - -[LM1] -'LAS CHICAS DE LUIGI' - -{ Premission cutscene } - -{ 8-Ball } - -[EBAL_H] -Espera, tío, que voy a hablar con Luigi. - -{ Mick (unused) } +{ UNUSED } [EBAL_I] El jefe os recibirá enseguida... -{ Luigi } - [EBAL_J] 8-Ball que ocuparse de una cosa arriba. @@ -1745,22 +796,9 @@ Quizá puedas hacerme un favor. [EBAL_L] Una de mis chicas necesita que la lleven, así que consigue un coche, recoge a Misty en la clínica y luego tráela aquí. -[EBAL_M] -¡Recuerda: nadie se mete con mis chicas! - [EBAL_N] ¡Así que no quites las manos del volante! -[EBAL_O] -Si no la cagas, puede que haya más trabajo para ti. ¡Ahora largo! - -{ Misty } - -[LM1_9] -Hola, soy Misty. - -{ Mission instructions } - [EBAL_4] ~r~¡8-Ball ha muerto! @@ -1770,6 +808,18 @@ Hola, soy Misty. [EBAL_6] ~g~¡Recoge a Misty! +[LM1] +'LAS CHICAS DE LUIGI' + +[LM2] +'NO DROGUES A MI ZORRA' + +[LM3] +'LLEVA A MISTY POR MÍ' + +[LM5] +'EL BAILE DE LA POLICÍA' + [LM1_2] ~g~Lleva a Misty al club de Luigi. @@ -1779,41 +829,12 @@ Hola, soy Misty. [LM1_6] ~g~¡Vuelve al coche! -[MISTY1] -~r~¡Misty está para el arrastre! - [LM1_7] Detén el vehículo junto a Misty y déjala subir. -{ Post-mission instructions } - [LM1_8] Puedes ir a ver a Luigi y buscar más trabajo o darte un paseo por Liberty City. -[LM1_8A] -Si quieres ganar un dinerillo extra, siempre puedes ''coger prestado'' un taxi... - -{ ====================================================================================== } -{ ================= MISSION: DON'T SPANK MA BITCH UP (LUIGI GOTERELLI) ================= } -{ ====================================================================================== } - -{ TITLE } - -[LM2] -'NO DROGUES A MI ZORRA' - -{ Premission cutscene } - -{ Mick } - -[LM2_C] -Luigi dijo que... que te diera esto... - -[LM2_D] -toma, toma, para ti. - -{ Luigi (letter) } - [LM2_A] Hay una nueva droga en la ciudad llamada SPANK. @@ -1823,14 +844,9 @@ Algún listillo ha estado dando esta basura a mis chicas en el puerto de Portlan [LM2_B] ¡Ve y dale con un bate de béisbol en su cara! -[LM2_F] -Luego coge su coche y repíntalo. - [LM2_G] ¡Quiero una compensación por este insulto! -{ Mission instructions } - [LM2_1] ~g~Coge su coche y haz que cambien su pintura. @@ -1849,19 +865,6 @@ Luego coge su coche y repíntalo. [LM2_4] ~g~¡Vuelve a pintar el coche! -{ ================================================================================= } -{ ================= MISSION: DRIVE MISTY FOR ME (LUIGI GOTERELLI) ================= } -{ ================================================================================= } - -{ TITLE } - -[LM3] -'LLEVA A MISTY POR MÍ' - -{ Premission cutscene } - -{ Luigi } - [LM3_A] Hola, tengo que hablar contigo... Bueno, Mick, ya hablaremos. @@ -1880,14 +883,9 @@ pero cuidado, ese es territorio de los Diablos. [LM3_F] Luego llévala rapidito hasta su taller en Trenton, -[LM3_G] -que a Joey no le gusta esperar. Recuerda, tienes un pie dentro... - [LM3_H] ¡así que estate pendiente del camino y no de Misty! -{ Mission instructions } - [LM3_1D] Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. @@ -1897,68 +895,14 @@ Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon~w~ y hacer saber a Misty que es [LM3_4] ~g~¡Recoge a Misty! -[LM3_10] -~g~¡Consigue un vehículo! - -[LM3_11] -~g~Misty no irá en un autobús, ¡hazte con otro vehículo! - -[LM3_1A] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. - -[LM3_1B] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. - -[LM3_1C] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. - -{ Misty } - [LM3_5] Ahora trabajas para Luigi, ¿no? ¡Ya era hora de que tuviese un conductor de confianza! -{ Postmission cutscene } - -{ Misty } - -[LM3_6] -¡Joey...! - -[LM3_6A] -¿Voy a jugar con tu paquetín otra vez? - -{ Joey } - [LM3_7] Estaré contigo en un minuto, bujía mía. -[LM3_8] -Hola, soy Joey. - -[LM3_9] -Luigi dijo que eras de fiar, así que vuelve más tarde, - -[LM3_9A] -que tendré trabajo para ti. - -[LM3_9B] -¿De acuerdo? - -{ =============================================================================== } -{ ================= MISSION: PUMP-ACTION PIMP (LUIGI GOTERELLI) ================= } -{ =============================================================================== } - -{ TITLE } - -[LM4] -'UN CHULO Y SU ESCOPETA' - -{ Premission cutscene } - -{ Luigi } - -[LM4_A] -Algún Diablo de las narices ha estado vendiendo a sus putitas en mi territorio. +[LM3_10] +~g~¡Consigue un vehículo! [LM4_B] Ve y resuélvelo de mi parte. @@ -1966,20 +910,6 @@ Ve y resuélvelo de mi parte. [LM4_C] Si necesitas un arma, ve a la puerta trasera de la tienda Ammu-Nation que está enfrente del metro. - -{ ============================================================================ } -{ ================= MISSION: THE FUZZ BALL (LUIGI GOTERELLI) ================= } -{ ============================================================================ } - -{ TITLE } - -[LM5] -'EL BAILE DE LA POLICÍA' - -{ Premission cutscene } - -{ Luigi } - [LM5_A] El baile de la policía se está celebrando en la sala Clásica, cerca del puente, @@ -1992,11 +922,6 @@ Tengo chicas haciendo la calles. [LM5_D] Llévalas al baile, sacarán una buena tajada. -[LM5_E] -Saca todo el dinero que puedas a los polis antes de que se lo beban. - -{ Mission instructions } - [LM5_1] ~g~¡Tienes a las chicas tan embutidas que les van a salir moratones! ~g~Primero deja a las que llevas y luego ve a por más. @@ -2012,64 +937,17 @@ Saca todo el dinero que puedas a los polis antes de que se lo beban. [LM5_5] ~g~¡Lleva a las chicas al baile de la policía! -[LM5_7] -~g~¡Si hay menos de cuatro chicas trabajando en el ~p~baile de la policía~g~, Luigi no estará contento! - [LM5_8] ~g~Chicas trabajando en el baile: ~1~ -[LM5_9] -CHICAS: +[JM2] +'DESPEDIDA A LEE CHONG ''EL GORDO''' -{ ============================================================================== } -{ ================= MISSION: MIKE LIPS LAST LUNCH (JOEY LEONE) ================= } -{ ============================================================================== } +[JM4] +'EL CHÓFER DE CIPRIANI' -{ TITLE } - -[JM1] -'EL ÚLTIMO ALMUERZO DE MIKE ''LABIOS'' ' - -{ Premission cutscene } - -{ Misty } - -[JM1_A] -Jo, me aburro, ¿cuándo me la vas a meter? - -{ Joey } - -[JM1_B] -Dame un momento, cariño, que tengo un asuntillo que tratar. - -[JM1_C] -Tengo un trabajito para ti, colega. - -[JM1_D] -Los hermanos Forelli me deben dinero desde hace mucho tiempo - -[JM1_E] -y hay que enseñarles respeto. - -[JM1_F] -Labios Forelli está atiborrándose en el restaurante de Saint Mark's, - -[JM1_G] -así que róbale el coche y llévalo al taller de bombas de 8-Ball en Harwood. - -[JM1_H] -Conoces a 8-Ball, ¿verdad? - -[JM1_I] -En cuanto esté cargado con una bomba, aparca el coche donde lo encontraste. - -[JM1_J] -Luego salte y disfruta del espectáculo. - -[JM1_K] -Pero cuidado, no va a estar comiendo toda la vida. - -{ Mission instructions } +[JM5] +'FIAMBRE EN EL MALETERO' [JM1_1] ~g~Lleva el coche de Forelli al taller que tiene 8-Ball al norte, tras Easy Credit Autos. @@ -2089,11 +967,6 @@ Pero cuidado, no va a estar comiendo toda la vida. [JM1_6] ~g~Vuelve a aparcar el coche en el sitio correcto. -[JM1_7] -~g~¡Cierra la puerta del coche! ¡Se dará cuenta! - -{ 8-Ball's messages, not voiced } - [JM1_8A] ~y~¡Ey, pero si es mi colega! @@ -2103,56 +976,24 @@ Pero cuidado, no va a estar comiendo toda la vida. [JM1_8C] ~y~Ten, tu primer coche es gratis, pero los siguientes te los cobraré. -{ ===================================================================================== } -{ ================= MISSION: FAREWELL 'CHUNKY' LEE CHONG (JOEY LEONE) ================= } -{ ===================================================================================== } - -{ TITLE } - -[JM2] -'DESPEDIDA A LEE CHONG ''EL GORDO''' - -{ Premission cutscene } - -{ Joey } - [JM2_A] Lee Chong ''el Gordo'' está traficando SPANK para una nueva banda de Colombia... o Colorado... O como se llame. [JM2_B] No me acuerdo. El caso es que no importa. -[JM2_C] -Tiene un puesto de fideos en Chinatown. - [JM2_D] Ese cabrito ha vendido su último fideo. [JM2_E] ¡Lo quiero muerto! -[JM2_F] -Si necesitas una pipa, ve a la parte de atrás del Ammu-Nation que está enfrente del metro. - [JM2_G] Búscate un nueve, queda claro, ¿no? [JM2_H] Y recuerda, ve con ojo en Chinatown: es territorio de las Tríadas. -{ =================================================================== } -{ ================= MISSION: VAN HEIST (JOEY LEONE) ================= } -{ =================================================================== } - -{ TITLE } - -[JM3] -'EL ROBO DE LA FURGONETA' - -{ Premission cutscene } - -{ Joey } - [JM3_A] Vamos a asaltar un furgón blindado. @@ -2171,30 +1012,12 @@ Luego llévalo al almacén de los muelles y mis chicos se encargarán desde ahí [JM3_F] El furgón no estará fuera todo el día, así que no pierdas el tiempo. -{ Mission instructions } - [JM3_1] ~g~Lleva el furgón al almacén. [JM3_2] ~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. -{ ============================================================================== } -{ ================= MISSION: CIPRIANI'S CHAUFFEUR (JOEY LEONE) ================= } -{ ============================================================================== } - -{ TITLE } - -[JM4] -'EL CHÓFER DE CIPRIANI' - -{ Premission cutscene } - -{ Joey } - -[JM4_A] -Sí, Toni, ya está a punto. Ahora es una delicia, ¿sabes? - [JM4_B] ¡Ah, aquí está el tío que te decía! @@ -2204,20 +1027,26 @@ Bueno, este no es italiano ni tampoco mecánico, pero sabe arreglar cosas. [JM4_D] Este es el capo de papá, Toni Cipriani. -{ Toni } - [JM4_E] Sí, soy Toni Cipriani. -{ Joey } - [JM4_F] Llévale al restaurante de Mamma en Saint Mark's, ¿va? [JM4_G] Oye, estoy planeando un curro que necesita un buen conductor, pásate por aquí más tarde, ¿estamos? -{ Mission instructions } +[JM4_2] +¡Espera aquí! Deja el motor en marcha. Esta no es una visita social. + +[JM4_3] +¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! + +[JM4_4] +Las Tríadas creen que pueden meterse conmigo. ¡Las Tríadas, CONMIGO! + +[JM4_6] +¡Mi coche! Dije que con cuidado. [JM4_7] ~g~Lleva a Toni al restaurante de Mamma. @@ -2225,90 +1054,24 @@ Oye, estoy planeando un curro que necesita un buen conductor, pásate por aquí [JM4_8] ~r~¡Han liquidado a Toni! -{ Toni, cutscene right after the premission one } - -[JM4_10] -Vale, chaval, llévame primero a la lavandería de Chinatown, tengo un asunto del que ocuparme. - -[JM4_11] -Las lavanderas no están pagando por su protección. - -[JM4_12] -Y ojo con el coche, Joey acaba de arreglar esta chatarra. - -[JM4_13] -Así que con cuidado, ¿vale? - -{ Toni, when bumping the car } - -[JM4_6] -¡Mi coche! Dije que con cuidado. - -{ Toni, when reaching the laundry } - -[JM4_2] -¡Espera aquí! Deja el motor en marcha. Esta no es una visita social. - -[JM4_3] -¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! - -{ Toni, after escaping and finishing the mission } - -[JM4_4] -Las Tríadas creen que pueden meterse conmigo. ¡Las Tríadas, CONMIGO! - -[JM4_5] -Pasa más tarde y les daremos algo que lavar... ¡Su propia ropa manchada de sangre! - -{ ================================================================================= } -{ ================= MISSION: DEAD SKUNK IN THE TRUNK (JOEY LEONE) ================= } -{ ================================================================================= } - -{ TITLE } - -[JM5] -'FIAMBRE EN EL MALETERO' - -{ Premission cutscene } - -{ Joey } - [JM5_A] Guapo, muy guapo... [JM5_B] ¡Justo te estaba buscando! -[JM5_C] -Vale, hay un coche cargado con un fiambre en el bar cercano a Callahan Point. - [JM5_D] Uno de los Forelli se las daba de mafioso y se llevó su merecido. [JM5_E] Lleva el cuerpo a la trituradora en Harwood, ¿vale? -{ Mission instructions } - [JM5_1] ~g~¡Llévalo a la trituradora! [JM5_2] ~g~¡Son los hermanos Forelli! -{ ===================================================================== } -{ ================= MISSION: THE GETAWAY (JOEY LEONE) ================= } -{ ===================================================================== } - -{ TITLE } - -[JM6] -'LA HUIDA' - -{ Premission cutscene } - -{ Joey } - [JM6_A] Vaya cochazo, ¿eh? @@ -2324,11 +1087,6 @@ Di mi palabra de que eras su hombre, así que no la cagues. [JM6_E] Llévales al banco antes de las cinco en punto, ni un minuto después. -{ Thief's dialogues } - -[JM6_1] -Llévanos al banco de la avenida principal. - [JM6_2] Mantén el motor en marcha, entraremos y saldremos enseguida. @@ -2338,479 +1096,30 @@ Mantén el motor en marcha, entraremos y saldremos enseguida. [JM6_4] ¡Líbrate de la poli y llévanos a la casa franca! -{ Mission instructions } - -[JM6_5] -~g~Necesitas un vehículo de fuga, ¡idiota! - [JM6_6] ~g~¡Busca un vehículo menos llamativo! [JM6_7] ~g~¡Necesitas a los 3 para robar el banco! -[JM6_8] -~r~¡Has perdido a todos los ladrones! - -{ ===================================================================== } -{ ================= MISSION: THE CROOK (MARTY CHONKS) ================= } -{ ===================================================================== } - -{ TITLE } - -[MEA1] -'EL CRIMINAL' - -{ Pager message to indicate Chonks' missions are activated } - -[MEAT1_A] -Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléfono público de Trenton si crees que puedes ayudar. - -{ Premission cutscene } - -{ Marty } - -[MEA1_B] -Me llamo Chonks, Marty Chonks. - -[MEA1_C] -Soy el dueño de la fábrica de comestibles Bitch'n' Dog que está a la vuelta de la esquina. - -[MEA1_D] -Tengo problemas económicos, pero, ¿y quién no? - -[MEA1_E] -He quedado con el director de mi banco. - -[MEA1_F] -Es un chorizo que no para de inflar los intereses del préstamo para sacarme una buena tajada. - -[MEA1_G] -Coge mi coche, búscale y tráelo de vuelta. - -[MEA1_H] -¡Tengo una sorpresita para ese parásito chupasangre! - -{ Mission instructions } - -[MEA1_B3] -~g~Reúnete con el director del banco. - -[MEA1_B6] -~g~Lleva el coche a la trituradora para eliminar las pruebas, allí sal del coche y la grúa lo recogerá. - -[MEA1_1] -~r~¡El director del banco está muerto! - -[MEA1_2] -~r~¡Te dijeron que trituraras el coche! - -[MEA1_3] -~g~¡Sal del coche! - -[MEA1_4] -~r~¡Has abandonado al director del banco! - -[MEA1_B5] -UNUSED - -{ Bank Manager, when picking him up } - -[MEA1_B4] -Ah, te envió el Sr. Chonks, ¿verdad? Visitemos a nuestro amigo. - -{ ======================================================================= } -{ ================= MISSION: THE THIEVES (MARTY CHONKS) ================= } -{ ======================================================================= } - -{ TITLE } - -[MEA2] -'LOS LADRONES' - -{ Premission cutscene } - -{ Marty } - -[MEA2_A] -Contraté a unos ladrones para que entraran en mi piso - -[MEA2_B] -y robaran cuanto pillaran para que yo pudiera reclamar a la aseguradora. - -[MEA2_C] -Ahora los muy cabritos me amenazan con delatarme - -[MEA2_D] -si no les doy una parte. - -[MEA2_E] -¿Te lo puedes creer? - -[MEA2_F] -He dejado un coche dentro de la fábrica. - -[MEA2_G] -Ve a recogerles con él en su territorio, en el barrio rojo. - -[MEA2_H] -Luego tráelos a la fábrica para que conozcan la opinión de Marty. - -{ Mission instructions } - -[MEA2_B3] -~g~Reúnete con los ladrones. - -[MEA2_B4] -~g~Llévalos a la fábrica de comestibles Bitch'n'Dog. - -[MEA2_B5] -UNUSED - -[MEA2_B6] -~g~Haz que repinten el coche para borrar las pruebas. - -[MEA2_1] -~r~¡Te dijeron que trituraras el vehículo! - -[MEA2_2] -~r~¡Un ladrón ha muerto! - -[MEA2_3] -~g~Lleva el coche de vuelta a la fábrica. - -[MEA2_4] -~r~¡Has dejado atrás a un ladrón! - -{ ==================================================================== } -{ ================= MISSION: THE WIFE (MARTY CHONKS) ================= } -{ ==================================================================== } - -{ TITLE } - -[MEA3] -'LA MUJER' - -{ Premission cutscene } - -{ Marty } - -[MEA3_A] -El negocio se irá a pique si no consigo un pastizal muy pronto. - -[MEA3_B] -Mi esposa tiene un seguro de vida y ella no ha hecho más que vaciarme los bolsillos. - -[MEA3_C] -He dejado un coche donde siempre. - -[MEA3_D] -Ve a por a mi esposa a Classic Nails y tráela a la fábrica. - -{ Mission instructions } - -[MEA3_B3] -~g~Recoge a la Sra. Chonks. - -[MEA3_B6] -~g~Llévate el coche y tíralo al mar, así eliminaremos las pruebas. - -[MEA3_1] -~r~¡La mujer está muerta! - -[MEA3_2] -~r~¡Se suponía que debías tirar el coche al agua! - -[MEA3_3] -~r~¡Has dejado atrás a su mujer! - -[MEA3_B5] -UNUSED - -{ Marty's wife, when picking her up } - -[MEA3_B4] -¿Marty quiere verme? Bueno, pues que sea rápido, porque tengo que ir a la peluquería. - -{ ===================================================================== } -{ ================= MISSION: HER LOVER (MARTY CHONKS) ================= } -{ ===================================================================== } - -{ TITLE } - -[MEA4] -'SU AMANTE' - -{ Premission cutscene } - -{ Marty } - -[MEA4_A] -Mierda, ¡tengo problemas! - -[MEA4_B] -Resulta que mi esposa salía con uno al que debo dinero. - -[MEA4_C] -¡Se ha cabreado y ahora quiere vengarse! - -[MEA4_D] -He aceptado verle, - -[MEA4_E] -y piensa que voy a devolverle el dinero. - -[MEA4_F] -Pero creo - -[MEA4_G] -¡que los perros de Liberty van a disfrutar de un nuevo sabor este mes! - -{ Mission instructions } - -[MEA4_B3] -~g~Recoge al amante de su mujer. - -[MEA4_1] -~r~¡Carlos está muerto! - -[MEA4_2] -~r~¡Marty Chonks ha muerto! - -[MEA4_3] -~r~¡Has abandonado a Carlos, el usurero! - -{ Carlos, when picking him up } - -[MEA4_B4] -¿Marty te envía? Vale, le voy a enseñar a ese sinvergüenza el significado de la palabra negocio. - -{ Postmission cutscene } - -{ Marty } - -[MEA4_B5] -¡Carl, hola! Ehhh... Necesito más tiempo para conseguir tu dinero. - -[MEA4_B7] -Pero si pasas por mi oficina... - -{ Carlos } - -[MEA4_B6] -Ya es muy tarde, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé de tu negocio... - -{ =============================================================== } -{ ================= MISSION: TURISMO (EL BURRO) ================= } -{ =============================================================== } - -{ TITLE } - -[DIAB1] -'TURISMO' - -{ Pager message that tells the player El Burro's missions are now available } - -[DIAB1_A] -El Burro quiere ofrecerte una oportunidad. Ve al teléfono público de los cerros de Hepburn si te interesa. - -{ Premission cutscene } - -{ El Burro, portorriqueño } - -[DIAB1_B] -Al habla El Burro, de los Diablos. - -[DIAB1_D] -Eres nuevo en Liberty, pero ya te estás ganando una reputación en las calles. - -[DIAB1_E] -Hay una carrera que empezará junto a la sala Clásica, cerca del puente Callahan. - -[DIAB1_F] -Consíguete un buen carro y el primero que pase por todos los puntos de control se llevará el premio. - -{ Mission instructions } - -[DIAB1_1] -~g~3... 2... 1... ¡ADELANTE! - -[DIAB1_4] -~g~Hazte con un coche rápido y ve a la parrilla de salida. - -[DIAB1_3] -~r~No sabes ganar ni una rifa, ¡FRACASADO! - -[DIAB1_2] -~g~Felicidades, has ganado con un tiempo increíble de ~1~ segundos. - -[DIAB1_5] -TIEMPO DE CARRERA: - -{ Pager message after succeeding this mission } - -[DIAB1_C] -Se te da bien correr. Pásate por el teléfono público y puede que El Burro tenga trabajo para ti. - -{ ============================================================================ } -{ ================= MISSION: I SCREAM, YOU SCREAM (EL BURRO) ================= } -{ ============================================================================ } - -{ TITLE } - -[DIAB2] -'IRA HELADA' - -{ Premission cutscene } - -{ El Burro, portorriqueño } - -[DIAB2_A] -¡Empecé mi negocio de entretenimiento exótico sin nada más que lo que cabía en mis pantalones de cuero! - -[DIAB2_B] -Una banda de roñosos amenazó con quitarme a mi protagonista si no les pago. - -[DIAB2_C] -Amenazaron al hombre equivocado, amigo. - -[DIAB2_D] -Su debilidad son los helados. - -[DIAB2_E] -Hazte con la bomba que dejé en Harwood, - -[DIAB2_F] -secuestra la camioneta del heladero mientras hace su ronda - -[DIAB2_G] -y engaña a esos idiotas con esa musiquita. - -[DIAB2_H] -Se esconden en un almacén del muelle Atlantic. - -{ Mission instructions } - -[DIAB2_1] -~g~Recoge el maletín en Harwood. - -[DIAB2_2] -~g~Encuentra un camión de helados. - -[DIAB2_3] -~g~Aparca el camión de helados en el muelle Atlantic. - -[DIAB2_4] -~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. - -[DIAB2_6] -~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. - -[DIAB2_7] -~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. - -[DIAB2_5] -~g~Sal del camión y luego usa el mando a distancia para detonarlo. - -{ ===================================================================== } -{ ================= MISSION: TRIAL BY FIRE (EL BURRO) ================= } -{ ===================================================================== } - -{ TITLE } - -[DIAB3] -'A LA HOGUERA' - -{ Premission cutscene } - -{ El Burro, portorriqueño } - -[DIAB3_A] -¡Unas Tríadas insolentes robaron mi lindo carro anoche, - -[DIAB3_B] -lo destrozaron y lo quemaron! - -[DIAB3_C] -En el baúl había algunas de mis más preciadas posesiones sobre burros... - -[DIAB3_D] -Objetos de coleccionista irremplazables, amigo. - -[DIAB3_E] -Escondí un arma en el borde de Chinatown. - -[DIAB3_F] -Tómala y enseña a esos vándalos de las Tríadas a tenerle miedo a la ira pijuda de El Burro. - -[DIAB3_G] -¡Arriba! - -{ Mission instructions, in large text } - -[DIAB3_1] -MATA A 25 TRÍADAS - -{ ===================================================================== } -{ ================= MISSION: BIG 'N' VEINY (EL BURRO) ================= } -{ ===================================================================== } - -{ TITLE } - -[DIAB4] -'GRANDE Y VENOSO' - -{ Premission cutscene } - -{ El Burro, portorriqueño } - -[DIAB4_A] -¡Un ladrón oportunista robó una camioneta con mi última publicación! - -[DIAB4_B] -Pero ese idiota drogado de SPANK dejó las puertas de atrás abiertas, - -[DIAB4_C] -¡y ahora mi literatura para adultos - -[DIAB4_D] -tan bellamente producida, tan gustosamente fotografiada, está siendo esparcida por toda Liberty! - -[DIAB4_E] -Toma la camioneta y sigue el rastro de los volúmenes 1, 2 y 3 de Donkey Does Dallas, - -[DIAB4_F] -tomándolos por el camino. - -[DIAB4_G] -¡Cuando alcances a ese bandido espaciado con SPANK, chíngatelo! - -[DIAB4_H] -Luego reparte mis revistas XXX por el barrio rojo. - -{ Mission instructions } - -[DIAB4_1] -~g~Lleva la furgoneta a la parte de atrás de Revistas XXX. - -{ =================================================================================== } -{ ================= MISSION: TAKING OUT THE LAUNDRY (TONI CIPRIANI) ================= } -{ =================================================================================== } - -{ TITLE } - [TM1] 'SACANDO LA COLADA' -{ Pager message that tells the player Toni's missions are available } +[TM2] +'LA ENTREGA' + +[TM3] +'SALVATORE HA CONVOCADO UNA REUNIÓN' + +[TM4] +'TRÍADAS Y TRIBULACIONES' + +[TM5] +'LLUVIA DE PECES' [TONI_P] ¡Tengo un trabajo urgente para ti! -Toni -{ Premission cutscene } - -{ Toni } - [TM1_A] Siéntate, chico, siéntate de una vez. @@ -2823,16 +1132,12 @@ La lavandería no quiere pagar la protección, ¿eh? [TM1_D] ¡Esos aspirantes a tipos duros van a saber lo que es ser un tipo duro! -{ Toni's Mamma } - [TM1_E] ¡Eso, enséñales respeto! ¡Las Tríadas no se ríen de ninguno de mis hijos! [TM1_F] Tu padre, Dios acoja su alma, no toleraba ni media a las Tríadas en Sicilia. -{ Toni } - [TM1_G] Lo siento, mamá. Sí, mamá. @@ -2845,27 +1150,12 @@ y a cualquiera de las Tríadas que se cruce en tu camino. [TM1_J] 8-Ball te dará lo que necesites. -{ ======================================================================== } -{ ================= MISSION: THE PICK-UP (TONI CIPRIANI) ================= } -{ ======================================================================== } - -{ TITLE } - -[TM2] -'LA ENTREGA' - -{ Premission cutscene } - -{ Toni's Mamma } - [TM2_A] Toni ha salido a partir cabezas, o a intentarlo... [TM2_AA] Nunca será tan duro como su padre. Te dejó una nota en la mesa. -{ Toni (letter) } - [TM2_B] La lavandería ya quiere pagar. ¡Buen trabajo, chico! @@ -2878,30 +1168,12 @@ Puede que intenten metértela doblada, pero no te dejes. [TM2_E] ¡Nadie, quiero decir nadie, se mete con Toni Cipriani! -{ Mission instructions } - [TM2_1] ~g~¡Lleva el dinero a Toni! [TM2_2] ~g~¡Los dejaste tiesos a todos! -[TM2_3] -~g~¡Es una trampa! ¡Liquidadlos a todos! - -{ ========================================================================================= } -{ ================= MISSION: SALVATORE'S CALLED A MEETING (TONI CIPRIANI) ================= } -{ ========================================================================================= } - -{ TITLE } - -[TM3] -'SALVATORE HA CONVOCADO UNA REUNIÓN' - -{ Premission cutscene } - -{ Toni's Mamma } - [TM3_MA] ¡No sé dónde está! @@ -2911,8 +1183,6 @@ Te juro que mi hijo a veces no sabe lo que hace. [TM3_MC] Ahora bien, su padre era diferente. Siempre en la cumbre, pendiente de todo, valiente... -{ Toni (letter) } - [TM3_A] Don Salvatore ha convocado una reunión. @@ -2934,8 +1204,6 @@ Si quieren guerra, la tendrán. [TM3_G] Ponte en marcha. -{ Mission instructions } - [TM3_1] ~g~Ve al taller de Joey a por la limusina. @@ -2948,114 +1216,9 @@ Ponte en marcha. [TM3_4] ~g~Lleva a los mafiosos a la casa de Salvatore. -[TM3_A1] -~r~¡Joey está frito! - -[TM3_A2] -~r~¡Joey y Luigi han sido incinerados! - -[TM3_A3] -~r~¡Joey, Luigi y Toni están calcinados! - -{ Toni, when the Triads ambush } - [TM3_5] ~y~¡Es una emboscada de las Tríadas! -{ Postmission cutscene } - -{ Toni } - -[TM3_H] -Buen trabajo, chaval, muy bueno. - -[TM3_I] -Vente, te presentaré al Don. - -{ Salvatore } - -[TM3_J] -¡Hola! ¡Luigi! - -{ Luigi } - -[TM3_K] -Mis chicas te han echado de menos, Salvatore. Hace mucho que no te vemos. - -{ Salvatore } - -[TM3_L] -Diles que en cuanto resolvamos este desafortunado incidente - -[TM3_M] -iremos todos al club para celebrarlo, ¿vale? - -[TM3_N] -¡Mi niño! - -{ Joey } - -[TM3_N2] -¿Cómo lo llevas, papá? - -{ Salvatore } - -[TM3_O] -¿Has encontrado ya una buena mujer? - -[TM3_P] -Tu madre, que en paz descanse, se retorcería en la tumba - -[TM3_Q] -si te viera sin una mujer. - -{ Joey } - -[TM3_R] -Lo sé, papá, estoy en ello. - -{ Salvatore } - -[TM3_S] -¡Toni! ¿Cómo está tu madre? - -[TM3_T] -Es una gran mujer, ¿sabes? Fuerte, ''firenze''. - -{ Toni } - -[TM3_U] -Está bien, estupendamente. - -{ Salvatore } - -[TM3_V] -Fantástico, fantástico. Bien, muchachos, entrad mientras yo hablo con nuestro nuevo amigo. - -[TM3_W] -Tienes un gran futuro por delante, hijo mío... - -{ ==================================================================================== } -{ ================= MISSION: TRIADS AND TRIBULATIONS (TONI CIPRIANI) ================= } -{ ==================================================================================== } - -{ TITLE } - -[TM4] -'TRÍADAS Y TRIBULACIONES' - -{ Premission cutscene } - -{ Toni's Mamma } - -[TM4_A] -Ah, eres tú. Toni no está. - -[TM4_A2] -Pero te ha dejado una de sus cartitas de amor. - -{ Toni } - [TM4_B] ¡Esto es la guerra! Las Tríadas tienen una piscifactoría como tapadera. @@ -3074,24 +1237,9 @@ Creen que está protegida por las Tríadas, así que creo que se merecen un cast [TM4_G] Qué narices, si ves la oportunidad, cárgate también a unos cuántos de sus soldados. -{ Mission instructions } - [TM4_GAT] ~g~Necesitas un camión de pescado de las Tríadas para entrar. -{ ====================================================================== } -{ ================= MISSION: BLOW FISH (TONI CIPRIANI) ================= } -{ ====================================================================== } - -{ TITLE } - -[TM5] -'LLUVIA DE PECES' - -{ Premission cutscene } - -{ Toni } - [TM5_B] Vale, ya me he hartado de esta mierda. @@ -3119,23 +1267,11 @@ Quiero que llueva pescado. [TM5_J] En plan bíblico, nada de bajo presupuesto. -{ ======================================================================== } -{ ================= MISSION: CHAPERONE (SALVATORE LEONE) ================= } -{ ======================================================================== } +[FM2] +'CORTANDO LA HIERBA' -{ TITLE } - -[FM1] -'CARABINA' - -{ Pager message, appears when Toni's missions have not been complete } - -[FRANGO] -~g~¡Salvatore quiere que ayudes primero a Toni a ocuparse de las Tríadas! - -{ Premission cutscene } - -{ Salvatore } +[FM4] +'ÚLTIMA VOLUNTAD' [FM1_A] Mis chicos y yo queremos hablar de negocios, @@ -3158,13 +1294,9 @@ Y aquí está, ¡la primera y única reina de Saba! [FM1_G] Fuera lo que fuera, seguro que me cuesta dinero. -{ Maria } - [FM1_H] Bueno, no pensarás que estoy aquí para conversar, ¿o sí? -{ Salvatore } - [FM1_I] Métete en el coche y cierra el pico. @@ -3174,8 +1306,6 @@ Llévate la limusina, pero devuélvela de una pieza, ¿me has oído? [FM1_K] Y cuidado con ella, es una lianta. -{ Maria } - [FM1_L] ¡Sí, sí, sí! Seguro que tu nuevo perrito faldero tiene todo previsto. @@ -3185,10 +1315,14 @@ Y cuidado con ella, es una lianta. [FM1_N] ¡Oye, tú, vamos a ver a Chico para que nos dé unas pirulas! -[FM1_O] -Creo que está en la estación de ferrocarril del muelle de Chinatown. +[FM1_P] +~g~Ese de ahí es Chico, párate cerca. -{ Mission instructions } +[FM1_S] +Aquí tienes, señorita. + +[FM1_TT] +¡UNA REDADA! [FM1_1] ~g~¡Vuelve al Stretch! @@ -3214,98 +1348,6 @@ Creo que está en la estación de ferrocarril del muelle de Chinatown. [FM1_8] ~r~¡Te cargaste al camello de María! -[FM1_P] -~g~Ese de ahí es Chico, párate cerca. - -[FM1_9] -~g~La fiesta es allí. Deja a María enfrente. - -[FM1_10] -~g~Has abandonado a María, vuelve y recógela. - -{ Cutscene when the player finds Chico } - -{ Chico, mexicano } - -[FM1_Q] -¡Ay, mira, es mi chica favorita! - -[FM1_Q1] -¿Quieres un poco de diversión? ¿Un poco de... hmmm, de SPANK? - -{ Maria } - -[FM1_R] -Hola, Chico. No, solo lo de siempre. - -{ Chico, mexicano } - -[FM1_S] -Aquí tienes, señorita. - -[FM1_S1] -Ey, deberías echar un vistazo a la fiesta del almacén en el lado este del muelle Atlantic. - -{ Maria } - -[FM1_T] -Gracias, Chico, nos vemos. - -{ Chico, mexicano } - -[FM1_U] -Gracias y disfruta. Es buen material. - -{ Maria } - -[FM1_V] -¡Venga, tú, vamos a ver esa fiesta! - -{ Cutscene when the player takes Maria to the party } - -{ Maria } - -[FM1_W] -Oye, tú, espera aquí y quédate pendiente del coche mientras yo voy a menear el esqueleto, ¿vale? - -{ Police dispatcher } - -[FM1_SS] -~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: asistan redada de narcóticos en el muelle Atlantic. - -{ Warehouse's guard } - -[FM1_TT] -¡UNA REDADA! - -{ Maria } - -[FM1_X] -¡Vale, tú, salgamos de aquí! ¡Uaaah! - -{ Cutscene when the player takes Maria back to Salvatore's home } - -{ Maria } - -[FM1_Y] -Quiero que sepas que me lo he pasado muy bien por primera vez en mucho tiempo y que me has tratado muy bien, con respeto. - -[FM1_AA] -Bueno, será mejor que me vaya. Espero que nos veamos pronto. - -{ ================================================================================ } -{ ================= MISSION: CUTTING THE GRASS (SALVATORE LEONE) ================= } -{ ================================================================================ } - -{ TITLE } - -[FM2] -'CORTANDO LA HIERBA' - -{ Premission cutscene } - -{ Salvatore } - [FM2_J] Déjanos a solas un momento. @@ -3315,25 +1357,47 @@ El cártel colombiano fabrica SPANK en Liberty, [FM2_K] pero no sabemos dónde y parece como si supieran qué vamos a hacer antes de que lo pensemos. -[FM2_B] -¡Tenemos a un chivato! - [FM2_L] Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. [FM2_M] Ha estado gastando más dinero del que gana. -[FM2_C] -No está ni chuleando ni traficando, así que estará cantando. - [FM2_N] Suele ir del trabajo a casa en taxi, así que síguelo. [FM2_O] Y si nos está vendiendo... mátalo. -{ Mission instructions } +[FM2_F] +Aquí viene nuestro amiguito. El señor Bocazas en persona. + +[FM2_G] +¿Te han seguido? Ya sabes que esto es nuestro secretito. + +[FM2_H] +No, no, no me han seguido. ¿Tienes lo mío? + +[FM2_I] +Toma tu SPANK, soplón, ahora habla. + +[FM2_P] +Vale, los Leone libran una guerra en dos frentes. + +[FM2_Q] +Tienen una guerra territorial con las Tríadas y no parece que ninguno se vaya a rendir. + +[FM2_R] +Mientras tanto, Joey Leone ha cabreado a los Forelli. + +[FM2_S] +Cada día pierden más hombres e influencia. + +[FM2_T] +Salvatore se está volviendo peligroso y paranoico. Sospecha de todos y de todo. + +[FM2_U] +Con lo leales que son algunos, ¿de qué tendría que preocuparse? [FM2_1] ~g~¡Ahí está Curly Bob! @@ -3365,72 +1429,6 @@ Y si nos está vendiendo... mátalo. [FM2_12] ~r~¡Te ha dado esquinazo! -[FM2_14] -~r~¡Te acercaste demasiado y asustaste a Curly! - -[FM2_15] -~g~No te acerques mucho, ¡o Curly sospechará! - -[FM2_16] -ASUSTÓMETRO: - -{ Cutscene that appears when successfully following Curly Bob } - -{ Miguel, colombiano } - -[FM2_F] -Aquí viene nuestro amiguito. El señor Bocazas en persona. - -{ Catalina, colombiana } - -[FM2_G] -¿Te han seguido? Ya sabes que esto es nuestro secretito. - -{ Curly Bob } - -[FM2_H] -No, no, no me han seguido. ¿Tienes lo mío? - -{ Catalina, colombiana } - -[FM2_I] -Toma tu SPANK, soplón, ahora habla. - -{ Curly Bob } - -[FM2_P] -Vale, los Leone libran una guerra en dos frentes. - -[FM2_Q] -Tienen una guerra territorial con las Tríadas y no parece que ninguno se vaya a rendir. - -[FM2_R] -Mientras tanto, Joey Leone ha cabreado a los Forelli. - -[FM2_S] -Cada día pierden más hombres e influencia. - -[FM2_T] -Salvatore se está volviendo peligroso y paranoico. Sospecha de todos y de todo. - -{ Catalina, colombiana } - -[FM2_U] -Con lo leales que son algunos, ¿de qué tendría que preocuparse? - -{ ================================================================================== } -{ ================= MISSION: BOMB DA BASE: ACT I (SALVATORE LEONE) ================= } -{ ================================================================================== } - -{ TITLE } - -[FM21] -'BASE FUERA: ACTO I' - -{ Premission cutscene } - -{ Salvatore } - [FM3_A] Tenemos que despachar a esos puñeteros colombianos, @@ -3458,38 +1456,15 @@ Si haces esto por mí, serás como de la familia. Todo lo que quieras. [FM3_I] Ve a ver a 8-Ball, necesitarás su ayuda para volar ese barco. -{ =================================================================================== } -{ ================= MISSION: BOMB DA BASE: ACT II (SALVATORE LEONE) ================= } -{ =================================================================================== } - -{ TITLE } - -[FM3] -'BASE FUERA: ACTO II' - -{ Premission cutscene, when not having 100.000 $ } - -{ 8-Ball } - [FM3_8A] ¡Hombre, colega! Salvatore me avisó, [FM3_8B] pero este trabajo va a necesitar muchos fuegos artificiales. -[FM3_8C] -Necesitaré 100.000 $ para cubrir gastos, - [FM3_8D] pero ya sabes que conmigo valdrá la pena. -[FM3_CC] -Regresa cuando tengas el dinero. - -{ Premission cutscene, when having 100.000 $ } - -{ 8-Ball } - [FM3_8E] Venga, ¡vamos allá! @@ -3499,13 +1474,6 @@ Puedo reventar el barco, pero aún no puedo usar una pipa con estas manos. [FM3_8G] ¡Toma, este fusil te ayudará a volar unas cuántas cabezas! -{ 8-Ball, when reaching the boat area } - -[FM3_8I] -Encuentra una posición elevada. Entraré cuando dispares el primer tiro. - -{ Mission instructions } - [FM3_4] ~g~¡Para el coche y deja que 8-Ball salga! @@ -3515,19 +1483,6 @@ Encuentra una posición elevada. Entraré cuando dispares el primer tiro. [FM3_8] ~r~¡Los guardias han sido alertados! -{ ============================================================================ } -{ ================= MISSION: LAST REQUESTS (SALVATORE LEONE) ================= } -{ ============================================================================ } - -{ TITLE } - -[FM4] -'ÚLTIMA VOLUNTAD' - -{ Premission cutscene } - -{ Salvatore } - [FM4_A] ¡Mi socio favorito! @@ -3549,83 +1504,14 @@ Tuvimos que ayudar a un tipo a que se decidiera y fue un poco... sucio. [FM4_H] Llévalo a la trituradora antes de que lo encuentre la pasma. -{ Pager message, appears right after getting into the target car } +[AM3] +'PURGA DE PAPARAZZIS' -[FM4_1] -Soy María. ¡El coche es una trampa! Estoy en el lado sur del puente Callahan. +[AM4] +'LA PAGA DE RAY' -{ Cutscene after reaching Maria } - -{ Maria } - -[FM4_2] -Mira, Salvatore cree que se la estamos jugando, - -[FM4_3] -así que te vendió al cártel para llegar a un trato. - -[FM4_4] -No podía permitírselo, o sea, lo peor es... - -[FM4_4B] -que yo tengo la culpa, porque le dije que somos pareja. - -[FM4_5] -¡No me preguntes por qué, no lo sé! - -[FM4_6] -Mira, la mafia te quiere muerto y yo también tengo que salir de aquí. - -[FM4_6B] -¡He visto demasiados asesinatos, demasiada sangre! - -[FM4_7] -Es una amiga mía, ¿vale?, una vieja amiga... Es Asuka, es de fiar. - -{ Asuka } - -[FM4_8] -Vamos, dejémonos de discursos. - -[FM4_9] -Mejor nos vamos antes de que haya más italianos histéricos con intenciones menos amistosas. - -{ Postmission cutscene } - -{ Maria } - -[LRQC_1] -Asuka y yo tenemos que hablar... - -[LRQC_2] -¿Por qué no te das una vuelta? - -{ Asuka } - -[LRQC_3] -Necesitarás un escondite. - -[LRQC_4] -Hay un almacén en la orilla de Belleville que podría servirte. - -[LRQC_5] -Regresa a mi apartamento cuando estés listo - -[LRQC_6] -y podremos tener una charla. - -{ ========================================================================================== } -{ ================= MISSION: SAYONARA SALVATORE (ASUKA KASEN, FIRST BATCH) ================= } -{ ========================================================================================== } - -{ TITLE } - -[AM1] -'SAYONARA, SALVATORE' - -{ Premission cutscene } - -{ Asuka } +[AM5] +'TANNER EL TRAIDOR' [AM1_A] Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, @@ -3642,32 +1528,18 @@ Puedo darte trabajo en nuestra organización, [AM1_E] pero primero debes demostrarme que has cortado todos tus lazos con la mafia. -{ Alternative subtitles that appear depending if the hour is single-digit or double digit, to make them uniform } - -[AM1_F] -Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (~1~:~1~) - -[AM1_K] -Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (0~1~:~1~) - [AM1_G] Asegúrate de que no salga con vida. [AM1_H] Mientras tanto María y yo nos pondremos al día. -{ Maria } - [AM1_I] Uy, Asuka, tienes un masajeador... -{ Asuka } - [AM1_J] Eso no es un masajeador. -{ Mission instructions } - [AM1_1] ~g~¡Salvatore está saliendo del club de Luigi! @@ -3683,120 +1555,30 @@ Eso no es un masajeador. [AM1_5] ~g~Ve al barrio rojo y espera a que Salvatore salga del club. -[AM1_6] -~g~Si te dejas ver por el club de Luigi, ¡la mafia te descubrirá! - [AM1_7] ~r~Salvatore está en su casita, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar ''Chacal''! [AM1_8] ~g~Salvatore saldrá del club de Luigi sobre las ~1~:~1~. -[AM1_10] -~g~Salvatore saldrá del club de Luigi sobre las 0~1~:~1~. - -[AM1_9] -~r~¡Salvatore ha vuelto a meterse en el club de Luigi! - -{ ========================================================================================== } -{ ================= MISSION: UNDER SURVEILLANCE (ASUKA KASEN, FIRST BATCH) ================= } -{ ========================================================================================== } - -{ TITLE } - -[AM2] -'BAJO VIGILANCIA' - -{ Premission cutscene } - -{ Asuka } - -[AM2_A] -La muerte de Salvatore es una placentera noticia, - -[AM2_A2] -eres un asesino eficaz. Eso me gusta en un hombre. - -[AM2_B] -Este es mi hermano Kenji. - -{ Kenji } - -[AM2_C] -Asuka tiene un trabajito para ti, pero cuando acabes, pásate por mi casino y podremos hablar. - -{ Asuka } - -[AM2_D] -Típico de Kenji, siempre está detrás de mis juguetes. - -{ The voiced dialogue doesn't match the English subtitles for the following strings } - -[AM2_E] -Mi contacto en la policía me dice que el FBI ha montado un operativo de vigilancia - -[AM2_E2] -en varios puntos de la ciudad. - -[AM2_F] -No tenemos tiempo para contactar con nadie y evitar que nos incriminen. - -[AM2_G] -Liquida a esos polis espías, pero cuidado: tendrán apoyo. - -{ Mission instructions } - [AM2_4] ~g~¡Has irrumpido como un elefante en una cacharrería! -{ ======================================================================================= } -{ ================= MISSION: PAPARAZZI PURGE (ASUKA KASEN, FIRST BATCH) ================= } -{ ======================================================================================= } - -{ TITLE } - -[AM3] -'PURGA DE PAPARAZZIS' - -{ Premission cutscene } - -{ Asuka (letter) } - [AM3_A] Un periodista ha estado husmeando por aquí. [AM3_B] María y yo nos ido de vacaciones juntas hasta que puedas librarte de ese mirón pervertido. -[AM3_C] -Ahora mismo estará probablemente en la bahía. ¡Roba una lancha de la policía y hunde su carrera! - -{ ======================================================================================= } -{ ================= MISSION: PAY DAY FOR RAY (ASUKA KASEN, FIRST BATCH) ================= } -{ ======================================================================================= } - -{ TITLE } - -[AM4] -'LA PAGA DE RAY' - -{ Premission cutscene } - -{ Asuka } - [AM4_A] ¡Si es guapo manitas! [AM4_B] María está un poquito liada, pero le diré que has venido. -{ Maria } - [AM4_C] ¿Quién es, Asuka? Sé que he sido muy traviesa, ¡pero necesito mear! ¿Vale? -{ Asuka } - [AM4_D] Es hora de que conozcas a nuestro espía en la policía. @@ -3809,64 +1591,6 @@ Aquí está su pago por el último trabajito que hizo para nosotros. [AM4_G] Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. -{ Ray, on each payphone } - -[AM4_1A] -Ve a la cabina al oeste del Parque Belleville. - -[AM4_1B] -Ve a la cabina del Campus de Liberty. - -[AM4_1C] -Ve a la cabina al sur del Parque Belleville. - -[AM4_1D] -Ven a verme a los baños públicos del parque. - -{ Postmission cutscene } - -{ Ray } - -[AM4_3] -¡Tú debes de ser el nuevo chico de los recados de Asuka! - -[AM4_4] -¿Tienes el dinero? ¿Está todo? - -[AM4_5] -Ya sé lo que estás pensando, otro policía corrupto. - -[AM4_6] -Bueno, éste es un mundo corrupto. - -[AM4_7] -Pierdo a un par de socios y esos idiotas de asuntos internos empiezan a meter las narices. - -[AM4_8] -¡Y seguro que les llega mi olor! - -[AM4_9] -¡Pues esta ciudad es una gran alcantarilla! - -[AM4_10] -Pero voy a necesitar un ayudita ajena al cuerpo. - -[AM4_11] -Si estás interesado, ya sabes dónde encontrarme. - -{ ======================================================================================== } -{ ================= MISSION: TWO-FACED TANNER (ASUKA KASEN, FIRST BATCH) ================= } -{ ======================================================================================== } - -{ TITLE } - -[AM5] -'TANNER EL TRAIDOR' - -{ Premission cutscene } - -{ Asuka (letter) } - [AM5_A] María y yo hemos ido de compras. @@ -3879,23 +1603,107 @@ Fuera de su coche no sabe hacer casi nada, así que le hemos puesto un localizad [AM5_D] ¡Haz que sufra! -{ Mission instructions } - [AM5_1] ¡Tanner te ha pillado! -{ ========================================================================= } -{ ================= MISSION: KANBU BUST-OUT (KENJI KASEN) ================= } -{ ========================================================================= } +[AS1] +'CEBO' -{ TITLE } +[AS2] +'CAFÉ PARA LLEVAR' + +[AS4] +'RESCATE' + +[AS1_A] +Parece que Miguel piensa que le maltrato. + +[AS1_B] +Pero ha revelado cuánto teme Catalina tu búsqueda de venganza. + +[AS2_A] +Subestimamos los planes que tiene Catalina para el SPANK. + +[AS2_B] +Va mucho más allá de hacer que los jamaicanos lo vendan en las esquinas. + +[AS2_D] +Vende SPANK en puestos callejeros. + +[AS2_1] +~g~¡Todos los puestos de café en Portland han sido destruidos! + +[AS2_2] +~g~¡Todos los puestos de café en Staunton Island han sido destruidos! + +[AS2_3] +~g~¡Todos los puestos de café en Shoreside Vale han sido destruidos! + +[AS2_4] +~r~¡El cártel ha avisado a sus camellos! + +[AS2_5] +~g~¡Todavía hay puestos de café en Shoreside Vale y en Staunton Island! + +[AS2_6] +~g~¡Todavía hay puestos de café en Shoreside Vale! + +[AS2_7] +~g~¡Todavía hay puestos de café en Staunton Island! + +[AS2_8] +~g~¡Todavía hay puestos de café en Portland! + +[AS2_9] +~g~¡Todavía hay puestos de café en Portland y en Shoreside Vale! + +[AS2_10] +~g~¡Todavía hay puestos de café en Portland y en Staunton Island! + +[AS2_12] +~g~¡Recorre los distritos de Liberty y busca puestos de café ~b~Espresso-2-Go~g~! + +[AS3_A] +¿Lo apretamos un poco más o esperamos a que se vuelva negro y se caiga? + +[AS3_B] +Dale un toque rápido... + +[AS3_D] +¡Mi manitas! + +[AS3_E] +Me aburría, así que vine a hacerle compañía a Asuka. + +[AS3_1] +~g~¡Busca una ~r~lancha~g~ y ve a la ~b~boya señalada! + +[AS3_3] +~g~¡Espera a que la ~y~avioneta~g~ comience a acercarse! + +[AS3_5] +~g~¡Recupera el cargamento! + +[AS3_4] +~g~¡Usa un lanzacohetes para derribar ~y~la avioneta~g~! + +[AS3_2] +~b~¡Ve a la boya del aeropuerto señalada! ~y~¡El avión se está acercando! + +[AS3_6] +~g~~1~ DE 8 [KM1] 'LA FUGA DEL KANBU' -{ Premission cutscene } +[KM3] +'UN MAL TRATO' -{ Kenji } +[KM4] +'SHIMA' + +[KM5] +'CONTRINCANTES TRAFICANTES' [KM1_A] Mi hermana te tiene en gran estima, @@ -3918,13 +1726,9 @@ Es un miembro importante de la familia. [KM1_H] Libéralo y llévatelo al dojo de Bedford Point. -{ Pager message that appears after completing this mission } - [KM1_D] Te damos las gracias por tus generosas acciones. Si alguna vez necesitas ayuda, el dojo tendrá el honor de proporcionarte dos hombres que te ayudarán. -{ Mission instructions } - [KM1_1] ~g~¡Roba un coche de la policía! @@ -3934,9 +1738,6 @@ Te damos las gracias por tus generosas acciones. Si alguna vez necesitas ayuda, [KM1_3] ~g~Ahora llévalo al dojo de la yakuza. -[KM1_4] -~g~¡Necesitas un coche de policía para hacer el trabajo! - [KM1_5] ~g~Ahora ve a la comisaría. @@ -3946,12 +1747,6 @@ Te damos las gracias por tus generosas acciones. Si alguna vez necesitas ayuda, [KM1_7] ~g~¡Sólo pueden entrar vehículos de policía autorizados! -[KM1_8A] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. - -[KM1_8D] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. - [KM1_9] ~r~No destruiste la pared con un coche bomba. @@ -3961,25 +1756,6 @@ Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdat [KM1_11] ~r~¡La policía te ha seguido! -[KM1_12] -~g~¡Llévalo al dojo, pero deshazte primero de la policía! - -[KM1_13] -¡Mete el vehículo en el garaje! - -{ =========================================================================== } -{ ================= MISSION: GRAND THEFT AUTO (KENJI KASEN) ================= } -{ =========================================================================== } - -{ TITLE } - -[KM2] -'ROBO DE VEHÍCULOS' - -{ Premission cutscene } - -{ Kenji } - [KM2_A] Es imposible sobreestimar la importancia del protocolo en este trabajo. @@ -3989,39 +1765,12 @@ Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca pude corre [KM2_C] Su debilidad son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. -[KM2_D] -No hace falta decir que debemos darle los coches como un regalo, para pagar mi deuda con él. - -[KM2_E] -Debes obtener los coches de la lista y llevarlos a un garaje que hay tras el aparcamiento de Newport. - [KM2_F] Mi honor lo exige. -{ Mission instructions } - -[KM2_1] -~g~Repara el coche, tiene que estar en perfecto estado. - [KM2_2] ~g~Coche entregado. -[KM2_3] -~g~Recuerda que los ~r~coches ~g~tienen que estar en perfecto estado para ser aceptados en el ~p~garaje~g~. - -{ ===================================================================== } -{ ================= MISSION: DEAL STEAL (KENJI KASEN) ================= } -{ ===================================================================== } - -{ TITLE } - -[KM3] -'UN MAL TRATO' - -{ Premission cutscene } - -{ Kenji } - [KM3_A] Cuando los problemas acechan, el tonto les da la espalda, mientras que el sabio los enfrenta. @@ -4040,11 +1789,6 @@ Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus re [KM3_E] ¡Nuestro honor exige que no dejes a nadie vivo! -{ Mission instructions } - -[KM3_1] -~g~El cártel espera a una banda jamaicana, ¡así que roba uno de sus coches! Dirígete al norte; encontrarás uno en Newport. - [KM3_2] ~g~Recoge a tu contacto. @@ -4054,15 +1798,9 @@ Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus re [KM3_4] ~r~¡Han escapado! -[KM3_5] -~g~Toca el claxon para empezar con el trato. - [KM3_6] ~g~¡Mátalos, mátalos a todos! -[KM3_7] -¡Es una trampa de la yakuza, tío! - [KM3_8] ~g~¡Necesitas un coche de los jamaicanos para este trabajo! @@ -4072,44 +1810,12 @@ Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus re [KM3_10] ~r~¡El contacto está muerto! -[KM3_11] -~g~El cártel ha sido atacado y el maletín no ha sido recuperado. - -[KM3_12] -~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. - -[KM3_13] -~g~Lleva el maletín de vuelta al casino. - -[KM3_14] -~r~¡Te han descubierto, han cancelado el trato! - -{ ================================================================ } -{ ================= MISSION: SHIMA (KENJI KASEN) ================= } -{ ================================================================ } - -{ TITLE } - -[KM4] -'SHIMA' - -{ Premission cutscene } - -{ Kenji } - [KM4_A] Para ser verdaderamente fuerte, es importante no mostrar debilidad. -[KM4_B] -El negocio es lo bastante afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. - [KM4_C] Hazte con el dinero inmediatamente para que podamos ingresarlo en las cuentas del casino. -{ Cutscene after going to Uncle BJ's Deli & Groceries } - -{ Male shop owner } - [KM4_1] ¡No puedo pagarte y no lo haría aunque pudiera! @@ -4122,46 +1828,26 @@ Hazte con el dinero inmediatamente para que podamos ingresarlo en las cuentas de [KM4_10] Además, ¿qué clase de yakuza eres tú? -{ Unused strings? } +{ Unused string? } [KM4_3] No pago a matones como vosotros para esto. Si quisiera esta clase de protección, llamaría a la policía, demonios. -[KM4_6] -¡Aquí está todo el dinero! - -{ Pager message that tells the player Donald Love's missions are available } - -[KM4_5] -Donald Love desea que te pases por su jardín de té para tener una charla. - -{ Mission instructions } - [KM4_4] ~g~¡Castiga a la banda responsable y recupera el ~b~dinero de la protección~g~! [KM4_7] ~r~¡El tendero la acaba de palmar! +[KM4_5] +Donald Love desea que te pases por su jardín de té para tener una charla. + +[KM4_6] +¡Aquí está todo el dinero! + [KM4_8] ~g~¡Maletín recolectado! -[KM4_11] -~g~¡Lleva el dinero de vuelta al casino! - -{ ===================================================================== } -{ ================= MISSION: SMACK DOWN (KENJI KASEN) ================= } -{ ===================================================================== } - -{ TITLE } - -[KM5] -'CONTRINCANTES TRAFICANTES' - -{ Premission cutscene } - -{ Kenji } - [KM5_A] ¡Tú! ¡Qué oportuno por tu parte que muestres ahora tu despreciable cara! @@ -4183,14 +1869,6 @@ Estos cerdos del cártel se están riendo de nosotros, ¡de mí! [KM5_F] ¡Arrolla a estos canallas y lava tu vergüenza en el río de la sangre de nuestros enemigos! -{ Mission instructions } - -[KM5_1] -~g~¡TRAFICANTE LIQUIDADO! - -[KM5_2] -~g~Uno de los jamaicanos se ha ido. - [KM5_3] ~r~No has matado a ~1~ jamaicanos. @@ -4200,30 +1878,1257 @@ Estos cerdos del cártel se están riendo de nosotros, ¡de mí! [KM5_5] ~g~Enhorabuena, has matado a ~1~ jamaicanos. ~1~$ ADICIONALES -[KM5_6] -~g~Debes matar a al menos 8 traficantes jamaicanos. +[RM1] +'SILENCIA AL SOPLÓN' -[KM5_7] -~g~¡Mátalos rápido! En cuanto vendan el SPANK se retirarán de las calles. +[RM3] +'FALTA DE PRUEBAS' -{ ================================================================================= } -{ ================= MISSION: BLING-BLING SCRAMBLE (KING COURTNEY) ================= } -{ ================================================================================= } +[RM4] +'DE PESCA' -{ TITLE } +[RM5] +'DESESCAYOLADOR' + +[RM1_D] +Se encuentra bajo protección armada en una propiedad de WitSec en el centro de Newport, en algún piso que hay detrás del aparcamiento. + +[RM1_E] +Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con nadie. + +[RM1_1] +~g~Ve a la casa de protección de testigos. + +[RM1_2] +~g~¡Cárgate a McAffrey! + +[RM2_A1] +¡Chico, estoy aquí! + +[RM2_A] +Un viejo colega del ejército tiene un negocio en Rockford. + +[RM2_D] +Va a necesitar respaldo y a cambio te venderá material de todo tipo a precios de ganga. + +[RM2_E] +Ray me avisó... Pero pensé que vendría más gente. + +[RM2_F] +Bueno, tres brazos son mejor que uno, así que sírvete. + +[RM2_G] +~g~¡Ve a ver a Phil! + +[RM2_H] +~r~¡Han matado a Phil! + +[RM2_L] +¡Caray! ¡Si hubieras estado a mi lado en Nicaragua, a lo mejor conservaría el brazo! + +[RM2_N] +Deja el dinero en el suelo. Ahora vete, ya me ocupo yo de la poli. + +[RM3_D] +Están transportando las pruebas por la ciudad. + +[RM3_E] +Tendrás que embestir al coche y recoger hasta la última prueba que se le caiga. + +[RM3_F] +En cuanto tengas todas, déjalas en tu coche y préndele fuego. + +[RM3_G] +Cuando acabes, nos irá mucho mejor, chico. + +[RM3_1] +~g~Deja las pruebas en un coche y después préndele fuego. + +[RM3_4] +~g~¡Al fiscal se le ha caído una prueba! + +[RM3_6] +~r~¡Las fotos circularán por toda la ciudad! + +[RM3_7] +~g~¡Ahora préndele fuego al coche! + +[RM4_A] +Creo que mi socio es un soplón. + +[RM4_C] +Casi todas las noches sale a pescar con su lancha cerca del faro que hay en Portland Rock. + +[RM4_D] +¡Roba una lancha de la policía y asegúrate de que se le acaben las ganas de dar puñaladas traperas! + +[RM4_1] +~g~Ve y roba una lancha de la policía. + +[RM4_2] +~g~¡Ve al faro y ''hunde'' al socio de Ray! + +[RM5_A] +¡Inútil de mierda! + +[RM5_A1] +¡La has cagado! Me la estoy jugando y ni siquiera eres capaz de matar a una maldita mosca. + +[RM5_B] +¡Te pagué una pasta para matar al testigo y aún sigue vivo! + +[RM5_B1] +¡Y hoy va a declarar ante los federales! + +[RM5_C] +Está a punto de ser trasladado del hospital general Carson, en Rockford. + +[RM5_D] +Si él canta, yo canto... + +[RM5_E] +¡así que termina el trabajo por el que te pagué! + +[RM5_1] +~g~Intercepta la ambulancia. + +[RM5_2] +~g~¡Te han descubierto! + +[RM5_3] +~g~¡Era un señuelo! + +[RM5_4] +~g~¡Las balas no penetran en esa escayola de cuerpo entero! + +[RM5_5] +~g~¡Esa escayola de cuerpo entero es ignífugo! + +[RM5_7] +~r~¡El testigo está a salvo! + +[RM5_8] +~g~¡El testigo se ha ahogado! + +[LOVE2] +'¡EXTERMINA AL WAKA-GASHIRA!' + +[LOVE3] +'UNA GOTA EN EL OCÉANO' + +[LOVE1_A] +Antes que nada, permíteme agradecerte que te hayas ocupado de ese asunto personal. + +[LOVE1_F] +Últimamente la gente tiende a malinterpretar las cosas. + +[LOVE1_D] +Pretenden exigirme más de lo pactado, pero no me gusta renegociar. + +[LOVE1_E] +Un trato es un trato, así que no van a ver ni un dólar mío. + +[LOVE1_G] +Rescata a mi amigo cueste lo que cueste. + +[LOVE1_2] +~g~Rescata al anciano oriental. + +[LOVE1_3] +~g~Lleva al anciano oriental de vuelta al edificio de Donald Love. + +[LOVE1_4] +~g~El anciano oriental debe estar detrás de alguna de estas puertas... + +[LOVE1_6] +~r~¡Las tripas del anciano oriental están desparramadas por las calles! + +[LOVE1_7] +~g~La puerta sólo se abrirá ante un coche de los colombianos. + +[LOVE2_A] +No hay nada como una clásica guerra de bandas para hacer que bajen los precios de las viviendas, + +[LOVE2_B] +excepto una plaga... pero eso sería excesivo en este caso. + +[LOVE2_C] +He observado que la yakuza y los colombianos no son precisamente buenos amigos. + +[LOVE2_D] +Vamos a aprovechar esta oportunidad de negocio. + +[LOVE2_E] +Quiero que mates a Kenji Kasen, el waka-gashira (segundo al mando) de la yakuza. + +[LOVE2_F] +Kenji está asistiendo a una reunión en lo alto del aparcamiento de Newport. + +[LOVE2_G] +¡Hazte con un coche de la banda del cártel y elimínalo! + +[LOVE2_H] +La yakuza debe culpar al cártel de esta declaración de guerra. + +[LOVE2_1] +~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! + +[LOVE2_2] +~g~¡Ahora ve al ~p~aparcamiento de Newport~g~ y cárgate a Kenji! + +[LOVE2_3] +~r~¡Si no llevas un coche del cártel, te descubrirán! + +[LOVE2_4] +~r~¡La yakuza te ha reconocido! + +[LOVE2_6] +~r~¡Has matado a todos los testigos! + +[LOVE3_A] +En estos días de hipocresía moral, ciertos artículos pueden resultar difíciles de importar. + +[LOVE3_C] +Echará varios paquetes al agua. + +[LOVE3_D] +Asegúrate de los consigues antes que nadie. + +[LOVE3_1] +~g~¡Consigue una ~r~lancha~g~ y sigue a la ~y~avioneta~g~! + +[LOVE4] +'ROBO DE ALTOS VUELOS' + +[LOVE5] +'SERVICIO DE ESCOLTA' + +[LOVE4_A] +Gracias por conseguir esos paquetes, pero sólo eran un señuelo. + +[LOVE4_B] +Lo siento, pero a veces los negocios son así. + +[LOVE4_C] +Mi verdadero objetivo se ocultaba en la avioneta. + +[LOVE4_F] +He sobornado a los funcionarios. + +[LOVE4_1] +~r~¡El cártel colombiano está aquí! + +[LOVE4_2] +~g~¡El paquete ha desparecido! Síguele la pista a los colombianos y recupéralo. + +[LOVE4_3] +~g~¿''Panlantic Construction''...? + +[LOVE4_5] +~g~El paquete debería estar en la avioneta... + +[LOVE4_6] +~g~¡Usa el ascensor! + +[LOVE5_B] +Mi amigo oriental necesitará que le escolten mientras comprueba la autenticidad de mi última adquisición. + +[LOVE5_1] +~g~¡En marcha! + +[LOVE5_2] +~g~¡Vas a necesitar un coche! + +[LOVE5_3] +~g~¡Comprueba la salida del túnel! + +[LOVE5_4] +~r~¡Protege el camión! + +[RM6] +'HOMBRE MUERTO' + +[RM6_A] +¿No te han seguido? Bien. + +[RM6_B] +Se acabó, ¡esto se me va de las manos y estoy con la soga al cuello! + +[RM6_D] +Soy hombre muerto, así que tengo que largarme. + +[RM6_E] +¡Consigue que no pierda mi vuelo en el aeropuerto y haré que tu trabajo haya merecido la pena! + +[RM6_666] +Cuida mi Patriot a prueba de balas. Nos vemos en Miami, Ray + +[CAT1] +'RESCATE' + +[CAT2] +'EL INTERCAMBIO' + +[CAT1_A] +Tengo a tu linda María. Si no quieres que parezca que un carnicero se ensañó con ella, + +{ UNUSED DUPLICATE } + +[CAT2_F] +Me he roto una uña y se me ha estropeado el peinado. Es increíble. ¡Me había costado cincuenta dólares! + +{ UNUSED DUPLICATE } + +[CAT2_G] +Estaba muerta de miedo, pero luego me dije a mí misma: ''Ya eres mayorcita''. + +{ UNUSED DUPLICATE } + +[CAT2_H] +Oh, nos lo vamos a pasar a lo grande, porque, ¿sabes?, mi hermana dijo que quería venirse a vivir con sus dos hijos, + +{ UNUSED DUPLICATE } + +[CAT2_I] +porque su marido a vuelto a enredar por ahí y... + +[CAT1_F] +¡Ve a donde está Catalina antes de que se acabe el tiempo! + +[CAT_MON] +~g~Todavía te falta dinero. Necesitas 500.000 dólares. + +[BITCH_D] +~g~¡María está muerta! + +[WEATHER] +FORZAR EL CLIMA + +[WEATHE2] +CLIMA NORMAL + +[8001] +¡Has fallado miserablemente! + +[1000] +HAS MUERTO + +[1001] +HAS MUERTO + +[1002] +HAS MUERTO + +[1003] +HAS MUERTO + +[1004] +HAS MUERTO + +[1005] +TRINCADO + +[1006] +TRINCADO + +[1007] +TRINCADO + +[1008] +TRINCADO + +[1009] +TRINCADO + +[GA_4] +Una bomba de coche vale 1.000 dólares. + +[GA_5] +Tu coche ya tiene una bomba instalada. + +[GA_6] +¡Apárcalo, activa el detonador pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! + +[GA_7] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. + +[GA_8] +Utiliza el detonador para activar la bomba. + +[GA_9] +Ha conseguido ~1~ de los 10 coches especiales. + +[GA_10] +Buen trabajo. Aquí tienes tus ~1~ dólares. + +[GA_11] +Ya tenemos este modelo. ¡No nos sirve para nada! + +[GA_12] +Bomba armada + +[GA_13] +Eres todo un profesional. Completa la lista y conseguirás una recompensa. + +[GA_14] +Ya están todos los coches. ¡Estupendo! Toma un detallito. + +[GA_15] +Espero que te guste el nuevo color. + +[GA_16] +Esta mano de pintura es gratuita. + +[GA_19] +No nos interesa ese modelo. + +[GA_20] +Tenemos de esos más de los que necesitamos. Lo siento, tío, no hay trato. + +[CR_1] +La grúa no puede levantar este vehículo. + +[PU_MONY] +No tienes suficiente dinero. + +[CO_ALL] +Te has hecho con todos. Toma un detallito... + +[PAUSED] +PARTIDA EN PAUSA + +[HEALTH1] +¡Largo! Estás completamente sano. + +[HEALTH2] +La sanidad cuesta dinero. + +[HEALTH3] +Te pondré como nuevo. + +[HEALTH4] +Te va a costar 250 $. + +[FEB_STA] +Estadísticas + +[FEB_BRI] +Resumen + +[FEB_CON] +Controles + +[FEB_AUD] +Sonido + +[FEB_DIS] +Pantalla + +[FEB_LAN] +Idioma + +[FEP_STA] +ESTADÍSTICAS + +[FEP_BRI] +RESUMEN + +[FEP_CON] +CONTROLES + +[FEP_AUD] +SONIDO + +[FEP_DIS] +PANTALLA + +[FEP_LAN] +IDIOMA + +[FEF_ST1] +¿Quién es el malo? + +[FEF_ST2] +Cuánta destrucción has producido + +[FEF_BR1] +¿Has perdido el hilo? + +[FEF_CO1] +¿Necesitas más control? + +[FEF_CO2] +Elige la mejor configuración del mando para tu estilo de juego + +[FEF_SA1] +¡Mantén tu sitio en el bloque! + +[FEF_SA2] +Guarda y carga tus partidas + +[FEF_AU1] +¡Dale candela al volumen! + +[FEF_AU2] +Elige una emisora de radio y un efecto de sonido + +[FEF_DI1] +¡Cambia el juego! + +[FEF_DI2] +Personaliza el juego para tu televisión + +[FEF_LA1] +¿Qué dices de los Willis? + +[FEF_LA2] +Elige tu idioma preferido + +[FEB_PMB] +Resumen de la última misión: + +[FEC_NA] +No disponible + +[FEC_CWL] +Siguiente arma + +[FEC_CWR] +Arma anterior + +[FEC_LOF] +Mirar hacia delante + +{ !!!!!!!!!!!!!!!!!! ACHTUNG! THIS STRING IS USED FOR BOTH THE MAP'S CURRENT TARGET AS WELL AS FOR THE ACTION OF TARGETING WITH A GUN! THIS WILL SCREW AROUND TRANSLATIONS !!!!!!!!!!!!!!! } +[FEC_TAR] +Objetivo + +[FEC_MOV] +Movimiento + +[FEC_CAM] +Cambiar cámara + +[FEC_PAU] +Pausa + +[FEC_ENV] +Entrar en vehículo + +[FEC_JUM] +Saltar + +[FEC_ATT] +Atacar o disparar + +[FEC_RUN] +Correr + +[FEC_FPC] +Cámara en primera persona + +[FEC_LL] +Mirar a la izquierda + +[FEC_LB1] +Mirar + +[FEC_LB2] +atrás + +[FEC_LB] +Mirar atrás + +[FEC_LR] +Mirar a la derecha + +[FEC_HOR] +Claxon + +[FEC_VES] +Controlar vehículo + +[FEC_RSC] +Cambiar emisora de radio + +[FEC_BRA] +Freno o marcha atrás + +[FEC_HAB] +Freno de mano + +[FEC_CAW] +Arma del vehículo + +[FEC_ACC] +Acelerar + +[FEC_SMT] +Activar misión especial + +[FEC_CCF] +Configuración: + +[FEC_CF1] +Ajuste1 + +[FEC_CF2] +Ajuste2 + +[FEC_CF3] +Ajuste3 + +[FEC_CF4] +Ajuste4 + +[FEC_CDP] +Controles a mostrar: + +[FEC_ONF] +A pie + +[FEC_INC] +En vehículos + +[FEC_VIB] +Vibración: + +[FEA_OUT] +Salida: + +[FEA_ST] +Estéreo + +[FEA_MNO] +Mono + +[FEA_NON] +Ninguna + +[FEA_FM0] +HEAD RADIO + +[FEA_FM1] +DOUBLE CLEF FM + +[FEA_FM2] +K-JAH RADIO + +[FEA_FM3] +RISE FM + +[FEA_FM4] +LIPS 106 + +[FEA_FM5] +GAME FM + +[FEA_FM6] +MSX FM + +[FEA_FM7] +FLASHBACK 95.6 + +[FEA_FM8] +CHATTERBOX FM + +[FED_DBG] +Menú de depuración + +[FED_RID] +Recargar IDE + +[FED_RIP] +Recargar IPL + +[FED_PAH] +Analizar pila + +[FED_RCD] +CCullZones::RecalculateCullZoneData + +[FED_DFL] +CTheScripts::DbgFlag + +[FED_DLS] +Cambiar luz blanca grande de depuración + +[FED_SPR] +Mostrar grupos de peatones en carretera + +[FED_SCR] +Mostrar grupos de vehículos en carretera + +[FED_SCZ] +Mostrar zonas de máscara selectiva + +[FED_DSR] +Solicitudes de depuración de streaming + +[FED_SCP] +gbShowCollisionPolys + +[FEM_MCM] +Menú de Memory Card + +[FEM_RMC] +Registrar MemCard uno + +[FEM_TFM] +Probar MemCard uno formateada + +[FEM_TUM] +Probar Memcard uno sin formato + +[FEM_CRD] +Crear directorio raíz + +[FEM_CLI] +Crear y cargar iconos + +[FEM_FFF] +Llenar primer archivo con basura + +[FEM_SOG] +Guardar sólo partida + +[FEM_CES] +Comprobar cada guardado de 0kB4 + +[FEM_STG] +Guardar partida + +[FEM_STS] +Guardar partida bajo el nombre GTA3 + +[FEM_CPD] +Crear copia protegida del directorio mag + +[FEM_MC2] +Menú de Memory Card 2 + +[FEM_TS] +Prueba de guardado: + +[FEM_TL] +Prueba de carga: + +[FEM_TD] +Prueba de borrado: + +[PL_STAT] +Estadísticas de jugador + +[PE_WAST] +Personas asesinadas + +[PE_WSOT] +Personas asesinadas por otros + +[CAR_EXP] +Coches reventados + +[TM_BUST] +Veces arrestado + +[M_WASTE] +Hombres civiles asesinados + +[F_WASTE] +Mujeres civiles asesinadas + +[PIG_WST] +Polis asesinados + +[GNG_WST] +Maleantes asesinados + +[MED_WST] +Médicos asesinados + +[FIRE_WS] +Bomberos asesinados + +[DED_CRI] +Criminales asesinados + +[DED_DED] +Vagabundos asesinados + +[DED_HOK] +Prostitutas asesinadas + +[HEL_DST] +Helicópteros destruidos + +[PER_COM] +Porcentaje completado + +[KGS_EXP] +Kgs de explosivos empleados + +[ACCURA] +Precisión de tiro + +[ELBURRO] +Mejor tiempo de ''Turismo'' en segundos + +[CAR_CRU] +Coches destrozados + +[HED_EX] +Cabezas explotadas + +[TM_DED] +Visitas al hospital + +[DAYSPS] +Días de juego transcurridos + +[MMRAIN] +mm de lluvia caídos + +[MXCARD] +Dist. máx. de salto acrobático (pies) + +[MXCARJ] +Altitud máx. de salto acrobático (pies) + +[MXCARDM] +Dist. máx. de salto acrobático (metros) + +[MXCARJM] +Altitud máx. de salto acrobático (metros) + +[MXFLIP] +Vueltas durante salto acrobático + +[MXJUMP] +Rotación máx. de salto acrobático + +[BSTSTU] +Mejor acrobacia hasta ahora: + +[INSTUN] +Acrobacia + +[PRINST] +Acrobacia perfecta + +[DBINST] +Acrobacia doble + +[DBPINS] +Acrobacia doble perfecta + +[TRINST] +Acrobacia triple + +[PRTRST] +Acrobacia triple perfecta + +[QUINST] +Acrobacia cuádruple + +[PQUINS] +Acrobacia cuádruple perfecta + +[NOSTUC] +No se han hecho acrobacias + +[NOUNIF] +Saltos únicos completados + +[NOUNGM] +Saltos únicos + +[NMISON] +Misiones intentadas + +[NMMISP] +Misiones superadas + +[PASDRO] +Pasajeros transportados + +[MONTAX] +Dinero conseguido en taxi + +[DAYPLC] +Gasto diario de la policía + +[CRIMRA] +Rango de criminal: + +[GMSTOR] +Almacenar partida + +[PREBRF] +Resúmenes anteriores + +[CNTLS] +Controles + +[MUSMEN] +Música/Efectos + +[GAMSET] +Ajustes del juego + +[LANGUA] +Idioma + +[DSPLAY] +Pantalla + +[DEBUGM] +Menú de depuración + +[QUITOP] +Salir de las opciones + +[CONTRL] +Configuración de controles + +[SET1EN] +Ajuste 1. Activado + +[SET1] +Ajuste 1. + +[SET2EN] +Ajuste 2. Activado + +[SET2] +Ajuste 2 + +[SET3EN] +Ajuste 3. Activado + +[SET3] +Ajuste 3 + +[SET4EN] +Ajuste 4. Activado + +[SET4] +Ajuste 4 + +[GOBACK] +Volver + +[SOUND] +SONIDO + +[MUSVOL] +Volumen de la música + +[SFXVOL] +Volumen de los efectos + +[SCROPT] +OPCIONES DE PANTALLA + +[CTRSCR] +Centrar pantalla + +[SCRFOR] +Formato de imagen + +[GMSVLQ] +GUARDAR-CARGAR-SALIR + +[GMREST] +Reiniciar partida + +[GMLOAD] +CARGAR PARTIDA + +[NOGMSV] +Sólo puedes guardar desde tu escondite. + +[DLFILE] +Borrar archivos de Grand Theft Auto III + +[CHFILE] +ELEGIR ARCHIVO A CARGAR + +[CHCDLD] +ELEGIR MEMORY CARD A USAR + +[CDUNFR] +Memory Card sin formato. + +[CHFIDL] +ELEGIR ARCHIVO A BORRAR + +[SVCONF] +CONFIRMACIÓN + +[SVFNAM] +El nombre de tu archivo guardado es + +[SAVEDN] +Error. Fallo al guardar. + +[LANGSL] +SELECCIÓN DE IDIOMA + +[ENGLIS] +Inglés + +[GERMAN] +Alemán + +[ITALIA] +Italiano + +[FRENCH] +Francés + +[SPAIN] +Español + +[RELIDE] +ReLoadIde + +[RELIPE] +ReLoadIpl + +[PARSHP] +Analizar pila + +[DBGFON] +CTheScripts::DbgFlag activado + +[DBFOFF] +CTheScripts::DbgFlag desactivado + +[BGWHON] +Luz blanca grande de depuración activada + +[BGWOFF] +Luz blanca grande de depuración desactivada + +[DSTRON] +Solicitudes de depuración de streaming activadas + +[DSTROFF] +Solicitudes de depuración de streaming desactivadas + +[PDRGON] +ShowPedRoadGroups activado + +[PRGOFF] +ShowPedRoadGroups desactivado + +[CRRGON] +ShowCarRoadGroups activado + +[CRGOFF] +ShowCarRoadGroups desactivado + +[CLZOON] +Zonas de máscara selectiva mostradas + +[CLZOOF] +Zonas de máscara selectiva ocultadas + +[SHPLON] +gbShowCollisionPolys activado + +[SHPLOF] +gbShowCollisionPolys desactivado + +[CULREC] +CCullZones::RecalculateCullZoneData() + +[FORMM1] +FormatMemCard 1 (prueba) + +[UNFRM1] +UnFormatMemCard 1 (prueba) + +[GORLEV] +Nivel de violencia + +[SICASS] +Puta locura + +[SICSIC] +Puto manicomio + +[SCASSL] +Seleccionado Puta locura + +[SCSCSL] +Seleccionado Puto manicomio + +[PRVMEN] +Resúmenes de misiones anteriores + +[DOSVGM] +¿Deseas guardar la partida? + +[FORMEN] +Menú de formato + +[MEMTST] +Pantalla MemoryCardTest + +[REGCAR] +Registrar MemoryCard uno + +[TEFONE] +Probar MemCard uno con formato + +[TEUFON] +Probar MemCard uno sin formato + +[CRROOT] +CreateRootDir + +[CRLDIC] +Crear y cargar iconos + +[FLFSGF] +Llenar el primer archivo con basura + +[PUSAVE] +Guardar sólo la partida + +[CHEVOK] +CheckEveryOkB4Save + +[SVGMON] +SaveTheGame + +[CNTSAV] +No se puede guardar la partida en una misión. + +[CNCSAV] +No se puede guardar la partida dentro de un vehículo. + +[CRMGSV] +Crear directorio de cargador con protección de copia + +[MGSVNC] +MagazineDirectory no creado + +[MGSVCN] +MagazineDirectory creado + +[YES] +Sí + +[NO] +No + +[X] +x + +[LAST] +Último mensaje + +[FEDS_XB] +Seleccionar + +[FEDS_ST] +Botón START - CONTINUAR + +[FEST_OO] +de + +[FEC_TUC] +Controlar torreta + +[FEC_SM3] +Activar misión secundaria (botón R3) + +[FEC_RS3] +Cambiar emisora de radio (botón L3) + +[FEC_HO3] +Claxon (botón L3) + +[DIAB1] +'TURISMO' + +[DIAB2] +'IRA HELADA' + +[DIAB3] +'A LA HOGUERA' + +[DIAB4] +'GRANDE Y VENOSO' + +[DIAB1_A] +El Burro quiere ofrecerte una oportunidad. Ve al teléfono público de los cerros de Hepburn si te interesa. + +[DIAB1_C] +Se te da bien correr. Pásate por el teléfono público y puede que El Burro tenga trabajo para ti. + +[DIAB1_1] +~g~3... 2... 1... ¡ADELANTE! + +[DIAB1_4] +~g~Hazte con un coche rápido y ve a la parrilla de salida. + +[DIAB1_3] +~r~No sabes ganar ni una rifa, ¡FRACASADO! + +[DIAB1_2] +~g~Felicidades, has ganado con un tiempo increíble de ~1~ segundos. + +[FIRST] +~g~1.° + +[SECOND] +~g~2.° + +[THIRD] +~g~3.° + +[FOURTH] +~g~4.° + +[DIAB2_1] +~g~Recoge el maletín en Harwood. + +[DIAB2_2] +~g~Encuentra un camión de helados. + +[DIAB2_3] +~g~Aparca el camión de helados en el muelle Atlantic. + +[DIAB2_4] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. + +[DIAB2_6] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. + +[DIAB2_7] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. + +[DIAB2_5] +~g~Sal del camión y luego usa el mando a distancia para detonarlo. [YD1] 'CORRE A POR LA PASTA' -{ Pager message that appears when the Yardies missions are available } +[YD2] +'JINETE CON UZI' + +[YD3] +'COLECCIONANDO COCHES DE BANDAS' + +[YD4] +'POR LOS AIRES' [YD_P] El Rey Courtney quiere hablarte. ¡Ve al teléfono público de Aspatria! -{ Premission cutscene } - -{ King Courtney } - [YD1_A] Habla el rey Courtney. @@ -4242,8 +3147,6 @@ El primer conductor que llegue a un punto de control se lleva mil pavos, y así [YD1_D1] Si ganas más puntos de control que los demás, podría tener trabajo para ti. -{ Mission instructions } - [YD1_E] ~g~¡Prepárate! @@ -4292,22 +3195,6 @@ Si ganas más puntos de control que los demás, podría tener trabajo para ti. [Y1_TEST] ¡COCHE AL AGUA! -[YD1_CNT] -¡~1~ de 15! - -{ ====================================================================== } -{ ================= MISSION: UZI RIDER (KING COURTNEY) ================= } -{ ====================================================================== } - -{ TITLE } - -[YD2] -'JINETE CON UZI' - -{ Premission cutscene } - -{ King Courtney } - [YD2_A] Necesito ver si eres capaz de hacer mi trabajo sucio, @@ -4320,68 +3207,39 @@ Dos de mis chicos llegarán allí enseguida para llevarte de paseo, [YD2_B1] a ver si eres quien dices que eres. -{ Dialogue from Yardie after reaching you } - [YD2_C] Vamos a dar un paseíto por los cerros de Hepburn para cargarnos a los asquerosos Diablos que han estado metiéndose con la reina Lizzy. -[YD2_D] -Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te eches atrás. - [YD2_CC] Toma, necesitarás una pipa. -{ Dialogue from Yardie after entering the car } +[YD2_D] +Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te eches atrás. [YD2_E] ¡Conduce! -{ Dialogue from Yardie when trying to get out of the car } - [YD2_F] ~r~Se quiere escapar, ¡cárgatelo! -{ Dialogue from Yardie after reaching the objective area } - [YD2_G1] Los cerros de Hepburn... Vamos a matar a algunos asquerosos Diablos... [YD2_G2] Pero recuerda, ~r~¡no salgas de este coche! -{ Dialogue from Yardie after killing the targets } - [YD2_H] ¡Vale, ya está! ¡Llévanos de vuelta a territorio jamaicano! ¡Vamos, vamos, vamos! -{ Dialogue from Yardie after taking them to the final goal } - [YD2_L] ¡Eres la Muerte personificada! -{ Dialogue from Yardie after trashing the car } - [YD2_M] ~r~¡Ha destrozado mi coche! ¡Liquídale! -{ Dialogue from Yardie when you are allowed to leave the car, but you must be in it } - [YD2_N] ¡Vuelve al coche! -{ ============================================================================= } -{ ================= MISSION: GANGCAR ROUND-UP (KING COURTNEY) ================= } -{ ============================================================================= } - -{ TITLE } - -[YD3] -'COLECCIONANDO COCHES DE BANDAS' - -{ Premission cutscene } - -{ King Courtney } - [YD3_A] Quiero que robes coches de otras bandas @@ -4406,8 +3264,6 @@ Déjalos en el garaje de Newport y recuerda, [YD3_D] UNUSED -{ Mission instructions } - [YD3_E] ~r~¡Ya has entregado un coche de los Diablos! @@ -4435,19 +3291,6 @@ UNUSED [YD3_M] ~r~¡Has volcado el vehículo! ¡Consigue otro! -{ ========================================================================= } -{ ================= MISSION: KINGDOM COME (KING COURTNEY) ================= } -{ ========================================================================= } - -{ TITLE } - -[YD4] -'POR LOS AIRES' - -{ Premission cutscene } - -{ King Courtney } - [YD4_A] ¡Escucha! @@ -4457,10 +3300,6 @@ Mueve el culo a Bedford Point. [YD4_A2] ¡Hay un cargamento en una tartana que necesito pronto! -{ Cutscene after entering the target car } - -{ Catalina, colombiana } - [YD4_B] CARTA: Dicen que estuviste entretenido. Igual que yo. @@ -4470,318 +3309,392 @@ CARTA: Dicen que estuviste entretenido. Igual que yo. [YD4_D] P.D. ¡MUERE, BASURA, MUERE! -{ Mission instructions } - [YD4_1] ~g~¡Son psicópatas adictos al SPANK! [YD4_2] ~g~¡Destruye las furgonetas de SPANK! -{ ============================================================================== } -{ ================= MISSION: SILENCE THE SNEAK (RAY MACHOWSKI) ================= } -{ ============================================================================== } +[HM_1] +'PASADA AMETRALLADA' -{ TITLE } +[HM_2] +'BOMBINATOR' -[RM1] -'SILENCIA AL SOPLÓN' +[HM_3] +'PREPARADO PARA ESTALLAR' -{ Premission cutscene } +[HM_5] +'ENFRENTAMIENTO' -{ Ray } +[HOOD1_A] +Ve al teléfono público de Wichita Gardens y hablaremos de negocios. -[RM1_A] -¡Ese canalla de McAffrey...! ¡Aceptó más sobornos que nadie, +[HM1_A] +¡Ey! ¡Soy D-Ice, de los Red Jacks! -[RM1_B] -se piensa que le darán la pensión completa si se convierte en un testigo de cargo! +[HM1_C] +Hay unos macarrillas en la calle que no piensan más que en pistolas y en SPANK. -[RM1_C] -¡Y ha cantado! +[HM1_3] +~g~Los Nines tienen su territorio en Wichita Gardens. -[RM1_D] -Se encuentra bajo protección armada en una propiedad de WitSec en el centro de Newport, en algún piso que hay detrás del aparcamiento. +[HM2_3] +¡Si golpeas las ruedas de un vehículo, el coche teledirigido estallará! -[RM1_E] -Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con nadie. +[HM2_4] +¡Si el coche teledirigido se sale fuera de cobertura, estallará solo! -{ Mission instructions } +[HM2_5] +~r~¡Te has ido de cobertura! -[RM1_1] -~g~Ve a la casa de protección de testigos. +[HM3_1] +~g~¡Ve al garaje, pero pon atención, porque el coche explotará si se daña demasiado! -[RM1_2] -~g~¡Cárgate a McAffrey! +[HM3_2] +~g~Lleva el coche de vuelta. ¡Tiene que estar inmaculado! -[RM1_3] -~r~¡McAffrey se ha escapado! +[HM3_3] +~g~¡Haz que reparen el vehículo! -[RM1_4] -~g~¡Has usado todas las granadas! ¡Consigue más en la tienda Ammu-Nation! +[HM4_D] +~g~¡Hazte con un vehículo! -[RM1_5] -~g~¡Vuelve y quema la casa franca! +[HM4_1] +~g~Dirígete al lugar donde está el cargamento. Necesitas conseguir 30 lingotes. -{ ========================================================================== } -{ ================= MISSION: ARMS SHORTAGE (RAY MACHOWSKI) ================= } -{ ========================================================================== } +[HM4_2] +~g~Recuerda: cuando el vehículo esté pesado y vaya más despacio, ve al garaje y deja el cargamento. -{ TITLE } +[HM5_3] +~r~¡Te han dicho que uses sólo un bate de béisbol! -[RM2] -'ESCASEZ DE MANOS' +[HM5_4] +~r~¡Tu contacto está muerto! -{ Premission cutscene } +[MEA1] +'EL CRIMINAL' -{ Ray } +[MEA2] +'LOS LADRONES' -[RM2_A1] -¡Chico, estoy aquí! +[MEA3] +'LA MUJER' -[RM2_A] -Un viejo colega del ejército tiene un negocio en Rockford. +[MEA4] +'SU AMANTE' -[RM2_B] -Combatimos juntos en Nicaragua, cuando el país sabía lo que hacía. +[MEAT1_A] +Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléfono público de Trenton si crees que puedes ayudar. -[RM2_C] -En fin, ayer unos cerdos del cártel lo zurraron y le dijeron que volverían hoy para quitarle parte de su stock. +[MEA1_B3] +~g~Reúnete con el director del banco. -[RM2_D] -Va a necesitar respaldo y a cambio te venderá material de todo tipo a precios de ganga. +[MEA1_B6] +~g~Lleva el coche a la trituradora para eliminar las pruebas, allí sal del coche y la grúa lo recogerá. -[RM2_D1] -Iría yo mismo, pero la ciática ya está en sus trece... ¡Cof, cof! Así que... buena suerte. +[MEA1_1] +~r~¡El director del banco está muerto! -{ Cutscene, appears when finding Phil } +[MEA1_2] +~r~¡Te dijeron que trituraras el coche! -{ Phil } +[MEA1_3] +~g~¡Sal del coche! -[RM2_E] -Ray me avisó... Pero pensé que vendría más gente. +[MEA1_4] +~r~¡Has abandonado al director del banco! -[RM2_E1] -¡No puedo creer que esos mamones amarillos me hayan vuelto a dejar con el culo al aire! +[MEA2_B3] +~g~Reúnete con los ladrones. -[RM2_F] -Bueno, tres brazos son mejor que uno, así que sírvete. +[MEA2_B4] +~g~Llévalos a la fábrica de comestibles Bitch'n' Dog. -[RM2_F1] -¡Los colombianos llegarán en cualquier momento! +[MEA2_B6] +~g~Haz que repinten el coche para borrar las pruebas. -{ Dialogue from Phil, when the Colombians arrive } +[MEA2_1] +~r~¡Te dijeron que trituraras el vehículo! -[RM2_K] -Maldita sea, ¡están aquí! ¡FUEGO A DISCRECIÓN! +[MEA2_2] +~r~¡Un ladrón ha muerto! -{ Dialogue from Phil, when the Colombians are killed } +[MEA2_4] +~r~¡Has dejado atrás a un ladrón! -[RM2_L] -¡Caray! ¡Si hubieras estado a mi lado en Nicaragua, a lo mejor conservaría el brazo! +[MEA3_B3] +~g~Recoge a la Sra. Chonks. -[RM2_M] -Si necesitas armas nuevas, pasa por aquí y coge lo que necesites de las taquillas. +[MEA3_B6] +~g~Llévate el coche y tíralo al mar, así eliminaremos las pruebas. -[RM2_N] -Deja el dinero en el suelo. Ahora vete, ya me ocupo yo de la poli. +[MEA3_1] +~r~¡La mujer está muerta! -{ Mission instructions } +[MEA3_2] +~r~¡Se suponía que debías tirar el coche al agua! -[RM2_G] -~g~¡Ve a ver a Phil! +[MEA3_3] +~r~¡Has dejado atrás a su mujer! -[RM2_H] -~r~¡Han matado a Phil! +[MEA4_B3] +~g~Recoge al amante de su mujer. -{ ========================================================================== } -{ ================= MISSION: EVIDENCE DASH (RAY MACHOWSKI) ================= } -{ ========================================================================== } +[MEA4_B6] +Ya es muy tarde, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé de tu negocio... -{ TITLE } +[MEA4_1] +~r~¡Carlos está muerto! -[RM3] -'FALTA DE PRUEBAS' +[MEA4_3] +~r~¡Has abandonado a Carlos, el usurero! -{ Premission cutscene } +[LOOK_A] +Pulsa y mantén pulsado el ~h~botón ~k~~VEHICLE_LOOKLEFT~~w~ o el ~h~botón ~k~~VEHICLE_LOOKRIGHT~~w~ para mirar~h~ a la izquierda~w~ o ~h~a la derecha ~w~mientras te encuentres en un vehículo. Pulsa ambos para mirar~h~ atrás~w~. -{ Ray } +[LOVE6_1] +~g~¡Ahora llévate a los policías lejos del almacén! -[RM3_A] -Conozco a un pez gordo de la ciudad, un tipo muy cándido, - -[RM3_H] -con, digamos... gustos exóticos y el dinero para pagárselos. - -[RM3_B] -Está involucrado en un asunto legal y la fiscalía tiene fotos de él muy comprometedoras - -[RM3_C] -en una fiesta en la morgue o algo así. - -[RM3_D] -Están transportando las pruebas por la ciudad. - -[RM3_E] -Tendrás que embestir al coche y recoger hasta la última prueba que se le caiga. - -[RM3_F] -En cuanto tengas todas, déjalas en tu coche y préndele fuego. - -[RM3_G] -Cuando acabes, nos irá mucho mejor, chico. - -{ Mission instructions } - -[RM3_1] -~g~Deja las pruebas en un coche y después préndele fuego. - -[RM3_4] -~g~¡Al fiscal se le ha caído una prueba! - -[RM3_5] -~g~Tienes ~1~ de 6 paquetes de pruebas. - -[RM3_6] -~r~¡Las fotos circularán por toda la ciudad! - -[RM3_7] -~g~¡Ahora préndele fuego al coche! - -[RM3_8] -~r~¡El coche es un señuelo! - -{ ========================================================================= } -{ ================= MISSION: GONE FISHING (RAY MACHOWSKI) ================= } -{ ========================================================================= } - -{ TITLE } - -[RM4] -'DE PESCA' - -{ Premission cutscene } - -{ Ray } - -[RM4_A] -Creo que mi socio es un soplón. - -[RM4_B] -Tenemos que cerrarle la boca para siempre. - -[RM4_C] -Casi todas las noches sale a pescar con su lancha cerca del faro que hay en Portland Rock. - -[RM4_D] -¡Roba una lancha de la policía y asegúrate de que se le acaben las ganas de dar puñaladas traperas! - -[RM4_E] -¡Quiero que se vaya a dormir con los peces, en vez de comérselos! - -{ Mission instructions } - -[RM4_1] -~g~Ve y roba una lancha de la policía. - -[RM4_2] -~g~¡Ve al faro y ''hunde'' al socio de Ray! +[LOVE6_2] +~r~¡No has distraído a la policía! [RM4_3] ~r~¡El socio de Ray ha escapado! -{ ============================================================================ } -{ ================= MISSION: PLASTER BLASTER (RAY MACHOWSKI) ================= } -{ ============================================================================ } - -{ TITLE } - -[RM5] -'DESESCAYOLADOR' - -{ Premission cutscene } - -{ Ray } - -[RM5_A] -¡Inútil de mierda! - -[RM5_A1] -¡La has cagado! Me la estoy jugando y ni siquiera eres capaz de matar a una maldita mosca. - -[RM5_B] -¡Te pagué una pasta para matar al testigo y aún sigue vivo! - -[RM5_B1] -¡Y hoy va a declarar ante los federales! - -[RM5_C] -Está a punto de ser trasladado del hospital general Carson, en Rockford. - -[RM5_D] -Si él canta, yo canto... - -[RM5_E] -¡así que termina el trabajo por el que te pagué! - -{ Mission instructions } - -[RM5_1] -~g~Intercepta la ambulancia. - -[RM5_2] -~g~¡Te han descubierto! - -[RM5_3] -~g~¡Era un señuelo! - -[RM5_4] -~g~¡Las balas no penetran en esa escayola de cuerpo entero! - -[RM5_5] -~g~¡Esa escayola de cuerpo entero es ignífugo! - -[RM5_6] -~g~¡Ha salido de la ambulancia! ¡Cárgate su escayola con un vehículo o una explosión! - -[RM5_7] -~r~¡El testigo está a salvo! - -[RM5_8] -~g~¡El testigo se ha ahogado! - -{ ======================================================================= } -{ ================= MISSION: MARKED MAN (RAY MACHOWSKI) ================= } -{ ======================================================================= } - -{ TITLE } - -[RM6] -'HOMBRE MUERTO' - -{ Premission cutscene } - -{ Ray } - -[RM6_A] -¿No te han seguido? Bien. - -[RM6_B] -Se acabó, ¡esto se me va de las manos y estoy con la soga al cuello! - [RM6_C] La CIA parece estar interesada en el SPANK [RM6_C1] y no les gusta que nos metamos con el cártel. -[RM6_D] -Soy hombre muerto, así que tengo que largarme. +[C_PASS] +¡AMENAZA ELIMINADA! -[RM6_E] -¡Consigue que no pierda mi vuelo en el aeropuerto y haré que tu trabajo haya merecido la pena! +[CTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. -{ Cutscene, appears when Ray has been taken safely to the airport } +[CTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. + +[COPCART] +~g~Tienes ~1~ segundos para volver a un vehículo de la policía antes de que termine la misión. + +[C_FAIL] +¡Misión de justiciero terminada! + +[C_CANC] +~r~¡Misión de justiciero cancelada! + +[C_ESCP] +~r~¡El sospechoso ha escapado! + +[C_TIME] +~r~¡Tu trabajo como defensor de la ley ha terminado! + +[C_VIGIL] +¡PREMIO POR JUSTICIERO! + +[A_FAIL2] +~r~¡Tu falta de rapidez ha sido fatal para el paciente! + +[A_FAIL3] +~r~¡El paciente está muerto! + +[A_PASS] +¡Rescatado! + +[F_FAIL2] +~r~¡Llegas demasiado tarde! + +[A_COMP2] +¡Nunca te cansarás! + +[RM2_M] +Si necesitas armas nuevas, pasa por aquí y coge lo que necesites de las taquillas. + +[HEAL_A] +Tu ~h~salud ~w~está indicada en naranja en la parte superior derecha de la pantalla. + +[YD1_CNT] +¡~1~ de 15! + +[FM1_9] +~g~La fiesta es allí. Deja a María enfrente. + +[FM1_Y] +Quiero que sepas que me lo he pasado muy bien por primera vez en mucho tiempo y que me has tratado muy bien, con respeto. + +[FM1_AA] +Bueno, será mejor que me vaya. Espero que nos veamos pronto. + +[NOCONTE] +Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. + +[WRCONT] +El mando conectado al puerto de mando 1 es un mando no compatible. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). + +[WRCONTE] +El mando conectado al puerto de mando 1 es un mando no compatible. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). + +[WRONGCD] +Disco incorrecto. Introduce el disco correcto. + +[NOCD] +La bandeja del disco está vacía. Introduce un disco. + +[OPENCD] +La bandeja del disco está abierta. Cierra la bandeja de disco. + +[CDERROR] +Error al leer el DVD de Grand Theft Auto III + +[RESTART] +Empezando una nueva partida + +[GA_3] +¡Ya no es gratis! ¡La mano de pintura son 1.000 dólares! + +[GA_1] +¡Hala! ¡Demasiado peligroso para mi gusto! + +[GA_1A] +Vuelve cuando no estés tan ocupado... + +[S_PROM2] +Puedes alojar un vehículo en el garaje de al lado al guardar tu partida. + +[STOCK] +mercancía agotada + +[FM1_O] +Creo que está en la estación de ferrocarril del muelle de Chinatown. + +[EBAL_B] +Es aquí, ¡entremos y cambiémonos de ropa! + +[EBAL_G] +Este es el club de Luigi. Vamos a la parte de atrás, a la puerta de servicio. + +[AM4_3] +¡Tú debes de ser el nuevo chico de los recados de Asuka! + +[AM4_4] +¿Tienes el dinero? ¿Está todo? + +[AM4_5] +Ya sé lo que estás pensando, otro policía corrupto. + +[AM4_6] +Bueno, éste es un mundo corrupto. + +[AM4_7] +Pierdo a un par de socios y esos idiotas de asuntos internos empiezan a meter las narices. + +[AM4_8] +¡Y seguro que les llega mi olor! + +[AM4_9] +¡Pues esta ciudad es una gran alcantarilla! + +[AM4_10] +Pero voy a necesitar un ayudita ajena al cuerpo. + +[AM4_11] +Si estás interesado, ya sabes dónde encontrarme. + +[CAM_A] +Pulsa el ~h~botón ~k~~CAMERA_CHANGE_VIEW_ALL_SITUATIONS~~w~ para cambiar la ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. + +[CAM_B] +Pulsa el ~h~botón de dirección hacia arriba ~w~y ~h~abajo ~w~para cambiar los modos de ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. + +[KM2_1] +~g~Repara el coche, tiene que estar en perfecto estado. + +[LM3_6] +¡Joey...! + +[LM3_6A] +¿Voy a jugar con tu paquetín otra vez? + +[LM3_9A] +que tendré trabajo para ti. + +[LM3_9B] +¿De acuerdo? + +[AWAY2] +~r~Se ha escapado. + +[AWAY] +~r~¡Se ha pirado de aquí! + +[JM6_1] +Llévanos al banco de la avenida principal. + +[GA_6B] +¡Apárcalo, activa el detonador pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! + +[GA_7B] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. + +[BAT1] +~g~¡Coge el bate! + +[EBAL_O] +Si no la cagas, puede que haya más trabajo para ti. ¡Ahora largo! + +[HELP9_B] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. + +[HELP9_C] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. + +[JM6_8] +~r~¡Has perdido a todos los ladrones! + +[COLT_IN] +¡La pistola ya está disponible en la tienda Ammu-Nation! + +[TAXI2] +~r~¡Se te acabó el tiempo! + +[TAXI3] +~r~¡Tu cliente ha salido por patas! + +[TAXI7] +~r~Tu coche está destrozado, haz que lo reparen. + +[TAXI4] +¡Carrera terminada! + +[TAXI5] +¡VIAJE RÁPIDO! + +[TAXI6] +Misión de taxi terminada + +[FRANGO] +~g~¡Salvatore quiere que ayudes primero a Toni a ocuparse de las Tríadas! + +[PAGEB12] +Soborno policial ya disponible en tu guarida. + +[PAGEB13] +Salud ya disponible en tu guarida. + +[PAGEB14] +Adrenalina ya disponible en tu guarida. + +[KM1_4] +~g~¡Necesitas un coche de policía para hacer el trabajo! + +[CAT1_B] +lleva 500.000 dólares a la mansión de Cedar Grove. + +[JM2_C] +Tiene un puesto de fideos en Chinatown. [RM6_1] Esta llave es de un almacén. @@ -4792,488 +3705,752 @@ Encontrarás dinero en metálico y ''suministros'' que guardé por si las cosas [RM6_3] Hasta la vista. -{ Pager message that appears when reaching Ray's lockup } +[FE_INIP] +Iniciando y cargando el menú de pausa... Espera, por favor. -[RM6_666] -Cuida mi Patriot a prueba de balas. Nos vemos en Miami, Ray +[FESZ_CA] +Cancelar -{ Mission instructions } +[FESZ_QU] +Abandonar -[RM6_4] -~g~Ve al almacén a por el cargamento de Ray. +[FESZ_L1] +¡La partida se ha guardado! -[RM6_5] -~g~La CIA vigila el puente, busca otro camino. +[FESZ_L2] +El nombre guardado es: -[RM6_6] -~r~¡Ray ha muerto! +[FESZ_OK] +ACEPTAR -[RM6_7] -~r~¡Ray ha perdido su avión! +[FES_NGA] +Nueva partida -[RM6_8] -~g~Has abandonado a Ray, vuelve a por él. +[FES_CAN] +Cancelar -{ ==================================================================== } -{ ================= MISSION: LIBERATOR (DONALD LOVE) ================= } -{ ==================================================================== } +[FESZ_QL] +Perderás todo el progreso en tu partida actual. ¿Quieres continuar con la carga? -{ TITLE } +[FESZ_QD] +¿Quieres borrar esta partida guardada? -[LOVE1] -'EL LIBERADOR' +[FESZ_QO] +¿Quieres sobreescribir esta partida guardada? -{ Premission cutscene } +[FESZ_QR] +¿Seguro que quieres empezar una nueva partida? Perderás todo el progreso desde la última partida guardada. -{ Donald Love } +[FESZ_QS] +¿QUIERES GUARDAR? -[LOVE1_A] -Antes que nada, permíteme agradecerte que te hayas ocupado de ese asunto personal. +[SLONFP] +Puerto 1. Archivo protegido. -[LOVE1_F] -Últimamente la gente tiende a malinterpretar las cosas. +[T4X4_1] +'PATIO DE RECREO' -[LOVE1_B] -La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, +[T4X4_2] +'UN PASEO POR EL PARQUE' -[LOVE1_H] -pero los grupos de hombres se vuelven codiciosos. +[T4X4_3] +'¡AGARRADO!' -[LOVE1_C] -Un activo valioso, un anciano oriental que conozco, +[MM_1] +'CAOS EN EL APARCAMIENTO' -[LOVE1_I] -está siendo retenido por unos sudamericanos en Aspatria. +[T4X4_1A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~15~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -[LOVE1_D] -Pretenden exigirme más de lo pactado, pero no me gusta renegociar. +[T4X4_1B] +¡~1~ de 15! -[LOVE1_E] -Un trato es un trato, así que no van a ver ni un dólar mío. +[T4X4_1C] +~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~20 SEGUNDOS~g~ adicionales. -[LOVE1_G] -Rescata a mi amigo cueste lo que cueste. +[T4X4_2A] +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~12~g~ puntos de control! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -{ Mission instructions } +[T4X4_2B] +¡~1~ de 12! -[LOVE1_1] -~g~Roba un coche de la banda colombiana para que puedas entrar en su escondite. Dirígete hacia el norte; podrás encontrar uno en Fort Staunton. +[T4X4_2C] +~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~10 SEGUNDOS~g~ adicionales. -[LOVE1_2] -~g~Rescata al anciano oriental. +[T4X4_3A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~20~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -[LOVE1_3] -~g~Lleva al anciano oriental de vuelta al edificio de Donald Love. +[T4X4_3B] +~Y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~15 SEGUNDOS~g~ adicionales. -[LOVE1_4] -~g~El anciano oriental debe estar detrás de alguna de estas puertas... +[T4X4_3C] +¡~1~ de 20! -[LOVE1_5] -~g~Deja de perder el tiempo, hazte con un coche de los colombianos y rescata al socio de Love. +[T4X4_F] +~r~¡Te has escapado! ¿Demasiado difícil para ti? -[LOVE1_6] -~r~¡Las tripas del anciano oriental están desparramadas por las calles! +[MM_1_A] +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~20 puntos de control~g~ en el aparcamiento! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -[LOVE1_7] -~g~La puerta sólo se abrirá ante un coche de los colombianos. +[MM_1_B] +¡~1~ de 20! -{ =============================================================================== } -{ ================= MISSION: WAKA-GASHIRA WIPEOUT (DONALD LOVE) ================= } -{ =============================================================================== } +[MM_1_C] +~g~Tendrás 20 segundos, más ~y~5 SEGUNDOS~g~ por cada punto de control. ~g~El cronómetro comenzará ~y~INMEDIATAMENTE. -{ TITLE } +[FM2_14] +~r~¡Te acercaste demasiado y asustaste a Curly! -[LOVE2] -'¡EXTERMINA AL WAKA-GASHIRA!' +[FM2_15] +~g~No te acerques mucho, ¡o Curly sospechará! -{ Premission cutscene } +[UPSIDE] +~r~¡Has volcado! -{ Donald Love } +[FM2_16] +ASUSTÓMETRO: -[LOVE2_A] -No hay nada como una clásica guerra de bandas para hacer que bajen los precios de las viviendas, +[LM3_11] +~g~Misty no irá en un autobús, ¡hazte con otro vehículo! -[LOVE2_B] -excepto una plaga... pero eso sería excesivo en este caso. +[LANDSTK] +Landstalker -[LOVE2_C] -He observado que la yakuza y los colombianos no son precisamente buenos amigos. +[IDAHO] +Idaho -[LOVE2_D] -Vamos a aprovechar esta oportunidad de negocio. +[STINGER] +Stinger -[LOVE2_E] -Quiero que mates a Kenji Kasen, el waka-gashira (segundo al mando) de la yakuza. +[LINERUN] +Linerunner -[LOVE2_F] -Kenji está asistiendo a una reunión en lo alto del aparcamiento de Newport. +[PEREN] +Perennial -[LOVE2_G] -¡Hazte con un coche de la banda del cártel y elimínalo! +[SENTINL] +Sentinel -[LOVE2_H] -La yakuza debe culpar al cártel de esta declaración de guerra. +[PATRIOT] +Patriot -{ Mission instructions } +[FIRETRK] +Camión de bomberos -[LOVE2_1] -~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! +[TRASHM] +Trashmaster -[LOVE2_2] -~g~¡Ahora ve al ~p~aparcamiento de Newport~g~ y cárgate a Kenji! +[STRETCH] +Stretch -[LOVE2_3] -~r~¡Si no llevas un coche del cártel, te descubrirán! +[MANANA] +Mañana -[LOVE2_4] -~r~¡La yakuza te ha reconocido! +[INFERNS] +Infernus -[LOVE2_5] -~g~¡Kenji ha palmado! ¡Sal de Newport y deshazte del coche! +[BLISTA] +Blista -[LOVE2_6] -~r~¡Has matado a todos los testigos! +[PONY] +Pony -[LOVE2_7] -~g~¡Ahora deshazte del coche! +[MULE] +Mule -[LOVE2_8] -~g~¡Sal de Newport! +[CHEETAH] +Cheetah -{ ============================================================================== } -{ ================= MISSION: A DROP IN THE OCEAN (DONALD LOVE) ================= } -{ ============================================================================== } +[AMBULAN] +Ambulancia -{ TITLE } +[FBICAR] +Coche del FBI -[LOVE3] -'UNA GOTA EN EL OCÉANO' +[MOONBM] +Moonbeam -{ Premission cutscene } +[ESPERAN] +Esperanto -{ Donald Love } +[TAXI] +Taxi -[LOVE3_A] -En estos días de hipocresía moral, ciertos artículos pueden resultar difíciles de importar. +[KURUMA] +Kuruma -[LOVE3_B] -Esta noche, durante su aproximación al aeropuerto, una avioneta sobrevolará la bahía. +[BOBCAT] +Bobcat -[LOVE3_C] -Echará varios paquetes al agua. +[WHOOPEE] +Mr. Whoopee -[LOVE3_D] -Asegúrate de los consigues antes que nadie. +[BFINJC] +BF Injection -{ Mission instructions } +[POLICAR] +Coche patrulla -[LOVE3_1] -~g~¡Consigue una ~r~lancha~g~ y sigue a la ~y~avioneta~g~! +[ENFORCR] +Enforcer -[LOVE3_2] -~g~¡Tienes todos los paquetes! Llévaselos a Donald Love. +[SECURI] +Securicar -[LOVE3_3] -~g~La avioneta ha tirado ~1~ de los 6 paquetes. +[BANSHEE] +Banshee -[LOVE3_4] -~r~¡Has destruido el avión! +[PREDATR] +Predator -[LOVE3_5] -~g~La avioneta está ahora a tu alcance. +[BUS] +Autobús -[LOVE3_6] -~r~¡La bofia ha llegado a los paquetes antes que tú! +[RHINO] +Rhino -{ =========================================================================== } -{ ================= MISSION: GRAND THEFT AERO (DONALD LOVE) ================= } -{ =========================================================================== } +[BARRCKS] +Barracks OL -{ TITLE } +[TRAIN] +Tren -[LOVE4] -'ROBO DE ALTOS VUELOS' +[HELI] +Helicóptero -{ Premission cutscene } +[DODO] +Dodo -{ Donald Love } +[COACH] +Coach -[LOVE4_A] -Gracias por conseguir esos paquetes, pero sólo eran un señuelo. +[CABBIE] +Cabbie -[LOVE4_B] -Lo siento, pero a veces los negocios son así. +[STALION] +Stallion -[LOVE4_C] -Mi verdadero objetivo se ocultaba en la avioneta. +[RUMPO] +Rumpo -[LOVE4_D] -Desgraciadamente, las autoridades aduaneras registraron la avioneta y la comenzaron a desmontar +[RCBANDT] +Bandit RC -[LOVE4_H] -hasta que yo intervine a través de mi fortuna. +[BELLYUP] +Furgoneta de las Tríadas -[LOVE4_E] -Cruza el puente hacia Shoreside Vale y ve al Aeropuerto Internacional Francis. +[MRWONGS] +Mr Wongs -[LOVE4_F] -He sobornado a los funcionarios. +[MAFIACR] +Sentinel de la mafia -[LOVE4_G] -Mis pertenencias estarán esperándote en el hangar de aduanas, dentro de la avioneta. +[YARDICR] +Lobo jamaicano -{ Cutscene, when going up into the construction area's elevator, finding Catalina, Miguel and Asuka } +[YAKUZCR] +Stinger de la yakuza -{ Catalina, colombiana } +[DIABLCR] +Stallion de los Diablos -[GTAB_A] -Oye, saquemos esto de aquí. Dios sabrá lo que será, +[COLOMCR] +Cruiser del cártel -[GTAB_B] -pero él lo quiere a toda costa, así que tendrá algún valor. +[HOODSCR] +Rumpo XL de los hood -{ Miguel, colombiano } +[AEROPL] +Avioneta -[GTAB_C] -¡¿Qué diablos?! +[SPEEDER] +Speeder -{ Catalina, colombiana } +[REEFER] +Reefer -[GTAB_D] -¡TÚ! +[PANLANT] +Panlantic -{ Miguel, colombiano } +[FLATBED] +Flatbed -[GTAB_E] -¡Tranquilo, amigo! ¡No es nada! ¡No es nada! +[YANKEE] +Yankee -{ Catalina, colombiana } +[BORGNIN] +Borgnine -[GTAB_F] -¡Te dejé desangrándote entre la basura! +[TOYZ] +TOYZ -{ Miguel, colombiano } +[FEST_DF] +Distancia recorrida a pie (millas) -[GTAB_G] -No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. +[FEST_DC] +Distancia recorrida en coche (millas) -{ Catalina, colombiana } +[FESTDFM] +Distancia recorrida a pie (metros) -[GTAB_H] -¡No seas cagón! +[FESTDCM] +Distancia recorrida en coche (metros) -{ Miguel, colombiano } +[FEST_R1] +''Patio de recreo'' en segundos -[GTAB_I] -¡No tenemos elección, nena! +[FEST_R2] +''Un paseo por el parque'' en segundos -{ Catalina, colombiana } +[FEST_R3] +''¡Agarrado!'' en segundos -[GTAB_J] -¡Siempre la hay, imbécil! +[FEST_RM] +''Caos en el aparcamiento'' en segundos -{ Miguel, colombiano } +[FEST_LS] +Gente salvada con una ambulancia -[GTAB_K] -¡Siento mucho lo de esa perra enloquecida, todas son iguales... ¿Por favor? +[FEST_CC] +Criminales asesinados en misiones de justiciero -{ Asuka } +[FEST_FE] +Incendios extinguidos -[GTAB_L] -Así que la zorra se fue. +[FEST_LF] +Vuelo más largo en Dodo -[GTAB_M] -Pero me has hecho un favor, +[FEST_BD] +Mejor tiempo al desactivar la bomba -[GTAB_N] -no eres el único que tiene una cuenta pendiente con el cártel... +[FEST_RP] +Masacres superadas -[GTAB_O] -¡Este gusano mató a mi hermano! +[FEST_MP] +Misiones superadas -{ Miguel, colombiano } +[FEST_BB] +Carrera forrada: -[GTAB_P] -¡Nunca maté a ningún yakuza! +[FEST_H0] +Máximo de puntos de control -{ Asuka } +[FEST_GC] +Coches de bandas destruidos: -[GTAB_Q] -¡Mientes! Todos vimos al asesino del cártel. +[FEST_H1] +Destrucción de los Diablos -[GTAB_R] -¡Vamos a cazaros y a mataros a todos, perros colombianos! +[FEST_H2] +La masacre de la mafia -[GTAB_S] -Me trabajaré a nuestro querido amigo para extraerle información y un poco de placer. +[FEST_H3] +Calamidad en el casino -[GTAB_T] -Tú, ven más tarde, estoy segura de que voy a necesitar tus servicios. +[FEST_H4] +Exterminio de Rumpos -{ Miguel, colombiano } +[USJ] +¡PREMIO POR ACROBACIA ÚNICA! -[GTAB_U] -¡Por favor, amigo! ¡No me dejes con ella, esa chica está loca! ¿Amigo? ¡Oye, amigo! ¡Amigo...! +[SPRAY] +Mete tu vehículo en el taller de pintura para perder tu ~h~nivel de búsqueda~w~, ~h~reparar~w~ y~h~ repintar~w~ tu vehículo. Coste: ~h~1.000 dólares -{ Mission instructions } +[HM1_1] +~g~Cepíllate a 20 Purple Nines en 2 minutos y 30 segundos. -[LOVE4_1] -~r~¡El cártel colombiano está aquí! +[KM1_8A] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. -[LOVE4_2] -~g~¡El paquete ha desparecido! Síguele la pista a los colombianos y recupéralo. +[KM1_8D] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. -[LOVE4_3] -~g~¿''Panlantic Construction''...? +[KM1_12] +~g~¡Llévalo al dojo, pero deshazte primero de la policía! -[LOVE4_7] -~g~Hay una zona en obras en Staunton Island, puede que hayan llevado el paquete allí. +[RATNG1] +Carterista -[LOVE4_4] -~g~¡Lleva el paquete a Donald Love! +[RATNG2] +Abusón -[LOVE4_5] -~g~El paquete debería estar en la avioneta... +[RATNG3] +Chorizo -[LOVE4_6] -~g~¡Usa el ascensor! +[RATNG4] +Granuja -[LOVE4_8] -~g~Necesitarás un coche para abrir el garaje. +[RATNG5] +Secuaz -[LOVE4_9] -~r~¡El avión ha sido destruido! +[RATNG6] +Conductor -[LOV4_10] -~r~¡La única pista sobre dónde se encuentra el paquete ha sido destruida! +[RATNG7] +Guardaespaldas -{ ========================================================================= } -{ ================= MISSION: ESCORT SERVICE (DONALD LOVE) ================= } -{ ========================================================================= } +[RATNG8] +Negociador -{ TITLE } +[RATNG9] +Socio -[LOVE5] -'SERVICIO DE ESCOLTA' +[RATNG10] +Sicario -{ Premission cutscene } +[RATNG11] +Asesino -{ Donald Love } +[RATNG12] +Mano derecha -[LOVE5_A] -Estás demostrando ser una inversión segura, algo muy raro en estos días. +[RATNG13] +Verdugo -[LOVE5_B] -Mi amigo oriental necesitará que le escolten mientras comprueba la autenticidad de mi última adquisición. +[RATNG14] +Capo -[LOVE5_C] -Quiero que le sigas, asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. +[RATNG15] +Jefe -{ Mission instructions } +[1010] +~r~Tu vehículo ha volcado -[LOVE5_1] -~g~¡En marcha! +[1011] +~r~Tu vehículo ha volcado -[LOVE5_2] -~g~¡Vas a necesitar un coche! +[1012] +~r~Tu vehículo ha volcado -[LOVE5_3] -~g~¡Comprueba la salida del túnel! +[1013] +~r~Tu vehículo ha volcado -[LOVE5_4] -~r~¡Protege el camión! +[1014] +~r~Tu vehículo ha volcado -[LOVE5_5] -~r~¡No has protegido al camión! +[JM4_10] +Vale, chaval, llévame primero a la lavandería de Chinatown, tengo un asunto del que ocuparme. -{ ================================================================ } -{ ================= MISSION: DECOY (DONALD LOVE) ================= } -{ ================================================================ } +[JM4_11] +Las lavanderas no están pagando por su protección. -{ TITLE } +[JM4_12] +Y ojo con el coche, Joey acaba de arreglar esta chatarra. -[LOVE6] -'SEÑUELO' +[JM4_13] +Así que con cuidado, ¿vale? -{ Premission cutscene } +[KM4_11] +~g~¡Lleva el dinero de vuelta al casino! -{ Donald Love } +[FEF_BR2] +Encuéntralo de nuevo leyendo los resúmenes de las misiones jugadas hasta la fecha. -[LOVE6_A] -Una lección sobre negocios, amigo mío: +[TRAIN_1] +Estación Kurowski -[LOVE6_E] -Si tienes una mercancía única, todo el mundo tratará de arrebatártela, +[TRAIN_2] +Estación Rothwell -[LOVE6_B] -aun sin conocer su verdadera valía. +[TRAIN_3] +Estación Baillie -[LOVE6_C] -Unos SWAT han acordonado la zona donde se encuentran mi socio y el paquete. +[SUBWAY1] +Estación Portland -[LOVE6_D] -Ve allí, recoge la furgoneta y haz de señuelo. +[SUBWAY2] +Estación Rockford -[LOVE6_F] -Mantenles ocupados y él podrá escaparse. +[SUBWAY3] +Estación Staunton sur -{ Mission instructions } +[SUBWAY4] +Terminal Shoreside -[LOVE6_1] -~g~¡Ahora llévate a los policías lejos del almacén! +[MEA4_2] +~r~¡Marty Chonks ha muerto! -[LOVE6_2] -~r~¡No has distraído a la policía! +[SPRAY1] +Mete tu vehículo en el taller de pintura para perder tu ~h~nivel de búsqueda~w~, ~h~reparar~w~ y~h~ repintar~w~ tu vehículo. Coste: ~h~1.000 dólares~w~. Esta vez es gratis. -[LOVE6_3] -~g~Tienes ~1~ segundos para volver al Securicar antes de fracasar la misión. +[JM4_A] +Sí, Toni, ya está a punto. Ahora es una delicia, ¿sabes? -[LOVE6_4] -~r~¡Has abandonado el Securicar señuelo! +[JM4_5] +Pasa más tarde y les daremos algo que lavar... ¡Su propia ropa manchada de sangre! -{ =============================================================================== } -{ ================= MISSION: LOVE'S DISAPPEARANCE (DONALD LOVE) ================= } -{ =============================================================================== } +[AMMU_A] +Luigi dijo que necesitabas una pipa... -{ TITLE } +[AMMU_B] +Joey me pidió que te armáramos... -[LOVE7] -'LA DESAPARICIÓN DE LOVE' +[AMMU_C] +Ve a la parte de atrás. Te dejé un nueve en el patio. -{ No dialogue or strings } +[AMMU_D] +Tengo todo lo necesario para defender tu casa. -{ ============================================================== } -{ ================= MISSION: UZI MONEY (D-ICE) ================= } -{ ============================================================== } +[AMMU_E] +¿También quieres una licencia? -{ TITLE } +[AMMU_F] +No necesito tu documentación, pareces de fiar. -[HM_1] -'PASADA AMETRALLADA' +[DETON] +DETONACIÓN: -{ Pager message that tells the player that D-Ice's missions are now available } +[DRIVE_A] +Ten una Uzi seleccionada cuando entres en un vehículo, luego mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. -[HOOD1_A] -Ve al teléfono público de Wichita Gardens y hablaremos de negocios. +[DRIVE_B] +Ten una Uzi seleccionada cuando entres en un vehículo, luego mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. -{ Premission cutscene } +[RECORD] +~g~¡NUEVO RÉCORD! -{ D-Ice } +[NRECORD] +~r~¡NO HAY UN NUEVO RÉCORD! -[HM1_A] -¡Ey! ¡Soy D-Ice, de los Red Jacks! +[RCHELP] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. -[HM1_B] -Tengo un problema, me la están liando. +[RCHELPA] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. -[HM1_C] -Hay unos macarrillas en la calle que no piensan más que en pistolas y en SPANK. +[RC_1] +¡Tienes 2 minutos para destruir todos los coches de los Diablos que puedas! -[HM1_D] -Se llaman ''Nines'', van de púrpura, y cada día en el que se hacen notar +[RC_2] +¡Tienes 2 minutos para destruir todos los coches de la mafia que puedas! -[HM1_G] -es otro día más que los Jacks parecemos blandos. +[RC_3] +¡Tienes 2 minutos para destruir todos los coches de la yakuza que puedas! + +[RC_4] +¡Tienes 2 minutos para destruir todos los coches de los jamaicanos que puedas! + +[RC_5] +¡Tienes 2 minutos para destruir todos los coches de los Hood que puedas! + +[RC_6] +¡Tienes 2 minutos para destruir todos los coches del cártel que puedas! + +[RAMPAGE] +¡MASACRE! + +[RAMP_P] +¡MASACRE COMPLETADA! + +[RAMP_F] +MASACRE FALLIDA + +[PAGE_00] +. + +[PAGE_01] +¡Mata a ~1~ Diablos en 120 segundos! + +[PAGE_02] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_03] +¡Mata a ~1~ mafiosos en 120 segundos! + +[PAGE_04] +¡Mata a ~1~ Tríadas en 120 segundos! + +[PAGE_05] +¡Mata a ~1~ Tríadas en 120 segundos! + +[PAGE_06] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_07] +¡Revienta ~1~ cabezas jamaicanas en 120 segundos! + +[PAGE_08] +¡Quema a ~1~ yakuzas en 120 segundos! + +[PAGE_09] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_10] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_11] +¡Aniquila a ~1~ jamaicanos en 120 segundos! + +[PAGE_12] +¡Quema a ~1~ yakuzas en 120 segundos! + +[PAGE_13] +¡Vuela a ~1~ jamaicanos en 120 segundos! + +[PAGE_14] +¡Fríe a ~1~ colombianos en 120 segundos! + +[PAGE_15] +¡Machaca a ~1~ Hoods en 120 segundos! + +[PAGE_16] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_17] +¡Arrolla a ~1~ colombianos con un coche en 120 segundos! + +[PAGE_18] +¡Destruye ~1~ vehículos disparando desde otro en 120 segundos! + +[PAGE_19] +¡Revienta ~1~ cabezas colombianas en 120 segundos! + +[PAGE_20] +¡Decapita a ~1~ Hoods en 120 segundos! + +[JM1_A] +Jo, me aburro, ¿cuándo me la vas a meter? + +[JM1_B] +Dame un momento, cariño, que tengo un asuntillo que tratar. + +[JM1_C] +Tengo un trabajito para ti, colega. + +[JM1_D] +Los hermanos Forelli me deben dinero desde hace mucho tiempo + +[JM1_E] +y hay que enseñarles respeto. + +[JM1_F] +Labios Forelli está atiborrándose en el restaurante de Saint Mark's, + +[JM1_G] +así que róbale el coche y llévalo al taller de bombas de 8-Ball en Harwood. + +[JM1_H] +Conoces a 8-Ball, ¿verdad? + +[JM1_I] +En cuanto esté cargado con una bomba, aparca el coche donde lo encontraste. + +[JM1_J] +Luego salte y disfruta del espectáculo. + +[JM1_K] +Pero cuidado, no va a estar comiendo toda la vida. + +[CAT2_A1] +¡Vamos, perra! + +[CAT2_A] +La verdadera pregunta es: ¿vienes buscando a María o buscándome a mí? + +[CAT2_B] +Tengo una noticia para ti: + +[CAT2_B2] +matarte será un placer, pero salir contigo sólo fue un negocio. + +[CAT2_C] +¡Eres muy pequeñito, amigo! + +[CAT2_D] +Dame el dinero. + +[CAT2_E] +¡Has estado muy ocupado! + +[CAT2_E2] +Pero no has aprendido que yo no soy de fiar. + +[CAT2_E3] +¡Mata al idiota! + +[CAT2_J] +¡Despega de una vez! + +[HM5_1] +Hola, Ice dijo que vendrías. Las reglas son sólo bates. Cero armas, cero coches. + +[HM5_5] +Es una batalla por respeto, ¿vale? + +[HELP14] +Para conseguir un arma, pasa sobre ella. No puedes recogerlas estando dentro de un vehículo. + +[CRUSH] +Aparca en la zona señalada y sal de tu vehículo para que sea triturado. + +[DIAB2_B] +Una banda de roñosos amenazó con quitarme a mi protagonista si no les pago. + +[DIAB2_C] +Amenazaron al hombre equivocado, amigo. + +[DIAB2_D] +Su debilidad son los helados. + +[DIAB2_E] +Hazte con la bomba que dejé en Harwood, + +[DIAB2_F] +secuestra la camioneta del heladero mientras hace su ronda + +[DIAB2_G] +y engaña a esos idiotas con esa musiquita. + +[DIAB2_H] +Se esconden en un almacén del muelle Atlantic. + +[DIAB3_A] +¡Unas Tríadas insolentes robaron mi lindo carro anoche, + +[DIAB3_B] +lo destrozaron y lo quemaron! + +[DIAB3_C] +En el baúl había algunas de mis más preciadas posesiones sobre burros... + +[DIAB3_D] +Objetos de coleccionista irremplazables, amigo. + +[DIAB3_E] +Escondí un arma en el borde de Chinatown. + +[DIAB3_F] +Tómala y enseña a esos vándalos de las Tríadas a tenerle miedo a la ira pijuda de El Burro. + +[DIAB3_1] +MATA A 25 TRÍADAS + +[DIAB4_A] +¡Un ladrón oportunista robó una camioneta con mi última publicación! + +[DIAB4_B] +Pero ese idiota drogado de SPANK dejó las puertas de atrás abiertas, + +[DIAB4_C] +¡y ahora mi literatura para adultos + +[DIAB4_D] +tan bellamente producida, tan gustosamente fotografiada, está siendo esparcida por toda Liberty! + +[DIAB4_E] +Toma la camioneta y sigue el rastro de los volúmenes 1, 2 y 3 de Donkey Does Dallas, + +[DIAB4_F] +tomándolos por el camino. + +[DIAB4_G] +¡Cuando alcances a ese bandido espaciado con SPANK, chíngatelo! + +[DIAB4_H] +Luego reparte mis revistas XXX por el barrio rojo. + +[DIAB4_1] +~g~Lleva la furgoneta a la parte de atrás de Revistas XXX. [HM1_E] Quiero que esos mierdecillas sepan lo que es un verdadero tiroteo desde un vehículo. @@ -5281,33 +4458,6 @@ Quiero que esos mierdecillas sepan lo que es un verdadero tiroteo desde un vehí [HM1_H] ¡Haz que esos Nines se larguen! -[HM1_F] -Pero ojo, también habrá Jacks que se creerán que vas a por ellos. - -{ Mission instructions } - -[HM1_1] -~g~Cepíllate a 20 Purple Nines en 2 minutos y 30 segundos. - -[HM1_2] -~g~Hazte con un vehículo y recuerda que sólo cuentan las muertes a tiros desde el coche. - -[HM1_3] -~g~Los Nines tienen su territorio en Wichita Gardens. - -{ =============================================================== } -{ ================= MISSION: TOYMINATOR (D-ICE) ================= } -{ =============================================================== } - -{ TITLE } - -[HM_2] -'BOMBINATOR' - -{ Premission cutscene } - -{ D-Ice } - [HM2_A] Los Nines me están presionando. @@ -5323,45 +4473,6 @@ Hay un coche aparcado en la calle. [HM2_E] Dentro verás algo que te servirá para poner a esos gallinas en su sitio -[HM2_F] -y cargarte sus blindados. - -{ Mission instructions } - -[HM2_1] -Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. - -[HM2_1A] -Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. - -[HM2_2] -~r~¡No has destruido todos los furgones blindados! - -[HM2_6] -~g~¡Te has cargado un furgón blindado! - -[HM2_3] -¡Si golpeas las ruedas de un vehículo, el coche teledirigido estallará! - -[HM2_4] -¡Si el coche teledirigido se sale fuera de cobertura, estallará solo! - -[HM2_5] -~r~¡Te has ido de cobertura! - -{ =================================================================== } -{ ================= MISSION: RIGGED TO BLOW (D-ICE) ================= } -{ =================================================================== } - -{ TITLE } - -[HM_3] -'PREPARADO PARA ESTALLAR' - -{ Premission cutscene } - -{ D-Ice } - [HM3_A] Algún cazurro me ha puesto una bomba en el coche. @@ -5383,30 +4494,6 @@ Un golpe más de la cuenta y podría saltar por los aires. [HM3_G] ¡Tira! -{ Mission instructions } - -[HM3_1] -~g~¡Ve al garaje, pero pon atención, porque el coche explotará si se daña demasiado! - -[HM3_2] -~g~Lleva el coche de vuelta. ¡Tiene que estar inmaculado! - -[HM3_3] -~g~¡Haz que reparen el vehículo! - -{ ================================================================ } -{ ================= MISSION: BULLION RUN (D-ICE) ================= } -{ ================================================================ } - -{ TITLE } - -[HM_4] -'FIEBRE DEL PLATINO' - -{ Premission cutscene } - -{ D-Ice } - [HM4_A] Tío, un vuelo de la Reserva Federal se la acaba de pegar en el Aeropuerto Francis. @@ -5425,33 +4512,6 @@ El platino pesa un huevo y hará que tu buga vaya a paso de tortuga, [HM4_H] así que ve dejándolo de vez en cuando en el garaje. -{ Mission instructions } - -[HM4_D] -~g~¡Hazte con un vehículo! - -[HM4_1] -~g~Dirígete al lugar donde está el cargamento. Necesitas conseguir 30 lingotes. - -[HM4_2] -~g~Recuerda: cuando el vehículo esté pesado y vaya más despacio, ve al garaje y deja el cargamento. - -[HM4_E] -UNUSED - -{ =========================================================== } -{ ================= MISSION: RUMBLE (D-ICE) ================= } -{ =========================================================== } - -{ TITLE } - -[HM_5] -'ENFRENTAMIENTO' - -{ Premission cutscene } - -{ D-Ice } - [HM5_A] Ya solo quedan unos pocos Nines, @@ -5482,432 +4542,682 @@ Reúnete con mi hermano pequeño, [HM5_J] él te enseñará dónde será la pelea. -{ D-Ice's brother, when the player finds him } +[MEA1_B] +Me llamo Chonks, Marty Chonks. -[HM5_1] -Hola, Ice dijo que vendrías. Las reglas son sólo bates. Cero armas, cero coches. +[MEA1_C] +Soy el dueño de la fábrica de comestibles Bitch'n' Dog que está a la vuelta de la esquina. -[HM5_5] -Es una batalla por respeto, ¿vale? +[MEA1_D] +Tengo problemas económicos, pero, ¿y quién no? -[HM5_6] -Vamos a partir cabezas... +[MEA1_E] +He quedado con el director de mi banco. -{ Mission instructions } +[MEA1_F] +Es un chorizo que no para de inflar los intereses del préstamo para sacarme una buena tajada. -[HM5_3] -~r~¡Te han dicho que uses sólo un bate de béisbol! +[MEA1_G] +Coge mi coche, búscale y tráelo de vuelta. -[HM5_4] -~r~¡Tu contacto está muerto! +[MEA1_H] +¡Tengo una sorpresita para ese parásito chupasangre! -{ ============================================================================= } -{ ================= MISSION: BAIT (ASUKA KASEN, SECOND BATCH) ================= } -{ ============================================================================= } +[MEA2_A] +Contraté a unos ladrones para que entraran en mi piso -{ TITLE } +[MEA2_C] +Ahora los muy cabritos me amenazan con delatarme -[AS1] -'CEBO' +[MEA2_D] +si no les doy una parte. -{ Premission cutscene } +[MEA2_E] +¿Te lo puedes creer? -{ Asuka } +[MEA2_F] +He dejado un coche dentro de la fábrica. -[AS1_A] -Parece que Miguel piensa que le maltrato. +[MEA2_G] +Ve a recogerles con él en su territorio, en el barrio rojo. -[AS1_B] -Pero ha revelado cuánto teme Catalina tu búsqueda de venganza. +[MEA2_H] +Luego tráelos a la fábrica para que conozcan la opinión de Marty. -[AS1_C] -Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty con el único fin de darte caza. +[MEA3_A] +El negocio se irá a pique si no consigo un pastizal muy pronto. -[AS1_D] -Haz de cebo y consigue que los escuadrones te sigan hasta Pike Creek, +[MEA3_B] +Mi esposa tiene un seguro de vida y ella no ha hecho más que vaciarme los bolsillos. -[AS1_E] -donde estarán esperando algunos de mis hombres. +[MEA3_C] +He dejado un coche donde siempre. -{ Mission instructions } +[MEA3_D] +Ve a por a mi esposa a Classic Nails y tráela a la fábrica. -[AS1_G] -~r~¡Todos los yakuza están muertos! +[MEA4_A] +Mierda, ¡la he liado! -[AS1_H] -~r~¡No has llevado al escuadrón de la muerte hasta la trampa de la yakuza! +[MEA4_B] +Resulta que mi esposa salía con uno al que debo dinero. -{ ======================================================================================= } -{ ================= MISSION: EXPRESSO-2-GO! (ASUKA KASEN, SECOND BATCH) ================= } -{ ======================================================================================= } +[MEA4_C] +¡Se ha cabreado y ahora quiere vengarse! -{ TITLE } +[MEA4_E] +y piensa que voy a devolverle el dinero. -[AS2] -'CAFÉ PARA LLEVAR' +[MEA4_F] +Pero creo... -{ Premission cutscene } +[MEA4_G] +¡que los perros de Liberty van a disfrutar de un sabor nuevo este mes! -{ Asuka } +[WELCOME] +BIENVENIDO A -[AS2_A1] -¡Está claro que Miguel tiene esa famosa resistencia latina! +[HM1_2] +~g~Hazte con un vehículo y recuerda que sólo cuentan las muertes a tiros desde el coche. -[AS2_A2] -Estoy agotada. +[HELP8_B] +Pulsa el ~h~botón ~k~~PED_SNIPER_ZOOM_IN~~w~ para ~h~acercar el zoom ~w~con el fusil y el ~h~botón ~k~~PED_SNIPER_ZOOM_OUT~~w~ para ~h~alejarlo~w~. -[AS2_A] -Subestimamos los planes que tiene Catalina para el SPANK. +[LRQC_1] +Asuka y yo tenemos que hablar... -[AS2_B] -Va mucho más allá de hacer que los jamaicanos lo vendan en las esquinas. +[LRQC_2] +¿Por qué no te das una vuelta? -[AS2_C] -El cártel tiene una tapadera, el Kappa Coffee House. +[LRQC_3] +Necesitarás un escondite. -[AS2_D] -Vende SPANK en puestos callejeros. +[LRQC_4] +Hay un almacén en la orilla de Belleville que podría servirte. -[AS2_E] -No tenemos otra opción más que sabotear esos puntos de venta. +[LRQC_5] +Regresa a mi apartamento cuando estés listo -[AS2_F] -¡Redúcelos a cenizas! +[LRQC_6] +y podremos tener una charla. -{ Mission instructions } +[JM6_5] +~g~Necesitas un vehículo de fuga, ¡idiota! -[AS2_1] -~g~¡Todos los puestos de café en Portland han sido destruidos! +[JM2_F] +Si necesitas una pipa, ve a la parte de atrás del Ammu-Nation que está enfrente del metro. -[AS2_2] -~g~¡Todos los puestos de café en Staunton Island han sido destruidos! +[LOVE4_7] +~g~Hay una zona en obras en Staunton Island, puede que hayan llevado el paquete allí. -[AS2_3] -~g~¡Todos los puestos de café en Shoreside Vale han sido destruidos! +[LOVE4_8] +~g~Necesitarás un coche para abrir el garaje. -[AS2_4] -~r~¡El cártel ha avisado a sus camellos! +[TSCORE] +GANANCIAS: ~1~ $ -[AS2_5] -~g~¡Todavía hay puestos de café en Shoreside Vale y en Staunton Island! +[AM1_9] +~r~¡Salvatore ha vuelto a meterse en el club de Luigi! -[AS2_6] -~g~¡Todavía hay puestos de café en Shoreside Vale! +[AM1_6] +~g~Si te dejas ver por el club de Luigi, ¡la mafia te descubrirá! -[AS2_7] -~g~¡Todavía hay puestos de café en Staunton Island! +[TM2_3] +~g~¡Es una trampa! ¡Liquidadlos a todos! -[AS2_8] -~g~¡Todavía hay puestos de café en Portland! +[FM4_1] +Soy María. ¡El coche es una trampa! Estoy en el lado sur del puente Callahan. -[AS2_9] -~g~¡Todavía hay puestos de café en Portland y en Shoreside Vale! +[JM1_7] +~g~¡Cierra la puerta del coche! ¡Se dará cuenta! -[AS2_10] -~g~¡Todavía hay puestos de café en Portland y en Staunton Island! +[KM5_1] +~g~¡TRAFICANTE LIQUIDADO! + +[KM5_6] +~g~Debes matar a al menos 8 traficantes jamaicanos. + +[KM5_7] +~g~¡Mátalos rápido! En cuanto vendan el SPANK se retirarán de las calles. + +[RM3_8] +~r~¡El coche es un señuelo! + +[LM3_8] +Hola, soy Joey. + +[LM3_9] +Luigi dijo que eras de fiar, así que vuelve más tarde, + +[KM3_5] +~g~Toca el claxon para empezar con el trato. + +[LOVE7] +'LA DESAPARICIÓN DE LOVE' + +[LOVE2_5] +~g~¡Kenji ha palmado! ¡Sal de Newport y deshazte del coche! [AS2_11] ~g~¡~1~ DE 9! -[AS2_12] -~g~¡Recorre los distritos de Liberty y busca puestos de café ~b~Espresso-2-Go~g~! +[GARAGE1] +~g~Sal del vehículo y aléjate caminando. -[AS2_12A] -~g~Cuando destruyas el primer puesto, ¡tendrás 8 mintutos antes que el cártel avise a sus camellos! +[KM3_11] +~g~El cártel ha sido atacado y el maletín no ha sido recuperado. -{ =============================================================================== } -{ ================= MISSION: S.A.M. (ASUKA KASEN, SECOND BATCH) ================= } -{ =============================================================================== } +[KM3_12] +~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. -{ TITLE } +[KM3_13] +~g~Lleva el maletín de vuelta al casino. -[AS3] -'TIERRA-AIRE' +[RM5_6] +~g~¡Ha salido de la ambulancia! ¡Cárgate su escayola con un vehículo o una explosión! -{ Premission cutscene } +[PBOAT_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. -{ Maria } +[PBOAT_2] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. -[AS3_A] -¿Lo apretamos un poco más o esperamos a que se vuelva negro y se caiga? +[DIAB1_B] +Al habla El Burro, de los Diablos. -{ Asuka } +[DIAB1_D] +Eres nuevo en Liberty, pero ya te estás ganando una reputación en las calles. -[AS3_B] -Dale un toque rápido... +[DIAB1_E] +Hay una carrera que empezará junto a la sala Clásica, cerca del puente Callahan. -{ Maria } +[DIAB1_F] +Consíguete un buen carro y el primero que pase por todos los puntos de control se llevará el premio. -[AS3_C] -¡Buaj! ¿Qué es esa cosa amarilla pegajosa? +[HM2_1] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. -[AS3_C1] -¡Hola, guapo! +[HM2_1A] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. -{ Asuka } +[HM2_2] +~r~¡No has destruido todos los furgones blindados! -[AS3_D] -¡Mi manitas! +[HM2_6] +~g~¡Te has cargado un furgón blindado! -{ Maria } +[RM3_A] +Conozco a un pez gordo de la ciudad, un tipo muy cándido, -[AS3_E] -Me aburría, así que vine a hacerle compañía a Asuka. +[RM3_H] +con, digamos... gustos exóticos y el dinero para pagárselos. -{ Asuka } +[RM3_B] +Está involucrado en un asunto legal y la fiscalía tiene fotos de él muy comprometedoras -[AS3_F] -Esta chica tiene un talento nato para la tortura. +[RM3_C] +en una fiesta en la morgue o algo así. -[AS3_F1] -Se las ha arreglado para extraerle esta joyita a nuestro invitado. +[LOVE6_A] +Una lección sobre negocios, amigo mío: -[AS3_G] -Hay una avioneta que llegará al Aeropuerto Francis en dos horas. +[LOVE6_E] +Si tienes una mercancía única, todo el mundo tratará de arrebatártela, -[AS3_G1] -Está lleno del veneno de Catalina. +[LOVE6_C] +Unos SWAT han acordonado la zona donde se encuentran mi socio y el paquete. -[AS3_H] -Podrás evitar la seguridad del aeropuerto si conduces una lancha hasta las boyas luminosas, +[LOVE6_D] +Ve allí, recoge la furgoneta y haz de señuelo. -[AS3_H1] -así podrás disparar a la avioneta al aterrizar. +[LOVE6_F] +Mantenles ocupados y él podrá escaparse. -[AS3_I] -¡Recoge el cargamento de entre los escombros y tráelo! +[AM3_C] +Ahora mismo estará probablemente en la bahía. ¡Roba una lancha de la policía y hunde su carrera! -{ Maria } +[FESZ_UC] +CANCELAR -[AS3_J] -Ten cuidado, guapo, ¿vale? +[FEDS_SM] +L1, R1 - CAMBIAR MENÚ -{ Asuka } +[FEDS_AS] +;= - CAMBIAR SELECCIÓN -[AS3_K] -Ahora prueba con el aceite picante... +[FEDSAS2] +<> - CAMBIAR SELECCIÓN -{ Mission instructions } +[FEDS_SS] +L1,R1 - CAMBIAR SELECCIÓN -[AS3_1] -~g~¡Busca una ~r~lancha~g~ y ve a la ~b~boya señalada! +[FEDSSC1] +; - ACELERAR -[AS3_1A] -~g~¡Ahora ve a la ~b~boya señalada~g~! +[FEDSSC2] += - RALENTIZAR -[AS3_3] -~g~¡Espera a que la ~y~avioneta~g~ comience a acercarse! +[MEA2_3] +~g~Lleva el coche de vuelta a la fábrica. -[AS3_5] -~g~¡Recupera el cargamento! +[RM1_3] +~r~¡McAffrey se ha escapado! -[AS3_4] -~g~¡Usa un lanzacohetes para derribar ~y~la avioneta~g~! +[RM1_4] +~g~¡Has usado todas las granadas! ¡Consigue más en la tienda Ammu-Nation! -[AS3_2] -~b~¡Ve a la boya del aeropuerto señalada! ~y~¡El avión se está acercando! +[RM1_5] +~g~¡Vuelve y quema la casa franca! -[AS3_6] -~g~~1~ DE 8 +[RM6_4] +~g~Ve al almacén a por el cargamento de Ray. -[STASH] -~g~¡Lleva el SPANK de vuelta a la ~p~zona en obras~g~! +[RM6_5] +~g~La CIA vigila el puente, busca otro camino. -{ ============================================================== } -{ ================= MISSION: RANSOM (CATALINA) ================= } -{ ============================================================== } +[HM2_F] +y cargarte sus blindados. -{ TITLE } +[HM_4] +'FIEBRE DEL PLATINO' -[AS4] -'RESCATE' +[MEA4_B7] +Pero si pasas por mi oficina... -[CAT1] -'RESCATE' +[MEA3_B4] +¿Marty quiere verme? Bueno, pues que sea rápido, porque tengo que ir a la peluquería. -{ Cutscene } +[KM3_7] +¡Es una trampa de la yakuza, tío! -{ Catalina (letter, colombiana) } +[FES_LOF] +Fallo al cargar. -[CAT1_A] -Tengo a tu linda María. Si no quieres que parezca que un carnicero se ensañó con ella, +[P1INSA] +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 tiene ~1~ KB de espacio disponible. Necesitas ~1~ KB para guardar. -[CAT1_B] -lleva 500.000 dólares a la mansión de Cedar Grove. +[P1INSN] +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 no tiene espacio suficiente. Por favor, borra algunos archivos. -{ Mission instructions } +[FES_SLO] +ARCHIVO -[CAT1_F] -¡Ve a donde está Catalina antes de que se acabe el tiempo! +[FES_ISC] +ESTÁ DAÑADO -[CAT_MON] -~g~Todavía te falta dinero. Necesitas 500.000 dólares. +[FESZ_TI] +ARCHIVO Z1 -[CAT1_E] -XXXX +[FESZ_SA] +Guardar partida -{ ==================================================================== } -{ ================= MISSION: THE EXCHANGE (CATALINA) ================= } -{ ==================================================================== } +[P1NOIN] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. -{ TITLE } +[P1INSE] +Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. -[CAT2] -'EL INTERCAMBIO' +[MC_LDFL] +¡Fallo al cargar! -{ Premission cutscene } +[MC_NWRE] +Reiniciando partida. -{ Catalina (colombiana) } +[LOVE6_3] +~g~Tienes ~1~ segundos para volver al Securicar antes de fracasar la misión. -[CAT2_A] -La verdadera pregunta es: ¿vienes buscando a María o buscándome a mí? +[LOVE6_4] +~r~¡Has abandonado el Securicar señuelo! -[CAT2_B] -Tengo una noticia para ti: +[HELP1] +Detente en el centro de la señal azul. -[CAT2_B2] -matarte será un placer, pero salir contigo sólo fue un negocio. +[HELP12] +Entra en la señal azul para comenzar una misión. -[CAT2_C] -¡Eres muy pequeñito, amigo! +[HJSTAT] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. -[CAT2_D] -Dame el dinero. +[HJSTATW] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! -[CAT2_E] -¡Has estado muy ocupado! +[DIAB1_5] +TIEMPO DE CARRERA: -[CAT2_E2] -Pero no has aprendido que yo no soy de fiar. +[LOVE3_4] +~r~¡Has destruido el avión! -[CAT2_E3] -¡Mata al idiota! +[F_FAIL1] +¡Misión del camión de bomberos terminada! -[CAT2_A1] -¡Vamos, perra! +[F_CANC] +~r~¡Misión del camión de bomberos cancelada! -{ Cutscene, after reaching Catalina at the dam } +[F_EXTIN] +INCENDIOS: -{ Catalina (colombiana) } +[A_COMP1] +¡Misiones de sanitario completadas! -[CAT2_J] -¡Despega de una vez! +[A_CANC] +~r~¡Misión de sanitario cancelada! -{ Mission instructions } +[A_COMP3] +¡Misiones de sanitario completadas! ¡Ahora no te cansarás al correr! -[CATINF1] -~g~¡Liquida a Catalina! +[ATUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. -[CATINF2] -~g~Sigue al helicóptero para encontrar a Catalina. +[ATUTOR3] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. -[BITCH_D] -~g~¡María está muerta! +[ALEVEL] +Nivel de misión de sanitario: ~1~ -{ =================================================== } -{ ================= ENDING CUTSCENE ================= } -{ =================================================== } +[A_FAIL1] +Misión de sanitario terminada. -{ Libery City News broadcaster } +[FEST_HA] +Nivel más alto de misión de sanitario -[END_A] -Los residentes de Cedar Groove todavía están asumiendo +[A_SAVES] +GENTE SALVADA: ~1~ -[END_B] -las consecuencias emocionales provocadas +[C_KILLS] +CRIMINALES ABATIDOS: ~1~ -[END_C] -por la guerra que estalló ayer en la zona. +[HM1_B] +Tengo un problema, me la están liando. -[END_D] -Un residente local, Clive Denver, dijo a la policía +[AM2_A] +La muerte de Salvatore es una placentera noticia, -[END_E] -que vio a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. +[AM2_A2] +eres un asesino eficaz. Eso me gusta en un hombre. -{ Maria } +[AM2_B] +Este es mi hermano Kenji. -[END_F] -¿Sabes? Vamos a pasar un buen rato, porque, como sabes... +[AM2_C] +Asuka tiene un trabajito para ti, pero cuando acabes, pásate por mi casino y podremos hablar. -[END_G] -¡Te amo! Yo, yo, yo realmente te amo, porque eres superfuerte, +[AM2_D] +Típico de Kenji, siempre está detrás de mis juguetes. -[END_H] -y eso es todo lo que necesito. +{ The voiced dialogue doesn't match the English subtitle for the next string } -[END_I] -Bueno, ¿qué estaba diciendo? +[AM2_E] +Mi contacto en la policía me dice que el FBI ha montado un operativo de vigilancia -[END_J] -Lo he olvidado. Pero me entiendes, ¿verdad? +{ The voiced dialogue doesn't match the English subtitle for the next string } -{ Libery City News broadcaster } +[AM2_E2] +en varios puntos de la ciudad. -[END_K] -Las explosiones sacudieron las casas más próximas y a sus residentes. +{ The voiced dialogue doesn't match the English subtitle for the next string } -[END_L] -Varios ciudadanos resultaron heridos a causa del tiroteo +[AM2_F] +No tenemos tiempo para contactar con nadie y evitar que nos incriminen. -[END_M] -entre las fuerzas terrestres y un helicóptero que rodeaba a la presa. +{ The voiced dialogue doesn't match the English subtitle for the next string } -{ Male witness } +[AM2_G] +Liquida a esos polis espías, pero cuidado: tendrán apoyo. -[END_N] -Sí, en estos jardínes tuvimos una vista excelente. +[F_START] +~g~Informe de vehículo en llamas en: ~a~. Ve y extingue el fuego. -[END_O] -Cuando el helicóptero estalló, +[AM4_1A] +Ve a la cabina al oeste del Parque Belleville. -[END_P] -fue mejor que los fuegos artificiales del 4 de julio. +[AM4_1B] +Ve a la cabina del Campus de Liberty. -{ Libery City News broadcaster } +[AM4_1C] +Ve a la cabina al sur del Parque Belleville. -[END_Q] -El número de víctimas asciende a las veinte +[AM4_1D] +Ven a verme a los baños públicos del parque. -[END_R] -mientras la policía sigue encontrando cuerpos. +[HJSTATF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. -[END_S] -No se han negado oficialmente los rumores +[HJSTAWF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! -[END_T] -de que las víctimas eran miembros del cártel colombiano, +[HM1_F] +Pero ojo, también habrá Jacks que se creerán que vas a por ellos. -[END_U] -y aún no hay pistas que aclaren las causas de la masacre. +[HM1_D] +Se llaman ''Nines'', van de púrpura, y cada día en el que se hacen notar -{ Maria } +[HM1_G] +es otro día más que los Jacks parecemos blandos. -[END_V] -Me he roto una uña y me pelo está hecho un asco, ¿puedes creerlo? +[MEA2_B] +y robaran cuanto pillaran para que yo pudiera reclamar a la aseguradora. -[END_W] -Me costó cincuenta dólares... +[TM3_H] +Buen trabajo, chaval, muy bueno. -{ Duplicates of Maria's dialogue, possibly unused } +[TM3_I] +Vente, te presentaré al Don. -[CAT2_F] -Me he roto una uña y se me ha estropeado el peinado. Es increíble. ¡Me había costado cincuenta dólares! +[TM3_J] +¡Hola! ¡Luigi! -[CAT2_G] -Estaba muerta de miedo, pero luego me dije a mí misma: ''Ya eres mayorcita''. +[TM3_K] +Mis chicas te han echado de menos, Salvatore. Hace mucho que no te vemos. -[CAT2_H] -Oh, nos lo vamos a pasar a lo grande, porque, ¿sabes?, mi hermana dijo que quería venirse a vivir con sus dos hijos, +[TM3_L] +Diles que en cuanto resolvamos este desafortunado incidente -[CAT2_I] -porque su marido a vuelto a enredar por ahí y... +[TM3_M] +iremos todos al club para celebrarlo, ¿vale? -{ =================================================================================================================== } -{ =================================================================================================================== } -{ ================================================== GAME CREDITS =================================================== } -{ =================================================================================================================== } -{ =================================================================================================================== } +[TM3_N] +¡Mi niño! + +[TM3_N2] +¿Cómo lo llevas, papá? + +[TM3_O] +¿Has encontrado ya una buena mujer? + +[TM3_P] +Tu madre, que en paz descanse, se retorcería en la tumba + +[TM3_Q] +si te viera sin una mujer. + +[TM3_R] +Lo sé, papá, estoy en ello. + +[TM3_S] +¡Toni! ¿Cómo está tu madre? + +[TM3_T] +Es una gran mujer, ¿sabes? Fuerte, ''firenze''. + +[TM3_U] +Está bien, estupendamente. + +[TM3_V] +Fantástico, fantástico. Bien, muchachos, entrad mientras yo hablo con nuestro nuevo amigo. + +[TM3_W] +Tienes un gran futuro por delante, hijo mío... + +[RM1_A] +¡Ese canalla de McAffrey...! ¡Aceptó más sobornos que nadie, + +[RM1_B] +se piensa que le darán la pensión completa si se convierte en un testigo de cargo! + +[RM1_C] +¡Y ha cantado! + +[RM4_B] +Tenemos que cerrarle la boca para siempre. + +[RM4_E] +¡Quiero que se vaya a dormir con los peces, en vez de comérselos! + +[LOVE3_B] +Esta noche, durante su aproximación al aeropuerto, una avioneta sobrevolará la bahía. + +[LOVE4_D] +Desgraciadamente, las autoridades aduaneras registraron la avioneta y la comenzaron a desmontar + +[LOVE4_H] +hasta que yo intervine a través de mi fortuna. + +[LOVE4_E] +Cruza el puente hacia Shoreside Vale y ve al Aeropuerto Internacional Francis. + +[GTAB_A] +Oye, saquemos esto de aquí. Dios sabrá lo que será, + +[GTAB_B] +pero él lo quiere a toda costa, así que tendrá algún valor. + +[GTAB_C] +¡¿Qué diablos?! + +[GTAB_D] +¡TÚ! + +[GTAB_E] +¡Tranquilo, amigo! ¡No es nada! ¡No es nada! + +[GTAB_F] +¡Te dejé desangrándote entre la basura! + +[GTAB_G] +No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. + +[GTAB_H] +¡No seas cagón! + +[GTAB_I] +¡No tenemos elección, nena! + +[GTAB_J] +¡Siempre la hay, imbécil! + +[GTAB_K] +¡Siento mucho lo de esa perra enloquecida, todas son iguales... ¿Por favor? + +[GTAB_L] +Así que la zorra se fue. + +[GTAB_M] +Pero me has hecho un favor, + +[GTAB_N] +no eres el único que tiene una cuenta pendiente con el cártel... + +[GTAB_O] +¡Este gusano mató a mi hermano! + +[GTAB_P] +¡Nunca maté a ningún yakuza! + +[GTAB_Q] +¡Mientes! Todos vimos al asesino del cártel. + +[GTAB_R] +¡Vamos a cazaros y a mataros a todos, perros colombianos! + +[GTAB_S] +Me trabajaré a nuestro querido amigo para extraerle información y un poco de placer. + +[GTAB_T] +Tú, ven más tarde, estoy segura de que voy a necesitar tus servicios. + +[GTAB_U] +¡Por favor, amigo! ¡No me dejes con ella, esa chica está loca! ¿Amigo? ¡Oye, amigo! ¡Amigo...! + +[LOVE5_A] +Estás demostrando ser una inversión segura, algo muy raro en estos días. + +[KM3_1] +~g~El cártel espera a una banda jamaicana, ¡así que roba uno de sus coches! Dirígete al norte; encontrarás uno en Newport. + +[LOVE1_1] +~g~Roba un coche de la banda colombiana para que puedas entrar en su escondite. Dirígete hacia el norte; podrás encontrar uno en Fort Staunton. + +[FM1_Q1] +¿Quieres un poco de diversión? ¿Un poco de... hmmm, de SPANK? + +[FM1_R] +Hola, Chico. No, solo lo de siempre. + +[FM1_T] +Gracias, Chico, nos vemos. + +[FM1_W] +Oye, tú, espera aquí y quédate pendiente del coche mientras yo voy a menear el esqueleto, ¿vale? + +[FM1_X] +¡Vale, tú, salgamos de aquí! ¡Uaaah! + +[FM1_Q] +¡Ay, mira, es mi chica favorita! + +[FM1_S1] +Ey, deberías echar un vistazo a la fiesta del almacén en el lado este del muelle Atlantic. + +[FM1_U] +Gracias y disfruta. Es buen material. + +[FM1_V] +¡Venga, tú, vamos a ver esa fiesta! + +[FM1_SS] +~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: asistan redada de narcóticos en el muelle Atlantic. + +[LOVE6_B] +aun sin conocer su verdadera valía. + +[TM3_A1] +~r~¡Joey está frito! + +[TM3_A2] +~r~¡Joey y Luigi han sido incinerados! + +[TM3_A3] +~r~¡Joey, Luigi y Toni están calcinados! + +[FM4_2] +Mira, Salvatore cree que se la estamos jugando, + +[FM4_3] +así que te vendió al cártel para llegar a un trato. + +[FM4_4] +No podía permitírselo, o sea, lo peor es... + +[FM4_4B] +que yo tengo la culpa, porque le dije que somos pareja. + +[FM4_5] +¡No me preguntes por qué, no lo sé! + +[FM4_6] +Mira, la mafia te quiere muerto y yo también tengo que salir de aquí. + +[FM4_6B] +¡He visto demasiados asesinatos, demasiada sangre! + +[FM4_7] +Es una amiga mía, ¿vale?, una vieja amiga... Es Asuka, es de fiar. + +[FM4_8] +Vamos, dejémonos de discursos. + +[FM4_9] +Mejor nos vamos antes de que haya más italianos histéricos con intenciones menos amistosas. [CRED001] ROCKSTAR STUDIOS @@ -6704,9 +6014,6 @@ DAVE WATSON [CRED253] MALCOLM SMITH -[CRED254] -JEFE DEL ESTUDIO - [CRED255] ANDREW SEMPLE @@ -6752,258 +6059,185 @@ STEVE K. [CRED269] GREG LAU -[CRED270] -MIKE HONG +[CINCAM] +Vista cinematográfica -{ =================================================================================================================== } -{ =================================================================================================================== } -{ ================================================ INTERFACE STRINGS ================================================ } -{ =================================================================================================================== } -{ =================================================================================================================== } +[KM1_13] +¡Mete el vehículo en el garaje! -{ ================================================================ } -{ ================= PAUSE MENU OPTIONS (CONSOLE) ================= } -{ ================================================================ } +[KM3_14] +~r~¡Te han descubierto, han cancelado el trato! -[FEB_STA] -Estadísticas +[EBAL_H] +Espera, tío, que voy a hablar con Luigi. -[FEB_BRI] -Resumen +[EBAL_M] +¡Recuerda: nadie se mete con mis chicas! -[FEB_CON] -Controles +[LM2_F] +Luego coge su coche y repíntalo. -[FEB_AUD] -Sonido +[LM2_D] +toma, toma, para ti. -[FEB_DIS] -Pantalla +[LM1_9] +Hola, soy Misty. -[FEB_LAN] -Idioma +[LM4_A] +Algún Diablo de las narices ha estado vendiendo a sus putitas en mi territorio. -[FEB_SAV] -Cargar +[FM2_B] +¡Tenemos a un chivato! -[FEB_CPC] -Configuración de controles +[FM2_C] +No está ni chuleando ni traficando, así que estará cantando. -[FEB_PMB] -Resumen de la última misión: - -{ ============================================================================= } -{ ================= PAUSE MENU DESCRIPTIONS (CONSOLE, UNUSED) ================= } -{ ============================================================================= } - -[FEF_ST1] -¿Quién es el malo? - -[FEF_ST2] -Cuánta destrucción has producido - -[FEF_BR1] -¿Has perdido el hilo? - -[FEF_CO1] -¿Necesitas más control? - -[FEF_CO2] -Elige la mejor configuración del mando para tu estilo de juego - -[FEF_SA1] -¡Mantén tu sitio en el bloque! - -[FEF_SA2] -Guarda y carga tus partidas - -[FEF_AU1] -¡Dale candela al volumen! - -[FEF_AU2] -Elige una emisora de radio y un efecto de sonido - -[FEF_DI1] -¡Cambia el juego! - -[FEF_DI2] -Personaliza el juego para tu televisión - -[FEF_LA1] -¿Qué dices de los Willis? - -[FEF_LA2] -Elige tu idioma preferido - -[FEF_BR2] -Encuéntralo de nuevo leyendo los resúmenes de las misiones jugadas hasta la fecha. - -{ ==================================================================== } -{ ================= CONSOLE PAUSE MENU HINT MESSAGES ================= } -{ ==================================================================== } - -[FEDS_XB] -Seleccionar - -[FEDS_ST] -Botón START - CONTINUAR - -[FEDS_SM] -L1, R1 - CAMBIAR MENÚ +[FM3_CC] +Regresa cuando tengas el dinero. [FEDS_AM] <> - CAMBIAR MENÚ -[FEDS_AS] -;= - CAMBIAR SELECCIÓN +[LOVE5_5] +~r~¡No has protegido al camión! -[FEDSAS2] -<> - CAMBIAR SELECCIÓN +[RM6_6] +~r~¡Ray ha muerto! -[FEDSAS3] -- CAMBIAR SELECCIÓN +[RM6_7] +~r~¡Ray ha perdido su avión! -[FEDSAS4] -;=<> - CAMBIAR SELECCIÓN +[RM6_8] +~g~Has abandonado a Ray, vuelve a por él. -[FEDS_SS] -L1,R1 - CAMBIAR SELECCIÓN +[FM1_10] +~g~Has abandonado a María, vuelve y recógela. -[FEDSSC1] -; - ACELERAR +[LOVE4_9] +~r~¡El avión ha sido destruido! -[FEDSSC2] -= - RALENTIZAR +[LOV4_10] +~r~¡La única pista sobre dónde se encuentra el paquete ha sido destruida! -[FEDS_SE] -Botón / - ELEGIR +[KM2_D] +No hace falta decir que debemos darle los coches como un regalo, para pagar mi deuda con él. -[FEDS_SB] -Botón / - ELEGIR Botón " - VOLVER +[KM4_B] +El negocio es lo bastante afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. -[FEDS_BA] -Botón " - VOLVER +[KM2_E] +Debes obtener los coches de la lista y llevarlos a un garaje que hay tras el aparcamiento de Newport. -[FEDS_TB] -ATRÁS +[FM3_8I] +Encuentra una posición elevada. Entraré cuando dispares el primer tiro. -{ INTERFACE ARROWS } +[LOVE1_B] +La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, -[FEA_UP] -; +[LOVE1_H] +pero los grupos de hombres se vuelven codiciosos. -[FEA_DO] -= +[LOVE1_C] +Un activo valioso, un anciano oriental que conozco, -[FEA_LE] -< +[LOVE1_I] +está siendo retenido por unos sudamericanos en Aspatria. -[FEA_RI] -> +[MEA4_D] +He aceptado verle, -{ ================================================================================ } -{ ================= REMNANTS FROM THE CONSOLE PAUSE MENU OPTIONS ================= } -{ ================================================================================ } +[MEA4_B4] +¿Marty te envía? Vale, le voy a enseñar a ese sinvergüenza el significado de la palabra negocio. -[FES_LGA] -Cargar partida +[MEA4_B5] +¡Carl, hola! Ehhh... Necesito más tiempo para conseguir tu dinero. -[FES_NGA] -Nueva partida +[MEA1_B4] +Ah, te envió el Sr. Chonks, ¿verdad? Visitemos a nuestro amigo. -[PRVMEN] -Resúmenes de misiones anteriores +[HM5_6] +Vamos a partir cabezas... -[FEC_CCF] -Configuración: +[LOVE1_5] +~g~Deja de perder el tiempo, hazte con un coche de los colombianos y rescata al socio de Love. -[FEC_CF1] -Ajuste1 +[AS1_D] +Haz de cebo y consigue que los escuadrones te sigan hasta Pike Creek, -[FEC_CF2] -Ajuste2 +[AS1_E] +donde estarán esperando algunos de mis hombres. -[FEC_CF3] -Ajuste3 +[AS2_C] +El cártel tiene una tapadera, el Kappa Coffee House. -[FEC_CF4] -Ajuste4 +[AS2_E] +No tenemos otra opción más que sabotear esos puntos de venta. -[FEC_CDP] -Controles a mostrar: +[AS2_F] +¡Redúcelos a cenizas! -[FEC_ONF] -A pie +[AS2_A1] +¡Está claro que Miguel tiene esa famosa resistencia latina! -[FEC_INC] -En vehículos +[AS2_A2] +Estoy agotada. -[FEC_VIB] -Vibración: +[SIREN_3] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[FEA_OUT] -Salida: +[SIREN_4] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[FEA_ST] -Estéreo +[AS3_C] +¡Buaj! ¿Qué es esa cosa amarilla pegajosa? -[FEA_MNO] -Mono +[AS3_C1] +¡Hola, guapo! -[FEA_NON] -Ninguna +[AS3_F] +Esta chica tiene un talento nato para la tortura. -[ENGLIS] -Inglés +[AS3_F1] +Se las ha arreglado para extraerle esta joyita a nuestro invitado. -[GERMAN] -Alemán +[AS3_G] +Hay una avioneta que llegará al Aeropuerto Francis en dos horas. -[ITALIA] -Italiano +[AS3_G1] +Está lleno del veneno de Catalina. -[FRENCH] -Francés +[AS3_H] +Podrás evitar la seguridad del aeropuerto si conduces una lancha hasta las boyas luminosas, -[SPAIN] -Español +[AS3_H1] +así podrás disparar a la avioneta al aterrizar. -[FESZ_SA] -Guardar partida +[AS3_I] +¡Recoge el cargamento de entre los escombros y tráelo! -[FES_SLO] -ARCHIVO +[AS3_J] +Ten cuidado, guapo, ¿vale? -[FES_ISF] -NO PRESENTE +[AS3_K] +Ahora prueba con el aceite picante... -[FES_SAG] -PRESENTE +[RM2_F1] +¡Los colombianos llegarán en cualquier momento! -[FES_ISC] -ESTÁ DAÑADO +[RM2_K] +Maldita sea, ¡están aquí! ¡FUEGO A DISCRECIÓN! -[FESZ_TI] -ARCHIVO Z1 +[LOVE2_7] +~g~¡Ahora deshazte del coche! -{ =================================================================== } -{ ================= PLAYSTATION 2 EXCLUSIVE PROMPTS ================= } -{ =================================================================== } +[LOVE2_8] +~g~¡Sal de Newport! -[P1INSA] -La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 tiene ~1~ KB de espacio disponible. Necesitas ~1~ KB para guardar. +[AM1_F] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (~1~:~1~) -[P1INSN] -La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 no tiene espacio suficiente. Por favor, borra algunos archivos. - -[P1NOIN] -No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. - -[FES_NOC] -No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. - -[P1INSE] -Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. +[LOVE5_C] +Quiero que le sigas, asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. [FESZ_SR] ¡Error al guardar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. @@ -7011,17 +6245,11 @@ Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. [FESZ_FO] ¿Deseas formatear la Memory Card (PS2) en la ranura de MEMORY CARD 1? -[FESZ_QF] -¿Seguro que quieres formatear la Memory Card (PS2) de la ranura de MEMORY CARD 1? - [FELZ_FO] La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. -[SLONNF] -La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. - -[FESZ_FM] -La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. ¿Deseas formatear la Memory Card (PS2)? +[FES_NOC] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. [FES_LOE] ¡Fallo al cargar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. @@ -7035,9 +6263,6 @@ Memory Card (PS2) de la ranura de MEMORY CARD 1 formateada con éxito. [ERFOUN] ¡Error al formatear la Memory Card (PS2)! -[SLONFM] -¡Error al formatear la Memory Card (PS2)! - [ERMCNP] No hay Memory Card (PS2) en la ranura de MEMORY CARD 1. @@ -7047,6 +6272,9 @@ Guardando en la Memory Card (PS2) de la ranura de MEMORY CARD 1. [FORSLO] Formateando Memory Card (PS2) de la ranura de MEMORY CARD 1. +[SLONFM] +¡Error al formatear la Memory Card (PS2)! + [SLONDR] No hay espacio suficiente en la Memory Card (PS2). Inserta una Memory Card (PS2) con, al menos, 500KB de espacio libre en la ranura de MEMORY CARD 1. @@ -7056,9 +6284,21 @@ No hay espacio suficiente en la Memory Card (PS2). Inserta una Memory Card (PS2) [FEFD_WR] Formateando la Memory Card (PS2) de la ranura de MEMORY CARD 1. No extraigas la Memory Card (PS2), ni reinicies o apagues la consola. +[FES_ISF] +NO PRESENTE + +[FES_SAG] +PRESENTE + [SLONNO] No hay una Memory Card (PS2) en la ranura de MEMORY CARD 1. +[SLONNF] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. + +[FESZ_FM] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. ¿Deseas formatear la Memory Card (PS2)? + [FESZ_FF] ¡Fallo al formatear! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. @@ -7077,164 +6317,661 @@ Sobrescribiendo datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY [FELD_WR] Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. -[MCLOAD] -Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. - [FEDL_WR] Borrando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. +[LM2_C] +Luigi dijo que... que te diera esto... + +[LM3_G] +que a Joey no le gusta esperar. Recuerda, tienes un pie dentro... + +[LM5_E] +Saca todo el dinero que puedas a los polis antes de que se lo beban. + +[JM5_C] +Vale, hay un coche cargado con un fiambre en el bar cercano a Callahan Point. + +[RM2_B] +Combatimos juntos en Nicaragua, cuando el país sabía lo que hacía. + +[RM2_C] +En fin, ayer unos cerdos del cártel lo zurraron y le dijeron que volverían hoy para quitarle parte de su stock. + +[RM2_D1] +Iría yo mismo, pero la ciática ya está en sus trece... ¡Cof, cof! Así que... buena suerte. + +[CATINF1] +~g~¡Liquida a Catalina! + +[CATINF2] +~g~Sigue al helicóptero para encontrar a Catalina. + +[BOATIN1] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. + +[BOATIN2] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. + +[BOATIN3] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. + +[BOATIN4] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. + +[JM6] +'LA HUIDA' + +[FM1] +'CARABINA' + +[JM1] +'EL ÚLTIMO ALMUERZO DE MIKE ''LABIOS'' ' + +[FM21] +'BASE FUERA: ACTO I' + +[FM3] +'BASE FUERA: ACTO II' + +[AM1] +'SAYONARA, SALVATORE' + +[AM2] +'BAJO VIGILANCIA' + +[KM2] +'ROBO DE VEHÍCULOS' + +[AS3] +'TIERRA-AIRE' + +[RM2] +'ESCASEZ DE MANOS' + +[LOVE6] +'SEÑUELO' + +[LOVE1] +'EL LIBERADOR' + +[RC1] +'DESTRUCCIÓN DE LOS DIABLOS' + +[RC2] +'LA MASACRE DE LA MAFIA' + +[RC3] +'CALAMIDAD EN EL CASINO' + +[RC4] +'EXTERMINIO DE RUMPOS' + +[RM2_E1] +¡No puedo creer que esos mamones amarillos me hayan vuelto a dejar con el culo al aire! + +[GREN_1] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. + +[GREN_2] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. + +[GREN_3] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. + +[LOVE4_G] +Mis pertenencias estarán esperándote en el hangar de aduanas, dentro de la avioneta. + +[KABOOM] +¡BUUUM! + +[SPLAT] +¡PLOF! + +[PANCAK] +¡APLASTADO! + +[SOAKED] +¡AGUADO! + +[HEAD] +Head Radio + +[DBL_CLF] +Double Clef FM + +[FLASHB] +Flashback FM + +[RISE] +Rise FM + +[LIPS] +Lips 106 + +[CHAT] +Chatterbox FM + +[K_JAH] +K-Jah Radio + +[GAM_FM] +Game Radio FM + +[MSX_FM] +MSX FM + +[TUBE1] +Cuando el metro abra, podrás coger un tren hasta Staunton Island. + +[TUBE2] +Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al Aeropuerto Internacional Francis. + +[TUBE_2] +Para subirte a un vagón, pulsa el ~h~botón Entrar al vehículo~w~. + +[LEGAL] +~g~¡Elimina la amenaza criminal! + +[GA_2] +He cambiado el motor y la mano de pintura. ¡La poli no te reconocerá! + +[LM1_8A] +Si quieres ganar un dinerillo extra, siempre puedes ''coger prestado'' un taxi... + +[TAXIH1] +Para cerca de un peatón señalado para recogerlo y luego condúcelo a su destino antes de que se acabe el tiempo. + +[LM5_7] +~g~¡Si hay menos de cuatro chicas trabajando en el ~p~baile de la policía~g~, Luigi no estará contento! + +[KM2_3] +~g~Recuerda que los ~r~coches ~g~tienen que estar en perfecto estado para ser aceptados en el ~p~garaje~g~. + +[KM5_2] +~g~Uno de los jamaicanos se ha ido. + +[BETRA_A] +Lo siento, cariño. + +[BETRA_B] +Soy una chica ambiciosa, ¿y tú? + +[BETRA_C] +Un Don Nadie. + +[JAILB_Q] +¡Vamos! + +[JAILB_R] +¡Señor pendejo! + +[JAILB_S] +No nos importará matarte. + +[JAILB_T] +Os vais a arrepentir. + +[JAILB_U] +Bien, bien, piérdete. + +[HELP15] +Cuando vayas a pie mantén pulsado el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para~h~ mirar atrás~w~. + +[FEC_LB3] +Mirar atrás + +[FEC_R3] +(botón R3) + [FES_AFO] Esta Memory Card (PS2) ya está formateada. +[FEA_UP] +; + +[FEA_DO] += + +[FEA_LE] +< + +[FEA_RI] +> + +[FEDSAS3] +- CAMBIAR SELECCIÓN + +[FEDSAS4] +;=<> - CAMBIAR SELECCIÓN + +[SPRAY_4] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. + +[SPRAY_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. + +[LITTLE] +LITTLE T + +[NICK] +NICK LOVE + +[AM1_10] +~g~Salvatore saldrá del club de Luigi sobre las 0~1~:~1~. + +[JAILB_V] +Hoy, Liberty City se ha visto conmocionada. + +[JAILB_A] +La policía y los servicios de emergencia lidian con las consecuencias + +[JAILB_B] +de un ataque devastador a un convoy policial ocurrido esta mañana. + +[JAILB_C] +No se ha informado de quiénes eran los prisioneros trasladados en el convoy + +[JAILB_D] +y ningún grupo ha reconocido la autoría. + +[JAILB_E] +El convoy abandonó las oficinas de la policía esta mañana + +[JAILB_F] +para hacer una transferencia de reos a la penitenciaría de Liberty. + +[JAILB_G] +El ataque se produjo en el puente Callahan, + +[JAILB_H] +dejando pocos testigos y al puente seriamente dañado. + +[JAILB_I] +Se cree que algunos de los convictos han perecido en la explosión + +[JAILB_J] +posterior al ataque inicial. + +[JAILB_W] +Pasadas las horas se hizo evidente que el ataque era obra de profesionales, + +[JAILB_K] +ya que la identificación de los prófugos se complicó + +[JAILB_L] +cuando piratas informáticos atacaron las bases de datos de la policía. + +[JAILB_O] +Con el retraso del proyecto del túnel Porter, + +[JAILB_P] +este desastre deja a Portland aislada del resto de la ciudad. + +[JAILB_M] +* + +[JAILB_N] +* + +[JAILB_X] +UNUSED + +[FEDS_SE] +Botón / - ELEGIR + +[FEDS_SB] +Botón / - ELEGIR Botón " - VOLVER + +[TM4_A] +Ah, eres tú. Toni no está. + +[TM4_A2] +Pero te ha dejado una de sus cartitas de amor. + +[DIAB2_A] +¡Empecé mi negocio de entretenimiento exótico sin nada más que lo que cabía en mis pantalones de cuero! + +[LM5_9] +CHICAS: + +[PERPIC] +Paquetes ocultos encontrados + +[CO_ONE] +Paquete oculto ~1~ de ~1~ + +[LOVE3_3] +~g~La avioneta ha tirado ~1~ de los 6 paquetes. + +[FARE11] +~g~Ve a la ~w~zona en obras~g~ de Fort Staunton. + +[GA_21] +No puedes guardar más coches en este garaje. + +[CHEAT1] +Trucos activados + +[CHEAT2] +Arma trucada + +[CHEAT3] +Salud trucada + +[CHEAT4] +Armadura trucada + +[CHEAT5] +Busca y captura trucado + +[CHEAT6] +Dinero trucado + +[CHEAT7] +Clima trucado + +[AS1_H] +~r~¡No has llevado al escuadrón de la muerte hasta la trampa de la yakuza! + +[FEDS_BA] +Botón " - VOLVER + +[RAMP_A] +¡TODAS LAS MASACRES COMPLETADAS! + +[USJ_ALL] +¡TODAS LAS ACROBACIAS COMPLETADAS! + +[FARE23] +~g~Ve al ~w~taller de importación/exportación~g~ en el distrito de la presa Cochrane. + +[L_TRN_1] +Puedes coger el tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[L_TRN_2] +Puedes coger el tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[S_TRN_1] +Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[S_TRN_2] +Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[AS1_C] +Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty con el único fin de darte caza. + +[AS1_G] +~r~¡Todos los yakuza están muertos! + +[JAN] +Ene + +[FEB] +Feb + +[MAR] +Mar + +[APR] +Abr + +[MAY] +May + +[JUN] +Jun + +[JUL] +Jul + +[AUG] +Ago + +[SEP] +Sept + +[OCT] +Oct + +[NOV] +Nov + +[DEC] +Dic + +[DEFDT] +--:---:---- --:--:-- + +[BUGGY] +COCHES RESTANTES: + +[BONUS] +~g~~1~$ ADICIONALES + +[HORN1] +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. + +[HORN2] +Pulsa el ~h~botón L1~w~ para tocar el ~h~claxon. + +[HORN3] +Pulsa el ~h~botón R1~w~ para tocar el ~h~claxon. + +[LM3_1A] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. + +[LM3_1B] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. + +[LM3_1C] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. + +[RADIO_A] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[RADIO_B] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[RADIO_C] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[RADIO_D] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[FEC_EXV] +Entrar/salir de vehículo + +[TAXI_M] +'TAXISTA' + +[COP_M] +'JUSTICIERO' + +[FIRE_M] +'BOMBERO' + +[AMBUL_M] +'SANITARIO' + +[HJ_IS] +PREMIO POR ACROBACIA: ~1~$ + +[HJ_PIS] +PREMIO POR ACROBACIA PERFECTA: ~1~$ + +[HJ_DIS] +PREMIO POR ACROBACIA DOBLE: ~1~$ + +[HJ_PDIS] +PREMIO POR ACROBACIA DOBLE PERFECTA: ~1~$ + +[HJ_TIS] +PREMIO POR ACROBACIA TRIPLE: ~1~$ + +[HJ_PTIS] +PREMIO POR ACROBACIA TRIPLE PERFECTA: ~1~$ + +[HJ_QIS] +PREMIO POR ACROBACIA CUÁDRUPLE: ~1~$ + +[HJ_PQIS] +PREMIO POR ACROBACIA CUÁDRUPLE PERFECTA: ~1~$ + +[AM1_K] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (0~1~:~1~) + +[IMPEXPP] +Garaje de Importación/Exportación, puerto de Portland. Requerimos varios vehículos; revisa nuestro tablón de notas para saber más. + +[VANHSTP] +¿Quieres abrir algún Securicar? Llévalo a nuestro garaje en el puerto de Portland. + +[EMVHPUP] +Se compran vehículos de emergencia nuevos y usados a buen precio. Llévalos a la grúa que hay al noroeste del puerto de Portland. + +[STANDS] +PUESTOS DESTROZADOS: + +[STASH] +~g~¡Lleva el SPANK de vuelta a la ~p~zona en obras~g~! + [MCSTNS] No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. ¿Quieres empezar? (SÍ o NO) +[LOVE3_5] +~g~La avioneta está ahora a tu alcance. + +[LOVE3_6] +~r~¡La bofia ha llegado a los paquetes antes que tú! + +[SIREN_1] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. + +[SIREN_2] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. + +[FM3_8C] +Necesitaré 100.000 $ para cubrir gastos, + +[MCLOAD] +Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. + [FES_GME] Fallo al leer la Memory Card (PS2) de la ranura de MEMORY CARD 1. Compruébala e inténtalo de nuevo. +[FESZ_QF] +¿Seguro que quieres formatear la Memory Card (PS2) de la ranura de MEMORY CARD 1? + +[FESZ_LS] +Carga completada. + +[RM3_5] +~g~Tienes ~1~ de 6 paquetes de pruebas. + +[LOVE3_2] +~g~¡Tienes todos los paquetes! Llévaselos a Donald Love. + +[LOVE4_4] +~g~¡Lleva el paquete a Donald Love! + +[FEB_SAV] +Cargar + +[FEP_SAV] +CARGAR PARTIDA + +[AS2_12A] +~g~Cuando destruyas el primer puesto, ¡tendrás 8 mintutos antes que el cártel avise a sus camellos! + +[AS3_1A] +~g~¡Ahora ve a la ~b~boya señalada~g~! + [NOCONT] Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. -[NOCONTE] -Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. +{ Possibly unused } -[WRCONT] -El mando conectado al puerto de mando 1 es un mando no compatible. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). +[BET_JB] +TRAICIONADO POR SU AMANTE CATALINA Y DADO POR MUERTO. TRAS SER CONDENADO Y SENTENCIADO, INICIA SU VIAJE A LA PRISIÓN DE LIBERTY CITY. PERO SÓLO TIENE UN PENSAMIENTO... ¡VENGANZA! -[WRCONTE] -El mando conectado al puerto de mando 1 es un mando no compatible. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). +[END_A] +Los residentes de Cedar Groove todavía están asumiendo -{ =============================================================== } -{ ================= CONTROLS MENU, ACTIONS (PC) ================= } -{ =============================================================== } +[END_B] +las consecuencias emocionales provocadas -[FEC_FIR] -Disparar +[END_C] +por la guerra que estalló ayer en la zona. -[FEC_NWE] -Siguiente arma +[END_D] +Un residente local, Clive Denver, dijo a la policía -[FEC_PWE] -Arma anterior +[END_E] +que vio a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. -[FEC_FOR] -Avanzar +[END_F] +¿Sabes? Vamos a pasar un buen rato, porque, como sabes... -[FEC_BAC] -Retroceder +[END_G] +¡Te amo! Yo, yo, yo realmente te amo, porque eres superfuerte, -[FEC_LEF] -Izquierda +[END_H] +y eso es todo lo que necesito. -[FEC_RIG] -Derecha +[END_I] +Bueno, ¿qué estaba diciendo? -[FEC_ZIN] -Acercar zoom +[END_J] +Lo he olvidado. Pero me entiendes, ¿verdad? -[FEC_ZOT] -Alejar zoom +[END_K] +Las explosiones sacudieron las casas más próximas y a sus residentes. -[FEC_EEX] -Entrar /salir +[END_L] +Varios ciudadanos resultaron heridos a causa del tiroteo -[FEC_RAD] -Radio +[END_M] +entre las fuerzas terrestres y un helicóptero que rodeaba a la presa. -[FEC_HRN] -Claxon +[END_N] +Sí, en estos jardínes tuvimos una vista excelente. -[FEC_SUB] -Misión secundaria +[END_O] +Cuando el helicóptero estalló, -[FEC_CMR] -Cambiar cámara +[END_P] +fue mejor que los fuegos artificiales del 4 de julio. -[FEC_JMP] -Saltar +[END_Q] +El número de víctimas asciende a las veinte -[FEC_SPN] -Esprintar +[END_R] +mientras la policía sigue encontrando cuerpos. -[FEC_HND] -Freno de mano +[END_S] +No se han negado oficialmente los rumores -{ !!!!!!!!!!!!!!!!!! ACHTUNG! THIS STRING IS USED FOR BOTH THE MAP'S CURRENT TARGET AS WELL AS FOR THE ACTION OF TARGETING WITH A GUN! THIS WILL SCREW AROUND TRANSLATIONS !!!!!!!!!!!!!!! } -[FEC_TAR] -Objetivo +[END_T] +de que las víctimas eran miembros del cártel colombiano, -[FEC_TUL] -Torreta a izq. +[END_U] +y aún no hay pistas que aclaren las causas de la masacre. -[FEC_TUR] -Torreta a dcha. +[END_V] +Me he roto una uña y me pelo está hecho un asco, ¿puedes creerlo? -[FEC_TFU] -Torreta /Dodo arriba +[PAPER1] +CRIMINAL HERIDO DE BALA POR SU NOVIA Y CÓMPLICE; EL TRIBUNAL ENCUENTRA CULPABLE AL ATRACADOR CON UN VEREDICTO UNÁNIME. -[FEC_TFD] -Torreta /Dodo abajo +[PAPER2] +¡DIEZ AÑOS POR AMOR! -[FEC_LBA] -Mirar atrás +[END_W] +Me costó cincuenta dólares... -[FEC_LOL] -Mirar a izq. - -[FEC_LOR] -Mirar a dcha. - -[FEC_NA] -No disponible - -{ ============================================================================ } -{ ================= CONTROLS MENU, ACTIONS, UNKNOWN LOCATION ================= } -{ ============================================================================ } - -[FEC_CLE] -Arma de la izquierda - -[FEC_CRI] -Arma de la derecha - -[FEC_MOV] -Movimiento - -[FEC_CAM] -Cambiar cámara - -[FEC_PAS] -Pausa - -[FEC_ENV] -Entrar en vehículo - -[FEC_RUN] -Correr - -[FEC_LL] -Mirar a la izquierda - -[FEC_LR] -Mirar a la derecha - -[FEC_LB] -Mirar atrás - -[FEC_RSC] -Cambiar emisora de radio - -[FEC_BRA] -Freno o marcha atrás - -[FEC_ACC] -Acelerar - -[FEC_SMT] -Activar misión especial - -[FEC_EXV] -Entrar/salir de vehículo +[FEB_CPC] +Configuración de controles [FEC_PED] Controles a pie @@ -7266,6 +7003,12 @@ Mirar hacia atrás [FEC_PFR] Disparar arma +[FEC_CLE] +Arma de la izquierda + +[FEC_CRI] +Arma de la derecha + [FEC_LKT] Fijar objetivo @@ -7314,6 +7057,9 @@ Mirar a la izq. en vehículo [FEC_LRG] Mirar a la dch. en vehículo +[FEC_HRN] +Claxon + [FEC_HBR] Freno de mano del vehículo @@ -7335,6 +7081,9 @@ Entrar /salir de vehículo [FEC_WPN] Disparar arma +[FEC_PAS] +Pausa + [FEC_FPO] Armas en primera persona @@ -7347,965 +7096,8 @@ Cambiar cámara en todas las situaciones [FEC_TSS] Capturar pantalla -[FEC_NTR] -Siguiente objetivo - -[FEC_PTT] -Objetivo anterior - -[FEC_CEN] -Centrar cámara - -[FEC_UND] -(NO) - -[FET_CFT] -A PIE - -[FET_CCR] -EN VEHÍCULO - -[FEC_TFL] -Torreta a izq. - -[FEC_TFR] -Torreta a dcha. - -[FEC_ORR] -o - -[FEC_NUS] -SIN USO - -[FEC_LUD] -Mirar arriba - -[FEC_LDU] -Mirar abajo - -{ ======================================================================================= } -{ ================= CONTROLS MENU, ACTIONS (REMNANTS FROM CONSOLE, PS2) ================= } -{ ======================================================================================= } - -[FEC_CWL] -Siguiente arma - -[FEC_CWR] -Arma anterior - -[FEC_LOF] -Mirar hacia delante - -[FEC_PAU] -Pausa - -[FEC_JUM] -Saltar - -[FEC_ATT] -Atacar o disparar - -[FEC_FPC] -Cámara en primera persona - -[FEC_VES] -Controlar vehículo - -[FEC_TUC] -Controlar torreta - -[FEC_SM3] -Activar misión secundaria (botón R3) - -[FEC_RS3] -Cambiar emisora de radio (botón L3) - -[FEC_HOR] -Claxon - -[FEC_HO3] -Claxon (botón L3) - -[FEC_LB3] -Mirar atrás - -[FEC_R3] -(botón R3) - -[FEC_LB1] -Mirar - -[FEC_LB2] -atrás - -[FEC_CAW] -Arma del vehículo - -[FEC_HAB] -Freno de mano - -{ ================================================================== } -{ ================= DEBUG STRINGS (CAN BE IGNORED) ================= } -{ ================================================================== } - -[FEC_DBG] -MENÚ DE DEPURACIÓN - -[FED_DBG] -Menú de depuración - -[FED_RID] -Recargar IDE - -[FED_RIP] -Recargar IPL - -[FED_PAH] -Analizar pila - -[FED_RCD] -CCullZones::RecalculateCullZoneData - -[FED_DFL] -CTheScripts::DbgFlag - -[FED_DLS] -Cambiar luz blanca grande de depuración - -[FED_SPR] -Mostrar grupos de peatones en carretera - -[FED_SCR] -Mostrar grupos de vehículos en carretera - -[FED_SCZ] -Mostrar zonas de máscara selectiva - -[FED_DSR] -Solicitudes de depuración de streaming - -[FED_SCP] -gbShowCollisionPolys - -[FEM_MCM] -Menú de Memory Card - -[FEM_RMC] -Registrar MemCard uno - -[FEM_TFM] -Probar MemCard uno formateada - -[FEM_TUM] -Probar Memcard uno sin formato - -[FEM_CRD] -Crear directorio raíz - -[FEM_CLI] -Crear y cargar iconos - -[FEM_FFF] -Llenar primer archivo con basura - -[FEM_SOG] -Guardar sólo partida - -[FEM_CES] -Comprobar cada guardado de 0kB4 - -[FEM_STG] -Guardar partida - -[FEM_STS] -Guardar partida bajo el nombre GTA3 - -[FEM_CPD] -Crear copia protegida del directorio mag - -[FEM_MC2] -Menú de Memory Card 2 - -[FEM_TS] -Prueba de guardado: - -[FEM_TL] -Prueba de carga: - -[FEM_TD] -Prueba de borrado: - -[RELIDE] -ReLoadIde - -[RELIPE] -ReLoadIpl - -[PARSHP] -Analizar pila - -[DBGFON] -CTheScripts::DbgFlag activado - -[DBFOFF] -CTheScripts::DbgFlag desactivado - -[BGWHON] -Luz blanca grande de depuración activada - -[BGWOFF] -Luz blanca grande de depuración desactivada - -[DSTRON] -Solicitudes de depuración de streaming activadas - -[DSTROFF] -Solicitudes de depuración de streaming desactivadas - -[PDRGON] -ShowPedRoadGroups activado - -[PRGOFF] -ShowPedRoadGroups desactivado - -[CRRGON] -ShowCarRoadGroups activado - -[CRGOFF] -ShowCarRoadGroups desactivado - -[CLZOON] -Zonas de máscara selectiva mostradas - -[CLZOOF] -Zonas de máscara selectiva ocultadas - -[SHPLON] -gbShowCollisionPolys activado - -[SHPLOF] -gbShowCollisionPolys desactivado - -[CULREC] -CCullZones::RecalculateCullZoneData() - -[FORMM1] -FormatMemCard 1 (prueba) - -[UNFRM1] -UnFormatMemCard 1 (prueba) - -[MEMTST] -Pantalla MemoryCardTest - -[REGCAR] -Registrar MemoryCard uno - -[TEFONE] -Probar MemCard uno con formato - -[TEUFON] -Probar MemCard uno sin formato - -[CRROOT] -CreateRootDir - -[CRLDIC] -Crear y cargar iconos - -[FLFSGF] -Llenar el primer archivo con basura - -[PUSAVE] -Guardar sólo la partida - -[CHEVOK] -CheckEveryOkB4Save - -[SVGMON] -SaveTheGame - -[CRMGSV] -Crear directorio de cargador con protección de copia - -[MGSVCN] -MagazineDirectory creado - -[MGSVNC] -MagazineDirectory no creado - -{ ======================================================================================================= } -{ ================= INGAME PLAYER STATISTICS. BE CAREFUL WITH WIDTH LIMITS IN 4:3 RATIO ================= } -{ ======================================================================================================= } - -{ ARTICLE ADDED BETWEEN NUMBERS } - -[FEST_OO] -de - -[PL_STAT] -Estadísticas de jugador - -[PE_WAST] -Personas asesinadas - -[PE_WSOT] -Personas asesinadas por otros - -[CAR_EXP] -Coches reventados - -[TM_BUST] -Veces arrestado - -[M_WASTE] -Hombres civiles asesinados - -[F_WASTE] -Mujeres civiles asesinadas - -[PIG_WST] -Polis asesinados - -[GNG_WST] -Maleantes asesinados - -[MED_WST] -Médicos asesinados - -[FIRE_WS] -Bomberos asesinados - -[DED_CRI] -Criminales asesinados - -[DED_DED] -Vagabundos asesinados - -[DED_HOK] -Prostitutas asesinadas - -[HEL_DST] -Helicópteros destruidos - -[PER_COM] -Porcentaje completado - -[KGS_EXP] -Kgs de explosivos empleados - -[ACCURA] -Precisión de tiro - -[ELBURRO] -Mejor tiempo de ''Turismo'' en segundos - -[CAR_CRU] -Coches destrozados - -[HED_EX] -Cabezas explotadas - -[TM_DED] -Visitas al hospital - -[DAYSPS] -Días de juego transcurridos - -[MMRAIN] -mm de lluvia caídos - -[MXCARD] -Dist. máx. de salto acrobático (pies) - -[MXCARJ] -Altitud máx. de salto acrobático (pies) - -[MXCARDM] -Dist. máx. de salto acrobático (metros) - -[MXCARJM] -Altitud máx. de salto acrobático (metros) - -[MXFLIP] -Vueltas durante salto acrobático - -[MXJUMP] -Rotación máx. de salto acrobático - -[BSTSTU] -Mejor acrobacia hasta ahora: - -[INSTUN] -Acrobacia - -[PRINST] -Acrobacia perfecta - -[DBINST] -Acrobacia doble - -[DBPINS] -Acrobacia doble perfecta - -[TRINST] -Acrobacia triple - -[PRTRST] -Acrobacia triple perfecta - -[QUINST] -Acrobacia cuádruple - -[PQUINS] -Acrobacia cuádruple perfecta - -[NOSTUC] -No se han hecho acrobacias - -[NOUNIF] -Saltos únicos completados - -[NOUNGM] -Saltos únicos - -[NMISON] -Misiones intentadas - -[NMMISP] -Misiones superadas - -[PASDRO] -Pasajeros transportados - -[MONTAX] -Dinero conseguido en taxi - -[DAYPLC] -Gasto diario de la policía - -[FEST_HA] -Nivel más alto de misión de sanitario - -[FEST_DF] -Distancia recorrida a pie (millas) - -[FEST_DC] -Distancia recorrida en coche (millas) - -[FESTDFM] -Distancia recorrida a pie (metros) - -[FESTDCM] -Distancia recorrida en coche (metros) - -[FEST_R1] -''Patio de recreo'' en segundos - -[FEST_R2] -''Un paseo por el parque'' en segundos - -[FEST_R3] -''¡Agarrado!'' en segundos - -[FEST_RM] -''Caos en el aparcamiento'' en segundos - -[FEST_LS] -Gente salvada con una ambulancia - -[FEST_CC] -Criminales asesinados en misiones de justiciero - -[FEST_FE] -Incendios extinguidos - -[FEST_LF] -Vuelo más largo en Dodo - -[FEST_BD] -Mejor tiempo al desactivar la bomba - -[FEST_RP] -Masacres superadas - -[FEST_MP] -Misiones superadas - -[FEST_BB] -Carrera forrada: - -[FEST_H0] -Máximo de puntos de control - -[FEST_GC] -Coches de bandas destruidos: - -[FEST_H1] -Destrucción de los Diablos - -[FEST_H2] -La masacre de la mafia - -[FEST_H3] -Calamidad en el casino - -[FEST_H4] -Exterminio de Rumpos - -[PERPIC] -Paquetes ocultos encontrados - -[CRIMRA] -Rango de criminal: - -{ ==================================================== } -{ ================= CRIMINAL RATINGS ================= } -{ ==================================================== } - -[RATNG1] -Carterista - -[RATNG2] -Abusón - -[RATNG3] -Chorizo - -[RATNG4] -Granuja - -[RATNG5] -Secuaz - -[RATNG6] -Conductor - -[RATNG7] -Guardaespaldas - -[RATNG8] -Negociador - -[RATNG9] -Socio - -[RATNG10] -Sicario - -[RATNG11] -Asesino - -[RATNG12] -Mano derecha - -[RATNG13] -Verdugo - -[RATNG14] -Capo - -[RATNG15] -Jefe - -{ =========================================================== } -{ ================= PAUSE MENU OPTIONS (PC) ================= } -{ =========================================================== } - -[FEP_STA] -ESTADÍSTICAS - -[FEP_BRI] -RESUMEN - -[FEP_CON] -CONTROLES - -[FEP_AUD] -SONIDO - -[FEP_DIS] -PANTALLA - -[FEP_LAN] -IDIOMA - -{ ============================================================= } -{ ================= MIXED BAG OF MENU OPTIONS ================= } -{ ============================================================= } - -[GMSTOR] -Almacenar partida - -[PREBRF] -Resúmenes anteriores - -[CNTLS] -Controles - -[MUSMEN] -Música/Efectos - -[GAMSET] -Ajustes del juego - -[LANGUA] -Idioma - -[DSPLAY] -Pantalla - -[DEBUGM] -Menú de depuración - -[QUITOP] -Salir de las opciones - -[CONTRL] -Configuración de controles - -[SET1EN] -Ajuste 1. Activado - -[SET1] -Ajuste 1. - -[SET2EN] -Ajuste 2. Activado - -[SET2] -Ajuste 2 - -[SET3EN] -Ajuste 3. Activado - -[SET3] -Ajuste 3 - -[SET4EN] -Ajuste 4. Activado - -[SET4] -Ajuste 4 - -[GOBACK] -Volver - -[SOUND] -SONIDO - -[MUSVOL] -Volumen de la música - -[SFXVOL] -Volumen de los efectos - -[SCROPT] -OPCIONES DE PANTALLA - -[CTRSCR] -Centrar pantalla - -[SCRFOR] -Formato de imagen - -[GMSVLQ] -GUARDAR-CARGAR-SALIR - -[GMREST] -Reiniciar partida - -[NOGMSV] -Sólo puedes guardar desde tu escondite. - -[DLFILE] -Borrar archivos de Grand Theft Auto III - -[CHFILE] -ELEGIR ARCHIVO A CARGAR - -[CHCDLD] -ELEGIR MEMORY CARD A USAR - -[CHFIDL] -ELEGIR ARCHIVO A BORRAR - -[CDUNFR] -Memory Card sin formato. - -[SVCONF] -CONFIRMACIÓN - -[SVFNAM] -El nombre de tu archivo guardado es - -[SAVEDN] -Error. Fallo al guardar. - -[LANGSL] -SELECCIÓN DE IDIOMA - -[GORLEV] -Nivel de violencia - -[SICASS] -Puta locura - -[SICSIC] -Puto manicomio - -[SCASSL] -Seleccionado Puta locura - -[SCSCSL] -Seleccionado Puto manicomio - -[DOSVGM] -¿Deseas guardar la partida? - -[FORMEN] -Menú de formato - -[CNTSAV] -No se puede guardar la partida en una misión. - -[CNCSAV] -No se puede guardar la partida dentro de un vehículo. - -[YES] -Sí - -[NO] -No - -[X] -x - -[LAST] -Último mensaje - -[FIRST] -~g~1.° - -[SECOND] -~g~2.° - -[THIRD] -~g~3.° - -[FOURTH] -~g~4.° - -[WRONGCD] -Disco incorrecto. Introduce el disco correcto. - -[NOCD] -La bandeja del disco está vacía. Introduce un disco. - -[OPENCD] -La bandeja del disco está abierta. Cierra la bandeja de disco. - -[CDERROR] -Error al leer el DVD de Grand Theft Auto III - -[RESTART] -Empezando una nueva partida - -[STOCK] -mercancía agotada - -[BAT1] -~g~¡Coge el bate! - -[FE_INIP] -Iniciando y cargando el menú de pausa... Espera, por favor. - -[FESZ_CA] -Cancelar - -[FESZ_QU] -Abandonar - -[FESZ_L1] -¡La partida se ha guardado! - -[FESZ_L2] -El nombre guardado es: - -[FESZ_OK] -ACEPTAR - -[FES_CAN] -Cancelar - -[FESZ_QL] -Perderás todo el progreso en tu partida actual. ¿Quieres continuar con la carga? - -[FESZ_QD] -¿Quieres borrar esta partida guardada? - -[FESZ_QO] -¿Quieres sobreescribir esta partida guardada? - -[FESZ_QR] -¿Seguro que quieres empezar una nueva partida? Perderás todo el progreso desde la última partida guardada. - -[FESZ_QS] -¿QUIERES GUARDAR? - -[UPSIDE] -~r~¡Has volcado! - -[1010] -~r~Tu vehículo ha volcado - -[1011] -~r~Tu vehículo ha volcado - -[1012] -~r~Tu vehículo ha volcado - -[1013] -~r~Tu vehículo ha volcado - -[1014] -~r~Tu vehículo ha volcado - -[DETON] -DETONACIÓN: - -[RECORD] -~g~¡NUEVO RÉCORD! - -[NRECORD] -~r~¡NO HAY UN NUEVO RÉCORD! - -[WELCOME] -BIENVENIDO A - -[TSCORE] -GANANCIAS: ~1~ $ - -[FESZ_UC] -CANCELAR - -[FES_LOF] -Fallo al cargar. - -[MC_LDFL] -¡Fallo al cargar! - -[MC_NWRE] -Reiniciando partida. - -{ ============================================================================================== } -{ ================= STRINGS RELATED TO VEHICLE STUNTS (NOT INCLUDING THE DODO) ================= } -{ ============================================================================================== } - -[HJSTAT] -Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. - -[HJSTATW] -Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! - -[HJSTATF] -Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. - -[HJSTAWF] -Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! - -[USJ_ALL] -¡TODAS LAS ACROBACIAS COMPLETADAS! - -[USJ] -¡PREMIO POR ACROBACIA ÚNICA! - -[HJ_IS] -PREMIO POR ACROBACIA: ~1~$ - -[HJ_PIS] -PREMIO POR ACROBACIA PERFECTA: ~1~$ - -[HJ_DIS] -PREMIO POR ACROBACIA DOBLE: ~1~$ - -[HJ_PDIS] -PREMIO POR ACROBACIA DOBLE PERFECTA: ~1~$ - -[HJ_TIS] -PREMIO POR ACROBACIA TRIPLE: ~1~$ - -[HJ_PTIS] -PREMIO POR ACROBACIA TRIPLE PERFECTA: ~1~$ - -[HJ_QIS] -PREMIO POR ACROBACIA CUÁDRUPLE: ~1~$ - -[HJ_PQIS] -PREMIO POR ACROBACIA CUÁDRUPLE PERFECTA: ~1~$ - -{ ================================================ } -{ ================= DATE STRINGS ================= } -{ ================================================ } - -[JAN] -Ene - -[FEB] -Feb - -[MAR] -Mar - -[APR] -Abr - -[MAY] -May - -[JUN] -Jun - -[JUL] -Jul - -[AUG] -Ago - -[SEP] -Sept - -[OCT] -Oct - -[NOV] -Nov - -[DEC] -Dic - -[DEFDT] ---:---:---- --:--:-- - -[BUGGY] -COCHES RESTANTES: - -[BONUS] -~g~~1~$ ADICIONALES - -[STANDS] -PUESTOS DESTROZADOS: - -{ ======================================================= } -{ ================= PC SPECIFIC STRINGS ================= } -{ ======================================================= } - -[FESZ_LS] -Carga completada. - -[FEP_SAV] -CARGAR PARTIDA - +[FEN_STA] +INICIAR PARTIDA [FEN_NET] Red @@ -8384,6 +7176,9 @@ Staunton [FEC_EMS] Sólo se permiten teclas del teclado. +[FEC_DBG] +MENÚ DE DEPURACIÓN + [FEC_TGD] Cambiar mando de juego/depuración @@ -8393,6 +7188,18 @@ Desactivar cámara de depuración [FEC_IVH] Invertir horizontalidad ratón +[FEC_MSL] +BIR + +[FEC_MSM] +BCR + +[FEC_MSR] +BDR + +[FEC_QUE] +¿? + [FEC_TWO] Sólo se permiten dos teclas del teclado. @@ -8417,6 +7224,9 @@ Usar Fijar objetivo con Arma anterior. [FEC_LBC] Usar Mirar a izq. con Mirar a la dcha. +[FEC_JBO] +JOY ~1~ + [NO_PAUZ] No se puede parar una partida multijugador. ¡Pulsa dos veces para salir! @@ -8525,24 +7335,6 @@ TIPO DE JUEGO [FET_CTL] AJUSTES DEL MANDO -[FET_CT1] -VER CONTROLES - -[FET_CT2] -CONTROLES A PIE - -[FET_CT3] -CONTROLES EN VEHÍCULO - -[FET_CT4] -STICK PARA CONDUCIR - -[FET_CT5] -GIRAR AL INCLINAR - -[FET_CT6] -STICK PARA ZURDOS - [FET_OPT] OPCIONES @@ -8675,6 +7467,9 @@ Volante [FEC_CNT] Tipo de mando: +[FET_APL] +APLICAR + [FES_CSA] Selecciona una apariencia: @@ -8702,6 +7497,87 @@ Espacios de partida disponibles: [FES_LCG] ¿Cargar partida y seguir jugando? +[FEC_FIR] +Disparar + +[FEC_NWE] +Siguiente arma + +[FEC_PWE] +Arma anterior + +[FEC_FOR] +Avanzar + +[FEC_BAC] +Retroceder + +[FEC_LEF] +Izquierda + +[FEC_RIG] +Derecha + +[FEC_ZIN] +Acercar zoom + +[FEC_ZOT] +Alejar zoom + +[FEC_EEX] +Entrar /salir + +[FEC_RAD] +Radio + +[FEC_SUB] +Misión secundaria + +[FEC_CMR] +Cambiar cámara + +[FEC_JMP] +Saltar + +[FEC_SPN] +Esprintar + +[FEC_HND] +Freno de mano + +[FEC_TUL] +Torreta a izq. + +[FEC_TUR] +Torreta a dcha. + +[FEC_LOL] +Mirar a izq. + +[FEC_LOR] +Mirar a dcha. + +[FEC_NTR] +Siguiente objetivo + +[FEC_PTT] +Objetivo anterior + +[FEC_LBA] +Mirar atrás + +[FEC_CEN] +Centrar cámara + +[FEC_UND] +(NO) + +[FET_CFT] +A PIE + +[FET_CCR] +EN VEHÍCULO + [CVT_MSG] Convirtiendo texturas a un formato óptimo para tu tarjeta de vídeo @@ -8711,6 +7587,15 @@ ACCIÓN [FEC_IBT] - +[FEC_SPC] +ESPACIO + +[FEC_MXO] +MXB1 + +[FEC_MXT] +MXB2 + [FEC_UNB] SIN ASIGNAR @@ -8735,39 +7620,17 @@ CONFIGURACIÓN DE CONTROL CON RATÓN [FET_DAM] MODELADO ACÚSTICO DINÁMICO -[FEC_CMP] -COMBO: MIRAR I+D +[FEC_TFL] +Torreta a izq. -[FEC_NTT] -No hay texto para esta tecla +[FEC_TFR] +Torreta a dcha. -{ ==================================================================================== } -{ ================= PC SPECIFIC STRINGS - AVAILABLE KEYS AND BUTTONS ================= } -{ ==================================================================================== } +[FEC_TFU] +Torreta /Dodo arriba -[FEC_MSL] -BIR - -[FEC_MSM] -BCR - -[FEC_MSR] -BDR - -[FEC_QUE] -¿? - -[FEC_JBO] -JOY ~1~ - -[FEC_SPC] -ESPACIO - -[FEC_MXO] -MXB1 - -[FEC_MXT] -MXB2 +[FEC_TFD] +Torreta /Dodo abajo [FEC_MWF] RUEDA ARR. @@ -8775,6 +7638,24 @@ RUEDA ARR. [FEC_MWB] RUEDA AB. +[FEC_ORR] +o + +[FEC_NUS] +SIN USO + +[FEC_LUD] +Mirar arriba + +[FEC_LDU] +Mirar abajo + +[FEC_CMP] +COMBO: MIRAR I+D + +[FEC_NTT] +No hay texto para esta tecla + [FEC_FNC] F~1~ @@ -8877,12 +7758,6 @@ WIN DCHO [FEC_WRC] APMENÚ -[FEC_STR] -NUM. INICIO - -[FEC_SFT] -MAYÚS - [WIN_TTL] Grand Theft Auto III @@ -8895,6 +7770,9 @@ Grand Theft Auto III necesita al menos la versión 8.1 de DirectX [WIN_VDM] Grand Theft Auto III necesita al menos 12 MB de memoria de vídeo +[DIAB3_G] +¡Arriba! + [FEM_RES] REANUDAR PARTIDA @@ -8952,6 +7830,9 @@ RESOLUCIÓN [FED_WIS] PANTALLA PANORÁMICA +[FEDS_TB] +ATRÁS + [FEA_MUS] VOLUMEN DE MÚSICA @@ -8997,18 +7878,14 @@ NO HAY HARDWARE DE SONIDO [FET_SNG] INICIAR NUEVA PARTIDA -[FEN_STA] -INICIAR PARTIDA - -[GMLOAD] -CARGAR PARTIDA - [GMSAVE] GUARDAR PARTIDA [FES_DGA] BORRAR PARTIDA +{ STRING MISSING FROM THE OFFICIAL SPANISH TRANSLATION. } + [FEM_NON] NADA @@ -9033,9 +7910,6 @@ Fantasma [WIN_RSZ] Error al seleccionar la nueva resolución de pantalla -[FET_APL] -APLICAR - [FET_APP] BIR, INTRO: APLICAR AJUSTES @@ -9045,6 +7919,9 @@ AJUSTES PREDETERMINADOS RESTAURADOS [FET_MST] CONDUCCIÓN CONTROLADA POR EL RATÓN +[FEC_STR] +NUM. INICIO + [FET_MIG] IZQUIERDA, DERECHA, RUEDA DEL RATÓN: AJUSTAR @@ -9066,30 +7943,27 @@ Te has quedado sin espacio en el disco duro. Por favor, libera espacio en tu dis [FED_SUB] SUBTÍTULOS -[FED_SHD] -SOMBRAS DINÁMICAS - -[FED_VET] -EFECTOS VISUALES - -[FED_VT0] -BAJO - -[FED_VT1] -MEDIO - -[FED_VT2] -ALTO - -[FED_VT3] -MÁXIMO - [FET_DSN] Apariencia predeterminada del jugador.bmp +[JM3] +'EL ROBO DE LA FURGONETA' + +[EBAL] +'DAME LIBERTAD' + +[LM4] +'UN CHULO Y SU ESCOPETA' + [REPLAY] REPETICIÓN +[FEC_SFT] +MAYÚS + +[CRED254] +JEFE DEL ESTUDIO + [CVT_CRT] No se pueden convertir las texturas para tu tarjeta de vídeo. Necesitas privilegios de administrador. Pulsa ESC para salir. @@ -9126,217 +8000,8 @@ SE HAN REINICIADO LOS AJUSTES [FET_RSC] HARDWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL -{ ========================================================= } -{ ================= CHEAT-RELATED STRINGS ================= } -{ ========================================================= } - -[CARSOFF] -Coches activados. - -[CARS_ON] -Coches desactivados. - -[TEXTXYZ] -Escribiendo coordenadas al archivo... - -[CHEATON] -Trucos ACTIVADOS - -[CHEATOF] -Trucos DESACTIVADOS - -[CHEAT1] -Trucos activados - -[CHEAT2] -Arma trucada - -[CHEAT3] -Salud trucada - -[CHEAT4] -Armadura trucada - -[CHEAT5] -Busca y captura trucado - -[CHEAT6] -Dinero trucado - -[CHEAT7] -Clima trucado - -{ ========================================================================================= } -{ ================= MIXED BAG ================= } -{ ========================================================================================= } - -[OUT_VEH] -~g~¡Sal del vehículo! - -[WANTED1] -~g~¡Despista a la poli! - -[NODOORS] -~g~¡No son sardinas! Consigue un vehículo con suficientes asientos. - -[TRASH] -~g~¡Has dejado tu vehículo hecho unos zorros! ¡Haz que lo reparen! - -[WRECKED] -~r~¡El vehículo está destrozado! - -[HORN] -~g~Toca el claxon. - -[NOMONEY] -~g~¡Necesitas más pasta! - -[OUTTIME] -~r~¡Demasiado lento, tío, demasiado lento! - -[SPOTTED] -~r~¡Te siguen la pista! - -[REWARD] -RECOMPENSA: $~1~ - -[GAMEOVR] -FIN DE LA PARTIDA - -[Z] -Valor del eje Z: ~1~ - -[M_FAIL] -¡MISIÓN FRACASADA! - -[M_PASS] -¡MISIÓN SUPERADA! $~1~ - -[O_PASS] -¡TRABAJO ESPORÁDICO SUPERADO! - -[O_FAIL] -¡TRABAJO ESPORÁDICO FRACASADO! - -[DEAD] -¡LIQUIDADO! - -[BUSTED] -¡TRINCADO! - -[KABOOM] -¡BUUUM! - -[SPLAT] -¡PLOF! - -[PANCAK] -¡APLASTADO! - -[SOAKED] -¡AGUADO! - -[NUMBER] -~1~ - -[SCORE] -~1~$ - -[LOADCAR] -CARGANDO VEHÍCULO... (PULSA EL BOTÓN L1 PARA CANCELAR) - -[IMPORT1] -Sal y espera a tu vehículo. - -[LUIGIS] -Club de Luigi - -[DODO_FT] -¡Volaste durante ~1~ segundos! - -[WEATHER] -FORZAR EL CLIMA - -[WEATHE2] -CLIMA NORMAL - -[8001] -¡Has fallado miserablemente! - -[1000] -HAS MUERTO - -[1001] -HAS MUERTO - -[1002] -HAS MUERTO - -[1003] -HAS MUERTO - -[1004] -HAS MUERTO - -[1005] -TRINCADO - -[1006] -TRINCADO - -[1007] -TRINCADO - -[1008] -TRINCADO - -[1009] -TRINCADO - -[PU_MONY] -No tienes suficiente dinero. - -[CO_ALL] -Te has hecho con todos. Toma un detallito... - -[PAUSED] -PARTIDA EN PAUSA - -[HEALTH1] -¡Largo! Estás completamente sano. - -[HEALTH2] -La sanidad cuesta dinero. - -[HEALTH3] -Te pondré como nuevo. - -[HEALTH4] -Te va a costar 250 $. - -[BET_JB] -TRAICIONADO POR SU AMANTE CATALINA Y DADO POR MUERTO. TRAS SER CONDENADO Y SENTENCIADO, INICIA SU VIAJE A LA PRISIÓN DE LIBERTY CITY. PERO SÓLO TIENE UN PENSAMIENTO... ¡VENGANZA! - -[USJI1] -SOBRAS - -[USJI2] -SOBRAS - -[USJI3] -SOBRAS - -[CINCAM] -Vista cinematográfica - -[LITTLE] -LITTLE T - -[NICK] -NICK LOVE - -[CO_ONE] -Paquete oculto ~1~ de ~1~ +[CRED270] +MIKE HONG { re3 updates } { new languages } From 66fc4e44fc25eeec3da8224e3cf5bc1a78bbd06b Mon Sep 17 00:00:00 2001 From: IlDucci Date: Thu, 3 Dec 2020 11:32:17 +0100 Subject: [PATCH 129/129] Fixing the Ghost vehicle name. --- gamefiles/TEXT/spanish.gxt | Bin 236540 -> 236534 bytes utils/gxt/spanish.txt | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 2adca1651c0769d0a36682d475008765c7395e80..7321c2ccefaf9707cfbfe07930b2aee512c3b2b2 100644 GIT binary patch delta 712 zcmXw%OK1~O6o${4#7AvYYiS+Rht&o#g0YE7p*mGeGM$oeCrRhVrubkMKCpzMQWX=l zP+Am4sBm^FV%?}+SqBUvB8VUcEiOguMnv5B0v`yiILX{DF8rMHo&Uf0au!PUzf1M^ z@3!E2y4Ug)zteE*bT$y(Fa;l>#&wBf}Hd`5pa-@zD7`+eS-Ru^b} zaWkp*!K5U#o`Lr?@0Ss*U;Ylax6!t$KwQhhhkufz`;$zYdmmB@*MV7Ak~aU zIXs{rT{51dnxHaLl%2ZDa`0{oRvDEWa7FN1g2Cq{%{bf^JX3SV`eg%fhM6dX$GCNxLw9;)ErjqfPruqUZwG{>^;y@vD3{2XYi`d(JZY( zk!HhFI7!in>}{xCT{rb~3~tprjQ!t`q?2}665W)c!|v+ibu+DL&_mM^8H4mFqIh~l z3Xf~>ld$`nr$}5U6nU(_SU->1?iKW=)l+;3K_O zx^OEkDn7fru~)%4I@l}Y2|C?7vFU81LmG*GcvD@ItZC>RF0T`H9*30GzH4<8p0NT0 zQ#Dw&p6q+P3RSCc#J5~pXtr+V=j!o-HBzi~V{xJ|cCj#q_K`}3G1vKqntnJ2$6*vs Lm6lDp{?z>kLC?j6 delta 718 zcmXw%O=uHQ5XWbdQu~!ui_JD^OVudGLz<*X1>IUmv)!8Twn_8WCMdF0QK+SYRE3C! z)(WDC6$iWs(t5GpTHYawibp?C=|MaQ_0XgEfuI$|s+;Wg@E(6=e)FGsk6A6b|CHPd z^FG{8_kB-sl}1}{yHt-862rQY$m&odHnnwB;ev>4dA0$c)32TPa6ioj{N9CDC#d}i zBc=4iC5NrG46M*{K*DPABhXRhZ85FN5Lb0r`RlOsKnj*9807d^Oa+fRTqnF`NHOAZ z4iD&CNWzO$8B`dD59K7F!6-MD%xM}lhlEIgC%{a{4JX3P;XIt&hRB zc3Z1?(Cu0+nSoAP3`-cJ7hyl<>2sK46U8G^gu(t@_l(oiM8%ACw>>BdnOQvX?d^TTnLmocG3ZP%oS)Z_tXuA55h-! zEr+m+)?~k#-P$ALTRPk$;aNJp2Bb(j)`WBzJ~!z1pDy>a6;F@CPT3MZ!v#mj{vn#WNp6rC3~HmWcJC*ibt PPrx{gl>S|J{%rUU0EEa? diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index db38d036..bba7091c 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -7905,7 +7905,7 @@ CONTROL: ESTÁNDAR USAR APARIENCIA [GHOST] -Fantasma +Ghost [WIN_RSZ] Error al seleccionar la nueva resolución de pantalla

wa#dAgP@G zC)x0)OQGz+(j$52^m@FpTJ14=SJVBa{lO!>^-W~soOwcH?g>WD7DB;T{XM+dp>A&;DfbB;-bO>Cnh1iGka$t$^}^(V@h1 zi56*Gejl+ykl<{QAj#6Yw1&Gqn)ozSWM?g{H=2$=KUnzvPSx(5Y2!D%4i3cw!(U@+ zjo6)U7+IujukzrJ%!B^tamQwQ^y-nb-Hg^l%n#P9sE zk`pb6KS|sCWu!GE*a&)PjKP4^41SYU;$|`I?%o6VL3%72y;|;g-za zgW;*!QP}$S6Js5=Gj?b8NakIg-Fx!xLq>YJF|`wP&d7L)o?#5?($dg^%#;snz|5s+ zS#;mrap+~9%oL-F<(-rt|3z_YWD#T!&T73-R>8_)?~`S_eGYa;jkRsUA}HGuL4!TU zK`q~canOUzGqdwM8WZJbzIe8j=slK+tJrH0|GeywR%<0E?iv?cK8c;%h8iVi`gW}w z&madWu#S<(rVY?H7HCxz4?6M+lH*V$MJn+HyB1)k0Hr!(9!*4bqBXi23&5T51tuG- zQ3Q$FtDth;1q@Gy1lr%Q3u8l_@$oDfp;PLAd7&$(MT0kB+1qnman#4v8;_8&$9H-% zxT2L{O~*MI4ZMhUo6*3s&>Q`a+{bFMh&fz$5@zIwn!7DKc%K|Izi&2;C+Sht7W~Gm zNFiu!>_*@YVe{92T_n?5LZT#P{ULtyMwRW^$m43AZECY?WG+bW@_YI+;y*91*c^FS zPoXERCeh5z@CwGo-qqC3$l*3xWRJ#+_kLcj9^N_no2G@WwAF`OEGhn)rCgUQ^M1>< z&TBwUgu08c%sWNnd^9D>ibuOnx);yvklK)38_9 z&(@B9eJv+~X;~fC+20fe*X3{Thsr+PKUrxu#1oTchu*+2(SML9YtsWWx6vXynD0Tn z$|kG=ep>N^*ef;~LCj!}&zQTHz&z?VH_aoUkGi zU=1{lZi=r(WZlcYyEzi4(SXb_o$kTyWascIkzIDOM}jSjma15_QA{p6coaKGF0gf% z_7D1l&MkRk=>GOeD3ZVvvM@ezY@a7?53t?Se(2U*ycUtdmyURiJ9c9aTBHbJl>4VD zsoaf{!sGfZmNR>8E+>mMY#dszb6WFGWGD&KO*(i?WeIRp>(Gh#fX^=kJCo0Y6`Q4!0T<=Ly+8l0spnG&h?zcT{YjP|u zI!eMcJEOtXUEQ8}BdTz^wMUd1Lq1p8a`MVUdfl_^2BZn{CEF6uN$aypG;=SRq``%C z^!43IEACdi>-FP#-W)7z4<4+=gN!Tpa*eYKv8!=HaB#*wDgB0%$Mq?@!gqg*ZOWoV zBa+8VUXwoe&IdD~*XrAO=@5^mJpH3lPyqtAK1Qzc&9SupJ+Vb}jSo*IL`%(CnSN{V z&R7RwqjN?tuNPmCxaN;*|L8Z1CjZ)pI_{_qHG^x38O*Qetl4Q%ZG^PVJu$fxFd2cN zPrMV^(yt-;)2cW78oUeQ;6qCHs53UYB1TC&G%ImK_Hx{KrXQKxk2z;hO{OgORcW1n zi+?4N`}H|KsH39eqsw_?j6b;ePqr`n0qg^yDUX)ypZ7G}xyZfWt={8vvrcJz!GlDv z$(%-4@yI$REbn|1o{YIdEG61@uUbyTX4m*A)ho#GB_*9>5+ly~+6Yb?aZ`o}r2|*| z>g*E@Kwsyr$t0^r(aGclqmMjM5HFgE^SzEj7ql6B8LL3q0~Vjs5qF;xibkDPf6+@> z;A9a#xUiUCRf{4dJ;T(rf1~KWwR|5svzC1#=0u9oO+E7Ib7M}*o3)`nI-XmeI;J4aMl2ex9eY~+cBA^9Zy^|5rb&5vYvB;y^DW&+ zOPL4#`=w<2S94M{CZ>p0KicE1MekpwA!O5-lCRDK>Z?8jHzk^%PUAMg%9zI!q z-{pz2=|8vroz{1ETahKL>C?lsiq2(y7cHR=wUIPGcJz!w7{wNp3=+ui*x85%zh@OU zR%KU>5j28DO6kE^;fJ{%DiZDVjI!-AHCm(TMDpOR>vZ2p8$)m&U%n{68}DI#JvT?q z^M8oPbCO8L0dK=)GHG;))FK~LCVJPO+F3X0n7Q8+mdwPBD)U}ZqZT~qztLba?pP4t z;ueWgSEYjR!yEB#^5R1qKDCW-@~ESGQM#5zwk?(Z}g$_i$&g@pMXZ0 zN6-}d-V)_s*kzD`NBVH_Vl0gY@U{a#Qum=`mCF-6qsg7y-nFC5t!3HG2ZKO3kliDw#WQWCZr>J1 z57CpI8}ScH=?!gWRX*duhxHdn)FDmy6E4N38jD)uSzU?FB+ntfZVfS}w#@x#-Fl!u z{kL?{)7GEXdWG=wMMh|fZqY2G$zDBY)>MzYJFn z`5PKQD}$4?zvBry2FuuWkCXPJHf2O2k%ZW0+{3T6XjaSQJ5|T$?E8U+v6Zt$V%~SC zH(cy;);)4}iTEkKK)JS$ zw|T`dv9%b6EJ;n|5VX!6l&IaJQ*%&Gfn=i{M;F`~d=AyST)?IDm@&p*L=MgEb>7&R z^qRAKv9dP42bsSSMZ?Wza8qKXjmHoIk_^Xc!ulH^$8NXii5Zi6YlCy7o)g zr$5?}Q6!U^5g4^mwWh>6{gTXKWBu7eedxly&&zMHs@G~vUq0g_yb)Ezn?`2QK)QGN zm~Ip=^fG+X94EFUqh;ERFKsK8JEZaCmr*A6X}dIM@`NVQ1M@QHgWp@I)k@^!8K3S3 zh|D2#Pm%qFf3fu0UV;4Bc|1GW8uuK11a*~i!hojJg3zspXmYe<#2o*7DS^`VF=)!3 zxDn5_736Qv8=;PDLh@Ik2tNBCZU#?=SHwq@%iw4AfhDdZ6dn}k;wK|bBO7@cBlL^D z@saP;TiWr=j$L-tdi$ujd0HnQa~9`OJ@e^F#jobs=S724JP+#olPZ@}o#GK$9Pi^g zs~XRGuvRVwe@ zK-s&?cOy$X_6pl$WL&4U66B79^QwpX$MxL_LC=q>|J-Nb>AUqbD{OgoyGEDMTwcz; zrYF^!d+DDneY{(}yZr>fiB^gnw|+8>wkOa>w_3%lF5{L1%tZ@LoMdyONRjdG&UCsdd??q7!)P zEEw9~uJ-6pMsTzKMgnwgmhfry6p1M5Sv1L*jJtIKuG5@1>z6)bqJ2Em-u>bLZGE@u z`Hj|}T#SbvoG+YLBXVU6Z56i{I`K5`qYL+OFVv&rUdf2IMiZ2MRAVGZW!#T}vrWej ztK?hD2txl`Mfnel8fTMRDk+QW(ZkzShn9z$vqd6kZN8x)8iE)9SfAUHW=p`&`}JSi z3JOFz>E*oY(Lx-FB}LBR8r{MJ^D+D<%jE6u6#d~(M$o)*FV5XX+Gr2T41TsQb{}*r znB)y#H!tWO+8nIv`r2m)^eMJHFks-%n>BuR4T;#&8}&bX4t{Ohh#X== zH2=-w0X=-H+R##D%;x-xvm|0aHgup9=_zAJ*{nrtX`+U7sy?(>J<-zVoViXQ7;Cv}V3hR5oo}+c~eEjFgr{lB|JtIVBx@Kdur3 zu~``{4<70lg1}FhF)%e}zC4Sq-d*^{PDy<2rCMKRuXJ4P;?n6t;ho}*p4l>gutiNR z&b7m{U3@*HPc%Z?M&+J4BW!GsSA^PRwV&24hX!`NwM26K7gQn@_z)eLDL$?z_|8(= zzKlP$XeEj854iAT`INiz)Pfzfrm=tri@m~f8V?QJ-IM;$7C&-lX>+!R=Hk{~cO`aN z>qEO)9NONlzV9wJ5=*2t{fuQmX_`R?>Hf(wUMC0DZ?x0y8}%QZ3L+T|3plB|L-+DL zvV>Be(;BVadM1OnswWafUEbSuR1}H`w7T{V?Z@A%7D5$j~|SyYPm@>9QyxD6?y&#)6K>zEPk49I}Gb(pCRA zTH&?kAN#*_VA=x6~7(#Rm^wl+S~GNoCg_<$ddq&>|^19Cem9Ep91-q`8=8gpzD zeu#v{KWzH$f}4>x-QrJKd}JD}(sGc1{C!q?v~zdiqY=|3Q3(x69BDqV^~^lQtz`_f zVzd*i(F%#-Mta-VhVh}Refiu@tbu;cqoKoirhOEM_2BpDKXJt`>vysJdrR$!Jb9YPLbeT{=2mglGGES2Y<{7 zv^s0(=t0Z(miCXTR`}T-D4cF>;B}tVxKC>I_$HcEdrbi>zh8Zk$!XC}FGQ2te53y5 znIid_ZWfmtG=l4iuf;+3Zul*8nYj+F!2_-7Ys_dLEy_=1OD!@^+2Y zI1($dkQvcOomlEN_P!k9Gsnuzi>(<0-Q+Kzt#2Y{S|=7u^q09Yx{da0RYv3_#(H~^ zapv=#{bG%fOWTJ$4V347SRa1@Yso{+%%e#y)Wzc&XR=ay9+;>!y2K93-(PfYj+oK? zS=D{8c$N0i<_XYb^s9IIfkZ9zCbNcp9v2TTliAhY{;-EXl%vq+K3dWjtoY$F%6B&! z^Kvo3VY@rpOU+f153&U5Aq&3}X_EbzzmRLk3-rq@&3E=n1K22?jh4|!`m1%NFYkrt zgVHqb<}&+C4D+}+*exg%>kSpLNqELCWF+~x=xb&($JPI9^&IMnl;kChE_JjwTIV6q z5bHawb`lfB69mQ8<3o&6lxcigfobZW*Kar>Cp=pXdV>msPl>{L7EyJqMGNA+H|y7R z>^|$#+BV;;I`RHyg&9HjjSg6XvqlpiI$LYxl5C3XW3o7jUP!oWZf7>h6(j;Zu9hFy zD1sg9zTd8qpB0y#k4;-g#eI^3*p1|5y&K<#W@Gqaans0rGFySOiTzVc6vFoXYYbKs zqK{)P!cNg3K7}w^RQ}M+3*E_;X-^Mk@i3I0tJ~CzRufZn%PAF|NDmLI1v;wVjEgUZ zZ{~~ii1x{2p=o4;hZgj#jzx|cS-f6yn7oqtxYpQ&)sj2)@9g(73&Beo*RyPqgou=- zv5~}rIK~^mT?qVmd2R%;&GZ4|w58Xxs)_&MhhL2~o(odmSt3ak;$Zm8=NX0fB!oZu zO|(gxTFhe zcmgG94Lv{)OVB5|H9h-$NJkB{CAvIk;*6dC^AjwPw2g}_Nip#yT@=sYS!{|1_o#Rk zHAqxc$8zvR+YjqMwFoZw#|*$pPBQZ$h-knq^UJ64f)VH)X_V= zunjup8xD>&jCrMGjyZAF80Wg{{Iu5aAai;%r9>TUQa||B2t``5M>P0JJwv_v{1NW( zZTdqSNp|)wR3}@(YK;>|Gp@@sg1e&`T-c6;RU`)mvuIK@eyl+zw>2X1!($AlrH$Ai z4Kn)K$MWvm9Fll7nf<|g`m8Pd4Z`Esej3;9pDg;CSVGMpd9pF2O1ALaGc@~7leN8@ z7fuPQrLd&^kSyh`#pV*ZlUHY^$zI8kzfI&vFCj|i6Ytiz$iGqi{Gv7SzHwXU&59kG z6EDyoo{Tm5pGI_h>@Jyz%t6UfDZI%FZfqkMtcRKAql+HYVK2L*nrSt%$T{%=`;Qi} zOQ?k#s0$LH5f$u)g$%zr=zy50jWkl;Q`E$-sYGh_Eguy@2WaL{Tr4tm!46|$k6W@HbwD7w#9B{v*GPaDbiI2r?=|_}+ z@_jKXt?L*fE0u|>Xl;Djy=tW+vG_%;L8`X+S-qlQKWL8D8()5;D{d#>#MwQr5R*$HJgp#40o ztM~ldx96E&{g%D2JgNOjy=(JnJ-<_Xfb6NXYe)D{KXoSiqvAkzd1aRy>UtNRJ*v6g>S>kAZaow@ z(>mzu6CybW;61&b*%PIoH>i9->#O(->$IirKD-m2RohZ)y%%R?Ale1j(u6!nVq}YSDoE+ z8NJ`_K%*b6srs7v)VnyH<*@6|j=PqvJ>7OZhWfv&wz6~cgXLzQzK<=OP;=<|my0&{ z-qn`v;1((#7U%51QxBy%ZM<8yM~$lR)E;p*mOa(c;nrY#_EDVu{lfyXgU`DX?3p&w zt;VEn+SoR!XFK)WW0ce0H2AFOwd<6Wv*&o$h@6$rJ*sG&Pk$&!irW0y#qR0eHy$pM zn-XoEcoSRfn-?Q@cA{i>Y*Vt;GNqCTp>T}redm#?n4%B!u)mk^OGbtdOY9_`ZVrg0{2rcXb#5)8Z(Q&y_012}pJlkOgm`U8 z`M+GWVb6`VPjsx?*k6K&eN@@#^D6zP3)LiiR5D)ssS521UoSc&MBl zXx)zP@9KQeG`2VP+{e@I!*PD>q;}}SN*M92&G*+g-@m>2{+;@s)@QGpUAsBY5qtk+ zIU#yde6{EPgQ^7+a++bjbr(LrQze`Y8~z)W=k*;5;g|1c3&sDuAOnoKx1gd=_p6lm zQw68R48D2imex-e8|M+lAa@o#&@RrYJ?_s)dHs;cuj=WC^?dd^pDg3ybB457xahri zY-P@DhANtk=89K$e@V3aS+!|i_HXsSxp5-f(V{FCDcvoaAW2RXezKfPN<8%A`u(fb z{(0T|^M~~rH|)|!CEui;2&_FmPQ&1MvEjp^RPtG7riqAUM4+1SYD3)6r|{n{8*1+X zfwd%x;m3Ihzr^E>9sc*Lg>kMdNWN}w&_kl_?{gaVx66Z^C7C&~9kpne)!_nev9Q;Q z8xM;QbZ5N({cH8jeF}ZLldeaDcW}o<{JW_lvT4+20L%emk~- z6JM6)kYuDxmQHHS+IypZft${*&bO{4F1ZfnBl=0qIV?C&F0)=%3l$P~XMPnc^<>0j z#_~m>5WRMiN1Qd@0#BRiW#h?wAbNHW>Y5?O#Jhl<7I)hDkSEyIe;x$AvFO~ccX`=1*S`BY9DH#k$CulaH|+Dr zbBouZ;KgN#f;SfLEPE9{)>QoZdtUSUIx*uqUcZ_`F{WA1i2BFb|M=oS5;t6wo*s(d7F?s6BTQd5ZYlpyaJlvL${?%fViGQQvpZYla|&53?le_4lI(;xmuQ1fM_W*(QjMCR}c{jTzi?h z=Q<TZ*JSF((vwy=;b$Mqm70R{zn|MohNH4 zgf}hczBlQ*JkGpnS2N7-GxN`Vns`6f>D=8MKj=KSo5}vXBzas~llOaw!~M4#)BU!! zkly?!4`0rb@$gpZL)LU@!YB1h-}O7zHsMh2alRy9X$9DR_(U^#uT4CF{b2uZLCSqke|*6;(%e4( zMse27p87^{VtjO8UXt%}zgsxeTs6;i^SAvLI5&Rh-?Y!KPvt z1LhHLt!q$l-Fo5KW%UmG<+j6JbZJc)=(w*;w;UbZPcdzRX^GqSMIOBD^W*&4O8>8i zzWXe68}G52Anw(gD=$7grx{}KEW3MPp;--E%>L`$ajxw){qo;1v)70G#YMZ-gLci& zwCAl9+5HHw%|TJYLqX5|aqcee?L(d(4GBVz%TVX2=HZ>cKPft#leSOPj#2kBoz7==O}$t{fsE|q_{HT za5lY*b&ZAlWQ zrwd7PK5rA0;NzdxGiNWn!QsQ&m)*GXz1pE}POF~}>tE0DN`zvRR8~|TJ$EHzbUC|S=;Tc?ePAv_GM=Vyw=P8`Q_-Jtn4g{ls&DU zopVbr4R$}Q?|e}3X@9Bxx%~Zg!@1EzJmyE$ z*JbSqPcLnE$v?|?;L_dV7d~Y~bL_x>%)8%ve-e%7)-5=xC)K0hoW?9U;_$p`?__59J?*tEk3+B5^rgG zS~R_Ei~A_m?yJPYUAo!xtL&;V_IO#XLp>(4$c#oA>p`-sv9kUCPMP6{VFYfySW9`sVcw0|EnV0D?c@IS>mK6B ztBJb4x-%zH%%@$AnR2gE<}ck=Th zO#1Y4(SRs9^ZeOopDwGK@0X81TV^L@^5DYbn|X>@*?vC7Q{1j^s9JmK{T?`W8;cbI z@i|7*(lEyO^!Z+huGPMu2j|J3mY*Sq4=#8-VzBTx{ElC{PL0Uc%!8a#Pv6PfnrUzE z^XQ0Rn<0g$BU2vq6^%!4v=bz{UO93KpYR5UpqTj03Si=QG?Pwj3+>9hQ@>an3G_PRA8jT58 z6HWJ<1O1wIMh3$hz8)9lc$x*|h^L#ETfH7*|G2DuP{vb`Y`@cSj47iI zPo1J?bA$8pE@CCCaQR&{eXHhbkxfR&o^wA-uY)*8B8QQTV9VgAHJ-)*bKktf5wgO# z&!5SP51TK?fz1qb4J4Cxxb59? z`+B&)*aEx=r^R3M+aY%)0>Q*8u`c-cuca}=Yp|}yJlt-pK3sB*L3SM=#UXmZCM%y&OgBws=X}0QDm&TnLx^dzIHz-;4|g zaZC-L6F2q@f=qH>fby*?twF;Fd-`RemPm($VjDN=*Q;vr%hBV=AwB2BT6UhZFS5KHu0*>wac^(H)Uq))-pLG9$^JrmG^m=0)rDua978yuVRP%+M}vT!vsFg6M2P}M4(1aj^ZxNwuLJyo)6mYmYRTDAvmS)|${?Eu6@B@zzbE zxqpu|a$nu8+Bx8pTk~@_YHp))qp1A_YUdt1_r3Oww7L1WZ+do%tXtQd6L23Y1jzl; z?sUc34@C*XeQWyLqka4h$#%)cRv%hVf z_TSJfx2ZxGw|=_~&TVdw>bA(-pq5+tzh3>bq})!(E`pXpitcl^o%6yh2rjZQL+2;x z+`J;EUVe`kvC0jt&EI)9+D|j=l$0S#e500eiW#%JyzS@s86rac@&YuK6@F0VPbmJ5509E<_i@t#%ho<>{C6HU7}Wwz$75qO@rME>%b zL6s2~J}jLuLlG~<Ds$BI|A((H+!UGO^NPDZP=A_siOS%mt5tczQeQ8 zH*VcsjT0{1=X$(!f-iNIxgP?AoH4Ue3l_$JaZN^?Z{=5#_ zilmbRhU+w^wX^T**5q)i;oW{XuD{jF{_#Dc$3UNg)EeRej zzkPWj_x0%EJ{=W5uk9ZHZY=WJ#rPS22977Q>6T(|5sbIlrS0LuZL-a2C>ixWWfi_; z)z6MQnjSClQBfD4vZbE|cq0D9v%Y~|`|5XY03P(Y+5WBdmh5v!dTvzQo}wQ6a&SNP zx2s88{ykmp2H&N}m~wN3mNHLcT`$r$k3t&B0A}u(J0N4N;Xu}4`i7M2ScO|uUPMyl z`m+nmjn`PeFJLRZwI=0MJ&xrK&zX^lxaO#lj6SUqe_E*gW=W2WS%Y1r@xV8pm3Umd z+4UK%@9SFK>c5{lV)?v%Wb6rMrSX7YmXG$9ST}kfS8Vr-CDId{5B@3Rsdv}BSAV^C z#hp5b>$%b0{MqjOp1+87#r|f?{ue=-bAPYe>YI(fQYFj=JQX(wKXzlmVXLCW>)bY( zT_f{cqH%bwjarM3=i@p$95jCI8LdBEkjCsD^6-F%OLd-4oAxgEh+)-s6>2>Fvt?|* zOVk{fwb1|=(>-*o;-?s{3KDzjuJh`%0WldqNupv$&-x2yhA5Z(3}~=QT|Z2npMZ6{kZ;` zkKm@Y-Q@3Y7S}|Tdf1)oJg#yw;yt@sdq5n7>dC2zaGl*2NkjO{pC*H3Z)Vn1Nb0iI zI)CuN;!#4?RW;-n<{tL9F*wliy-}JoKV3Lx^|AeSm+1MDv399>Wh-;hWQUSlzg1k! zdX5=Lb6?h@b76F6{=T2*N}UzY#POK}$N-`Es3biy*FP(1pu%j-uhwGCy;uw_KpTl4 zDs#75&)&D6mv!+L@}BJMX0>FjS(h@C$n6zYf<#Tp1pdupi^&~4Uivb>LSy3Yuma1Q`CE(^1Yf9#zITR*k_#?zcxp%Zqd9qlE^&LsOaCI3uiBHC$mlQqPE7~ zkmqfOtPjycU!5y6$G2Pg<*3@W21R3AB;VSgk0;eN5d~Q5Q+U{)I+N;EiBqO^< zF0sGZ)IJTIgkI5MR$|qZ26qoU4BRl58^!&z`tBKt@Mz8@c$(bG?(^5Lc>e7xo`2_x z=YM>~^Z$0m^Z$Ou^Y3n+j}yS+ZRgg-BqD{o#hsp`pH!`F^l<)+kJo>H$l(3j#{@Cu zi{zq63%)@L`Mn@?@_S^N*gz?MX5{!9sa`&JbiIt&RilAwW+r)~z4bHR>SW=h$n?pQ z&B%M2#e8lT!21XF$t?x_-cK^=T?8VyU0EcfvTjjd?ljQm_KBIFx6bZs>trb{=1e@B zwcOnnvfBHDYW*LIQa)UnZ9Q*t&2EO>65f0ISw-;TU{UREi9_qi`}*LlRM`qvvgn9d0R%LGxkrZ$3u^qTjvlx5hFE%^^783tNT2hgS`Iw)^09zUY9`KZi#uM zi3)bhWUiRKojkIrV(fdsQ*ZhUFTYmLI~w})`Yo$ae*IC!cHudUN6r0wX>c(7kM6-bF;MZykydr)|yIlll{s{noI$$Wj9xsg|D}& z*SwED-jsbn)kpO=?~^_$9+^cZBFWwJxd%+7lV~faB5A4F3+>5lUCl&HX8(Moxs>_* zX1cdY$CMmHXXBhlI&A3_zItSk?j32B7BtJ2v=d*mfO}blL72E zvtEX%ay2wvZ#?fOi`9za@^;H@zG2L<)c9g!nQW-nus*6bdaW&QLe4zVd^B&}H5U~_ zk4!zJ2riJoyc0bu@7jbF=;LEUdv>rSmk@bGekpZ$1ee##x=FCNvzu@;=)S8@BbpnY zGrN3tC9;-TB3;^%Qy}7Ik^b&HX4qh&w(uZGCaPJ_qIxe`&n;-@I(szc&@KP%?v}CE z7+#agT4MO*J;1E4{cGYZF)fQthMP9yqm?MwG9$*m@|WR;zQoKA%FcO3Yh>an+4FBN zdbvM}#6OmtT*De$TUVb}J8SH>Ub&vD(DTS*UDB_79)z`*Ao2`GeoApMi7hssAwyt4lF=JMMc&)PNO%n2V?3+L4W1evi}Z*;(nDrokw zcyznIozx6~r|oZg6vvz_&-^tCZT)be>Ztx5NM}cS;;DQZW96AWb7ymA{Q34rt8Xl2 zl+==yvIn)x;`rkCj3O%)^HX|&oAL>G8h`YSWsHf2GSbu(quU?PPn=XAb4zAJ?=4!i z?rZ#hyo~<)Rcroj@BvCcDoRGV@k>hSS+w?eD%0ObiFX(3M=Sk(l;BO;8_%30*|5>izId@YgTdu?1viAu`kP7`~+|qY+%%#!y4Ld45^c`@A`uF)NPtM~klR=kh$rWtpJe znK@hDy&rI&cgu|3ZXNg!<8UwYhIlu=GHd)=4HCe7{#TvM&0w5!G3+w+<5fJ(j4ms! ziSOD|dSYJp)SU>dhKx!k zCYh1M74%|0(~}vJcvHqJ9`B@T+cl+TkfM9Kw_qIk9xfy1$c!MI%DxQ9iMnpdXS~2Y zoV{JW{bJ$l8%sHHalXSiZHOk6HGaG>j^@2l{o6wE(Go$M4ZmBz#ZQHs>$6Q)$0Na3 zzRems2_G$%x$k$>B_by`_PehX4?}Bmqid+s>N?st1Gt+0=dtH)*)29)ZiiQ86|c%y zk~3{VMKXo*7i?^NLjjp8d8?k#j*dP>C1MkH!{SCMa^*4S((6c6v^K|)^kuh1te1WT zJ>@lW{)8OEt?gVbvqm!|vqT6WJJjoFyb9m8oiBb;zsJMOJGQfv*BZBThV#5W(POWi zswoB#vBUSjD*4<$RyB;M$qLUxj$Myhh1J!tgUQ&7QyDy4X9^B-Up8 zy)$c9Zeqi+FP0pPh=lcj+M%^aV?3qTMrx_((T-#gCvp$e_p6&73ZLNh}^qO7Ghq zqq*IevC@Lj-QFM?yUulrvgC-YYtcwCT2{t0f0soH$|WAUegtM_-4jlj4qSV&+_;!DQBC5Hoidz3I)YODnyO8X9)TW30w(zVYzFlGl96 z>Z|P2(}V41wm0w=ZH0?k0*~ugjoqpC??m3hhODRwDTa z83tKK>rOZg3(Ov~%L-oEDZVWOBglSV$+LPg&en{KCEbVV>RL;{&-BN_aDJ?PwLUzq zU*UZ8m4{$y?-bqbR?;7D+l2&>28u zNF*p5uD7{-V_R0w=m3eLm^5!xUE1W-XLeligUL#7sc1B0KYz8XDf5GL0}@6vw31(1 z4||M#{)jfYAEUG4hfWy1JMX4l7+J$Laf}m=P%30iw@#}k87SUZWXmc12H?QwxyCw7RPs)+ zl##eN^MucqXhT$cyu>6qO%YT|PuHuvrSriBon}#)2V~yaziSn48yN&lU$Qp-yLa*3 zEbKw?AWt*f!imn$^zWHJcRS6?-fs`{$s?!7;-}1u=QqCur`_zeo(vpubE{!aw7wX}F9*!-g^Lr3&wJx!ED;_sCHB*KC!$|M>H z%CrWJmAJ$c@W7e^U+DyanOJ6q*{dV_g+Juvv$#uHpLx`AK2n^Xec3@Mk(T+lh$O3w z$?>92pW+0OfPH8*Q}*oF_v==l%v{zQ_M*SUPlzL6PVjsm&XdUScjOt2aW0wON<0&7{gE(SJl^54-0Ur3a0(#l@%|FWdVqdD(#qn@1=4R9PK zdY^A89CD*Q;>_&6(L(<+W|7tn;uSpIKjy4HyQk4Pzx2odbVerahd*v0h-D}j{1>&p zUMmmZtiNAbMjRAM);sxt*l}k&AfWh=-e#W-|1HCntXDD!R{0u-@QbFeHT1Rmp1$aA zR_nB+Pcd2Nr;nEv!{p6muX~RHs>})I$T-NFd7rpg6n#?vx38e51M&6ZnOt1#2G#N) zkE>7g1*3!5|4=1;;%iW$ZZZ{0$?4%qp0U8jIe6lEFcC7`D7`Y9wU2`3UjFT!#rm_- zD%xQgbeER?q~!ij7je+jYR6a}*MBlPC^efRN&5m(j}kgP-(0r7w``zWkg*Y7hCg$M z?r=f@$5<2P+ApJi3)me zbMzJ((arBK7)RgO-Hcrj$uFWpTC$E*?p1`QhNval{l>C#Y;-W7wa#9S2g?)ofmeyt U@qBzUZWMMBCk#siFFnW`C=JhfW$JXo)qYVPXK4#qq6;F{3_c} z;ZJkUI(mf?T{Sv|821OtLm}oGrV!T+bMX7VMW5y1x1Lmf4nF;diaGeH#>2tyc}eLI zS-QTYI1YT$a00k^Lg`811BO$i@6*20!0F#to_64!hC6^Kn*5!>iwt)G&$*`0&H!$9 zdT?r%(@xGvh2z>BCr_k8+1~aTY~_T~Dd%RxlyhNH>6G)lVaoY*O6e&)`Ph3tMNS&R+XGh9UR0lOJ>p;9ZZ= z(9{m2qoJ)HL+Hi7pzTnK*9^0Vx;;v#eK#AXeNP#teRuw%^3cAo8>W4q_#=)b>c;ZC zVUA_mD@x~B-Zf0UZTe%SQ*VP#E2ge;hN-LdZtQNV$%QlIX>xvh+3_^FzUu!(>Fn!% z<6&RN4YRMqFHz=rcP5sTOaDrp09Ue7p2%mj-C&XD|AIW(ZZ(+Yg{r+-{^TwdFUH28K!THHyP*~@mH0H^K1XJDo+gZ)c?F;bbQcw zsFV25DV=tVm~7O^%SNY8R$4psnGKxRB`2{&&#|vYr-$?aju99gAO0()bBw!$J~FvmFMyz+C5=bYYjo-X@KrBlx5ce{R_?MDBCVT@~^@i>_cQ|9T$LzxeI4F236 zeU|n;=P~FLeo^VP^;wTe->Y=Sx^;#b>s~g@SeJ3W!BHWG+y`GRAwB@Vct7Ruom^ZqkzOjN;M{M(m*SODXBm1P z4jm?9@pvcjkY6Isx>z@QpJEDE_i+KeSfWyrhAU9kDd-1u=buj@W;u-i@A4RfdCp@v z*^3@y0>A1pT>YZQn85FO3?Cne=Utl!Qo}t)kQ(E08*)68fj&IR=n=Hh>M{PG_83fX zY1d{1GR*QAGA#8NGOYC&GHme}GVJsiG92(2G7K`A(WD$RdLwABc#Qv__ZTu<^%xHf z#?KsMBV-uqF=QC;F=S}=7&1)v7&7EMh72Q31~elR4Wk+4p4vW|k%D0~Bg+gk=5H{J zW@Ha?RLYYmcFU3Jic_-+a(o=I&bxOF(@|DFuk;EWWy1u+m{VIkhQDq17(TYkW6ZDN zm{V-Cg3vU^V+75K9wSgjJVv0L>M;Uk+GE6)vnmg?0e|>s*QQGfpAWb}wqG$iq6h~x^j;oTz{3`q$+DWF0MFjU^j<`FQE@F&-2>uR65X@Q9I}*tZ zWZv_)q^F#fUiKJTx!^JU?R}5oD0Rq596ubT>@gf=rN?lTOCN{-u+4m0js={PeTade zr^>Mod7;Wb&dHPROu{bbvZSXwGtlAANo=Px$Mx&!A49*LIfNRleV+uqvpjna z#yhD5{>+>_x{^yp!-&b5S-`mj7766Noy6r#3GG~Ezqzub4>|#yk0rR~PC#5uBXT(4 zMmZaBRIUWvB!idxXPYGwaEoLDZk0s=x5-M6u|eG$aD(g*80%xejdC&Is9X=YNk%+s z{WhTAfLo*^;8vLzF#7cv3&5^`8{|;H5qUM>MtM8ns0>$=kM-NwB;x~amSn&!vLxVESru@bZ1p%=FM9)S zkkA>t(#MmzCI%dlX#qD%A>gPi4!B94 z4!Btk1l%HL0&bP70k_G>$E~lHdZ`b%L5cxKWO=}i@@&9Sc`@K7c|G7}xfXDX3}5Zr zZEZPMj27V(7vH^}OMBl2Xxjj|`;sGJD6N!|>&Sq6O0`f6>F$pN=YN5E||&*Qdw zSs8GHJQ;9A_66K1#{-VaxqzGGO2ExBbdB}f)*|BrZk1^Px5*sCsPW0>fE#2_z!5nT zaHE_FI4YL{ZjynY*S;F+n`L~!EixtGR@oeIn;iET@#>zn_AEBuLj#UTA>c;Y9&l7% z4Y)~$eXoDES*8ZuB5ML}l|uoy$*UeSVO?j>MjB*7z!B*PxKTC)9F+qBH_3&7o8{i` z^X*`~0k_KXfZJq;$B0*F18$HZZk7X30&bS~0&bCrTff*& ztE>;WO7tz1>7R92iz*}2HYki zHd>pASM>omNHXAv%nP_t)&(4uX9I4MlL0r&n*q1T`vJGgs2}uwwMo6lh*yPx8)R9) z5!n!MqdXIER1O6UJqL`q5patP+hlz;x5}h|+oZ!|#H%F%H^`=dBeE;tMmZ8N{5fFE z-+(cHf5`f3X^}|*w@O#QZL-8;#H%L)ZjgNeN91_G$e#m_%GH38Z#-drwKmKB0k_Ds zfLo;;aGNam81ZUzz{ocOM!penqg)6$Dg%Dl`f6*Ex`3NydcZBRFyK~M8*rOEWjKO( zwJ+cXIT>(7E(VO`d$aZxsgKH-fSY7Wz|Ar@;1*dGFyd9fZL-&6#H$wrZjjdlj>vlf zH_8~72d0vdhNv_L+$6<-n`LRhE%HpjtukPX$=uK;5swkCasfBU69Gr$nSdMRV8Bs1 z8E}(a47gdY2HYaiFIZm@_*KAdGRtGct91cmPZw}R_6OW3uLTUh3b;vzK56YYHp|3- zTO=JY^2vbPWSz%|SGxj6y({2|ycKYx4Ej-PANf^Xz)dnO;AZIwxJ8x++$x&_Zj)Ue zBVHX2xIxYa9FfZbH_F86ce~s^(iD}!TTOORb~=LlJFA_(%6({erkFxs9n@`48TF8|jGCqxJ8~H_S#h@1j=CE5 zkCk{a)tQ#V+wrW`QQvhqRZ0|4pLdvbQOFsCt|~J+GuXv;P=<=uMfbUOv@Y6=nrfn= zwa{lB?&)mD!v{WreI_@~_|ppgBxAD+8OS*@>2Rrljd1}r%w#<6bU57M_B8dgAx(NG zHn#{xe>ea*Q%Pjfa=_6G_yuZ-A4B`87^(>(OR)b?s0nl-+>`G3`4c8=tK-$+GYA{4sfAf~UtNH`mh>@^YXjW$}HUCndus zdYqPPCJ&2B2P*n3Pid|M9FghsJ-ty51RRwo7J7PS>6g5Ise~iUo2D&`Zv!L zmlp$0$dGHEo|IVur{slz(^CJxJx{xw2)IMWnI5p}$UXm|JUm?)^{&S;*%okIP6wQj zCI9Yul5#rWluW1mnN1Uo|KjVRuASYO!9%JcuFJUq1+XZ`YY@$G=)vi?2KlaLbu zqptp+o}QAr_dQNaCg65?H{cF=2DKf^kiler8Z~W)aVGL4>Q2dw)}7u*4Lq4of+{i{ z@q)OLF3Zc^q?dZ=+xMOWE_U{$AZN#4c^sD>`hTgA;c3aPnZ)HHC)HGs;keJCu7w&> zIS!_MpT1jC@fc<}>cG9A149k6ZkES!X+>L(4#!&PF^p80XLKlWgU6`Lz2GtGa;qS} zdlvCJ%k5S*d>M=%nz&{HeUjJ@;mT?AWG)_)veJ<+BsZ6{ZVOdVTi@vfw9R-}%4Eq}B zDwl-Dan@s)XAKt(Gt!J7s5}ft+YLi}iGHopQ6`i>8^)3%#|3k9XyfIJQj#DPoY=0GcE2i_^5UBVZaW;{I5SLMd zO_d5MtQc|y>q4rh)5Yy5{+o^!aY_XHLKzNYi+TFO0LA#lUQdS~4u+B(5BzYs$MD0K zJcb{}p*+U}KRn@a3;Ym@baWgftnj!E^TlLf{Cv&m+~!V(vdNEat~~8An9l#5%Eoh< zH#{9O6krg?4;h~K7%~inBajYu*=!i>a@{c4WeFUFJYbjC4MSw7L-1ssv#Q#?=swu=aky`pV|= z@_dW(WN|JyyiIWqHT*-ylf!EKq~UybSq@n{Sn6efjjM=5+;i4WDLqSe7`;@OA{%XQtTg^atXIx>oJh;Ck1Bs6k(GL<6J&+Sf}DB4=qb!u z&(8x&&y$YGy#Y5$UBFR!=^O1?81+??Cy|*UC!DU(el{!98;mDgkS&uuF3RMOd0diZ z-)=ZpmitE-E+*xwZy&Ze=yZ!Vdoyw|;G(=XO8JxVb{YB!!^j~ITE9sggv>SBl1Rkg z@$}x96il8}YL;xbc2e1roG>1&2Qts(NkO*lrsq_yN8XyCeWgl8S!eCzxL;QOEBz`_ zNzLk!C(MrN&Z6wHHq*I;obhy=qutY@c25@)a>V*d7xMC?=`f8uK=mo@D_u-T#QIA2 zmSpICN^dV^q{nR65sS-8^OKHvQ4U+b9k|4B!p7TyaUGqb{dVLVD0}Jsone-Q$Anb#ocd_Vmb{F-q@>=VfHta55$P zOr9?IMwgATE1#4u^M|hdY+3H<(8Ceae^+-_(v8|q2I`@*wZ~fg5W$q#@-~(?p4k#&LWE@Pd48p=gp2;>|76Y%cR4cB#pbLky|&IE%AU(*sUEWs!|5 zhdBAN&B0u`S4Mb#_{I>=gEeJ`*(leWl6OX{Z27K|y!CB{XUvero{qUc%ltf_OUoc@ zCy)L06!XafwxZA3JjE_qHk+;rv2K}ebGCrJ=e}>$_6s;5f8E+Cv?p-~!|3hZk{)Kb zs~{UaKb&~FjirG7_%4r2aarg2VT<_z7o_+t)=oJi&jk#hF})R_t3#%T0`xH1_tl%0 zOI~Kg)uDl2l%9aga@y=WvpXfzY#tSn=q$DQTZB%E=1WD)$B4(6J3~zVBIdj~#EqUw z$YyJ&M8C3rOW8(w*X&q=-FI93EM?1b(EPJhNXQ|Rxm3U%gYU35;fJd|y*rNk6-Mvr zmRTP)Jf~B(1)P^tCPNwVdAg0IjC?F^x-BD7J8JW#oKDKzfDzvUF3OI8yXAdbv&!(R zXNGCNWyF)S9wR=yZLy+U%F0GtbIZt=uFux^U+zxG1shAbJ0pY4XUg4JTfJ<(c{yNn zq#JW*g2&L?DbrPVE-qK>*>0>aZ#Jkr-38nwxL0vcszXkit$Dw0wavAj&bXYj`Pd7c z%r!gqc4Xu!vr#YfzuN5HTTI9plX(u}RjbEX->1CD^*5QR^cH1sgTp1?5}uL76ja=_DP#pMiYk7&OVLu{!_DvqPhwy)VRa-mCZ4Mn{Rwtm;? z4H!ANQA>6L9$jR!f*b?X;Z3hA+a)8M~m{F!90 z%yn}rS;?TyR=3tCE7^EPws?%(`$cOf+gXsOjh;*8<&w!(KyLqx$zLdDWuVDcOeCeC zI;n8SbIf>(?HM^_&*G|~oDR4k=S+SUH17=<{uA&VIc@EikUvCF51~#^#&w~xoHcp|^_IbI4NX@vv52fR z9_~lxm^>x$>Z`}Dq z*3F#})=nC=wF%A#vXwM^^?l>-!1^`9_&YF{Pa3@wdC>`@XOPFfW%NwGS6=%#b(@85 z>*Z>|4RVi*;iN}oWWbGbf51`c3b;v@2HY$g1IF20XtN+&ZM@k;Lhg zPfmWT$%7ikdgt4aAs?6hO-9Ead38)Nw&}9McyiFgQlqo>xX5GFg6eJT`9fKC8Giw> z_a$p{CYI=X>$J_8$l0bDo%4O7$%#^u>@_({*tagUc1oRDx#V*7Y^8)d-UChk67G19 z3%F6H1ss(*0XNC&fScv1fLr9bfLrA)kKwEH%m+&OcG+ZdVyi7LdwRKDE(KhYcTDGH z)S1dQmU0^Rv^^a;{|g?YptH^MAYXmo^wxv?XRnQSR(zJMFx}3EeolUjdds;uf6j0_ z)~159d#=)s1bVt*9&GHIsQkG^ryMu_T&gTbT&|LbIVto`zAoS_HYBG;@h#*pDAbN7r6nI3Rf76)8L zF3q`IaJ8Bj46{~q!Z6ptw+ypBbKNlG;i9`ZmV&Fv>@+&ZINJH-%t{Gy>7KFVA?}r7 zFSD;wIf=P*_V*3LrWZ~suEbI22{Ml;E22taH9m3j>rI^&cOpYmv}nP>}DOYb`U=chwRyz*lYZk(PyS*ujikckzIi&FV_P`Zu7tV zvn6@k%RIANR=WBm`kgsP=B7;sjB$UfwO@+KlfUe7QMP+}xl_t6$HTMT30d}=#)BN7 z>~hOeC5E+cyUNDXS2?YHRTAwn+3E7z64o8uzcqRi*QfU#aP3r*c*o?)HYZOd3I5gZ zE4>{xoHZ&#r4zAY#jh*96MLoUZhu#*WD@Q2o{Lw&s3o8O73Im~Q!=&LY%q zx$)%k38^!ASa;oQ?U!QhGQ`?1q5U~iRJIc0$!Y5g$If!u##NeuTBylc%H(CP=RsVp zA8*e>{&gROwzzhHk%OIgeGwNVInH=c(>VEUigC&=VaL)n^k}$1iyv=r&^QGluLkc@nVoTgm3q4%1c3?)i=+=>Pg?_T$+T^XWsCV*%%7-hE0hVZ0IZff9UR zw6$4+qK8<&^womowwRsNnSVQ*W?nF8hD|Mj$IhborCRUCk$D7_uoG!JqJozQ?*t^?9_hW4K?)JLv zj_%$Co@#WSku5ijGLO7tI10S&SM*t)XT5Eh=UK}RD4pk7ZyM%#*1R2%0e$g2>*6mc z56@U%`)Q@e@I!o$(s>%Q+c3{tFB(QlC7EAT9vmOZ5yKdkTr~`n%ACE*!}HeDhH*?J z6MjkQUBCwn;|NgRH;mLwcJEUjs97!;=6UNAKd*A~ymjF(D-T>lUR`gFeCddw`!YexA=RH5qW6 zFDFdTIKr1_ot|k$^yTc%(@n_v8OG-Cs9MyD$AUr8~PDrro2~ChdONFzvqYIpwF_$A3{V?Y_}4?LNxdr`^XruRI0d z9foHD_x!rji@@g%)7Gw$3FP?l+Lm5HO%q8*Nr)nFJ^J9Ds^SW48POA2pRH4 zrbV(6_b7;wLdu2;dAf^bJiOx|Ft6Q#XX*WDADDi75O*+8JIV2-vVCy6wA~fl0H;%o z`@Oh(mbUwTQ>PK9X5p(p{|9O=Xj5`C8ZF8s*A zNs8++uAE`0M-CdM51ceiA6WK)^3w;-8m8UHOjbJWUNB6XuCu;q(bP0pTgcbHwte#Puc-c`)5WZB!E7*cao>% z-mgEEakwXgVDv0()Shdv^x}cl7-@T6->QFQ2IzU*B!C0$gCDl%i};!g^z$;t4qu`* zqJLl*&%Nz2H1SF==s2+8#F#Y8Fb4Lb$MD;89z*6gJ%*f9W*a{y#x{=;6h_W5I(&G# z#|R2*JVvlS?lEMZ_g%)1V7=XA_}D3rp~J4Z#)J8?*<%Fj;~qmlb>D3~MYQ8F=1pdv z(V^!v9wS)40jsrlLp>P#8CZ=t0^Ic-hB5ZzQw?M6Q>Q6z1kZDyHVj?W;b%S@#s4Sb zXNU3sdOS}|$BI6Hd%dw@Zyq(nmB{7rdMm?>4443VDwbhPNY>wF81JV9jQ98g#(7r2 zct7Q*l%KX6FkaiKpx=!iqyLegFgomY68GXdP#ecp2zm2M#3-EN&&cnfJQ=>GF6Tc& zeqc4^iaY5OF>!$Je#VL5d$2C7BFWOb69dov5O}Q?{+*c zp1h^l#gqB>IJ%1=Zzy(gWBu1Sx{DiEspl@lWccdk4v*8aZmP$wD z^!pXV4dMUF12>eS(cy-2?+m3UfhV9E#CG74GO8u*y;Ft2#ScrY#G*hKPZPP^;d z4WqNQ_baA6PdIrZ70PqZ4^STcUehYWG{z<4r!gkorO#64<%TKqHN%v-Yk=}l=3Ry< z^O&g8Df1rJzJ5cdYa{z@bo#k$nDVsVO@93*%ud7XYt%hTXJ1}!)@_BC#h z(rJr5SJ{_-TWR~uTvh%Hp?(& zJ8hV!pG$$Fa*v;Q*iYdMX zo4t&eo0OK7!j4IrL&&iBlCl7y|Ov9KTC$dzFkc4@TcQTz*c+N@fhrCF>~cA#kBiH!?b(H<4UL9 z_ZV&hzGm3PsBd*`R=8j+T&?`vC+_qZlV`){jE>3k+NHZ(zhIHc|EQSr>v_YRUjyG( zIvsk0Va~7XhB?1B{FCxS!0;;Y(w3(3wM0@XYYFQXdJ#| zm{N@VUZqnfYYbC{qlT%IqwAE1GR*%z#gySa!<1pXvnj2G+SD1!kJyVGY0aM+<|KdB zFgjlEF~nQFk!?oZx^T}ADyGzH4ZBwVLZ77%+_On}=mSd((+7?kX40_mHRb2Hw&FXL zY@g$L(=f-iZ-de~uD1+xT*H4r=^WP@!_;lrjgb;y&3%GA8t30LOnqK+GH47R_e09V zeoq~xy_%d&w;7%NX6#w^JKD_=jtcvW{gl7i1?8hZ!giXSeppf68T$)ovxby&MRAit;o5)LUPzP~0oV!{qgd%IxO*p}*F4 zsPiLlC{6%h`5VP}RNgaw>U^5<&?h^Lhd%j~Vb1qCCpa#S1pCTgraYPxE`Ez`Mx6f) z{1eCH^1#bZKl-iC?Qbd% z?Eu3TgTBq^u*DXSA?n2OM#tmtIJGN+HrY*KQ`8DS({DZd1u}3c{=Gb2}%(1`zk4op*hZ*MBpLS!XG_c)2 zlSgyT!T(|yV?Tpf=ja&w8&{OhaV<3-j%(gkrL(2he^tzJoi)sHT{Rw#Ysfpw!*La? zO^)knr*qA3*FQ}?Xxyte**LDfPG*f`Td{`DusC+!`9_oTlMC;%{U+xpQ~zBtW!q+$ zPoK1BDcgiPZHKZ=bFyg+JZYG^ZT&ZGhcA?#F-&=mUsF2uoc`a6spruq1NA%v`|%mw z#qKQT*ZYhoxE)2G--$dB=X=u$|6aig#;Iqy0=LPwe0i$a6BCf{Oja5Icn06fG+M$=grVp|moy*q@N5C(iQF;VQ9Jbgn zlsNPu#gt*OVQ0GqO6Q{&7AmG)#{V|^)qEr4WQd^R0Gk>QZE=s$X^ZJ51LIG#laoCm zcY1_v>U_VS`Xq*}@43wOfzk0R9;4$O|7>)~e{iWii;fq6RxwBajA6=u+Aw|ZAmSU_ zq;8LSjP{Q%(`TvYYw$_(P|qU}D~PGv_l>^|{28pXjt+TtJ6&l^n7TyUp?($_hL|$+ zVWm?)3k_30hYV9cYn?v%7B2k9#zkL!8TnYoYW`0SwoMTHuUf>Z*CA^6=?}r#bc}7Z0B@I(2gWZEjt3eUABg2J7mdD-%h8T{(5bPwpcmBFf);lc^tu=bB`Nw z*URIm+>3JojyHm=ZQ4jrZVCsL zJtZ#(oR*E>6cvtlX@*pz<_gWtj7w9!I7AKRj-d zwE^QBVm2<$s>R)&2X{?F`*=4YV7&W3O8cb`&l+tQGVBgGBGbRc)A79vlP!u&ZDXM0 zyIuj~J2|7Z-za9l(STd!+;&fIlOw)g$l3MHzWuoD4LBjgdpv(qntMG?$?zas8h67y z9q;}J{tnq{?Q=ek`&MnAv$-|kh^z`2-=hmSDr-HdTlfs)@D&W2n0fx7kAq&EnSeMl$74*MT^_^vE_w_nSU1Y}(Z*SiF|gQUKPx-*7))MC_ya0rEe5Yw<{$s&gF z&m@OuJ6t#fdLo(QeVBoViQ651@;{07tZKz|;!>I4>p0m)T*>gggUgC@y||ud?cz?uknNJEL$|FX zj1Jw-_ZYezt@7i;!7(|Hb6DK3cjvI9dx*36C^qIO@^F432v^c%xZxc7T0Bf7i%)mY zhW-ml@Zjr0IIfpB4inQVSdV^3F`Acqf7dX^JJDmbb5AGe_%>{87S3cjuk-m_Jd6B? z^BqTvxpus_bqeyAX1O!^UF7LzW{-LupY1NWy9$?PINXC*E@TbmnT5;-dU!YBtQ_*V z3%-#up02E{cQ}ph1M(t=@un{Du@M-fyKeyBb6CGGG=#dcdj-uHb1v0e;Q-QS2S~1y zC)V)ij=LlW1)+>ByB)?4Xmb;E$oCTXC%uapFA(9+&H;B5LldZz>~wVCl)U*-w2yDC z;JSrO&618&^d9W-zln5c4kev4?WChN4t-|W7rt=8@3D+DjL#{_JjBKv-izg*rFb79 zm*-VS+#mi<#R-V9_dK4(*P8NB+_T6JbKTiEUUQKiJe$Wmk^FNEGUp4p%K@p+K?Z!= zzSQZ%E>B-NhI4@e zZeVclIs98Zu9vw1;~S5^c9-!)WOcxeawy;^-Z!*oF(0GfY#8(L36C*@Pk4+qYtU%p zX@+bbV^Q4bF%t3f9wQN7bx~!g)YqfFvm`{GF#aN-p52Y!A3eUJDrCReRI( zx5%b|@g3KI+ho+=8xM*#O9RGtdIQGy>jG|+_*sRG+Q^AW?)e_=9piwmOo^Dg%O zz@-k%i&OAbcu5kUw~@gw5toadcrS8jJ#lvl*Fq)t3G~HNAB2}n0Y_vf?q(NkO+V!@ z?w{cP&%h#{P3kwzE@E#BX?U$k1|uH^E_7nPT*8?+F#l!-Nlqtr6I<39E2dG4yGd;xWF37;uBk z3pgU{0&bM80Y_y=z)iBnw+SEH=`q(_k1@v&dyF}L++)n~OCDp65BF_ij!*O$b9@@? zRpbY(@TY+1ftkk2JILFMcn6n%Cj34z1i+tJ4nqL^+2Sw+z@O=uBgI4<)vvO=hIm`V z$KNy1$=<*AI3_FJAl5Z>=-)W(8r`qhHJZNQ=&sR=iXjzp@4t0)j0$yBwy)t_-iGhN zl`@^}9ddy(q*6Fo#d?9YzL;uv-{(1v`B=pL8GPbGE*dTXzmFP7F{R({+W&Lp(ff4^ zN3c!21%bJF7`|G>cj>8P#F?>X!Sw#zUFHY@^u)YCYyxM2?L zm|+fVYDszER&vNNQVCgBRywA#th}!6b3xtkABri&Q?!xQ*xz&gYW@6Wk72&mzvFnA zs!RPb#cXrMf3h8|tquBJr6<8Z?R}-Q{e84Acvu`cY;?H14ErUe^RqM^|E2t_FFk3P z^`&*j!+?0y=o#S4PeY$*6U(?P6UB^OqudzPudWOr-KD@X|8B+9+eGZINvGcS8=Vd@ z@gC)Yo68Z@*~kMomx-TLOx=#2q?mem#W3}7?_K&Vb-UCs$3EI*;CQzi<{0-_n;hd* zC$sv0^FX$v_4X$W(+8&fxY9YY>PSMc0>`3UcY| z$fNbQy1|OsSH>{=T4$KjT`|n3*W!$W&r)yYuh(a(w{3>0w+l{wt(gz{TIJzR@vLF$ zaNZ!LGlw~7nDTd-Y?Ob!Vah+Ej{I)=%J5%z*v*%@hAIE_7nDx@Ij=`Tt+g; zX-g>tUi=w`y#p=-Qyh7_OED9LjM6EZOfXFPCdF3H7n9gek>O-i$q3XyoEdtZ14?)Q{>TAboiee zhSvA|8TmoSxP}KDmABwOSZR`-c-MFw+vgn~Y^aX?JNU~yK*AhU?7mNXl=g*n`ELHg zpC`_{%~;P%#CR_W7tp6*Z;tOM;BW3iju9~Gy#Y7M^8rU?@~0p}cN{NDC1tzeIr)ej z47d^B2vQ#2Svr_Q`#tbI=u|C=7;+cif#j?09A z@eY^ghj(Xw%XlI&nf9W`ct<#3eCyTo!|PZ5w(&H^WZqGa0`G1Zh8_lB z4q|`IQlAWl;}CPQwSH0QoM6ihqj{-2sB})Gq+!Oi#fBNvjv7DX*rq=o;M(j!qx=6= zF&EDDJ!mI|Pxc~k9C5hYeZP14#~}k=FPJrZjua6q${n3dVesuE(DApXVT#DcF92KK z^8AwyyV!Wmu#4?Ks&vNlahFlo_}JV+?zMxHpB;noRk9Jex;Az@KxBS6a@L(|=|dGw+>%@y!#g5sn8lZ^>}9 zQ^b3$cy=1r8i(OPm(s+#PapLyu!|)zqalalh|DLp_n}5XCdJ5?PJzEW?sB9<=|MVg}6#V+_L~=6tJRIK&x`VXrqlhC^KO7!Gl{&iLUF+s7J)q9=|s3=2Q+F@{t8 zHlt%=kDGXx^y05v>qy~S4FMPBP1L}9QyG+eaHkix#@|?pl4eSt!*{xRae)|rg@p`{ zDo)Nq4vBZ2NH3P=$R^{#?Gky~czTlfyL5jB?G&|s`}8v&r{n^B1LsHyCQq;ZEa@m| zqj>rZ7A}X8b`EOw80TC8H_8^&iqXCM^X4OW$?S$McO~ZShlwiTrY!+2GGQ z+{ndj!ZL@u$P{(YR=UXag7Ua_wk&r%WxlMn8-6l7HUm{6)Pj&}5zoO{+bGP7*+@^I z9{fGC#6|qw0Y%yHN%8}Oo_r8=Zi?||H)TsUxZ22J#cs_yZkT>`$}s)viA9dzt*tM5 zjHZ@lq<0uby>Y+MF?4z1A*EBKjY||W&Kxt$I5XbbWSm*% zjR@7HH>x^8Kyh~Rw$i&x`JWKv-o?I&Ua4t8Kyi7S1O${Y&A?7raz{1 z*1=x#7-EcHrF6!VgN8B1<%(ghP17G&9AYc%{fTwT&oOpbI~>tU;J}{B{xl>>7cXX~DPtrBk|OhGZlwImt^wW=c^?QkHJ% zkzUOE+32@U>ZL&<(kM}Bl4fa-71FpkgQ=LJA@4lj}2(7@yP`B89IpUr{qLHzp| zbg~NkD`f|89XOZczYl`@LFkKZt#H3x07ULpjIjTv(kASuuvh8xx)1GzE(MtS(1vqq64@1-aW##W4b*(Le9#-SuMbN{; zpwzbd8MOKt{DvB!UO%|y4wG>Oo>++|wQt&`&UsrMTHFt*`CBiaj$}1tuG;bQ;9rTK zX+dp^E%4t~cuX8<8U7htW7mT9$d;8e>&CMRdaHB)X3*Bd7{kN(S*=NH)3WLXv_27a zrJhAEs7kUI&r-q#HT`yDJPW`@U#@e%qlM@}54+a*lX}k%AbR~{_?Z?XKYfs1rz3m> zKhd_dz(LsL=K8pq6iKwU6s=dilzy-TZE?0!9~>!rQajED?`P5eS||Gq{C7Eg`fe zv}%T&wH~9g(@GDbo!b8KEk*oH=^n&C56fORMr!pTpobCr)CwwtKEJ?upSJ)<`KU}m ze+LoYd}|ylCE#c{H>h2DEB%8rnZD;enEE9LTjX!X2A}*Q;w3$foT|<5abr|#tOS+g zq(8BjM_mNwtfjq3RZsH0J%%`1^-6ul`#R;knU)IZZyDMlw_1KZykb4ZK&`2^K82q@ zhkx0^FfE76ulC7ltw@e`$C8ye@dJ)Lc|#&Z0QlF4cOpUS}GQ~gxe1JwcjiCU!CXHItaj8cTYXn?^)~R=ufXfmS`l1(b z-qUCLTZ6ynJkb$zK7S?l@Y40QhL`&Si5|fAIcU zogx-Xpy3ToTV)R?=Vz3_($H;Yoe2ljIiSa<=bFJUsd?dHG%vWbDe#Cy&{%VZoPOVVF z-0j3VnSuo>*uUlRPZp>X^xN6u5v=K)&9!rRE%f>*yupv>*0#|sueu)I&QES7VIKR= z+xZK9n^^@{$7;OkFC(KNcOlF+nRR{GsNy{!4UH9{#a{dygFf@O)gO04%$Rfy^lRgn zYxk5}^%&cke^v8cPhoG&j_R<_=Q!Dqu9M89nCU;}ey^EcZO+MP!rdjGXI@Y3B*3rP zm*#?x*p9h>-)vh~;D^A^pBN`TkM?K{u1H+j{XUR;Nu8N~<}&AF&-@K@KCa{BV4ma0 z=$~K|^SSdv>?j|zk@5-MvvK?@AdhC597hbTKZKu|olrVv6Iu!2sHrFV27kj{Z{HdL zcQv}dsjg@2fqOQ_Q+6H8 zVm+pIr>*0lZdN)ydh1fo707luDrWhfPEOVyXbs&bjfGx(r6=urrp}cAW_bbm6KIh; z7tVh5cXCo6zM8}Sxt37&YFqSFw!Rdx#oL*Bq-JP2FJTf-a%R(B z)H%JC?f89+&L;W?V<7oBPD*p@nQ$i_J+?-MoXM+ueBBW-2B@cxMNg_9okeO(dRku% zQCp-v1|8_m+3#!BraB8%iyU387CJC$j*;VHB|;;M)}wCB+7~)4urKD}zDh(nS=(FS zcEa96bw5eZ(CEqj$GWkr@1>lLZtR0HS9b=)v^;ZB%BC%_npnn9^g$nsA4Gc#P_dvc zIKtYDL1(aLC$%eB2Gvi$2KpFJ>uSr@wMd_=?V;*N{p*s{rjN92Q@u;&){)cm7-4Bu zuW`;+dbw7SRw0HfqFrvyTia?GoLZUESznE_RUaom*S>_y9k?Rqu=kJQx$)3w1OCM+ zFIMXma=bjK+*h-<977(6!$i|kJA=yh7 zYi|kv{upRu(HWOr}_Ue4n%w0Wumz!_2wpQF0;QxJBjlOG| z`W|h{i060TIz!cGxxVT8xxlTayJ1Jx92gh1PexAeDRmuRfSApQ*mr-&R{UzBt3D&6 zRwEf{ecVtlQG1VfBh@{D?k%Z*tDsfJAa^$ zG=Nfo7HMV1KDMcK9nx?lji3C=K-si1$U3;rBbBi)4`&b~D{GMbIaBxz*JxH^G-j&3 z7*Xlje3r48+GT&$7(rcXwU~V~C*VJ^(r#>0oFJ5=z6Des9*5BP4lr2`@H7JwVrch|MUuPts6DLY?RTJE5d5$LH%1$zq)k` ztoTK7s`p`KFTxskx--AAZAO|~%ap|oZ@!5{w||O$uhEMB!ZSX4i`QSRcim|_%#N8G z>a4y|v$q>VwN~zTMwEmxK(k=xk{U(0zH_cYZgehFGw=z3)9T05o8RSQyU zY=e2@GLw=m_s=%Hzv*n`y%O4uw&<%_f4)fFvM0(z?WE9;uH*D=)dHWSOSWU86|`)Fp%>UXSnm+%w!ESj&e z=BhM5(^>DLr)ynR?XFLMC8N5NIl-RQ=jda7=LGAbdZR|q;?&PHhu2yMS10B}USGA| zuJ$ZIKbraaHg4s^%ulFK%AhCwv@j_;JLnbk(dx`luix)Hv#+oF)q*WB9@5+R99#Nu zUPiyrK2?fp^x;Xi-a61b5nf7PCB3yDc|CgXQcZD(`m6AZDVPOWr<{JzlU#kyHR>3+fQJ0 z)SIuRsVCl8VW~z(zYbE@ewK1xKLWdH{HpGFXd&(u7(qC9_=I|V^$DFF-0M*m&N!|! z4+Kv9-I};{#(%~;tH!`VTltt%l}z`*v_EN8DYVD_yW#4p&nNtDxGIg-+4}CQYuivS z?t8DnkFj=dUY(zPBkGMhW>l}%(=_5}45CJAtC!W4OudY&1ZSo09_W)k(s7>obfL5i%JHyF*ny`Bg)Aq^!xQ6x2cj z@@am?+5}fC)zB^=#sP129XI`N5$Kw)uz&CCdTPWr=y6pa;;O8kQF3%zl&i&Zr*%ITH54m5r9a{n&0l zZq8iZwnWMi?zi_*t`MwoHvP8gLfzRx$VDk5~(|&l2FY8_O#9TY6{_tFh|& zQT)Wn!Zmmap3}9MScd?U} z{c^bcViTzB{z^>FpM>aBWlRYcwg zpx%8Jrg;`+t>*i+x$s!Dsb}fcma5O{E?Y;>$fKk4*%o`@SedPIjGW=rkoqBi^7nl7 zcMm|ezPHc){*@Zg-D*{yE@+7rCayC5CGz<*XCvQa;fl(>>0w--R8m%_^kzA=KyTyx zxm}-(inOV}yLq#U6wl|`3g?x+Rp6!B8~lj7C7$#!W{^|$$eXy-CF3URD&G3F=iym! zb0y_7%s6I1=10&YX;m$7l%$e_(SlV~>Ol3Z)~@bT`u3$eIo`LwQ>{>j<(NTLy)Y(o z6n-y)4RrO73jq{J1 z=UiF{eNYRx_sX#~aY(a7Mmn}Z&GhYo-hZ<`$a$x|^o>K_cPS_5EL*C_`*c%Wl|yHu zr$=!5<>`KJ>vzude@1S7Kg~zhJL#)Av`G*5ec^AG4D_#7Uk$ey7wb89I<9W#(_E|d z9VX34s&yp)c8hbzo%^7ECtR(+G|qcZbB-brGlWc9mxviARu-l<+Wz)X@JslVr1e)~xDu<>=dP z-<6~4P268{=dNdaK6dtxG#cCge~r@y`c|f218!}}|M?o{X#HEI+_^Bib2h2Zu)3g8 zpB~CJRc{3`OW@wwXN#IA-fUK~%2Pcz;yS{NyYCwJ-@)_#yXc{SwYF*nJ&)3xp0o({ zt{GPURhb#$jhRL59zgdG{dG@U>x#~J!RpU4S1ZtZoUd>2EQ(cea6CZG{%r+De^Ous9mc?%5(o##?%NzNef?^usC(`>Ez~_aSTMyAccVH0yn9 z@c$X$S>@!Scd_QdZ16r{ZArDDwRmRgT8Xd9bgQ09XoXr~PdwB8%nfa-E!ZPhDC&Y1 zQhgTOPyS3}kvpTi-N?ApsdF_R?wg6V9mRU0%$Yj=wk&?jwAeb%1$eDL^KeXaTe`{rAVv|Lq&UQk)rWo7Rx^;POb zYm$9W{kdz<@4Y;BLoZ+6$oii3tB>m4A$mXOGWDpZ0lIHpgR%GjUH=jHpDjEUqvXu6 z^bNJ!&7J#D!=pFydj>hvs%pD`KOcT}+=pyUHA`<{B+@abaVo=;1DwSNy~&~7{nyM3$OXo-7O zt_p0|*P#2J?Dg+SV-6$E2b~DszIUE`ac*iYnHdUe$@F+?@J7pMH08Uv%xt_ZKj>8P z_A>CChc_DgkFoz*PLN(v)$LBb+*w8Jk`FT46H=LylB^>;hH`}Qc2*35Nm)zj_Ud#U$2T1aJNOkvFB z3{<<_m?!z_)}5Y%^F6vBK-R@fgm+!|m5-E+#n08>@Ey4Vs%!e@TJ3L=?)DAeXQO1y zleChinI_K_DLdx^X8@xY&rn%y;q6W$J=r3acbe%poR6AE_Pw1k8T9J;7N4cHx$eVA;xFXiBhuJuUGX?$#Ay}0jh=v~yU z&;1!?tDaKTKi9+mxsvM)VKm_W$lp%ojn*8-&bI`s?^IHI)#@&1CcR15EY%G6R(>vO zS|k};e+HN90>m4IGL?K9irO3aE6_dB{G*V=)cdeYB*1=ntWpM#e9 zr1_j~YTx41n8g|PAljtt`qunG{PZC5dc9kwr`)yr)%rt!{ZhjJN#4k~!f|t!-R{=S z|Fl`A5yD`AG`*AUKaeo~}rnUSG32x%~`f4~!>zhs%$GXXsz<+@vlzC;5MBRM!ozGP^+=>nz;?4!y-fpYWs9 zmGj03#b-1!^BW6n)1OGQYNUHtzc$me^sY@clhGQQ?%TL)ufwX%dR*-tPI7DP_Y%=l zc_PN>OWU$ve`|sJEPl;YAiMgoUmy8@Mz88~jC8DF@y-_QtgER;E%w0`murP)DLOx@ zCviSo)!QGm3-?0&vIQ#<{esz;kgfjDbu93>UQzt<|iuszhkIh5zsF@ zrSP5JPIvlzV}_xp9=a-WE>T|Pq6PG~96P?nC6tU zAid)=Zib|sN6-`LAN(&Poa#*1TIy4^$xOoESlI1uEHE?YtRfF*Au|JAJ!u1t7tC1v z-7<}G%r2N0Xs^}&bdRHVqP&$g^4w0U+Ws{Y;q0N8t0(BQweyNQDII+R^3zxQ&UMB= zMhZ$x%vLF@`o7kvIJ@;L!#>;Bbw=lw>auzhkpA?;PP5GI`7J5Ei$jfTtF%cq3aD@D zDW$e`tJ%sLKi3lOKA1K6yKvRmqS4UD7wwI6oEG4G&^(8}@et-Q_b-@c*Md%(~8 z&ALwU%~IbUqYN!f>$8nzh`k)`t)Cz#J%%$<-{7Pcd}Q`*=v^U|jbo%1C!P%{=zeeh6#YeTuzNr`gR&wpV^}ZgU(SouQX@sXd+;vf3 zlxn8a>sog!kW$dk*$+pl+R`XViM2hRTyT%cd#>GRmm2c+*4-xOYwc}N#&@=;HGyh$ z)*0t-TT)-umh=vAmDhVhbuOwjq-%Uo8&LP8`L7Ar-V0^CU>|;_)B4;Ib7i34a0d81 zi(a(@KPj({Z?*e9GY<71t}^OB+#x&$T$NW>yV`GrQ=_$OpuQLEXCQq;-vIUVh&u`W z=1^Y?Qtz|Z~*bsD!+SN+$G+GmPr=~j9p-+gXBUV@Z-laXKR zseRX{`hFAZME7BDmV&!?%|BW{h(2J<8d@ z{Kj9=(Z1knP^?gA@H5{xVvQgLtnU)(SBl8bcQq681#ncWR=kzV+QDsSK)y`pRk`}1Ot*U2u@AGp+z0&77>Y=`M@7tWI-nxD7 z72a%>Orl@!dD>Ec%QFtqCwxrks}JgA5uz4P;8a>h5bm(`bb|ZGYLp;V=blC`)o)dM ze%4jLfLNX7{#GqlKOez)X70alP}LfB$<>EFGn)8T`&QoRos2U2g@O*W%CV^T*WTy# zYbH-2xPxaje{7i zH)E3eBgf9T%kgQYL{FV{1=F?8pHzDe=BFCvHLu~*y1Sspyq_`t)M~lb(=_gDB=OcM zm{zC-_DI>8qftN9Dx(j-hov%cc6m)x8r7qYePN1^;p-su1324 zX=@w{XA`Z&=eTNe1=pRVTF&c=60p9>mi4_ewyN`nF;Uk9->;urIvVPndq=->&|J|+ ze8vr~9F&G@v*r*w8xDpn^Je#AZ@zc%w{32I|IBBT)l5}0Tz_v}{h2m<4mzRVa+h0& zk@9v6ZF3_(C1-o&W;?zQeNMkmud`h%Otgw`QDeyMtvc4(&*$6!H*3Oc?f*`Vs9$mH ze!WUzKI(d?(V+j@=Hr3VZ+7BdT}x`)?Y|E8otbQvv4%ZY_m3T*e%^LUj3!!B^K+gt zfcp~leU+Ij1-UfaX0E{~!x*Hwmqur16MX-35`I_P3h$TnZHIBwuX^ln}B37=w z_#Nk?#?IB?V|zY=KZ?JL!tWv&(^>1#Sj}-J@zZk0@86(eKKmI*)p{{U$=#u@Og@HC zJH8zqS2en-y?ng%>xf?;n9p+ur~4gBTFt3AB3&soVpelY|8-nl1N>PT*F@$bT%)vC zTB`baCtB6yK_)EeC?CtsNFZ{ zZ*>i&UFkWR1F&DN$@G${R;v~oi@ur1-RwNA@0wNnoz>bLm-f=0y>4{Xsm+P~D&w`l z%#G^`Eu|G@T~n)aRrR3Rjm{PSZA|)=#+BRW^Zp)}zDHPn%I7aPdS!n(sGq)H9joT3 z^a<~$)o*O+2^H%UK7v%&?`j0&JozGKDra+DcxO{>##*-`odez@=*4;`PP1U0yBb&Y zM2xneUUgP!gHdQKM$0(O?11%(8>5!CtUW)1r?u>aqWQ>7)D)YTwD=2 zbD3AtQ&Wz{n5AFctJQ^$zV=)~J;KiwYKqq9*U348>Q13r_n;ni>{T7>>56{!hVs|m zxzskbPO7p{X4RYSm&8Rm^>)8I^WNtrWB=71pqEQMgBGQB{7AXFR#zd~MdiKEjYwBy zekq3*=4kZ$lJ`07^_{cTHQukHeSL@?tS8Od1ADEl{%Xd|+o4`!@~KBsi`2B9(lH)Y zR}ONhZL48fEYSqhccXPWMHE!Gq=`Dfk+18EYt+h8ttfTCEpIYToZ{@tG z_Q-m7^){4`&;IrTX9%BNhW}URljg#;kwK%7*FC?Gv0KIluRRD0{vY=4=Gm_6yze~z z6yEAo$z3I@V>#(gGU)<=E0Q({QUs(}p13HW+AV^W^PO1w9;GBK-Uh8@NJuhqRy*C;f&o?+Ek`Ep?%l+H}^6}gM zuw)F~WZ%cJpR8l$xls016wA}X+dA&JF_OF&_U;ky>)?29x!I*W(g9B|uB)ha+;e?* zAd&RsR=-;QIPYR*Nu*M@uQ!E;H!{iTLPn$O;(5oD;rb{Cqa|r;>ibS(@nPOl(rSsk zYj!^!*YR)_#-x3kvTv-F$%#w!IX!Cm?KMk5-#N7tKha28?DpMA!B78{%U!XnKTNmtYtX^IMp?Cs~?Mh>E-syIeA^Uda*7u_|Iy+_~vW4kx;9!2^ zHK;iLX4ct=57F+*vCWB!M_+2!sN7Y(lvJj-GC3K(c6F5&jHQwhQ{^hh z7(S?q#+{elF8ScQ496#b(Mck$-nSFrxSNO^*p_GWT2IKnK0mx$)EUE>*nRK$Gxo!0`d6IPSlT-^@QGDqv5BF58b;vHEZDI zN?}cYVV3MD%P>L~$yQ0}`5MtZRU2pU(E2f%OcfK2#zyz^b^OKpY}7KG$LlI`-&B#_ zab4bQlNCmzT~>B1my^Q3i4*;fa=jR~_iX*24x*%d=bQ(g*_tvM*?uxc>16QH&s&BU ztHZ2gG>dzb&=L=F-sJOnuf7ub;oe&RIn~aVqeH|-+OlhB**VW7-x;#>GPSWf7}JWz zW#(F>{mqg$yi8uldG7a%Nby)Xk-L4jzj=B6?0Un$Zi^#xV|tJ7$M~*^F;vsT1XXeDbH)*+TQx=Li{$ zlSLLmTjfOQ{r*`Na?RteNp+9$=%s8X(ofuf^@wCpWZd{!hndIxZpopzAvf5VK<51N zyyyMDtY_Ekb4IeHhsMuW_W#odH|q@9DzAC*a%?eqO9%2~vutSmD@#XjYXauKS>rxl zS6-qS-LMJ>m)Cu39l1Sm>g?VLb$p_cl}e}vEktJ&@TzS&Q<2JCezdT^oho7c&PI+o z3`>Ll?yK|pSf{e_grQB&a+HxQzRIO6^mQGh?S-NC z>-{RsrFq^Jrq_epN@?98MPf9?CZ`Oo)IQLK5=`V2_{MVk;H}Y z|C2SZxD_&|lab+;)iM8f-Nx!xG`@FdzhiIN(s_@E1@axcMt-|K&*+os4KfTZWDuR` zZshwuo-LJW{O_l6<>N%Qbitw)NY1Z{?eM~Sc;w2)DG!_gc3HnPimjXlwl%dL8*IhV|?Ca}aX`M7GC=c<3};*iLfkCnJLYdWHHNPt5cVKtr!dORM^%&t&KZ|2WWe_kK+ZXVpc zJoCx2mULAPF*0dx_z+4($0zGs-aNLq{rS3eH`jRd_ZMG{lqIQ#S+b)^_Okn0RGrz( z-zpU=u*VrEGy1ianCOd}KV7rz?v^@mD z9eZzO#oncf((XmJL;6UUHI~0zXS;v-gLQVad50`L}gPHahR{ z3K^z@Q-@TIAuokuyxRWGbBu4E&z3~;{pWY%@ghF=`{sJ$NOOFDjX0i6D&w`kTgO>m z$7H_dHM`1t*Df918I13Be7fR17s#I=RnNmPy8OXRqvOdwW|S@WXG`jXLqA`-LF05` zia8=g2vJ5T+X;O=F#vwfZe$&htf+WYZAKeK=SC?Rhl(nt&4&E&?N{sU~`FWNY-bm?wpC$Vs&ujiNGl?mCTy@06OSVrs$M+hM zO8R=09ER3%Rr2J0KU=megVXUES=BEVD~h2-?tJBZ?Q_>wWTa~) z#?{uxycMV1%&7RBzJ0ovAIbeuIR1%iD`Fc7>Bq6*G!(NRF@ByddMCTf|8yN7om^@> zkF23(R&w92$uP-#_dp(OR(4z$8%2{{s_k&J`F(Pt@tPfs1n_BH(`aRc8%bHICv>2$ zerB>q6YtNnwoI)4_{P&V(%&4A(3R+SHO@(NM_)M|?ZNJH1UBD&Q;uYTvjZglr;11G zqb2j{{W`x4Bk8;jQ9fMPbq5Mr=4npZE7G=~Zf*t=i?{*>&!9_So8CfXKrsgb_S2OUYy}KMI<&f zwU0RL+jt2(eRh({>~$Vo3}ayLthLiFAHx-UDN{=_VlKOLj+_XJ?K!NZj>I0Xv)J{s z(^<}SEs6#M@)NnVd9vn-h0gQ29BPkxo@tZvXkvUjI~Z(2pA{4NNl}(pu&AWB^@gKA zTeQsHdi;_>t0vX$n~vjt>zR4i$$O{lNO@+nbL5A2(&PQvK8o-mGNZ2%e|y3y9u~#y z%5Lkd_qYdTw89to>aOAT9ddrd_vo9q_&$8jJ-wU9+jT}Bbez4Xk2)cb=< zEXUtH-gnm-Aq$JyQKdRe*T2p!Uo+0ENsdjNpEq(idPn0zyWI(P9?W^Pcu7O)_1UsV zlIqPkgYshm-rN%9u077dqm$%O?-Q}N=D*6-gL3=YW2YzWr4c;Jw0-LcY=?iZ((yG< zY@T-G)Pdhx`SLyQo0qmZyPkFhl4iP(w!3C;mK5a)_ao%sx0rmi6HolqF_80)<<|F{ zzC1jDDrGjhHpRT@QRF#hEhc&@0L@ij7CXW@{)#d*z&|lCIfvhSm6A0?XLiM3+q0G@ zG@ht^q_U%rPWcU7;=%jLuj*OeH@duEedh7%(if+*_#=9aTb&~V##{b=tujsf=HeTA z$Fi7W2)Pfk8sVCjrb5Hn^!oNZRt?A{DSW&*MNjpR@s4%2cwdy+a~d^%riu+ilW$o` zW3vVnG{)vir(yR5XlZ<9qrN#HuGxD=7nvvbB>HS!_q!AAo1&5GJIhMQYoab&xGt@m zm%j0MU4bL9%?!|#fkfMH0deioGxN_*ws+~j*>B@}9!2(2j*v&Qv5Du|EvcwU z+D-GVHShP=kuaFl$VHUPZ_#y)r|aBU%{$g)eC%AZ5Jz6VQ7-S6E1Dh3hlut~IM2~R zC%F!7_+CcCqP#OpwwWZ+Ps>x|mGzplYCXQvD#^9lSA=@DuF_+9lX%yPhpbPfKc3yZ zEHGV=C`Gcm)bHj3GUWxW#h6#U=^8z9s7|)!Mj;YO((AUihj&;&qZ@qPrS2h8pPvyTudtHm~`_J_nX_F2FLI^zUf}Ri79vwF-99BjS+Cgc5R{W5iI@>5;2nwyte{p_^AS4Sg? zU#wsC6wu(_1pl}D)pdKl;5#QfYu-G1ykd4umb>vRmDqV71kLm`wu<^=7iW9QwLONj zccB=8)|tC;^$5tqsQpqr=}34auIg2*Wd3gHkj-t)v9EmR z#i9r5q^XVCc(OAs=|pRpdeKdso$Qar+PgHn>xJx4D2P8o<9@~dzVcN+oo-p@{Ve)Fd3M)Y~CH7?QFT@WI~Umv8VM*Zmt zJ-)L>Hyb^{BWoRlcsOhJ;>_Sul^e^;O9vhNK3XjDpu1{CJi9shsh$E!(s_P7z8MdD z^lYcQf8wYNfQC_O(9|`?u4*}+hv#SO*W-GxbzOgZN>xvta_`!c1FhGeYWQq% zCOXtXxp~Q%Sth?Py8HK&HN&+l?ALm>G{Bc3QjuI_q*?NRfBieFuJj4>^v#YP#bopA zCHwqVHk3Xg(sbEejp84zyjU-YrzFL?($CkiaMRp0)7zM#15Kx^yj-TJXGY_W(eDSG3fGMD!-Qzh$B^K=rKpWf!A|>Zw@krHItc~pGDi`=BN>UOFsPmRbANQ*xTNY zzQkV3Dveiew`(}DvI>Dj$=W%uqRKU{yW>ApIn zES*&(MKQ`q#e>PTy4Ockn07%yv7dCo8Z<2CX!R%Su9oxLGx{vNYSa{*kp5CdWD-!`am~WGvSV$0rJk+(v)Cej^`MgzvC{ z2IAB=cJ56hQ4>eQr+RGm?Tlu3=2-NJ`Z^(~e}7#QKM=>9VFWt&x+9#~QY$}%l<0!F zWg#Jrqbw06X4|oz#hT%Kk8=6Fh=XfdB7v>FZP~}Q4YEG&l{K!p>a5f)nJ(VMpzMr*m9GQt^mZG9J5fb=sVx zXnVBIz$v6dWvD*XL0vP)m&!(kzyqd-%Q95l><{iwwmKG56{CXe{e;Io7-gQ5!EYbE zAGdB6rL*Jo_-nkf1+pp{;ZYRx9IIJzK1cLD+OA^p&wgF`;ku4DWuYG~3HVF~I3%^n zp^miVMcdNLAAP?cwdBF91g$*1NE%&bXUCC`-aty~yovHRYxK`oe4_JnKQ{7@PMlPc zOb;-rzq7bHU-dc8ShnygdM20H8r%8m%^%G}*DZS*#KI?9*)pNe(w`aj7-Ungc z&C=?zO^&?jAN@HW7SVv5#*D{4&iKSwUbZzAs6C6@AGS;$u2GK}OL%?Xj;B)==98Zo zg_oXHK}K2Qysg8L$w`jqerp|nvaS^yiW{36UNn-KyE>s^79Nfde=MTBc<;q^#K_mz ziHnLLD_j!aT z-C33g)jhQvBGiBmv!}mo+E|;Pjm$K0Sv!Rh5UbrCeJ{6$B<9%jry<@`9KZv+&v%k` zD6;2=F|K1D^uufD^7B)FaAV!J$<`}xUdER4oV+c|&qB=1DtQHK+cLy+7Wccm*|rou zzI&fX5oJ2?IN6voIC1RqCz+Wg+mqdduAASzrv;arCYJf{mYpQ6Wb&&uXX_-QKYLXt z@Bm03SA0sW#3gMUv1|6qmMeXDy22=vS)Q+&kXK!l@y4TnO)es)+#GVp&(FLtOh{M$ zHPij9@X4KZq8k?wGwSJ2v|(Xs6o2%IUq^8sjBw70u(5c)T9h={L?;nDGafiiP+bZ63W+WKkDpcO)V@ z^G}_wxG`hcyHSj+TnR*fw%Fm zylYT+I+3(GXBQF7QpHo|RTW7_;qJ(aoXN|5ZaDbk^+_ah?d0w(_*l6)+l*NgebaOM zd{{pHzfQMVZ&8{z(7t2jc3wmIPTJjNXrGohzN#1>p8opwm+Q|w`|$DU{=xPjbk;jB z&+khA{^0K3!FD!yA-O9l)mu-b+yXtja-d5DvxtsWj=48NP2l=j_KV7eDw&v>A3&l#dNk&C~5`TTv zxLIPM#h}eI4-)}Q(~Tjs$xwc~Fn|<21&A)5u5swqIZ1b~FYl_1*H}S^{${#4*%Vn`qZ@6z zCwIwnc1QNRyGM%khP(-#X3N2{8?=!!t+Sh+bo_7b{%76g@6S(Mppvxqj+$y>=sHmk zRyJmGArDWH3~QPXg|r4OX!~aI{Jqo2>0X{fa{2sZ^yzGJE+{-`k%edRZ~>OJLpKi# zn`X@|G<+T2$ulQ*rtz5-Pup*^&EMS}pgxG-ok;;e?2 z^9=v<#GjqAgu#xw5@bORxYH*vw{uBar30ZuRN5*BxLN1EzkVC!-(I1vX8kgcRvlPP z*<7?l8!6Gm#-KE4E_!E?=(WBvo}3K)K3Fq!xBGDJKtPRk)z4ObN4H|ceq+RW{!wMH zE4TE-7XIe+JOCaj?iH8D(?7q%8q}t(q4BbtqxK;^D?IjEqw4$XGajvzChy|KxlHoO z&3$qsvAPZllHHz*_IEe)vD_zUPtkMhqMus z)Oocxa#4-;rmbD~)nz#E;odIEj7)Jg_l+KR#gE;v5`JTU3wo-9+3`e^i5bokPx;{3 z;`4QWtG04p-U^}0ZDiK_T{Foyd^-2J`;lj`#9UCwQw&;fGCpm+8byxiF;P7q-jd+! zdFs9_$b!=l>9-r7p&uwg5Upw>3ajY`i zbTyg({T-!H@2EleKJmpYLv6Z+Cpt{w=*`JvwuLk{4*qG4u0|L+@Y(U8Y?uspC*Zsz zU&VQpzj$}NpKd&?8F$SFf#zLy@2+cpy=Wl+a)J6K-D9DLhF4Y~=A}D*fnz;|i<`xz z`<-rIKE37}3vKN+_m+UY1K)m1J5&B*d9Ztwo~^32C*kx>_39oc$J)JGH?4m2)~^g7 z*5}jp2U#x(j{n9LsaU73y7;@pxKk1JJ|{@M`+lQ68trafR#I-m667(h6tU8LROMqG z=ARZF(NG-8AL=NQW^3*|A`ahM$E+ju>>PUad17)H!N$-uk+w1K)3A{$$?Ua_nGKRd z_vvN(Tz89{K3Si~24`mVaJ|F4qrRwEXKyBJ$`;EmQOU!cOA1Nn*e7Ch{A-V6jN>kw z!Ml(PUQ}Db#OlEIlR6r*)a^Bnxrg%0>yuh*6nVUPqx-{kt(rC|d!D(o2M@zGJ<*$! z-pUkz|5=}{8AXF~3Q~D*&G}!O1~E5z;FEPvynnqEs_tZ9P>eN_V3wCZm4)!jbj)_^~?>{t6U;kXMv#zgu zwo4ECLyzAMr@Z%dn*Og#$D2z0(ejn)F%Di$9XMSCSe8FNSvaao$G`FdzQ&t8mAL!m zMd<6^@ek{)f4HlDiayi#DL1%1t=bMECa-_HuJH6V2w7FF2HkO~D`h_Nj2%Tn)ZN*b zIEL1V%=Lq3MMEvAdeQx@M~Oq|AjTi>yn4L871d{U(It+`)Q>rEJ4Pq&xz|mFC?7bl z3X8(;ulaFGo^tFL>+?5HN6zyuRTWyR`=L_znM}ql0{`xA#~{9TJy*mRIrO#C*>qIu zthsjze%6V|zC}rMLD=-@Ec@!R4aYxT=a5|5XCu>pGu!Q&>w2Flr1lQse^_JSOhAQ;->^bX4iAHw+Sg!1Ok-CNM%yh5n)0Gp?lPo<^QjYw=I^)^;^_}(C-I_a-es;RU zRrXzG{q7pUyRrVyHBQI!1QMNR_0kbrZtrsWAup_>D@LXXxxRfBVQ zJzYQ*fqIs8zE;^t`6vnLxybVCd-cSCnKi!1M?}gFMs7d9lK}kG|AhpP*E#cE2|G_) z``Q?p1y>iapVk4&enZTtLsN2?zDG!~SDt=;!qsSQ?(dx>e7?^0=WC8nm)6?FBkyIw zbw<);J@&elq=Ejym5C=jfEOnHGFh@M`(sghgug!Fx??19yT%zD#F>gpK4?~5J^e{t zLf^B8Fy(xe%}7Pb->h?u;(Rlb*}nI*;iU?r{0 zzGA=1^YukGveqq+-s$B|7T;)SJ@({$ADd76Mbz=md6G37U`u2)nw}2(M~eoQHCkuM z)8{y97|vUX`S`)jlK))&Xnil14A;l&FMSpcv7h4@_K=eT3bu7zw~V8gu!5+V`skZ$ zgya1m6RmgLGrR6SnqRDc_ZXkwtzK_@*|g#edZg9O-%$?FR zRKOH5#x4)5O}skmI$CtusfeX7adXmD73%You0kEBLMdH8 zGUbKc5q|828O^mUcJn{i-~or>L>l6i`5^x2IgO6?jmJvi>V8u4Xg8D{j3(U=PcyrM z)rB5><^NjO_ugDKMFyVpQHEReJ^Hw-NojY$onzFAnq9N^eTB68toU;#{p1bF`ug*k zh7+1-XQ*q)u4o2p>w~l6A_+d9tYNzoH%lY+Q^gM6Grq9>hi9;!^L{cMQ+vUw zjc#xY(pl5lm`{6Sk4979pnm4s{tyT0^r$`bPX@N}IK3MwJjHANB3FF0W*LN}Nt%~2 zY;1kBD4i^GbDnJ-pIyMh#gVB4Ay_EG0!NyvtWbn5)1V``>p57iD>_F_5vh^RZ3&jp z4B3v9@UZXPh|@43bZ4P_V?5$`zeAa-JptW!MmuTl*yoQPQled6Nuqd~?-TEaQx-pw zjUMzE!(jj7T)udmBcv@uU=v1aw5}{4$y$DO(&jPpICGu`SM^KBa)`;MaDTL8xg+a< z=gw;WZE-(cHb5t08U&g%X0L6TGOM~h%w1kiiZgHC9lC_O@#8ZojzysMc<0)aHSf-} z!ct?=Jc(v8ba1qgp6n(!dR0y!PD}^-yebYolRG;McVUlN(n$JFR?*()YqnKC`RTeo z?UZ#Mqs+O7Zj0GmvKzCT3u;0ZysNKa-1h44pN_*Ll%i)p8MXM91>mbUP3>#vNjR<~ z<9UKvbj#iOkmLT%Khzm81HPuwysT@g5Lg^5>$CEhVp0fs)itE7(vdsEWaJ=^EqU|y-&VI>mF!S7k zjvf;lCJ`K+$JAz$MSO2@vF&*1x^6?Hn{TuDoxgl@jbD$ztWeSYH_3K;TRJXtxjo7K z(h6QRK59Q)v^v^q+oqf>w;qQ!xfxEU>u3bk8M?@&D4XrWNPa47P9A+9Yo{T3 z9=+4aJO#ThTONgiJSrJYZc(HwQq7K&^PY)OLIxV4Io+_bEI7z#S$!Vn>GJeQHepNl zlW%nn{)`o;BT*bX*KRAh^RqQVbQM|XK-C>T<74P~db0Pd$SRC^x5PuXBKPCdm=hhG zR}Pc4<7i2b#dUdW*AB96 z+og%#@X@Y<$0sV2i`{#k2FWIkL_V$@UFKDOnW)N^%}8S`xGY;{Btv*{IucH{*E*5$$wMI&8KaCrnLC#&CUTl}(;k1l7}! z{+Ollmvn$9)O79M%Yi<64^hlqPtAbccBKC2l{2;G_Tf5WFPjmp z;d!d8ch9-1GaRwPU=N%#=Q?+8S?!y3K~HX-wY_I2>EmeUtl2)x+0Vmm75SK}&=UU3 zDUC1|Qmk(WT{Xhk$-g~m#hgDn`EXZ-xgrJIF7ju+PuH>kxH3et|Ha`7wlPmy>wXHj zHJ&N{%2JGBy!N8`#>VVCKzn$c2SO|v(t9U4po3+xH^{_3cb&_M95v%0u^C$x;T`Oc z1*4(NU}!L>wdksba4diS;=7e5t3XW=?$`_1`Q4*MS^I@qDlLv)%#Oa%#9{%0613j~xXZeg8DF(ILdK<{tzaE1PVX zc8g53>&onCx{;w7tIr04+v(X_ijx>pf5AFUBl zmBp5ih*IRBD-fdYszP?!pQ1Zi`6SCb-f>{OYLciqUnMv5+sjT|$2WM~&>cd!YVs!; z5L7uv(qf-$>Fve(eGAd?t=50bdvP^V+Lh%-x}loq z7nwSX=N$XWJU?q@v8ch@wmi|o^JgKQUp8l?!9%AH$m6Ca(`z+~>(cXJ?|J4)-kavJ z_Wm#O4Ikknn|`#eIP%VBqZ~fsC7$a~Si4dyo+F}d=W3R-haC| z^^87t#>0H0votB{@wt5TzLni9sSG+iS?7_xJ~jFKY$U!m`xeZ=yBiM=V$`-!x+baf z{^mr;V|{0gX0JDJ^upKiKG?tIXB7KIJ@If`eK-NDi!^C&*H5GZy|PD~SI6XQcqc9Y z%h~e~-^z+Yg<{O!Upn%r>q1WDX1t6yk=~B})`!aw$7@KN4`wGHu6cPYI^aZi$cp=D z{(QyA6>k2B_bqw({74#j)e`np`L*jrzfUzUxSqg)!7By#QEi?W80rkLowU!M9c zXbR6Ds2rATjyq7qx~>h8z8as~E8ET3h587;{SrYGxoJp6y`i*{7qk{rlZ@?0h}&oi#_%InE!gE9aSMjdCrs ze|D$c9dq!za}m0!KA0RBI?%x}|K!KXfyF=?wvcV*hugC!V)yH4E<9+AG=F^VgG=H8cWNkZpnK@eb+xoqN<=JMu1LI6sF}(M${I(IbNSTL<4*HdVjJe(CpDf5Cof+4EZu{_XnL-t0eK z`>l0oyhBJ==;p3(Gw+FbXZ3yR-stz}{ybU#>IMC$b+&i5>GM21NtpaMYRq~XtDk(3 z2ktYnOL#<+MX72(Qig_4);P0&wb5Ay zA8#bThNmhHXLzGHOqO}Dvaw0F#qv;f%&!M!dUE>h`h9xKGoo?XWcoJ-JeYmpv->-G z%Ak2k>&mVn(Oom=8@PlL(aLL$yJ-peHQGpDVrl&h@z?BZ23jV+ zp~2DmInb)7J)0r)`Do2kW@vOHezN{$+o50_hyWppSW`Cm!TNuCd1Gmf`DBeT-Jvu( zcL^QmXh(o&2uE(L@U`g%oPvicF zJ8W@2IkyAXH{3yt;j=o1M~@x(e`BNTS));=8ci;}8XX^Pcs!!Lqy}pF!qZEsY|n$1_}}Qthi;birv^FpwI<^3>;GX%#NDNDrq#xb_8(nz zs&TPxH43U0svonwL0fjif=S}KMcmhXm?h(5dvd>W3>p;;k8{rbpXb)l2x!prxIYdr znrh`(>7X`WA51g?O}fIb;~!?oD_iSpwA&M({nGh8t#Eq}EMR}VSx2sE2B-%c$b$71 zi3cV5#Q9xCMeF#g|Ehv0Gb}!knQI`=(RwGO!zGW`_xVP45Q{zQ{F?*z&gg@<F?!IyN)YzwM%qNT2$E)tN&p@XApVnt@s%`Ipx3_+D+HGK;!3XP% z_87Fo;DdGb+(rD(N#}GVI`3?5d?zdnL-`MBWfPZL`R3_rRs;2m#zh;~jr>NoBbzFp zx*0V1L2aBoKXFi36Ls#C>rSijW4sK#?rW}wK?&YM`Puu;&x^$*_+njI zEIp4ZY|w~DgdU8kBl7OaB6+QhwFt!%AQV|N>bY)j*70ZSjOk5Iwq8zviz6pwbV&ot zDh8QL7s5^eoR$yf5ucs%cRs`_=E-A4!4KEjpRV&^FU`p&-&!*Ar?*0ELjmxIZ#yf`o@gql*eAQE(d9osB^6yi>M$uUFWCrLrHgEOsu{VQ)xd+ZUEGEsE z*{}Nhx}jS;g9Ar7?)>^@`N-rAjy4M9xX$GA?qrNsRDSVr$5e44YGW=eun^Q(VI+)u@Lz4HTR4+YbwY0QR-`%YkFq9 zvfg4|Q7=qorxvv5>6q`ktIYS=-#b`@>wSOhvqgb%or|aNh|R~@?@p2~yFoL};Adh3 z`iAy7Mn~;c7|P>*b}Nv}=P&VNW7S-rRNC9tdevC@bd^ZWyn}()o}?0rm8Tqc+Bov7 z^*33TTMVKOS{ge9aKCEaD7si*yjj#gTJkzt-_Qs7oUQ99yElfqaqmM&62>x@$k96y zd6ZZ=^=#a|zedVV$^N7D`Bx`fz5mp`Z!CL#vd+={_9Q+}@OyZ&XE}vT;~3-6HN1`l zWD1VIzy1wuSLhj!@Zr#hyWSryB025bz^ z#BK{?vV?ET_Bc<%Tm6yqgK3SuQ`^Am$?DaIg>91u7&llAsG5h5v z##JR`b7VU?boPwL%l&Up7mddpipF@(KVS0nZ$3n(lbdYpI!bKc%lYxiOfN`*4l6Kf`9{I{sw+VlDaI#T!amTY;k4Msc+&YVO=0-lp2ONBsX- zxdoK{-U+2W5$eJE^k3(fhpWyM8|-KI<`MbH*K_2_omBQSM#v~@3>)|o;(lC-2jgt{MFj)W_9^?tvcVX+1yL;^z^$o*%Wu4t>aJD zXTPyMZm6T4$&{NS3tyk`0+( zgu>sJEs)YBdAQ?YsEi<-Uug+|uhbJG6l^r`cwO2-v{;=v=Y_)XTV`uKb+BR)M* zbnaDek`16Gxtw2%r?R8qkqJCq|H9<&Eku5}KHD|){yM&o zLV9_?lT$3=ck!B*rov^vEKF@MbcXOAi*L{Hj%s?u?N%6TA0ixrWeG%Sl70p z@=dX-o&L>5@7v08iXKNtH#F<7^BW&NfBTeSsZHh@Gh3B#PQARJuhHIHqtCPa(I;!- z6{=tU)G^%!*g!)MmSo3HiaJK&QDpP+iNfxo^FB47-aFN>&rY*FUD35n3|g2?boEqC z9rBL3-|p$Us?3HSdjjW^b;iTfD38~#x;(z!f0M_c18R7wUZqOEJ|srh=e&aiG_@sM{vvvW{XKC3de`R)%~{&q3)J;+ z8X~%GusY5@SsdVf@}48g%EaQ`3K2WX;yo8K)Zi8GpRS&rmfdqB?ywx!u=37yh5VssqPpT@PkL}1CO~xzMn)SnzTxQ&!N9Ku2&DPb`_2#)<^Nx%rhCyNR zSriyOi|HXg%6E^YJUD!|njxM}$4Q(cVAJ zI(_I5PuHu^KYs9UmNbeAk5A`_Y-Cvt#RIo2(Lh?VgUOXiPE?GRGNZ3@4GL-89JnrD zj0^npyuV(wey}Jzu1P&uyxDVNrL-ECWpuR2G?I9-x{e9+x z6H35KaqxT$G+zH@kM10n)_Sw7U7jNblG=I18BNtkJ?0(vZ7BI%_xg|4*hQrWE9RKJ ztcQf*n+lSBkoTtlcxI!Aq%7fFFRT|5SE2Y-kAp|2|BgVosf^gwcsgyJ*E1uBYq-w0 z9xiL0{P#~TzJL4T`=4HX{}=1~Wz^nsjzc!yJa4UYc|i93)=59Z<@eVw-5WVE$2D1W zSnm7n;!X4*_3-={wuG0~*;xp&z1%0@VR8juV>&l%8Hq!g+*S~mq{&!9phW+JluhAc^dER>P zuU97Ztp~2{T{_QKwxaj)_M*|1YSn+eetm!O>TaDuiO1`^44XBKtlW3Z3s|3c2%~yB z!S!D})qv)!_KGd8QQ7cYG|6m4gTGwzl~ewFY4P8@oad7@o8QZCFVB5^I^H#Wy(+)B8|m@V_fMAGjq#HcHDYE~U5pPwo~(KH-9Oj3x1#3Uc1X&~$)?UI`IW!s zJ^gCcx|o+QiU*+|40k45)v^8R*U!k~$>G~MEy=dr@Ec1Xc`xsmqy6l(E(68X25E+t z@G4%*o<(a`AoiPaNA+jx7(Wpm^Nj~<)E};^bou||(yyzF_EoI%q)%2R6Qxz2KRabM z$w$4BHU4tRg~k13jat(La zn$yjB7K@s_ms;NW)|Nhp(mdo+K=#1_@ z>Yhmvs5KsWE2)}MZ&FM+${F{p6-{!6Sz8aqcXSX#jZ>yfo+2o#k}I*QkJrfQo4sre z9qmv>dTC$he2E+9_V-1<%OdJ({_GUFiaO+eUgd6HL{N4k){*^r_Rc3K51UF5_xyPL z+LhO?yMNwPl4ja>@3B$#Qam+d@57SYSD|Oe&)2+sbnvg-C5zoXyz)~0RoIihjR|RJ zr}`cL_qhl?etF7)>G#d9!xjERG}pX(>^MNx5yP#S!~Ep)s;kd6!>0dsm7Y*NdtTAuIaH-MqYh+m)PCHI1fg^7wF#R8`bEY~DQG23(CLl7X?G zuPex~{U=7%4;Z_w?~tUAmL9f>c7JzTUl{9!m2_s!AsYXF$z^*)Qj>Y&WTablB}U4l zJO0VC&Bx38NB(F%*5Kx5efDkP01rdO-!5qmf8wp@r-zQB*o&9vy}xRpzh4<)_CQ-c zPff=*?cLCKwC4EMgFiY^$G`r^Mcux-8gMd#uQCE}c$4}6cF8uWU#FoQ_4O3IdW^k} zp449@i6ieUfF36=e)ZhvwpgVi0#$F?y3L*wyqt?$3Tc`abuo%tW^`c1U)O)APBGXMdI1c+NjAZ_qn^(>d>7b8Y7H z+HiW9N1dH>A`%?C@nXt@gD1k0|8mm0Gkv>%h2yPnu^MqEgxgkpISL7fL{o3IdJV_J z=VIHn^UTkxWaJ@y*rqmTYmj{+7uxe$nuygzqja}?qoTKoUdFmT|7F; zD7-2*lccx0wrcU#ga2u9b$jUE(vaLwrwgK>#@OdQ6KB!wWp@4EI*NaE%WNP*wjl2_ zHwk`GU7x*Fxnx08{e7_LLe*GH`5!5~s(-J-arVgIoDUrb5l6p?jp#11k!xpN9{cti zU3u9}dTZ4VZ!+Vb-lO4PywP>KQ{P`4e6o09%Y68_0@QDNC1A_$a6DaB^=wIco)vky4)y3{8MMTQ-nwEt=XLJ*!+je&u3o;gs&PA-9-sdG<3)>a z`c@yUu2(xx>`$q(=l^vUqT%Rk=XLV&mtD>7HDLY$m5c+ya75Dcmb6wad=JHV4a~E? zc&x-&=CRHmzf*^neW?rUHvPLbg7fD&HSew5>Af|cJ+Qaye0=)7_gKHTtVBj7(jTSb zd>*gMf$HZc>g(;x1dd$r%3b9hB_s;qdS3@|K3!)IUg@E=UW-2O{<~ej_D=0>9xRUNz#8YL>)U%vR_21n^_Fzj zeHI&{3}Sm*C(qBCpRCW&3?|EEbQ$(B*@k&8yP+ShS;Fc|Ok^i-+Sh!1l9=L$GDf2^3m6KDX-Btv_D%C6T^=k%o|e!uKEZ`zlp zg%?ZCZ+`yMr5zagXz2(-{XVN1e{`y}kFmGzWHJ_g{$&0Aqf^FL_obXs7gSeQhf1xk zEB^bBqN(t=%aS=%;$wMR-80$rb$nv4>W0~c-=4vbmRI(k(b*ZOn_5Nm;4UjX zuZ|}RdA`PKZJ1W&iRYQzM%uxo@a%S3f;@CO2O`4{4|ILBs$bE7ht6KGJr-19OXe1N z)5%BcbNGBY+LOD{aBfDq?5ocC#*&4az@CQpm!I^Ufgh|-B8lVfI{D`M=DdB(eF&Ya zuC)77&aOV~ZiVlxqpGVJ(O7ER>f9f!Gu=y~dp&PHxIKB4r}$J&R6$u6V6j%WdYhyk z(LB9?7vPO`l8(AXt*W;4E?Tp=R+Z3hR+WTW>(lj@&HvM>f4WzEoNevoKdj>@;bp$- zqx^J@FM9CmbLt$OotNZohE}!7e-J=Tj>c+f_Takh&p7$f=^PwyUF+I)cO1Uz_u}ot z6C$+h0x#wqWa7tf!t37m8=4<6Z`LW@FG_yygGe`?Eo%m~8LG**Cn98<^(*8!tr+7q zesB*By9-Ot#~(c-e{`Mvd28*|{Qj~R7Wr&_yZ-s+hqrd5vr4YS51B)H^8&{nzf9j>SxNYc+}@B^Wzoz40sag^l@e$2a3rc>OC+SU#G zs{6_odCMQ&Sy;OJll2W|^-VTj$GLGX&;Its+0WP6^?R?4{ihda%h>as`*i$^i*r9( zBa_JS4u09L+;!gBmCv!7pRL_5@|$^cwWmT9$?4yD+49z)=b74BRj*b4HxiY1uo(8` zew8g7_mi26caN>T={SQBb`TmJMeOjc(>ul7<$XTahl{@MNgFKqhs7hVjuB_>M}xwi zblU#6zgnN+clV+ti|xDOm$_%JA#UYBY)p@aE%FsdkFq#Q;{T^ERQM{gtN%aN7B*e8 zBFJWKnLqNEb`FmW# z@2o!a{ydq4Uv5{Xal6heH&d(p<+`FX+%c&adh8i?rhSvgPP$&US!8^6Qckww{tkJ` ze_k`7>aF$L?TMoB*F3i;3x*@rH+nkaw#?R%y@Q;^TMve;BnFR*Ui;o`-r)F~MB|4` z6J!r_Xrg<8^Ith+crOl&HeW?0?BVtD(DrV%ALgwGo@S;p6(vL`XlcZDH%t^MrgV1- z{flIH_uLf!y4tlU5nbdBY-sYGu~N~+wLe|4xA!SbHrBlt;aMI2C_ZLvG6;8knV~o_ zISHwwht-i*wb9rhx==Iuu`|Q`%eu+&R`s%XHm`S$FLi@ieTLj5SZ+xogSw+LIC*kj@Ky8V z`dOP(b~fLVJL#O)4mU6J57tR`X6F?fM_3oVsxMjDuh(al@jRD=tn(y%T;A6;=;T>u zx2N-5O|P4#*3e+AOn26yVEZ6;c=>c)cf_F?8X?=!dmGFB)l?B^|T&uam}}h*y{B#iDvV5a!A; z$7<&|O6W**D^u_JBxzi21t;dJc-l`sb1um=tNxV=Hl1(H^NWdg?UNLZzH%ECv*msPr_99K~^Xa-u4!Ps?<25R2 zc7^$qt=$JC<{Qf4zHHA3eD;&o*YJz)*J3q|v-fhPb32Cf)v{$0&CSyB;Hd}V2QFFp zt0W1J@<7z1HVGeb%8|{ho)Lb`jXs~vAcLW+$-(~m4g-I;&WZBq>g?BdDWL&EG4%XOpY@!}*a@B47WO2~S2QASF_^x1psT(R?5GvV$!Vr;2AUtFq9QGQvK z4APT~vA(hJh|KNgR08pKN-|C)UeMKACdaz}QaqK33hGHAfz0pgIdilR^IG zn!|K>kd=r`;8&Te1z`CQ&|SmT79I|ovku^2S+MiIdLBz^wm z^K1;&5Em}6nelb8f%S|OScx2fMyih?>&;8QWZg2f_Fl%h8i|*~yDAGh$(r($>k@x( z>U!eiydMDH#2jmZ`RTdEYsn_py^(RYn4;GK`myP`U^*LXDwm7H@n?&K7^X$smIBq;1 z#YfvKe2jC!)o&& z20e&yI1n4NuJIMWrLS#&GybIv>xRf6Chp$+f#$JxJ~sA;o8xGq&C(OMA1#T79Iuvy zKEaj)&l>MevR{6@&GFYU+L57Z7U>FEW>+&%2bpLA90Pn=8F81W7xtlC>>wu>N=T{ymI#&GSVEq}}z5*ejw9=B9V?ZC~~HM7>Prmy3EMI3F+f*Uv(5=WH2x z=DS_#R;N5g?0i+q4w)Y;YWAKo~d-mvS;OL%hNekU^12J{c07`f3c3y&9n7C zJ9xah#qXW`Y^;#?nL&oh)BkMEVmDrI6oME1uD2-S(wFmPq5MZaOgCn!XPw{Uq8i6p zG>%R*Os!RR+u7^e7v(mdG}pZ`=WqKGi;r2ydA@O<^3C65 zEaY2UHp_KubX9k+yHn}eI?qb|U!3rhjoz+GujgLRQySB>%+UTU`+J(F=w%%-&EqT1 zQ89XiEPg*`6cF$jk;%2pio}dU1LU?diM)^Aj`zW;WB>H@L}7VAYr&|ahxE$ArgI8E z;NxWy+o5#+MwaJGt7Azlz8%fUpl96g zC$^W>&D$*=EeU%{dr|qxT||DeA}d>)_iVXeP8=>?J6hiHXY1%hptS zdr=RGkDl>*l;pAH0rENdP0@zU7ms!i#~l0qaq~{pY!5stX4lg(L2fV{l^NBZFJV91o%P{c%4&e)3XY*CQjmXZ7%4uygk~ zUT2NhdTaMB^FHc+75!hvku;HwhGiq)?pY`{UZU&RAxV6ZO-$rJj(e&9!H)4BXg2=+ z>|_n!THha?BFm?zDq=Fet@9A)zT}N<$1j`8PqR~)`m;FKR^@*!w4q{bJQBtU*pN zcQBD#>j&5G0de)N0QU2GRE}~L7;s!I?78TJhHz$A!Fxq1uhH@7ssB9TnwHB*M$2y| z`^!;9Nf|-omv5B)-z=GaxMVTAz1cg-(u9>**UhhCc0Tgzx077%2A3^;uzEmNw!X9E z?hPi^!%1wc@5_%SFMDV8+m7RHt;?szz8m|93HP5NtiQQwx_<>-7I{OoIomwtL1v@D z!4c7@9Yx|1x#N{QuU9f`@~8(olF7R6i}>0xG`e<7`+Q}ayTkX%%Lo^hq2$aVYZl+& zhFN9(`YS$rLG;EA-n0fX|oR7SbT86tRFt*Mx%jLmUpMwk^ zEgD#A+8|vW7II>vt_?xmQTA}1mjtW8(h;wOs}pzAQFn6tl4|eyu1<7DZ`OH7D{7=y zdzU`rJL?bM{HvA6d6uzi=h^z>UOdl-+y1)kuo`OL#le%~n@6YzCcjc&9QQ8c2RHw1 zP+7O&`Qm`@rqS7}sV=SJVsmu8<-?lF(d&YRKG!{eY+8n6jH4I0u9!GpxUGmJt-G_} ze9ZMD|G8gKhdhmxk=@ru{xBo4`t!Wvi?8Q<@Q$_Jzy5X|&4=3~Uxm-7U+2FQ@2cI) z>18n83s~lD1jwXg1$A~+IN2XB+&FQR*hUH~0-k_VAL;w2xbohqwy#ca1>l^X-o?gu zM|$k3Zu|`b}(PKYI+_WppxlwKYvg2w7oOPdc)@c6Z@!gaBP)>s*dq|kx_OWu} zbkv&VXf|(97x2v4Pqg)Y-0O@om5EMr@^)PaLZdj^d#a5$G&MijrhC>keo#$uoL%yseZBctO=bd)_apu~+j~Cw+?Dq2akCCo{nF&I^uf z&c)7b2%_XUq;$DEil^ii_^yV8J!SWC1GibrZ3TEKb89k5H;X-v>X|oeB|L}=nzqN#Q4%Po9Ira(cDQ@f`SOzx>NsjS z4UNMs-W-y$7f)&;KWOo~r^MYy!>Iv|GyT`p#Q!hB-`AE&P(Qk73|2+3Kck6g6OAakq6I^4Zx^Xkw{gI}gkpZ!|L2jQeuMXoO5xl9MdsABSfK3ZNpPZ=t zax+`)hRu1*t7b3b$X*Je4&Cd(z|5HLiM$(Uq_0&lGjZVBSCb&(`OSa4g1tf+Bvqv_D@6{PCLQ zr|ZwnI(y#U$*x#Oc}IDO-5*ca5t)hl`Itj~w7ywqU=z4FUmFbFvKP-fEJylu{co0b zzC+UKS%tditA644=pl3*jNiZg-6_+cp)BlvxAB~^*1S|#5FejWXB{uei3pCf2(iA* zOnzDpqi<=KS=rj;FV}ZLl|z?bWQWP5oV>azUQ`-cA8EH6Bmc_}>&@2fn4C`EnRewL z-jnj_T?Cunh`Gjc_xkfU*D*HdEc%`-*m1Pzh)&-in$tgDC};V6eIgH8Ks~5AKOH!~ z=L8u){`ggS+Rc*d?P+%79cld0va(+;yPj*FtZ!BLZ2Y(bznD3-*yzo8V;Q@1#dlik z9V+8$XAA7N>q1Z6+qyz*z`mk+_OTr#WO_V%B)ol>H|*VaojX08P&{kiBRyQB{&KA! zR3Cq~X3X1;(t(|_E|UCT7Y(1?Nf92?;CUPJeC$lYS{%#z!I~qEgV=`oT3#rQg!|ai5Ie69nuK%jk*o>J-NQErLMS?%OK%V22t{AiTz<@R1a1r zv#Cv1JQjxk^=W;tZU8UYK0IDoZkQkQt=Z$Y^_6AQ$)BxJbqy!$`D|I+_Chha42aB% zt+O*aJSNS07M=h~X5!HxA)U3ukw)y<+0pm1%enc*8`^pXsVm7k%;_COfPTih@=z9^O%d zE_f-1%T@MsBAsb$xZ7&vM50%D#yo$@zVF8i1A1mTT=1?&`^9?(RV#aZ!5WIE2il`G z-Ca*$giztZM1lK$_+@632|ZaO>TlU2l2_i})p?04amwe!BvwmK#>v0M3lgNSbgKK; z9Ts&(8^L_jN1l%Cw)L{S+25a!lojllw|$7Eg!fb1e36~n=eAcJKRg$uAET#P;Jb*vd1648p^fXewGF^q$$;!tjZ{5G`LUd zliS@a-aA5L|MK*FqIpVDTFO(c16R+CEFP^Bl7tbXxHysLPc~qE z3H9a6$#?fYvX$w6JUms7FV=V)F`_G);nB& zRnf-!RM%M@o01`XW7(4T@;EUOtss3)fesjVr@#JP*8S1L| z=UI4{*Cugqk~a6FWe*>&t9p;k<*d{B`FNfCXwA%WHsz2k4Yt}gUDK`8Un~hhu5(^Q zB)_l*HM;YUeaptA<5maHqb^B*wrHkJ)bO8k>?E(PMHR(oho={W#Bxm03uWU`uDhi5 zoUV^g-KYDbv0Hnc_0-{NI4lR6vH9lf$F3&Xy)QOP1}Mk}!@2Pb|4+Pe?y;+5UZ{hk zt;0(S^x9shL-WlWqC%AYM5Z^9RrJ5P4o6d-Yp#dUb4AbJndKb0B%QPQ{l>I%6Z@+i z%_7A$tF$bN&wpd(0pD9l&Dz~VdAt7I@8^1UckIdf-`%3m*ID`^yrcV6dLNYEyh-VU z(|J92y=R*G<)gd%r@F$^q8yw1P;c%=a#yRnP(1_w?b9qnk6*rX$A9$}x;%TeJZA2i zxxUZJ6Vd+VIzKe--CL}qv&RDR5O^~dmaX>0Ix_v2hbu_CxMifQa7Pe12%l_*bd%*w zK69L7GMnPbJRz^ObN8L4`L~vAy)Vm?>Y?GQ_Hp1gZ9H5Q_)BLGPm&_F;Tk=#=9okI zwmG}b*HK>McQ_|q9Kau*XKY?iqQ70gijux*7@c+P+KS;aY3w^R`1{z(pR5r^%16##WhpZ6(aTq{6?;xzXDxAj zX)oVivp!gKzS>^?)AGilD_i()&t6!!D4@G}%~q_Xy5suXR?;5nsBNy<$nT3MZ1l_6 z$o87AVj*8_AOEoW_WwQO#uwWGjb7TpSpPK-qCp-6N!)``rC6>H0jHAE1!8?Y>x`$@ zebv3Nf-)JuXR(#jloNft&Xntl?te(M3N7CRr$!pk{nJHV7;mkwcj2gXR9rd^?&6;F z|1cIyCOz%8=sWtzt8NzsavuMpH7+OWR>ic2INivQ@O4%o^3_e1Nxy02+MauR7ZZ(f z9utdTVq{hlQbmzxygogxV9A1dYKir%@*tKu9WFepA*^Wo#0qJr3Ql&2?&?#vH+K}w zxqh>j={}-)ek%M^IkH9LsZ)$pX*%Ho|Z+>t6b?*Ur$Z|e7Rd89r`*%{nef5-aWeZ2^RjmMeYl zYQE(xJvQ|ex>TXFel;1}tQMGy+||Iz^ry=rMz-icmk8N?ruu()>2Ljj_Nu6ujPv%Q zAnW>geba6GblHmQpn#57j7*Q9{sbQ8o!)=G#$yk7K@ z+M(qKrzbx}&2Ja&tdIun60EO~ws|4hK3b#vaQ%^ar%N{DdeVHbJc5j%)=(^Ou9x7+ zE6rRC+LCjvClNX_&t|i(k9OCa%eQ&vUwar)qLPU!m1x%b?mC8c<2^iKlku~URt8=5 z>(h05-62bFNz2whUE`8AANbKa?>ndOzgY9B1ER(KxM`X-=vDC`^Wf1lk^XXhdc2P1 zrDKWn49+?q(^-Oqvlj2YnbYI^`ROe~Z#oK%hU~NjJ-_-`mlS#1(eFox5&n-Qsn!LH zp~u~c=O|Us^YjT>i{D`X#7P$L)(NjBV!V2k&zE(yB3^e^RCx8-!#l5J|7MN8 z=6qFFGH2cA;+@m=;l2)LYZ*oPMxO3b``s=P&7Q#he1~$NR)`=WpX2Y1RBW347x(X_ zVzaOv6@%%X4yJQ6<9Hrq5v3=chV%1uQ}US1hWGG@Eu)PlI=FL}LCC;o(xI#9z0O6k zuwBW1nf-VZYd&7~^wByW-h^%aU#1kA@V>A~hFB+otVx-#(_QumOXBX2Pq@-&{n__d z47VD!d)T{UG5N@J1nM}5nfK+nqvpP>6rDf4=-LyD{*Y%M?|iF+sEaNidwY5H z+&$adlI+L2SyCl`SreI(SAFrz{OY*Y#NPQ&KAC)H$1@yYt88vQiJi_Ow?=Ozf7dCa zCHYBvUHED1`rlkvbv}L0xW<}wf0<=x6h(%XykpL~&X=ly1lSes|M=xt$G3sV?PcJ} zO76&hrkYV#{cKS-ygyy?;k_GYzP-+6ZL&8Ocdb%}qnFyqbr`=Myu@$h+T>6h8P za@5AisdbKh$8Y>>3`y$kv?2GsKMCKn7YQ#cHX*H%@yJ-IJ|GMMz=vjxIesl=~pRE70XWfq@+Cv8C!F$?PosG>Jh32ZZ z>;`}}lhEZmly(5o<-TfDI-Q2m zHM&AEdr&5NnOXM*Hz9U?zpNY|@b*}%Lgyc>^L2LS{cS8N+?(nj&$H{4Bq8Dt*WZyE zUq;P-+8a7aT`r}*I^Lt=N>qxb?T}#mt?%Hzo=RF1wcB;zmmi(Z^FObydau`J4{Yxy z(AB(;Y2j3SU6ak+oeKX4`*1mad~-*snLTwz&c@P4*L&sH5h$W3z`}fY)y5ch)Exu! z24#{;N8*e*lUMvsL=6?&VH09brrd5}_D`Se3Lk8-aq4Qgx98`pn*E!r=X|s%{l&8W z|G4N@>0cX1m!XQaTK)b^AFfg0I?KiVwNcFES-Ek4{hVhf4%9{2##^hOf4FOb$1duw@@EDFYs{)#A(Uc%QB7A(V4w)zq5< zoN@hmoFbC?hd>gFLgO2E{RVL-dYQ)vpaei7h$k_??^{%?kQ#EmoO$)4270!+tbc8&` zjyjM(IX#P%M9MB`ZTmpf%?M*jtr)gTTs^IW>3K~mX`gf@$ch}3@Ap==ZU3wHCI z@Lg8Aqua!~Xc#V!BV8gWPaTSP^oQ!z**r4IUV9$ephIV{By;9Htwh0uKUCGp>yEqM z#oez{Zg@}r|Gi6Xay565dlL5dmmTUx-7cGKUsC(WXDzaRlzZ*ut*^f3yzB7gI}NNe z>t^e_n^X=7N!Z#T5{e(KD`59AHw)u;4LW|9ZjYmEG-1odJZK|kvab7Ghd(4w_qhqL zUd7Ls;l%v}RV*RlwO-PeMl~%-OdcJ^p=8fGxGnc6R?-4Y@XO;h-}F;MGUpVT#K(Cu z?#+_(m!pmjAkgna-R|Um5p7>aZeIsw$F;aGqV3Dc?d#C$aozBXsQWUK`#NaT^^sZp ze~qr)cl+cEX|tEHT_L@rARInFrlPV-;=@%j$tHUL3qLwu`PN!l?LO#v%K=2IGLxIC zDcW&!?x|%Dc0JllH+68CMtwwg9YK-SP}2FXcWvGTzM6zH_p0+0c03qf=z8FE9G)>amPB(IO8jlV?|Z z%#EsVGRoJjyH`>5Do$l5yN=qq%A3i+sK>l>s%U$kUc8j!aa5g(A20cSooI-Px?)=k zm%fe$S!&fTP1D(%Xz0=EPd2*Ba;m-K_;q*2rbhp7W=FTH2V0FvBJ+dXrxV66?90T-@=NpVBM8-Do%V@76EImV=(J6xcUbf5bUe`CoSB zph~mOQ&00ME>(|JB+L z@b>ylm*b=FuJ1ovJ>4=^a(T2q!|VEoZ#_6(mB-YHGS81sJ=E{5^Udk_@t*Qz=*csA z25XzH(MCsCZaU3ioIG$==DR*iIhTp?@En5B2kDcVN|Dv`|DK5CSzxWyk!~85?fJc~ z(Oj2(j$GR#IkV%6$GNleAJ@OFCs(D97dRTmpbt+ZiZk5$n{3EFessQ2o_yG7dW;5n zm+xiH-(R2Vy&4%U?f#rm|7jiT{F^&FpYCBgb3PhS86C4$o|^V*RiYIWNo-ROlC%@cImE9ac^cYU!jqte=V9vs`q-b#pPWhXQIw}U=Q z!q4#AeiPT;EN*TWjrvMSE=)Nht~~~McWYlLh(p(rlq3A8UUMF3z(V9YsQW~~tw zH|xs%PR{pE8YAP&)d`q^;w6@MKvd>O1ui;tGqXBBmd*h6iD^(&O0Fly_z>! zSU+k7#-r?=lJ89 zo@LDgNi$F6Ev&^iSI)ClMzUost-h5%y0T}HScl<_$5ndXJDQrjhNtX2&wQcX#IuKI zv(pI)=X-Lky(_A$vpcqFW4s#up&J>HCgjKEWD{wPB;-n{E{33`mAy17bA+fyHrAu{ zKN~hWG@mSGNBW)D)k)`LVkr;G`kI>`?+gXP)9#L4`Al*0{=1ILLeb8Ol1+LYPLGu1 zyjf?>HmTw{--jsX-)jQ&!ZMQE5%Y|;nSu1o3U5nnKjeUQ7s!U{}O>YDkNz%hu5kCxbhU)Z@ zuA^dB`0a&aL1NSBjg5JeS~l3VM|7Rav0tLGb@eUjJb{$SghWWeF5Cy}{~w;TMgpW6 zT_oY$UH%OJ(c4p(LYi5#5Jk>?_}z78_Lv1t4BvK8d}En(OU7w$EI%%2tbNWy z>!VXX!5Z)|&&qke^c2T9r6<-vGrwDBqAqIU`hUNxwA1UB0~@?%W3DF0>PwOeMfqRR zdT@o5oXyjn-?K$S@*|qxE_urV>H~yT-g>HgZ3nbFHG3L`ZuYaKIZwMbUg*|-RK6De zK^2xg89{MjydWyGzH8XzcQl5N_){UsBjS@xj!y#do!+{S0g`0JtMyaqgd)RNu9Nm>))X_mpSF;v*wkfj@U=1S+WAUzh)~%o*hr~ zQ+mvT!kVQ1c#YS+Yp(Jw`*^(gO`i18TGv0_$+k28WXbc}>o?c^>5^=cG7HJz2?u@m zHr#63V&kKA26=W4Px#gPYo^QVUq}1c=J*>F_dWCVoV7Qfoo8e9 z9{9DW87iBD=JGF9j;PhQ@($;^g2aAwiW>PC{2UZBitqRP70!ib#-tVBQ9Vyh+E*Q` z5a>-(?FA1#&MBQ|Ht{_Y3`0iO`)RW`OY*lb`Fpx38O*I7K#3X&?d2Dcf$fe*lwn_& z(0R7aR;S*CP0)>3h0El}JC8G_3kb#H#{(tP)VcS4v#Va*jV7bX zR(A}5!{rf|S&7m3q|B?hg74x%U058`k$l0Q$&N!nI|fyV6CXnzJPg00nK6%dq>N9x zPPWD4c@qyY!?SgbbMm|7M(26ZaU@t*ybQ_gls?v$aT20z`HlsdRU|v^f;Ru7MN?1h zZS12)|DX2mrCG1*Jna1WC_s0r<#Z(Zl1|#Wx3_R&k1{!$as)+oEy?*km!My z%TR{1FBUvg7gPfW@2-8&>mRSV)Ic7s5!pGkLoa@wR+7)^Af8t}`R6lBLH zFKNUoJE+|!ayxac@!4o>Jo_!Rm>U`1^*sC2;4=%znst2Nj^oHgI?^+8P`qKp zvC_pMco3iIu^L9>W?6&KtVOtK)`NqZ?#du5Bx`%Nq684+NvcITGs{2RJ2dly3*JvP z2?bPfKuf#u0~YzK^eT#scJ{3(W#jne)z9o=kIvZ-#$;n8G;4vzLmTJ4^s5cOtdb8y zt8_!H8SBYGsU7Q%9nBxGY?H;1Np^KsoXeG}E=*N3dBE3nw$Zky4r7px)cfCG8Q#b1 z|KfevUFvFa9S`V}P^jhC(-Gt^ESZ^kxJAc_0Q8p*sbkCDg-SkyG~mfu|w zEU#o9Fz(ootn>U6g`qJ!!5ZK&8%i&Io_8o^!5*)kQR`f}g|FHRDH-qi-s)ZUc=;Qx zda+t=-z4t^H?EINnfVWv&v%b%5##(u7ReNR_RiSWth>vHP5#pA|7f-R!}b4Ig`q(j zk$pa|>&*=PqP3nz3wLy$y%L>Otj5KzqJSD13aB=LnFP~)MWt{U8KV!V#B$RCpUnzt)a-pq<}>b&iHo#(0k+8aBc)Rj zAuCBRk3i;O@^FoFcWj8tXq+4vr5g|?PsEvU2OX;u4bQS-2K!IXGBI%BcXXkPycteR z#uc=%@rjgyWbiGDM*-PYCvxc_ie`1%>JtI^bHpj?q|Fcc;H@k^8>7n1dS>-3!elc#K z8;Q%KvV&+hmV8I&>CWa&R>}EG_eK|W-~xzHnC^jr=2fXS->xMZDd@|8la8A{0_;h9 zo)`^B;s>)!`$nSvcD2FBOARQiKoRhv2f0pKjTz6%0{IznW0e~J8><%S+Vl18v#LH| zIai;yHf+76LvU*?=WJ6i@fz)6CChDLGInFfuw|yjhr_)rA^5WrXio-b%-eo{dmT7D zKKhxJ#VKB#=<*zw8h5fc(9xmVv7iHM_EvNtM%ofQvURpcJSbSJu%dTTYnG^Bh8;B* zzolPxDUf7Rne8>3vGDP10ekm%@7tIe&U#UNVbrX3k~R3CYB~ld_)hI~tPu#s)#*o) z5Bon~`asUMZ1FE-u_}R)${foc-b|0qQmU$0ES_APS4Ssy0`sLtB!&69OX@ZD!vo(R z9+>{#>iu-#4N{O_T76^Rw)(G@a?p; z?=G60-$u4=)ZDPdicNjN4Lst8@qKeA)nE{`{Nud2Dp}@dKKt&cS3&sxT8DkP`p;~) zVZ;-fIeHKr8`|kvK8$C$`&WlNKUlQx?WyrMsV0xDcBCcQ96aCrMj3XA?vW1fMJ{7~ zwx~2MMY?%D(t_W~7c58vDK5@76NwWeJzc+`I$4=0r+#M}zA2$)Tp&F%M6np@#({c@ zfy4{56C~@MuL5u0B@LuSZ>=#VPv|#K$Cgfv;n|rwm)?+Py~KkAv(FQGo6p~D^Q;)a zc}K@|v&UYs~SlIF?d@oIq$Cx?qLO)m| zqv%Z^QP(K#gb3fWynulQMK8U^QlU26eBQf~EWKF2sBsievV89@-k>Sp1)j6ij3kYW zML)fQ5JhVfH<9pUN9cHNNuV%?9xesxyy zpB>WSX0A`xFJNLT$R8@tO3+ybiV~yX&FCH{Uj63k`=3f;^0GN7b0YmD114iZ!syi_ z;sMW$yQ2E)b!l+Yk`*cHK+pT1!eAHk*f0HSQxokm_)a;Woy@lJj%RS{rpPCMRn&0;r@xjY9HRN;+>&xw(M4R zRX6XX>7MovmiL|$x4ZA7HG_x>HCcJog(KY3_Nig~=K3D}_PR02((`;Caoa&>cK^R) z#Nj9`I&09qx*sgM;bwkydkNp^{+SPZRa(r1E@%IZ{_zEU!6fU;MwIu=oe<e4aUYcT7oEShJ{gxDs37qdbH^Ec<>zW{tTT(fD1!p=` z4B+{X*Dup!^gRnct1aRT2Q{#sfIRD#viXz*)jCaFZ@;b3uz2YlfgH2N7 zowMGLM54OyC3$+XM({3c_iYRmpIm)o&HufH_vFga-x~&!VE+y@yyo|>ai!O6OEz(6 z!-M|CwRN%LoluZ7fP8lsL0+-;XZ}KMV*|=4_ce6h!r}vYw8D;Aj3z$VT>$a9V zdtg&YvNZxZar*q_)jEpey|X1aG_#%wiU08M+(}Y*8I9Il+Q_2+=}AwjuE6s4uDh?U zr$0L#;?KH|`Vuy@;i1}v@DCNcH^FV_r;lh0N%9o^st(Kd z#l6Ko;S}_=+$Zqip4tvulZ}X*EG8VzmJ`;-VSi`GJ#6Bz{o3-DdEZp)l`yDsVZ9Bd z&3<)^v#l%&WYJlOGyT7(aTEon^3RhL*?8J&(d2UF6zxNff@R{Z0kh>> zuk^uceE@0k`()PE_UPKoXyZuT$rfeWC1( zu%l^GS^flSKK`5Q|H*drD69QwQ4O7nWoKVPSl+cK-VC6Z#Tf%0?TbKRls)H*<`t8t zL*5ybUjcPH2;hZA#!Xtw&C2k##>uoTKR9QUj9oRQHJ(|;Dzf48x9*gq55+Z`k@yoom@J2qfL1@u0>zA1YdCf2giM;|L*EP z+%cy&GP<+u;rdf9e0BBjum0m3wtO8nca8k-*0}QPZ?3uCTYr1Y-unw`C(mB2|J8b) ztzWE5T^$g2KdY8jYP7uFf3o$L3)k-~F3SnB7G!#STvp&_MmGNSaz6oy9KZbD8sWjR z$X4L&tV%P?FcSTDSND(h-X&5VM-Q^^*@GfI7Pa~O-)X9BhF|WlXL;qz-MdpI$!FWw`H^<)rcGa_v$=Q18En}sZv zZbnqU#9_EW8hOLfXdW^cp0B5WdCLEvtnc>psW=xAjBji#na8#Yw6@xmEMV^NZ@=|; zk1C?|At(G@^`T;UxQzbHCwRNj0oTDP>fm!*hls0i7%vo+&@qpHGkPXh-Ux1$@tq~f z-Wo*itL3OXy??x|`{(&Kq0cw=&JShy(FavX@W?_w?E9ZaT4Zz9y+2;<_zf{2Dkd#- zlr)jj_859IygV0w+M^hU%`+B{oZ`&6+B#578&W#EA?DfM+mttilXb&>pPMqq2kn?7 z>8PS#EqLC^#|v~?3)eKNbg9GBYAoMK3uiFcb6CBq#o!Hm|;=BY@dOl~qAD;r`_5Poz0TBVVMf+;)qMaDbZ zsqE8aF>%Ox{kG;eX{C1B{1Yeab?t5E{^YQE4;J)up8nh_?$>4_FBtvsv_@_$S%&A6 zJMS@mchThakeuiEdBVZNeR;w9$>A66)0w@dWRncgs`i1(weK&;UoJbw`#f9rYND7t zkh|+e^E-}K`yJUXj{5VJtrZ_9Ppw1jRRrs-TfRptZpZX&vg#8Ev&2D*;}c(lwul~v zUvyl$N?O1xQ*Zam+skG@KH@ohBg7GRjXxIQPgZuU0tFBB@V^*ChDt_e)SZ9aropSn zx(mLa1w5$s^ze0PAo^ipqDN73>kP6^FbrRDx}8bzOoCVqzvIcPD#>};n`=e<;yde) zob`8?1^Zydj55g=>reUXi^b*JRabKtt)MVJJ{D{CiHT(9H*&+O)@NjPTbnZn*|dKQ zI6PhWipJUDyw6a9KF+hd=ak9{H!PPSQ%#!dh-WRDZMda>HiO*rZh=lxEdgPZ)K3d~fi=r7;LhL$N-eJqP0 zTcZ_WLU%-G)o6S|gYsVW%rb%T<8VNW%iUGx*&eP_v*VTZr>UaT>OrznJ1qRNd$R8Q zK8e>B^s^J@uhuv3PJO(7^$RF>{oUxr15x6<3IG?qvJ=gQ-y&1J-IQa5nA0F{BFyR^O9wkjYUI2X5M}yKkzCGd2jtDk2%*& z;@o7!=NjkmIWL9!6N%PZKHn~%E$O6)cvVG8Vl(PcF`oh>&JQ=<1*o z+_Fn)n)4{=bhZlCF7ZU2R&7Q;ls=UW#huNY`~evOVIHAp^ku`Ge7NH(Z7M$?k;7rQ z(SxB7Ts*<~@X~tLM<(xXg!KKqM-UaGX|X}Hn|o~cvp+rR++ZMkMm3|pgGD_(Vbxh4 z@(`@q9~w2k)AOn3RMmnx_{w?SU2UyN&3Vv9F!JU8qTwVtq2VCxSseV)diJAF*F{9e z-(0_kg>}3*BB%DWK1nSKf~WR4ofmO-5@gwu;QH3;i7&6(v;AyA@q@L({-)zy?wU|z zft~tPGL1wUEOFX^6LOh#dSSH@AE(LF2h zvK#KMtmoX~=aciCXZZQS0K?Cp@jP3yRla+!G^e+-ib(oU{G+9Hbbw{g8?+Yo_4U*a zkF6c_#kXu2%i-JDlsU1aH)}Z0lk(#3S4A0BAISTR$_BJ&t~24;^ejj_>`BO%j%eS_ zT4r(5J(#L=vnAQBa+WmsPuEJ~`Hku49^^7BR8+!lnG=Ob?~jlFY5eR%kyX$EIt^x->YngIV|i?&tAqQ(!{>;k8EM`wqpje#Mh#R)m!{3=XtrFTIB(qs$af{ zE%bcWTN{7Yi}Tpx%8w37ojnHAdXKJlW7H(NF^g0{+FaeB5&Vx12zGyKyjEfV^7_yH z1(SQpW{>gxPw{wv=?kryn5L>Kd4Y2gMiNPyC)dcYXiik{9|V zPMLOM9N*I;bZM8hT~}5{c2tz-k4|xLpPbmzT=m25dNZ}pd*5Q^v{thCctMjFkM1JS z;iES`)av8qP2FXIAIWW%PV$(XnfXr_U-!r#AA4ov3EYx%&_tQ)i$mY3V$sCCPh^ia zZ%ARiwJ-{*;QjC<3j`98Qj{i*t=MQ8uKJ;(`X@gzR*hZB&YFew{m!Qp5X%(x^puEHxSAH72q@=O?tL@BF;h#++C=NVI=5g=cv(_e=fV`Zmy!$X43M8jdDb&qX&gKU|dL zQMRU{zEOu><3n2m9-E*S9dvFCUgZzCRNfY+&M^l|hps4-##-+-4o%1B_R!;J)>lh( z_~`g``wsQt$H!BA24@nN^}4^XdbxVZ5XbTl?%5PjPMi?6QOYQ1o`Esn21c~{?IlN^ zC3`bwb_>27!`f(71GOINKTmeokbnCeU3bdL>zCvLj;_Z74Z=$WZLjG25j_ zrD5qTuIq&kPI+ecX9rEz4^OLyqkC=5ZHEeph?k&+8A;h|AjQ=A#KD@(YKzKzy|MRQ zj8}&}O47DQWK(wCg`A>JTB5Q+|8aVxb=&H!L$Opf5cH#it>)1`H}j%w@W(ASZf1CK z=ohTXWb*ONV}v*-vSyvY69tmdOTK@;8x+T?-Z8V-H1D_l$Ne>9Cy8hpIkwh?MxfhI%+6i~ zaqpz3A;s1cX%t(LCKCTw*Lt4yNN)0-;-=Px@>+12vpzVN$Jjp3?J6i-tjzwgDA{l} z1y^6JC&T@XUloq`*7zVYu9>^bYh)zaHUs{rzs9u=if7$MaQ~oe?S^ABBkV}VST{4_ zsK51lu}0aJdgC${?XD5nfn=zi$LEpg9-5ppo#ZfyhaG+;#d!npXpe6@oL{lD3HaPsBJ9E@Zx4v9Ea&?IpNlP^Mejt)tr6KTH`KCOs)GI zmB24)Bjx5DE4|m%w%21WP5dYy+YbJo}fbSUp?4FLlwZn-0E>WWpO#)M(cihx$wbdUxVDGPA%hvqz$HyNLJ!{(^akn=I{LyMVYl_u8L7YU6H;dQN zV{0^y;)Q5*V$4nPu*|K`5`rNb$acOJrP;J*zaU@)j#?L&h_!8V86k^B%Jb}?L>+M5RUNe# z#cmT7uZ@9d0cWU$3pd14W>iBq>@V^vwe@#FO`&F@^*hH6{xy{magu~S>? zY&a^$VHm3Xzz;<2wKE5b@J#H<)^WZl-`yU}tVL0uodfwk;}6Z@EpoWLjVpfW7q{!j zW<-|s>WbIgO2{pT&WoQX!H_fDII5z4Ik}adnL> zG%Gk-2hQPkb)#(GV3Dqu50l62MfXuXUb11vi9}|cuP;b`f9cBoPig$gr?=i@E%usJ z`53#3PDx=n`8QkRX%Xw}*_;_@|9LEu_j0wy2hvgOWb`OP1NLa-ksV39jP+vuesd4l ztPal@Gw!w_IK`&?WW{Ou7MYt|ghmHhYajWXl*M8(AuH5RXwSduohi22HY1#>qY_`qI-NncTD(K&@P_EIbWlp-6u#WN4ox zCojAxnq(Kx+K*r8e%?jBBh#pFY%`Gu5~OPJaP5ffMAY*&mroz8?8V-0@1T5kw0X3i zIaTeRu6FD?QTceae{22wblnH%oAypyIjwI5ClVg6Z{6?p;P}lt=e-r7YWLO}_2ug0 ze54avRzRI)cygovoRfZk^)R13Y+zA+d3X5{v)X0+-umV3HQToi7{S{8WAfgo>zkd& z4_1$Nj&|>^Rxj49Air9De1}!z$e4YH6WHuoezE$Y*vs|(TdSAf?K0J)UCiG)a5YQ6 zee3A=^1u+@Z>{}LukYcev=3Hq`&2(TX8YEf_Zw?=*tm~RHsD5D=e^+wI@ElyKB46E z17>(=``&u`+p9GkJ+brJeG1X^-qruL+MIbcv@TZuo$J}~6zAeT4mkhlZa@_U*groo z1G|>SM3JHV>##~9?fn!vi{UR7>`pT%i)4 zIlpIo)w*c%XnlLUI7<56N^I{sKA{1)jHAcB)yD6S)^BEqW7O6%c+Kl{4mnK*(EIt~ zAiinyWc5TzpUwR3)$;4>SMAL7^)>dl*ZkkOhT!pf$75~HmIT^qkN5Aae_@3Kpc_ho z0WRhd%hEs;I%|NZPuHJDO7G)Eb2#ClH(3MeB~OzaFzacIPFP2^p@zFVo-9n7gLGtB z@PH--|9cDC=?$L`*LSd)lbnC;y1#kM7Ok8f7&@HsfLDT~igGo8jiTm%RD2*>{2mjj^@5e{mYrRKQIP*zkakW&2Jxb@>cIJ zT9Q>X?DmlPjV7?Fq?gQ*^#=!TQ6XE5LVCV^@P{3x>!2s`57w_+&S)QLH!h3gcQOL{ zN1xLB>uV3 z&&yuCHc4c+=z<%Kjj7&*uF;efd{+E+w@rDKyuC__zPLU-Toiq|YE682G)XEuL+93l zVoLT5cP_2uz2h1Bye>vPd*!pWM61`0PHJxY^T`u-Pn0KXTGF4#i!)-n_&ZweMvvrM zoW!QN`&>^Lc2m(lQ5gU5lSI>ptWFYy3;MA~X}Wl{F`gU}`p$YzX1Waqgd#N&_Dyd| zqaPhmqitgtnV)2X-d);1_T;Yqa01VG(HSFYC!1#s_$1UZwwc|s&0{rh)&)ja%aVO~ z^sL>(^;z^^d^zp26l5Ib`8odXYKt7Z(uFjYwjW;nXdAvG4vj}bj_pG>o+LHvh8s*aSJUeDeV%#M&J+!1R=#yV!4?%|3 z{4Fl!8Kw{FvZ1_K)@)ky_OxkQK3a6v5(ilYwvFdU8Fz^pyBK_WOe1&_2S-?($*i~C^qhX*&Z6(Ov$Bhw6MSRg2KHhO zl71O+j*aCzdFY!lE684LdHsr-Ja-V2P0}=ZEsH10BvsS-x@b zv^aOFJ|yDxaIiexT!&I@M*N!S>+!)Wn2e8uXLXrNO9nEMjUL)RJtS<$o?ksE2-jkh zvD?OFIatUvo;>>XvTif;U;5ZDFSuUEwesY%CA?W9x?2{=IxAYW3a2JlH{_3LNJ4-|{Ob>wPA7cUpxW`wP~L6J7HTHSn+he}S%2hjAZ>vy(I{PML02hFUH z@%HFAnlH+Nt8$np`<{K)k5_=DS`Yk;Li6>1v7XU^{5pE2Eyl?j_?7h%3#7+Jq^&4z zgnHbLptl5F>g3lB?9Cvr3WM^b@@d#iR**+LYiWF`{-EAg-J^H|ho|Swe4@;{xR7;z zxv(%g-yGgm5593wP(@AKIPl@JS6O-1T7-btqPWYbGg&mwx7RN)^NCNVy<)wh%B%Gm z{_5GJk^hzbqVvuSXeby&k960F+9z{2D|P3(QvTc)! z6FykKYFCuWFXr7y+C)B=_A#lxtWBJyCVqm#$i;iK-Y0ZGBNl-?kZt1?InuLt7hN74 z7MAYj0k;O~qeqe@?o8IMuCY$`V2O_OQYA)w4<57YEiN?|jR}_Q$9vZ{70-BweycKz z$Lv1%SxFw792k)%m=oUyp1XX=L<^)PSw7dY;7VbzXh8t#*gEQH-Pau9DOL=6^;mVodKQ5D)EMWY#M^T*gIrB6~b zk!;yZmG)gb* zHil=tD*}BLw3oBUXT|o#w5nf47Vyi{IZ`z0TJ8#i5yWKWbbZoF?O7%tnwG9*UOuOLt~G`c!?O43h293ME>J zWM@5L0iyAS`RaNGec0C9SPiUM-8h@qr`57Z68vC6$9iNz)9?6O{eeE9bu`^j;5Jx| za&=HZOW2eCxP{lM2hB=vgLdpAy4~FiJb6ZzMI_2*p1qU^uyu{mMRkyT&8(O0U)a~8 z!D5lYCrm|16B*%gaSu#*94or!%I7>;*zjqr>Dhxu8Bn(di+8Fe;Ld84hu^d$#UJ_7 z&*lS4PThf>E;5)^RJRGM}CmgHN9eE5uJFil@j=ba^EqSH&PzPg?i@0~G!xOTtT zKhzGehif;9J$Lr3v=i|=tJjmY1I%g8?<|V7U(^o4%X^91!PbpgPW`r*Xm;y;?bv~G z-r@J>$Id1v9PDh79)G!h zwTos>f47^6B-nA})F?WAvgm1N>Fk4s`Rwem)2UrK1GBwDcI&jS`Fq#%|M2)eyMgDt zO}p9bBW*X7`8yNW-b>%-i~(5f@^KfHerVh-zu6@Q*YjsPNR2k_&O6NQdNQKjZuSLr z7yN_OcFsFJTEA?{kcy91d-&Qdx_2Ov0wct`c9!p*-nBz97@>j_1f)q1-`nHWenC40 z{r3I!e0IR$njQOb!j4A0X1C(({vFQE-ZK(xhWm?u?Sc$SySv&A`lW-ic8#|i7NlP~ z{hGAcSw=3~bLDqX|9JgB5&+Kg8PcJ~4_2Fzt?3Vk_DGYccG=mFg>#qp^m#(!rf2&K z+gBRZaD(KvD>g~!T@w5VKc(u+7T_|^&9;pWx{sl=MtDbBI|bk~x!=3Y(mFK2qi&1c z<2+x_$0$bY2Wo&3v_mWz(~}{1&)Xsz=3M> z#tBxb-)7&Z)5CG#&BwKSv)%o-#~zK`dUp4IX!{^LX&>%;XEU78-=1=(y5Sb)?Wlfo z;5H{Iqg(pwv)-h@ZtrZZXLdXL<;;`X(XOO6j=vh3ZVEnYkG9>s;2eYVJ_7-3K-O>S z!)T_RgT=B-WX-PImHB1Xa3EyVSrzrYtP3Lj|4nE z=%&To6liw5nElP=vIun==Fv7;<3^PfmJ2!V+pU+UnTXF#QeSVqU zM2R>$HZ)(97swiB&CT+|gO=p{(He_d92= zy>{@QH#z0&8)xgMQOW7Njc9C1)ZDiI>1ucLbej`R4;S>8?>8AMPqS$g8BD`yeROet zW^C)sv^{N4c!_S%y0o?I()k=b*?<8XIqw=|kx71*H%;yRocNv8fD4Vu;_qIHk-L!Eq7RyBW_(_8FoAJkAfF}Iu9Sehx?aki1w((Pz znY@sCJg0x{&(ChUac5@jL=Ak}3okz+hrO{S+icYQ2D*H_es}t;lZSJb%`X$llCra8 zk&B+iB~eRMLPMMxnTGuzuG#+h+TIP6XIsFUu?pQmCW1O!PPlrLQg$9xBt`rC>vPe8 z4B?Ni@vZ+pT@9Am7f+{HT0A&g{x}O4XFBpY-Ewg=26A&07}D4mi>_Z?-yR+?eee1f z$h&DAUpnbDl*aR905wO}$Dff9&v6PJ^NPu2@e*ju2T*CBO^7>q0asE*9tP^{JDEoX zGZ=Fs^O5#_2P298lfwd4q8bLsj`f4AdSBSeFAgRaN>@*Havf4n3~ySWjo+ii>O&oNkh+m<9e^V8|coF@WL z(I7qQ=273{+xaBf`K)D9p6-G9qXYK55BNqx(TJoumFC>e_C6kNRF)|_t~zxWN7 z&Zzytfw3%7CU@pi8J783hS8YhQ-8Ng;dDNFxI@RYx?!H4@o?qEn?u{H58UxlEZ7Yu zK|jBO?tDYTmZwjyv-$6?J0nQZNQiORNE$JDQT2s*`fxorCVHLY!1vbkbo?ge<2)IS z=Xe>kV^e(N14&s~nE0fKf%OCn`?8^be6*WbFRw2mM(OOfw$IjQyqpRIFYEW>K3MYI zY$$&9eZ!dKqxfY_2VXu~{fwKO{b;rL(fURcZ@xJ~y-Ur~-X!miQ0=wDM*ArG^Me#U zK05T~X9;Uif3mRYz6}35%h#X#3$Krld!gK&QYCvhPWPf4&f~+#7!OyjGtuh4*>Ub< z9bcN)yp)HRYov5;M{eZC49-<|-fJXq+k&Y>?by+{{3*HVURuzTn!DzGv1T=6vQvx& zuQE5!C%zgF4fQl#Ck2y^TZ|g=VkRH;Lch_ec@q_h$8p&qW7Ul1)x5;J4^*dYU#|O-NF0tfr zB73I)e#VBwN#13Kt@Y0qM!m~6A2HaEJ{O6zLik?%(o8VA`(8itC=VO#qgk4aw|F}I z89w_JUqGSez>5_j59X+U&Ykx7QS8inbo8B*Ygk8-&R_zb&UU1Z8O4|N_-pI4ux>3`11az5$t6T z5=)-*R8JSIyH=pji{p1WCOlapb$qAP#TaxXtUKY`D7(&2rh}&3sNYBOe`R6t>+5f~ zLHP8~5BdDuX> z-z#eO=CGG17XwLJIpe_N}6ADom;Y`gX*di}*M%`b*;A`mr)sSDk;4)b|w{naIh;`pip z{Ku|~ya~;C;_n@mks=U%SlvAPzq!cE=MJ}dh}+q2YO&&wy5GWI6=@zcrlFHe;8%L0i?(xb)kpG_1i61^SY-}bim z5BVqu*mo7?!GHPV{!6L-d057=?%9vemks%BpFhZS_Or zr7JT+dvE-nZEpPN4uX%@eC^@!3yJeqF~973RJ}i1&(ys^dX5*{&(yl=RKg!FxGwj5 zovWkpY}FX_yGq(f!2lnX!f-3+9cqo2v-+GTvmOpg@m5~28d+CYc)El$0ywH1)g4vJk1%PN&&&dOE$DP~{5<@|d7!K$Xf9L;@?kND0Cw0doB zUh3JJwc4pH;N{}5)uUOV2lIIGndj;HJ^0EiW=}vqFDja&SRp=(5BuH<#As$T;|qU$ zO<@w%{)1|`!<8g9d296vTqFgBoNCxLYrG13zxjs4BnF2cm-<j- z+|CgEF+&hd#Tw^kPY>$sQyF*%L#vJYf}-!yPn06^DidvwzBem=<$%RHe;Fmn`u3IU zoghX@n%lv(_i)X<-Q*5-V1+TP=4}l4VdvY_`bS35YSuaLf7<@V!l_I)N})AQlE=S0 z#u<8S+LMs9C)`@WND|Jofa=A9qn-NTxVhpPPw(F2K$mvb0Y)aEjo|lDf2k<}9wAHnr zHBG;?R*oJlj<|c{Z;mr{Us`hVrR$YdC$XIwd$68(+FGnr*Ut4?L$e#zIXh>E-7xBj zGi&!&Yv;|J2K3o1#&ROJv7BIYZp5h(JwTy4#x!p^_CRj`}H+^6>b^++$4rFyXb zI$>TvHw<(huM>w((GBH5)~VQO`}pdA9Tc|m?OagLvGdl#e4tDcn%O-R>URUv{>|z6kq7JVeu0Vem{w8QrdhT3dv_Gf z9BBOD`mDK=G^pUtGBAI#dVYWPo#@KvxdESrI{WW@v3(EYZO{IByqMp`@8y^*J&)*n zkxQ{x_Q?L#DlKUm|6Bcq&F`%k+q;Mg%hDTD}20d7tFnxCJgPs2W2a1Z0$e6{iC((7CnD4 z^tQK?d!vt^eJr#^SIm?bdWd?%Qid ztBj5Qwbg?4aYIADI9bda%y$;A`|y5!Rl)xCA+64`cZ-%gncqKdLaX;TR^;h?v^xTx zA2f9W!-?e1*UzZ#vHqP;=NS1fXNs;OThSCv7NO7?nkFByM>vgQEu4f!{URKF;?H@f z+lw{U`Q1_c+Yb+mBaYr07zD3-)9QxiCM@kk>I4HQ!IZ|6nof$%4#Onnu6e}I<|rc0 zI*Y&2;m!9j7Jp`AgLp@Hw<$Fex@jJzCt|&fS1#}B0?w!6@3z0#}^l^qgxW6!YcEJ6eHC7e6ut*Y(Nj_)(%lgKy$&OTmp4U|a zX!b81e9wz!uf{%+Q#2i!|IV=sW9lp$s$EMMCE{}zedOsoGTG$>3MJcZp^6@fP~#0 zt0Cj9;-SS^CfMw=t@+WiDss8ESO33Sf5gP7L6Vcz)D$P zCGu!<>NB`D?LRnX|8R{4uWEnM6pm-xXMFrbOLCB1iXP64kR`v15`VI2<9C&QT1--n zxA_SEcFwAjprqeFzSjA_KPr@0YaTKi&%ss=Yp4ZY)G^aOwRQiPmlkA2*b4K0XZbVP zF6l zy}eDw?=#1x7qwq@_H>&SMl8#&Lx463ciQ8wD#S!%A`>@(%6y#ta97YozedDAbIiFB z7TpsTEq%;eZx0{>t4|o@&#%_b(lZ>-um0t+n)rCp3_Z&rK5MUACk(PW>Si}r#Aza$ z|GV|~Kdit1e*OKA>+e@q+ne_*h=fE?<#eKc{rr+`HLn?4#{>uiB7*jl1tm5m5fg@5OK0{@Rl5_KEjD`6*Umi8@0pe~8vk z*0afB*@>wvZ<)+zlH@EII7coYEa-lGJvUyTBa{5lc#*8S>hajafk2GIW6!xWIB1=P z%HkHWOb^&htE|mDnW!S%iXXCXpU%(AkizdSskFm(Xw!;AJ`OFdsF8Vf zmO1A_J|7>nJ<>XK-*60OrO?%rst*BZVFz? zdRmm_kmr|SoVi@iHdZ8D9xiCAg277Mb9K;H9c&~Bjd2U@`ShY@XC6IaN3!jg0U@=EdqSnnE?7My^4|HyG*6_r8t%kPY0?A{?Tr(O93+TRcr>x-%o~ z>V)uEl9`zXnc1&+#THyr8y}NOzrsRpL*8KrmXY6)KF^9ssu`jh3yBXynVCO&Ud|Y2 z%N3*Dr4(IS7So2{jKe?k7QvgR@?X!(!yDUE&Huo}P?H!Rd3Cr6Ms84|;Fy!3nFxlQTsbW+-+U*S}F!LCT9Y7bO_>Km(H=o{( zeu*!cnD_&>|M&IZ$7{T8H^K3H$EdK_a%5DJ*y+q>oM?q6gw;7Ng4Y7Cy zT%2s(#@&mb)k227$M`?4$N1)o^{fq9-4gGePjjBLy1!r2*qx{1#Hp4cX5KmvxZvtR4Z0?zfXF4r3wmkxv(#DIyqWiD>EVvC{D_(IFZp#e{o$>im;Gd! zBJshrZ<8H7UZc|?x|pSm!e!fI+v*d2$AU2wR-Sq^&xp_@OebPK3ve0!QJjTw<6AJCuvAyi<@bj_#->e=co)v zR_%Ph%%$%I>3gd;xQe(uN%NBDD4e7kO~vfLtRB_`J41bG1=-O{8|d~WYee0f+gcF) z%KBLa_PMnjD=t=9tPQO&!u;!gzO`i}8O5q^pk`+bN9*}?vQNfHhLv*`m({_Mv;L5&S%+mWjcY{nd}YyY zTS4-rCqCZv%sh^8)fVTRbv(WM|AJ63d3N@@FZlB4C#Gm(E?XY{agn@adi; z+h?!K&yU|?A^D`@oo=Z8WJL+AVX{BEa`s@2YHw=s;&?(m@@|h0?YUa(YVMVo+YrST zYHxl2%k}@)7Z%^U{{N%(|AXa~d3KS3wJPrg6`>R({nz!sh~W3u|6f^u{_XMa{+}1! z&-+!B&|8@8)8Z-Huf^lJUA>4k?`Dr@Z?2eF^PjDmUS<3L(}Hwzp(ks-Vr+Gh^Ta^B zRaPe+WaG=o{@WU1+p4?#%jFzy&PXDEUUNJ@Zs+*<&M_+2i1Vg)$YW-m zMaANr@^lro(L4GB{qC{=qU(8s z&RwgU^7&2-6zz{)W~a%`#BF8HyE;&W#uA8TtHu5_a`jI*{1YF}vc${oOo3I~Il|68 zZ|=yl!<@uB&yei5llgM@HQ(6t*+JfWae5}xEa&|1%Ok7(w71x81ikr4&eZ#*_}Je4 z{9r+7Rad2G-@BEMebau%1&Mci*|BcSsyeS4$9~A!4S6>#KZ_AQFI3_T`zu@d{$g;w z*%+S}GVgo)>%~>O#(z5aKF>(6gR;7l8kHPH?nRFFJ#hJOQI;C;=zt8Z>P~j}<}QFT zIPqszyljv?-z!Qox?j1q2f#UZIYE2>*mog3b^)?>e0{w1^Ky;xvUVB9R)AFC+6AD0mG!EEWg@?|o;_J({m-LTIa$eF z@L$%V;&QR~n^Ak#OGT1pVNOkg3Uy`=e>hH#R+SdzNJ3O1spW{fR=aPu`{C8EE{w@) z_~Fal_?3B@_wQHh9l3&!&97dGL#kM2FG>L+8GTc%vq8NLjBS6h`Z_Pe#+D_0vMjBt z_B#u5Qij)4SM!!SIhFn7(LA`5%pl5F;da?k+^=2x53Q=v#~Gsx8%EWVrM%ESKnlaYuyoSWrk(K`!~BOV{%SB zIp(5782oMvI5XDDCqaA2{pkWH#MVk54E6 z;oc7Nc;V0Pp+c6>-hkvat$q{BaJEF3R-j*AZvpbyb_>wsZTCe3?AHHWoB~_*xX*L* z>Ep%EsZMM!X`HEF`2TEsX2%6?ThBn3Uj!Z8NwuXenalRvyeTrf_ws;x;+M;n-Mdy~ zCpwCv-Bz2dk5{@JkuKy}cfJ3%rMt`L#_@UQ7&>NsAFUDjCig7sx8G|q5b)n3tL+sp zXB-@6Y`XrsvF~5dRNYkO~UE5H}Bco$Vfv`0XkZz zOH=e4Tg^6qa!8N(x&7Jqu6}bpRo~!0_AT_h(D;*)$i`0={KmiW9RGDy)R%k$0BqF5u1hTF5=zV&u|!!j=l8z=jAMcSCR^)vsoZ7B#^<1eytj>#DI z8xPD$bGwJqtJVwPFqwu=B*a@9)v0OfudH0k+mfHGD9Sq%>~8))*Y0-J`u2l-{@%ZF z^gqY8XPk%oXUKm2@C#M9kYuW)i4 zJf2z$H@~@@hW;O`kJVwn@6+2auWvNB@BG69nlewYzgT_LC#S8DYp-#AcZS_5 z>{fK&U;X`|FRIzz`idgnt$u&W9UDOx{B^aSiH6%zluUx5wW=bt(MN2`r}fuo0UCg@SE?5^EZRu|eex%b$PzEw-0 z(RD;3?@!h=kv4+CCA3)VYq=BAczUS~nGXkrg`*mrlAgQzqk8lD72e6(U6dzlWMFny8u9AL zWA#Cy`i}n|JjT1A-;R}|q8&tF4Em2hrGSylC;Gyp_7e}EMJ#vIKg!u(#YXc1Q`ayb zTL4F}ZtC8IbH`=cktn+OgM+>wUrRI1{_Z-vHq|8f+vj&v3+ZipXFxXlh@%q-Xg}r@tkE~U4|ZmPjsG>2ynxlIWNLGB!y^) zcmL1&>$BJt|7X?f;ToR|#EtK*N>-8Q=!SUf$BPC=Pb!NM+0CR4bZEs76ovl&;zSZr zm15ids%|K$WmPj4vwGrCG@to{WnIZ5itmb2@=6-c+UPy3aj2(cY@eRl)R+}$(mnJT zipmG8Q=#0|HMMTieZRRbT|tHHW;;6bWc?PsFXL_WHe+XI(@fN&5otCnl5h6}olvp$ z@pNinf(>1u2U?wNOS+2=L6OeHLH+bW+4t7}SpXi3ZsYvu!k-_fRnk`!KKo0ut=2T{ zNkKM=9)7%FX8X+!ie_{^mfoQN>skb7ovJEjw*a|$$68g9?vvHq-jHHn5!}SHMaD(J zZn-V)oHyhAk2Qi-64B}7!#i|eP-`=99djFVqTYMg(6raRwKF#uiD91}F>5zI!A?YJ z4W(#P^lTLOLW#0xO{>vGzt(Judd1-4bvU5^C+m}__1nih|7$&cu|7@IFQ$d%{S&81 zF8h%O%_Fh)=aVK$_uqXg9kj?Fc`AKpC#vg{h1r*lS07!Eo@FPi(}(r;J${;jRI>ez zdHH)1$tIlNZ1=jh=e)Pk=~kZiJFl1p9cW}W{c2J2`GQOD}b!cpn(W}}u^Y5({FWOdgZhwnUH^-D?m&fCc9aNVmhxITDx`{kl zy+(O({mU8KcMoji@@Kbxbd9n0Z!OHef9+!$|K@%*YcK3*_CcHlb}LbSiFYVd47Pu} zjnmD(;{(UT-nCcmCP%^iV$p&O<83^7eb4Wn@Ri#o;bD8`Ru*&k(l=W1pVwTo+SD16 z2Wv#K!<*nNfA|NBM(pGttZ!t6gcdiI)2J0aINB7Eym_y)3?QMfJx20Ge#TbZZZjh%akqbe_mJz6%Cp6IvE=tZEq}tsi2f!H7CHaw5nt&vW zxM?#*Bv}fcY;ywa*|NKOi3!KcZks+5R5l!K&{YjKpE?wtF;$9M!DK5`4#2{uk{o_% zSJIxZ7UvrB^Cc7AiPfm?N67Z>Gdf0PqdKvsqVUISmcjG#w?{`iHb4Kdqgwv_b-xyq zs-fylGDtu^w%K0S`}2-HRPLRn;lqB)5Wt+T{rzQa`EPdCDo>o>^qy!ywSjL>zphrS zfbUgmSaQ&bC&W_mFdEA~itB&>I7N5-buU13pSic6G%3WgIznZ+hu-s>0Mw@ zo`9>PM>pF%S)=bW4)<0c@@MyU^5XYDT=AD(+7H+N;YDKqVqvHX$}+xO-^6 zl22Z3Wc1ssE!wnFroIRhE%e!S)#OR9a;X=q)%mWss}`_+TipFPIyc;RNBR&r_eR7i^gW)Bk& zj+R+~sbVFI6IZz})~VaK7WevJ9&xoYCx6h8B$HQTi&;@?QxT4yY|0Ha#WVYcZsylHso{?biyooyqV^cgkG;X1rJZ_Ag)an=0C?`u(fd{AS(!RsH_o*ZgK}_uS8J zho|cV=)I-;Y9y`3sX07Z*t0cN(&Osh({}0o%jD4PYSn2TFB;yxlOdg`+9aOExlM2T z{$8x7xZyXgJDtb26f@yfae`K&E-Nf}xGQ8oJbG$}pMSspClRdl@OiA8-86fD8+%7m zZtwDHCbAMtY~>fnbK9xyCyZ!K^!ZV9Qp;hN)phW~>8THn6~}(De@{GSSMmGn)3bwf z@2pSOK&{)hU;6pN<{b51j&kqlrCOxUH7nOO<&VwF1go4fVaioYAzZ}&Ujm%;iCH-~fgRtSm|JKdh*=g_|1Z$#{p$x6GdVsFTs) z;>{whyL-vddawM{{%JMq!E(@Eo^$J6k*#sZ&P_in^hNg~TD9pvSmWGVG-*!^x$;M3 z4)gKq#urr#HN=&-Tb%7qwV&H0~@}my!6v)Wy?Y>hvCUvCM&X8pL)os=5 zAFWyEOiA9UbDhsuZ&oi}s*}MX>ZzQ_HmW6yR&ZJsSa$YuQShS`-<7k_YrBvB;^5wY zIewq4;oh3Tn0e14WEG3=tXAFd{1@vtQsQY6@ShGkvP9nQFm}cILE0DHJP271E?62>aSf&vb=6;P z_Oa?NPcK(aMlY$bvrQcA4*Bf4h=B|QQ@oQ~XOZy_tZd;xR)oa1hR@vO1s|MGhS1Y{ zMd)B2i+|xi?3C(VBJ|8>_Tr}Pc(HcD@iVWp8palZzQ45G+cm6{k$o#}|8kA^x@c=w zFG)DPE^EECuw-m-EY_bGkR0zQpBCKq5_fArcJkvD0qhtOt#A4m{t(@@`smP`j~9mH zr|#}CtGBRVuaY8GI{yUfn>A0|zrBKC9x_8#`UIY-TE=C+*@-kasGvyNFJ|7=aawVE z{p-=fn9bemU1>xX_})>MQ13De*_?F>^@^T9KHw>L{1=N)lYv!Ho4WAx)fe`8>MCjI zc&^2q>nP}9B$_IEVZp2M!v1wNb+#uD&L2dB$tTLIzkAe+Uft@P)83u+?)?1j-_Il5 z#n;>GY40z4)cu-sBgAb!U(UtaIu9?hL))w`X}hH3uPp8Dov$pYY~%4k&!_8KXZ!zV zjUa0%dgmu(*XSOW^Rbr}E|>dTFGn7@|9Ww#4CIT9;msj` zeNaN&_C-dRtmBM}od!Lh9Tu?p+k?(L7LP27e7fegH^Y;&=JD0HtrR<c}{q zj)wijhwonfi#0DFO8V!_+vv}wMr@z9tDx-KRL}CdV06Cs9Mga_c};%B_v!}^mOk&# z@D|%YIDYZJ`kZmTz1}#5I=s;K`rbVy-x0C;bgtvglV82~{a;*sqpQ2Gk!a)lYp#3O z&%+_zJO4_~#3S?({6%pjXmW(`tS9Z(16Sq6c)4eiYkzpi>E&$uxp7edZ>KF;Mv2j$ zu@Bnbeul#;7B3fOexJ{tf9rs{=kvMt&(?g^>(m|IG(UaQmJ?Nrq1fGBZRNB1cbP9; zlHa5$_ZGDO=IUQ9s6Wpv#mud4=3QmY;$ry#?@(l#57DlC;y0H}slsOS#Xo8PpB>eq zpDhHxzPy8|cV?q&mpKtCfw?_?drwb09LF1dvUt0#&;3Oy{zAs9-gUcXln-I``)#s6 z*7BT#TxRXFe#Z05vWhjy=c{UYyJmEC$lE#BnK|?J;7~J4-(Oundv$g2cE#%9;xnr3 z6;07XRTPvSjbWqit|+2n9y>qze9=cmj=ktNI?aBm3$j`)tRDQfJi7`8{hu=^bXbm~ zzih+|?a14Hcr3mZG_{YvS^cM9_hGnqMuk(R&$3r}E1zk6u~K{Zf~1*56LOzRf6tm- z);DiHsVX2sd;X~>eX!;iRd@o|Zk%L;!8Y)Aj^@3?)|ErPs-@^=ay{dDN0~Z?IXC`3 zS8GkC-dPy^_hbIIk9O$XcYHF2xJ6quLNB=DRo48$dP`$5mb_B6=v&AClZW0rAW(m* zGJ3mqdhZz5=qSMMgZ?)b1AyZ4$_Xl4JU$|-n_>Hm92{;OX0X7IkLuD`Cv z{OYQ;(c61Ud(#g-Z|cA3O{X6%cyVrG&}3d*W4-v?iuB6;&#lEWSb@*wPw zl_NLZPA!|&K&>yYe&>5yNsPa<132r{%g&|qq|#k}ucJAS!xQHb*G8(e_`|DYCCiReNtXZri z`^{q^G1tUf^6|ZMMy|rs-4wJ+uJiJMOx7Zbt1_ob-kOa_&TKbh zsbIK`4_x6alen8MQ{gaMn6n4FYF1U*yq=*NtIowxU~etz z{LT7Xog^!9S(Q~`$9s^?4m4cw{iF52>iu4+`Ra6Q9Wlws@ug46K|w@d!4r&_h!C9 zLgL$J)sSkXCiEtiAyV{cQL@vQGeBy2Lr z^I6if#TgB~?7M5$pMT!x3x<8)PWrAYO{&2uuWW7Twui5dOzzQlYeM@{(e?4C+R?M3 z0(;*&K{jitH@R{n<_QQ1T-s&p@;Fq*ybBwNzV7$F=gnbett80iWc*Am) z;!B_PHd3pZyM@&>x9LVpttM`?E*tH{0>zU1S?B0+0fl)!pL}m8M_&AVFTRoSC1~*d z>4H-fU{ulj#J0hzElfLg6+V|aT67y+S<22wi8aiIo+#{>$!y9TJoV|>As6@799cJ? z+Lyy;y*O&j4-YFm(NC6`Y+N0f=y~3+V+Wj=5YN7`+B{p6D!{-bBGRd-DD}8>) zQFKWjo*%1b-e>*6!H?nB&9w(yFNaS0lMizx1EeJR+;xE&YkXY$r}(;L=(fDmq^b;g zJ910ck}vZ+d*|De13Qsm`DtC3?T{{!?Cn_K_@ diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index 22063c35..77bc957c 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -1,227 +1,136 @@ -[LETTER1] +{ Grand Theft Auto III Spanish (Spain) Translation } +{ Contains some of the official fixes made by Rockstar for the iOS port } +{ Additional translation rewrites, corrections and fixes by IlDucci } + +[LETTER1] abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789"$,.'-?!!SDBF [DEFNAM] Claude---------------------- +{ ============================================================================== } +{ ================= IN-MISSION WARNING MESSAGES FOR THE PLAYER ================= } +{ ============================================================================== } + [IN_VEH] -~g~¡Hey! ¡Vuelve al vehículo! +~g~¡Oye! ¡Vuelve al vehículo! [IN_VEH2] -~g~¡Necesitarás un coche para este trabajo! +~g~¡Necesitas un coche para realizar este trabajo! [IN_BOAT] -~g~¡Necesitarás un barco para este trabajo! +~g~¡Necesitas una lancha para realizar este trabajo! [HEY] -~g~¡No vayas solo, mantén tu grupo unido! +~g~¡No te vayas por tu cuenta! ¡Mantén a tu grupo unido! [HEY2] -~g~¡No os dividáis, mantened el grupo unido! +~g~¡No os dividáis, mantened al grupo unido! [HEY3] -~g~¡Has perdido a tu número uno, vuelve y recupera a 8-Ball! +~g~¡Has perdido a tu colega! ¡Vuelve a por 8-Ball! [HEY4] -~g~¡Perder a Misty y Luigi te costará caro! ¡Ve y recógela! +~g~¡Si pierdes a Misty, Luigi te linchará! ¡Ve y recógela! [HEY5] -~g~Una de las chicas está ausente sin permiso, ¡vuelve y recógela! +~g~Una de las chicas se ha escapado, ¡vuelve y recógela! [HEY6] -~g~Dejaste tu honor con el Yakuza Kanbu. ¡Debes protegerlo! +~g~Dejaste tu honor con el yakuza Kanbu. ¡Debes protegerlo! [HEY7] -~g~Sería útil un arma extra. ¡Vuelve y encuentra a tu contacto! +~g~Vendría bien tener una ayudita. ¡Vuelve y encuentra a tu contacto! [HEY8] -~g~Protección significa exactamente eso: ¡Protege al viejo caballero oriental! +~g~Protección significa exactamente eso: ¡Protege al anciano oriental! [HEY9] ~g~¿Quieres que corra la voz por las calles? ¡Ve a ver al contacto! +[AWAY] +~r~¡Se ha pirado de aquí! + +[AWAY2] +~r~Se ha escapado. + +{ ========================================================================================== } +{ ================= HELP TEXTS (SEEN IN THE TOP LEFT CORNER OF THE SCREEN) ================= } +{ ========================================================================================== } + +[HELP1] +Detente en el centro de la señal azul. + [HELP2_A] -Pulsa el ~h~botón /~w~ cuando corras para ~h~esprintar. +Pulsa el ~h~botón /~w~ mientras corres para ~h~esprintar~w~. [HELP3] Sólo puedes esprintar durante cortos períodos antes de cansarte. [HELP4_A] -Pulsa el ~h~ botón ~k~~VEHICLE_ACCELERATE~~w~ para ~h~acelerar. +Pulsa el~h~ botón ~k~~VEHICLE_ACCELERATE~~w~ para ~h~acelerar~w~. [HELP4_D] -Mueve el~h~ joystick analógico de la derecha ~w~ hacia arriba para ~h~acelerar. +Mueve el~h~ joystick analógico derecho~w~ hacia arriba para ~h~acelerar~w~. [HELP5_A] Pulsa el~h~ botón ~k~~VEHICLE_BRAKE~~w~ para ~h~frenar~w~, o para ~h~dar marcha atrás~w~ si el vehículo está detenido. [HELP5_D] -Mueve del ~h~joystick analógico de la derecha~w~ hacia atrás para ~h~frenar~w~, o para ~h~dar marcha atrás~w~ si el vehículo se ha detenido. +Mueve el ~h~joystick analógico derecho~w~ hacia atrás para ~h~frenar~w~, o para ~h~dar marcha atrás~w~ si el vehículo se ha detenido. [HELP6_A] -Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo. +Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo~w~. [HELP6_C] -Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo. +Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo~w~. [HELP6_D] -Pulsa el ~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~ para utilizar el ~h~ freno de mano del vehículo. +Pulsa el~h~ botón ~k~~VEHICLE_HANDBRAKE~ ~w~para utilizar el ~h~freno de mano del vehículo~w~. [HELP7_A] -Pulsa y mantén el~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar~w~ con el rifle de francotirador. +Pulsa y mantén el~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar~w~ con el fusil de francotirador. [HELP7_D] -Pulsa y mantén el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar ~w~ con el rifle de francotirador. +Pulsa y mantén el~h~ botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar~w~ con el fusil de francotirador. [HELP8_A] -Pulsa el~h~ botón ~k~~PED_SNIPER_ZOOM_IN~ ~w~para ~h~ampliar el zoom ~w~con el rifle y el~h~ botón ~k~~PED_SNIPER_ZOOM_OUT~ ~w~para ~h~reducir el zoom ~w~de nuevo. +Pulsa el~h~ botón ~k~~PED_SNIPER_ZOOM_IN~ ~w~para ~h~acercar el zoom ~w~con el fusil y el ~h~botón ~k~~PED_SNIPER_ZOOM_OUT~~w~ para ~h~alejarlo~w~. + +[HELP8_B] +Pulsa el ~h~botón ~k~~PED_SNIPER_ZOOM_IN~~w~ para ~h~acercar el zoom ~w~con el fusil y el ~h~botón ~k~~PED_SNIPER_ZOOM_OUT~~w~ para ~h~alejarlo~w~. [HELP9_A] -Pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar~w~ el rifle de francotirador. +Pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar~w~ el fusil de francotirador. + +[HELP9_B] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. + +[HELP9_C] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. [HELP10] -Esta insignia indica que estás buscado por la policía. +Esta insignia indica que la policía va a por ti. [HELP11] -Cuantas más insignias tengas mayor será tu grado de peligrosidad asignado en la búsqueda y captura. +Cuantas más insignias tengas, más peligroso te considerarán. + +[HELP12] +Entra en la señal azul para comenzar una misión. [HELP13] -Algunas veces puedes necesitar utilizar caminos no mostrados en el radar. +Algunas veces tendrás que usar caminos no mostrados en el radar. -[TIMER] -Esta es una misión cronometrada, debes completarla antes de que el temporizador llegue a cero. +[HELP14] +Para conseguir un arma, pasa sobre ella. No puedes recogerlas estando dentro de un vehículo. -[MISTY1] -~r~¡Misty es carne de depósito de cadáveres! +[HELP15] +Cuando vayas a pie mantén pulsado el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para~h~ mirar atrás~w~. -[OUT_VEH] -~g~¡Fuera del vehículo! - -[GARAGE] -Conduce el coche dentro del garaje, luego sal caminando. - -[WANTED1] -~g~¡Despista a los polis y pierde tu grado de búsqueda y captura! - -[NODOORS] -~g~¡No son sardinas! Consigue un coche con suficientes asientos. - -[TRASH] -~g~¡Has dejado tu vehículo bien jodido! ¡Haz que lo reparen! - -[WRECKED] -~r~¡El vehículo está destrozado! - -[HORN] -~g~Toca el claxon. - -[HORN4] -Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon - -[NOMONEY] -~g~¡Necesitas más pasta! - -[OUTTIME] -~r~¡Demasiado lento, tío, demasiado lento! - -[SPOTTED] -~r~¡Te siguen la pista! - -[REWARD] -RECOMPENSA $~1~ - -[GAMEOVR] -JUEGO ACABADO - -[Z] -Eje-Z valor: ~1~ - -[M_FAIL] -¡FRACASO EN LA MISIÓN! - -[M_PASS] -¡MISIÓN SUPERADA! $~1~ - -[O_PASS] -¡TRABAJO ESPORÁDICO SUPERADO! - -[O_FAIL] -¡FRACASO EN TRABAJO ESPORÁDICO! - -[DEAD] -¡LIQUIDADO! - -[BUSTED] -¡REVENTADO! - -[S_PROMP] -Cuando no estés en una misión puedes ~h~guardar tu partida aquí~w~, esto hará avanzar el tiempo seis horas. - -[NUMBER] -~1~ - -[SCORE] -~1~$ - -[LOADCAR] -CARGANDO VEHÍCULO... (PULSA EL BOTÓN L1 PARA CANCELAR) - -[CARSOFF] -Coches activados. - -[CARS_ON] -Coches desactivados. - -[TEXTXYZ] -Escribiendo coordenadas para archivar... - -[CHEATON] -Modo trucos ACTIVADO - -[CHEATOF] -Modo trucos DESACTIVADO - -[UZI_IN] -¡La Uzi está ahora en el depósito de Municiones! - -[IMPORT1] -Ve afuera y espera a tu vehículo. - -[PAGEB1] -Pistola entregada en escondite - -[PAGEB2] -Uzi entregada en escondite - -[PAGEB3] -Armadura personal entregada en escondite - -[PAGEB4] -Escopeta entregada en escondite - -[PAGEB5] -granadas entregadas en escondite - -[PAGEB6] -molotovs entregados en escondite - -[PAGEB7] -AK47 entregada en escondite - -[PAGEB8] -Rifle de francotirador entregado en escondite - -[PAGEB9] -M16 entregado en escondite - -[PAGEB10] -Lanzacohetes entregado en escondite - -[PAGEB11] -Lanzallamas entregado en escondite +{ WANTED SYSTEM TUTORIAL } [WANT_A] -Sólo serás arrestado si tienes un ~h~grado de búsqueda y captura. +Sólo serás arrestado si estás en ~h~búsqueda y captura~w~. [WANT_B] Tu ~h~grado de peligrosidad asignado a tu búsqueda y captura~w~ está representado por la hilera de estrellas en la parte superior derecha de la pantalla. @@ -236,31 +145,372 @@ dos... tres... [WANT_F] -A medida que tu ~h~grado de búsqueda y captura ~w~ aumenta te verás acosado por formas más poderosa de cumplimiento de la ley. +A medida que tu ~h~grado de búsqueda y captura~w~ vaya aumentando, te verás acosado por cuerpos policiales con una mayor potencia de fuego. [WANT_G] -Cuando seas ~h~'reventado'~w~ serás llevado a la comisaría de policía más cercana. +Cuando seas ~h~''trincado''~w~ serás llevado a la comisaría de policía más cercana. [WANT_H] -Los polis te requisarán todas tus armas y algo de tu dinero como soborno. +Los polis requisarán todas tus armas y algo de tu dinero como soborno. [WANT_I] Habrás fracasado en cualquier misión que estuvieses llevando a cabo. [WANT_J] -Encontrarás modos de reducir tu grado de búsqueda y captura cuanto más juegues. +A medida que avances en el juego encontrarás formas de reducir tu grado de búsqueda y captura. [WANT_K] -Si estás en un coche, ~h~LOS LAVADEROS ~w~ limpiarán ~h~tu grado de búsqueda y captura. +Si estás en un coche, los ~h~TALLERES DE PINTURA~w~ te quitarán ~h~tu grado de búsqueda y captura~w~. + +[HEAL_A] +Tu ~h~salud ~w~está indicada en naranja en la parte superior derecha de la pantalla. [HEAL_B] -Cuando seas ~h~'liquidado'~w~ volverás al hospital más cercano. +Cuando seas ~h~''liquidado''~w~ volverás al hospital más cercano. [HEAL_C] -Perderás tus armas y los doctores te cobrarán algún dinero por remendarte. +Los doctores te quitarán tus armas y te cobrarán un dinero por remendarte. [HEAL_E] -Encontrarás modos de curarte o de protegerte cuanto más juegues al juego. +A medida que avances en el juego encontrarás modos de curarte o de protegerte. + +{ WEAPON CONTROLS TUTORIAL } + +[GUN_1A] +Pulsa el ~h~botón ~k~~PED_CYCLE_WEAPON_RIGHT~~w~ y el ~h~botón ~k~~PED_CYCLE_WEAPON_LEFT~ ~w~para cambiar de arma. + +[GUN_2A] +¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... + +[GUN_2C] +¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... + +[GUN_2D] +¡Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático~w~ y pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta darle a los objetivos... + +[GUN_3A] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. + +[GUN_3B] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. + +[GUN_4A] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~~w~, puedes caminar o correr y seguir teniendo en la mira a un objetivo. + +[GUN_4B] +Mientras mantienes pulsado el ~h~botón ~k~~PED_LOCK_TARGET~~w~, puedes caminar o correr y seguir teniendo en la mira a un objetivo. + +[GUN_5] +Puedes practicar disparando a estos blancos. Cuando hayas terminado puedes continuar la misión. + +{ OTHER HINTS } + +[BOMB] +Mete tu vehículo en la tienda de ~h~bombas~w~ para poner una. Coste: ~h~1.000$~w~. + +[SAVE1] +Pasa por la puerta para ~h~guardar la partida~w~. No podrás guardar durante una misión. + +[SAVE2] +Cualquier vehículo que dejes en este garaje se conservará al guardar la partida. + +[AMMU] +Entra a la tienda Ammu-Nation para comprar armas. + +[BRIDGE1] +Cuando el puente Callahan esté reparado podrás conducir hasta Staunton Island. + +[TUNNEL] +Cuando el túnel Porter esté abierto podrás conducir hasta Staunton Island. + +[TIMER] +Esta es una misión cronometrada, debes completarla antes de que el temporizador llegue a cero. + +[GARAGE] +Mete el vehículo dentro del garaje y luego sal caminando. + +[S_PROMP] +Cuando no estés en una misión, podrás ~h~guardar tu partida aquí~w~. Esto hará avanzar el tiempo seis horas. + +[S_PROM2] +Puedes alojar un vehículo en el garaje de al lado al guardar tu partida. + +[SPRAY] +Mete tu vehículo en el taller de pintura para perder tu ~h~nivel de búsqueda~w~, ~h~reparar~w~ y~h~ repintar~w~ tu vehículo. Coste: ~h~1.000 dólares + +[SPRAY1] +Mete tu vehículo en el taller de pintura para perder tu ~h~nivel de búsqueda~w~, ~h~reparar~w~ y~h~ repintar~w~ tu vehículo. Coste: ~h~1.000 dólares~w~. Esta vez es gratis. + +[LOOK_A] +Pulsa y mantén pulsado el ~h~botón ~k~~VEHICLE_LOOKLEFT~~w~ o el ~h~botón ~k~~VEHICLE_LOOKRIGHT~~w~ para mirar~h~ a la izquierda~w~ o ~h~a la derecha ~w~mientras te encuentres en un vehículo. Pulsa ambos para mirar~h~ atrás~w~. + +[CAM_A] +Pulsa el ~h~botón ~k~~CAMERA_CHANGE_VIEW_ALL_SITUATIONS~~w~ para cambiar la ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. + +[CAM_B] +Pulsa el ~h~botón de dirección hacia arriba ~w~y ~h~abajo ~w~para cambiar los modos de ~h~cámara ~w~cuando vayas a pie o estés en un vehículo. + +[HORN1] +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. + +[HORN2] +Pulsa el ~h~botón L1~w~ para tocar el ~h~claxon. + +[HORN3] +Pulsa el ~h~botón R1~w~ para tocar el ~h~claxon. + +[HORN4] +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. + +[RADIO_A] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[RADIO_B] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[RADIO_C] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[RADIO_D] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. + +[SIREN_1] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. + +[SIREN_2] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. + +[SIREN_3] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. + +[SIREN_4] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. + +[BOATIN1] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. + +[BOATIN3] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. + +[BOATIN2] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. + +[BOATIN4] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. + +[GREN_1] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. + +[GREN_2] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. + +[GREN_3] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. + +[TUBE1] +Cuando el metro abra, podrás coger un tren hasta Staunton Island. + +[TUBE2] +Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al Aeropuerto Internacional Francis. + +[TUBE_2] +Para subirte a un vagón, pulsa el ~h~botón Entrar al vehículo~w~. + +[SPRAY_4] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. + +[SPRAY_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. + +[L_TRN_1] +Puedes coger en tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[L_TRN_2] +Puedes coger en tren para recorrer Portland. Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[S_TRN_1] +Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[S_TRN_2] +Puedes coger el metro para recorrer Liberty City. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un tren. + +[RCHELP] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. + +[RCHELPA] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. + +[DRIVE_A] +Ten una Uzi seleccionada cuando entres en un vehículo, luego mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. + +[DRIVE_B] +Ten una Uzi seleccionada cuando entres en un vehículo, luego mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. + +[CRUSH] +Aparca en la zona señalada y sal de tu vehículo para que sea triturado. + +[GARAGE1] +~g~Sal del vehículo y aléjate caminando. + +[PBOAT_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. + +[PBOAT_2] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. + +{ ============================================================================================================================ } +{ ================= PAGER MESSAGES, INDICATING THAT THE PLAYER HAS UNLOCKED WEAPONS AND ITEMS IN ITS HIDEOUT ================= } +{ ============================================================================================================================ } + +[PAGEB1] +Pistola ya disponible en tu guarida. + +[PAGEB2] +Uzi ya disponible en tu guarida. + +[PAGEB3] +Chaleco antibalas ya disponible en tu guarida. + +[PAGEB4] +Escopeta ya disponible en tu guarida. + +[PAGEB5] +Granadas ya disponibles en tu guarida. + +[PAGEB6] +Molotovs ya disponibles en tu guarida. + +[PAGEB7] +AK47 ya disponible en tu guarida. + +[PAGEB8] +Fusil de francotirador ya disponible en tu guarida. + +[PAGEB9] +M16 ya disponible en tu guarida. + +[PAGEB10] +Lanzacohetes ya disponible en tu guarida. + +[PAGEB11] +Lanzallamas ya disponible en tu guarida. + +[PAGEB12] +Soborno policial ya disponible en tu guarida. + +[PAGEB13] +Salud ya disponible en tu guarida. + +[PAGEB14] +Adrenalina ya disponible en tu guarida. + +{ ==================================================================================================================== } +{ ================= PAGER MESSAGES, INDICATING THAT GUNS HAVE BEEN UNLOCKED AT THE AMMU-NATION STORE ================= } +{ ==================================================================================================================== } + +[COLT_IN] +¡La pistola ya está disponible en la tienda Ammu-Nation! + +[UZI_IN] +¡La Uzi ya está disponible en la tienda Ammu-Nation! + +{ ================================================================================================== } +{ ================= PAGER MESSAGES THAT APPEAR WHEN CERTAIN CAR SHOPS ARE UNLOCKED ================= } +{ ================================================================================================== } + +[IMPEXPP] +Garaje de Importación/Exportación, puerto de Portland. Requerimos varios vehículos; revisa nuestro tablón de notas para saber más. + +[VANHSTP] +¿Quieres abrir algún Securicar? Llévalo a nuestro garaje en el puerto de Portland. + +[EMVHPUP] +Se compran vehículos de emergencia nuevos y usados a buen precio. Llévalos a la grúa que hay al noroeste del puerto de Portland. + +{ =============================================================== } +{ ================= RAMPAGE SUBMISSIONS STRINGS ================= } +{ =============================================================== } + +[RAMPAGE] +¡MASACRE! + +[RAMP_P] +¡MASACRE COMPLETADA! + +[RAMP_F] +MASACRE FALLIDA + +[RAMP_A] +¡TODAS LAS MASACRES COMPLETADAS! + +{ Pager messages } + +[PAGE_00] +. + +[PAGE_01] +¡Mata a ~1~ Diablos en 120 segundos! + +[PAGE_02] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_03] +¡Mata a ~1~ mafiosos en 120 segundos! + +[PAGE_04] +¡Mata a ~1~ Tríadas en 120 segundos! + +[PAGE_05] +¡Mata a ~1~ Tríadas en 120 segundos! + +[PAGE_06] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_07] +¡Revienta ~1~ cabezas jamaicanas en 120 segundos! + +[PAGE_08] +¡Quema a ~1~ yakuzas en 120 segundos! + +[PAGE_09] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_10] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_11] +¡Aniquila a ~1~ jamaicanos en 120 segundos! + +[PAGE_12] +¡Quema a ~1~ yakuzas en 120 segundos! + +[PAGE_13] +¡Vuela a ~1~ jamaicanos en 120 segundos! + +[PAGE_14] +¡Fríe a ~1~ colombianos en 120 segundos! + +[PAGE_15] +¡Machaca a ~1~ Hoods en 120 segundos! + +[PAGE_16] +¡Destruye ~1~ vehículos en 120 segundos! + +[PAGE_17] +¡Arrolla a ~1~ colombianos con un coche en 120 segundos! + +[PAGE_18] +¡Destruye ~1~ vehículos disparando desde otro en 120 segundos! + +[PAGE_19] +¡Revienta ~1~ cabezas colombianas en 120 segundos! + +[PAGE_20] +¡Decapita a ~1~ Hoods en 120 segundos! + +{ ======================================================== } +{ ================= PERCENTAGE BAR TEXTS ================= } +{ ======================================================== } [DAM] DAÑO: @@ -269,7 +519,7 @@ DAÑO: MUERTES: [FARES] -TARIFAS: +CARRERAS: [BULL] LINGOTES: @@ -283,23 +533,9 @@ ESTADO DEL COCHE: [COLLECT] RECOGIDOS: -[BOMB] -Conduce tu vehículo a la tienda de bombas para poner una ~h~bomba~w~. Coste - ~h~1.000$. - -[SAVE1] -Atraviesa la puerta para ~h~guardar la partida ~w~. No puedes guardas durante una misión. - -[SAVE2] -Cualquier vehículo dejado en este garaje será almacenado cuando la partida sea guardada. - -[AMMU] -Ve dentro del depósito de Municiones para comprar un arma. - -[BRIDGE1] -Cuando el Puente Callahan esté reparado podrás conducir hasta la isla Staunton. - -[TUNNEL] -Cuando el túnel Porter esté abierto podrás conducir hasta la isla Staunton. +{ ================================================================================== } +{ ================= POSSIBLY MAP SCREEN INDICATIONS, MISSING IN PC ================= } +{ ================================================================================== } [LUIGI] MISIONES DE LUIGI @@ -332,11 +568,15 @@ MISIONES DE RAY MISIONES DE LOVE [YARDIE] -MISIONES DE YARDIE +MISIONES DE JAMAICANOS [HOOD] MISIONES DE HOOD +{ =========================================================== } +{ ================= LIBERTY CITY AREA NAMES ================= } +{ =========================================================== } + [CITYZON] Liberty City @@ -344,10 +584,10 @@ Liberty City Portland [PORT_W] -Punta Callahan +Callahan Point [PORT_S] -Embarcadero Atlantic +Muelle Atlantic [PORT_E] Puerto de Portland @@ -356,7 +596,7 @@ Puerto de Portland Trenton [S_VIEW] -Mirador de Portland +Portland View [CHINA] Chinatown @@ -368,28 +608,28 @@ Playa de Portland Saint Mark's [REDLIGH] -Distrito Red Light +Barrio rojo [TOWERS] -Altos de Hepburn +Cerros de Hepburn [HARWOOD] Harwood [ROADBR1] -Puerto de Callahan +Puente Callahan [ROADBR2] -Puerto de Callahan +Puente Callahan [TUNNELP] Túnel Porter [BOMB1] -Garaje de 8-Ball +Taller de 8-Ball [COM_ZON] -Isla Staunton +Staunton Island [STADIUM] Aspatria @@ -401,3778 +641,43 @@ Rockford Campus de Liberty [CONSTRU] -Fuerte Staunton +Fort Staunton [PARK] -Belleville Park +Parque Belleville [COM_EAS] Newport [SHOPING] -Punta de Bedford +Bedford Point [YAKUSA] Torrington [SUB_ZON] -Costa de Vale +Shoreside Vale [AIRPORT] -Aeropuerto internacional +Aeropuerto Int. Francis [PROJECT] -Jardines de Wichita +Wichita Gardens [SUB_IND] -Cala de la Cúspide +Pike Creek [SWANKS] -Bosque de Cedros +Cedar Grove [BIG_DAM] Presa Cochrane [SUB_ZO2] -Costa de Vale +Shoreside Vale [SUB_ZO3] -Costa de Vale - -[CAR_1] -Ambulancia - -[CAR_2] -Camión de bomberos - -[CAR_3] -Policía - -[CAR_4] -Oficial - -[CAR_5] -Cuartel - -[CAR_6] -Rinoceronte - -[CAR_7] -Coche del FBI - -[CAR_8] -Securicar - -[CAR_9] -Moonbeam - -[CAR_10] -Coach - -[CAR_11] -Flatbed - -[CAR_12] -Rápido - -[CAR_13] -Trashmaster - -[CAR_14] -Patriot - -[CAR_15] -Sr. Whoopee - -[CAR_16] -Mule - -[CAR_17] -Yankee - -[CAR_18] -Pony - -[CAR_19] -Bobcat - -[CAR_20] -Rumpo - -[CAR_21] -Blista - -[CAR_22] -Dodo - -[CAR_23] -Bus - -[CAR_24] -Sentinel - -[CAR_25] -Cheetah - -[CAR_26] -Banshee - -[CAR_27] -Aguijón - -[CAR_28] -Infernus - -[CAR_29] -Esperanto - -[CAR_30] -Kuruma - -[CAR_31] -Stretch - -[CAR_32] -Perennial - -[CAR_33] -Landstalker - -[CAR_34] -Manana - -[CAR_35] -Idaho - -[CAR_36] -Semental - -[CAR_37] -Taxi - -[CAR_38] -Cabbie - -[CAR_39] -Buggy - -[LUIGIS] -Casa de Luigi - -[GOAWAY] -~g~¡Ya estás en una misión! - -[LUIGGO] -~g~Luigi está entrevistando a algunas chicas nuevas -¡Vuelve más tarde! - -[JOEYGO] -~g~Joey's está en la ciudad con Misty. ¡Pásate más tarde! - -[TONIGO] -~g~Toni ha llevado a su mamá a la ópera -¡Llama en otro momento! - -[KEMUGO] -~g~Maria y Kemuri están muy ocupadas en este momento - ¡Pásate más tarde! - -[KENJGO] -~g~Kenji ha ido a encuentro con los Yakuza -¡Llama en otro momento! - -[RAYGO] -~g~Ray tiene otros servicios por los que rondar -¡Inténtalo de nuevo más tarde! - -[LOVEGO] -~g~Donald Love tiene otros asuntos que atender -¡Pide una cita más tarde! - -[KENSGO] -~g~¡Kenji está ocupado! -¡Llama más tarde! - -[ASUSGO] -~g~¡Asuka no está disponible en este momento! - -[HOODGO] -~g~Los Capos no están disponibles en este momento! - -[WRONGT1] -~g~Vuelve entre las 05:00 y las 21:00 para un trabajo - -[WRONGT2] -~g~Vuelve entre las 06:00 y las 14:00 para un trabajo - -[WRONGT3] -~g~Vuelve entre las 15:00 y las 00:00 para un trabajo - -[GUN_1A] -Utiliza el ~h~botón ~k~~PED_CYCLE_WEAPON_RIGHT~ ~w~y el ~h~botón ~k~~PED_CYCLE_WEAPON_LEFT~ ~w~para pasar por tus armas. - -[GUN_2A] -Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~apuntar de modo automático ~w~, ¡pulsa el ~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta disparar a los objetivos... - -[GUN_2C] -Mantén pulsado el ~h~botón ~k~~PED_LOCK_TARGET~ ~w~para ~h~ apuntar de modo automático ~w~, ¡pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta disparar a los objetivos... - -[GUN_2D] -Mantén pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~ para ~h~ apuntar de modo automático,~w~ ¡pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar! Intenta disparar a los objetivos... - -[GUN_3A] -Mientras que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. - -[GUN_3B] -Mientras que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~,~w~ pulsa el ~h~botón ~k~~PED_CYCLE_TARGET_LEFT~~w~ o el ~h~botón ~k~~PED_CYCLE_TARGET_RIGHT~ para cambiar de objetivo. - -[GUN_4A] -Mientras que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~ puedes caminar o correr mientras mantienes fijado un objetivo. - -[GUN_4B] -Mientras que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~ puedes caminar o correr mientras mantienes fijado un objetivo. - -[GUN_5] -Puedes practicar el apuntar y disparar en estos objetivos de papel. Cuando hayas terminado retoma la misión. - -[TAXI1] -~g~ Busca la tarifa. - -[FARE1] -~g~Destino ~w~'Club Sex Kitten Miau' ~g~en Redlight. - -[FARE2] -~g~Destino ~w~'Supa Save' ~g~en el Mirador de Portland. - -[FARE3] -~g~Destino ~w~la 'sala de la vieja escuela' ~g~en Chinatown. - -[FARE4] -~g~Destino ~w~el 'Café Greasy Joe' ~g~en Punta Callahan. - -[FARE5] -~g~Destino ~w~'depósito de Municiones' ~g~en Redlight. - -[FARE6] -~g~Destino ~w~'Autos de crédito fácil' ~g~en Saint Mark. - -[FARE7] -~g~Destino ~w~'Bar de topless de Woody' ~g~en Redlight. - -[FARE8] -~g~Destino ~w~'Restaurante Marcos' ~g~en Saint Mark. - -[FARE9] -~g~Destino ~w~'garaje de importación y exportación' ~g~en Portland Harbor. - -[FARE10] -~g~Destino ~w~'Punk Noodles' ~g~en Chinatown. - -[FARE12] -~g~Destino ~w~'Estadio de Fútbol' ~g~en Aspatria. - -[FARE13] -~g~Destino ~w~'La iglesia' ~g~en Punta de Bedford - -[FARE14] -~g~Destino ~w~'El Casino' ~g~en Torrington - -[FARE15] -~g~Destino ~w~'Universidad Liberty' ~g~en el Campus de Liberty - -[FARE16] -~g~Destino ~w~'Centro comercial' ~g~en la zona de Belleville Park - -[FARE17] -~g~Destino ~w~'Muso' ~g~en Newport - -[FARE18] -~g~Destino ~w~'Edificio de AmCo' ~g~en Torrington - -[FARE19] -~g~Destino ~w~'Bolt Burgers' ~g~en Punta de Bedford - -[FARE20] -~g~Destino ~w~'El parque' ~g~en Belleville - -[FARE21] -~g~Destino ~w~'Aeropuerto internacional de Francis' - -[FARE22] -~g~Destino ~w~'el dique de Cochrane' - -[FARE24] -~g~Destino ~w~'El hospital' ~g~en la Cúspide de la Cala - -[FARE25] -~g~Destino ~w~'El parque' ~g~en la Costa de Vale - -[FARE26] -~g~Destino ~w~'Torres del Noroeste' ~g~en los Jardines de Wichita - -[NEW_TAX] -¡MÁS GRANDE! ¡MÁS RÁPIDO! ¡MÁS DURO! Nuevos taxis Borgnine abre su negocio en Harwood. ¡Llame hoy al 555-BORGNINE! - -[TSCORE2] -$~1~ - -[IN_ROW] -~1~ ¡Prima EN UNA FILA! $~1~ - -[TTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. - -[TTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. - -[ATUTOR2] -~g~Conduce CON CUIDADO a los pacientes hasta el hospital. Cada golpe reduce sus posibilidades de supervivencia. - -[A_TIME] -+~1~ segundos - -[A_FULL] -~r~¡¡Ambulancia completa!! - -[A_RANGE] -~g~La radio de la ambulancia está fuera de alcance, ¡acércate hasta un hospital! - -[FTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. - -[FTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del coche de bomberos. - -[F_PASS1] -¡Fuego apagado! - -[F_RANGE] -~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate hasta una estación de bomberos! - -[C_BREIF] -~g~Sospechoso visto por última vez en la zona ~a~. - -[C_RANGE] -~g~La radio de la policía está fuera de alcance, ¡acércate a una comisaría! - -[DODO_FT] -¡Huiste por ~1~ segundos! - -[EBAL_A] -Conozco un lugar al borde del distrito Red Light donde podemos escondernos, - -[EBAL_A1] -pero mis manos están hechas un desastre de modo que será mejor que conduzcas tú, hermano. - -[EBAL_1] -Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. - -[EBAL_1B] -Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. - -[EBAL_2] -~g~¡Vuelve al coche! - -[EBAL_3] -Este es el ~h~radar~w~. Utilízalo para surcar la ciudad, ¡sigue el ~h~pitido~w~ en el ~h~radar~w~ para encontrar el escondite! - -[EBAL_D] -Conozco un tipo, tiene contactos, su nombre es Luigi. - -[EBAL_D1] -Él y yo nos conocemos de antes de modo que probablemente podríamos conseguirte algún trabajo. Venga, vamos hacia allí. - -[EBAL_E] -Venga, vamos a pasarnos por allí y te presentaré. - -[EBAL_I] -El jefe saldrá para veros dentro de poco... - -[EBAL_J] -8-Ball tiene un asunto arriba. - -[EBAL_K] -Quizás puedes hacerme un favor - -[EBAL_L] -Una de mis chicas necesita que la lleven de modo que consigue un coche y recoge a Misty en la clínica. Luego tráela de vuelta aquí. - -[EBAL_N] -¡Así que mantén tus manos sobre el volante - -[EBAL_4] -~r~¡8-Ball está muerto! - -[EBAL_5] -~g~¡Consigue un vehículo! - -[EBAL_6] -~g~¡Recoge a Misty! - -[LM1] -'LAS CHICAS DE LUIGI' - -[LM2] -'NO PEGUES A MI ZORRA' - -[LM3] -'LLEVA A MISTY POR MÍ' - -[LM5] -'EL BAILE DE LA POLICÍA' - -[LM1_2] -~g~Lleva a Misty al Club de Luigi. - -[LM1_3] -~g~Toca el claxon para conseguir que la chica entre en el coche. - -[LM1_6] -~g~¡Vuelve al coche! - -[LM1_7] -Detén el vehículo junto a Misty y déjala subir. - -[LM1_8] -Puedes ir y ver a Luigi en busca de más trabajo o ver que se cuece en Liberty City. - -[LM2_A] -Hay un nuevo tipo importante en la ciudad que responde al nombre de AZOTE. - -[LM2_E] -Algún tipo listo ha estado mostrando esta basura a mis chicas abajo en el puerto de Portland. - -[LM2_B] -¡Ve y muéstrale un bate de béisbol en su cara! - -[LM2_G] -¡Quiero una compensación por este insulto! - -[LM2_1] -~g~Coge su coche y haz que lo vuelvan a rociar. - -[LM2_2A] -¡Utiliza el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar un puñetazo ~w~y ~h~dar una patada~w~ o ~h~balancear ~w~el bate de béisbol! - -[LM2_2C] -¡Utiliza el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar un puñetazo ~w~y ~h~dar una patada~w~ o ~h~balancear ~w~el bate de béisbol ~w~! - -[LM2_2D] -¡Utiliza el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar un puñetazo ~w~y ~h~dar una patada~w~ o ~h~balancear ~w~el bate ~w~! - -[LM2_3] -~g~¡Esconde el coche en el garaje de Luigi! - -[LM2_4] -~g~¡Vuelve a rociar el coche! - -[LM3_A] -Hey, tengo que hablar contigo... De acuerdo Mick, hablaré contigo más tarde. - -[LM3_B] -¿Cómo te vá, chico? - -[LM3_C] -El hijo del Don, Joey Leone, quiere un poco de acción de su chica de siempre, Misty. - -[LM3_D] -Ve a recogerla en los Altos de Hepburn... - -[LM3_E] -pero cuidado, ésa es la turba del Diablo. - -[LM3_F] -Luego llévala hasta el garaje de él en Trenton y hazlo rápido, - -[LM3_H] -¡así que mantén la vista sobre la carretera y lejos de Misty! - -[LM3_1D] -Pulsa el ~h~ botón L3 ~w~ para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. - -[LM3_2] -~g~Lleva a Misty a Joey's. - -[LM3_4] -~g~¡Ve a recoger a Misty! - -[LM3_5] -Ahora trabajas de forma regular para Luigi, ¿no? Ya era hora de que tuviese un conductor en el que pudiésemos confiar! - -[LM3_7] -Estaré contigo en un minuto, bujía. - -[LM3_10] -~g~¡Coge un vehículo! - -[LM4_B] -Ve y ocúpate de las cosas por mí. - -[LM4_C] -Si necesitas una pieza ve a la puerta trasera del depósito de Municiones en el lado contrario al metro. - -[LM5_A] -El baile de la policía se está celebrando en la sala de la vieja escuela cerca del puente - -[LM5_B] -y parece que están buscando un poco de acción a la 'antigua usanza'. - -[LM5_C] -Ahora tengo chicas por toda la ciudad, pateando las calles. - -[LM5_D] -Llévalas al baile, harán bulto. - -[LM5_1] -~g~Estás embutiendo a esas damas demasiado, ¡les van a salir moratones! ~g~Primero deja a esas chicas, luego vuelve a por más. - -[LM5_2] -~r~¡Una de las chicas de Luigi es un saco de grasa! - -[LM5_3] -~g~¡Necesitas un coche! - -[LM5_4] -~g~Recoge a las chicas que trabajan en St. Marks. - -[LM5_5] -~g~Lleva a las chicas al Baile de la Policía! - -[LM5_8] -~g~Chicas trabajando en el Baile: ~1~ - -[JM2] -'DESPEDIDA A LEE CHONG 'EL GORDO'' - -[JM4] -'EL CHOFER DE CIPRIANI' - -[JM5] -'LA MOFETA MUERTA EN EL MALETERO' - -[JM1_1] -~g~Lleva el coche de Forelli hasta el garaje de 8-Ball al Norte de aquí, detrás de 'Autos de crédito fácil'. - -[JM1_2] -~g~Vuelve a aparcar el coche en el restaurante de Marco. - -[JM1_3] -~g~¡Activa la bomba del coche y luego sal de ahí! - -[JM1_4] -~g~¡Estás destrozando el vehículo! ¡Repáralo! - -[JM1_5] -~g~¡La bomba del coche no está colocada! - -[JM1_6] -~g~Vuelve a colocar el coche en la posición correcta. - -[JM1_8A] -~y~¡Hey, es mi gran hombre! - -[JM1_8B] -~y~La tienda de bombas está automatizada. Simplemente entra conduciendo, detén tu coche y la tienda hará el resto. - -[JM1_8C] -~y~Ten, tu primer coche puede salirte gratis, pero después de eso te costará dinero. - -[JM2_A] -Lee Chong 'el Gordo' está dando palizas para una nueva banda de Colombia... o Colorado... o algo así.... - -[JM2_B] -La verdad es que no estoy seguro. De todas formas, quién necesita detalles. - -[JM2_D] -Esa rata a vendido su último refrito. - -[JM2_E] -¡Quiero que le liquides! - -[JM2_G] -Equípate con una nueve, sabes dónde está, ¿verdad? - -[JM2_H] -Bueno, recuerda, vigila tu espalda en China Town, es territorio de las Tríadas. - -[JM3_A] -De acuerdo vamos a por la furgoneta de la paga. - -[JM3_B] -Sale de China Town todos los días. - -[JM3_C] -Las balas ni siquiera abollarán el blindaje de la armadura de la furgoneta, de modo que coge un coche y échala de la carretera. - -[JM3_D] -Ahora golpéala fuerte y los imbéciles de los guardias de seguridad se achicarán. - -[JM3_E] -Luego llévala al almacén en los muelles y mis chicos se encargarán desde ahí. - -[JM3_F] -Bueno, no estarán haciendo sus rondas todo el día, de modo que no pierdas el tiempo. - -[JM3_1] -~g~Lleva la furgoneta al almacén. - -[JM3_2] -~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. - -[JM4_B] -¡Oh! ¡Aquí está el tipo del que te hablaba! - -[JM4_C] -De acuerdo, escucha. Este tío no es italiano y no es un mecánico, pero puede arreglar las cosas. - -[JM4_D] -Este es el Capo, Toni Cipriani. - -[JM4_E] -Sí, soy Toni Cipriani - -[JM4_F] -Bien, llévale al restaurante de Mamá en St Marks. - -[JM4_G] -Ahora escúchame, estoy planeando un trabajo que necesita un buen conductor de modo que pásate por aquí más tarde, ¿de acuerdo? - -[JM4_2] -¡Espera aquí! Mantén el motor en marcha. Esto no es una visita social. - -[JM4_3] -¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! - -[JM4_4] -Las Tríadas creen que pueden meterse conmigo, las Tríadas, ¡CONMIGO! - -[JM4_6] -¡Hey vigila el coche! Dije que nada de numeritos. - -[JM4_7] -~g~Lleva a Toni al restaurante de su mamá. - -[JM4_8] -~r~¡Toni ha sido liquidado! - -[JM5_A] -¡Cojonudo! Estupendo. - -[JM5_B] -De acuerdo, ¡justo el tipo con el que necesito hablar! - -[JM5_D] -Uno de los Forellis pensó que era un tipo listo, de modo que se llevó lo que estaba buscando. - -[JM5_E] -Lleva el cuerpo a la trituradora en Harwood, ¿de acuerdo? - -[JM5_1] -~g~¡Llévalo a la trituradora! - -[JM5_2] -~g~¡Son los hermanos Forelli! - -[JM6_A] -Debe ser todo un viajecito, ¿eh? - -[JM6_B] -De acuerdo, escucha. Lleva un coche hasta la casa franca en St. Marks y recoge a algunos de los míos. - -[JM6_C] -Están atracando un banco y necesitan un conductor. - -[JM6_D] -Di mi palabra de que eras el hombre, de modo que no fastidies esto. - -[JM6_E] -Llévales al banco antes de las cinco en punto, ni un minuto después. - -[JM6_2] -Mantén el motor en marcha, entraremos y saldremos enseguida. - -[JM6_3] -¡¡¡Sácanos de aquí!! - -[JM6_4] -¡¡¡Líbrate de los polis y llévanos a la casa franca!! - -[JM6_6] -~g~¡Ve y consigue un vehículo menos llamativo! - -[JM6_7] -~g~¡Necesitas a los 3 para robar el banco! - -[TM1] -'SACANDO LA COLADA' - -[TM2] -'EL ENCARGO' - -[TM3] -'SALVATORE HA CONVOCADO UNA REUNIÓN' - -[TM4] -'TRÍADAS Y TRIBULACIONES' - -[TM5] -'EL PEZ GLOBO' - -[TONI_P] -¡Tengo un trabajo urgente para ti! -Toni - -[TM1_A] -~w~Toma asiento, chico, siéntate. - -[TM1_B] -~w~Así que la lavandería no pagará protección, ¿eh? - -[TM1_C] -~w~¿Las Tríadas creen que pueden meterse conmigo? - -[TM1_D] -~w~Vamos a enseñar a esos aspirantes a tipos duros lo que significa ser un tipo duro. - -[TM1_E] -~w~Sí, enséñales algo de respeto. Ningún hijo mío recibe de nadie de las Tríadas. - -[TM1_F] -~w~Tu padre, Dios acoja su alma, no aguantó ninguna mierda de las Tríadas en Sicilia. - -[TM1_G] -~w~Lo siento Ma. Sí Ma. - -[TM1_H] -~w~Quiero que destruyas sus furgonetas de lavandería - -[TM1_I] -~w~y destroces a cualquiera de las Tríadas que se interponga en tu camino. - -[TM1_J] -~w~8-Ball puede suministrarte lo que necesites. - -[TM2_A] -~w~TONI ha salido a machacar a la gente o a intentarlo. - -[TM2_AA] -Nunca será tan duro como su padre, te dejó una nota en la mesa. - -[TM2_B] -~w~La lavandería ha aceptado pagar. ¡Lo hiciste realmente bien, chico! - -[TM2_C] -~w~Ve a recoger el dinero y tráelo de vuelta aquí. Cuidado con las Tríadas. - -[TM2_D] -~w~Pueden estar metiéndote un petardo por el culo, y no mancharse. - -[TM2_E] -~w~¡Nadie, quiero decir nadie, se mete con TONI CIPRIANI! - -[TM2_1] -~g~¡¡Devuélvele el dinero a Toni!! - -[TM2_2] -~g~¡Los dejaste tiesos a todos! - -[TM3_MA] -~w~¡No sé dónde está! - -[TM3_MB] -~w~Te juro que ese chico mío a veces no se conoce a sí mismo. - -[TM3_MC] -~w~Ahora bien, su padre era diferente. Siempre en la cumbre, al cargo de todo, valiente... - -[TM3_A] -~w~Don Salvatore ha convocado una reunión. - -[TM3_B] -~w~Necesito que recojas la limusina y a su chico, Joey, del garaje. - -[TM3_C] -~w~Luego recoge a Luigi en su club, vuelve aquí y recógeme a mí, - -[TM3_D] -~w~luego todos iremos juntos a la casa del jefe. - -[TM3_E] -~w~Esos Tríadas, no saben cuándo parar. - -[TM3_F] -~w~Quieren una guerra. Tendrán una guerra. - -[TM3_G] -~w~Ahora en marcha. - -[TM3_1] -~g~Coge el Stretch de Joey's. - -[TM3_2] -~g~Ahora ve a recoger a Luigi. - -[TM3_3] -~g~Ahora ve a recoger a Toni. - -[TM3_4] -~g~Lleva a los mafiosos hasta la casa de Salvatore. - -[TM3_5] -~y~¡¡Es una emboscada de las Tríadas!! - -[TM4_B] -~w~¡Estamos en GUERRA! Las Tríadas tienen una fábrica de pescado como fachada. - -[TM4_C] -~w~La mayor parte de sus negocios se pierde en el mercado de pescado de Chinatown. - -[TM4_D] -~w~Esa lavandería todavía nos debe por la protección. - -[TM4_E] -~w~Consideran que las Tríadas les están protegiendo ahora, así que digo que les demos su merecido castigo. - -[TM4_F] -~w~¡Toma a esos chicos y golpea a los Señores de la Guerra de las Tríadas! - -[TM4_G] -~w~Demonios, si tienes la oportunidad, revienta también a algunos de sus soldados. - -[TM4_GAT] -~g~Necesitas un 'Camión para pescado Tríada' para entrar. - -[TM5_A] -TEXT NO LONGER REQUIRED - -[TM5_B] -~w~Ya he tenido bastante de esta mierda. - -[TM5_C] -~w~¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! - -[TM5_D] -8-Ball ha instalado una bomba en un camión de la basura. - -[TM5_E] -~w~Tiene un temporizador, así que si la lías no quedarán evidencias. Vete y toma ese camión de basura. - -[TM5_F] -~w~¡Cuidado, 8-Ball dice que es muy sensible y que cualquier movimiento puede hacerlo estallar! - -[TM5_G] -~w~Su fábrica de pescado abrirá sus puertas a un camión de basura, así que puedes conducirlo allí directamente. - -[TM5_H] -~w~Aparca entre las latas de gas y ¡sal pitando de ese infierno! - -[TM5_I] -~w~Quiero que llueva trozos de caballa. - -[TM5_J] -~w~Esto es realmente bíblico, nada de bajo presupuesto. - -[FM2] -CORTANDO LA HIERBA - -[FM4] -ÚLTIMOS DESEOS - -[FM1_A] -~w~Yo y los chicos queremos hablar de negocios - -[FM1_B] -~w~Así que esta tarde vas a vigilar a mi chica. - -[FM1_C] -~w~¡OYE, MARÍA! ¡MUEVE ESE CULO! - -[FM1_D] -~w~El grandísimo estúpido hace esto todo el tiempo. - -[FM1_E] -~w~Y aquí está ella ¡La primera y única Reina de Saba! - -[FM1_F] -~w~¿Qué hacíais ahí arriba? - -[FM1_G] -~w~Fuera lo que fuera, seguro que me cuesta dinero. - -[FM1_H] -~w~Bueno, no pensarás que me voy a quedar a conversar ¿no? - -[FM1_I] -~w~Métete en ese coche y cierra la bocaza. - -[FM1_J] -~w~Llévate la limusina, pero devuélvela de una pieza ¿me has oído? - -[FM1_K] -~w~Y vigílala, puede causarte problemas. - -[FM1_L] -~w~¡Sí, sí, sí! Estoy segura de que tu nuevo perrito faldero tiene todo previsto. - -[FM1_M] -~w~¿Pues no es fuerte y grande? - -[FM1_N] -~w~¡Eh, Fido, vayamos a visitar a Chico y hacer una fiestecita! - -[FM1_P] -~g~Ese de ahí es Chico, párate cerca. - -[FM1_S] -~w~Ahí vas, señora. - -[FM1_TT] -~w~¡ES UNA REDADA POLICIAL! - -[FM1_1] -~g~¡Vuelve al Stretch! - -[FM1_2] -~g~¡Entra en el Stretch! - -[FM1_3] -~r~Si abandonas a María y Salvatore te zurrará, vuelve y recógela. - -[FM1_4] -~g~¡Te has deshecho de la mujer del Don! ¡Vuelve al almacén y espera a María! - -[FM1_5] -~g~¡Lleva a María sana y salva con Salvatore! - -[FM1_6] -~g~¡Chico no estará allí para siempre, lleva a María al muelle! - -[FM1_7] -~r~¡María está muerta! A Salvatore no le va a gustar nada... - -[FM1_8] -~r~¡Te cargaste al proveedor de Maria! - -[FM2_J] -Déjanos solos un minuto. - -[FM2_A] -El Cartel colombiano está haciendo SPANK en algún lugar de Liberty. - -[FM2_K] -pero no sabemos dónde y parece como si supieran todo lo que hacemos antes de que lo hagamos. - -[FM2_L] -Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. - -[FM2_M] -Ha estado malgastando más dinero del que gana. - -[FM2_N] -Normalmente toma un taxi de vuelta a casa tras el trabajo. Así que síguele. - -[FM2_O] -Y si nos está traicionando... mátalo. - -[FM2_F] -Aquí viene nuestro amiguito. El señor Bocazas en persona. - -[FM2_G] -¿Te han seguido? Sabes que lo que pasa aquí es nuestro pequeño secreto. - -[FM2_H] -No... no. No me han seguido. ¿Tienes mi mercancía? - -[FM2_I] -Aquí está tu SPANK, soplón, ahora habla. - -[FM2_P] -OK, así que los de Leone libran una guerra en dos frentes. - -[FM2_Q] -Tienen una guerra territorial con las Tríadas y no hay signos de que ninguno se vaya a rendir. - -[FM2_R] -Mientras tanto Joey Leone se ha hecho mala sangre con los Forellis. - -[FM2_S] -Cada día que pasa pierden hombres e influencia en la ciudad. - -[FM2_T] -Salvatore es cada vez más peligroso y paranoico. Sospecha de todos y de todo. - -[FM2_U] -Con lealtades como la tuya, por qué tendría que preocuparse. - -[FM2_1] -~g~¡Ahí está Curly Bob! - -[FM2_2] -~g~¡Curly ha salido del club, síguele! - -[FM2_5] -~g~Llévale al Puerto Portland. - -[FM2_6] -~r~¡Curly no entrará en un taxi accidentado! - -[FM2_7] -~r~¡Curly se ha esfumado! ¡Ya no hay encuentro! - -[FM2_8] -~g~¡Golpea a Curly Bob! - -[FM2_9] -~r~¡Curly Bob está muerto! - -[FM2_10] -~r~¡Curly se largó! - -[FM2_11] -~g~Aparca frente al club de Luigi, Curly Bob saldrá pronto. - -[FM2_12] -~r~¡Os ha dado esquinazo! - -[FM3_A] -~w~Tenemos que terminar con esos bastardos colombianos, - -[FM3_B] -~w~pero mientras estamos en guerra con las Tríadas no somos lo bastante fuertes. - -[FM3_C] -~w~El Cartel tiene fondos ilimitados procedentes de esa mierda de SPANK. - -[FM3_D] -~w~si les atacamos abiertamente, fregarán el suelo con nosotros. - -[FM3_E] -~w~Deben estar haciendo SPANK en ese barco grande al que os llevó Curly. - -[FM3_F] -~w~Así que tenemos que usar las cabezas, o mejor, una cabeza. La tuya. - -[FM3_G] -~w~Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal hacia mí, Salvatore Leone. - -[FM3_H] -~w~Si haces esto por mí, serás todo un hombre, cualquier cosa que quieras. - -[FM3_I] -~w~Ve a ver a 8-Ball, necesitas su experiencia para volar ese barco. - -[FM3_8A] -~w~¡Eh, hombre! Salvatore ha llamado, - -[FM3_8B] -~w~pero un trabajo como este necesita muchos fuegos artificiales. - -[FM3_8D] -~w~pero sabes que conmigo consigues mucho a cambio de tu pasta. - -[FM3_8E] -~w~De acuerdo, ¡vamos a hacerlo! - -[FM3_8F] -~w~Puedo hacer detonar este pequeño, pero aún no puedo usar una pieza con estas manos. - -[FM3_8G] -~w~¡Toma, este rifle te ayudará a reventar algunas cabezas! - -[FM3_4] -~g~¡Para el coche y deja que 8-Ball salga! - -[FM3_7] -~r~¡¡8-Ball se ha helado! - -[FM3_8] -~r~¡Los guardias han sido alertados! - -[FM4_A] -~w~Es mi limpiador favorito. - -[FM4_B] -~w~Estoy orgulloso de ti, hijo, sacudiste la mierda de esas pelotas grasientas. - -[FM4_C] -~w~Tengo un trabajito más para ti antes de que podamos celebrarlo. - -[FM4_D] -~w~Hay un coche a la vuelta del edificio del club de Luigi. - -[FM4_E] -~w~El interior está pringado de sesos. - -[FM4_F] -~w~Tuvimos que ayudar a un tipo a que se decidiera, y fue un poco -er- sucio. - -[FM4_H] -~w~Llévalo a la trituradora antes de que los polis lo encuentren. - -[AM3] -'SANGRA PAPARAZZI' - -[AM4] -'DÍA DE PAGA PARA RAY' - -[AM5] -'TANNER DOS CARAS' - -[AM1_A] -Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, - -[AM1_B] -de negocios o de lo que sea. Pongamos las cartas sobre la mesa. - -[AM1_C] -Yo soy Yakuza y sé que trabajas para la familia de Salvatore Leone. - -[AM1_D] -Puedo darte trabajo en nuestra organización, - -[AM1_E] -Pero primero debes demostrarme que has cortado todos tus lazos con la Mafia. - -[AM1_G] -Asegúrate de que no llega vivo a su club. - -[AM1_H] -Mientras tanto María y yo nos pondremos al día por los viejos tiempos. - -[AM1_I] -Oh.. Asuka, tienes masajista. - -[AM1_J] -Eso no es un masajista. - -[AM1_1] -~g~¡Salvatore está saliendo del club de Luigi! - -[AM1_2] -~r~¡Te han descubierto! - -[AM1_3] -~r~¡Has perdido a Salvatore! - -[AM1_4] -~r~Buen intento, ¡has asustado al objetivo! ¿Y te llamas a ti mismo pistolero? - -[AM1_5] -~g~Ve al Distrito de la Luz Roja y espera a que Salvatore salga del club. - -[AM1_7] -~r~Salvatore está en casa, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar Chacal! - -[AM1_8] -~g~Salvatore saldrá del club del Luigi aproximadamente a las ~1~:~1~ - -[AM2_4] -~g~¡Te han visto venir como a un elefante al galope! - -[AM3_A] -Un periodista ha estado metiendo sus narices por aquí. - -[AM3_B] -María y yo nos hemos tomado unas pequeñas vacaciones juntos hasta que puedas librarte de ese mirón pervertido. - -[AM4_A] -¡Es mi guapo manitas! - -[AM4_B] -María está muy ocupada en este momento, pero le diré que has llamado. - -[AM4_C] -¿Quién es? ¿Asuka? Ya sé que he sido una niña traviesa, ¡pero es que necesitaba mear! ¿Vale? - -[AM4_D] -Es el momento de que te encuentres con nuestro hombre dentro del DPL. - -[AM4_E] -Aquí está su pago por el último trabajito que hizo para nosotros. - -[AM4_F] -El es comprensiblemente cauteloso. - -[AM4_G] -Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. - -[AM5_A] -María y yo hemos ido de compras. - -[AM5_B] -¡Nuestra fuente en la policía nos ha informado de que uno de nuestros conductores es un extrañamente animado poli camuflado! - -[AM5_C] -El es un inútil fuera de su coche así que lo hemos marcado con un seguidor. - -[AM5_D] -¡Hazle sangrar! - -[AM5_1] -¡Tanner está sobre ti! - -[AS1] -'CEBO' - -[AS2] -'MARCHANDO UN EXPRESO' - -[AS4] -'RESCATE' - -[AS1_A] -~w~Parece que Miguel piensa que le maltrato - -[AS1_B] -~w~Pero él ha revelado cuánto teme Catalina tu búsqueda de revancha. - -[AS2_A] -~w~Infravaloramos los planes de Catalina para el SPANK - -[AS2_B] -~w~Va mucho más allá de los Yardies vendiéndolo en las esquinas. - -[AS2_D] -~w~Han vendido SPANK en puestos callejeros. - -[AS2_1] -¡¡Todos los puestos de expreso en Portland destruidos!! - -[AS2_2] -~g~¡¡Todos los puestos de expreso en Staunton Island destruidos!! - -[AS2_3] -~g~¡¡Todos los puestos de expreso en Shoreside Vale destruidos!! - -[AS2_4] -~r~¡¡El Cartel ha avisado a sus camellos!! - -[AS2_5] -~g~¡Todavía hay puestos de expreso en Shoreside Vale y en Staunto Island! - -[AS2_6] -~g~¡Todavía hay puestos de expreso en Shoreside Vale! - -[AS2_7] -~g~¡Todavía hay puestos de expreso en Staunton Island! - -[AS2_8] -~g~¡Todavía hay puestos de expreso en Portland! - -[AS2_9] -~g~¡Todavía hay puestos de expreso en Portland y en Shoreside Vale! - -[AS2_10] -~g~¡Todavía hay puestos de expreso en Portland y en Staunton Island! - -[AS2_12] -~g~¡Cruza los distritos de Liberty para buscar puestos de ~b~Marchando un Expreso! - -[AS3_A] -~W~¿Lo apretamos un poco más o esperamos a que se vuelva negro y caiga? - -[AS3_B] -~w~Dale un pinchazo rápido... - -[AS3_D] -~w~¡Mi manitas! - -[AS3_E] -~w~Me aburría, así que vine a hacer compañía a Asuka. - -[AS3_1] -~g~Busca un ~r~bote~g~ y ve al ~b~boya del aeropuerto! - -[AS3_3] -~g~Espera a que el ~y~avión~g~ comience a acercarse! - -[AS3_5] -~g~¡Recupera la carga! - -[AS3_4] -~g~¡¡Usa un lanzador de cohetes para derribar ~y~el avión~g~!! - -[AS3_2] -~b~¡Ve al boya del aeropuerto! ~y~¡¡El avión se está acercando!! - -[AS3_6] -~g~~1~ DE 8 - -[KM1] -'KANBU REVIENTA' - -[KM3] -'TRATO SIGILOSO' - -[KM4] -'SHIMA' - -[KM5] -'HEROÍNA' - -[KM1_A] -Mi hermana habla muy bien de ti, - -[KM1_E] -aunque todavía debo convencerme de que un gaijin puede ofrecerme algo más que contratiempos. - -[KM1_B] -Tal vez puedas ayudar con una situación que me tiene en desventaja. - -[KM1_F] -Desde luego que el fracaso lleva consigo su propia desgracia. - -[KM1_C] -Un Yakuza Kanbu está bajo custodia esperando ser trasladado y juzgado. - -[KM1_G] -Es un valioso miembro de la familia. - -[KM1_H] -Libéralo y llévatelo al dojo de Bedford Point. - -[KM1_D] -Te damos las gracias por tus generosas acciones. Si alguna vez necesitas ayuda el dojo tendrá el honor de proporcionarte dos hombres que permanecerán a tu lado. - -[KM1_1] -~g~¡Roba un coche de la pasma! - -[KM1_2] -~g~¡Carga el coche con una bomba! - -[KM1_3] -~g~Ahora llévalo al dojo Yakuza. - -[KM1_5] -~g~Vale, ahora ve a la comisaría. - -[KM1_6] -~g~¡Pon una bomba en el coche! - -[KM1_7] -~g~¡Sólo vehículos de policía autorizados! - -[KM1_9] -~r~No usaste un coche bomba para destruir la pared. - -[KM1_10] -~r~El Yakuza Kanbu está muerto - ¡y tu honor también! - -[KM1_11] -~r~¡Trajiste la desgracia a ti mismo! - -[KM2_A] -Es imposible sobreestimar la importancia del protocolo en esta sección de trabajo. - -[KM2_B] -Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca tuve la oportunidad de devolver su amabilidad. - -[KM2_C] -Su punto débil son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. - -[KM2_F] -Mi honor lo demanda. - -[KM2_2] -~g~Coche entregado. - -[KM3_A] -Cuando los problemas acechan, el tonto les da la espalda, mientras el hombre sabio los enfrenta. - -[KM3_B] -El Cartel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. - -[KM3_C] -Ahora están negociando con los jamaicanos para humillarnos aún más. - -[KM3_D] -Están cerrando un trato en toda la ciudad. - -[KM3_F] -Llévate a uno de mis hombres, roba un coche Yardie y ve a presentar tus respetos a los colombianos. - -[KM3_E] -Nuestro honor demanda que no dejes a nadie vivo. - -[KM3_2] -~g~Ve y recoge a tu contacto. - -[KM3_3] -~g~¡La reunión está teniendo lugar en el estacionamiento del hospital de Rockford! - -[KM3_4] -~r~¡Han escapado! - -[KM3_6] -~g~¡Mátalos, mátalos a todos! - -[KM3_8] -~g~¡Necesitas un coche Yardie para hacer el trabajo! - -[KM3_9] -~r~Uno de los colombianos está muerto, se acabó el trato. - -[KM3_10] -~r~¡El contacto está muerto! - -[KM4_A] -Para ser verdaderamente fuerte es importante que nunca demuestres debilidad. - -[KM4_C] -Ve y recolecta el dinero inmediatamente, para que podamos ingresarlo en las cuentas del casino. - -[KM4_1] -¡No puedo pagarte y no lo haría aunque pudiera! - -[KM4_9] -¡Una banda de jóvenes acaban de arrasar el local! ¡Se han llevado todo! - -[KM4_2] -No servís para nada. - -[KM4_10] -De todas maneras, ¡qué clase de Yakuza eres TÚ? - -[KM4_3] -Esto no es para lo que os pago, tíos. Si quisiera esta clase de protección habría llamado al maldito servicio de policía. - -[KM4_4] -~g~¡Castiga a la banda responsable y recupera el dinero de la protección! - -[KM4_7] -~r~¡El tendero la acaba de palmar! - -[KM4_5] -Donald Love desea que te dejes caer en su jardín de té para que podáis hablar. - -[KM4_6] -¡Aquí está todo el dinero! - -[KM4_8] -~g~¡Maletín recolectado! - -[KM5_A] -¡TÚ! ¡Qué adecuado que elijas este momento para enseñar tu cara culo! - -[KM5_B] -Parece que tus intentos para disuadir a los jamaicanos - -[KM5_B1] -que se conviertan en chicos malos en el Cartel, ¡son totalmente inadecuados! - -[KM5_C] -¡Los camellos Yardie se alinean en las calles de Liberty vendiendo paquetes de SPANK como si fueran perritos calientes! - -[KM5_D] -Estos cerdos del Cartel se están riendo de nosotros, ¡en mi cara! - -[KM5_E] -¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene una base segura! - -[KM5_F] -¡¡¡Entierra estos sacos de basura y lava tu vergüenza en ríos de la sangre de nuestros enemigos!!! - -[KM5_3] -~r~Fallaste al matar al menos a ~1~ yardies. - -[KM5_4] -~g~Felicitaciones, mataste a ~1~ yardies. - -[KM5_5] -~g~Enhorabuena, mataste ~1~ yardies. ~1~$ EXTRA - -[RM1] -'SILENCIA AL SOPLÓN' - -[RM3] -'POCA EVIDENCIA' - -[RM4] -'DE PESCA' - -[RM5] -'PASTA DE YESO' - -[RM1_D] -Se encuentra bajo protección armada en la propiedad de WitSec, en el centro de Newport, en algún piso que hay detrás del aparcamiento. - -[RM1_E] -Incendia ese lugar, eso les hará salir y podrás cazarlos, asegúrate de que no hable con nadie. - -[RM1_1] -~g~Comprueba la casa de protección de testigos. - -[RM1_2] -~g~¡Saca a McAffrey! - -[RM2_A1] -¡Eh tú, el chaval de ahí! - -[RM2_A] -Un viejo colega del ejército lleva un asunto en Rockford. - -[RM2_D] -Va a necesitar algún respaldo y a cambio te dará cualquier herramienta que compres a precios de ganga. - -[RM2_E] -Ray se adelantó al llamar....pero pensé que serías algo más. - -[RM2_F] -Bien, tres armas son mejor que una, así que hazte con lo que necesites. - -[RM2_G] -~g~¡Ve a echar un vistazo a Phil! - -[RM2_H] -~r~¡¡Han matado a Phil!! - -[RM2_L] -¡Hey! ¡Si hubiera estado de tu bando en Nicaragua quizás todavía conservaría mi brazo! - -[RM2_N] -No te preocupes por el dinero. Ahora lárgate de aquí, yo entretendré a los polis. - -[RM3_D] -Están llevando la prueba por toda la ciudad. - -[RM3_E] -Vas a tener que deshacerte del coche y recoger hasta la última prueba que quede por ahí. - -[RM3_F] -Cuando lo tengas todo, déjalo en el coche y préndele fuego. - -[RM3_G] -Lo vamos a llevar mucho mejor sin este chico. - -[RM3_1] -~g~Deja la prueba en un coche y después préndele fuego. - -[RM3_4] -~g~¡El Fiscal ha retirado la prueba! - -[RM3_6] -~r~¡Las fotos habrán acabado con toda posibilidad de Libertad! - -[RM3_7] -~g~¡Ahora préndele fuego al coche! - -[RM4_A] -Creo que mi socio es una rata. - -[RM4_C] -Casi todas las noches sale a pescar con su barca cerca del faro que hay en Portland Rock. - -[RM4_D] -¡Roba una barca de la policía y asegúrate de que se vengan abajo sus planes de darte una puñalada trapera! - -[RM4_1] -~g~Vete y roba una barca de la policía. - -[RM4_2] -~g~¡Vete al faro y 'liquida' al socio de Ray! - -[RM5_A] -¡Inútil de mierda! - -[RM5_A1] -¡Eres un absoluto imbécil! Tengo el culo a tiro y ni siquiera eres capaz de matar a una maldita mosca. - -[RM5_B] -¡Te he pagado una pasta para que mates al testigo y aún sigue vivo! - -[RM5_B1] -¡Y hoy va a declarar ante los Federales! - -[RM5_C] -Le van a llevar de un momento a otro del Hospital General Carson a Rockford. - -[RM5_D] -Si se chiva, yo canto.... - -[RM5_E] -¡así que vete y haz el trabajo por el que se te pagó! - -[RM5_1] -~g~¡¡Detén la ambulancia!! - -[RM5_2] -~g~¡¡Te han chafado!! - -[RM5_3] -~g~¡Ha sido una trampa! - -[RM5_4] -~g~¡¡Las balas no van a atravesar ese chaleco antibalas!! - -[RM5_5] -~g~¡¡Ese chaleco antibalas es a prueba de fuego!! - -[RM5_7] -~r~¡¡Han llevado al testigo!! - -[RM5_8] -~g~¡¡El testigo se ha ahogado!! - -[LOVE2] -'¡EXTERMINA A WAKA-GASHIRA!' - -[LOVE3] -'UNA GOTA EN EL OCÉANO' - -[LOVE1_A] -Antes que nada, déjame que te agradezca que te hayas ocupado de ese asunto personal. - -[LOVE1_F] -La gente tiende a malinterpretar las cosas últimamente. - -[LOVE1_D] -Están intentando sacarme más de lo pactado, pero no soy precisamente partidario de revisar los tratos. - -[LOVE1_E] -Un trato es un trato, así que no van a ver ni un duro mío. - -[LOVE1_G] -Ve a rescatar a mi amigo, haz lo que haga falta. - -[LOVE1_2] -~g~Rescata al Anciano Caballero Oriental. - -[LOVE1_3] -~g~Lleva de vuelta al edificio de Donal Love al Anciano Caballero Oriental. - -[LOVE1_4] -~g~El Anciano Caballero Oriental debe estar en uno de los aparcamientos.... - -[LOVE1_6] -~r~¡Las tripas del Anciano Caballero Oriental están esparcidas por las calles! - -[LOVE1_7] -~g~Sólo se abrirá la puerta para un coche de la Banda Colombiana. - -[LOVE2_A] -No hay nada como una de esas guerras de bandas pasadas de moda para hacer que bajen los precios de la vivienda, - -[LOVE2_B] -excepto desencadenar una plaga......pero eso sería llegar demasiado lejos en este caso. - -[LOVE2_C] -He observado que Yakuza y los Colombianos no son precisamente buenos amigos. - -[LOVE2_D] -Vamos a aprovechar las posibilidades de negocio que se presentan. - -[LOVE2_E] -Quiero que mates a Kanji Kase, el WAKA-cuchillera de Yakuza. - -[LOVE2_F] -Kenji está asistiendo a una reunión en lo alto del aparcamiento de los almacenes de Newport. - -[LOVE2_G] -¡Hazte con un coche de la banda del Cartel y elimínalo! - -[LOVE2_H] -El Yakuza debe culpar al Cartel por esta declaración de guerra. - -[LOVE2_1] -~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! - -[LOVE2_2] -~g~¡Ahora ve a los ~p~almacenes de Newport~g~ y cárgate a Kenji! - -[LOVE2_3] -~r~¡Si lo haces sin un coche del Cartel te identificarán! - -[LOVE2_4] -~r~¡¡El Yakuza te ha identificado!! - -[LOVE2_6] -~r~¡¡Has matado a todos los testigos!! - -[LOVE3_A] -En estos días de hipocresía moral ciertos artículos pueden resultar difíciles de importar. - -[LOVE3_C] -Echará varios paquetes en el agua. - -[LOVE3_D] -Asegúrate de que los recoges antes que nadie más lo haga. - -[LOVE3_1] -~g~¡Consigue una ~r~barca~g~ y sigue al ~y~avión~g~! - -[LOVE4] -'GRAN LADRÓN AÉREO' - -[LOVE5] -'SERVICIO DE ESCOLTA' - -[LOVE4_A] -Gracias por hacerte con esos paquetes, pero no eran más que una trampa. - -[LOVE4_B] -Lo siento, pero a veces así son los negocios. - -[LOVE4_C] -Mi objetivo real se ocultaba por completo en el avión. - -[LOVE4_F] -Tengo sobornados a los oficiales. - -[LOVE4_1] -~r~¡Está aquí el Cartel Colombiano!! - -[LOVE4_2] -~g~¡Ha desaparecido el paquete! Sigue la pista a los colombianos y recupéralo. - -[LOVE4_3] -~g~¿Construcción Panlántica ...? - -[LOVE4_5] -~g~El paquete debería estar en el avión.... - -[LOVE4_6] -~g~¡Sube en el ascensor a lo alto de la torre! - -[LOVE5_B] -Mi amigo Oriental va a necesitar una escolta mientras trata de comprobar si mi última adquisición es auténtica o no. - -[LOVE5_1] -~g~¡Vamos! - -[LOVE5_2] -~g~¡Vas a necesitar un coche! - -[LOVE5_3] -~g~¡Sigue hasta que puedas encontrar la salida del túnel! - -[LOVE5_4] -~r~¡Protege el camión! - -[RM6] -'HOMBRE SEÑALADO' - -[RM6_A] -¿No te han seguido? Bien. - -[RM6_B] -Así de fácil, ¡no tengo dónde meterme y me estoy empezando a hundir aquí mismo! - -[RM6_D] -Soy un hombre señalado, así que tengo que largarme de aquí. - -[RM6_E] -¡Consigue que no pierda mi vuelo en el aeropuerto y haré que haya merecido la pena tu trabajo! - -[RM6_666] -Cuida de mi Patriot a prueba de balas. Nos vemos en Miami, Ray - -[CAT1] -'RESCATE' - -[CAT2] -'EL INTERCAMBIO' - -[CAT1_A] -Tengo a la preciosa María. No creo que quieras que su cara parezca como si se hubiera enfadado con el carnicero. - -[CAT2_F] -Me he roto una uña y se me ha estropeado el peinado. Es increíble. ¡Me había costado 50 $! - -[CAT2_G] -Tenía tanto miedo, pero entonces me dije a mí misma, ahora eres una gran chica. - -[CAT2_H] -Oh, nos lo vamos a pasar a lo grande, porque, ¿sabes?, mi hermana dijo que quería venirse a vivir con sus dos hijos, - -[CAT2_I] -porque su marido a vuelto a enredar por ahí y..... - -[CAT1_C] -XXXX - -[CAT1_D] -XXXX - -[CAT1_E] -XXXX - -[CAT1_F] -¡Ve a donde está Catalina antes de que se acabe el tiempo! - -[CAT1_G] -XXXX - -[CAT1_H] -XXXX - -[CAT1_I] -XXXX - -[CAT1_J] -XXXX - -[CAT1_K] -XXXX - -[CAT1_L] -XXXX - -[AS4_1] -XXXX - -[CAT_MON] -~g~Todavía no tienes suficiente dinero. Necesitas 500.000 $. - -[BITCH_D] -~g~¡María está muerta! - -[WEATHER] -FORZAR EL CLIMA - -[WEATHE2] -CLIMA NORMAL - -[8001] -¡¡Has fallado miserablemente!! - -[1000] -ESTÁS MUERTO - -[1001] -ESTÁS MUERTO - -[1002] -ESTÁS MUERTO - -[1003] -ESTÁS MUERTO - -[1004] -ESTÁS MUERTO - -[1005] -AVERIADO - -[1006] -AVERIADO - -[1007] -AVERIADO - -[1008] -AVERIADO - -[1009] -AVERIADO - -[GA_4] -Las bombas de coche valen 1000 $ cada una - -[GA_5] -Tu coche ya tiene instalada una bomba. - -[GA_6] -Apárcalo, prepáralo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL POR PATAS! - -[GA_7] -Arma con el ~h~botón ~k~~PED_FIREWEAPON~~w~. La bomba estallará cuando se arranque el motor. - -[GA_8] -Utiliza el detonador para activar la bomba. - -[GA_9] -Ha conseguido ~1~de los 10 coches especiales - -[GA_10] -Buen ejemplar. Aquí tienes tus ~1~$ - -[GA_11] -Las ruedas ya están listas. ¡No sirve para nada! - -[GA_12] -Bomba armada - -[GA_13] -Entregado como un profesional. Completa la lista y conseguirás una bonificación. - -[GA_14] -Todos los coches. ¡ESTUPENDO! Aquí hay algo para ti. - -[GA_15] -Espero que te guste el nuevo color. - -[GA_16] -Repintarlo es adicional. - -[GA_19] -No nos interesa ese modelo. - -[GA_20] -Tenemos de esos más de los que podamos ocuparnos. Lo siento, tío, no hay negocio. - -[CR_1] -La grúa no puede levantar este vehículo. - -[PU_MONY] -No tienes suficiente dinero. - -[CO_ALL] -Los tienes todos. Aquí hay algo para ti... - -[PAUSED] -JUEGO EN PAUSA GAME PAUSED - -[HEALTH1] -¡Lárgate de aquí! Estás completamente sano. - -[HEALTH2] -La salud cuesta dinero. - -[HEALTH3] -Te pondré como nuevo. - -[HEALTH4] -Eso te va a costar 250 $. - -[FEB_STA] -Estadísticas - -[FEB_BRI] -Informes - -[FEB_CON] -Controles - -[FEB_AUD] -Sonido - -[FEB_DIS] -Pantalla - -[FEB_LAN] -Idioma - -[FEP_STA] -ESTADÍSTICAS - -[FEP_BRI] -INFORMES - -[FEP_CON] -CONTROLES - -[FEP_AUD] -SONIDO - -[FEP_DIS] -PANTALLA - -[FEP_LAN] -IDIOMA - -[FEF_ST1] -¿Quién es el malo? - -[FEF_ST2] -Cuánta destrucción has producido - -[FEF_BR1] -¿Has perdido el hilo? - -[FEF_CO1] -¿Necesitas más control, pirado? - -[FEF_CO2] -Elige la mejor configuración del mando para tu estilo de juego - -[FEF_SA1] -¡Mantén tu sitio en el bloque! - -[FEF_SA2] -Guarda y carga tus partidas - -[FEF_AU1] -¡Pon el volumen a tope! - -[FEF_AU2] -Elige una emisora de radio y un efecto de sonido - -[FEF_DI1] -¡Cambia el juego! - -[FEF_DI2] -Personaliza el juego para tu televisión - -[FEF_LA1] -¿Qué dices de los willis? - -[FEF_LA2] -Elige la forma de hablar que prefieras - -[FEB_PMB] -Informes de la Misión Previa: - -[FEC_NA] -No Disponible - -[FEC_CWL] -Cambiar al Arma izquierda - -[FEC_CWR] -Cambiar al Arma izquierda - -[FEC_LOF] -Mirar hacia delante - -[FEC_TAR] -Objetivo - -[FEC_MOV] -Movimiento - -[FEC_CAM] -Modos de Cámara - -[FEC_PAU] -Pausa - -[FEC_ENV] -Entrar al vehículo - -[FEC_JUM] -Saltar - -[FEC_ATT] -Ataque o Arma de Fuego - -[FEC_RUN] -Correr - -[FEC_FPC] -Cámara en primera persona - -[FEC_LL] -Mirar a la izquierda - -[FEC_LB1] -Mirar - -[FEC_LB2] -detrás - -[FEC_LB] -Mirar detrás - -[FEC_LR] -Mirar a la derecha - -[FEC_HOR] -Bocina - -[FEC_VES] -Control del vehículo - -[FEC_RSC] -Cambiar de emisora de Radio - -[FEC_BRA] -Freno o Marcha Atrás - -[FEC_HAB] -Freno de mano - -[FEC_CAW] -Arma del coche - -[FEC_ACC] -Acelerar - -[FEC_SMT] -Activar misión especial - -[FEC_CCF] -Configuración: - -[FEC_CF1] -Ajuste1 - -[FEC_CF2] -Ajuste2 - -[FEC_CF3] -Ajuste3 - -[FEC_CF4] -Ajuste4 - -[FEC_CDP] -Pantalla del mando: - -[FEC_ONF] -A Pie - -[FEC_INC] -En Coche - -[FEC_VIB] -Vibración: - -[FEA_OUT] -Salida: - -[FEA_ST] -Estéreo - -[FEA_MNO] -Mono - -[FEA_NON] -Ninguna - -[FEA_FM0] -HEAD RADIO - -[FEA_FM1] -DOUBLE CLEFF FM - -[FEA_FM2] -K-JAH RADIO - -[FEA_FM3] -RISE FM - -[FEA_FM4] -LIPS 106 - -[FEA_FM5] -GAME FM - -[FEA_FM6] -MSX FM - -[FEA_FM7] -FLASHBACK 95.6 - -[FEA_FM8] -CHATTERBOX 109 - -[FED_DBG] -Menú de Depuración - -[FED_RID] -Recargar IDE - -[FED_RIP] -Recargar IPL - -[FED_PAH] -Analizar pila - -[FED_RCD] -CCullZones::RecalculateCullZoneData - -[FED_DFL] -CTheScripts::DbgFlag - -[FED_DLS] -Activada la Luz de Depuración Blanca Grande - -[FED_SPR] -Mostrar Grupos de Carretera Ped - -[FED_SCR] -Mostrar Grupos de Carretera de Coches - -[FED_SCZ] -Mostrar Zonas 'A escoger' - -[FED_DSR] -Compilar las Solicitudes de Streaming - -[FED_SCP] -gbShowCollisionPolys - -[FEM_MCM] -Memory Card Menu - -[FEM_RMC] -Registrar MemCard Uno - -[FEM_TFM] -Probar Formato de MemCard Uno - -[FEM_TUM] -Probar Memcard Uno SinFormato - -[FEM_CRD] -Crear Dir Raiz - -[FEM_CLI] -Crear y Cargar Iconos - -[FEM_FFF] -Llenar Primer Archivo con Necedades - -[FEM_SOG] -Guardar Sólo El Juego - -[FEM_CES] -Comprobar Cada 0kBpara Guardar - -[FEM_STG] -Guardar El Juego - -[FEM_STS] -Guardar El Juego bajo el nombre GTA3 - -[FEM_CPD] -Crear copia protegida del directorio Revista - -[FEM_MC2] -Memory Card Menu 2 - -[FEM_TS] -Probar Guardar: - -[FEM_TL] -Probar Guardar: - -[FEM_TD] -Probar Borrar: - -[PL_STAT] -Estadísticas del jugador - -[PE_WAST] -Personas que has dilapilado - -[PE_WSOT] -Personas dilapiladas por otros - -[CAR_EXP] -Coches explotados - -[TM_BUST] -Tiempos no conseguidos - -[M_WASTE] -Hombres civiles dilapilados - -[F_WASTE] -Mujeres civiles dilapiladas - -[PIG_WST] -Polis dilapilados - -[GNG_WST] -Miembros de bandas dilapilados - -[MED_WST] -Personal médico dilapilado - -[FIRE_WS] -Bomberos empleados - -[DED_CRI] -Criminales dilapilado - -[DED_DED] -Vagos dilapilados - -[DED_HOK] -Prostitutas dilapiladas - -[HEL_DST] -Helicópteros destruidos - -[PER_COM] -Porcentaje cumplido - -[KGS_EXP] -Kgs de explosivos empleados - -[ACCURA] -Puntería - -[ELBURRO] -Mejor tiempo de Turismo en segundos - -[CAR_CRU] -Coches destrozados - -[HED_EX] -Cabezas explotadas - -[TM_DED] -Visitas al hospital - -[DAYSPS] -Días de juego transcurridos - -[MMRAIN] -mm de lluvia caídos - -[MXCARD] -Máx. dist. Salto INSANO (pies) - -[MXCARJ] -Máx. altitud Salto INSANO (pies) - -[MXCARDM] -Máx. dist. Salto INSANO (metros) - -[MXCARJM] -Máx. altura Salto INSANO (metros) - -[MXFLIP] -Máx. vueltas Salto INSANO - -[MXJUMP] -Máx. rotación Salto INSANO - -[BSTSTU] -Mejor maniobra INSANA hasta ahora: - -[INSTUN] -Maniobra Insana - -[PRINST] -Maniobra insana perfecta - -[DBINST] -Maniobra insana doble - -[DBPINS] -Maniobra insana doble perfecta - -[TRINST] -Maniobra insana triple - -[PRTRST] -Maniobra insana triple perfecta - -[QUINST] -Maniobra insana cuádruple - -[PQUINS] -Maniobra insana cuádruple perfecta - -[NOSTUC] -Ninguna maniobra insana completada - -[NOUNIF] -Saltos Únicos completados - -[NOUNGM] -Total de Saltos Únicos - -[NMISON] -Misiones intentadas - -[NMMISP] -Misiones conseguidas - -[PASDRO] -Pasajeros tirados en marcha - -[MONTAX] -Dinero conseguido en taxi - -[DAYPLC] -Gasto diario en policias - -[CRIMRA] -Porcentaje criminal: - -[GMSTOR] -Almacén de Juego - -[PREBRF] -Informes Previos - -[CNTLS] -Controles - -[MUSMEN] -Música / Efectos Especiales - -[GAMSET] -Ajustes del Juego - -[LANGUA] -Idioma - -[DSPLAY] -Pantalla - -[DEBUGM] -Menú de Depuración - -[QUITOP] -Salir de las Opciones - -[CONTRL] -Configuración de Control - -[SET1EN] -Ajuste 1. Activado - -[SET1] -Ajuste 1. - -[SET2EN] -Ajuste 2. Activado - -[SET2] -Ajuste 2 - -[SET3EN] -Ajuste 3. Activado - -[SET3] -Ajuste 3 - -[SET4EN] -Ajuste 4. Activado - -[SET4] -Ajuste 4 - -[GOBACK] -Volver - -[SOUND] -SONIDO - -[MUSVOL] -Volumen de la Música - -[SFXVOL] -Volumen de los Efectos Especiales - -[SCROPT] -OPCIONES DE PANTALLA - -[CTRSCR] -Centrar Pantalla - -[SCRFOR] -Formato de Pantalla - -[GMSVLQ] -JUEGO GUARDAR-CARGAR-SALIR - -[GMREST] -Reiniciar Juego - -[GMLOAD] -Cargar Juego - -[NOGMSV] -Sólo puedes guardar desde tu escondite. - -[DLFILE] -Borrar Archivos de Grand Theft Auto III - -[CHFILE] -ELEGIR ARCHIVO A CARGAR - -[CHCDLD] -Elegir Tarjeta desde la que Cargar - -[CDUNFR] -Tarjeta sin formato. - -[CHFIDL] -ELIGE UN ARCHIVO A BORRAR - -[SVCONF] -CONFIRMACIÓN DE GURDAR - -[SVFNAM] -El nombre de tu archivo guardado es - -[SAVEDN] -Error. Fallo al guardar. - -[LANGSL] -SELECCIÓN DEL IDIOMA - -[ENGLIS] -Inglés - -[GERMAN] -Alemán - -[ITALIA] -Italiano - -[FRENCH] -Francés - -[SPAIN] -Español - -[RELIDE] -ReLoadIde - -[RELIPE] -ReLoadIpl - -[PARSHP] -Analizar Pila - -[DBGFON] -Activado CTheScripts::DbgFlag - -[DBFOFF] -Desactivado CTheScripts::DbgFlag - -[BGWHON] -Activada Luz Blanca Grande de Depuración - -[BGWOFF] -Desactivada Luz Blanca Grande de Depuración - -[DSTRON] -Activadas Solicitudes de Depuración de Streaming - -[DSTROFF] -Desactivadas Solicitudes de Depuración de Streaming - -[PDRGON] -Activado ShowPedRoadGroups - -[PRGOFF] -Desactivado ShowPedRoadGroups - -[CRRGON] -Activado ShowCarRoadGroups - -[CRGOFF] -Desactivado ShowCarRoadGroups - -[CLZOON] -Activado Mostrar Zonas a escoger - -[CLZOOF] -Desactivado Mostrar Zonas a escoger - -[SHPLON] -gbShowCollisionPolys Sí - -[SHPLOF] -gbShowCollisionPolys No - -[CULREC] -CCullZones::RecalculateCullZoneData() - -[FORMM1] -FormatMemCard 1 (materialprueba) - -[UNFRM1] -UnFormatMemCard 1 (materialprueba) - -[GORLEV] -Nivel Gore - -[SICASS] -Joder de mala manera - -[SICSIC] -Cabrón fastidioso - -[SCASSL] -Seleccionado Joder de mala manera - -[SCSCSL] -Seleccionado Cabrón fastidioso - -[PRVMEN] -Informes de Misiones Previas - -[DOSVGM] -¿Deseas guardar el juego? - -[FORMEN] -Menú de Formato - -[MEMTST] -Pantalla MemoryCardTest - -[REGCAR] -Registrar MemoryCard Uno - -[TEFONE] -Probar Formato de MemCard Uno - -[TEUFON] -Probar MemCard Uno sin formato - -[CRROOT] -CreateRootDir - -[CRLDIC] -Crear y Cargar Iconos - -[FLFSGF] -Llenar Primer Archivo Con Necedades - -[PUSAVE] -Guardar Sólo el juego - -[CHEVOK] -CheckEveryOkB4Save - -[SVGMON] -SaveTheGame - -[CNTSAV] -No se puede guardar el juego. En una misión. - -[CNCSAV] -No se puede guardar el juego. Estás en un coche - -[CRMGSV] -Crear directorio de revista con protección de copia - -[MGSVNC] -No Creado MagazineDirectory - -[MGSVCN] -Creado MagazineDirectory - -[YES] -Sí - -[NO] -No - -[X] -x - -[LAST] -Último Mensaje - -[FEDS_XB] -Seleccionar - -[FEDS_ST] -Botón START - CONTINUAR - -[FEST_OO] -de - -[FEC_TUC] -Control de Torreón - -[FEC_SM3] -Activador de Misión Espacial (botón R3) - -[FEC_RS3] -Cambiar de emisora de Radio (botón L3) - -[FEC_HO3] -Bocina (botón L3) - -[DIAB1] -'TURISMO' - -[DIAB2] -'YO GRITO, TU GRITAS' - -[DIAB3] -'JUICIO POR FUEGO' - -[DIAB4] -'GRANDE Y VENOSO' - -[DIAB1_A] -El burro quiere ofrecerte una oportunidad. Ve al teléfono público de Hepburn Heights si quieres más información. - -[DIAB1_C] -Participas en una carrera desagradable. Pásate por el teléfono público de nuevo y puede que 'El Burro' tenga algo de trabajo para ti. - -[DIAB1_1] -~g~3...2...1... ¡VAMOS VAMOS VAMOS! - -[DIAB1_4] -~g~Hazte con un coche rápido y ve a la cuadrícula de inicio. - -[DIAB1_3] -~r~No podrías ganar ni una rifa, ¡FRACASADO! - -[DIAB1_2] -~g~Felicidades, ganaste con un tiempo increíble de ~1~ segundo. - -[FIRST] -~g~ Primero (or ~g~1o) - -[SECOND] -~g~ Segundo (or ~g~2o) - -[THIRD] -~g~ Tercero (or ~g~3o) - -[FOURTH] -~g~ Cuarto (or ~g~4o) - -[DIAB2_1] -~g~ Recoge el maletín en Harwood. - -[DIAB2_2] -~g~ Encuentra una furgoneta de helados. - -[DIAB2_3] -~g~ Aparca la furgoneta de helados en Atlantic Quays. - -[DIAB2_4] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. - -[DIAB2_6] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. - -[DIAB2_7] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. - -[DIAB2_5] -~g~ Sal de la furgoneta y luego usa el mando a distancia para detonar la furgoneta del helado. - -[YD1] -'PELEA BLING-BLING' - -[YD2] -'JINETE CON UZI' - -[YD3] -'REUNIÓN DE COCHES DE GANGSTERS' - -[YD4] -'LLEGÓ EL REINADO' - -[YD_P] -El Rey Courtney quiere hablarte. ¡¡Ve al teléfono público de Aspatria!! - -[YD1_A] -~w~Este es el Rey Courtney - -[YD1_A1] -~w~Mi banda Yardie necesita un conductor y tú tienes reputación de ser hábil al volante. - -[YD1_B] -~w~Ve al basurero que hay detrás del estadio y en un coche espera a los otros candidatos. - -[YD1_C] -~w~Tengo hombres vigilando los puestos de control en todo Staunton. - -[YD1_D] -~w~El primer conductor que llegue a un puesto de control se lleva un billete de los grandes, luego hay que ir a la siguiente parada. - -[YD1_D1] -~w~Si ganas más puestos de control que cualquier otro conductor, podría tener algo de trabajo para ti. - -[YD1_E] -~g~Preparado para una carrera! - -[YD1_F] -~g~Te saltaste el comienzo -¡Me gusta tu estilo!! - -[YD1_G] -~r~Esto es una CARRERA DE COCHES. ¡Necesitas un COCHE, idiota! - -[YD1GO] -~g~VAMOS!! - -[YD1_1] -~r~1 - -[YD1_2] -~r~2 - -[YD1_3] -~r~3 - -[YD1_BON] -¡¡1.000$!! - -[Y1_1ST] -~G~¡Llegaste el primero con ~1~ exitosos puestos de control! - -[Y1_2ND] -~y~Segundo con ~1~ exitosos puestos de control. ~y~Cerca, pero ¡no eres el mejor! - -[Y1_3RD] -~r~Tercero con ~1~ exitosos puestos de control. ~r~¡Creí que dijiste que eras bueno! - -[Y1_LAST] -~r~¡Fuiste el último! ~r~¡Malgastaste mi tiempo, IDIOTA! - -[Y1_J1ST] -~y~Empatado el primero con ~1~ exitosos puestos de control. ~y~Bien, pero ¡debes ser el mejor si quieres conducir para la Reina Lizzy! - -[Y1_J2ND] -~r~Empatado el segundo con ~1~ exitosos puestos de control. ¡Conduces como un mono loco! - -[Y1JLAST] -~r~¡Empatado el último! Hablas como un conductor, pero conduces como un hablador! - -[Y1_TEST] -COCHE AL AGUA!! - -[YD2_A] -~w~Necesito ver si eres capaz de hacer mi trabajo sucio. - -[YD2_A1] -~w~A ver si se puede confiar en ti. - -[YD2_B] -~w~Dos de mis chicos estarán allí en cualquier momento para llevarte de paseo, - -[YD2_B1] -~w~a ver si eres quien dices que eres. - -[YD2_C] -~w~Nos vamos a dar un pequeño paseo a Hepburn Heights, acabaremos con los asquerosos Diablos que han estado metiéndose con la Reina Lizzy. - -[YD2_CC] -~w~Toma, necesitaras una 'pieza' - -[YD2_D] -~w~Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te entren dudas. - -[YD2_E] -~w~¡Vamos a conducir! - -[YD2_F] -~r~Ha obtenido la libertad bajo fianza con nuestra pasta, ¡dispara a su culo amarillo!!! - -[YD2_G1] -~w~Hepburn Heights... Vamos a matar algunos asquerosos Diablos... - -[YD2_G2] -~w~Pero recuerda, ~r~¡No salgas de este coche!! - -[YD2_H] -~w~VALE, Llévanos de vuelta a territorio Yardie! VAMOS VAMOS VAMOS!!! - -[YD2_L] -~w~¡Lo hiciste bien, Reaperman! - -[YD2_M] -~r~¡Ha destrozado mi coche! ¡Liquidale! - -[YD2_N] -~w~¡Vuelve a poner tu culo en este coche! - -[YD3_A] -Quiero que empujes algunos coches de gangsters - -[YD3_A1] -para que podamos dar el golpe en territorio enemigo. - -[YD3_B] -Necesito un Mafia Sentinel, - -[YD3_B1] -un Yakuza Stinger y un - -[YD3_B2] -Diablo Stallion para poder dar a cualquier gangster de Liberty. - -[YD3_C] -Déjales en el garaje de Newport y recuerda, - -[YD3_C1] -¡¡aniquilados no nos son de utilidad !! - -[YD3_D] -Nivel de texto sobrante - -[YD3_E] -~r~¡Ya le has dado a un coche de gangsters, diablo! - -[YD3_F] -~r~¡Ya le has dado a un coche de gangsters Mafia! - -[YD3_G] -~r~¡Ya le has dado a un coche de gangsters Yakuza! - -[YD3_H] -~g~¡Coche de gangsters Diablo empujado! - -[YD3_I] -~g~¡Coche de gangsters Mafia empujado! - -[YD3_J] -~g~¡Coche de gangsters Yakuza empujado! - -[YD3_K] -~r~¡El coche está casi destrozado!¡Haz que lo reparen! - -[YD3_L] -~g~¡Llevalo al ~p~ garaje! - -[YD3_M] -~r~¡Lo volcaste! ¡Consigue otro! - -[YD4_A] -¡Escucha! - -[YD4_A1] -Pásate por Bedford Point. - -[YD4_A2] -¡Hay un cargamento en un viejo coche y lo necesito pronto! - -[YD4_B] -CARTA: He oído que has sido un chico aplicado. Bien, yo he sido una chica aplicada. - -[YD4_C] -Creo que es hora de que seas testigo del poder real del ¡'SPANK'! Besos y abrazos, Catalina, xxx - -[YD4_D] -POSDATA: ¡¡MUERE PEEG DOG, MUERE!! - -[YD4_1] -¡¡Te hemos pellado necio!! - -[YD4_2] -¡¡Destruye las furgonetas de SPANK - -[HM_1] -'DINERO UZI' - -[HM_2] -'TOYMINATOR' - -[HM_3] -'PREPARADO PARA ESTALLAR' - -[HM_5] -'REDOBLE' - -[HOOD1_A] -Ve al teléfono público de Wichita Gardens y hablaremos de negocios. - -[HM1_A] -¡Tío, Soy D-Ice de los Red Jacks! - -[HM1_C] -Esos jovenes macarras, salen a la calle y no tienen nada más que pistolas y SPANK en sus cabezas. - -[HM1_3] -~g~Los 'Nines' tienen su territorio en Wichita Gardens. - -[HM2_3] -Si golpeas las ruedas de un vehículo el RC buggy ¡se detonará! - -[HM2_4] -Si se sale fuera de cobertura el RC buggy ¡se detonará! - -[HM2_5] -~r~¡Fuera de cobertura! - -[HM3_1] -~g~Ve al garaje pero pon atención porque si el coche se daña demasiado ¡explotará! - -[HM3_2] -~g~Lleva el coche de vuelta, tiene que estar en perfectas condiciones ¡sin daños! - -[HM3_3] -~g~¡Haz que reparen el coche! - -[HM4_D] -~g~¡Hazte con un vehículo! - -[HM4_E] -NO MAS TEXTO REQUERIDO - -[HM4_1] -~g~Dirígete al lugar donde el cargamento ha sido esparcido, necesitas conseguir 30 lingotes de oro. - -[HM4_2] -~g~Recuerda, cuando el vehículo es demasiado pesado y lento ve al garaje y deja el cargamento. - -[HM5_3] -~r~¡Te han dicho que uses sólo un bate de béisbol! - -[HM5_4] -~r~¡Tu contacto está muerto! - -[MEA1] -'EL CRIMINAL' - -[MEA2] -'LOS LADRONES' - -[MEA3] -'LA MUJER' - -[MEA4] -'SU AMANTE' - -[MEAT1_A] -Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléfono público de Trento si crees que puedes ayudar. - -[MEA1_B3] -~g~Ve y reúnete con el Director del Banco. - -[MEA1_B6] -~g~Lleva el coche a la trituradora para eliminar las evidencias, sal del coche y la grúa lo recogerá. - -[MEA1_1] -~r~¡El director del banco está muerto! - -[MEA1_2] -~r~¡Te dijeron que trituraras el coche! - -[MEA1_3] -~g~¡Sal del coche! - -[MEA1_4] -~r~Has dejado atrás al director del banco! - -[MEA2_B3] -~g~Ve a encontrarte con los ladrones. - -[MEA2_B4] -~g~Llévalos a la fábrica de comestibles Bitch'n'Dog - -[MEA2_B6] -~g~Haz que repinten el coche para eliminar cualquier evidencia. - -[MEA2_1] -~r~¡Te dijeron que trituraras el vehículo! - -[MEA2_2] -~r~¡Un ladrón ha muerto! - -[MEA2_4] -~r~¡Has dejado atrás a un ladrón! - -[MEA3_B3] -~g~Ve y recoge a la Sra. Chonks - -[MEA3_B6] -~g~Llévate el coche y tíralo al mar, así eliminaremos cualquier evidencia. - -[MEA3_1] -~r~¡La mujer está muerta! - -[MEA3_2] -~r~¡Se suponía que ibas a tirar el vehículo al agua! - -[MEA3_3] -~r~¡Has dejado atrás a su mujer! - -[MEA4_B3] -~g~Recoge al amante de su mujer. - -[MEA4_B6] -Es demasiado tarde para eso, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé del negocio... - -[MEA4_1] -~r~¡Carlos está muerto! - -[MEA4_3] -~r~¡Has dejado atrás a Carlos el prestamista! - -[LOOK_A] -Pulsa y mantén pulsado el ~h~botón ~k~~VEHICLE_LOOKLEFT~~w~ o el ~h~botón ~k~~VEHICLE_LOOKRIGHT~~w~ para mirar ~h~ a la izquierda ~w~ o ~h~ a la derecha ~w~ mientras te encuentres en un vehículo. Pulsa ambos para mirar ~h~ atrás ~w~. - -[LOVE6_1] -~g~¡Ahora llévate a los policías lejos del almacén! - -[LOVE6_2] -~r~¡No conseguiste llevar lejos a la policía! - -[RM4_3] -¡El socio de Ray ha escapado! - -[RM6_C] -La CIA parece tener intereses creados con el SPANK - -[RM6_C1] -y a ellos no les gusta que nos metamos con el Cartel. - -[C_PASS] -¡AMENAZA ELIMINADA! - -[CTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilante. - -[CTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilante. - -[COPCART] -~g~Tienes ~1~ segundos para retornar a un vehículo de la policía antes de que termine la misión. - -[C_FAIL] -¡Misión Vigilante terminada! - -[C_CANC] -~r~¡Misión Vigilante cancelada! - -[C_ESCP] -~r~¡El sospechoso ha escapado! - -[C_TIME] -~r~¡Tu trabajo como defensor de la ley ha terminado! - -[C_VIGIL] -¡¡BONO VIGILANTE!! - -[A_FAIL2] -~r~¡Tu falta de urgencia ha sido fatal para el paciente! - -[A_FAIL3] -~r~¡¡El paciente está muerto!! - -[A_PASS] -¡Rescatado! - -[F_FAIL2] -~r~¡Llegas demasiado tarde! - -[A_COMP2] -¡Nunca te cansarás! - -[RM2_M] -Si necesitas un poco de pólvora pasa por aquí y coge lo que necesites de las taquillas. - -[HEAL_A] -Tu ~h~salud ~w~ está marcada en naraja en la parte superior derecha de la pantalla. - -[YD1_CNT] -¡~1~ de 15! - -[FM1_9] -~g~Esa de allí es la fiesta, deja a María enfrente. - -[FM1_Y] -~w~Quiero que sepas que me lo he pasado muy bien por primera vez en mucho tiempo, y que me has tratado muy bien. Con respeto y todo eso. - -[FM1_AA] -~w~Oh, será mejor que me vaya. Espero que nos veamos pronto. - -[NOCONTE] -Por favor vuelve a conectar el mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) al puerto de mando 1 para continuar. - -[WRCONT] -El mando conectado al puerto de mando 1 es un mando no soportado. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). - -[WRCONTE] -El mando conectado al puerto de mando 1 es un mando no soportado. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). - -[WRONGCD] -Disco incorrecto. Por favor inserta el disco correcto. - -[NOCD] -La bandeja del disco está vacía. Por favor inserta un disco. - -[OPENCD] -La bandeja del disco está abierta. Por favor ciera la bandeja de disco. - -[CDERROR] -Error al leer el DVD de Grand Theft Auto III - -[RESTART] -Empezando una juego nuevo - -[GA_3] -¡No hay más freebies. 1000$ para repintar! - -[GA_1] -¡Uauhh! ¡No toco nada TAN caliente! - -[GA_1A] -Regresa cuando no estés tan ocupado... - -[S_PROM2] -El garaje de al lado puede alojar un vehículo cuando tú guardas tu partida. - -[STOCK] -mercancía agotada - -[FM1_O] -~w~Creo que está en la estación de ferrocarril del muelle de Chinatown. - -[EBAL_B] -Este es el lugar, justo aquí, dejemos la calle y ¡encontremos un cambio de ropas! - -[EBAL_G] -Este es el club de Luigi. Vamos por la parte de atrás y usemos la puerta de servicio. - -[AM4_3] -¡Tú debes de ser el nuevo chico de los recados de Asuka! - -[AM4_4] -¿Tienes el dinero? ¿Está todo aquí? - -[AM4_5] -Ya sé lo que estás pensando, otro policía corrupto. - -[AM4_6] -Bueno, éste es un mundo corrupto. - -[AM4_7] -Sólo porque perdí un par de socios, esos mamones de asuntos internos han empezado a meter las narices. - -[AM4_8] -Cuento con que pueden pillarme. - -[AM4_9] -Bien, esta ciudad es una gran alcantarilla. - -[AM4_10] -Pero voy a necesitar un poco de ayuda fuera del sindicato. - -[AM4_11] -Y si estás interesado ya sabes dónde encontrarme. - -[CAM_A] -Pulsa el ~h~botón ~k~~CAMERA_CHANGE_VIEW_ALL_SITUATIONS~~w~ para cambiar ~h~cámara ~w~ modos cuando vayas a pié o estés en un vehículo. - -[CAM_B] -Pulsa el ~h~botón de dirección hacia arriba ~w~ y ~h~ abajo ~w~ para cambiar los modos de ~h~cámara ~w~cuando vayas a pié o estés en un vehículo. - -[KM2_1] -~g~Repara el coche, tiene que estar en perfecto estado. - -[LM3_6] -Joey... - -[LM3_6A] -¿Voy a jugar contigo otra vez? - -[LM3_9A] -debe de haber algo de trabajo para ti. - -[LM3_9B] -¿De acuerdo? - -[AWAY2] -~r~Se escaparon. - -[AWAY] -~r~¡Se ha pirado de aquí! - -[JM6_1] -Ve al banco de la avenida principal. - -[GA_6B] -Aparca, selecciónalo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y ¡ADELANTE! - -[GA_7B] -Armar con ~h~botón ~k~~PED_FIREWEAPON~~w~. La bomba explotará cuando el motor sea arrancado. - -[BAT1] -~g~¡Coge el bate! - -[EBAL_O] -Si no estropeas esto, puede que haya más trabajo para ti. Ahora ¡vete de aquí! - -[HELP9_B] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~ el rifle del francotirador. - -[HELP9_C] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ disparar ~w~ el rifle del francotirador. - -[JM6_8] -~r~¡Has perdido a todos los ladrones! - -[COLT_IN] -¡La pistola está ahora en el almacén de Munición! - -[TAXI2] -~r~¡Se te acabó el tiempo! - -[TAXI3] -~r~¡Tu pasajero se marchó aterrorizado! - -[TAXI7] -~r~Tu coche está destrozado, haz que lo reparen. - -[TAXI4] -¡Tarifa completa! - -[TAXI5] -¡¡DE VELOCIDAD!! - -[TAXI6] -Misión de taxi terminada - -[FRANGO] -~g~¡Salvatore quiere que ayudes a Toni a tratar con los Triad primero! - -[PAGEB12] -Policía Bribe entregado en el escondite - -[PAGEB13] -Salud entregada en el escondite - -[PAGEB14] -Adrenalina entregada en el escondite - -[KM1_4] -~g~¡Necesitas un coche de policía para hacer el trabajo! - -[CAT1_B] -trae 500.000 a la Villa en Cedar Grove. - -[JM2_C] -Tiene un puesto de fideos en China Town. - -[RM6_1] -Aquí está la llave de la cerradura. - -[RM6_2] -Encontrarás algo de dinero en metálico y 'suministros' que he almacenado en caso de que las cosas se pongan feas. - -[RM6_3] -Nos vemos pronto. - -[FE_INIP] -Iniciando y cargando el Menú de Pausa... Por favor espera. - -[FESZ_CA] -Cancelar - -[FESZ_QU] -Abandonar - -[FESZ_L1] -¡Partida guardada con éxito! - -[FESZ_L2] -Tu nombre guardado es: - -[FESZ_OK] -ACEPTAR - -[FES_NGA] -Partida nueva - -[FES_CAN] -Cancelar - -[FESZ_QL] -Todo progreso en tu partida actual no guardado será perdido. ¿Proceder con la carga? - -[FESZ_QD] -¿Quieres borrar esta partida guardada? - -[FESZ_QO] -¿Quieres sobreescribir este partida guardado? - -[FESZ_QR] -¿Estás seguro de que quieres empezar una nueva partida? Todo progreso desde la última partida guardada será perdido. ¿Proceder? - -[FESZ_QS] -¿QUIERES GUARDAR? - -[SLONFP] -Puerto 1. Archivo protegido. - -[T4X4_1] -'LUGAR DE JUEGOS DEL PATRIOTA' - -[T4X4_2] -'UN PASEO POR EL PARQUE' - -[T4X4_3] -'AGARRADO!' - -[MM_1] -'DISTURBIO DE DIFERENTES NIVELES' - -[T4X4_1A] -~g~Tienes ~y~5 minutos ~g~ para conseguir ~y~ 15~g~ puestos de control. ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN - -[T4X4_1B] -¡~1~ de 15! - -[T4X4_1C] -~y~PASA A TRAVES ~g~ del primer puesto de control para que comience el cronómetro. ~g~Cada puesto de control te acreditará con ~y~20 SEGUNDOS ~g~. - -[T4X4_2A] -¡¡~g~Tienes ~y~2 minutos ~g~ para conseguir ~y~12~g~ puestos de control!! ~g~Puedes conseguirlos en ~y~ CUALQUIER ORDEN. - -[T4X4_2B] -¡~1~ de 12! - -[T4X4_2C] -~y~PASA A TRAVÉS ~g~ del primer puesto de control para que comience el cronómetro. ~g~Cada puesto de control te premiará con ~y~10 SEGUNDOS~g~ - -[T4X4_3A] -~g~Tienes ~y~5 minutos ~g~ para conseguir ~y~20~g~ puestos de control. ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN. - -[T4X4_3B] -~Y~PASA A TRAVES ~g~ del primer puesto de control para que comience el cronómetro. ~g~Cada puesto de control te premiará con ~y~15 SEGUNDOS ~g~. - -[T4X4_3C] -¡~1~ de 20! - -[T4X4_F] -¡~r~Saliste bajo fianza! ¿Demasiado duro para ti? - -[MM_1_A] -¡~g~Tienes ~y~2 minutos ~g~ para conseguir ~y~20 puestos de control ~g~ en el multiniveles! ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN. - -[MM_1_B] -¡~1~ de 20! - -[MM_1_C] -~g~Eso son 20 segundos, más ~y~5 SEGUNDOS ~g~ por cada puesto de control. ~g~El cornómetro comenzará ~y~ INMEDIATAMENTE. - -[FM2_14] -~r~¡Estuviste muy cerca y asustaste a Curly! - -[FM2_15] -~g~No te acerques demasiado o Curly ¡sospechará algo! - -[UPSIDE] -~r~¡Giraste las ruedas! - -[FM2_16] -ASUSTOMETRO: - -[LM3_11] -~g~Misty no irá en el autobús,¡hazte con otro vehículo! - -[LANDSTK] -Landstalker - -[IDAHO] -Idaho - -[STINGER] -Stinger - -[LINERUN] -Linerunner - -[PEREN] -Perennial - -[SENTINL] -Sentinel - -[PATRIOT] -Patriot - -[FIRETRK] -Coche de bomberos - -[TRASHM] -Trashmaster - -[STRETCH] -Stretch - -[MANANA] -Manana - -[INFERNS] -Infernus - -[BLISTA] -Blista - -[PONY] -Pony - -[MULE] -Mule - -[CHEETAH] -Cheetah - -[AMBULAN] -Ambulancia - -[FBICAR] -F.B.I. - -[MOONBM] -Moonbeam - -[ESPERAN] -Esperanto - -[TAXI] -Taxi - -[KURUMA] -Kuruma - -[BOBCAT] -Bobcat - -[WHOOPEE] -Mr Whoopee - -[BFINJC] -Inyección BF - -[POLICAR] -Policía - -[ENFORCR] -Enforcer - -[SECURI] -Securicar - -[BANSHEE] -Banshee - -[PREDATR] -Predator - -[BUS] -Bus - -[RHINO] -Rhino - -[BARRCKS] -Barracas OL - -[TRAIN] -Tren - -[HELI] -Helicóptero - -[DODO] -Dodo - -[COACH] -Coach - -[CABBIE] -Cabbie - -[STALION] -Stallion - -[RUMPO] -Rumpo - -[RCBANDT] -Bandido RC - -[BELLYUP] -Triad - -[MRWONGS] -Mr Wongs - -[MAFIACR] -Mafia - -[YARDICR] -Yardie - -[YAKUZCR] -Yakuza - -[DIABLCR] -Diablo - -[COLOMCR] -Cartel - -[HOODSCR] -Hoods - -[AEROPL] -Avioneta - -[SPEEDER] -Veloz - -[REEFER] -Chaquetón - -[PANLANT] -Panlantic - -[FLATBED] -Flatbed - -[YANKEE] -Yankee - -[BORGNIN] -Borgnine - -[TOYZ] -TOYZ - -[FEST_DF] -Distancia recorrida a pié (millas) - -[FEST_DC] -Distancia recorrida en coche (millas) - -[FESTDFM] -Distancia recorrida a pié (m) - -[FESTDCM] -Distancia recorrida en coche (m) - -[FEST_R1] -Área de juego Patriota en segundos - -[FEST_R2] -Un paseo por el Parque en segundos - -[FEST_R3] -¡Agarrado! en segundos - -[FEST_RM] -Disturbio en el multiniveles en segundos - -[FEST_LS] -Gente salvada en una ambulancia - -[FEST_CC] -Criminales matados en Misión Vigilante - -[FEST_FE] -Total de fuegos extinguidos - -[FEST_LF] -Vuelo más largo en Dodo - -[FEST_BD] -Mejor idoneo para desconectar la bomba - -[FEST_RP] -Rampas pasadas - -[FEST_MP] -Misiones pasada - -[FEST_BB] -Pelea bling-bling: - -[FEST_H0] -Máximos puestos de control - -[FEST_GC] -Total de Coches de gangsters: - -[FEST_H1] -Destrucción Diablo - -[FEST_H2] -Masacre de Mafia - -[FEST_H3] -Calamidad en el Casino - -[FEST_H4] -Destructor Rumpo - -[USJI1] -TEXTO NO MAS REQUERIDO - -[USJI2] -TEXTO NO MAS REQUERIDO - -[USJI3] -TEXTO NO MAS REQUERIDO - -[USJ] -¡BONO DE ACROBACIA UNICA! - -[SPRAY] -Conduce tu vehículo a la tienda de pintura para perder tu ~h~nivel de buscado~w~, ~h~reparar ~w~ y ~h~ repintar ~w~ tu vehículo. Coste - ~h~1.000$ - -[HM1_1] -~g~Congela 20 Purpura Nines en 2 minutos 30 segundos. - -[KM1_8A] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ activar la bomba, ~w~ recuerda apartarte del camino. - -[KM1_8D] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ activar la bomba, ~w~ recuerda apártarte del camino. - -[KM1_12] -~g~¡Llévalo al dojo pero deshazte primero de los policías! - -[RATNG1] -Carterista - -[RATNG2] -Querido - -[RATNG3] -Ladrón - -[RATNG4] -Chorizo - -[RATNG5] -Goon - -[RATNG6] -Hombre sobre ruedas - -[RATNG7] -Músculos de alquiler - -[RATNG8] -Reparador - -[RATNG9] -Asociado - -[RATNG10] -Limpiador - -[RATNG11] -Asesino - -[RATNG12] -Hombre diestro - -[RATNG13] -Ejecutor - -[RATNG14] -Capo - -[RATNG15] -Jefe - -[1010] -~r~Tu vehículo está volcado - -[1011] -~r~Tu vehículo está volcado - -[1012] -~r~Tu vehículo está volcado - -[1013] -~r~Tu vehículo está volcado - -[1014] -~r~Tu vehículo está volcado - -[JM4_10] -VALE, Chaval. Llévame a la lavandería de Chinatown primero, tengo un negocio del que ocuparme. - -[JM4_11] -Esas mujeres que lavan no están recibiendo su dinero de protección. - -[JM4_12] -Y vigila el coche, Joey acaba de arreglar ese montón de basura - -[JM4_13] -Entonces no me vengas con cuentos, ¿VALE? - -[KM4_11] -~g~¡Llévate el dinero de vuelta al casino! - -[FEF_BR2] -Encuéntralo de nuevo leyendo cualquier informe de misión conseguido hasta la fecha. +Shoreside Vale [TRAIN_1] Estación Kurowski @@ -4190,340 +695,4720 @@ Estación Portland Estación Rockford [SUBWAY3] -Estación Staunton South +Estación Staunton sur [SUBWAY4] Terminal Shoreside -[MEA4_2] -~r~¡Marty Chonks está muerta! +{ ================================================= } +{ ================= VEHICLE NAMES ================= } +{ ================================================= } -[SPRAY1] -Lleva tu vehículo a la tienda de pintura para perder tu ~h~nivel de buscado~w~, ~h~reparar~w~y ~h~repintar ~w~tu vehículo. Coste - ~h~ 1.000$ ~w~. Esta vez es gratis. +[CAR_1] +Ambulancia -[JM4_A] -Sí, lo sé Toni, la he puesto a tono. Ella está a punto, ¿sabes lo que de digo? +[AMBULAN] +Ambulancia -[JM4_5] -Pasa más tarde y les daremos algo para que lave, ¡sus propias ropas manchadas de sangre! +[CAR_2] +Camión de bomberos + +[FIRETRK] +Camión de bomberos + +[CAR_3] +Coche patrulla + +[POLICAR] +Coche patrulla + +[CAR_4] +Enforcer + +[ENFORCR] +Enforcer + +[CAR_5] +Barracks + +[BARRCKS] +Barracks OL + +[CAR_6] +Rhino + +[RHINO] +Rhino + +[CAR_7] +Coche del FBI + +[FBICAR] +Coche del FBI + +[CAR_8] +Securicar + +[SECURI] +Securicar + +[CAR_9] +Moonbeam + +[MOONBM] +Moonbeam + +[CAR_10] +Coach + +[COACH] +Coach + +[CAR_11] +Flatbed + +[FLATBED] +Flatbed + +[CAR_12] +Linerunner + +[LINERUN] +Linerunner + +[CAR_13] +Trashmaster + +[TRASHM] +Trashmaster + +[CAR_14] +Patriot + +[PATRIOT] +Patriot + +[CAR_15] +Mr. Whoopee + +[WHOOPEE] +Mr. Whoopee + +[CAR_16] +Mule + +[MULE] +Mule + +[CAR_17] +Yankee + +[YANKEE] +Yankee + +[CAR_18] +Pony + +[PONY] +Pony + +[CAR_19] +Bobcat + +[BOBCAT] +Bobcat + +[CAR_20] +Rumpo + +[RUMPO] +Rumpo + +[CAR_21] +Blista + +[BLISTA] +Blista + +[CAR_22] +Dodo + +[DODO] +Dodo + +[CAR_23] +Autobús + +[BUS] +Autobús + +[CAR_24] +Sentinel + +[SENTINL] +Sentinel + +[CAR_25] +Cheetah + +[CHEETAH] +Cheetah + +[CAR_26] +Banshee + +[BANSHEE] +Banshee + +[CAR_27] +Stinger + +[STINGER] +Stinger + +[CAR_28] +Infernus + +[INFERNS] +Infernus + +[CAR_29] +Esperanto + +[ESPERAN] +Esperanto + +[CAR_30] +Kuruma + +[KURUMA] +Kuruma + +[CAR_31] +Stretch + +[STRETCH] +Stretch + +[CAR_32] +Perennial + +[PEREN] +Perennial + +[CAR_33] +Landstalker + +[LANDSTK] +Landstalker + +[CAR_34] +Mañana + +[MANANA] +Mañana + +[CAR_35] +Idaho + +[IDAHO] +Idaho + +[CAR_36] +Stallion + +[STALION] +Stallion + +[CAR_37] +Taxi + +[TAXI] +Taxi + +[CAR_38] +Cabbie + +[CABBIE] +Cabbie + +[CAR_39] +Buggy + +[BFINJC] +BF Injection + +[PREDATR] +Predator + +[TRAIN] +Tren + +[HELI] +Helicóptero + +[RCBANDT] +Bandit RC + +[BELLYUP] +Furgoneta de las Tríadas + +[MRWONGS] +Mr Wongs + +[MAFIACR] +Sentinel de la mafia + +[YARDICR] +Lobo jamaicano + +[YAKUZCR] +Stinger de la yakuza + +[DIABLCR] +Stallion de los Diablos + +[COLOMCR] +Cruiser del cártel + +[HOODSCR] +Rumpo XL de los hood + +[AEROPL] +Avioneta + +[SPEEDER] +Speeder + +[REEFER] +Reefer + +[PANLANT] +Panlantic + +[BORGNIN] +Borgnine + +[TOYZ] +TOYZ + +{ ======================================================= } +{ ================= RADIO STATION NAMES ================= } +{ ======================================================= } + +[FEA_FM0] +HEAD RADIO + +[HEAD] +Head Radio + +[FEA_FM1] +DOUBLE CLEF FM + +[DBL_CLF] +Double Clef FM + +[FEA_FM2] +K-JAH RADIO + +[K_JAH] +K-Jah Radio + +[FEA_FM3] +RISE FM + +[RISE] +Rise FM + +[FEA_FM4] +LIPS 106 + +[LIPS] +Lips 106 + +[FEA_FM5] +GAME FM + +[GAM_FM] +Game Radio FM + +[FEA_FM6] +MSX FM + +[MSX_FM] +MSX FM + +[FEA_FM7] +FLASHBACK 95.6 + +[FLASHB] +Flashback 95.6 + +[FEA_FM8] +CHATTERBOX FM + +[CHAT] +Chatterbox FM + +{ ============================================================================================================== } +{ ================= STRINGS RELATED TO GARAGES (BOMB SHOP, SPRAY SHOP, IMPORT/EXPORT, CRUSHER) ================= } +{ ============================================================================================================== } + +[GA_1] +¡Hala! ¡Demasiado peligroso para mi gusto! + +[GA_1A] +Vuelve cuando no estés tan ocupado... + +[GA_2] +He cambiado el motor y la mano de pintura. ¡La poli no te reconocerá! + +[GA_3] +¡Ya no es gratis! ¡La mano de pintura son 1.000 dólares! + +[GA_4] +Una bomba de coche vale 1.000 dólares. + +[GA_5] +Tu coche ya tiene una bomba instalada. + +[GA_6] +Apárcalo, prepáralo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! + +[GA_6B] +¡Apárcalo, prepáralo tocando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! + +[GA_7] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. + +[GA_7B] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. + +[GA_8] +Utiliza el detonador para activar la bomba. + +[GA_9] +Ha conseguido ~1~ de los 10 coches especiales. + +[GA_10] +Buen trabajo. Aquí tienes tus ~1~ dólares. + +[GA_11] +Ya tenemos este modelo. ¡No nos sirve para nada! + +[GA_12] +Bomba armada + +[GA_13] +Eres todo un profesional. Completa la lista y conseguirás una recompensa. + +[GA_14] +Ya están todos los coches. ¡Estupendo! Toma un detallito. + +[GA_15] +Espero que te guste el nuevo color. + +[GA_16] +Esta mano de pintura es gratuita. + +[GA_19] +No nos interesa ese modelo. + +[GA_20] +Tenemos de esos más de los que necesitamos. Lo siento, tío, no hay trato. + +[GA_21] +No puedes guardar más coches en este garaje. + +[CR_1] +La grúa no puede levantar este vehículo. + +{ ============================================================================================ } +{ ================= MESSAGES TO INDICATE THAT MISSIONS ARE NOT YET AVAILABLE ================= } +{ ============================================================================================ } + +[GOAWAY] +~g~¡Ya estás en una misión! + +[LUIGGO] +~g~Luigi está entrevistando a unas chicas nuevas... ¡Vuelve más tarde! + +[JOEYGO] +~g~Joey ha salido con Misty. ¡Pásate más tarde! + +[TONIGO] +~g~Toni ha llevado a su mamá a la ópera... ¡Llama en otro momento! + +[KEMUGO] +~g~María y Kemuri están muy liadas... ¡Pásate más tarde! + +[KENJGO] +~g~Kenji está reunido con la yakuza, ¡llama en otro momento! + +[RAYGO] +~g~Ray tiene otros baños por los que rondar, ¡ven en otro momento! + +[LOVEGO] +~g~Donald Love tiene otros asuntos que atender. ¡Pide una cita más tarde! + +[KENSGO] +~g~¡Kenji está ocupado! ¡Llama más tarde! + +[ASUSGO] +~g~¡Asuka no está disponible en este momento! + +[HOODGO] +~g~¡Los Hoods no pueden atenderte en este momento! + +[WRONGT1] +~g~Vuelve entre las 05:00 y las 21:00 para buscar trabajo. + +[WRONGT2] +~g~Vuelve entre las 06:00 y las 14:00 para buscar trabajo. + +[WRONGT3] +~g~Vuelve entre las 15:00 y las 00:00 para buscar trabajo. + +{ ============================================================================ } +{ ================= SUBTITLES FOR THE AMMU-NATION SHOP CLERK ================= } +{ ============================================================================ } [AMMU_A] -Luigi dijo que tú necesitabas una pieza... +Luigi dijo que necesitabas una pipa... [AMMU_B] -Joey me dijo que te armáramos... +Joey me pidió que te armáramos... [AMMU_C] -Así que ve por la parte de atrás de la tienda. Te dejé un nueve en el patio. +Ve a la parte de atrás. Te dejé un nueve en el patio. [AMMU_D] -Te conseguí todas las defensas necesarias para la casa. +Tengo todo lo necesario para defender tu casa. [AMMU_E] ¿También quieres una licencia? [AMMU_F] -No necesito ver ningún documento, pareces de fiar. +No necesito tu documentación, pareces de fiar. -[DETON] -DETONACION: +{ ==================================================================================================================== } +{ ==================================================================================================================== } +{ =============================================== SIDE MISSION STRINGS =============================================== } +{ ==================================================================================================================== } +{ ==================================================================================================================== } -[DRIVE_A] -Ten un Uzi seleccionado cuando entres en un vehículo, entonces mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. +{ ==================================================================== } +{ ================= TAXI/CABBIE SIDE MISSION STRINGS ================= } +{ ==================================================================== } -[DRIVE_B] -Ten un Uzi seleccionado cuando entres a un vehículo, entonces mira a la izquierda o a la derecha y pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar. +[TAXI_M] +'TAXISTA' -[RECORD] -~g~¡¡NUEVO RECORD!! +[TSCORE2] +$~1~ -[NRECORD] -~r~¡NO HAY NUEVO RECORD! +[IN_ROW] +¡~1~ CONSECUTIVOS! $~1~ -[RCHELP] -Pulsa botón ~k~~PED_FIREWEAPON~, o conduce el coche de RC hasta las ruedas de un coche para detonarlo. +[TAXIH1] +Para cerca de un peatón señalado para recogerlo, luego condúcelo a su destino antes de que se acabe el tiempo. -[RCHELPA] -Pulsa el botón ~k~~PED_FIREWEAPON~, o conduce el coche RC hasta unas ruedas de coche para detonarlo. +[TAXI1] +~g~Busca un cliente. + +[TAXI2] +~r~¡Se te acabó el tiempo! + +[TAXI3] +~r~¡Tu pasajero ha salido corriendo! + +[TAXI4] +¡Carrera terminada! + +[TAXI5] +¡VIAJE RÁPIDO! + +[TAXI6] +Misión de taxi terminada + +[TAXI7] +~r~Tu coche está destrozado, haz que lo reparen. + +[FARE1] +~g~Ve al ~w~club Sex Kitten Meeouch ~g~en el barrio rojo. + +[FARE2] +~g~Ve a ~w~Supa Save ~g~en Portland View. + +[FARE3] +~g~Ve a ~w~la sala Clásica ~g~en Chinatown. + +[FARE4] +~g~Ve a la ~w~cafetería Greasy Joe ~g~en Callahan Point. + +[FARE5] +~g~Ve a la ~w~tienda de armas Ammu-Nation ~g~en el barrio rojo. + +[FARE6] +~g~Ve a ~w~Easy Credit Autos ~g~en Saint Mark's. + +[FARE7] +~g~Ve al ~w~bar de topless de Woody ~g~en el barrio rojo. + +[FARE8] +~g~Ve al ~w~restaurante Marcos ~g~en Saint Mark's. + +[FARE9] +~g~Ve al ~w~taller de importación y exportación ~g~en el puerto de Portland. + +[FARE10] +~g~Ve a ~w~Punk Noodles ~g~en Chinatown. + +[FARE11] +~g~Ve a la ~w~zona en obras~g~ de Fort Staunton. + +[FARE12] +~g~Ve al ~w~estadio de fútbol ~g~en Aspatria. + +[FARE13] +~g~Ve a la ~w~iglesia ~g~de Bedford Point. + +[FARE14] +~g~Ve al ~w~casino ~g~de Torrington. + +[FARE15] +~g~Ve a la ~w~universidad ~g~en el Campus de Liberty. + +[FARE16] +~g~Ve al ~w~centro comercial ~g~en la zona del parque Belleville. + +[FARE17] +~g~Ve al ~w~museo ~g~de Newport. + +[FARE18] +~g~Ve al ~w~edificio de AmCo ~g~en Torrington. + +[FARE19] +~g~Ve a ~w~Bolt Burgers ~g~en Bedford Point. + +[FARE20] +~g~Ve al ~w~parque ~g~de Belleville. + +[FARE21] +~g~Ve al ~w~Aeropuerto Internacional Francis. + +[FARE22] +~g~Ve a la ~w~presa Cochrane~g~. + +[FARE23] +~g~Ve al ~w~taller de importación/exportación~g~ en el distrito de la presa Cochrane. + +[FARE24] +~g~Ve al ~w~hospital ~g~de Pike Creek. + +[FARE25] +~g~Ve al ~w~parque ~g~de Shoreside Vale. + +[FARE26] +~g~Ve a las ~w~Torres del Noroeste ~g~de Wichita Gardens. + +[NEW_TAX] +¡MÁS GRANDES! ¡MÁS RÁPIDO! ¡MÁS DUROS! Los nuevos taxis Borgnine abren su negocio en Harwood. ¡Llame hoy al 555-BORGNINE! + +[TTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. + +[TTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. + +{ ============================================================================= } +{ ================= AMBULANCE/PARAMEDIC SIDE MISSIONS STRINGS ================= } +{ ============================================================================= } + +[AMBUL_M] +'SANITARIO' + +[A_SAVES] +GENTE SALVADA: ~1~ + +[ATUTOR2] +~g~Conduce a los pacientes hasta el hospital con mucho cuidado. Cada golpe reducirá sus posibilidades de supervivencia. + +[A_TIME] ++~1~ segundos + +[A_FULL] +~r~¡Ambulancia llena! + +[A_RANGE] +~g~La radio de la ambulancia está fuera de cobertura, ¡acércate a un hospital! + +[A_COMP1] +¡Misiones de sanitario completadas! + +[A_CANC] +~r~¡Misión de sanitario cancelada! + +[A_COMP3] +¡Misiones de sanitario completadas! ¡Ahora no te cansarás al correr! + +[ATUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. + +[ATUTOR3] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. + +[ALEVEL] +Nivel de misión de sanitario: ~1~ + +[A_FAIL1] +Misión de sanitario terminada. + +[A_FAIL2] +~r~¡Tu falta de rapidez ha sido fatal para el paciente! + +[A_FAIL3] +~r~¡El paciente está muerto! + +[A_PASS] +¡Rescatado! + +[A_COMP2] +¡Nunca te cansarás! + +{ ============================================================================ } +{ ================= FIRE TRUCK/FIREMEN SIDE MISSIONS STRINGS ================= } +{ ============================================================================ } + +[FIRE_M] +'BOMBERO' + +[F_EXTIN] +INCENDIOS: + +[FTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. + +[FTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. + +[F_PASS1] +¡Fuego apagado! + +[F_FAIL1] +¡Misión del camión de bomberos terminada! + +[F_CANC] +~r~¡Misión del camión de bomberos cancelada! + +[F_RANGE] +~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate a una estación de bomberos! + +[F_FAIL2] +~r~¡Llegas demasiado tarde! + +[F_START] +~g~Informe de vehículo en llamas en: ~a~. Ve y extingue el fuego. + +{ ============================================================================== } +{ ================= POLICE CAR/VIGILANTE SIDE MISSIONS STRINGS ================= } +{ ============================================================================== } + +[COP_M] +'JUSTICIERO' + +[C_KILLS] +CRIMINALES ABATIDOS: ~1~ + +[LEGAL] +~g~¡Elimina la amenaza criminal! + +[C_BREIF] +~g~Sospechoso visto por última vez en: ~a~. + +[C_RANGE] +~g~La radio de la policía está fuera de cobertura, ¡acércate a una comisaría! + +[C_PASS] +¡AMENAZA ELIMINADA! + +[CTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. + +[CTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. + +[COPCART] +~g~Tienes ~1~ segundos para volver a un vehículo de la policía antes de que termine la misión. + +[C_FAIL] +¡Misión de justiciero terminada! + +[C_CANC] +~r~¡Misión de justiciero cancelada! + +[C_ESCP] +~r~¡El sospechoso ha escapado! + +[C_TIME] +~r~¡Tu trabajo como defensor de la ley ha terminado! + +[C_VIGIL] +¡PREMIO POR JUSTICIERO! + +{ ======================================================================== } +{ ================= CHECKPOINT RUN SIDE MISSIONS STRINGS ================= } +{ ======================================================================== } + +[T4X4_1] +'PATIO DE RECREO' + +[T4X4_1A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~15~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. + +[T4X4_1B] +¡~1~ de 15! + +[T4X4_1C] +~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~20 SEGUNDOS~g~ adicionales. + +[T4X4_2] +'UN PASEO POR EL PARQUE' + +[T4X4_2A] +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~12~g~ puntos de control! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. + +[T4X4_2B] +¡~1~ de 12! + +[T4X4_2C] +~y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~10 SEGUNDOS~g~ adicionales. + +[T4X4_3] +'¡AGARRADO!' + +[T4X4_3A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~20~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. + +[T4X4_3B] +~Y~PASA A TRAVÉS~g~ del primer punto de control para que comience el cronómetro. ~g~Cada punto de control te brindará ~y~15 SEGUNDOS~g~ adicionales. + +[T4X4_3C] +¡~1~ de 20! + +[MM_1] +'CAOS EN EL APARCAMIENTO' + +[MM_1_A] +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~20 puntos de control~g~ en el aparcamiento! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. + +[MM_1_B] +¡~1~ de 20! + +[MM_1_C] +~g~Tendrás 20 segundos, más ~y~5 SEGUNDOS~g~ por cada punto de control. ~g~El cronómetro comenzará ~y~INMEDIATAMENTE. + +[T4X4_F] +~r~¡Te has escapado! ¿Demasiado difícil para ti? + +{ ============================================================================ } +{ ================= RC CAR DESTRUCTION SIDE MISSIONS STRINGS ================= } +{ ============================================================================ } + +[RC1] +'DESTRUCCIÓN DE LOS DIABLOS' + +[RC2] +'LA MASACRE DE LA MAFIA' + +[RC3] +'CALAMIDAD EN EL CASINO' + +[RC4] +'EXTERMINIO DE RUMPOS' [RC_1] -¡Tienes 2 minutos para volar cuantos coches de gangsters Diablo sean posibles! +¡Tienes 2 minutos para destruir todos los coches de los Diablos que puedas! [RC_2] -¡Tienes 2 minutos para bolar cuantos coches de gangsters Mafia sean posibles! +¡Tienes 2 minutos para destruir todos los coches de la mafia que puedas! [RC_3] -Tienes 2 minutos para bolar cuantos coches de gangsters Yakuza sean posibles! +¡Tienes 2 minutos para destruir todos los coches de la yakuza que puedas! [RC_4] -¡Tienes 2 minutos para volar cuantos coches de gangsters Yardie sean posibles! +¡Tienes 2 minutos para destruir todos los coches de los jamaicanos que puedas! [RC_5] -Tienes 2 minutos para volar cuantos coches de gangsters Hood sean posibles! +¡Tienes 2 minutos para destruir todos los coches de los Hood que puedas! [RC_6] -Tienes 2 minutos para volar cuantos coches de gangsters Cartel sean posibles! +¡Tienes 2 minutos para destruir todos los coches del cártel que puedas! -[RAMPAGE] -¡¡ATAQUE!! +{ ==================================================================================================================== } +{ ==================================================================================================================== } +{ ================================================ MAIN STORY STRINGS ================================================ } +{ ==================================================================================================================== } +{ ==================================================================================================================== } -[RAMP_P] -¡ATAQUE COMPLETADO! +{ ================================================== } +{ ================= OPENING SCENES ================= } +{ ================================================== } -[RAMP_F] -ATAQUE FALLIDO +{ Catalina, colombiana } -[PAGE_00] -. +[BETRA_A] +Lo siento, cariño. -[PAGE_01] -¡Mata ~1~ Diablo en 120 segundos! +[BETRA_B] +Soy una chica ambiciosa, ¿y tú? -[PAGE_02] -¡Destruye ~1~ vehículo en 120 segundos! +[BETRA_C] +Un Don Nadie. -[PAGE_03] -¡Mata ~1~ Mafia en 120 segundos! +{ Newspaper clip. Only PAPER1 is used } -[PAGE_04] -¡Mata ~1~ Tríadas en 120 segundos! +[PAPER1] +CRIMINAL HERIDO DE BALA POR SU NOVIA Y CÓMPLICE; EL TRIBUNAL ENCUENTRA CULPABLE AL ATRACADOR CON UN VEREDICTO UNÁNIME. -[PAGE_05] -¡Mata ~1~ Tríada en 120 segundos! +[PAPER2] +¡DIEZ AÑOS POR AMOR! -[PAGE_06] -¡Destruye ~1~ vehículo en 120 segundos! +[PAPER3] +* -[PAGE_07] -¡Revienta ~1~ cabezas Yardie en 120 segundos! +{ Cutscene where the Colombians kidnap the Old Oriental Gentlemen. Claude and 8-Ball escape from the van. } -[PAGE_08] -¡Quema ~1~ Yakuza en 120 segundos! +{ Libery City News broadcaster } -[PAGE_09] -¡Destruye ~1~ vehículo en 120 segundos! +[JAILB_V] +Hoy, Liberty City se ha visto conmocionada. -[PAGE_10] -¡Destruye ~1~ vehículo en 120 segundos! +[JAILB_A] +La policía y los servicios de emergencia lidian con las consecuencias -[PAGE_11] -¡Aniquila ~1~ Yardie en 120 segundos! +[JAILB_B] +de un ataque devastador a un convoy policial ocurrido esta mañana. -[PAGE_12] -¡Quema ~1~ Yakuza en 120 segundos! +[JAILB_C] +No se ha informado de quiénes eran los prisioneros trasladados en el convoy -[PAGE_13] -¡Vuela ~1~ Yardie en 120 segundos! +[JAILB_D] +y ningún grupo ha reconocido la autoría. -[PAGE_14] -¡Fríe ~1~ Colombianos en 120 segundos! +[JAILB_E] +El convoy abandonó las oficinas de la policía esta mañana -[PAGE_15] -¡Machaca ~1~ Hood en 120 segundos! +[JAILB_F] +para hacer una transferencia de reos a la penitenciaría de Liberty. -[PAGE_16] -¡Destruye ~1~ vehículo en 120 segundos! +[JAILB_G] +El ataque se produjo en el puente Callahan, -[PAGE_17] -¡Machaca ~1~ Colombianos con un coche en 120 segundos! +[JAILB_H] +dejando pocos testigos y al puente seriamente dañado. -[PAGE_18] -¡Conduce por ahí en coche y destruye ~1~ vehículo en 120 segundos! +[JAILB_I] +Se cree que algunos de los convictos han perecido en la explosión -[PAGE_19] -¡Corta ~1~ cabezas colombiana en 120 segundos! +[JAILB_J] +posterior al ataque inicial. -[PAGE_20] -¡Córtale la cabeza a ~1~ Hoods en 120 segundos! +[JAILB_W] +Pasadas las horas se hizo evidente que el ataque era obra de profesionales, + +[JAILB_K] +ya que la identificación de los prófugos se complicó + +[JAILB_L] +cuando piratas informáticos atacaron las bases de datos de la policía. + +[JAILB_O] +Con el retraso del proyecto del túnel Porter, + +[JAILB_P] +este desastre deja a Portland aislada del resto de la ciudad. + +[JAILB_M] +* + +[JAILB_N] +* + +[JAILB_X] +En una declaración realizada hoy previamente, + +{ Colombian thug } + +[JAILB_Q] +¡Vamos! + +[JAILB_R] +¡Señor pendejo! + +[JAILB_S] +No nos importará matarte. + +{ Police officer } + +[JAILB_T] +Os vais a arrepentir. + +{ Colombian thug } + +[JAILB_U] +Bien, bien, piérdete. + +{ ======================================================================= } +{ ================= MISSION: GIVE ME LIBERTY (NO OWNER) ================= } +{ ======================================================================= } + +{ TITLE } + +[EBAL] +'DAME LIBERTAD' + +{ 8-Ball } + +[EBAL_A] +Conozco un lugar en las afueras del barrio rojo donde podemos escondernos, + +[EBAL_A1] +pero mis manos están destrozadas, así que conduce tú, hermano. + +{ Mission instructions } + +[EBAL_1] +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. + +[EBAL_1B] +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. + +[EBAL_2] +~g~¡Vuelve al coche! + +[EBAL_3] +Este es el ~h~radar~w~. Utilízalo para recorrer la ciudad: ¡sigue el ~h~punto~w~ en el ~h~radar~w~ para encontrar el escondite! + +{ 8-Ball } + +[EBAL_B] +Es aquí, ¡entremos y cambiémonos de ropa! + +{ 8-Ball } + +[EBAL_D] +Conozco a un tipo con contactos, se llama Luigi. + +[EBAL_D1] +Somos viejos amigos, así que podremos buscarte curro. Vamos a verlo. + +{ 8-Ball } + +[EBAL_E] +Venga, vamos a pasarnos por allí y te presentaré. + +{ 8-Ball } + +[EBAL_G] +Este es el club de Luigi. Vamos a la parte de atrás, a la puerta de servicio. + +{ ============================================================================ } +{ ================= MISSION: LUIGI'S GIRLS (LUIGI GOTERELLI) ================= } +{ ============================================================================ } + +{ TITLE } + +[LM1] +'LAS CHICAS DE LUIGI' + +{ Premission cutscene } + +{ 8-Ball } + +[EBAL_H] +Espera, tío, que voy a hablar con Luigi. + +{ Mick (unused) } + +[EBAL_I] +El jefe os recibirá enseguida... + +{ Luigi } + +[EBAL_J] +8-Ball que ocuparse de una cosa arriba. + +[EBAL_K] +Quizá puedas hacerme un favor. + +[EBAL_L] +Una de mis chicas necesita que la lleven, así que consigue un coche, recoge a Misty en la clínica y luego tráela aquí. + +[EBAL_M] +¡Recuerda: nadie se mete con mis chicas! + +[EBAL_N] +¡Así que no quites las manos del volante! + +[EBAL_O] +Si no la cagas, puede que haya más trabajo para ti. ¡Ahora largo! + +{ Misty } + +[LM1_9] +Hola, soy Misty. + +{ Mission instructions } + +[EBAL_4] +~r~¡8-Ball ha muerto! + +[EBAL_5] +~g~¡Consigue un vehículo! + +[EBAL_6] +~g~¡Recoge a Misty! + +[LM1_2] +~g~Lleva a Misty al club de Luigi. + +[LM1_3] +~g~Toca el claxon para que la chica entre en el coche. + +[LM1_6] +~g~¡Vuelve al coche! + +[MISTY1] +~r~¡Misty está para el arrastre! + +[LM1_7] +Detén el vehículo junto a Misty y déjala subir. + +{ Post-mission instructions } + +[LM1_8] +Puedes ir a ver a Luigi y buscar más trabajo o darte un paseo por Liberty City. + +[LM1_8A] +Si quieres ganar un dinerillo extra, siempre puedes ''coger prestado'' un taxi... + +{ ====================================================================================== } +{ ================= MISSION: DON'T SPANK MA BITCH UP (LUIGI GOTERELLI) ================= } +{ ====================================================================================== } + +{ TITLE } + +[LM2] +'NO DROGUES A MI ZORRA' + +{ Premission cutscene } + +{ Mick } + +[LM2_C] +Luigi dijo que... que te diera esto... + +[LM2_D] +toma, toma, para ti. + +{ Luigi (letter) } + +[LM2_A] +Hay una nueva droga en la ciudad llamada SPANK. + +[LM2_E] +Algún listillo ha estado dando esta basura a mis chicas en el puerto de Portland. + +[LM2_B] +¡Ve y dale con un bate de béisbol en su cara! + +[LM2_F] +Luego coge su coche y repíntalo. + +[LM2_G] +¡Quiero una compensación por este insulto! + +{ Mission instructions } + +[LM2_1] +~g~Coge su coche y haz que cambien su pintura. + +[LM2_2A] +¡Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar puñetazos~w~, ~h~patadas~w~ o ~h~pegar ~w~con el bate! + +[LM2_2C] +¡Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar puñetazos~w~, ~h~patadas~w~ o ~h~pegar ~w~con el bate! + +[LM2_2D] +¡Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~dar puñetazos~w~, ~h~patadas~w~ o ~h~pegar ~w~con el bate! + +[LM2_3] +~g~¡Mete el coche en el garaje de Luigi! + +[LM2_4] +~g~¡Vuelve a pintar el coche! + +{ ================================================================================= } +{ ================= MISSION: DRIVE MISTY FOR ME (LUIGI GOTERELLI) ================= } +{ ================================================================================= } + +{ TITLE } + +[LM3] +'LLEVA A MISTY POR MÍ' + +{ Premission cutscene } + +{ Luigi } + +[LM3_A] +Hola, tengo que hablar contigo... Bueno, Mick, ya hablaremos. + +[LM3_B] +¿Cómo te va, chico? + +[LM3_C] +El hijo del Don, Joey Leone, quiere fiesta con su chica de siempre, Misty. + +[LM3_D] +Recógela en los cerros de Hepburn, + +[LM3_E] +pero cuidado, ese es territorio de los Diablos. + +[LM3_F] +Luego llévala rapidito hasta su taller en Trenton, + +[LM3_G] +que a Joey no le gusta esperar. Recuerda, tienes un pie dentro... + +[LM3_H] +¡así que estate pendiente del camino y no de Misty! + +{ Mission instructions } + +[LM3_1D] +Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. + +[LM3_2] +~g~Lleva a Misty al local de Joey. + +[LM3_4] +~g~¡Recoge a Misty! + +[LM3_10] +~g~¡Consigue un vehículo! + +[LM3_11] +~g~Misty no irá en un autobús, ¡hazte con otro vehículo! + +[LM3_1A] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. + +[LM3_1B] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. + +[LM3_1C] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. + +{ Misty } + +[LM3_5] +Ahora trabajas para Luigi, ¿no? ¡Ya era hora de que tuviese un conductor de confianza! + +{ Postmission cutscene } + +{ Misty } + +[LM3_6] +¡Joey...! + +[LM3_6A] +¿Voy a jugar con tu paquetín otra vez? + +{ Joey } + +[LM3_7] +Estaré contigo en un minuto, bujía mía. + +[LM3_8] +Hola, soy Joey. + +[LM3_9] +Luigi dijo que eras de fiar, así que vuelve más tarde, + +[LM3_9A] +que tendré trabajo para ti. + +[LM3_9B] +¿De acuerdo? + +{ =============================================================================== } +{ ================= MISSION: PUMP-ACTION PIMP (LUIGI GOTERELLI) ================= } +{ =============================================================================== } + +{ TITLE } + +[LM4] +'UN CHULO Y SU ESCOPETA' + +{ Premission cutscene } + +{ Luigi } + +[LM4_A] +Algún Diablo de las narices ha estado vendiendo a sus putitas en mi territorio. + +[LM4_B] +Ve y resuélvelo de mi parte. + +[LM4_C] +Si necesitas un arma, ve a la puerta trasera de la tienda Ammu-Nation que está enfrente del metro. + + +{ ============================================================================ } +{ ================= MISSION: THE FUZZ BALL (LUIGI GOTERELLI) ================= } +{ ============================================================================ } + +{ TITLE } + +[LM5] +'EL BAILE DE LA POLICÍA' + +{ Premission cutscene } + +{ Luigi } + +[LM5_A] +El baile de la policía se está celebrando en la sala Clásica, cerca del puente, + +[LM5_B] +y parece que tienen ganas de una fiesta más ''clásica''. + +[LM5_C] +Tengo chicas haciendo la calles. + +[LM5_D] +Llévalas al baile, sacarán una buena tajada. + +[LM5_E] +Saca todo el dinero que puedas a los polis antes de que se lo beban. + +{ Mission instructions } + +[LM5_1] +~g~¡Tienes a las chicas tan embutidas que les van a salir moratones! ~g~Primero deja a las que llevas y luego ve a por más. + +[LM5_2] +~r~¡Te has cargado a una de las chicas de Luigi! + +[LM5_3] +~g~¡Necesitas un coche! + +[LM5_4] +~g~Recoge a las chicas que trabajan en Saint Mark's. + +[LM5_5] +~g~¡Lleva a las chicas al baile de la policía! + +[LM5_7] +~g~¡Si hay menos de cuatro chicas trabajando en el ~p~baile de la policía~g~, Luigi no estará contento! + +[LM5_8] +~g~Chicas trabajando en el baile: ~1~ + +[LM5_9] +CHICAS: + +{ ============================================================================== } +{ ================= MISSION: MIKE LIPS LAST LUNCH (JOEY LEONE) ================= } +{ ============================================================================== } + +{ TITLE } + +[JM1] +'EL ÚLTIMO ALMUERZO DE MIKE ''LABIOS'' ' + +{ Premission cutscene } + +{ Misty } [JM1_A] -Ey, estoy aburrida, ¿cuándo vas a tomarme? +Jo, me aburro, ¿cuándo me la vas a meter? + +{ Joey } [JM1_B] -En un momento, cariño, tengo un pequeño negocio del que ocuparme. +Dame un momento, cariño, que tengo un asuntillo que tratar. [JM1_C] -Tengo un pequeño trabajo para ti, colega. +Tengo un trabajito para ti, colega. [JM1_D] Los hermanos Forelli me deben dinero desde hace mucho tiempo [JM1_E] -y ellos necesitan que alguien les enseñe un poco de respeto. +y hay que enseñarles respeto. [JM1_F] -Labios Forelli está poniéndose como un cerdo en el St Marks Bistro +Labios Forelli está atiborrándose en el restaurante de Saint Mark's, [JM1_G] -así que roba su coche y llévalo a la tienda de bombas 8-Ball en Harwood. +así que róbale el coche y llévalo al taller de bombas de 8-Ball en Harwood. [JM1_H] -Conoces 8-Ball, ¿verdad? +Conoces a 8-Ball, ¿verdad? [JM1_I] -Una vez que esté cargado con una bomba, ve a aparcar el coche donde lo encontraste. +En cuanto esté cargado con una bomba, aparca el coche donde lo encontraste. [JM1_J] -Luego siéntate y contempla todo el espectáculo. +Luego salte y disfruta del espectáculo. [JM1_K] Pero cuidado, no va a estar comiendo toda la vida. -[CAT2_A1] -¡Vamos, perra estúpida! +{ Mission instructions } -[CAT2_A] -La verdadera cuestión es, lo que quieres es ¿rescatar a María o llevarme a mí de vuelta? +[JM1_1] +~g~Lleva el coche de Forelli al taller que tiene 8-Ball al norte, tras Easy Credit Autos. -[CAT2_B] -Bueno, tengo noticias para ti, +[JM1_2] +~g~Vuelve a aparcar el coche frente al restaurante de Marco. -[CAT2_B2] -dispararte será un placer pero salir contigo fue sólo un asunto de negocios. +[JM1_3] +~g~¡Activa la bomba del coche y luego sal de ahí! -[CAT2_C] -¡Eres muy peccino, amigo! +[JM1_4] +~g~¡Te estás cargando el coche! ¡Repáralo! -[CAT2_D] -Echame el dinero +[JM1_5] +~g~¡La bomba del coche no está activada! -[CAT2_E] -Has sido un chico aplicado! +[JM1_6] +~g~Vuelve a aparcar el coche en el sitio correcto. -[CAT2_E2] -Pero no has aprendido, yo no soy de fiar +[JM1_7] +~g~¡Cierra la puerta del coche! ¡Se dará cuenta! -[CAT2_E3] -Mata al idiota +{ 8-Ball's messages, not voiced } -[CAT2_J] -Atrapa esta cosa en el aire! +[JM1_8A] +~y~¡Ey, pero si es mi colega! -[HM5_1] -Tío, Ice dijo que vendría. Hay reglas. Bates sólo. No armas, no coches. +[JM1_8B] +~y~El taller de bombas está automatizado. Solo tienes que meter el coche, pararlo y el taller hará el resto. -[HM5_5] -Esta es una batalla por el respeto, ¿vale? +[JM1_8C] +~y~Ten, tu primer coche es gratis, pero los siguientes te los cobraré. -[HELP14] -Para conseguir armas pasa sobre ellas. Estas no pueden conseguirse cuando se está dentro de un vehículo. +{ ===================================================================================== } +{ ================= MISSION: FAREWELL 'CHUNKY' LEE CHONG (JOEY LEONE) ================= } +{ ===================================================================================== } -[CRUSH] -Aparca en el área señalada y sal de tu vehículo. El vehículo será entonces triturado. +{ TITLE } + +[JM2] +'DESPEDIDA A LEE CHONG ''EL GORDO''' + +{ Premission cutscene } + +{ Joey } + +[JM2_A] +Lee Chong ''el Gordo'' está traficando SPANK para una nueva banda de Colombia... o Colorado... O como se llame. + +[JM2_B] +No me acuerdo. El caso es que no importa. + +[JM2_C] +Tiene un puesto de fideos en Chinatown. + +[JM2_D] +Ese cabrito ha vendido su último fideo. + +[JM2_E] +¡Lo quiero muerto! + +[JM2_F] +Si necesitas una pipa, ve a la parte de atrás del Ammu-Nation que está enfrente del metro. + +[JM2_G] +Búscate un nueve, queda claro, ¿no? + +[JM2_H] +Y recuerda, ve con ojo en Chinatown: es territorio de las Tríadas. + +{ =================================================================== } +{ ================= MISSION: VAN HEIST (JOEY LEONE) ================= } +{ =================================================================== } + +{ TITLE } + +[JM3] +'EL ROBO DE LA FURGONETA' + +{ Premission cutscene } + +{ Joey } + +[JM3_A] +Vamos a asaltar un furgón blindado. + +[JM3_B] +Sale de Chinatown todos los días. + +[JM3_C] +Las balas ni siquiera abollarán el furgón, así que coge un coche y échalo de la carretera. + +[JM3_D] +Si lo zurras bien, los imbéciles de los guardias se achantarán. + +[JM3_E] +Luego llévalo al almacén de los muelles y mis chicos se encargarán desde ahí. + +[JM3_F] +El furgón no estará fuera todo el día, así que no pierdas el tiempo. + +{ Mission instructions } + +[JM3_1] +~g~Lleva el furgón al almacén. + +[JM3_2] +~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. + +{ ============================================================================== } +{ ================= MISSION: CIPRIANI'S CHAUFFEUR (JOEY LEONE) ================= } +{ ============================================================================== } + +{ TITLE } + +[JM4] +'EL CHÓFER DE CIPRIANI' + +{ Premission cutscene } + +{ Joey } + +[JM4_A] +Sí, Toni, ya está a punto. Ahora es una delicia, ¿sabes? + +[JM4_B] +¡Ah, aquí está el tío que te decía! + +[JM4_C] +Bueno, este no es italiano ni tampoco mecánico, pero sabe arreglar cosas. + +[JM4_D] +Este es el capo de papá, Toni Cipriani. + +{ Toni } + +[JM4_E] +Sí, soy Toni Cipriani. + +{ Joey } + +[JM4_F] +Llévale al restaurante de Mamma en Saint Mark's, ¿va? + +[JM4_G] +Oye, estoy planeando un curro que necesita un buen conductor, pásate por aquí más tarde, ¿estamos? + +{ Mission instructions } + +[JM4_7] +~g~Lleva a Toni al restaurante de Mamma. + +[JM4_8] +~r~¡Han liquidado a Toni! + +{ Toni, cutscene right after the premission one } + +[JM4_10] +Vale, chaval, llévame primero a la lavandería de Chinatown, tengo un asunto del que ocuparme. + +[JM4_11] +Las lavanderas no están pagando por su protección. + +[JM4_12] +Y ojo con el coche, Joey acaba de arreglar esta chatarra. + +[JM4_13] +Así que con cuidado, ¿vale? + +{ Toni, when bumping the car } + +[JM4_6] +¡Mi coche! Dije que con cuidado. + +{ Toni, when reaching the laundry } + +[JM4_2] +¡Espera aquí! Deja el motor en marcha. Esta no es una visita social. + +[JM4_3] +¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! + +{ Toni, after escaping and finishing the mission } + +[JM4_4] +Las Tríadas creen que pueden meterse conmigo. ¡Las Tríadas, CONMIGO! + +[JM4_5] +Pasa más tarde y les daremos algo que lavar... ¡Su propia ropa manchada de sangre! + +{ ================================================================================= } +{ ================= MISSION: DEAD SKUNK IN THE TRUNK (JOEY LEONE) ================= } +{ ================================================================================= } + +{ TITLE } + +[JM5] +'FIAMBRE EN EL MALETERO' + +{ Premission cutscene } + +{ Joey } + +[JM5_A] +Guapo, muy guapo... + +[JM5_B] +¡Justo te estaba buscando! + +[JM5_C] +Vale, hay un coche cargado con un fiambre en el bar cercano a Callahan Point. + +[JM5_D] +Uno de los Forelli se las daba de mafioso y se llevó su merecido. + +[JM5_E] +Lleva el cuerpo a la trituradora en Harwood, ¿vale? + +{ Mission instructions } + +[JM5_1] +~g~¡Llévalo a la trituradora! + +[JM5_2] +~g~¡Son los hermanos Forelli! + +{ ===================================================================== } +{ ================= MISSION: THE GETAWAY (JOEY LEONE) ================= } +{ ===================================================================== } + +{ TITLE } + +[JM6] +'LA HUIDA' + +{ Premission cutscene } + +{ Joey } + +[JM6_A] +Vaya cochazo, ¿eh? + +[JM6_B] +Bueno, escucha. Lleva un coche a la casa franca de Saint Mark's y recoge a unos colegas. + +[JM6_C] +Van a atracar un banco y necesitan un conductor. + +[JM6_D] +Di mi palabra de que eras su hombre, así que no la cagues. + +[JM6_E] +Llévales al banco antes de las cinco en punto, ni un minuto después. + +{ Thief's dialogues } + +[JM6_1] +Llévanos al banco de la avenida principal. + +[JM6_2] +Mantén el motor en marcha, entraremos y saldremos enseguida. + +[JM6_3] +¡Sácanos de aquí! + +[JM6_4] +¡Líbrate de la poli y llévanos a la casa franca! + +{ Mission instructions } + +[JM6_5] +~g~Necesitas un vehículo de fuga, ¡idiota! + +[JM6_6] +~g~¡Busca un vehículo menos llamativo! + +[JM6_7] +~g~¡Necesitas a los 3 para robar el banco! + +[JM6_8] +~r~¡Has perdido a todos los ladrones! + +{ ===================================================================== } +{ ================= MISSION: THE CROOK (MARTY CHONKS) ================= } +{ ===================================================================== } + +{ TITLE } + +[MEA1] +'EL CRIMINAL' + +{ Pager message to indicate Chonks' missions are activated } + +[MEAT1_A] +Un amigo dijo que tú podías arreglar algunos problemas que tengo. Ve al teléfono público de Trenton si crees que puedes ayudar. + +{ Premission cutscene } + +{ Marty } + +[MEA1_B] +Me llamo Chonks, Marty Chonks. + +[MEA1_C] +Soy el dueño de la fábrica de comestibles Bitch'n' Dog que está a la vuelta de la esquina. + +[MEA1_D] +Tengo problemas económicos, pero, ¿y quién no? + +[MEA1_E] +He quedado con el director de mi banco. + +[MEA1_F] +Es un chorizo que no para de inflar los intereses del préstamo para sacarme una buena tajada. + +[MEA1_G] +Coge mi coche, búscale y tráelo de vuelta. + +[MEA1_H] +¡Tengo una sorpresita para ese parásito chupasangre! + +{ Mission instructions } + +[MEA1_B3] +~g~Reúnete con el director del banco. + +[MEA1_B6] +~g~Lleva el coche a la trituradora para eliminar las pruebas, allí sal del coche y la grúa lo recogerá. + +[MEA1_1] +~r~¡El director del banco está muerto! + +[MEA1_2] +~r~¡Te dijeron que trituraras el coche! + +[MEA1_3] +~g~¡Sal del coche! + +[MEA1_4] +~r~¡Has abandonado al director del banco! + +[MEA1_B5] +UNUSED + +{ Bank Manager, when picking him up } + +[MEA1_B4] +Ah, te envió el Sr. Chonks, ¿verdad? Visitemos a nuestro amigo. + +{ ======================================================================= } +{ ================= MISSION: THE THIEVES (MARTY CHONKS) ================= } +{ ======================================================================= } + +{ TITLE } + +[MEA2] +'LOS LADRONES' + +{ Premission cutscene } + +{ Marty } + +[MEA2_A] +Contraté a unos ladrones para que entraran en mi piso + +[MEA2_B] +y robaran cuanto pillaran para que yo pudiera reclamar a la aseguradora. + +[MEA2_C] +Ahora los muy cabritos me amenazan con delatarme + +[MEA2_D] +si no les doy una parte. + +[MEA2_E] +¿Te lo puedes creer? + +[MEA2_F] +He dejado un coche dentro de la fábrica. + +[MEA2_G] +Ve a recogerles con él en su territorio, en el barrio rojo. + +[MEA2_H] +Luego tráelos a la fábrica para que conozcan la opinión de Marty. + +{ Mission instructions } + +[MEA2_B3] +~g~Reúnete con los ladrones. + +[MEA2_B4] +~g~Llévalos a la fábrica de comestibles Bitch'n'Dog. + +[MEA2_B5] +UNUSED + +[MEA2_B6] +~g~Haz que repinten el coche para borrar las pruebas. + +[MEA2_1] +~r~¡Te dijeron que trituraras el vehículo! + +[MEA2_2] +~r~¡Un ladrón ha muerto! + +[MEA2_3] +~g~Lleva el coche de vuelta a la fábrica. + +[MEA2_4] +~r~¡Has dejado atrás a un ladrón! + +{ ==================================================================== } +{ ================= MISSION: THE WIFE (MARTY CHONKS) ================= } +{ ==================================================================== } + +{ TITLE } + +[MEA3] +'LA MUJER' + +{ Premission cutscene } + +{ Marty } + +[MEA3_A] +El negocio se irá a pique si no consigo un pastizal muy pronto. + +[MEA3_B] +Mi esposa tiene un seguro de vida y ella no ha hecho más que vaciarme los bolsillos. + +[MEA3_C] +He dejado un coche donde siempre. + +[MEA3_D] +Ve a por a mi esposa a Classic Nails y tráela a la fábrica. + +{ Mission instructions } + +[MEA3_B3] +~g~Recoge a la Sra. Chonks. + +[MEA3_B6] +~g~Llévate el coche y tíralo al mar, así eliminaremos las pruebas. + +[MEA3_1] +~r~¡La mujer está muerta! + +[MEA3_2] +~r~¡Se suponía que debías tirar el coche al agua! + +[MEA3_3] +~r~¡Has dejado atrás a su mujer! + +[MEA3_B5] +UNUSED + +{ Marty's wife, when picking her up } + +[MEA3_B4] +¿Marty quiere verme? Bueno, pues que sea rápido, porque tengo que ir a la peluquería. + +{ ===================================================================== } +{ ================= MISSION: HER LOVER (MARTY CHONKS) ================= } +{ ===================================================================== } + +{ TITLE } + +[MEA4] +'SU AMANTE' + +{ Premission cutscene } + +{ Marty } + +[MEA4_A] +Mierda, ¡tengo problemas! + +[MEA4_B] +Resulta que mi esposa salía con uno al que debo dinero. + +[MEA4_C] +¡Se ha cabreado y ahora quiere vengarse! + +[MEA4_D] +He aceptado verle, + +[MEA4_E] +y piensa que voy a devolverle el dinero. + +[MEA4_F] +Pero creo + +[MEA4_G] +¡que los perros de Liberty van a disfrutar de un nuevo sabor este mes! + +{ Mission instructions } + +[MEA4_B3] +~g~Recoge al amante de su mujer. + +[MEA4_1] +~r~¡Carlos está muerto! + +[MEA4_2] +~r~¡Marty Chonks ha muerto! + +[MEA4_3] +~r~¡Has abandonado a Carlos, el usurero! + +{ Carlos, when picking him up } + +[MEA4_B4] +¿Marty te envía? Vale, le voy a enseñar a ese sinvergüenza el significado de la palabra negocio. + +{ Postmission cutscene } + +{ Marty } + +[MEA4_B5] +¡Carl, hola! Ehhh... Necesito más tiempo para conseguir tu dinero. + +[MEA4_B7] +Pero si pasas por mi oficina... + +{ Carlos } + +[MEA4_B6] +Ya es muy tarde, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé de tu negocio... + +{ =============================================================== } +{ ================= MISSION: TURISMO (EL BURRO) ================= } +{ =============================================================== } + +{ TITLE } + +[DIAB1] +'TURISMO' + +{ Pager message that tells the player El Burro's missions are now available } + +[DIAB1_A] +El Burro quiere ofrecerte una oportunidad. Ve al teléfono público de los cerros de Hepburn si te interesa. + +{ Premission cutscene } + +{ El Burro, portorriqueño } + +[DIAB1_B] +Al habla El Burro, de los Diablos. + +[DIAB1_D] +Eres nuevo en Liberty, pero ya te estás ganando una reputación en las calles. + +[DIAB1_E] +Hay una carrera que empezará junto a la sala Clásica, cerca del puente Callahan. + +[DIAB1_F] +Consíguete un buen carro y el primero que pase por todos los puntos de control se llevará el premio. + +{ Mission instructions } + +[DIAB1_1] +~g~3... 2... 1... ¡ADELANTE! + +[DIAB1_4] +~g~Hazte con un coche rápido y ve a la parrilla de salida. + +[DIAB1_3] +~r~No sabes ganar ni una rifa, ¡FRACASADO! + +[DIAB1_2] +~g~Felicidades, has ganado con un tiempo increíble de ~1~ segundos. + +[DIAB1_5] +TIEMPO DE CARRERA: + +{ Pager message after succeeding this mission } + +[DIAB1_C] +Se te da bien correr. Pásate por el teléfono público y puede que El Burro tenga trabajo para ti. + +{ ============================================================================ } +{ ================= MISSION: I SCREAM, YOU SCREAM (EL BURRO) ================= } +{ ============================================================================ } + +{ TITLE } + +[DIAB2] +'IRA HELADA' + +{ Premission cutscene } + +{ El Burro, portorriqueño } + +[DIAB2_A] +¡Empecé mi negocio de entretenimiento exótico sin nada más que lo que cabía en mis pantalones de cuero! [DIAB2_B] -Una banda de infames me ha amenazado con quitarme mi afiliación si no les pago una parte. +Una banda de roñosos amenazó con quitarme a mi protagonista si no les pago. [DIAB2_C] Amenazaron al hombre equivocado, amigo. [DIAB2_D] -Ellos tienen debilidad por el helado. +Su debilidad son los helados. [DIAB2_E] -Consigue la bomba que he ocultado en Harwood, +Hazte con la bomba que dejé en Harwood, [DIAB2_F] -secuestra la furgoneta habitual de los helados en sus rondas. +secuestra la camioneta del heladero mientras hace su ronda [DIAB2_G] -y seduce a esos idiotas para que caigan en su ruina con el jeengle-jeengle +y engaña a esos idiotas con esa musiquita. [DIAB2_H] -Se ocultan en un almacén de Atlantic Quay +Se esconden en un almacén del muelle Atlantic. + +{ Mission instructions } + +[DIAB2_1] +~g~Recoge el maletín en Harwood. + +[DIAB2_2] +~g~Encuentra un camión de helados. + +[DIAB2_3] +~g~Aparca el camión de helados en el muelle Atlantic. + +[DIAB2_4] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. + +[DIAB2_6] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. + +[DIAB2_7] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. + +[DIAB2_5] +~g~Sal del camión y luego usa el mando a distancia para detonarlo. + +{ ===================================================================== } +{ ================= MISSION: TRIAL BY FIRE (EL BURRO) ================= } +{ ===================================================================== } + +{ TITLE } + +[DIAB3] +'A LA HOGUERA' + +{ Premission cutscene } + +{ El Burro, portorriqueño } [DIAB3_A] -Algunas Tríadas insolentes robaron mi bonito coche anoche, +¡Unas Tríadas insolentes robaron mi lindo carro anoche, [DIAB3_B] -destrózalo y deja que se queme. +lo destrozaron y lo quemaron! [DIAB3_C] -Algunos de mi más preciosos artículos sobre burros estaban en el maletero - +En el baúl había algunas de mis más preciadas posesiones sobre burros... [DIAB3_D] -objetos de colección que son irremplazables, amigo. +Objetos de coleccionista irremplazables, amigo. [DIAB3_E] -He escondido un arma punzante en el borde de Chinatown. +Escondí un arma en el borde de Chinatown. [DIAB3_F] -Tómalo y enseña a esos vándalos de las Tríadas a tenerle miedo a la ira bien fundada de El Burro. +Tómala y enseña a esos vándalos de las Tríadas a tenerle miedo a la ira pijuda de El Burro. + +[DIAB3_G] +¡Arriba! + +{ Mission instructions, in large text } [DIAB3_1] -MATA 25 TRIADS +MATA A 25 TRÍADAS + +{ ===================================================================== } +{ ================= MISSION: BIG 'N' VEINY (EL BURRO) ================= } +{ ===================================================================== } + +{ TITLE } + +[DIAB4] +'GRANDE Y VENOSO' + +{ Premission cutscene } + +{ El Burro, portorriqueño } [DIAB4_A] -¡Un ladrón oportunista ha robado mi furgoneta donde llevaba mis últimas publicaciones periodísticas! +¡Un ladrón oportunista robó una camioneta con mi última publicación! [DIAB4_B] -Pero ese idiota colgado de SPANK ha dejado las puertas de atrás abiertas +Pero ese idiota drogado de SPANK dejó las puertas de atrás abiertas, [DIAB4_C] -y ahora toda mi bellamente editada, +¡y ahora mi literatura para adultos [DIAB4_D] -literatura para adultos con tan buen gusto fotografiada está siendo esparcida por todo Liberty! +tan bellamente producida, tan gustosamente fotografiada, está siendo esparcida por toda Liberty! [DIAB4_E] -Coge la furgoneta y sigue el sendero de Donkey Does Dallas volúmenes 1,2 y 3 +Toma la camioneta y sigue el rastro de los volúmenes 1, 2 y 3 de Donkey Does Dallas, [DIAB4_F] -conseguido según vas. +tomándolos por el camino. [DIAB4_G] -Cuando hayas seguido el sendero de ese ladronzuelo con cabeza de SPANK, acaba con él! +¡Cuando alcances a ese bandido espaciado con SPANK, chíngatelo! [DIAB4_H] -Luego reparte mi material de Revistas XXX en el Red Light District (Distrito de la luz roja) +Luego reparte mis revistas XXX por el barrio rojo. + +{ Mission instructions } [DIAB4_1] -~g~Lleva la furgoneta a la parte de atrás de Revistas XXX +~g~Lleva la furgoneta a la parte de atrás de Revistas XXX. + +{ =================================================================================== } +{ ================= MISSION: TAKING OUT THE LAUNDRY (TONI CIPRIANI) ================= } +{ =================================================================================== } + +{ TITLE } + +[TM1] +'SACANDO LA COLADA' + +{ Pager message that tells the player Toni's missions are available } + +[TONI_P] +¡Tengo un trabajo urgente para ti! -Toni + +{ Premission cutscene } + +{ Toni } + +[TM1_A] +Siéntate, chico, siéntate de una vez. + +[TM1_B] +La lavandería no quiere pagar la protección, ¿eh? + +[TM1_C] +¿Las Tríadas creen que pueden meterse conmigo? + +[TM1_D] +¡Esos aspirantes a tipos duros van a saber lo que es ser un tipo duro! + +{ Toni's Mamma } + +[TM1_E] +¡Eso, enséñales respeto! ¡Las Tríadas no se ríen de ninguno de mis hijos! + +[TM1_F] +Tu padre, Dios acoja su alma, no toleraba ni media a las Tríadas en Sicilia. + +{ Toni } + +[TM1_G] +Lo siento, mamá. Sí, mamá. + +[TM1_H] +Quiero que te cargues sus furgonetas de lavandería + +[TM1_I] +y a cualquiera de las Tríadas que se cruce en tu camino. + +[TM1_J] +8-Ball te dará lo que necesites. + +{ ======================================================================== } +{ ================= MISSION: THE PICK-UP (TONI CIPRIANI) ================= } +{ ======================================================================== } + +{ TITLE } + +[TM2] +'LA ENTREGA' + +{ Premission cutscene } + +{ Toni's Mamma } + +[TM2_A] +Toni ha salido a partir cabezas, o a intentarlo... + +[TM2_AA] +Nunca será tan duro como su padre. Te dejó una nota en la mesa. + +{ Toni (letter) } + +[TM2_B] +La lavandería ya quiere pagar. ¡Buen trabajo, chico! + +[TM2_C] +Ve a por el dinero y tráelo aquí. Cuidado con las Tríadas. + +[TM2_D] +Puede que intenten metértela doblada, pero no te dejes. + +[TM2_E] +¡Nadie, quiero decir nadie, se mete con Toni Cipriani! + +{ Mission instructions } + +[TM2_1] +~g~¡Lleva el dinero a Toni! + +[TM2_2] +~g~¡Los dejaste tiesos a todos! + +[TM2_3] +~g~¡Es una trampa! ¡Liquidadlos a todos! + +{ ========================================================================================= } +{ ================= MISSION: SALVATORE'S CALLED A MEETING (TONI CIPRIANI) ================= } +{ ========================================================================================= } + +{ TITLE } + +[TM3] +'SALVATORE HA CONVOCADO UNA REUNIÓN' + +{ Premission cutscene } + +{ Toni's Mamma } + +[TM3_MA] +¡No sé dónde está! + +[TM3_MB] +Te juro que mi hijo a veces no sabe lo que hace. + +[TM3_MC] +Ahora bien, su padre era diferente. Siempre en la cumbre, pendiente de todo, valiente... + +{ Toni (letter) } + +[TM3_A] +Don Salvatore ha convocado una reunión. + +[TM3_B] +Necesito que vayas a por la limusina y su hijo, Joey, a su taller. + +[TM3_C] +Luego recoge a Luigi en su club, ven a buscarme, + +[TM3_D] +y nos iremos todos juntos a la casa del jefe. + +[TM3_E] +Los de las Tríadas no saben cuándo parar... + +[TM3_F] +Si quieren guerra, la tendrán. + +[TM3_G] +Ponte en marcha. + +{ Mission instructions } + +[TM3_1] +~g~Ve al taller de Joey a por la limusina. + +[TM3_2] +~g~Recoge a Luigi. + +[TM3_3] +~g~Ahora recoge a Toni. + +[TM3_4] +~g~Lleva a los mafiosos a la casa de Salvatore. + +[TM3_A1] +~r~¡Joey está frito! + +[TM3_A2] +~r~¡Joey y Luigi han sido incinerados! + +[TM3_A3] +~r~¡Joey, Luigi y Toni están calcinados! + +{ Toni, when the Triads ambush } + +[TM3_5] +~y~¡Es una emboscada de las Tríadas! + +{ Postmission cutscene } + +{ Toni } + +[TM3_H] +Buen trabajo, chaval, muy bueno. + +[TM3_I] +Vente, te presentaré al Don. + +{ Salvatore } + +[TM3_J] +¡Hola! ¡Luigi! + +{ Luigi } + +[TM3_K] +Mis chicas te han echado de menos, Salvatore. Hace mucho que no te vemos. + +{ Salvatore } + +[TM3_L] +Diles que en cuanto resolvamos este desafortunado incidente + +[TM3_M] +iremos todos al club para celebrarlo, ¿vale? + +[TM3_N] +¡Mi niño! + +{ Joey } + +[TM3_N2] +¿Cómo lo llevas, papá? + +{ Salvatore } + +[TM3_O] +¿Has encontrado ya una buena mujer? + +[TM3_P] +Tu madre, que en paz descanse, se retorcería en la tumba + +[TM3_Q] +si te viera sin una mujer. + +{ Joey } + +[TM3_R] +Lo sé, papá, estoy en ello. + +{ Salvatore } + +[TM3_S] +¡Toni! ¿Cómo está tu madre? + +[TM3_T] +Es una gran mujer, ¿sabes? Fuerte, ''firenze''. + +{ Toni } + +[TM3_U] +Está bien, estupendamente. + +{ Salvatore } + +[TM3_V] +Fantástico, fantástico. Bien, muchachos, entrad mientras yo hablo con nuestro nuevo amigo. + +[TM3_W] +Tienes un gran futuro por delante, hijo mío... + +{ ==================================================================================== } +{ ================= MISSION: TRIADS AND TRIBULATIONS (TONI CIPRIANI) ================= } +{ ==================================================================================== } + +{ TITLE } + +[TM4] +'TRÍADAS Y TRIBULACIONES' + +{ Premission cutscene } + +{ Toni's Mamma } + +[TM4_A] +Ah, eres tú. Toni no está. + +[TM4_A2] +Pero te ha dejado una de sus cartitas de amor. + +{ Toni } + +[TM4_B] +¡Esto es la guerra! Las Tríadas tienen una piscifactoría como tapadera. + +[TM4_C] +Casi todos sus negocios pasan por la lonja de Chinatown. + +[TM4_D] +La lavandería todavía no ha pagado la protección. + +[TM4_E] +Creen que está protegida por las Tríadas, así que creo que se merecen un castigo. + +[TM4_F] +¡Llévate a estos chicos y elimina a los líderes de las Tríadas! + +[TM4_G] +Qué narices, si ves la oportunidad, cárgate también a unos cuántos de sus soldados. + +{ Mission instructions } + +[TM4_GAT] +~g~Necesitas un camión de pescado de las Tríadas para entrar. + +{ ====================================================================== } +{ ================= MISSION: BLOW FISH (TONI CIPRIANI) ================= } +{ ====================================================================== } + +{ TITLE } + +[TM5] +'LLUVIA DE PECES' + +{ Premission cutscene } + +{ Toni } + +[TM5_B] +Vale, ya me he hartado de esta mierda. + +[TM5_C] +¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! + +[TM5_D] +8-Ball ha instalado una bomba en un camión de la basura. + +[TM5_E] +Tiene un temporizador, así que si la lías no quedará nada de ti. Ve a por el camión. + +[TM5_F] +¡Cuidado, 8-Ball dice que es muy sensible y que cualquier golpe puede hacerlo estallar! + +[TM5_G] +Su piscifactoría abrirá sus puertas a uno de sus camiones, así que podrás entrar sin más. + +[TM5_H] +¡Aparca entre los tanques de gas y lárgate de ahí! + +[TM5_I] +Quiero que llueva pescado. + +[TM5_J] +En plan bíblico, nada de bajo presupuesto. + +{ ======================================================================== } +{ ================= MISSION: CHAPERONE (SALVATORE LEONE) ================= } +{ ======================================================================== } + +{ TITLE } + +[FM1] +'CARABINA' + +{ Pager message, appears when Toni's missions have not been complete } + +[FRANGO] +~g~¡Salvatore quiere que ayudes primero a Toni a ocuparse de las Tríadas! + +{ Premission cutscene } + +{ Salvatore } + +[FM1_A] +Mis chicos y yo queremos hablar de negocios, + +[FM1_B] +así que esta tarde vas a cuidar de mi chica. + +[FM1_C] +¡OYE, MARÍA! ¡MUEVE ESE CULO! + +[FM1_D] +La muy idiota siempre hace lo mismo. + +[FM1_E] +Y aquí está, ¡la primera y única reina de Saba! + +[FM1_F] +¿Qué hacías arriba? + +[FM1_G] +Fuera lo que fuera, seguro que me cuesta dinero. + +{ Maria } + +[FM1_H] +Bueno, no pensarás que estoy aquí para conversar, ¿o sí? + +{ Salvatore } + +[FM1_I] +Métete en el coche y cierra el pico. + +[FM1_J] +Llévate la limusina, pero devuélvela de una pieza, ¿me has oído? + +[FM1_K] +Y cuidado con ella, es una lianta. + +{ Maria } + +[FM1_L] +¡Sí, sí, sí! Seguro que tu nuevo perrito faldero tiene todo previsto. + +[FM1_M] +¿No es fuerte y grande? + +[FM1_N] +¡Oye, tú, vamos a ver a Chico para que nos dé unas pirulas! + +[FM1_O] +Creo que está en la estación de ferrocarril del muelle de Chinatown. + +{ Mission instructions } + +[FM1_1] +~g~¡Vuelve al Stretch! + +[FM1_2] +~g~¡Entra en el Stretch! + +[FM1_3] +~r~Si abandonas a María, Salvatore hará que te maten. Vuelve y recógela. + +[FM1_4] +~g~¡Has dejado a la chica del Don tirada! ¡Vuelve al almacén y espera a María! + +[FM1_5] +~g~¡Lleva a María sana y salva con Salvatore! + +[FM1_6] +~g~¡Chico no estará esperando todo el día, lleva a María al muelle! + +[FM1_7] +~r~¡María está muerta! A Salvatore le va a sentar muy mal... + +[FM1_8] +~r~¡Te cargaste al camello de María! + +[FM1_P] +~g~Ese de ahí es Chico, párate cerca. + +[FM1_9] +~g~La fiesta es allí. Deja a María enfrente. + +[FM1_10] +~g~Has abandonado a María, vuelve y recógela. + +{ Cutscene when the player finds Chico } + +{ Chico, mexicano } + +[FM1_Q] +¡Ay, mira, es mi chica favorita! + +[FM1_Q1] +¿Quieres un poco de diversión? ¿Un poco de... hmmm, de SPANK? + +{ Maria } + +[FM1_R] +Hola, Chico. No, solo lo de siempre. + +{ Chico, mexicano } + +[FM1_S] +Aquí tienes, señorita. + +[FM1_S1] +Ey, deberías echar un vistazo a la fiesta del almacén en el lado este del muelle Atlantic. + +{ Maria } + +[FM1_T] +Gracias, Chico, nos vemos. + +{ Chico, mexicano } + +[FM1_U] +Gracias y disfruta. Es buen material. + +{ Maria } + +[FM1_V] +¡Venga, tú, vamos a ver esa fiesta! + +{ Cutscene when the player takes Maria to the party } + +{ Maria } + +[FM1_W] +Oye, tú, espera aquí y quédate pendiente del coche mientras yo voy a menear el esqueleto, ¿vale? + +{ Police dispatcher } + +[FM1_SS] +~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: asistan redada de narcóticos en el muelle Atlantic. + +{ Warehouse's guard } + +[FM1_TT] +¡UNA REDADA! + +{ Maria } + +[FM1_X] +¡Vale, tú, salgamos de aquí! ¡Uaaah! + +{ Cutscene when the player takes Maria back to Salvatore's home } + +{ Maria } + +[FM1_Y] +Quiero que sepas que me lo he pasado muy bien por primera vez en mucho tiempo y que me has tratado muy bien, con respeto. + +[FM1_AA] +Bueno, será mejor que me vaya. Espero que nos veamos pronto. + +{ ================================================================================ } +{ ================= MISSION: CUTTING THE GRASS (SALVATORE LEONE) ================= } +{ ================================================================================ } + +{ TITLE } + +[FM2] +'CORTANDO LA HIERBA' + +{ Premission cutscene } + +{ Salvatore } + +[FM2_J] +Déjanos a solas un momento. + +[FM2_A] +El cártel colombiano fabrica SPANK en Liberty, + +[FM2_K] +pero no sabemos dónde y parece como si supieran qué vamos a hacer antes de que lo pensemos. + +[FM2_B] +¡Tenemos a un chivato! + +[FM2_L] +Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. + +[FM2_M] +Ha estado gastando más dinero del que gana. + +[FM2_C] +No está ni chuleando ni traficando, así que estará cantando. + +[FM2_N] +Suele ir del trabajo a casa en taxi, así que síguelo. + +[FM2_O] +Y si nos está vendiendo... mátalo. + +{ Mission instructions } + +[FM2_1] +~g~¡Ahí está Curly Bob! + +[FM2_2] +~g~¡Curly ha salido del club, síguelo! + +[FM2_5] +~g~Llévale al puerto de Portland. + +[FM2_6] +~r~¡Curly no se meterá en un taxi cascado! + +[FM2_7] +~r~¡Curly se ha asustado! ¡Han cancelado la reunión! + +[FM2_8] +~g~¡Elimina a Curly Bob! + +[FM2_9] +~r~¡Curly Bob la ha espichado! + +[FM2_10] +~r~¡Curly se ha largado! + +[FM2_11] +~g~Aparca enfrente del club de Luigi; Curly Bob saldrá pronto. + +[FM2_12] +~r~¡Te ha dado esquinazo! + +[FM2_14] +~r~¡Te acercaste demasiado y asustaste a Curly! + +[FM2_15] +~g~No te acerques mucho, ¡o Curly sospechará! + +[FM2_16] +ASUSTÓMETRO: + +{ Cutscene that appears when successfully following Curly Bob } + +{ Miguel, colombiano } + +[FM2_F] +Aquí viene nuestro amiguito. El señor Bocazas en persona. + +{ Catalina, colombiana } + +[FM2_G] +¿Te han seguido? Ya sabes que esto es nuestro secretito. + +{ Curly Bob } + +[FM2_H] +No, no, no me han seguido. ¿Tienes lo mío? + +{ Catalina, colombiana } + +[FM2_I] +Toma tu SPANK, soplón, ahora habla. + +{ Curly Bob } + +[FM2_P] +Vale, los Leone libran una guerra en dos frentes. + +[FM2_Q] +Tienen una guerra territorial con las Tríadas y no parece que ninguno se vaya a rendir. + +[FM2_R] +Mientras tanto, Joey Leone ha cabreado a los Forelli. + +[FM2_S] +Cada día pierden más hombres e influencia. + +[FM2_T] +Salvatore se está volviendo peligroso y paranoico. Sospecha de todos y de todo. + +{ Catalina, colombiana } + +[FM2_U] +Con lo leales que son algunos, ¿de qué tendría que preocuparse? + +{ ================================================================================== } +{ ================= MISSION: BOMB DA BASE: ACT I (SALVATORE LEONE) ================= } +{ ================================================================================== } + +{ TITLE } + +[FM21] +'BASE FUERA: ACTO I' + +{ Premission cutscene } + +{ Salvatore } + +[FM3_A] +Tenemos que despachar a esos puñeteros colombianos, + +[FM3_B] +pero mientras estemos en guerra con las Tríadas, no tendremos la fuerza necesaria. + +[FM3_C] +El cártel tiene fondos ilimitados gracias a esa mierda del SPANK. + +[FM3_D] +Si les atacamos abiertamente, nos harán picadillo. + +[FM3_E] +Estarán fabricando el SPANK en ese barco grande al que te llevó Curly. + +[FM3_F] +Así que tenemos que actuar con cuidado, o mejor dicho, tú tienes que hacerlo. + +[FM3_G] +Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal para mí, Salvatore Leone. + +[FM3_H] +Si haces esto por mí, serás como de la familia. Todo lo que quieras. + +[FM3_I] +Ve a ver a 8-Ball, necesitarás su ayuda para volar ese barco. + +{ =================================================================================== } +{ ================= MISSION: BOMB DA BASE: ACT II (SALVATORE LEONE) ================= } +{ =================================================================================== } + +{ TITLE } + +[FM3] +'BASE FUERA: ACTO II' + +{ Premission cutscene, when not having 100.000 $ } + +{ 8-Ball } + +[FM3_8A] +¡Hombre, colega! Salvatore me avisó, + +[FM3_8B] +pero este trabajo va a necesitar muchos fuegos artificiales. + +[FM3_8C] +Necesitaré 100.000 $ para cubrir gastos, + +[FM3_8D] +pero ya sabes que conmigo valdrá la pena. + +[FM3_CC] +Regresa cuando tengas el dinero. + +{ Premission cutscene, when having 100.000 $ } + +{ 8-Ball } + +[FM3_8E] +Venga, ¡vamos allá! + +[FM3_8F] +Puedo reventar el barco, pero aún no puedo usar una pipa con estas manos. + +[FM3_8G] +¡Toma, este fusil te ayudará a volar unas cuántas cabezas! + +{ 8-Ball, when reaching the boat area } + +[FM3_8I] +Encuentra una posición elevada. Entraré cuando dispares el primer tiro. + +{ Mission instructions } + +[FM3_4] +~g~¡Para el coche y deja que 8-Ball salga! + +[FM3_7] +~r~¡8-Ball ha pasado a mejor vida! + +[FM3_8] +~r~¡Los guardias han sido alertados! + +{ ============================================================================ } +{ ================= MISSION: LAST REQUESTS (SALVATORE LEONE) ================= } +{ ============================================================================ } + +{ TITLE } + +[FM4] +'ÚLTIMA VOLUNTAD' + +{ Premission cutscene } + +{ Salvatore } + +[FM4_A] +¡Mi socio favorito! + +[FM4_B] +Estoy orgulloso de ti, hijo, pusiste finos a esos sudacas. + +[FM4_C] +Tengo un trabajito más para ti antes de que podamos celebrarlo. + +[FM4_D] +Hay un coche a la vuelta del edificio del club de Luigi. + +[FM4_E] +El interior está pringado de sesos. + +[FM4_F] +Tuvimos que ayudar a un tipo a que se decidiera y fue un poco... sucio. + +[FM4_H] +Llévalo a la trituradora antes de que lo encuentre la pasma. + +{ Pager message, appears right after getting into the target car } + +[FM4_1] +Soy María. ¡El coche es una trampa! Estoy en el lado sur del puente Callahan. + +{ Cutscene after reaching Maria } + +{ Maria } + +[FM4_2] +Mira, Salvatore cree que se la estamos jugando, + +[FM4_3] +así que te vendió al cártel para llegar a un trato. + +[FM4_4] +No podía permitírselo, o sea, lo peor es... + +[FM4_4B] +que yo tengo la culpa, porque le dije que somos pareja. + +[FM4_5] +¡No me preguntes por qué, no lo sé! + +[FM4_6] +Mira, la mafia te quiere muerto y yo también tengo que salir de aquí. + +[FM4_6B] +¡He visto demasiados asesinatos, demasiada sangre! + +[FM4_7] +Es una amiga mía, ¿vale?, una vieja amiga... Es Asuka, es de fiar. + +{ Asuka } + +[FM4_8] +Vamos, dejémonos de discursos. + +[FM4_9] +Mejor nos vamos antes de que haya más italianos histéricos con intenciones menos amistosas. + +{ Postmission cutscene } + +{ Maria } + +[LRQC_1] +Asuka y yo tenemos que hablar... + +[LRQC_2] +¿Por qué no te das una vuelta? + +{ Asuka } + +[LRQC_3] +Necesitarás un escondite. + +[LRQC_4] +Hay un almacén en la orilla de Belleville que podría servirte. + +[LRQC_5] +Regresa a mi apartamento cuando estés listo + +[LRQC_6] +y podremos tener una charla. + +{ ========================================================================================== } +{ ================= MISSION: SAYONARA SALVATORE (ASUKA KASEN, FIRST BATCH) ================= } +{ ========================================================================================== } + +{ TITLE } + +[AM1] +'SAYONARA, SALVATORE' + +{ Premission cutscene } + +{ Asuka } + +[AM1_A] +Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, + +[AM1_B] +sea de negocios u otra. Pongamos las cartas sobre la mesa. + +[AM1_C] +Soy yakuza y sé que trabajaste para la familia de Salvatore Leone. + +[AM1_D] +Puedo darte trabajo en nuestra organización, + +[AM1_E] +pero primero debes demostrarme que has cortado todos tus lazos con la mafia. + +{ Alternative subtitles that appear depending if the hour is single-digit or double digit, to make them uniform } + +[AM1_F] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (~1~:~1~) + +[AM1_K] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (0~1~:~1~) + +[AM1_G] +Asegúrate de que no salga con vida. + +[AM1_H] +Mientras tanto María y yo nos pondremos al día. + +{ Maria } + +[AM1_I] +Uy, Asuka, tienes un masajeador... + +{ Asuka } + +[AM1_J] +Eso no es un masajeador. + +{ Mission instructions } + +[AM1_1] +~g~¡Salvatore está saliendo del club de Luigi! + +[AM1_2] +~r~¡Te han descubierto! + +[AM1_3] +~r~¡Has perdido a Salvatore! + +[AM1_4] +~r~Muy bonito, ¡has asustado al objetivo! ¿Y te consideras un asesino? + +[AM1_5] +~g~Ve al barrio rojo y espera a que Salvatore salga del club. + +[AM1_6] +~g~Si te dejas ver por el club de Luigi, ¡la mafia te descubrirá! + +[AM1_7] +~r~Salvatore está en su casita, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar ''Chacal''! + +[AM1_8] +~g~Salvatore saldrá del club de Luigi sobre las ~1~:~1~. + +[AM1_10] +~g~Salvatore saldrá del club de Luigi sobre las 0~1~:~1~. + +[AM1_9] +~r~¡Salvatore ha vuelto a meterse en el club de Luigi! + +{ ========================================================================================== } +{ ================= MISSION: UNDER SURVEILLANCE (ASUKA KASEN, FIRST BATCH) ================= } +{ ========================================================================================== } + +{ TITLE } + +[AM2] +'BAJO VIGILANCIA' + +{ Premission cutscene } + +{ Asuka } + +[AM2_A] +La muerte de Salvatore es una placentera noticia, + +[AM2_A2] +eres un asesino eficaz. Eso me gusta en un hombre. + +[AM2_B] +Este es mi hermano Kenji. + +{ Kenji } + +[AM2_C] +Asuka tiene un trabajito para ti, pero cuando acabes, pásate por mi casino y podremos hablar. + +{ Asuka } + +[AM2_D] +Típico de Kenji, siempre está detrás de mis juguetes. + +{ The voiced dialogue doesn't match the English subtitles for the following strings } + +[AM2_E] +Mi contacto en la policía me dice que el FBI ha montado un operativo de vigilancia + +[AM2_E2] +en varios puntos de la ciudad. + +[AM2_F] +No tenemos tiempo para contactar con nadie y evitar que nos incriminen. + +[AM2_G] +Liquida a esos polis espías, pero cuidado: tendrán apoyo. + +{ Mission instructions } + +[AM2_4] +~g~¡Has irrumpido como un elefante en una cacharrería! + +{ ======================================================================================= } +{ ================= MISSION: PAPARAZZI PURGE (ASUKA KASEN, FIRST BATCH) ================= } +{ ======================================================================================= } + +{ TITLE } + +[AM3] +'PURGA DE PAPARAZZIS' + +{ Premission cutscene } + +{ Asuka (letter) } + +[AM3_A] +Un periodista ha estado husmeando por aquí. + +[AM3_B] +María y yo nos ido de vacaciones juntas hasta que puedas librarte de ese mirón pervertido. + +[AM3_C] +Ahora mismo estará probablemente en la bahía. ¡Roba una lancha de la policía y hunde su carrera! + +{ ======================================================================================= } +{ ================= MISSION: PAY DAY FOR RAY (ASUKA KASEN, FIRST BATCH) ================= } +{ ======================================================================================= } + +{ TITLE } + +[AM4] +'LA PAGA DE RAY' + +{ Premission cutscene } + +{ Asuka } + +[AM4_A] +¡Si es guapo manitas! + +[AM4_B] +María está un poquito liada, pero le diré que has venido. + +{ Maria } + +[AM4_C] +¿Quién es, Asuka? Sé que he sido muy traviesa, ¡pero necesito mear! ¿Vale? + +{ Asuka } + +[AM4_D] +Es hora de que conozcas a nuestro espía en la policía. + +[AM4_E] +Aquí está su pago por el último trabajito que hizo para nosotros. + +[AM4_F] +Él es comprensiblemente cauteloso. + +[AM4_G] +Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. + +{ Ray, on each payphone } + +[AM4_1A] +Ve a la cabina al oeste del Parque Belleville. + +[AM4_1B] +Ve a la cabina del Campus de Liberty. + +[AM4_1C] +Ve a la cabina al sur del Parque Belleville. + +[AM4_1D] +Ven a verme a los baños públicos del parque. + +{ Postmission cutscene } + +{ Ray } + +[AM4_3] +¡Tú debes de ser el nuevo chico de los recados de Asuka! + +[AM4_4] +¿Tienes el dinero? ¿Está todo? + +[AM4_5] +Ya sé lo que estás pensando, otro policía corrupto. + +[AM4_6] +Bueno, éste es un mundo corrupto. + +[AM4_7] +Pierdo a un par de socios y esos idiotas de asuntos internos empiezan a meter las narices. + +[AM4_8] +¡Y seguro que les llega mi olor! + +[AM4_9] +¡Pues esta ciudad es una gran alcantarilla! + +[AM4_10] +Pero voy a necesitar un ayudita ajena al cuerpo. + +[AM4_11] +Si estás interesado, ya sabes dónde encontrarme. + +{ ======================================================================================== } +{ ================= MISSION: TWO-FACED TANNER (ASUKA KASEN, FIRST BATCH) ================= } +{ ======================================================================================== } + +{ TITLE } + +[AM5] +'TANNER EL TRAIDOR' + +{ Premission cutscene } + +{ Asuka (letter) } + +[AM5_A] +María y yo hemos ido de compras. + +[AM5_B] +¡Nuestro contacto en la policía nos ha informado que uno de nuestros conductores es un poli infiltrado que se mueve de forma extraña! + +[AM5_C] +Fuera de su coche no sabe hacer casi nada, así que le hemos puesto un localizador. + +[AM5_D] +¡Haz que sufra! + +{ Mission instructions } + +[AM5_1] +¡Tanner te ha pillado! + +{ ========================================================================= } +{ ================= MISSION: KANBU BUST-OUT (KENJI KASEN) ================= } +{ ========================================================================= } + +{ TITLE } + +[KM1] +'LA FUGA DEL KANBU' + +{ Premission cutscene } + +{ Kenji } + +[KM1_A] +Mi hermana te tiene en gran estima, + +[KM1_E] +pero yo debo convencerme de que un gaijin puede ofrecerme algo más que desilusiones. + +[KM1_B] +Tal vez puedas ayudar con una situación que me tiene en desventaja. + +[KM1_F] +Por supuesto, el fracaso conllevará una desgracia. + +[KM1_C] +Un kanbu, o jefe de la yakuza, está bajo custodia a la espera de juicio. + +[KM1_G] +Es un miembro importante de la familia. + +[KM1_H] +Libéralo y llévatelo al dojo de Bedford Point. + +{ Pager message that appears after completing this mission } + +[KM1_D] +Te damos las gracias por tus generosas acciones. Si alguna vez necesitas ayuda, el dojo tendrá el honor de proporcionarte dos hombres que te ayudarán. + +{ Mission instructions } + +[KM1_1] +~g~¡Roba un coche de la policía! + +[KM1_2] +~g~¡Instala una bomba en el coche! + +[KM1_3] +~g~Ahora llévalo al dojo de la yakuza. + +[KM1_4] +~g~¡Necesitas un coche de policía para hacer el trabajo! + +[KM1_5] +~g~Ahora ve a la comisaría. + +[KM1_6] +~g~¡Pon una bomba en el coche! + +[KM1_7] +~g~¡Sólo pueden entrar vehículos de policía autorizados! + +[KM1_8A] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. + +[KM1_8D] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. + +[KM1_9] +~r~No destruiste la pared con un coche bomba. + +[KM1_10] +~r~El kanbu está muerto, ¡y tu honor también! + +[KM1_11] +~r~¡La policía te ha seguido! + +[KM1_12] +~g~¡Llévalo al dojo, pero deshazte primero de la policía! + +[KM1_13] +¡Mete el vehículo en el garaje! + +{ =========================================================================== } +{ ================= MISSION: GRAND THEFT AUTO (KENJI KASEN) ================= } +{ =========================================================================== } + +{ TITLE } + +[KM2] +'ROBO DE VEHÍCULOS' + +{ Premission cutscene } + +{ Kenji } + +[KM2_A] +Es imposible sobreestimar la importancia del protocolo en este trabajo. + +[KM2_B] +Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca pude corresponder su amabilidad. + +[KM2_C] +Su debilidad son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. + +[KM2_D] +No hace falta decir que debemos darle los coches como un regalo, para pagar mi deuda con él. + +[KM2_E] +Debes obtener los coches de la lista y llevarlos a un garaje que hay tras el aparcamiento de Newport. + +[KM2_F] +Mi honor lo exige. + +{ Mission instructions } + +[KM2_1] +~g~Repara el coche, tiene que estar en perfecto estado. + +[KM2_2] +~g~Coche entregado. + +[KM2_3] +~g~Recuerda que los ~r~coches ~g~tienen que estar en perfecto estado para ser aceptados en el ~p~garaje~g~. + +{ ===================================================================== } +{ ================= MISSION: DEAL STEAL (KENJI KASEN) ================= } +{ ===================================================================== } + +{ TITLE } + +[KM3] +'UN MAL TRATO' + +{ Premission cutscene } + +{ Kenji } + +[KM3_A] +Cuando los problemas acechan, el tonto les da la espalda, mientras que el sabio los enfrenta. + +[KM3_B] +El cártel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. + +[KM3_C] +Ahora están negociando con los jamaicanos para humillarnos aún más. + +[KM3_D] +Están cerrando un trato en la ciudad. + +[KM3_F] +Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus respetos a los colombianos. + +[KM3_E] +¡Nuestro honor exige que no dejes a nadie vivo! + +{ Mission instructions } + +[KM3_1] +~g~El cártel espera a una banda jamaicana, ¡así que roba uno de sus coches! Dirígete al norte; encontrarás uno en Newport. + +[KM3_2] +~g~Recoge a tu contacto. + +[KM3_3] +~g~¡La reunión está teniendo lugar en el aparcamiento del hospital de Rockford! + +[KM3_4] +~r~¡Han escapado! + +[KM3_5] +~g~Toca el claxon para empezar con el trato. + +[KM3_6] +~g~¡Mátalos, mátalos a todos! + +[KM3_7] +¡Es una trampa de la yakuza, tío! + +[KM3_8] +~g~¡Necesitas un coche de los jamaicanos para este trabajo! + +[KM3_9] +~r~Uno de los colombianos ha muerto, se ha cancelado el trato. + +[KM3_10] +~r~¡El contacto está muerto! + +[KM3_11] +~g~El cártel ha sido atacado y el maletín no ha sido recuperado. + +[KM3_12] +~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. + +[KM3_13] +~g~Lleva el maletín de vuelta al casino. + +[KM3_14] +~r~¡Te han descubierto, han cancelado el trato! + +{ ================================================================ } +{ ================= MISSION: SHIMA (KENJI KASEN) ================= } +{ ================================================================ } + +{ TITLE } + +[KM4] +'SHIMA' + +{ Premission cutscene } + +{ Kenji } + +[KM4_A] +Para ser verdaderamente fuerte, es importante no mostrar debilidad. + +[KM4_B] +El negocio es lo bastante afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. + +[KM4_C] +Hazte con el dinero inmediatamente para que podamos ingresarlo en las cuentas del casino. + +{ Cutscene after going to Uncle BJ's Deli & Groceries } + +{ Male shop owner } + +[KM4_1] +¡No puedo pagarte y no lo haría aunque pudiera! + +[KM4_9] +¡Una banda de chavales acaba de arrasar el local! ¡Se han llevado todo! + +[KM4_2] +¡Sois inútiles! + +[KM4_10] +Además, ¿qué clase de yakuza eres tú? + +{ Unused strings? } + +[KM4_3] +No pago a matones como vosotros para esto. Si quisiera esta clase de protección, llamaría a la policía, demonios. + +[KM4_6] +¡Aquí está todo el dinero! + +{ Pager message that tells the player Donald Love's missions are available } + +[KM4_5] +Donald Love desea que te pases por su jardín de té para tener una charla. + +{ Mission instructions } + +[KM4_4] +~g~¡Castiga a la banda responsable y recupera el ~b~dinero de la protección~g~! + +[KM4_7] +~r~¡El tendero la acaba de palmar! + +[KM4_8] +~g~¡Maletín recolectado! + +[KM4_11] +~g~¡Lleva el dinero de vuelta al casino! + +{ ===================================================================== } +{ ================= MISSION: SMACK DOWN (KENJI KASEN) ================= } +{ ===================================================================== } + +{ TITLE } + +[KM5] +'CONTRINCANTES TRAFICANTES' + +{ Premission cutscene } + +{ Kenji } + +[KM5_A] +¡Tú! ¡Qué oportuno por tu parte que muestres ahora tu despreciable cara! + +[KM5_B] +¡Parece que tus intentos para disuadir a los jamaicanos + +[KM5_B1] +de convertirse en aliados del cártel han sido totalmente inútiles! + +[KM5_C] +¡Los traficantes jamaicanos están llenando las calles de Liberty, vendiendo SPANK como si fueran perritos calientes! + +[KM5_D] +Estos cerdos del cártel se están riendo de nosotros, ¡de mí! + +[KM5_E] +¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene un buen motivo! + +[KM5_F] +¡Arrolla a estos canallas y lava tu vergüenza en el río de la sangre de nuestros enemigos! + +{ Mission instructions } + +[KM5_1] +~g~¡TRAFICANTE LIQUIDADO! + +[KM5_2] +~g~Uno de los jamaicanos se ha ido. + +[KM5_3] +~r~No has matado a ~1~ jamaicanos. + +[KM5_4] +~g~Enhorabuena, has matado a ~1~ jamaicanos. + +[KM5_5] +~g~Enhorabuena, has matado a ~1~ jamaicanos. ~1~$ ADICIONALES + +[KM5_6] +~g~Debes matar a al menos 8 traficantes jamaicanos. + +[KM5_7] +~g~¡Mátalos rápido! En cuanto vendan el SPANK se retirarán de las calles. + +{ ================================================================================= } +{ ================= MISSION: BLING-BLING SCRAMBLE (KING COURTNEY) ================= } +{ ================================================================================= } + +{ TITLE } + +[YD1] +'CORRE A POR LA PASTA' + +{ Pager message that appears when the Yardies missions are available } + +[YD_P] +El Rey Courtney quiere hablarte. ¡Ve al teléfono público de Aspatria! + +{ Premission cutscene } + +{ King Courtney } + +[YD1_A] +Habla el rey Courtney. + +[YD1_A1] +Mi banda jamaicana necesita un conductor y tú tienes reputación de ser bueno. + +[YD1_B] +Ve en un coche al basurero que hay detrás del estadio y a los otros candidatos. + +[YD1_C] +Tengo hombres vigilando puntos de control por toda Staunton. + +[YD1_D] +El primer conductor que llegue a un punto de control se lleva mil pavos, y así de punto a punto. + +[YD1_D1] +Si ganas más puntos de control que los demás, podría tener trabajo para ti. + +{ Mission instructions } + +[YD1_E] +~g~¡Prepárate! + +[YD1_F] +~g~Te has saltado la salida. ¡Me gusta tu estilo! + +[YD1_G] +~r~Esto es una carrera DE COCHES. ¡Necesitas un COCHE, idiota! + +[YD1GO] +~g~¡VAMOS! + +[YD1_1] +~r~1 + +[YD1_2] +~r~2 + +[YD1_3] +~r~3 + +[YD1_BON] +¡1.000$! + +[Y1_1ST] +~G~¡Has quedado primero con ~1~ puntos de control! + +[Y1_2ND] +~y~Eres el segundo con ~1~ puntos de control. ~y~¡Casi, pero no! + +[Y1_3RD] +~r~Eres el tercero con ~1~ puntos de control. ~r~¿No decías que eras bueno? + +[Y1_LAST] +~r~¡Has quedado el último! ~r~¡Me has hecho perder el tiempo, IDIOTA! + +[Y1_J1ST] +~y~Has empatado el primero con ~1~ puntos de control. ~y~Bien, ¡pero debes ser el mejor si quieres conducir para la Reina Lizzy! + +[Y1_J2ND] +~r~Has empatado el segundo con ~1~ puntos de control. ¡Conduces como un mono loco! + +[Y1JLAST] +~r~¡Has empatado el último! ¡Hablas como un conductor, pero conduces como un hablador! + +[Y1_TEST] +¡COCHE AL AGUA! + +[YD1_CNT] +¡~1~ de 15! + +{ ====================================================================== } +{ ================= MISSION: UZI RIDER (KING COURTNEY) ================= } +{ ====================================================================== } + +{ TITLE } + +[YD2] +'JINETE CON UZI' + +{ Premission cutscene } + +{ King Courtney } + +[YD2_A] +Necesito ver si eres capaz de hacer mi trabajo sucio, + +[YD2_A1] +si se puede confiar en ti. + +[YD2_B] +Dos de mis chicos llegarán allí enseguida para llevarte de paseo, + +[YD2_B1] +a ver si eres quien dices que eres. + +{ Dialogue from Yardie after reaching you } + +[YD2_C] +Vamos a dar un paseíto por los cerros de Hepburn para cargarnos a los asquerosos Diablos que han estado metiéndose con la reina Lizzy. + +[YD2_D] +Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te eches atrás. + +[YD2_CC] +Toma, necesitarás una pipa. + +{ Dialogue from Yardie after entering the car } + +[YD2_E] +¡Conduce! + +{ Dialogue from Yardie when trying to get out of the car } + +[YD2_F] +~r~Se quiere escapar, ¡cárgatelo! + +{ Dialogue from Yardie after reaching the objective area } + +[YD2_G1] +Los cerros de Hepburn... Vamos a matar a algunos asquerosos Diablos... + +[YD2_G2] +Pero recuerda, ~r~¡no salgas de este coche! + +{ Dialogue from Yardie after killing the targets } + +[YD2_H] +¡Vale, ya está! ¡Llévanos de vuelta a territorio jamaicano! ¡Vamos, vamos, vamos! + +{ Dialogue from Yardie after taking them to the final goal } + +[YD2_L] +¡Eres la Muerte personificada! + +{ Dialogue from Yardie after trashing the car } + +[YD2_M] +~r~¡Ha destrozado mi coche! ¡Liquídale! + +{ Dialogue from Yardie when you are allowed to leave the car, but you must be in it } + +[YD2_N] +¡Vuelve al coche! + +{ ============================================================================= } +{ ================= MISSION: GANGCAR ROUND-UP (KING COURTNEY) ================= } +{ ============================================================================= } + +{ TITLE } + +[YD3] +'COLECCIONANDO COCHES DE BANDAS' + +{ Premission cutscene } + +{ King Courtney } + +[YD3_A] +Quiero que robes coches de otras bandas + +[YD3_A1] +para que podamos atacar sus territorios. + +[YD3_B] +Necesito un Mafia Sentinel, + +[YD3_B1] +un Yakuza Stinger y un + +[YD3_B2] +Diablo Stallion para que podamos ir a por cualquier banda de Liberty. + +[YD3_C] +Déjalos en el garaje de Newport y recuerda, + +[YD3_C1] +¡dañados no nos sirven de nada! + +[YD3_D] +UNUSED + +{ Mission instructions } + +[YD3_E] +~r~¡Ya has entregado un coche de los Diablos! + +[YD3_F] +~r~¡Ya has entregado un coche de la mafia! + +[YD3_G] +~r~¡Ya has entregado un coche de la yakuza! + +[YD3_H] +~g~¡Coche de los Diablos entregado! + +[YD3_I] +~g~¡Coche de la mafia entregado! + +[YD3_J] +~g~¡Coche de la yakuza entregado! + +[YD3_K] +~r~¡El coche está casi destrozado! ¡Haz que lo reparen! + +[YD3_L] +~g~¡Llévalo al ~p~garaje~g~! + +[YD3_M] +~r~¡Has volcado el vehículo! ¡Consigue otro! + +{ ========================================================================= } +{ ================= MISSION: KINGDOM COME (KING COURTNEY) ================= } +{ ========================================================================= } + +{ TITLE } + +[YD4] +'POR LOS AIRES' + +{ Premission cutscene } + +{ King Courtney } + +[YD4_A] +¡Escucha! + +[YD4_A1] +Mueve el culo a Bedford Point. + +[YD4_A2] +¡Hay un cargamento en una tartana que necesito pronto! + +{ Cutscene after entering the target car } + +{ Catalina, colombiana } + +[YD4_B] +CARTA: Dicen que estuviste entretenido. Igual que yo. + +[YD4_C] +¡Es hora de que seas testigo del verdadero poder del 'SPANK'! Con mucho amor, Catalina. + +[YD4_D] +P.D. ¡MUERE, BASURA, MUERE! + +{ Mission instructions } + +[YD4_1] +~g~¡Son psicópatas adictos al SPANK! + +[YD4_2] +~g~¡Destruye las furgonetas de SPANK! + +{ ============================================================================== } +{ ================= MISSION: SILENCE THE SNEAK (RAY MACHOWSKI) ================= } +{ ============================================================================== } + +{ TITLE } + +[RM1] +'SILENCIA AL SOPLÓN' + +{ Premission cutscene } + +{ Ray } + +[RM1_A] +¡Ese canalla de McAffrey...! ¡Aceptó más sobornos que nadie, + +[RM1_B] +se piensa que le darán la pensión completa si se convierte en un testigo de cargo! + +[RM1_C] +¡Y ha cantado! + +[RM1_D] +Se encuentra bajo protección armada en una propiedad de WitSec en el centro de Newport, en algún piso que hay detrás del aparcamiento. + +[RM1_E] +Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con nadie. + +{ Mission instructions } + +[RM1_1] +~g~Ve a la casa de protección de testigos. + +[RM1_2] +~g~¡Cárgate a McAffrey! + +[RM1_3] +~r~¡McAffrey se ha escapado! + +[RM1_4] +~g~¡Has usado todas las granadas! ¡Consigue más en la tienda Ammu-Nation! + +[RM1_5] +~g~¡Vuelve y quema la casa franca! + +{ ========================================================================== } +{ ================= MISSION: ARMS SHORTAGE (RAY MACHOWSKI) ================= } +{ ========================================================================== } + +{ TITLE } + +[RM2] +'ESCASEZ DE MANOS' + +{ Premission cutscene } + +{ Ray } + +[RM2_A1] +¡Chico, estoy aquí! + +[RM2_A] +Un viejo colega del ejército tiene un negocio en Rockford. + +[RM2_B] +Combatimos juntos en Nicaragua, cuando el país sabía lo que hacía. + +[RM2_C] +En fin, ayer unos cerdos del cártel lo zurraron y le dijeron que volverían hoy para quitarle parte de su stock. + +[RM2_D] +Va a necesitar respaldo y a cambio te venderá material de todo tipo a precios de ganga. + +[RM2_D1] +Iría yo mismo, pero la ciática ya está en sus trece... ¡Cof, cof! Así que... buena suerte. + +{ Cutscene, appears when finding Phil } + +{ Phil } + +[RM2_E] +Ray me avisó... Pero pensé que vendría más gente. + +[RM2_E1] +¡No puedo creer que esos mamones amarillos me hayan vuelto a dejar con el culo al aire! + +[RM2_F] +Bueno, tres brazos son mejor que uno, así que sírvete. + +[RM2_F1] +¡Los colombianos llegarán en cualquier momento! + +{ Dialogue from Phil, when the Colombians arrive } + +[RM2_K] +Maldita sea, ¡están aquí! ¡FUEGO A DISCRECIÓN! + +{ Dialogue from Phil, when the Colombians are killed } + +[RM2_L] +¡Caray! ¡Si hubieras estado a mi lado en Nicaragua, a lo mejor conservaría el brazo! + +[RM2_M] +Si necesitas armas nuevas, pasa por aquí y coge lo que necesites de las taquillas. + +[RM2_N] +Deja el dinero en el suelo. Ahora vete, ya me ocupo yo de la poli. + +{ Mission instructions } + +[RM2_G] +~g~¡Ve a ver a Phil! + +[RM2_H] +~r~¡Han matado a Phil! + +{ ========================================================================== } +{ ================= MISSION: EVIDENCE DASH (RAY MACHOWSKI) ================= } +{ ========================================================================== } + +{ TITLE } + +[RM3] +'FALTA DE PRUEBAS' + +{ Premission cutscene } + +{ Ray } + +[RM3_A] +Conozco a un pez gordo de la ciudad, un tipo muy cándido, + +[RM3_H] +con, digamos... gustos exóticos y el dinero para pagárselos. + +[RM3_B] +Está involucrado en un asunto legal y la fiscalía tiene fotos de él muy comprometedoras + +[RM3_C] +en una fiesta en la morgue o algo así. + +[RM3_D] +Están transportando las pruebas por la ciudad. + +[RM3_E] +Tendrás que embestir al coche y recoger hasta la última prueba que se le caiga. + +[RM3_F] +En cuanto tengas todas, déjalas en tu coche y préndele fuego. + +[RM3_G] +Cuando acabes, nos irá mucho mejor, chico. + +{ Mission instructions } + +[RM3_1] +~g~Deja las pruebas en un coche y después préndele fuego. + +[RM3_4] +~g~¡Al fiscal se le ha caído una prueba! + +[RM3_5] +~g~Tienes ~1~ de 6 paquetes de pruebas. + +[RM3_6] +~r~¡Las fotos circularán por toda la ciudad! + +[RM3_7] +~g~¡Ahora préndele fuego al coche! + +[RM3_8] +~r~¡El coche es un señuelo! + +{ ========================================================================= } +{ ================= MISSION: GONE FISHING (RAY MACHOWSKI) ================= } +{ ========================================================================= } + +{ TITLE } + +[RM4] +'DE PESCA' + +{ Premission cutscene } + +{ Ray } + +[RM4_A] +Creo que mi socio es un soplón. + +[RM4_B] +Tenemos que cerrarle la boca para siempre. + +[RM4_C] +Casi todas las noches sale a pescar con su lancha cerca del faro que hay en Portland Rock. + +[RM4_D] +¡Roba una lancha de la policía y asegúrate de que se le acaben las ganas de dar puñaladas traperas! + +[RM4_E] +¡Quiero que se vaya a dormir con los peces, en vez de comérselos! + +{ Mission instructions } + +[RM4_1] +~g~Ve y roba una lancha de la policía. + +[RM4_2] +~g~¡Ve al faro y ''hunde'' al socio de Ray! + +[RM4_3] +~r~¡El socio de Ray ha escapado! + +{ ============================================================================ } +{ ================= MISSION: PLASTER BLASTER (RAY MACHOWSKI) ================= } +{ ============================================================================ } + +{ TITLE } + +[RM5] +'DESESCAYOLADOR' + +{ Premission cutscene } + +{ Ray } + +[RM5_A] +¡Inútil de mierda! + +[RM5_A1] +¡La has cagado! Me la estoy jugando y ni siquiera eres capaz de matar a una maldita mosca. + +[RM5_B] +¡Te pagué una pasta para matar al testigo y aún sigue vivo! + +[RM5_B1] +¡Y hoy va a declarar ante los federales! + +[RM5_C] +Está a punto de ser trasladado del hospital general Carson, en Rockford. + +[RM5_D] +Si él canta, yo canto... + +[RM5_E] +¡así que termina el trabajo por el que te pagué! + +{ Mission instructions } + +[RM5_1] +~g~Intercepta la ambulancia. + +[RM5_2] +~g~¡Te han descubierto! + +[RM5_3] +~g~¡Era un señuelo! + +[RM5_4] +~g~¡Las balas no penetran en esa escayola de cuerpo entero! + +[RM5_5] +~g~¡Esa escayola de cuerpo entero es ignífugo! + +[RM5_6] +~g~¡Ha salido de la ambulancia! ¡Cárgate su escayola con un vehículo o una explosión! + +[RM5_7] +~r~¡El testigo está a salvo! + +[RM5_8] +~g~¡El testigo se ha ahogado! + +{ ======================================================================= } +{ ================= MISSION: MARKED MAN (RAY MACHOWSKI) ================= } +{ ======================================================================= } + +{ TITLE } + +[RM6] +'HOMBRE MUERTO' + +{ Premission cutscene } + +{ Ray } + +[RM6_A] +¿No te han seguido? Bien. + +[RM6_B] +Se acabó, ¡esto se me va de las manos y estoy con la soga al cuello! + +[RM6_C] +La CIA parece estar interesada en el SPANK + +[RM6_C1] +y no les gusta que nos metamos con el cártel. + +[RM6_D] +Soy hombre muerto, así que tengo que largarme. + +[RM6_E] +¡Consigue que no pierda mi vuelo en el aeropuerto y haré que tu trabajo haya merecido la pena! + +{ Cutscene, appears when Ray has been taken safely to the airport } + +[RM6_1] +Esta llave es de un almacén. + +[RM6_2] +Encontrarás dinero en metálico y ''suministros'' que guardé por si las cosas se ponían feas. + +[RM6_3] +Hasta la vista. + +{ Pager message that appears when reaching Ray's lockup } + +[RM6_666] +Cuida mi Patriot a prueba de balas. Nos vemos en Miami, Ray + +{ Mission instructions } + +[RM6_4] +~g~Ve al almacén a por el cargamento de Ray. + +[RM6_5] +~g~La CIA vigila el puente, busca otro camino. + +[RM6_6] +~r~¡Ray ha muerto! + +[RM6_7] +~r~¡Ray ha perdido su avión! + +[RM6_8] +~g~Has abandonado a Ray, vuelve a por él. + +{ ==================================================================== } +{ ================= MISSION: LIBERATOR (DONALD LOVE) ================= } +{ ==================================================================== } + +{ TITLE } + +[LOVE1] +'EL LIBERADOR' + +{ Premission cutscene } + +{ Donald Love } + +[LOVE1_A] +Antes que nada, permíteme agradecerte que te hayas ocupado de ese asunto personal. + +[LOVE1_F] +Últimamente la gente tiende a malinterpretar las cosas. + +[LOVE1_B] +La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, + +[LOVE1_H] +pero los grupos de hombres se vuelven codiciosos. + +[LOVE1_C] +Un activo valioso, un anciano oriental que conozco, + +[LOVE1_I] +está siendo retenido por unos sudamericanos en Aspatria. + +[LOVE1_D] +Pretenden exigirme más de lo pactado, pero no me gusta renegociar. + +[LOVE1_E] +Un trato es un trato, así que no van a ver ni un dólar mío. + +[LOVE1_G] +Rescata a mi amigo cueste lo que cueste. + +{ Mission instructions } + +[LOVE1_1] +~g~Roba un coche de la banda colombiana para que puedas entrar en su escondite. Dirígete hacia el norte; podrás encontrar uno en Fort Staunton. + +[LOVE1_2] +~g~Rescata al anciano oriental. + +[LOVE1_3] +~g~Lleva al anciano oriental de vuelta al edificio de Donald Love. + +[LOVE1_4] +~g~El anciano oriental debe estar detrás de alguna de estas puertas... + +[LOVE1_5] +~g~Deja de perder el tiempo, hazte con un coche de los colombianos y rescata al socio de Love. + +[LOVE1_6] +~r~¡Las tripas del anciano oriental están desparramadas por las calles! + +[LOVE1_7] +~g~La puerta sólo se abrirá ante un coche de los colombianos. + +{ =============================================================================== } +{ ================= MISSION: WAKA-GASHIRA WIPEOUT (DONALD LOVE) ================= } +{ =============================================================================== } + +{ TITLE } + +[LOVE2] +'¡EXTERMINA AL WAKA-GASHIRA!' + +{ Premission cutscene } + +{ Donald Love } + +[LOVE2_A] +No hay nada como una clásica guerra de bandas para hacer que bajen los precios de las viviendas, + +[LOVE2_B] +excepto una plaga... pero eso sería excesivo en este caso. + +[LOVE2_C] +He observado que la yakuza y los colombianos no son precisamente buenos amigos. + +[LOVE2_D] +Vamos a aprovechar esta oportunidad de negocio. + +[LOVE2_E] +Quiero que mates a Kenji Kasen, el waka-gashira (segundo al mando) de la yakuza. + +[LOVE2_F] +Kenji está asistiendo a una reunión en lo alto del aparcamiento de Newport. + +[LOVE2_G] +¡Hazte con un coche de la banda del cártel y elimínalo! + +[LOVE2_H] +La yakuza debe culpar al cártel de esta declaración de guerra. + +{ Mission instructions } + +[LOVE2_1] +~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! + +[LOVE2_2] +~g~¡Ahora ve al ~p~aparcamiento de Newport~g~ y cárgate a Kenji! + +[LOVE2_3] +~r~¡Si no llevas un coche del cártel, te descubrirán! + +[LOVE2_4] +~r~¡La yakuza te ha reconocido! + +[LOVE2_5] +~g~¡Kenji ha palmado! ¡Sal de Newport y deshazte del coche! + +[LOVE2_6] +~r~¡Has matado a todos los testigos! + +[LOVE2_7] +~g~¡Ahora deshazte del coche! + +[LOVE2_8] +~g~¡Sal de Newport! + +{ ============================================================================== } +{ ================= MISSION: A DROP IN THE OCEAN (DONALD LOVE) ================= } +{ ============================================================================== } + +{ TITLE } + +[LOVE3] +'UNA GOTA EN EL OCÉANO' + +{ Premission cutscene } + +{ Donald Love } + +[LOVE3_A] +En estos días de hipocresía moral, ciertos artículos pueden resultar difíciles de importar. + +[LOVE3_B] +Esta noche, durante su aproximación al aeropuerto, una avioneta sobrevolará la bahía. + +[LOVE3_C] +Echará varios paquetes al agua. + +[LOVE3_D] +Asegúrate de los consigues antes que nadie. + +{ Mission instructions } + +[LOVE3_1] +~g~¡Consigue una ~r~lancha~g~ y sigue a la ~y~avioneta~g~! + +[LOVE3_2] +~g~¡Tienes todos los paquetes! Llévaselos a Donald Love. + +[LOVE3_3] +~g~La avioneta ha tirado ~1~ de los 6 paquetes. + +[LOVE3_4] +~r~¡Has destruido el avión! + +[LOVE3_5] +~g~La avioneta está ahora a tu alcance. + +[LOVE3_6] +~r~¡La bofia ha llegado a los paquetes antes que tú! + +{ =========================================================================== } +{ ================= MISSION: GRAND THEFT AERO (DONALD LOVE) ================= } +{ =========================================================================== } + +{ TITLE } + +[LOVE4] +'ROBO DE ALTOS VUELOS' + +{ Premission cutscene } + +{ Donald Love } + +[LOVE4_A] +Gracias por conseguir esos paquetes, pero sólo eran un señuelo. + +[LOVE4_B] +Lo siento, pero a veces los negocios son así. + +[LOVE4_C] +Mi verdadero objetivo se ocultaba en la avioneta. + +[LOVE4_D] +Desgraciadamente, las autoridades aduaneras registraron la avioneta y la comenzaron a desmontar + +[LOVE4_H] +hasta que yo intervine a través de mi fortuna. + +[LOVE4_E] +Cruza el puente hacia Shoreside Vale y ve al Aeropuerto Internacional Francis. + +[LOVE4_F] +He sobornado a los funcionarios. + +[LOVE4_G] +Mis pertenencias estarán esperándote en el hangar de aduanas, dentro de la avioneta. + +{ Cutscene, when going up into the construction area's elevator, finding Catalina, Miguel and Asuka } + +{ Catalina, colombiana } + +[GTAB_A] +Oye, saquemos esto de aquí. Dios sabrá lo que será, + +[GTAB_B] +pero él lo quiere a toda costa, así que tendrá algún valor. + +{ Miguel, colombiano } + +[GTAB_C] +¡¿Qué diablos?! + +{ Catalina, colombiana } + +[GTAB_D] +¡TÚ! + +{ Miguel, colombiano } + +[GTAB_E] +¡Tranquilo, amigo! ¡No es nada! ¡No es nada! + +{ Catalina, colombiana } + +[GTAB_F] +¡Te dejé desangrándote entre la basura! + +{ Miguel, colombiano } + +[GTAB_G] +No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. + +{ Catalina, colombiana } + +[GTAB_H] +¡No seas cagón! + +{ Miguel, colombiano } + +[GTAB_I] +¡No tenemos elección, nena! + +{ Catalina, colombiana } + +[GTAB_J] +¡Siempre la hay, imbécil! + +{ Miguel, colombiano } + +[GTAB_K] +¡Siento mucho lo de esa perra enloquecida, todas son iguales... ¿Por favor? + +{ Asuka } + +[GTAB_L] +Así que la zorra se fue. + +[GTAB_M] +Pero me has hecho un favor, + +[GTAB_N] +no eres el único que tiene una cuenta pendiente con el cártel... + +[GTAB_O] +¡Este gusano mató a mi hermano! + +{ Miguel, colombiano } + +[GTAB_P] +¡Nunca maté a ningún yakuza! + +{ Asuka } + +[GTAB_Q] +¡Mientes! Todos vimos al asesino del cártel. + +[GTAB_R] +¡Vamos a cazaros y a mataros a todos, perros colombianos! + +[GTAB_S] +Me trabajaré a nuestro querido amigo para extraerle información y un poco de placer. + +[GTAB_T] +Tú, ven más tarde, estoy segura de que voy a necesitar tus servicios. + +{ Miguel, colombiano } + +[GTAB_U] +¡Por favor, amigo! ¡No me dejes con ella, esa chica está loca! ¿Amigo? ¡Oye, amigo! ¡Amigo...! + +{ Mission instructions } + +[LOVE4_1] +~r~¡El cártel colombiano está aquí! + +[LOVE4_2] +~g~¡El paquete ha desparecido! Síguele la pista a los colombianos y recupéralo. + +[LOVE4_3] +~g~¿''Panlantic Construction''...? + +[LOVE4_7] +~g~Hay una zona en obras en Staunton Island, puede que hayan llevado el paquete allí. + +[LOVE4_4] +~g~¡Lleva el paquete a Donald Love! + +[LOVE4_5] +~g~El paquete debería estar en la avioneta... + +[LOVE4_6] +~g~¡Usa el ascensor! + +[LOVE4_8] +~g~Necesitarás un coche para abrir el garaje. + +[LOVE4_9] +~r~¡El avión ha sido destruido! + +[LOV4_10] +~r~¡La única pista sobre dónde se encuentra el paquete ha sido destruida! + +{ ========================================================================= } +{ ================= MISSION: ESCORT SERVICE (DONALD LOVE) ================= } +{ ========================================================================= } + +{ TITLE } + +[LOVE5] +'SERVICIO DE ESCOLTA' + +{ Premission cutscene } + +{ Donald Love } + +[LOVE5_A] +Estás demostrando ser una inversión segura, algo muy raro en estos días. + +[LOVE5_B] +Mi amigo oriental necesitará que le escolten mientras comprueba la autenticidad de mi última adquisición. + +[LOVE5_C] +Quiero que le sigas, asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. + +{ Mission instructions } + +[LOVE5_1] +~g~¡En marcha! + +[LOVE5_2] +~g~¡Vas a necesitar un coche! + +[LOVE5_3] +~g~¡Comprueba la salida del túnel! + +[LOVE5_4] +~r~¡Protege el camión! + +[LOVE5_5] +~r~¡No has protegido al camión! + +{ ================================================================ } +{ ================= MISSION: DECOY (DONALD LOVE) ================= } +{ ================================================================ } + +{ TITLE } + +[LOVE6] +'SEÑUELO' + +{ Premission cutscene } + +{ Donald Love } + +[LOVE6_A] +Una lección sobre negocios, amigo mío: + +[LOVE6_E] +Si tienes una mercancía única, todo el mundo tratará de arrebatártela, + +[LOVE6_B] +aun sin conocer su verdadera valía. + +[LOVE6_C] +Unos SWAT han acordonado la zona donde se encuentran mi socio y el paquete. + +[LOVE6_D] +Ve allí, recoge la furgoneta y haz de señuelo. + +[LOVE6_F] +Mantenles ocupados y él podrá escaparse. + +{ Mission instructions } + +[LOVE6_1] +~g~¡Ahora llévate a los policías lejos del almacén! + +[LOVE6_2] +~r~¡No has distraído a la policía! + +[LOVE6_3] +~g~Tienes ~1~ segundos para volver al Securicar antes de fracasar la misión. + +[LOVE6_4] +~r~¡Has abandonado el Securicar señuelo! + +{ =============================================================================== } +{ ================= MISSION: LOVE'S DISAPPEARANCE (DONALD LOVE) ================= } +{ =============================================================================== } + +{ TITLE } + +[LOVE7] +'LA DESAPARICIÓN DE LOVE' + +{ No dialogue or strings } + +{ ============================================================== } +{ ================= MISSION: UZI MONEY (D-ICE) ================= } +{ ============================================================== } + +{ TITLE } + +[HM_1] +'PASADA AMETRALLADA' + +{ Pager message that tells the player that D-Ice's missions are now available } + +[HOOD1_A] +Ve al teléfono público de Wichita Gardens y hablaremos de negocios. + +{ Premission cutscene } + +{ D-Ice } + +[HM1_A] +¡Ey! ¡Soy D-Ice, de los Red Jacks! + +[HM1_B] +Tengo un problema, me la están liando. + +[HM1_C] +Hay unos macarrillas en la calle que no piensan más que en pistolas y en SPANK. + +[HM1_D] +Se llaman ''Nines'', van de púrpura, y cada día en el que se hacen notar + +[HM1_G] +es otro día más que los Jacks parecemos blandos. [HM1_E] -Quiero mostrarle a esos perros macarras cómo funciona un verdadero tiroteo desde un vehículo +Quiero que esos mierdecillas sepan lo que es un verdadero tiroteo desde un vehículo. [HM1_H] -¡Llévate a esos nueve fuera de aquí!! +¡Haz que esos Nines se larguen! + +[HM1_F] +Pero ojo, también habrá Jacks que se creerán que vas a por ellos. + +{ Mission instructions } + +[HM1_1] +~g~Cepíllate a 20 Purple Nines en 2 minutos y 30 segundos. + +[HM1_2] +~g~Hazte con un vehículo y recuerda que sólo cuentan las muertes a tiros desde el coche. + +[HM1_3] +~g~Los Nines tienen su territorio en Wichita Gardens. + +{ =============================================================== } +{ ================= MISSION: TOYMINATOR (D-ICE) ================= } +{ =============================================================== } + +{ TITLE } + +[HM_2] +'BOMBINATOR' + +{ Premission cutscene } + +{ D-Ice } [HM2_A] -Esos Nines me están presionando. +Los Nines me están presionando. [HM2_B] -Esos perros tienen coches blindados y están traficando con SPANK... +Tienen coches blindados y ahora están traficando SPANK [HM2_C] -y colocándoselo a los hermanos sin pudor. +a los hermanos sin ningún pudor. [HM2_D] -Hay un coche aparcado arriba de la calle. +Hay un coche aparcado en la calle. [HM2_E] -Hay algo de material allí dentro para poner a esos mariquitas en su sitio... +Dentro verás algo que te servirá para poner a esos gallinas en su sitio + +[HM2_F] +y cargarte sus blindados. + +{ Mission instructions } + +[HM2_1] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. + +[HM2_1A] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. + +[HM2_2] +~r~¡No has destruido todos los furgones blindados! + +[HM2_6] +~g~¡Te has cargado un furgón blindado! + +[HM2_3] +¡Si golpeas las ruedas de un vehículo, el coche teledirigido estallará! + +[HM2_4] +¡Si el coche teledirigido se sale fuera de cobertura, estallará solo! + +[HM2_5] +~r~¡Te has ido de cobertura! + +{ =================================================================== } +{ ================= MISSION: RIGGED TO BLOW (D-ICE) ================= } +{ =================================================================== } + +{ TITLE } + +[HM_3] +'PREPARADO PARA ESTALLAR' + +{ Premission cutscene } + +{ D-Ice } [HM3_A] -Algún effa ha cableado mis ruedas para bolarlas. +Algún cazurro me ha puesto una bomba en el coche. [HM3_B] -Si pierdo esas ruedas, mi reputación en la calle estará muerta. +Si lo pierdo, mi reputación en la calle se irá a la porra. [HM3_C] -Coge mi coche y llévalo al garaje de St Marks, ¿vale tío? +Coge mi coche y llévalo al taller de Saint Mark's, ¿valiendo? [HM3_D] -Déjales difundir eso, déjales que se ocupen de esa bomba. +Que se encarguen ellos de desarmar la bomba. [HM3_E] -Los relojes están avanzando y el cableado está liado. +El tiempo avanza y ese trasto es un peligro. [HM3_F] -Otro fallo más y esa cosa podría volar. +Un golpe más de la cuenta y podría saltar por los aires. [HM3_G] -¡Ahora muévelo! +¡Tira! + +{ Mission instructions } + +[HM3_1] +~g~¡Ve al garaje, pero pon atención, porque el coche explotará si se daña demasiado! + +[HM3_2] +~g~Lleva el coche de vuelta. ¡Tiene que estar inmaculado! + +[HM3_3] +~g~¡Haz que reparen el vehículo! + +{ ================================================================ } +{ ================= MISSION: BULLION RUN (D-ICE) ================= } +{ ================================================================ } + +{ TITLE } + +[HM_4] +'FIEBRE DEL PLATINO' + +{ Premission cutscene } + +{ D-Ice } [HM4_A] -Tío, un vuelo de la Reserva federal se acaba de estrellar en el Francis International. +Tío, un vuelo de la Reserva Federal se la acaba de pegar en el Aeropuerto Francis. [HM4_B] Hay platino por toda la pista. @@ -4532,739 +5417,515 @@ Hay platino por toda la pista. Consigue un coche y agarra todo lo que puedas. [HM4_F] -Puedes dejar el marrón en uno de mis garajes. +Puedes dejar la mercancía en uno de mis garajes. [HM4_G] -Este platino es muy pesado y va a hacer que tus ruedas se muevan más despacio. +El platino pesa un huevo y hará que tu buga vaya a paso de tortuga, [HM4_H] -Así que haz repartos regulares en el garaje. +así que ve dejándolo de vez en cuando en el garaje. + +{ Mission instructions } + +[HM4_D] +~g~¡Hazte con un vehículo! + +[HM4_1] +~g~Dirígete al lugar donde está el cargamento. Necesitas conseguir 30 lingotes. + +[HM4_2] +~g~Recuerda: cuando el vehículo esté pesado y vaya más despacio, ve al garaje y deja el cargamento. + +[HM4_E] +UNUSED + +{ =========================================================== } +{ ================= MISSION: RUMBLE (D-ICE) ================= } +{ =========================================================== } + +{ TITLE } + +[HM_5] +'ENFRENTAMIENTO' + +{ Premission cutscene } + +{ D-Ice } [HM5_A] -Esos Nines se han quedado con pocos costrosos... +Ya solo quedan unos pocos Nines, [HM5_B] -pero todavía quieren seguir. +pero todavía quieren guerra. [HM5_C] -Aceptaron un cuerpo a cuerpo. . +Han aceptado un mano a mano. [HM5_D] -Uno de sus gangsters contra dos de los nuestros, o mejor... +Un puñado de los suyos contra dos de los nuestros, [HM5_E] -dos de vosotros +o más bien, tú y uno más. [HM5_F] -Yo os apoyaré pero... +Os ayudaría, pero... [HM5_G] -La vista de mi libertad bajo fianza no es hasta dentro de tres meses, +No quiero jugarme mi libertad condicional, [HM5_H] -¿sabes lo que te digo? +¿me captas? [HM5_I] -Ve y reúnete con mi hermano pequeño, +Reúnete con mi hermano pequeño, [HM5_J] -Te enseñará dónde están peleando por una causa justa. +él te enseñará dónde será la pelea. -[MEA1_B] -El nombre es Chonks, Marty Chonks. +{ D-Ice's brother, when the player finds him } -[MEA1_C] -Soy el dueño de la fábrica de comestibles Bitchin' Dog que está a la vuelta de la esquina. +[HM5_1] +Hola, Ice dijo que vendrías. Las reglas son sólo bates. Cero armas, cero coches. -[MEA1_D] -Tengo problemas económicos, pero ¡ey!, y quién no, ¿verdad? +[HM5_5] +Es una batalla por respeto, ¿vale? -[MEA1_E] -Voy a reunirme con el director de mi banco más tarde. +[HM5_6] +Vamos a partir cabezas... -[MEA1_F] -Es un tramposo bastardo que sigue engordando los pagos del préstamo para llevarse una buena porción. +{ Mission instructions } -[MEA1_G] -Coge mi coche, ve a buscarle y traelé de vuelta. +[HM5_3] +~r~¡Te han dicho que uses sólo un bate de béisbol! -[MEA1_H] -¡¡Tengo una pequeña sorpresa para ese parasito chupasangres!! +[HM5_4] +~r~¡Tu contacto está muerto! -[MEA2_A] -Contraté algunos ladrones para que entraran en mi apartamento... +{ ============================================================================= } +{ ================= MISSION: BAIT (ASUKA KASEN, SECOND BATCH) ================= } +{ ============================================================================= } -[MEA2_C] -Los bastardos ladrones amenazan con contárselo a la compañía de seguros, +{ TITLE } -[MEA2_D] -si no les doy una parte +[AS1] +'CEBO' -[MEA2_E] -¿Puedes creerlo? +{ Premission cutscene } -[MEA2_F] -He dejado un coche dentro de las puertas de la fábrica. +{ Asuka } -[MEA2_G] -Úsalo para ir a recogerles en su territorio en el Red Light District. +[AS1_A] +Parece que Miguel piensa que le maltrato. -[MEA2_H] -Luego traelos de vuelta a la fábrica de manera que pueda hacerles ver el punto de vista de Marty. +[AS1_B] +Pero ha revelado cuánto teme Catalina tu búsqueda de venganza. -[MEA3_A] -El negocio se va a hundir a no ser que me haga con una buena cantidad de dinero muy pronto. +[AS1_C] +Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty con el único fin de darte caza. -[MEA3_B] -Mi esposa tiene una póliza de seguro y todo lo que ella ha sido para mí es un agujero en mis bolsillos. +[AS1_D] +Haz de cebo y consigue que los escuadrones te sigan hasta Pike Creek, -[MEA3_C] -He dejado un coche en el lugar habitual +[AS1_E] +donde estarán esperando algunos de mis hombres. -[MEA3_D] -Ve a recoger a mi esposa en Classic Nails y traela de vuelta a la fábrica. +{ Mission instructions } -[MEA4_A] -Diablos,¡tengo problemas! +[AS1_G] +~r~¡Todos los yakuza están muertos! -[MEA4_B] -Resulta que mi esposa estaba viéndose con un tipo a quien le debo dinero. +[AS1_H] +~r~¡No has llevado al escuadrón de la muerte hasta la trampa de la yakuza! -[MEA4_C] -¡Parece muy enfadado y está tratando de recuperar su dinero! +{ ======================================================================================= } +{ ================= MISSION: EXPRESSO-2-GO! (ASUKA KASEN, SECOND BATCH) ================= } +{ ======================================================================================= } -[MEA4_E] -cree que voy a devolverle el dinero... +{ TITLE } -[MEA4_F] -pero yo creo que... +[AS2] +'CAFÉ PARA LLEVAR' -[MEA4_G] -¡los perros de Liberty van a disfrutar de un nuevo sabor este mes! +{ Premission cutscene } -[WELCOME] -BIENVENIDO A +{ Asuka } -[HM1_2] -~g~Hazte con un vehículo, y recuerda que sólo cuentan los asesinatos con Uzi desde el coche. +[AS2_A1] +¡Está claro que Miguel tiene esa famosa resistencia latina! -[HELP8_B] -Pulsa el ~h~ botón ~k~~PED_SNIPER_ZOOM_IN~~w~ para ~h~ hacer zoom en ~w~ con el rifle y el ~h~botón ~k~~PED_SNIPER_ZOOM_OUT~~w~ para ~h~ retirar el zoom ~w~ otra vez. +[AS2_A2] +Estoy agotada. -[LRQC_1] -Asuka y yo vamos a tener que hablar, uh, +[AS2_A] +Subestimamos los planes que tiene Catalina para el SPANK. -[LRQC_2] -¿Por qué no das un paseo por ahí? +[AS2_B] +Va mucho más allá de hacer que los jamaicanos lo vendan en las esquinas. -[LRQC_3] -Necesitas un lugar para esconderte +[AS2_C] +El cártel tiene una tapadera, el Kappa Coffee House. -[LRQC_4] -Hay un almacén en la orilla de Belleville que puede tener lo que necesitas. +[AS2_D] +Vende SPANK en puestos callejeros. -[LRQC_5] -Regresa a mi apartamento cuando estés listo, +[AS2_E] +No tenemos otra opción más que sabotear esos puntos de venta. -[LRQC_6] -y podemos tener una pequeña charla. +[AS2_F] +¡Redúcelos a cenizas! -[JM6_5] -~g~Necesitas un vehículo para escapar, ¡idiota! +{ Mission instructions } -[JM2_F] -Si necesitas una pieza ve por detrás de AmmuNation, enfrente del metro. +[AS2_1] +~g~¡Todos los puestos de café en Portland han sido destruidos! -[LOVE4_7] -~g~Hay una zona de construcción en Staunton Island, puede que llevaran el paquete allí. +[AS2_2] +~g~¡Todos los puestos de café en Staunton Island han sido destruidos! -[LOVE4_8] -~g~Necesitarás un coche para abrir el garaje. +[AS2_3] +~g~¡Todos los puestos de café en Shoreside Vale han sido destruidos! -[TSCORE] -GANANCIAS: ~1~ $ +[AS2_4] +~r~¡El cártel ha avisado a sus camellos! -[AM1_9] -~r~¡Salvatore ha escapado de vuelta al club de Luigi! +[AS2_5] +~g~¡Todavía hay puestos de café en Shoreside Vale y en Staunton Island! -[AM1_6] -~g~Si te dejas ver por el club de Luigi, ¡la Mafia te encontrará! +[AS2_6] +~g~¡Todavía hay puestos de café en Shoreside Vale! -[TM2_3] -~g~¡Es una trampa! ¡Liquidadlos a todos! +[AS2_7] +~g~¡Todavía hay puestos de café en Staunton Island! -[FM4_1] -Esta es María. ¡El coche es una trampa! Encuéntrame en el lado sur de Callahan Bridge. +[AS2_8] +~g~¡Todavía hay puestos de café en Portland! -[JM1_7] -~g~¡Cierra la puerta del coche! ¡Se dará cuenta! +[AS2_9] +~g~¡Todavía hay puestos de café en Portland y en Shoreside Vale! -[KM5_1] -~g~¡¡TRAFICANTE DESMENUZADO!! - -[KM5_6] -~g~Debes matar al menos 8 traficantes Yardie. - -[KM5_7] -~g~¡Mátalos rápido! Una vez que venden el SPANK se retiran de las calles. - -[RM3_8] -~r~¡¡El coche es un señuelo!! - -[LM3_8] -Hola, soy Joey. - -[LM3_9] -Luigi dijo que tú eras de fiar, así que vuelve más tarde, - -[KM3_5] -~g~Toca el claxon para poder hacer el trato. - -[LOVE7] -DESAPARICION DEL AMOR - -[LOVE2_5] -~g~¡Kenji es carne de parachoques! ¡Sal de Newport y deshazte del coche! +[AS2_10] +~g~¡Todavía hay puestos de café en Portland y en Staunton Island! [AS2_11] -~g~ ~1~ DE 9! +~g~¡~1~ DE 9! -[GARAGE1] -~g~Sal del vehículo y camina afuera. +[AS2_12] +~g~¡Recorre los distritos de Liberty y busca puestos de café ~b~Espresso-2-Go~g~! -[KM3_11] -~g~El Cartel ha sido atacado y el maletín no ha sido recuperado. +[AS2_12A] +~g~Cuando destruyas el primer puesto, ¡tendrás 8 mintutos antes que el cártel avise a sus camellos! -[KM3_12] -~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. +{ =============================================================================== } +{ ================= MISSION: S.A.M. (ASUKA KASEN, SECOND BATCH) ================= } +{ =============================================================================== } -[KM3_13] -~g~Lleva el maletín de vuelta al casino. +{ TITLE } -[RM5_6] -~g~¡Ha salido en libertad bajo fianza! ¡¡Destruye su chaleco salvavidas con un vehículo o una explosión!! +[AS3] +'TIERRA-AIRE' -[PBOAT_1] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones del barco. +{ Premission cutscene } -[PBOAT_2] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones del barco. +{ Maria } -[DIAB1_B] -Este es El Burro de los Diablos. +[AS3_A] +¿Lo apretamos un poco más o esperamos a que se vuelva negro y se caiga? -[DIAB1_D] -Ahora estás en Liberty, pero ya te estás ganando una reputación en las calles. +{ Asuka } -[DIAB1_E] -Hay una carrera en la calle que empieza en la vieja escuela cerca de Callahan Bridge. +[AS3_B] +Dale un toque rápido... -[DIAB1_F] -Consíguete unas ruedas y el primero que pase por todos los checkpoints gana el premio. +{ Maria } -[HM2_1] -Usa los buggies RC para destruir los coches blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~ para detonar. +[AS3_C] +¡Buaj! ¿Qué es esa cosa amarilla pegajosa? -[HM2_1A] -Usa los buggies RC para destruir los coches blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para detonar. +[AS3_C1] +¡Hola, guapo! -[HM2_2] -~r~¡Fallaste en la destrucción de los coches blindados! +{ Asuka } -[HM2_6] -~g~¡Coche blindado destrozado! +[AS3_D] +¡Mi manitas! -[RM3_A] -Conozco un hombre muy importante en la ciudad, un tipo suave, +{ Maria } -[RM3_H] -con gustos exóticos y el suficiente dinero para pagárselos. +[AS3_E] +Me aburría, así que vine a hacerle compañía a Asuka. -[RM3_B] -Está involucrado en un asunto legal y la acusación tiene fotos de él muy comprometedoras +{ Asuka } -[RM3_C] -en una fiesta en la morgue o algo así. +[AS3_F] +Esta chica tiene un talento nato para la tortura. -[LOVE6_A] -Una lección en negocios, amigo mío. +[AS3_F1] +Se las ha arreglado para extraerle esta joyita a nuestro invitado. -[LOVE6_E] -Si tienes una mercancía única, el mundo y su mujer tratarán de quitártela de tus garras. +[AS3_G] +Hay una avioneta que llegará al Aeropuerto Francis en dos horas. -[LOVE6_C] -Equipos SWAT han acordonado el área alrededor de mi asociado y el paquete. +[AS3_G1] +Está lleno del veneno de Catalina. -[LOVE6_D] -Ve hacia allí, recoge la furgoneta y actúa como un señuelo. +[AS3_H] +Podrás evitar la seguridad del aeropuerto si conduces una lancha hasta las boyas luminosas, -[LOVE6_F] -Mantenles ocupados y él podrá escaparse bien. +[AS3_H1] +así podrás disparar a la avioneta al aterrizar. -[AM3_C] -¡Está probablemente afuera en la bahía mientras lees esto! ¡Roba un barco de policía, y hunde su carrera! +[AS3_I] +¡Recoge el cargamento de entre los escombros y tráelo! -[FESZ_UC] -CANCELAR +{ Maria } -[FEDS_SM] -L1,R1-CAMBIAR MENU Mientras se busque un menú en particular: +[AS3_J] +Ten cuidado, guapo, ¿vale? -[FEDS_AS] -;=-CAMBIAR SELECCION +{ Asuka } -[FEDSAS2] -<>-CAMBIAR SELECCION +[AS3_K] +Ahora prueba con el aceite picante... -[FEDS_SS] -L1,R1-CAMBIAR SELECCION +{ Mission instructions } -[FEDSSC1] -;-MOVIMIENTO MAS RAPIDO +[AS3_1] +~g~¡Busca una ~r~lancha~g~ y ve a la ~b~boya señalada! -[FEDSSC2] -=-DETENER MOVIMIENTO +[AS3_1A] +~g~¡Ahora ve a la ~b~boya señalada~g~! -[MEA2_3] -~g~Traer el coche de vuelta a la fábrica. +[AS3_3] +~g~¡Espera a que la ~y~avioneta~g~ comience a acercarse! -[RM1_3] -~r~¡McAffrey se escapó! +[AS3_5] +~g~¡Recupera el cargamento! -[RM1_4] -~g~¡Has usado todas las granadas! ¡Consigue más en Ammunation! +[AS3_4] +~g~¡Usa un lanzacohetes para derribar ~y~la avioneta~g~! -[RM1_5] -~g~¡Vuelve y quema la casa de seguridad! +[AS3_2] +~b~¡Ve a la boya del aeropuerto señalada! ~y~¡El avión se está acercando! -[RM6_4] -~g~ Pásate por la taquilla y consigue el cargamento de Ray. +[AS3_6] +~g~~1~ DE 8 -[RM6_5] -~g~La CIA tiene el puente bajo vigilancia, encuentra otra ruta para pasar +[STASH] +~g~¡Lleva el SPANK de vuelta a la ~p~zona en obras~g~! -[HM2_F] -y destroza todo su material blindado. +{ ============================================================== } +{ ================= MISSION: RANSOM (CATALINA) ================= } +{ ============================================================== } -[HM_4] -'LINGOTES DE ORO' +{ TITLE } -[MEA2_B5] -TEXTO NO MAS REQUERIDO +[AS4] +'RESCATE' -[MEA1_B5] -TEXTO NO MAS REQUERIDO +[CAT1] +'RESCATE' -[MEA3_B5] -TEXTO NO MAS REQUERIDO +{ Cutscene } -[MEA4_B7] -pero si pasas por mi oficina... +{ Catalina (letter, colombiana) } -[MEA3_B4] -¿ Marty quiere verme? Bueno, pues que sea rápido porque tengo que ir a la peluquería. +[CAT1_A] +Tengo a tu linda María. Si no quieres que parezca que un carnicero se ensañó con ella, -[KM3_7] -¡Es una trampa Yakuza, tío! +[CAT1_B] +lleva 500.000 dólares a la mansión de Cedar Grove. -[FES_LOF] -Fallo al cargar. +{ Mission instructions } -[P1INSA] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. ~1~K de espacio disponible para guardar. ~1~K necesario. +[CAT1_F] +¡Ve a donde está Catalina antes de que se acabe el tiempo! -[P1INSN] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. No hay espacio disponible para guardar. Por favor borra algunos archivos. +[CAT_MON] +~g~Todavía te falta dinero. Necesitas 500.000 dólares. -[FES_SLO] -GUARDAR ARCHIVO +[CAT1_E] +XXXX -[FES_ISC] -ESTA CORRUPTO +{ ==================================================================== } +{ ================= MISSION: THE EXCHANGE (CATALINA) ================= } +{ ==================================================================== } -[FESZ_TI] -GUARDAR Z1 +{ TITLE } -[FESZ_SA] -Guardar Partida +[CAT2] +'EL INTERCAMBIO' -[P1NOIN] -No hay memory card (PS2) insertada en la ranura para MEMORY CARD 1 +{ Premission cutscene } -[P1INSE] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. +{ Catalina (colombiana) } -[MC_LDFL] -¡Error al cargar! +[CAT2_A] +La verdadera pregunta es: ¿vienes buscando a María o buscándome a mí? -[MC_NWRE] -Ahora, reinicio de partida +[CAT2_B] +Tengo una noticia para ti: -[LOVE6_3] -~g~Tienes ~1~ segundo para volver al Securicar antes de que falles en la misión. +[CAT2_B2] +matarte será un placer, pero salir contigo sólo fue un negocio. -[LOVE6_4] -~r~¡Te deshiciste del Securicar señuelo! +[CAT2_C] +¡Eres muy pequeñito, amigo! -[HELP1] -Detente en el centro del marcador azul. +[CAT2_D] +Dame el dinero. -[HELP12] -Vaya hasta el centro del marcador azul para dar comienzo una misión. +[CAT2_E] +¡Has estado muy ocupado! -[HJSTAT] -Distancia: ~1~. ~1~m. Altura: ~1~.~1~m. Vueltas: ~1~. Rotación: ~1~_ +[CAT2_E2] +Pero no has aprendido que yo no soy de fiar. -[HJSTATW] -Distancia: ~1~.~1~m. Altura: ~1~.~1~m. Vueltas: ~1~. Rotación: ~1~_ Y, ¡qué buen aterrizaje! +[CAT2_E3] +¡Mata al idiota! -[DIAB1_5] -TIEMPO DE CARRERA +[CAT2_A1] +¡Vamos, perra! -[LOVE3_4] -~r~¡Has destruído el avión!! +{ Cutscene, after reaching Catalina at the dam } -[F_FAIL1] -¡Misión de coche de bomberos terminada! +{ Catalina (colombiana) } -[F_CANC] -~r~ ¡Misión de coche de bomberos cancelada! +[CAT2_J] +¡Despega de una vez! -[F_EXTIN] -FUEGOS: +{ Mission instructions } -[A_COMP1] -¡Misión de paramédicos completada! +[CATINF1] +~g~¡Liquida a Catalina! -[A_CANC] -~r~¡Misión de paramédicos cancelada! +[CATINF2] +~g~Sigue al helicóptero para encontrar a Catalina. -[A_COMP3] -¡Misión de paramédicos completada! ¡Nunca te cansarás cuando estés corriendo! +[BITCH_D] +~g~¡María está muerta! -[ATUTOR] -Pulsa el ~h~ botón ~k~~TOGGLE_SUBMISSIONS~~w~ para conectar o desconectar misiones de paramédico. +{ =================================================== } +{ ================= ENDING CUTSCENE ================= } +{ =================================================== } -[ATUTOR3] -Pulsa el ~h~ botón ~k~~TOGGLE_SUBMISSIONS~~w~ para conectar o desconectar misiones de paramédico. +{ Libery City News broadcaster } -[ALEVEL] -Nivel de misión de paramédico ~1~ +[END_A] +Los residentes de Cedar Groove todavía están asumiendo -[A_FAIL1] -Misión de paramédico terminada. +[END_B] +las consecuencias emocionales provocadas -[FEST_HA] -Nivel más alto de misión de paramédico +[END_C] +por la guerra que estalló ayer en la zona. -[A_SAVES] -GENTE SALVADA: ~1~ +[END_D] +Un residente local, Clive Denver, dijo a la policía -[C_KILLS] -CRIMINALES MATADOS: ~1~ +[END_E] +que vio a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. -[HM1_B] -Tengo un problema, están tratando de camelarme. +{ Maria } -[AM2_A] -La muerte de Salvatore es una placentera noticia, +[END_F] +¿Sabes? Vamos a pasar un buen rato, porque, como sabes... -[AM2_A2] -eres un asesino eficaz - Eso me gusta en un hombre. +[END_G] +¡Te amo! Yo, yo, yo realmente te amo, porque eres superfuerte, -[AM2_B] -Este es mi hermano Kenji. +[END_H] +y eso es todo lo que necesito. -[AM2_C] -Asuka tiene un pequeño trabajo para ti, pero cuando hayas terminado, pásate por mi casino y podremos hablar. +[END_I] +Bueno, ¿qué estaba diciendo? -[AM2_D] -Justo como Kenji, siempre tratando de jugar con mis juguetes. +[END_J] +Lo he olvidado. Pero me entiendes, ¿verdad? -[AM2_E] -Mi fuente en la policía me dice que la Mafia está acechando nuestros intereses en la ciudad +{ Libery City News broadcaster } -[AM2_E2] -con el propósito de localizarte. +[END_K] +Las explosiones sacudieron las casas más próximas y a sus residentes. -[AM2_F] -No podemos continuar con nuestras operaciones hasta que entablen negociaciones. +[END_L] +Varios ciudadanos resultaron heridos a causa del tiroteo -[AM2_G] -Liquida a esos estúpidos espías y acaba con esta vendetta de una vez por todas. +[END_M] +entre las fuerzas terrestres y un helicóptero que rodeaba a la presa. -[F_START] -~g~Informe de vehículo en llamas en el ~a~área. Ve y extingue el fuego. +{ Male witness } -[AM4_1A] -Ve al teléfono de West Belleville Park. +[END_N] +Sí, en estos jardínes tuvimos una vista excelente. -[AM4_1B] -Ve al teléfono de Liberty Campus. +[END_O] +Cuando el helicóptero estalló, -[AM4_1C] -Ve al teléfono de South Belleville Park. +[END_P] +fue mejor que los fuegos artificiales del 4 de julio. -[AM4_1D] -Encuéntrame en el bloque del baño en el parque. +{ Libery City News broadcaster } -[HJSTATF] -Distancia:~1~pies. Altura: ~1~pies. Vueltas: ~1~. Rotación: ~1~_ +[END_Q] +El número de víctimas asciende a las veinte -[HJSTAWF] -Distancia: ~1~pies. Altura: ~1~pies. Vueltas: ~1~. Rotación: ~1~_. Y, ¡qué buen aterrizaje! +[END_R] +mientras la policía sigue encontrando cuerpos. -[HM1_F] -Pero vigila a tus espaldas, habrá Jacks en las calles que creerán que estás tratando de volarles también la cabeza. +[END_S] +No se han negado oficialmente los rumores -[HM1_D] -'Nueves' es su etiqueta y púrpura es su bandera y cada día ellos sacuden sus colores... +[END_T] +de que las víctimas eran miembros del cártel colombiano, -[HM1_G] -otro día más que los 'Jacks' parecen blanditos. +[END_U] +y aún no hay pistas que aclaren las causas de la masacre. -[MEA2_B] -y roba lo que encuentres para que así pueda reclamarle al seguro como haces tú. +{ Maria } -[TM3_H] -~w~Te lo montaste bien allí, chaval, muy bien. +[END_V] +Me he roto una uña y me pelo está hecho un asco, ¿puedes creerlo? -[TM3_I] -~w~Vamos, te presentaré al Don. +[END_W] +Me costó cincuenta dólares... -[TM3_J] -~w~¡Eeeyyyy! ¡Luigi! +{ Duplicates of Maria's dialogue, possibly unused } -[TM3_K] -~w~Oh, mis chicas han estado echándote de menos mucho tiempo, Salvatore, has estado fuera mucho tiempo. +[CAT2_F] +Me he roto una uña y se me ha estropeado el peinado. Es increíble. ¡Me había costado cincuenta dólares! -[TM3_L] -~w~Diles que una vez que nos hayamos ocupado de este desgraciado incidente, +[CAT2_G] +Estaba muerta de miedo, pero luego me dije a mí misma: ''Ya eres mayorcita''. -[TM3_M] -~w~iremos todos al club para celebrar, ¿vale? +[CAT2_H] +Oh, nos lo vamos a pasar a lo grande, porque, ¿sabes?, mi hermana dijo que quería venirse a vivir con sus dos hijos, -[TM3_N] -~w~Ese es mi chico +[CAT2_I] +porque su marido a vuelto a enredar por ahí y... -[TM3_N2] -~w~¿Cómo lo llevas, papá? - -[TM3_O] -~w~¿Has encontrado ya una buena mujer? - -[TM3_P] -~w~Ey, tu madre, que en paz descanse, se retorcería en la tumba - -[TM3_Q] -~w~si te viera sin una mujer. - -[TM3_R] -~w~Lo sé, papá, me estoy ocupando de eso. - -[TM3_S] -~w~¡TONI! ¿Cómo está tu madre? - -[TM3_T] -~w~Ella es una gran mujer, ¿sabes? Fuerte. Firenze. - -[TM3_U] -~w~Ella está bien... estupenda. - -[TM3_V] -~w~Fantástico, fantástico. Ahora escuchadme, chavales, entrad dentro mientras yo hablo aquí con nuestro nuevo amigo. - -[TM3_W] -~w~No veo más que cosas buenas para ti, hijo mío... - -[RM1_A] -Esa bola de mierda, McAffrey, aceptó más sobornos que nadie. - -[RM1_B] -Cree que va a conseguir una rebaja honorable de sus cargos si ofrece evidencias del estado - -[RM1_C] -¡El ha cantado! - -[RM4_B] -Tenemos que cerrarle la boca para siempre. - -[RM4_E] -Quiero que se vaya a dormir con los peces en lugar de comérselos. - -[LOVE3_B] -En su aproximación al aeropuerto esta noche, una avioneta ligera sobrevolará la bahía. - -[LOVE4_D] -Desgraciadamente las autoridades aduaneras registraron el avión y lo estaban desguazando - -[LOVE4_H] -hasta que yo intervine a pesar del gran coste personal. - -[LOVE4_E] -Cruza el puente a Shoreside Vale, y ve al aeropuerto Francis International. - -[GTAB_A] -Ey, saquemos esto de aquí. Dios sabe qué será. - -[GTAB_B] -pero él parece quererlo a toda costa así que debe de tener algún valor. - -[GTAB_C] -¡Quién diablos! - -[GTAB_D] -¡TÚ! - -[GTAB_E] -¡Ey, tranquilo, amigo! ¡De nada! De nada! - -[GTAB_F] -¡Te dejé metiendo tu corazón en el charco! - -[GTAB_G] -No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. - -[GTAB_H] -¡No seas mariquita! - -[GTAB_I] -¡No tenemos elección, nene! - -[GTAB_J] -¡Siempre hay una elección, bastardo! - -[GTAB_K] -¡Siento mucho lo de ese perro enloquecido, son todos iguales... ¿¿por favor?? - -[GTAB_L] -Así que la buscona se fué. - -[GTAB_M] -Pero me has hecho un favor, - -[GTAB_N] -no eres el único que tiene una cuenta pendiente con el Cartel, - -[GTAB_O] -¡ese gusano mató a mi hermano! - -[GTAB_P] -¡Nunca maté a ningún Yakuza! - -[GTAB_Q] -¡MENTIROSO! Todos vimos al asesino del Cartel. - -[GTAB_R] -¡Vamos a cazaros y a mataros a todos, perros colombianos! - -[GTAB_S] -Estaré trabajando con nuestro querido amigo para extraerle información y un poco de placer. - -[GTAB_T] -Tú, ven más tarde, estoy seguro que voy a necesitar tus servicios. - -[GTAB_U] -Por favor, amigo, no me dejes con ella, ¡esa chica está loca! ¿Amigo?. Ey, ¡AMIIIGO!... ¡Aiiieeeaaaargghh! - -[LOVE5_A] -Estás demostrando ser una inversión segura, algo muy raro en estos días que corren. - -[KM3_1] -~g~¡El Cartel espera que una banda Yardie vaya y robe un coche Yardie! Dirígete hacia el norte, encontrarás uno en Newport. - -[LOVE1_1] -~g~Ve a robar un coche de la banda Colombiana, para que puedas infiltrar el escondite, dirígete hacia el norte y encontrarás uno en Fort Staunton) - -[FM1_Q1] -~w~¿Estás buscando un poco de diversión?. ¿Un poco de... hmmm? ¿Algo de zurra? - -[FM1_R] -~w~Hola, chico. Hah, lo de siempre. - -[FM1_T] -~w~Gracias Chico, nos vemos pronto. - -[FM1_W] -~w~De acuerdo Fido, espera aquí y quédate pendiente del coche mientras yo voy a menear mi culo, ¿vale? - -[FM1_X] -~w~VALE Fido, salgamos de aquí. ¡Uauhhh! - -[FM1_Q] -~w~¡Ey María! ¡Es mi chica favorita! - -[FM1_S1] -~w~Ey, a lo mejor deberías echar un vistazo en la fiesta del almacén en el lado este de Atlantic Quays. - -[FM1_U] -~w~Gracias y disfruta. Es buen material - -[FM1_V] -~w~Vamos Fido, ¡vamos a echar un vistazo a esa fiesta! - -[FM1_SS] -~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: Asistir redada de narcóticos en Atlantic Quays. - -[LOVE6_B] -incluso aunque no sean conscientes de su verdadera valía. - -[TM3_A1] -~r~¡El amigo de Joey! - -[TM3_A2] -~r~¡Joey y Luigi han sido incinerados! - -[TM3_A3] -~r~¡Joey, Luigi y Toni están quemados! - -[FM4_2] -Escucha, Salvatore cree que estamos engañándole, - -[FM4_3] -así que te ofreció al Cartel para poder hacer un trato. - -[FM4_4] -No podía permitir que hiciera eso, o sea, lo peor es que, - -[FM4_4B] -es mi culpa... porque le dije que éramos un asunto a tratar. - -[FM4_5] -No me preguntes por qué. No lo sé. - -[FM4_6] -Mira, eres un hombre marcado en terreno Mafia y yo tengo que salir de aquí también. - -[FM4_6B] -¡He visto demasiados asesinatos. Demasiada sangre! - -[FM4_7] -Es una amiga mía, ¿vale?, una vieja amiga... es Asuka, alguien en quien podemos confiar. - -[FM4_8] -Vamos, ya vale de discursos. - -[FM4_9] -Será mejor que salgamos de aquí antes de que haya más italianos histéricos pretendiendo hacer reuniones poco amistosas. +{ =================================================================================================================== } +{ =================================================================================================================== } +{ ================================================== GAME CREDITS =================================================== } +{ =================================================================================================================== } +{ =================================================================================================================== } [CRED001] ROCKSTAR STUDIOS [CRED002] -PRODUCER +PRODUCTOR [CRED003] LESLIE BENZIES [CRED004] -ART DIRECTOR +DIRECTOR DE ARTE [CRED005] AARON GARBUT [CRED006] -TECHNICAL DIRECTION +DIRECCIÓN TÉCNICA [CRED007] OBBE VERMEIJ @@ -5273,7 +5934,7 @@ OBBE VERMEIJ ADAM FOWLER [CRED009] -DESIGN +DISEÑO [CRED010] CRAIG FILSHIE @@ -5288,7 +5949,7 @@ CHRIS ROTHWELL JAMES WORRALL [CRED014] -WRITTEN BY +GUIÓN [CRED015] JAMES WORRALL @@ -5300,13 +5961,13 @@ PAUL KUROWSKI DAN HOUSER [CRED018] -CHARACTERS +PERSONAJES [CRED019] IAN MCQUE [CRED020] -ANIMATION & DIRECTION +ANIMACIÓN Y DIRECCIÓN [CRED021] ALEX HORTON @@ -5321,7 +5982,7 @@ AUTO DESIGN PAUL KUROWSKI [CRED025] -ARTISTS +ARTISTAS [CRED026] KEIRAN BAILLIE @@ -5342,7 +6003,7 @@ ANDREW SOOSAY ALISDAIR WOOD [CRED032] -CODERS +PROGRAMADORES [CRED033] ALAN CAMPBELL @@ -5360,7 +6021,7 @@ ALEXANDER ROGER GRAEME WILLIAMSON [CRED038] -SCORE +MÚSICA [CRED039] CRAIG CONNER @@ -5369,25 +6030,25 @@ CRAIG CONNER STUART ROSS [CRED041] -SOUND DESIGN & MASTERING +DISEÑO DE SONIDO Y MASTERIZADO [CRED042] ALLAN WALKER [CRED043] -AUDIO PROGRAMMING +PROGRAMACIÓN DE AUDIO [CRED044] RAYMOND USHER [CRED045] -TEST MANAGER +DIRECTOR DE PRUEBAS [CRED046] CRAIG ARBUTHNOTT [CRED047] -LEAD TESTERS +JEFES DE PRUEBAS [CRED048] ANDY DUTHIE @@ -5399,7 +6060,7 @@ JOHN HAIME NEIL CORBETT [CRD050A] -TESTERS +PROBADORES [CRED051] GRAEME JENNINGS @@ -5420,7 +6081,7 @@ MARK FLETT MICHAEL SUTHERLAND [CRED057] -TECHNICAL SUPPORT +SOPORTE TÉCNICO [CRED058] LORRAINE ROY @@ -5432,43 +6093,43 @@ CHRISTINE CHALMERS ROCKSTAR [CRED061] -EXECUTIVE PRODUCER +PRODUCTOR EJECUTIVO [CRED062] SAM HOUSER [CRED063] -PRODUCER +PRODUCTOR [CRED064] DAN HOUSER [CRED065] -DIRECTOR OF DEVELOPMENT +DIRECTOR DE DESARROLLO [CRED066] JAMIE KING [CRED067] -TECHNICAL PRODUCER +PRODUCTOR TÉCNICO [CRED068] GARY J. FOREMAN [CRED069] -ASSOCIATE PRODUCER +PRODUCTOR ASOCIADO [CRED070] JEREMY POPE [CRED071] -MUSIC SUPERVISOR +SUPERVISOR MUSICAL [CRED072] TERRY DONOVAN [CRED073] -ROCKSTAR PRODUCTION TEAM +EQUIPO DE PRODUCCIÓN DE ROCKSTAR [CRED074] TERRY DONOVAN @@ -5504,37 +6165,37 @@ PAUL YEATES STANTON SARJEANT [CRED085] -VP OF MARKETING +VICEPRESIDENTE DE MÁRKETING [CRED086] TERRY DONOVAN [CRED087] -TECHNICAL COORDINATOR +COORDINADOR TÉCNICO [CRED088] BRANDON ROSE [CRED089] -QA MANAGER +DIRECTOR DE C.C. [CRED090] JEFF ROSA [CRED091] -LEAD ANALYST +JEFE DE ANÁLISIS [CRED092] ADAM DAVIDSON [CRED093] -GAME ANALYST +ANALISTA DEL JUEGO [CRED094] RICHARD HUIE [CRED095] -TEST TEAM +EQUIPO DE PRUEBAS [CRED096] LANCE WILLIAMS @@ -5549,7 +6210,7 @@ BRIAN PLANER OSWALD GREENE [CRED100] -LIBERTY TREE EDITORIAL +EDITORIAL DEL LIBERTY TREE [CRED101] JAMES WORRALL @@ -5570,106 +6231,106 @@ JENEFER GROSS LAURA PATERSON [CRED107] -CUT-SCENES +CINEMÁTICAS [CRED108] -SCRIPT BY DAN HOUSER AND JAMES WORRALL +GUIÓN DE DAN HOUSER Y JAMES WORRALL [CRED109] -AUDIO DIRECTED BY DAN HOUSER +AUDIO DIRIGIDO POR DAN HOUSER [CRED110] -AUDIO PRODUCED BY RENAUD SEBBANE +AUDIO PRODUCIDO POR RENAUD SEBBANE [CRED111] -CAST +REPARTO [CRED112] -FRANK VINCENT AS SALVATORE LEONE +FRANK VINCENT COMO SALVATORE LEONE [CRED113] -JOE PANTOLIANO AS LUIGI GOTERELLI +JOE PANTOLIANO COMO LUIGI GOTERELLI [CRED114] -MICHAEL MADSEN AS TONI CIPRIANI +MICHAEL MADSEN COMO TONI CIPRIANI [CRED115] -MICHAEL RAPAPORT AS JOEY LEONE +MICHAEL RAPAPORT COMO JOEY LEONE [CRED116] -DEBBI MAZAR AS MARIA +DEBBI MAZAR COMO MARÍA [CRED117] -KYLE MACLACHAN AS DONALD LOVE +KYLE MACLACHAN COMO DONALD LOVE [CRED118] -ROBERT LOGGIA AS RAY MACHOWSKI +ROBERT LOGGIA COMO RAY MACHOWSKI [CRED119] -GURU AS 8-BALL +GURU COMO 8-BALL [CRED120] -SONDRA JAMES AS MOMMA +SONDRA JAMES COMO MAMMA [CRED121] -LIANA PAI AS ASUKA +LIANA PAI COMO ASUKA [CRED122] -LES MAU AS KENJI +LES MAU COMO KENJI [CRED123] -CYNTHIA FARRELL AS CATALINA +CYNTHIA FARRELL COMO CATALINA [CRED124] -AL ESPINOSA AS MIGUEL +AL ESPINOSA COMO MIGUEL [CRED125] -CHRIS PHILLIPS AS EL BURRO +CHRIS PHILLIPS COMO EL BURRO [CRED126] -HUNTER PLATIN AS CHICO +HUNTER PLATIN COMO CHICO [CRED127] -WALTER MUDU AS D-ICE +WALTER MUDU COMO D-ICE [CRED128] -CURTIS MCCLARIN AS CURTLY +CURTIS MCCLARIN COMO CURTLY [CRED129] -BILL FIORE AS DARKEL +BILL FIORE COMO DARKEL [CRED130] -CHRIS PHILLIPS AS MARTY CHONKS +CHRIS PHILLIPS COMO MARTY CHONKS [CRED131] -HUNTER PLATIN AS CURLY BOB +HUNTER PLATIN COMO CURLY BOB [CRED132] -WALTER MUDU AS KING COURTNEY +WALTER MUDU COMO KING COURTNEY [CRED133] -HUNTER PLATIN AS ONE-ARMED PHIL +HUNTER PLATIN COMO ONE-ARMED PHIL [CRED134] -KIM GURNEY AS MISTY +KIM GURNEY COMO MISTY [CRED135] -MOTION CAPTURE +CAPTURA DE MOVIMIENTOS [CRED136] -ANIMATED BY +ANIMACIÓN [CRD136A] ALEX HORTON [CRED137] -DIRECTED BY +DIRECCIÓN [CRD137A] NAVID KHONSARI [CRED138] -PRODUCED BY +PRODUCCIÓN [CRD138A] JAMIE KING @@ -5678,10 +6339,10 @@ JAMIE KING RENAUD SEBBANE [CRED139] -RECORDED AT MODERN UPRISING STUDIOS, BROOKLYN +GRABADA EN MODERN UPRISING STUDIOS, BROOKLYN [CRED140] -ACTORS +ACTORES [CRD140A] RENAUD SEBBANE @@ -5696,22 +6357,22 @@ STEPHEN DANIELS ROBERT STIO [CRD140E] -JENNY GROSS. +JENNY GROSS [CRED141] -PEDESTRIAN DIALOGUE +DIÁLOGO DE PEATONES [CRED142] -WRITTEN BY DAN HOUSER, NAVID KHONSARI & JAMES WORRALL +ESCRITO POR DAN HOUSER, NAVID KHONSARI Y JAMES WORRALL [CRED143] -DIRECTED BY CRAIG CONNER, DAN HOUSER AND LAZLOW +DIRIGIDO POR CRAIG CONNER, DAN HOUSER Y LAZLOW [CRED144] -PRODUCED BY RENAUD SEBBANE +PRODUCIDO POR RENAUD SEBBANE [CRED145] -CAST +REPARTO [CRED146] HUNTER PLATIN @@ -5927,10 +6588,10 @@ FALKO BURKERT SARA SEWELL [CRED217] -RADIO STATIONS AND MUSIC +EMISORAS DE RADIO Y MÚSICA [CRED218] -PRODUCERS FOR ROCKSTAR UK +PRODUCTORES DE ROCKSTAR REINO UNIDO [CRD218A] CRAIG CONNER @@ -5939,19 +6600,19 @@ CRAIG CONNER STUART ROSS [CRED219] -SOUNDTRACK CO-ORDINATOR +COORDINADOR DE BANDA SONORA [CRED220] TERRY DONOVAN [CRED221] -PRODUCER FOR ROCKSTAR GAMES +PRODUCTOR DE ROCKSTAR GAMES [CRED222] DAN HOUSER [CRED223] -EDITED BY +EDICIÓN [CRED224] CRAIG CONNER @@ -5963,7 +6624,7 @@ ALLAN WALKER LAZLOW [CRED227] -DJ BANTER AND IMAGING WRITTEN BY +GUIÓN DE LOCUTORES Y ANUNCIOS [CRED228] DAN HOUSER @@ -5972,7 +6633,7 @@ DAN HOUSER LAZLOW [CRED230] -SPECIAL THANKS TO +AGRADECIMIENTOS ESPECIALES [CRED231] ADAM TEDMAN @@ -6005,7 +6666,7 @@ EMILY ANDERSON RICHIE HENDERSON [CRED241] -CHRSTIAN CANTAMESSA +CHRISTIAN CANTAMESSA [CRED242] JERONIMO BARRERA @@ -6043,11 +6704,14 @@ DAVE WATSON [CRED253] MALCOLM SMITH +[CRED254] +JEFE DEL ESTUDIO + [CRED255] ANDREW SEMPLE [CRED256] -ARTIST +ARTISTAS [CRED257] STUART PETRI @@ -6088,473 +6752,142 @@ STEVE K. [CRED269] GREG LAU -[CINCAM] -Cámara Cinemática +[CRED270] +MIKE HONG -[KM1_13] -Lleva el vehículo al garaje! +{ =================================================================================================================== } +{ =================================================================================================================== } +{ ================================================ INTERFACE STRINGS ================================================ } +{ =================================================================================================================== } +{ =================================================================================================================== } -[KM3_14] -~r~¡Has sido ubicado, se rompió el trato!! +{ ================================================================ } +{ ================= PAUSE MENU OPTIONS (CONSOLE) ================= } +{ ================================================================ } -[EBAL_H] -Espera aquí tío, mientras voy y hablo con Luigi. +[FEB_STA] +Estadísticas -[EBAL_M] -¡Recuerda que nadie se mete con mis chicas! +[FEB_BRI] +Resumen -[LM2_F] -Entonces coge su coche y repíntalo. +[FEB_CON] +Controles -[LM2_D] -aquí, aquí, cógelo. +[FEB_AUD] +Sonido -[LM1_9] -Hola, soy Misty. +[FEB_DIS] +Pantalla -[LM4_A] -Algún Diablo mal nacido ha estado vendiendo a sus putitas en mi patio de atrás. +[FEB_LAN] +Idioma -[FM2_B] -¡Nos hicimos con una rata! +[FEB_SAV] +Cargar -[FM2_C] -No está ni 'chuleando' ni 'traficando' así que debe de estar hablando. +[FEB_CPC] +Configuración de controles -[FM3_CC] -~w~Regresa, hermano, cuando tengas el dinero. +[FEB_PMB] +Resumen de la última misión: + +{ ============================================================================= } +{ ================= PAUSE MENU DESCRIPTIONS (CONSOLE, UNUSED) ================= } +{ ============================================================================= } + +[FEF_ST1] +¿Quién es el malo? + +[FEF_ST2] +Cuánta destrucción has producido + +[FEF_BR1] +¿Has perdido el hilo? + +[FEF_CO1] +¿Necesitas más control? + +[FEF_CO2] +Elige la mejor configuración del mando para tu estilo de juego + +[FEF_SA1] +¡Mantén tu sitio en el bloque! + +[FEF_SA2] +Guarda y carga tus partidas + +[FEF_AU1] +¡Dale candela al volumen! + +[FEF_AU2] +Elige una emisora de radio y un efecto de sonido + +[FEF_DI1] +¡Cambia el juego! + +[FEF_DI2] +Personaliza el juego para tu televisión + +[FEF_LA1] +¿Qué dices de los Willis? + +[FEF_LA2] +Elige tu idioma preferido + +[FEF_BR2] +Encuéntralo de nuevo leyendo los resúmenes de las misiones jugadas hasta la fecha. + +{ ==================================================================== } +{ ================= CONSOLE PAUSE MENU HINT MESSAGES ================= } +{ ==================================================================== } + +[FEDS_XB] +Seleccionar + +[FEDS_ST] +Botón START - CONTINUAR + +[FEDS_SM] +L1, R1 - CAMBIAR MENÚ [FEDS_AM] -<>- CAMBIAR MENU +<> - CAMBIAR MENÚ -[LOVE5_5] -~r~¡Fallaste protegiendo el camión! +[FEDS_AS] +;= - CAMBIAR SELECCIÓN -[RM6_6] -~r~¡Ray está muerto! +[FEDSAS2] +<> - CAMBIAR SELECCIÓN -[RM6_7] -~r~¡Ray ha perdido su avión! +[FEDSAS3] +- CAMBIAR SELECCIÓN -[RM6_8] -~g~Has dejado atrás a Ray, vuelve a por él. +[FEDSAS4] +;=<> - CAMBIAR SELECCIÓN -[FM1_10] -~g~Has dejado atrás a María, vuelve y recógela. +[FEDS_SS] +L1,R1 - CAMBIAR SELECCIÓN -[LOVE4_9] -~r~¡El avión ha sido destrozado! +[FEDSSC1] +; - ACELERAR -[LOV4_10] -~r~¡La única pista del lugar donde está el paquete ha sido destruída! +[FEDSSC2] += - RALENTIZAR -[KM2_D] -No hace falta decir que debemos darle los coches como un regalo, para pagar la deduda que tenemos con él. +[FEDS_SE] +Botón / - ELEGIR -[KM4_B] -El negocio es lo suficientemente afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. +[FEDS_SB] +Botón / - ELEGIR Botón " - VOLVER -[KM2_E] -Debes obtener los coches de la lista y llevarlos a un garaje detrás del aparcamiento de Newport. +[FEDS_BA] +Botón " - VOLVER -[FM3_8I] -~w~Consigue una posición ventajosa, entonces entraré cuando dispares el primer tiro. +[FEDS_TB] +ATRÁS -[LOVE1_B] -La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, - -[LOVE1_H] -pero los grupos de hombres se hacen ambiciosos. - -[LOVE1_C] -Un valioso recurso, un viejo caballero oriental que conozco, - -[LOVE1_I] -ha sido tomado prisionero por unos sudamericanos en Aspatria. - -[MEA4_D] -He aceptado verle... - -[MEA4_B4] -Marty te envió, ¿ahh?. VALE, voy a enseñar a ese asqueroso el significado de la palabra negocio. - -[MEA4_B5] -¡Carl, hola! y eehh... necesito más tiempo para conseguir tu dinero. - -[MEA1_B4] -Ah, el Sr. Chonks te envió, ¿verdad?. Vamos a hacerle una visita al amiguete. - -[HM5_6] -Vamos a romperle el cuello a algún que otro mamón. - -[LOVE1_5] -~g~Deja de perder el tiempo, hazte con un coche de la mafia Colombiana y rescata al socio de Love. - -[AS1_D] -~w~Actúa como cebo y consigue que los escuadrones de la muerte te sigan hasta Pike Creek. - -[AS1_E] -~w~donde algunos de mis hombres estarán esperándoles. - -[AS2_C] -~w~el Cartel tiene una compañía de tapadera, el Kappa Coffe House. - -[AS2_E] -~w~No tenemos otra opción que poner esos puntos de venta de droga fuera de servicio. - -[AS2_F] -~w~¡¡Redúcelos a astillas!! - -[AS2_A1] -~w~Ciertamente Miguel tiene algo de esa famosa resistencia latina. - -[AS2_A2] -~w~Estoy muy agotado. - -[SIREN_3] -Para conectar las sirenas de este vehículo pulsa el ~h~ botón ~k~~VEHICLE_HORN~ ~w~. - -[SIREN_4] -Para conectar las sirenas de este vehículo golpea el ~h~ botón ~k~~VEHICLE_HORN~ ~w~. - -[AS3_C] -~w~¡Eeeeeeyoooo! ¿Qué ES esa cosa amarilla pegajosa? - -[AS3_C1] -~w~Oh, hola nena. - -[AS3_F] -~w~Tiene los atributos de una chica muy natural, esta nena. - -[AS3_F1] -~w~Se las ha arreglado para quitarle esta pequeña joya a nuestro invitado. - -[AS3_G] -~w~Hay un avión que está llegando al Francis International en 2 horas. - -[AS3_G1] -~w~Está lleno de veneno de Catalina. - -[AS3_H] -~w~Puedes evitar la seguridad del aeropuerto sacando un bote hasta las boyas luminosas. - -[AS3_H1] -y disparando al avión en su aterrizaje. - -[AS3_I] -~w~¡Recoge el cargamento de los escombros! - -[AS3_J] -~w~Oh, ten cuidado ahora, ¿VALE nena? - -[AS3_K] -~w~Ahora prueba el aceite picante... - -[RM2_F1] -¡Esos colombianos estarán aquí en cualquier momento! - -[RM2_K] -Maldición, ¡¡están aquí!! ¡¡ECHA EL PESTILLO Y CARGA!! - -[LOVE2_7] -~g~ ¡Ahora tira el coche! - -[LOVE2_8] -~g~¡Ahora sal de Newport! - -[AM1_F] -Salvatore Leone saldrá de Luigis a eso de las (~1~: ~1~). - -[LOVE5_C] -Quiero que le sigas, y asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. - -[FESZ_SR] -¡Error al guardar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. - -[FESZ_FO] -¿Deseas formatear la memory card (PS2) en la ranura de MEMORY CARD 1? - -[FELZ_FO] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. - -[FES_NOC] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. - -[FES_LOE] -¡Error al cargar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. - -[FES_DEE] -¡Error al borrar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. - -[FORSUC] -Memory card (PS2) de la ranura de MEMORY CARD 1 formateada con éxito. - -[ERFOUN] -¡Error al formatear la memory card (PS2)! - -[ERMCNP] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. - -[SVMEM1] -Guardar en la memory card (PS2) de la ranura de MEMORY CARD 1. - -[FORSLO] -Formatear memory card (PS2) de la ranura de MEMORY CARD 1. - -[SLONFM] -¡Error al formatear la memory card (PS2)! - -[SLONDR] -No hay espacio suficiente en la memory card (PS2). Inserta una memory card (PS2) con, al menos, 500KB de espacio libre en la ranura de MEMORY CARD 1. - -[SLNSP] -No hay espacio suficiente en la memory card (PS2). Inserta una memory card (PS2) con, al menos, 200KB de espacio libre en la ranura de MEMORY CARD 1. - -[FEFD_WR] -Formateando la memory card (PS2) de la ranura de MEMORY CARD 1. No extraigas la memory card (PS2), ni reinicies, o apagues la consola. - -[FES_ISF] -NO PRESENTE - -[FES_SAG] -PRESENTE - -[SLONNO] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. - -[SLONNF] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. - -[FESZ_FM] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. ¿Deseas formatear la memory card (PS2)? - -[FESZ_FF] -Error al formatear! Por favor comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. - -[MCDNSP] -No hay espacio suficiente en la memory card (PS2) de la ranura de MEMORY CARD 1. Inserta una memory card (PS2) con, al menos, 500KB de espacio libre para guardar los datos de esta aplicación. ¿Deseas empezar? (SI o NO) - -[MCGNSP] -No hay espacio suficiente en la memory card (PS2) de la ranura de MEMORY CARD 1. Se necesitan al menos 200KB para guardar los datos de esta aplicación. ¿Deseas empezar? (SI o NO) - -[FESZ_WR] -Guardando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. - -[FESZ_OW] -Sobrescribiendo datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. - -[FELD_WR] -Cargando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. - -[FEDL_WR] -Borrando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. - -[LM2_C] -Luigi dijo que, que te diera esto y así... - -[LM3_G] -Joey no es a quien estabas esperando, ¿recuerdas?, tienes el pie en la puerta... - -[LM5_E] -Consigue tanto dinero como puedas antes de que los policías se lo metan en el bolsillo. - -[JM5_C] -De acuerdo, hay un coche cargado con un fiambre en el café cercano a Callahan Point. - -[RM2_B] -Tuvimos acción en Nicaragua, en aquellos tiempos cuando el país sabía lo que estaba haciendo - -[RM2_C] -Algunos cerdos del Cartel le asustaron ayer, y dijeron que volverían hoy para quitarle parte de su almacén. - -[RM2_D1] -Iría yo mismo pero la vieja ciática está molestándome otra vez -achís, achís-, esto, ehhh... buena suerte. - -[CATINF1] -~g~¡Captura a Catalina! - -[CATINF2] -~g~Sigue al helicóptero para encontrar a Catalina. - -[BOATIN1] -Sube a un bote y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. - -[BOATIN2] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote para abordarlo. - -[BOATIN3] -Sube a un bote y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. - -[BOATIN4] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote para abordarlo. - -[JM6] -'LA HUÍDA' - -[FM1] -'CARABINA' - -[JM1] -'EL ULTIMO ALMUERZO DE 'MIKE 'LABIOS' - -[FM21] -'BOMBARDEA ESA BASE: ACTO I' - -[FM3] -'BOMBARDEA ESA BASE: ACTO II' - -[AM1] -'SAYONARA, SALVATORE' - -[AM2] -'BAJO VIGILANCIA' - -[KM2] -'GRAND THEFT AUTO' - -[AS3] -'S.A.M.' - -[RM2] -'SUMINISTRO DE ARMAS' - -[LOVE6] -'SEÑUELO' ' - -[LOVE1] -'EL LIBERADOR' - -[RC1] -'DESTRUCCIÓN DEL DIABLO' - -[RC2] -'LA MASACRE DE LA MAFIA' - -[RC3] -'CALAMIDAD EN EL CASINO' - -[RC4] -'ATAQUE RUMPO' - -[RM2_E1] -¡No puedo creer que esos bastardos de la barriga amarilla me dejaran sin la cobertura necesaria otra vez! - -[GREN_1] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. - -[GREN_2] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. - -[GREN_3] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. - -[LOVE4_G] -Mi propiedad estará esperándote en el angar de aduanas del avión. - -[KABOOM] -¡BOOM! - -[SPLAT] -¡PLOF! - -[PANCAK] -¡APLASTADO! - -[SOAKED] -¡EMPAPADO! - -[HEAD] -HEAD RADIO - -[DBL_CLF] -DOUBLE CLEF FM - -[FLASHB] -FLASHBACK FM - -[RISE] -RISE FM - -[LIPS] -LIPS 106 - -[CHAT] -CHATTERBOX FM - -[K_JAH] -K-JAH Radio - -[GAM_FM] -GAME FM - -[MSX_FM] -MSX FM - -[TUBE1] -Cuando el metro abra, podrás coger un tren hasta Staunton Island - -[TUBE2] -Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al aeropuerto Francis International. - -[TUBE_2] -Para abordar un tren del metro, pulsa el ~h~ botón 'entrar al vehículo' ~w~. - -[LEGAL] -~g~¡Eliminar la amenaza criminal! - -[GA_2] -Nuevo motor y trabajo de pintura. ¡Los policías no te reconocerán! - -[LM1_8A] -Para ganar un poco de dinero extra, por qué no 'tomar prestado' un taxi... - -[TAXIH1] -Para cerca de un peatón señalado para recogerlo, luego condúcelo a su destino antes de que se acabe el tiempo. - -[LM5_7] -~g~¡Menos de cuatro chicas trabajando el ~p~ Fuzz Ball ~g~ y Luigi no será feliz! - -[KM2_3] -~g~Recuerda los ~r~ coches ~g~ tienen que estar en perfecto estado para ser aceptados en el ~p~ garaje ~g~. - -[KM5_2] -~g~Un Yardie anda por las calles. - -[BETRA_A] -Perdón, cariño. - -[BETRA_B] -Soy una chica ambiciosa ¿y tú?, - -[BETRA_C] -eres tiempo perdido. - -[JAILB_Q] -Vamos! - -[JAILB_R] -Señor picha-boba! - -[JAILB_S] -No hay problema en matarte. - -[JAILB_T] -Vas a sentirlo. - -[JAILB_U] -De acuerdo, de acuerdo. Piérdete. - -[HELP15] -Cuando vayas a pié pulsa el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para ~h~ mirar atrás ~w~. - -[FEC_LB3] -Mira detrás - -[FEC_R3] -(botón R3) - -[FES_AFO] -Esta memory card (PS2) ya está formateada. +{ INTERFACE ARROWS } [FEA_UP] ; @@ -6568,170 +6901,1352 @@ Esta memory card (PS2) ya está formateada. [FEA_RI] > -[FEDSAS3] -- CAMBIAR SELECCION +{ ================================================================================ } +{ ================= REMNANTS FROM THE CONSOLE PAUSE MENU OPTIONS ================= } +{ ================================================================================ } -[FEDSAS4] -;=<> - CAMBIAR SELECCION +[FES_LGA] +Cargar partida -[SPRAY_4] -Usa el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[FES_NGA] +Nueva partida -[SPRAY_1] -Usa el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[PRVMEN] +Resúmenes de misiones anteriores -[LITTLE] -LITTLE T +[FEC_CCF] +Configuración: -[NICK] -NICK LOVE +[FEC_CF1] +Ajuste1 -[AM1_10] -~g~Salvatore estará abandonando Luigi's aproximadamente a las 0~1~:~1~. +[FEC_CF2] +Ajuste2 -[JAILB_V] -la ciudad de Liberty hoy está conmocionada. +[FEC_CF3] +Ajuste3 -[JAILB_A] -Así la policía y los servicios de urgencias se encargan de las secuelas ... +[FEC_CF4] +Ajuste4 -[JAILB_B] -de un ataque devastador a un convoy policial ocurrido esta mañana. +[FEC_CDP] +Controles a mostrar: -[JAILB_C] -Ningún detalle se ha hecho público sobre los prisioneros que estaban siendo trasladados en el convoy, +[FEC_ONF] +A pie -[JAILB_D] -Y ningún grupo ha admitido su responsabilidad. +[FEC_INC] +En vehículos -[JAILB_E] -El convoy abandonó las oficinas de la policía a primera hora de esta mañana... +[FEC_VIB] +Vibración: -[JAILB_F] -con el objeto de hacer una transferencia de rutina a la penitenciaría de Liberty. +[FEA_OUT] +Salida: -[JAILB_G] -El ataque se produjo en el puente de Callahan, +[FEA_ST] +Estéreo -[JAILB_H] -dejando pocos testigos y el puente notablemente dañado. +[FEA_MNO] +Mono -[JAILB_I] -Se cree que algunos de los convictos han perecido en la explosión... +[FEA_NON] +Ninguna -[JAILB_J] -que siguió al ataque inicial. +[ENGLIS] +Inglés -[JAILB_W] -Pasadas las horas parece evidente que el ataque propinado a la policía se llevó a cabo por profesionales, +[GERMAN] +Alemán -[JAILB_K] -Cuando la identificación de los delincuentes ausentes se había complicado más aún... +[ITALIA] +Italiano -[JAILB_L] -por un ataque de piratas informático a las bases de datos de los cuarteles de la policía. +[FRENCH] +Francés -[JAILB_O] -Con el proyecto del túnel Porter fuera del plazo previsto, +[SPAIN] +Español -[JAILB_P] -el desastre deja a Portland aislada del resto de la ciudad. +[FESZ_SA] +Guardar partida -[JAILB_M] -* +[FES_SLO] +ARCHIVO -[JAILB_N] -* +[FES_ISF] +NO PRESENTE -[JAILB_X] -En una declaración realizada hoy previamente, +[FES_SAG] +PRESENTE -[FEDS_SE] -Botón / - ELEGIR +[FES_ISC] +ESTÁ DAÑADO -[FEDS_SB] -Botón / - ELEGIR Botón " - VOLVER +[FESZ_TI] +ARCHIVO Z1 -[TM4_A] -~w~Oh, eres tú. TONI no está aquí. +{ =================================================================== } +{ ================= PLAYSTATION 2 EXCLUSIVE PROMPTS ================= } +{ =================================================================== } -[TM4_A2] -~w~Pero ha dejado para ti una de sus encantadoras cartas de amor. +[P1INSA] +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 tiene ~1~ KB de espacio disponible. Necesitas ~1~ KB para guardar. -[DIAB2_A] -¡Puse en marcha mi negocio de entretenimiento exótico de la nada, excepto lo que cabía en mis pantalones de cuero! +[P1INSN] +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 no tiene espacio suficiente. Por favor, borra algunos archivos. -[LM5_9] -CHICAS: +[P1NOIN] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. + +[FES_NOC] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. + +[P1INSE] +Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. + +[FESZ_SR] +¡Error al guardar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. + +[FESZ_FO] +¿Deseas formatear la Memory Card (PS2) en la ranura de MEMORY CARD 1? + +[FESZ_QF] +¿Seguro que quieres formatear la Memory Card (PS2) de la ranura de MEMORY CARD 1? + +[FELZ_FO] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. + +[SLONNF] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. + +[FESZ_FM] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. ¿Deseas formatear la Memory Card (PS2)? + +[FES_LOE] +¡Fallo al cargar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. + +[FES_DEE] +¡Fallo al borrar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. + +[FORSUC] +Memory Card (PS2) de la ranura de MEMORY CARD 1 formateada con éxito. + +[ERFOUN] +¡Error al formatear la Memory Card (PS2)! + +[SLONFM] +¡Error al formatear la Memory Card (PS2)! + +[ERMCNP] +No hay Memory Card (PS2) en la ranura de MEMORY CARD 1. + +[SVMEM1] +Guardando en la Memory Card (PS2) de la ranura de MEMORY CARD 1. + +[FORSLO] +Formateando Memory Card (PS2) de la ranura de MEMORY CARD 1. + +[SLONDR] +No hay espacio suficiente en la Memory Card (PS2). Inserta una Memory Card (PS2) con, al menos, 500KB de espacio libre en la ranura de MEMORY CARD 1. + +[SLNSP] +No hay espacio suficiente en la Memory Card (PS2). Inserta una Memory Card (PS2) con, al menos, 200KB de espacio libre en la ranura de MEMORY CARD 1. + +[FEFD_WR] +Formateando la Memory Card (PS2) de la ranura de MEMORY CARD 1. No extraigas la Memory Card (PS2), ni reinicies o apagues la consola. + +[SLONNO] +No hay una Memory Card (PS2) en la ranura de MEMORY CARD 1. + +[FESZ_FF] +¡Fallo al formatear! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. + +[MCDNSP] +No hay espacio suficiente en la Memory Card (PS2) de la ranura de MEMORY CARD 1. Inserta una Memory Card (PS2) con, al menos, 500KB de espacio libre para guardar los datos de esta aplicación. ¿Deseas empezar? (SÍ o NO) + +[MCGNSP] +No hay espacio suficiente en la Memory Card (PS2) de la ranura de MEMORY CARD 1. Se necesitan al menos 200KB para guardar los datos de esta aplicación. ¿Deseas empezar? (SÍ o NO) + +[FESZ_WR] +Guardando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. + +[FESZ_OW] +Sobrescribiendo datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. + +[FELD_WR] +Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. + +[MCLOAD] +Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. + +[FEDL_WR] +Borrando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. + +[FES_AFO] +Esta Memory Card (PS2) ya está formateada. + +[MCSTNS] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. ¿Quieres empezar? (SÍ o NO) + +[FES_GME] +Fallo al leer la Memory Card (PS2) de la ranura de MEMORY CARD 1. Compruébala e inténtalo de nuevo. + +[NOCONT] +Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. + +[NOCONTE] +Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. + +[WRCONT] +El mando conectado al puerto de mando 1 es un mando no compatible. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). + +[WRCONTE] +El mando conectado al puerto de mando 1 es un mando no compatible. Grand Theft Auto III necesita un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2). + +{ =============================================================== } +{ ================= CONTROLS MENU, ACTIONS (PC) ================= } +{ =============================================================== } + +[FEC_FIR] +Disparar + +[FEC_NWE] +Siguiente arma + +[FEC_PWE] +Arma anterior + +[FEC_FOR] +Avanzar + +[FEC_BAC] +Retroceder + +[FEC_LEF] +Izquierda + +[FEC_RIG] +Derecha + +[FEC_ZIN] +Acercar zoom + +[FEC_ZOT] +Alejar zoom + +[FEC_EEX] +Entrar /salir + +[FEC_RAD] +Radio + +[FEC_HRN] +Claxon + +[FEC_SUB] +Misión secundaria + +[FEC_CMR] +Cambiar cámara + +[FEC_JMP] +Saltar + +[FEC_SPN] +Esprintar + +[FEC_HND] +Freno de mano + +{ !!!!!!!!!!!!!!!!!! ACHTUNG! THIS STRING IS USED FOR BOTH THE MAP'S CURRENT TARGET AS WELL AS FOR THE ACTION OF TARGETING WITH A GUN! THIS WILL SCREW AROUND TRANSLATIONS !!!!!!!!!!!!!!! } +[FEC_TAR] +Objetivo + +[FEC_TUL] +Torreta a izq. + +[FEC_TUR] +Torreta a dcha. + +[FEC_TFU] +Torreta /Dodo arriba + +[FEC_TFD] +Torreta /Dodo abajo + +[FEC_LBA] +Mirar atrás + +[FEC_LOL] +Mirar a izq. + +[FEC_LOR] +Mirar a dcha. + +[FEC_NA] +No disponible + +{ ============================================================================ } +{ ================= CONTROLS MENU, ACTIONS, UNKNOWN LOCATION ================= } +{ ============================================================================ } + +[FEC_CLE] +Arma de la izquierda + +[FEC_CRI] +Arma de la derecha + +[FEC_MOV] +Movimiento + +[FEC_CAM] +Cambiar cámara + +[FEC_PAS] +Pausa + +[FEC_ENV] +Entrar en vehículo + +[FEC_RUN] +Correr + +[FEC_LL] +Mirar a la izquierda + +[FEC_LR] +Mirar a la derecha + +[FEC_LB] +Mirar atrás + +[FEC_RSC] +Cambiar emisora de radio + +[FEC_BRA] +Freno o marcha atrás + +[FEC_ACC] +Acelerar + +[FEC_SMT] +Activar misión especial + +[FEC_EXV] +Entrar/salir de vehículo + +[FEC_PED] +Controles a pie + +[FEC_VEH] +Controles en vehículos + +[FEC_FPR] +Controles en primera persona + +[FEC_CMM] +Controles comunes + +[FEC_PWL] +Ir a la izquierda + +[FEC_PWR] +Ir a la derecha + +[FEC_PWF] +Andar hacia delante + +[FEC_PWT] +Andar hacia la cámara + +[FEC_PLB] +Mirar hacia atrás + +[FEC_PFR] +Disparar arma + +[FEC_LKT] +Fijar objetivo + +[FEC_PJP] +Saltar a pie + +[FEC_PSP] +Esprintar a pie + +[FEC_PSH] +Disparar a pie + +[FEC_TLF] +Objetivo a la izq. + +[FEC_TRG] +Objetivo a la dcha. + +[FEC_CCM] +Centrar cámara tras jugador + +[FEC_SZI] +Acercar zoom de fusil + +[FEC_SZO] +Alejar zoom de fusil + +[FEC_LKL] +Mirar izq. en primera persona + +[FEC_LRT] +Mirar dcha. en primera persona + +[FEC_LUP] +Mirar arr. en primera persona + +[FEC_LDN] +Mirar abj. en primera persona + +[FEC_LBH] +Mirar hacia atrás en vehículo + +[FEC_LLF] +Mirar a la izq. en vehículo + +[FEC_LRG] +Mirar a la dch. en vehículo + +[FEC_HBR] +Freno de mano del vehículo + +[FEC_ACL] +Acelerar vehículo + +[FEC_BRK] +Frenar vehículo + +[FEC_TSM] +Misiones secundarias + +[FEC_CRD] +Cambiar emisora de radio + +[FEC_ENT] +Entrar /salir de vehículo + +[FEC_WPN] +Disparar arma + +[FEC_FPO] +Armas en primera persona + +[FEC_SMS] +Mostrar puntero del ratón + +[FEC_CMS] +Cambiar cámara en todas las situaciones + +[FEC_TSS] +Capturar pantalla + +[FEC_NTR] +Siguiente objetivo + +[FEC_PTT] +Objetivo anterior + +[FEC_CEN] +Centrar cámara + +[FEC_UND] +(NO) + +[FET_CFT] +A PIE + +[FET_CCR] +EN VEHÍCULO + +[FEC_TFL] +Torreta a izq. + +[FEC_TFR] +Torreta a dcha. + +[FEC_ORR] +o + +[FEC_NUS] +SIN USO + +[FEC_LUD] +Mirar arriba + +[FEC_LDU] +Mirar abajo + +{ ======================================================================================= } +{ ================= CONTROLS MENU, ACTIONS (REMNANTS FROM CONSOLE, PS2) ================= } +{ ======================================================================================= } + +[FEC_CWL] +Siguiente arma + +[FEC_CWR] +Arma anterior + +[FEC_LOF] +Mirar hacia delante + +[FEC_PAU] +Pausa + +[FEC_JUM] +Saltar + +[FEC_ATT] +Atacar o disparar + +[FEC_FPC] +Cámara en primera persona + +[FEC_VES] +Controlar vehículo + +[FEC_TUC] +Controlar torreta + +[FEC_SM3] +Activar misión secundaria (botón R3) + +[FEC_RS3] +Cambiar emisora de radio (botón L3) + +[FEC_HOR] +Claxon + +[FEC_HO3] +Claxon (botón L3) + +[FEC_LB3] +Mirar atrás + +[FEC_R3] +(botón R3) + +[FEC_LB1] +Mirar + +[FEC_LB2] +atrás + +[FEC_CAW] +Arma del vehículo + +[FEC_HAB] +Freno de mano + +{ ================================================================== } +{ ================= DEBUG STRINGS (CAN BE IGNORED) ================= } +{ ================================================================== } + +[FEC_DBG] +MENÚ DE DEPURACIÓN + +[FED_DBG] +Menú de depuración + +[FED_RID] +Recargar IDE + +[FED_RIP] +Recargar IPL + +[FED_PAH] +Analizar pila + +[FED_RCD] +CCullZones::RecalculateCullZoneData + +[FED_DFL] +CTheScripts::DbgFlag + +[FED_DLS] +Cambiar luz blanca grande de depuración + +[FED_SPR] +Mostrar grupos de peatones en carretera + +[FED_SCR] +Mostrar grupos de vehículos en carretera + +[FED_SCZ] +Mostrar zonas de máscara selectiva + +[FED_DSR] +Solicitudes de depuración de streaming + +[FED_SCP] +gbShowCollisionPolys + +[FEM_MCM] +Menú de Memory Card + +[FEM_RMC] +Registrar MemCard uno + +[FEM_TFM] +Probar MemCard uno formateada + +[FEM_TUM] +Probar Memcard uno sin formato + +[FEM_CRD] +Crear directorio raíz + +[FEM_CLI] +Crear y cargar iconos + +[FEM_FFF] +Llenar primer archivo con basura + +[FEM_SOG] +Guardar sólo partida + +[FEM_CES] +Comprobar cada guardado de 0kB4 + +[FEM_STG] +Guardar partida + +[FEM_STS] +Guardar partida bajo el nombre GTA3 + +[FEM_CPD] +Crear copia protegida del directorio mag + +[FEM_MC2] +Menú de Memory Card 2 + +[FEM_TS] +Prueba de guardado: + +[FEM_TL] +Prueba de carga: + +[FEM_TD] +Prueba de borrado: + +[RELIDE] +ReLoadIde + +[RELIPE] +ReLoadIpl + +[PARSHP] +Analizar pila + +[DBGFON] +CTheScripts::DbgFlag activado + +[DBFOFF] +CTheScripts::DbgFlag desactivado + +[BGWHON] +Luz blanca grande de depuración activada + +[BGWOFF] +Luz blanca grande de depuración desactivada + +[DSTRON] +Solicitudes de depuración de streaming activadas + +[DSTROFF] +Solicitudes de depuración de streaming desactivadas + +[PDRGON] +ShowPedRoadGroups activado + +[PRGOFF] +ShowPedRoadGroups desactivado + +[CRRGON] +ShowCarRoadGroups activado + +[CRGOFF] +ShowCarRoadGroups desactivado + +[CLZOON] +Zonas de máscara selectiva mostradas + +[CLZOOF] +Zonas de máscara selectiva ocultadas + +[SHPLON] +gbShowCollisionPolys activado + +[SHPLOF] +gbShowCollisionPolys desactivado + +[CULREC] +CCullZones::RecalculateCullZoneData() + +[FORMM1] +FormatMemCard 1 (prueba) + +[UNFRM1] +UnFormatMemCard 1 (prueba) + +[MEMTST] +Pantalla MemoryCardTest + +[REGCAR] +Registrar MemoryCard uno + +[TEFONE] +Probar MemCard uno con formato + +[TEUFON] +Probar MemCard uno sin formato + +[CRROOT] +CreateRootDir + +[CRLDIC] +Crear y cargar iconos + +[FLFSGF] +Llenar el primer archivo con basura + +[PUSAVE] +Guardar sólo la partida + +[CHEVOK] +CheckEveryOkB4Save + +[SVGMON] +SaveTheGame + +[CRMGSV] +Crear directorio de cargador con protección de copia + +[MGSVCN] +MagazineDirectory creado + +[MGSVNC] +MagazineDirectory no creado + +{ ======================================================================================================= } +{ ================= INGAME PLAYER STATISTICS. BE CAREFUL WITH WIDTH LIMITS IN 4:3 RATIO ================= } +{ ======================================================================================================= } + +{ ARTICLE ADDED BETWEEN NUMBERS } + +[FEST_OO] +de + +[PL_STAT] +Estadísticas de jugador + +[PE_WAST] +Personas asesinadas + +[PE_WSOT] +Personas asesinadas por otros + +[CAR_EXP] +Coches reventados + +[TM_BUST] +Veces arrestado + +[M_WASTE] +Hombres civiles asesinados + +[F_WASTE] +Mujeres civiles asesinadas + +[PIG_WST] +Polis asesinados + +[GNG_WST] +Maleantes asesinados + +[MED_WST] +Médicos asesinados + +[FIRE_WS] +Bomberos asesinados + +[DED_CRI] +Criminales asesinados + +[DED_DED] +Vagabundos asesinados + +[DED_HOK] +Prostitutas asesinadas + +[HEL_DST] +Helicópteros destruidos + +[PER_COM] +Porcentaje completado + +[KGS_EXP] +Kgs de explosivos empleados + +[ACCURA] +Precisión de tiro + +[ELBURRO] +Mejor tiempo de ''Turismo'' en segundos + +[CAR_CRU] +Coches destrozados + +[HED_EX] +Cabezas explotadas + +[TM_DED] +Visitas al hospital + +[DAYSPS] +Días de juego transcurridos + +[MMRAIN] +mm de lluvia caídos + +[MXCARD] +Dist. máx. de salto acrobático (pies) + +[MXCARJ] +Altitud máx. de salto acrobático (pies) + +[MXCARDM] +Dist. máx. de salto acrobático (metros) + +[MXCARJM] +Altitud máx. de salto acrobático (metros) + +[MXFLIP] +Vueltas durante salto acrobático + +[MXJUMP] +Rotación máx. de salto acrobático + +[BSTSTU] +Mejor acrobacia hasta ahora: + +[INSTUN] +Acrobacia + +[PRINST] +Acrobacia perfecta + +[DBINST] +Acrobacia doble + +[DBPINS] +Acrobacia doble perfecta + +[TRINST] +Acrobacia triple + +[PRTRST] +Acrobacia triple perfecta + +[QUINST] +Acrobacia cuádruple + +[PQUINS] +Acrobacia cuádruple perfecta + +[NOSTUC] +No se han hecho acrobacias + +[NOUNIF] +Saltos únicos completados + +[NOUNGM] +Saltos únicos + +[NMISON] +Misiones intentadas + +[NMMISP] +Misiones superadas + +[PASDRO] +Pasajeros transportados + +[MONTAX] +Dinero conseguido en taxi + +[DAYPLC] +Gasto diario de la policía + +[FEST_HA] +Nivel más alto de misión de sanitario + +[FEST_DF] +Distancia recorrida a pie (millas) + +[FEST_DC] +Distancia recorrida en coche (millas) + +[FESTDFM] +Distancia recorrida a pie (metros) + +[FESTDCM] +Distancia recorrida en coche (metros) + +[FEST_R1] +''Patio de recreo'' en segundos + +[FEST_R2] +''Un paseo por el parque'' en segundos + +[FEST_R3] +''¡Agarrado!'' en segundos + +[FEST_RM] +''Caos en el aparcamiento'' en segundos + +[FEST_LS] +Gente salvada con una ambulancia + +[FEST_CC] +Criminales asesinados en misiones de justiciero + +[FEST_FE] +Incendios extinguidos + +[FEST_LF] +Vuelo más largo en Dodo + +[FEST_BD] +Mejor tiempo al desactivar la bomba + +[FEST_RP] +Masacres superadas + +[FEST_MP] +Misiones superadas + +[FEST_BB] +Carrera forrada: + +[FEST_H0] +Máximo de puntos de control + +[FEST_GC] +Coches de bandas destruidos: + +[FEST_H1] +Destrucción de los Diablos + +[FEST_H2] +La masacre de la mafia + +[FEST_H3] +Calamidad en el casino + +[FEST_H4] +Exterminio de Rumpos [PERPIC] -Paquetes Ocultos encontrados +Paquetes ocultos encontrados -[CO_ONE] -Paquete Oculto ~1~ de ~1~ +[CRIMRA] +Rango de criminal: -[LOVE3_3] -~g~El avión ha tirado ~1~de los 6 paquetes. +{ ==================================================== } +{ ================= CRIMINAL RATINGS ================= } +{ ==================================================== } -[FARE11] -~g~Destino ~w~'Lugar en obras' ~g~ en Fort Staunton. +[RATNG1] +Carterista -[GA_21] -No puedes almacenar más coches en este aparcamiento. +[RATNG2] +Abusón -[CHEAT1] -Trampas activadas +[RATNG3] +Chorizo -[CHEAT2] -Arma trucada +[RATNG4] +Granuja -[CHEAT3] -Salud trucada +[RATNG5] +Secuaz -[CHEAT4] -Armadura trucada +[RATNG6] +Conductor -[CHEAT5] -Nivel de Se Busca trucado +[RATNG7] +Guardaespaldas -[CHEAT6] -Dinero trucado +[RATNG8] +Negociador -[CHEAT7] -Clima trucado +[RATNG9] +Socio -[AS1_H] -~r~¡¡No has conseguido guiar al Escuadrón de la Muerte a la trampa del Yakuza!! +[RATNG10] +Sicario -[FEDS_BA] -Botón "- VOLVER +[RATNG11] +Asesino -[RAMP_A] -¡COMPLETADAS TODAS LAS RAMPAS! +[RATNG12] +Mano derecha + +[RATNG13] +Verdugo + +[RATNG14] +Capo + +[RATNG15] +Jefe + +{ =========================================================== } +{ ================= PAUSE MENU OPTIONS (PC) ================= } +{ =========================================================== } + +[FEP_STA] +ESTADÍSTICAS + +[FEP_BRI] +RESUMEN + +[FEP_CON] +CONTROLES + +[FEP_AUD] +SONIDO + +[FEP_DIS] +PANTALLA + +[FEP_LAN] +IDIOMA + +{ ============================================================= } +{ ================= MIXED BAG OF MENU OPTIONS ================= } +{ ============================================================= } + +[GMSTOR] +Almacenar partida + +[PREBRF] +Resúmenes anteriores + +[CNTLS] +Controles + +[MUSMEN] +Música/Efectos + +[GAMSET] +Ajustes del juego + +[LANGUA] +Idioma + +[DSPLAY] +Pantalla + +[DEBUGM] +Menú de depuración + +[QUITOP] +Salir de las opciones + +[CONTRL] +Configuración de controles + +[SET1EN] +Ajuste 1. Activado + +[SET1] +Ajuste 1. + +[SET2EN] +Ajuste 2. Activado + +[SET2] +Ajuste 2 + +[SET3EN] +Ajuste 3. Activado + +[SET3] +Ajuste 3 + +[SET4EN] +Ajuste 4. Activado + +[SET4] +Ajuste 4 + +[GOBACK] +Volver + +[SOUND] +SONIDO + +[MUSVOL] +Volumen de la música + +[SFXVOL] +Volumen de los efectos + +[SCROPT] +OPCIONES DE PANTALLA + +[CTRSCR] +Centrar pantalla + +[SCRFOR] +Formato de imagen + +[GMSVLQ] +GUARDAR-CARGAR-SALIR + +[GMREST] +Reiniciar partida + +[NOGMSV] +Sólo puedes guardar desde tu escondite. + +[DLFILE] +Borrar archivos de Grand Theft Auto III + +[CHFILE] +ELEGIR ARCHIVO A CARGAR + +[CHCDLD] +ELEGIR MEMORY CARD A USAR + +[CHFIDL] +ELEGIR ARCHIVO A BORRAR + +[CDUNFR] +Memory Card sin formato. + +[SVCONF] +CONFIRMACIÓN + +[SVFNAM] +El nombre de tu archivo guardado es + +[SAVEDN] +Error. Fallo al guardar. + +[LANGSL] +SELECCIÓN DE IDIOMA + +[GORLEV] +Nivel de violencia + +[SICASS] +Puta locura + +[SICSIC] +Puto manicomio + +[SCASSL] +Seleccionado Puta locura + +[SCSCSL] +Seleccionado Puto manicomio + +[DOSVGM] +¿Deseas guardar la partida? + +[FORMEN] +Menú de formato + +[CNTSAV] +No se puede guardar la partida en una misión. + +[CNCSAV] +No se puede guardar la partida dentro de un vehículo. + +[YES] +Sí + +[NO] +No + +[X] +x + +[LAST] +Último mensaje + +[FIRST] +~g~1.° + +[SECOND] +~g~2.° + +[THIRD] +~g~3.° + +[FOURTH] +~g~4.° + +[WRONGCD] +Disco incorrecto. Introduce el disco correcto. + +[NOCD] +La bandeja del disco está vacía. Introduce un disco. + +[OPENCD] +La bandeja del disco está abierta. Cierra la bandeja de disco. + +[CDERROR] +Error al leer el DVD de Grand Theft Auto III + +[RESTART] +Empezando una nueva partida + +[STOCK] +mercancía agotada + +[BAT1] +~g~¡Coge el bate! + +[FE_INIP] +Iniciando y cargando el menú de pausa... Espera, por favor. + +[FESZ_CA] +Cancelar + +[FESZ_QU] +Abandonar + +[FESZ_L1] +¡La partida se ha guardado! + +[FESZ_L2] +El nombre guardado es: + +[FESZ_OK] +ACEPTAR + +[FES_CAN] +Cancelar + +[FESZ_QL] +Perderás todo el progreso en tu partida actual. ¿Quieres continuar con la carga? + +[FESZ_QD] +¿Quieres borrar esta partida guardada? + +[FESZ_QO] +¿Quieres sobreescribir esta partida guardada? + +[FESZ_QR] +¿Seguro que quieres empezar una nueva partida? Perderás todo el progreso desde la última partida guardada. + +[FESZ_QS] +¿QUIERES GUARDAR? + +[UPSIDE] +~r~¡Has volcado! + +[1010] +~r~Tu vehículo ha volcado + +[1011] +~r~Tu vehículo ha volcado + +[1012] +~r~Tu vehículo ha volcado + +[1013] +~r~Tu vehículo ha volcado + +[1014] +~r~Tu vehículo ha volcado + +[DETON] +DETONACIÓN: + +[RECORD] +~g~¡NUEVO RÉCORD! + +[NRECORD] +~r~¡NO HAY UN NUEVO RÉCORD! + +[WELCOME] +BIENVENIDO A + +[TSCORE] +GANANCIAS: ~1~ $ + +[FESZ_UC] +CANCELAR + +[FES_LOF] +Fallo al cargar. + +[MC_LDFL] +¡Fallo al cargar! + +[MC_NWRE] +Reiniciando partida. + +{ ============================================================================================== } +{ ================= STRINGS RELATED TO VEHICLE STUNTS (NOT INCLUDING THE DODO) ================= } +{ ============================================================================================== } + +[HJSTAT] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. + +[HJSTATW] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! + +[HJSTATF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. + +[HJSTAWF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! [USJ_ALL] -¡COMPLETADAS TODAS LOS MANIOBRAS ÚNICAS! +¡TODAS LAS ACROBACIAS COMPLETADAS! -[FARE23] -~g~Destino ~w~'garaje importación exportación' ~g~en el distrito de Cochrane Dam +[USJ] +¡PREMIO POR ACROBACIA ÚNICA! -[L_TRN_1] -Puedes alcanzar el tren-L que rodea Portland. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o salir~w~de un tren. +[HJ_IS] +PREMIO POR ACROBACIA: ~1~$ -[L_TRN_2] -Puedes alcanzar el tren-L que rodea Portland. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o salir~w~de un tren. +[HJ_PIS] +PREMIO POR ACROBACIA PERFECTA: ~1~$ -[S_TRN_1] -Puedes tomar los trenes subterráneos que recorren Liberty. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o salir~w~de un tren. +[HJ_DIS] +PREMIO POR ACROBACIA DOBLE: ~1~$ -[S_TRN_2] -Puedes tomar los trenes subterráneos que recorren Liberty. Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o salir~w~de un tren. +[HJ_PDIS] +PREMIO POR ACROBACIA DOBLE PERFECTA: ~1~$ -[AS1_C] -~w~Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty y cuyo único objetivo es el de darte caza. +[HJ_TIS] +PREMIO POR ACROBACIA TRIPLE: ~1~$ -[AS1_G] -~r~¡¡Todos los Yakuza están muertos!! +[HJ_PTIS] +PREMIO POR ACROBACIA TRIPLE PERFECTA: ~1~$ + +[HJ_QIS] +PREMIO POR ACROBACIA CUÁDRUPLE: ~1~$ + +[HJ_PQIS] +PREMIO POR ACROBACIA CUÁDRUPLE PERFECTA: ~1~$ + +{ ================================================ } +{ ================= DATE STRINGS ================= } +{ ================================================ } [JAN] Ene @@ -6776,355 +8291,20 @@ Dic COCHES RESTANTES: [BONUS] -~g~EXTRA ~1~$ - -[HORN1] -Pulsa el ~h~botón L3 ~w~ para tocar el ~h~claxon. - -[HORN2] -Pulsa el ~h~botón L1 ~w~ para tocar el ~h~claxon. - -[HORN3] -Pulsa el ~h~botón R1 ~w~ para tocar el ~h~claxon. - -[LM3_1A] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y hacer saber a Misty que estás allí. - -[LM3_1B] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y hacer saber a Misty que estás allí. - -[LM3_1C] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y hacer saber a Misty que estás allí. - -[RADIO_A] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. - -[RADIO_B] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. - -[RADIO_C] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. - -[RADIO_D] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. - -[FEC_EXV] -Entrar y salir del vehículo - -[TAXI_M] -'TAXISTA' - -[COP_M] -'VIGILANTE' - -[FIRE_M] -'BOMBERO' - -[AMBUL_M] -'PARAMÉDICO' - -[HJ_IS] -PRIMA POR ESCENA LOCA: ~1~$ - -[HJ_PIS] -PRIMA POR ESCENA LOCA PERFECTA ~1~$ - -[HJ_DIS] -PRIMA POR DOBLE ESCENA LOCA ~1~$ - -[HJ_PDIS] -PRIMA POR DOBLE ESCENA LOCA PERFECTA ~1~$ - -[HJ_TIS] -PRIMA POR TRIPLE ESCENA LOCA ~1~$ - -[HJ_PTIS] -PRIMA POR TRIPLE ESCENA LOCA PERFECTA ~1~$ - -[HJ_QIS] -PRIMA POR CUÁDRUPLE ESCENA LOCA ~1~$ - -[HJ_PQIS] -PRIMA POR CUÁDRUPLE ESCENA LOCA PERFECTA ~1~$ - -[AM1_K] -Salvatore Leone estará saliendo de Luigi's en unas tres horas. (0~1~:~1~) - -[IMPEXPP] -El garaje Importación Exportación, Puerto de Portland. Tenemos órdenes para varios vehículos. Revisa nuestro tablón de notas para ver necesidades. - -[VANHSTP] -¿Algunos coches de seguridad cascados? Llévalos a nuestro garaje en el Puerto de Portland. - -[EMVHPUP] -Se han pagado grandes porcentajes por coches nuevos/usados. Llévalos a la grúa que hay al noroeste del Puerto de Portland. +~g~~1~$ ADICIONALES [STANDS] -ESCALERAS ROTAS: +PUESTOS DESTROZADOS: -[STASH] -¡~g~Guarda el SPANK en la parte trasera de la ~p~zona en construcción! - -[MCSTNS] -No hay memory card (PS2) insertada en la ranura para MEMORY CARD 1. ¿Quieres empezar? (SI o NO) - -[LOVE3_5] -~g~El avión está ahora a tu alcance. - -[LOVE3_6] -¡~r~La Poli encontró antes los paquetes! - -[SIREN_1] -Para poner en marcha las sirenas de estos coches, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. - -[SIREN_2] -Para poner en marcha las sirenas de estos coches, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. - -[FM3_8C] -~w~Necesitaré 100.000 $ para cubrir gastos. - -[MCLOAD] -Cargando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. - -[FES_GME] -Error al leer la memory card (PS2) de la ranura de MEMORY CARD 1. Por favor compruébalo e inténtalo de nuevo. - -[FESZ_QF] -¿Estás seguro que quieres formatear la memory card (PS2) de la ranura de MEMORY CARD 1? +{ ======================================================= } +{ ================= PC SPECIFIC STRINGS ================= } +{ ======================================================= } [FESZ_LS] -Cargado con éxito. - -[RM3_5] -~g~Tienes ~1~ de 6 paquetes de pruebas. - -[LOVE3_2] -¡~g~Tienes todos los paquetes! Llévalos de vuelat a Donald Love. - -[LOVE4_4] -¡~g~Lleva el paquete de vuelta a Donald Love! - -[FEB_SAV] -Cargar +Carga completada. [FEP_SAV] -CARGAR JUEGO - -[AS2_12A] -Después de destrozar el primer puesto, ¡tendrás 8 mintutos antes que el Cartel envíe a sus matones! - -[AS3_1A] -¡~g~Ahora vete al ~b~boya del aeropuerto! - -[NOCONT] -Por favor, para continuar vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1. - -[BET_JB] -TRAICIONADO POR CATALINA, SU AMANTE Y ABANDONADO PARA QUE MURIERA. CONDENADO Y SENTENCIADO, INICIA SU VIAJE A LA PRISIÓN DE LIBERTY CITY. PERO SÓLO TIENE UN PENSAMIENTO... ¡VENGANZA! - -[END_A] -Los Residentes de Cedar Groove se adaptan a las consecuencias - -[END_B] -emocionales tras el estallido de la guerra - -[END_C] -que se produjo ayer en la zona. - -[END_D] -Un residente local, Clive Denver describió a la policía - -[END_E] -a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. - -[END_F] -Oh, sabes, vamos a pasar un buen rato, porqué lo sabes. - -[END_G] -Te quiero, Yo, yo, yo realmente te quiero, porque eres un hombre tan fuerte - -[END_H] -y eso es todo lo que necesito. - -[END_I] -Bueno, ¿qué estaba diciendo? - -[END_J] -Oh, sabes, lo he olvidado. Pero sabes lo que quiero decir, ¿verdad? - -[END_K] -El sonido de las explosiones sacudieros las casas más próximas, la gente se esconde. - -[END_L] -Varios ciudadanos resultaron heridos a causa del tiroteo entre - -[END_M] -las fuerzas terrestres y un helicóptero que rodeaba a la presa. - -[END_N] -Sí, aquí en los jardínes tenemos una vista excelente. - -[END_O] -Cuando finalmente el helicóptero consiguió escapar, - -[END_P] -mejor que los fuegos artificiales del 4 de Julio. - -[END_Q] -Con un número de víctimas superior a veinte, - -[END_R] -la policía continúa buscando cuerpos. - -[END_S] -No han habido desmentidos oficiales acerca de los rumores - -[END_T] -de que los muertos eran miembros de Cartel Colombiano, - -[END_U] -y se sigue sin pistas que aclaren las causas de la masacre. - -[END_V] -Me he roto una uña y me pelo hecho un asco, ¿puedes creértelo? - -[PAPER1] -UN DISPARO CRIMINAL REALIZADO POR SU NOVIA Y CÓMPLICE. EL TRIBUNAL CON UN VERDICTO ANÓNIMO, ENCUENTRA CULPABLE AL LADRÓN ARMADO. - -[PAPER2] -¡DIEZ AÑOS POR AMOR! - -[END_W] -Me ha costado cincuenta dólares... - -[FEB_CPC] -Configuración del control - -[FEC_PED] -Controles a pie - -[FEC_VEH] -Controles en vehículo - -[FEC_FPR] -Controles en primera persona - -[FEC_CMM] -Controles comunes - -[FEC_PWL] -IR a la izquierda - -[FEC_PWR] -IR a la derecha - -[FEC_PWF] -Andar hacia delante - -[FEC_PWT] -Andar hacia la cámara - -[FEC_PLB] -Mirar hacia atrás. - -[FEC_PFR] -Disparar arma - -[FEC_CLE] -Cambiar Arma a la Izq. - -[FEC_CRI] -Cambiar Arma a la Dcha. - -[FEC_LKT] -Bloquear objetivo - -[FEC_PJP] -Salto Peatón - -[FEC_PSP] -Sprint Peatón - -[FEC_PSH] -Disparar Peatón - -[FEC_TLF] -Siguiente objetivo a la izq. - -[FEC_TRG] -Siguiente objetivo a la dcha. - -[FEC_CCM] -Centrar cámara detrás del jugador. - -[FEC_SZI] -Acercar rifle francotirador - -[FEC_SZO] -Alejar rifle francotirador - -[FEC_LKL] -Mirar izq. en primera persona - -[FEC_LRT] -Mirar dcha. en primera persona - -[FEC_LUP] -Mirar arr. en primera persona - -[FEC_LDN] -Mirar abj. en primera persona - -[FEC_LBH] -Mirar hacia atrás en vehículo - -[FEC_LLF] -Mirar a la izq. en vehículo - -[FEC_LRG] -Mirar a la dch. en vehículo - -[FEC_HRN] -Claxon - -[FEC_HBR] -Freno de mano del vehículo - -[FEC_ACL] -Acelerar vehículo - -[FEC_BRK] -Frenar vehículo - -[FEC_TSM] -Intercambiar SubMisiones Sí/No - -[FEC_CRD] -Cambiar emisoras de radio - -[FEC_ENT] -Entrar/Salir del vehículo - -[FEC_WPN] -Disparar arma - -[FEC_PAS] -Pausa - -[FEC_FPO] -Cambiar armas primera persona. - -[FEC_SMS] -Cambiar puntero del ratón. - -[FEC_CMS] -Cambiar modo cámara en todas situaciones. - -[FEC_TSS] -Capturar pantalla - -[FEN_STA] -INICIAR JUEGO +CARGAR PARTIDA [FEN_NET] Red @@ -7133,10 +8313,10 @@ Red Conexión [FEN_GAM] -Buscar juego +Buscar partida [FEN_TYP] -Tipo de juego +Tipo de partida [FEN_TY0] Duelo a muerte @@ -7145,19 +8325,19 @@ Duelo a muerte Duelo a muerte sigiloso [FEN_TY2] -Equipo Duelo a muerte +Duelo a muerte en equipo [FEN_TY3] Duelo a muerte sigiloso en equipo [FEN_TY4] -Acumula efectivo +Busca la pasta [FEN_TY5] Captura la bandera [FEN_TY6] -Rat race +Carrera de locos [FEN_TY7] Dominación @@ -7166,7 +8346,7 @@ Dominación Nombre: [FEN_GNA] -Nombre del juego: +Nombre de partida: [FEM_MAP] Elegir mapa @@ -7181,7 +8361,7 @@ Color del jugador Liberty City [FEM_MA1] -RedLight +Barrio rojo [FEM_MA2] Chinatown @@ -7190,112 +8370,94 @@ Chinatown La Torre [FEM_MA4] -La alcantarilla +Alcantarillas [FEM_MA5] Zona industrial [FEM_MA6] -Los muelles +Muelles [FEM_MA7] Staunton [FEC_EMS] -Por favor sólo teclas de teclado. - -[FEC_DBG] -Menú de depuración +Sólo se permiten teclas del teclado. [FEC_TGD] Cambiar mando de juego/depuración [FEC_TDO] -Cambiar cámara depuración No +Desactivar cámara de depuración [FEC_IVH] Invertir horizontalidad ratón -[FEC_MSL] -BIR - -[FEC_MSM] -BCR - -[FEC_MSR] -BDR - -[FEC_QUE] -??? - [FEC_TWO] -Permitidas sólo dos teclas del teclado +Sólo se permiten dos teclas del teclado. [FEC_UMS] -Por favor sólo teclas de ratón. +Sólo se permiten botones del ratón. [FEC_OMS] -Permitida sólo una tecla del ratón +Sólo se permite un botón del ratón. [FEC_UJS] -Por favor sólo botones de joystick. +Sólo se permiten botones del joystick. [FEC_OJS] -Permitido sólo un botón de joystick por acción +Sólo se permite un botón del joystick por acción. [FEC_PTL] -Usar Bloquear objetivo al cambiar arma a izq. +Usar Fijar objetivo con Siguiente arma. [FEC_PTR] -Usar Bloquear objetivo al cambiar arma a dcha. +Usar Fijar objetivo con Arma anterior. [FEC_LBC] Usar Mirar a izq. con Mirar a la dcha. -[FEC_JBO] -JOY ~1~ - [NO_PAUZ] -No se puede detener en multijugador. ¡Pulsa 2 veces para salir! +No se puede parar una partida multijugador. ¡Pulsa dos veces para salir! [FEM_SL1] -Hueco 1 libre +Espacio 1 libre [FEM_SL2] -Hueco 2 libre +Espacio 2 libre [FEM_SL3] -Hueco 3 libre +Espacio 3 libre [FEM_SL4] -Hueco 4 libre +Espacio 4 libre [FEM_SL5] -Hueco 5 libre +Espacio 5 libre [FEM_SL6] -Hueco 6 libre +Espacio 6 libre [FEM_SL7] -Hueco 7 libre +Espacio 7 libre [FEM_SL8] -Hueco 8 libre +Espacio 8 libre [FEM_MM] MENÚ PRINCIPAL [FEM_SNG] -Iniciar nuevo juego +NUEVA PARTIDA [FEM_QTW] Salir [FEQ_SRE] -¿Estás seguro de querer salir? Se perderán todos los progresos desde la última partida guardada. ¿Quieres proceder? +¿Seguro que quieres salir del juego? Se perderán todos los progresos desde la última partida guardada. [FEQ_SRW] -¿Estás seguro de querer salir del juego? +¿Seguro que quieres salir del juego? [FEG_SRV] SERVIDOR @@ -7313,46 +8475,46 @@ TIPO PING [FET_FG] -DETECTAR JUEGO +ENCONTRAR PARTIDA [FET_SP] -JUGADOR INDIVIDUAL +UN JUGADOR [FET_MP] MULTIJUGADOR [FET_HG] -ALOJAR JUEGO +CREAR PARTIDA [FET_PS] -CONFIG. JUGADOR +AJUSTES DE JUGADOR [FET_CON] CONEXIÓN [FET_AUD] -CONFIG. AUDIO +AJUSTES DE AUDIO [FET_GFX] -CONFIG. GFX +AJUSTES GRÁFICOS [FET_DIS] -AJUSTE DE PANTALLA +AJUSTES DE PANTALLA [FET_LAN] -DEFINIR IDIOMA +AJUSTES DE IDIOMA [FET_LG] -CARGAR JUEGO +CARGAR PARTIDA [FET_DG] -BORRAR JUEGO +BORRAR PARTIDA [FET_NG] -PARTIDA NUEVA +NUEVA PARTIDA [FET_SG] -GUARDAR JUEGO +GUARDAR PARTIDA [FET_MAP] ELEGIR MAPA @@ -7361,7 +8523,25 @@ ELEGIR MAPA TIPO DE JUEGO [FET_CTL] -AJUSTE DEL MANDO +AJUSTES DEL MANDO + +[FET_CT1] +VER CONTROLES + +[FET_CT2] +CONTROLES A PIE + +[FET_CT3] +CONTROLES EN VEHÍCULO + +[FET_CT4] +STICK PARA CONDUCIR + +[FET_CT5] +GIRAR AL INCLINAR + +[FET_CT6] +STICK PARA ZURDOS [FET_OPT] OPCIONES @@ -7373,40 +8553,40 @@ SALIR DEL JUEGO ESTADÍSTICAS [FET_BRE] -INFORMES +RESUMEN [FEC_WAR] Aviso [FEC_OKK] -Aceptar +ACEPTAR [FED_CON] -Confirmación borrar archivo +Confirmación de borrado [FES_SSC] -Juego guardado con éxito. +Partida guardada. [DEL_FNM] -Juego eliminado con éxito. +Partida eliminada. [PCLOAD] -Cargando datos del juego +Cargando datos de la partida [PCRESRT] Reiniciando Grand Theft Auto III [FEC_DLF] -Error al borrar. +Fallo al borrar. [FEC_SVU] -Error al guardar. +Fallo al guardar. [FEC_LUN] -Error al cargar. Archivo dañado, por favor borrar. +Fallo al cargar. Archivo dañado, por favor, bórralo. [FEN_PLA] -Número de Jugadores: +Número de jugadores: [FET_NON] NO HAY PARTIDAS DISPONIBLES @@ -7424,25 +8604,25 @@ RED LOCAL INTERNET [FET_REF] -Refrescar +Actualizar [FET_FIL] -Filtro +Filtrar [FET_JG] Unirse [FEC_NTW] -Talk To Network +Conectar con red [FEC_ESR] Tecla Esc limitada [FEC_GSL] -Show head bob: +Balanceo de cabeza: [FIL_FLT] -FILTRAR LISTAS DE JUEGOS +FILTRAR LISTAS DE PARTIDAS [FET_SAN] INICIAR NUEVA PARTIDA @@ -7457,10 +8637,10 @@ Servidor: Tipo de juego: [FIL_SPC] -¿Juegos con espacio disponible? +¿Partidas que no estén llenas? [FIL_PNG] -Ping: +Latencia: [FEN_UKH] Anfitrión desconocido @@ -7475,16 +8655,16 @@ Tipo de juego no encontrado NO CONECTADO A INTERNET [FET_PAU] -MENÚ PAUSA +MENÚ DE PAUSA [FET_SGA] -INICIAR JUEGO +INICIAR PARTIDA [FEC_SGJ] -Establecer Joystick de juego +Establecer joystick de juego [FEC_PAD] -Gamepad +Mando [FEC_JOY] Joystick @@ -7495,119 +8675,35 @@ Volante [FEC_CNT] Tipo de mando: -[FET_APL] -APLICAR - [FES_CSA] -Seleccionar aspecto de la lista inferior: +Selecciona una apariencia: [FES_SKN] -NOMBRE DEL ASPECTO +NOMBRE DE APARIENCIA [FES_DAT] FECHA [FES_NON] -NO HAY SKINS DISPONIBLES +NO HAY APARIENCIAS DISPONIBLES [FEA_FM9] REPRODUCTOR MP3 [FESZ_QZ] -¿Estás seguro que deseas guardar esta partida? +¿Seguro que deseas guardar esta partida? [FES_CGA] -Huecos del juego disponibles: +Espacios de partida disponibles: [FES_SCG] -¿Guardar el juego actual? +¿Guardar la partida actual? [FES_LCG] -¿Cargar el juego y seguir jugando? - -[FEC_FIR] -Disparar - -[FEC_NWE] -Siguiente arma - -[FEC_PWE] -Arma anterior - -[FEC_FOR] -Avanzar - -[FEC_BAC] -Hacia atrás - -[FEC_LEF] -Izquierda - -[FEC_RIG] -Derecha - -[FEC_ZIN] -Acercar zoom - -[FEC_ZOT] -Alejar zoom - -[FEC_EEX] -Entrar+salir - -[FEC_RAD] -Radio - -[FEC_SUB] -Rendición - -[FEC_CMR] -Cambiar cámara - -[FEC_JMP] -Saltar - -[FEC_SPN] -Esprint - -[FEC_HND] -Freno de mano - -[FEC_TUL] -Torreta a la izqd. - -[FEC_TUR] -Torreta a la dcha. - -[FEC_LOL] -Mirar a la izq. - -[FEC_LOR] -Mirar a la dcha. - -[FEC_NTR] -Siguiente objetivo - -[FEC_PTT] -Objetivo anterior - -[FEC_LBA] -Mirar atrás - -[FEC_CEN] -Centrar cámara - -[FEC_UND] -(NO) - -[FET_CFT] -A PIE - -[FET_CCR] -EN VEHÍCULO +¿Cargar partida y seguir jugando? [CVT_MSG] -Convertir texturas a un formato óptimo para tu tarjeta de vídeo +Convirtiendo texturas a un formato óptimo para tu tarjeta de vídeo [FET_CAC] ACCIÓN @@ -7615,17 +8711,8 @@ ACCIÓN [FEC_IBT] - -[FEC_SPC] -BES - -[FEC_MXO] -MXB1 - -[FEC_MXT] -MXB2 - [FEC_UNB] -SIN ESTABLECER +SIN ASIGNAR [FET_CME] MÉTODO DE CONTROL @@ -7643,55 +8730,59 @@ CONFIGURACIÓN DE CONTROL ESTÁNDAR CONFIGURACIÓN DE CONTROL CLÁSICA [FET_MTI] -CONFIGURACIÓN DE CONTROL DEL RATÓN +CONFIGURACIÓN DE CONTROL CON RATÓN [FET_DAM] MODELADO ACÚSTICO DINÁMICO -[FEC_TFL] -Torre Izquierda - -[FEC_TFR] -Torre derecha - -[FEC_TFU] -Torre /Dodo arriba - -[FEC_TFD] -Torre /Dodo abajo - -[FEC_MWF] -RUEDA ARR - -[FEC_MWB] -RUEDA AB - -[FEC_ORR] -o - -[FEC_NUS] -SIN USO - -[FEC_LUD] -Mirar Ar - -[FEC_LDU] -Mirar Ab - [FEC_CMP] -COMOBO: MIRAR I+D +COMBO: MIRAR I+D [FEC_NTT] No hay texto para esta tecla +{ ==================================================================================== } +{ ================= PC SPECIFIC STRINGS - AVAILABLE KEYS AND BUTTONS ================= } +{ ==================================================================================== } + +[FEC_MSL] +BIR + +[FEC_MSM] +BCR + +[FEC_MSR] +BDR + +[FEC_QUE] +¿? + +[FEC_JBO] +JOY ~1~ + +[FEC_SPC] +ESPACIO + +[FEC_MXO] +MXB1 + +[FEC_MXT] +MXB2 + +[FEC_MWF] +RUEDA ARR. + +[FEC_MWB] +RUEDA AB. + [FEC_FNC] F~1~ [FEC_IRT] -INS +INSERT [FEC_DLL] -SUP +SUPR [FEC_HME] INICIO @@ -7700,10 +8791,10 @@ INICIO FIN [FEC_PGU] -REPAG +RE PÁG [FEC_PGD] -AVPAG +AV PÁG [FEC_UPA] ARRIBA @@ -7712,7 +8803,7 @@ ARRIBA ABAJO [FEC_LFA] -IZQDA +IZDA [FEC_RFA] DCHA @@ -7745,10 +8836,10 @@ INTRO BLOQ DESPL [FEC_PSB] -PAUSA INTER +PAUSA/INTER [FEC_BSP] -RETROCEDER +RETROCESO [FEC_TAB] TAB @@ -7763,52 +8854,55 @@ INTRO MAYÚS IZQ [FEC_RSF] -MAYÚS DCH +MAYÚS DCHA [FEC_LCT] -CONTROL I +CTRL IZQ [FEC_RCT] -CONTROL D +CTRL DCHO [FEC_LAL] -ALT I +ALT IZQ [FEC_RAL] -ALT D +ALT DCHO [FEC_LWD] -WIN I +WIN IZQ [FEC_RWD] -WIN D +WIN DCHO [FEC_WRC] APMENÚ +[FEC_STR] +NUM. INICIO + +[FEC_SFT] +MAYÚS + [WIN_TTL] Grand Theft Auto III [WIN_95] -Grand Theft Auto III no se puede ejecutar bajo W95 +Grand Theft Auto III no se puede ejecutar bajo Windows 95 [WIN_DX] Grand Theft Auto III necesita al menos la versión 8.1 de DirectX [WIN_VDM] -Grand Theft Auto III necesita al menos 12MB de espacio de memoria de vídeo - -[DIAB3_G] -¡Arriba! +Grand Theft Auto III necesita al menos 12 MB de memoria de vídeo [FEM_RES] -REANUDAR JUEGO +REANUDAR PARTIDA [FES_SNG] -INICIAR NUEVO JUEGO +INICIAR NUEVA PARTIDA [FEM_SP] -Jugador individual +UN JUGADOR [FEM_MP] MULTIJUGADOR @@ -7820,49 +8914,46 @@ SALIR INICIAR NUEVA PARTIDA [FES_LG] -CARGAR JUEGO +CARGAR PARTIDA [FEM_HST] -ALOJAR JUEGO +CREAR PARTIDA [FEM_OPT] OPCIONES [FEM_DBG] -Corregir errores +DEPURACIÓN [FET_PSU] -CONFIG. JUGADOR +AJUSTES DE JUGADOR [FET_DEF] -RESTAURAR VALORES +RESTAURAR PREDETERMINADOS [FED_BRI] BRILLO [FED_TRA] -RASTROS +ESTELAS [FEM_LOD] -DISTANCIA DE REPRESENTACIÓN +DISTANCIA DE DIBUJADO [FEM_VSC] SINCRONÍA DE IMAGEN [FEM_FRM] -LIMITADOR DE CUADROS +LIMITADOR DE FOTOGRAMAS [FED_RES] -RESOLUCIÓN DE PANTALLA +RESOLUCIÓN [FED_WIS] PANTALLA PANORÁMICA -[FEDS_TB] -ATRÁS - [FEA_MUS] -VOLUMEN DE LA MÚSICA +VOLUMEN DE MÚSICA [FEA_SFX] VOLUMEN DE EFECTOS @@ -7889,7 +8980,7 @@ ESPAÑOL HARDWARE DE SONIDO [FEA_SPK] -AJUSTE DE ALTAVOCES +CONFIGURACIÓN DE ALTAVOCES [FEA_2SP] 2 ALTAVOCES @@ -7898,19 +8989,28 @@ AJUSTE DE ALTAVOCES MÁS DE 2 ALTAVOCES [FEA_EAR] -MICRÓFONOS +AURICULARES [FEA_NAH] NO HAY HARDWARE DE SONIDO [FET_SNG] -INICIAR NUEVO JUEGO +INICIAR NUEVA PARTIDA + +[FEN_STA] +INICIAR PARTIDA + +[GMLOAD] +CARGAR PARTIDA [GMSAVE] -GUARDAR JUEGO +GUARDAR PARTIDA [FES_DGA] -BORRAR JUEGO +BORRAR PARTIDA + +[FEM_NON] +NADA [FEC_IVV] INVERTIR VERTICALIDAD RATÓN @@ -7919,40 +9019,40 @@ INVERTIR VERTICALIDAD RATÓN SENSIBILIDAD DEL RATÓN [FET_CCN] -COTROLES: CLÁSICOS +CONTROL: CLÁSICO [FET_SCN] -CONTROLES: ESTÁNDAR +CONTROL: ESTÁNDAR [FES_SET] -Usar skin +USAR APARIENCIA [GHOST] -Ghost +Fantasma [WIN_RSZ] -Error al seleccionar nueva pantalla de resolución +Error al seleccionar la nueva resolución de pantalla + +[FET_APL] +APLICAR [FET_APP] -BIR, VOLVER A APLICAR LOS AJUSTES +BIR, INTRO: APLICAR AJUSTES [FET_HRD] -AJUSTES POR DEFECTO RESTAURADOS +AJUSTES PREDETERMINADOS RESTAURADOS [FET_MST] CONDUCCIÓN CONTROLADA POR EL RATÓN -[FEC_STR] -NUM. INICIO - [FET_MIG] -IZQUIERDA, DERECHA, RUEDA DEL RATÓN PARA AJUSTAR +IZQUIERDA, DERECHA, RUEDA DEL RATÓN: AJUSTAR [FET_CIG] -RETROCESO PARA QUITAR - BIR, VOLVER A CAMBIAR +RETROCESO: QUITAR - BIR, INTRO: CAMBIAR [FET_RIG] -SELECCIONAR NUEVO CONTROL PARA ESTA ACCIÓN O ESC PARA CANCELAR +SELECCIONA UN NUEVO CONTROL O PULSA ESC PARA CANCELAR [FET_EIG] NO SE PUEDE DEFINIR UN CONTROL PARA ESTA ACCIÓN @@ -7961,34 +9061,37 @@ NO SE PUEDE DEFINIR UN CONTROL PARA ESTA ACCIÓN Por favor, introduce el disco 2 de Grand Theft Auto III en la unidad o pulsa ESC para cancelar [CVT_ERR] -Te has quedado sin espacio en el disco duro. Por favor, antes de seguir consigue algo de espacio en tu disco duro. Pulsa ESC para cancelar. +Te has quedado sin espacio en el disco duro. Por favor, libera espacio en tu disco duro antes de continuar. Pulsa ESC para cancelar. [FED_SUB] SUBTÍTULOS +[FED_SHD] +SOMBRAS DINÁMICAS + +[FED_VET] +EFECTOS VISUALES + +[FED_VT0] +BAJO + +[FED_VT1] +MEDIO + +[FED_VT2] +ALTO + +[FED_VT3] +MÁXIMO + [FET_DSN] -Aspecto por defecto del jugador.bmp - -[JM3] -'VAN HEIST' - -[EBAL] -'DÁME LIBERTAD' - -[LM4] -'EXPLOSIVA ACCIÓN MACARRA' +Apariencia predeterminada del jugador.bmp [REPLAY] -VOLVER A JUGAR - -[FEC_SFT] -MAYÚS - -[CRED254] -JEFE DE ESTUDIO +REPETICIÓN [CVT_CRT] -No se pueden convertir texturas con tu tarjeta de vídeo. Debes conectarte con una cuenta de Administrador para hacerlo. Pulsa ESC para salir. +No se pueden convertir las texturas para tu tarjeta de vídeo. Necesitas privilegios de administrador. Pulsa ESC para salir. [FEM_ON] SÍ @@ -8003,28 +9106,237 @@ SÍ NO [FES_WAR] -Guardando, por favor espera... +Guardando, espera... [FED_DLW] -Borrando, por favor espera... +Borrando, espera... [FED_LDW] -Cargando, por favor espera... +Cargando, espera... [FEC_SLC] -Ranura en mal estado +Ranura dañada [FED_LFL] -Error al cargar el juego. El juego se reiniciará. +Error al cargar la partida. El juego se reiniciará. [FET_RSO] -RESTAURADO AJUSTE ORIGINAL +SE HAN REINICIADO LOS AJUSTES [FET_RSC] -HARDAWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL +HARDWARE NO DISPONIBLE. RESTAURADO AJUSTE ORIGINAL -[CRED270] -MIKE HONG +{ ========================================================= } +{ ================= CHEAT-RELATED STRINGS ================= } +{ ========================================================= } + +[CARSOFF] +Coches activados. + +[CARS_ON] +Coches desactivados. + +[TEXTXYZ] +Escribiendo coordenadas al archivo... + +[CHEATON] +Trucos ACTIVADOS + +[CHEATOF] +Trucos DESACTIVADOS + +[CHEAT1] +Trucos activados + +[CHEAT2] +Arma trucada + +[CHEAT3] +Salud trucada + +[CHEAT4] +Armadura trucada + +[CHEAT5] +Busca y captura trucado + +[CHEAT6] +Dinero trucado + +[CHEAT7] +Clima trucado + +{ ========================================================================================= } +{ ================= MIXED BAG ================= } +{ ========================================================================================= } + +[OUT_VEH] +~g~¡Sal del vehículo! + +[WANTED1] +~g~¡Despista a la poli! + +[NODOORS] +~g~¡No son sardinas! Consigue un vehículo con suficientes asientos. + +[TRASH] +~g~¡Has dejado tu vehículo hecho unos zorros! ¡Haz que lo reparen! + +[WRECKED] +~r~¡El vehículo está destrozado! + +[HORN] +~g~Toca el claxon. + +[NOMONEY] +~g~¡Necesitas más pasta! + +[OUTTIME] +~r~¡Demasiado lento, tío, demasiado lento! + +[SPOTTED] +~r~¡Te siguen la pista! + +[REWARD] +RECOMPENSA: $~1~ + +[GAMEOVR] +FIN DE LA PARTIDA + +[Z] +Valor del eje Z: ~1~ + +[M_FAIL] +¡MISIÓN FRACASADA! + +[M_PASS] +¡MISIÓN SUPERADA! $~1~ + +[O_PASS] +¡TRABAJO ESPORÁDICO SUPERADO! + +[O_FAIL] +¡TRABAJO ESPORÁDICO FRACASADO! + +[DEAD] +¡LIQUIDADO! + +[BUSTED] +¡TRINCADO! + +[KABOOM] +¡BUUUM! + +[SPLAT] +¡PLOF! + +[PANCAK] +¡APLASTADO! + +[SOAKED] +¡AGUADO! + +[NUMBER] +~1~ + +[SCORE] +~1~$ + +[LOADCAR] +CARGANDO VEHÍCULO... (PULSA EL BOTÓN L1 PARA CANCELAR) + +[IMPORT1] +Sal y espera a tu vehículo. + +[LUIGIS] +Club de Luigi + +[DODO_FT] +¡Volaste durante ~1~ segundos! + +[WEATHER] +FORZAR EL CLIMA + +[WEATHE2] +CLIMA NORMAL + +[8001] +¡Has fallado miserablemente! + +[1000] +HAS MUERTO + +[1001] +HAS MUERTO + +[1002] +HAS MUERTO + +[1003] +HAS MUERTO + +[1004] +HAS MUERTO + +[1005] +TRINCADO + +[1006] +TRINCADO + +[1007] +TRINCADO + +[1008] +TRINCADO + +[1009] +TRINCADO + +[PU_MONY] +No tienes suficiente dinero. + +[CO_ALL] +Te has hecho con todos. Toma un detallito... + +[PAUSED] +PARTIDA EN PAUSA + +[HEALTH1] +¡Largo! Estás completamente sano. + +[HEALTH2] +La sanidad cuesta dinero. + +[HEALTH3] +Te pondré como nuevo. + +[HEALTH4] +Te va a costar 250 $. + +[BET_JB] +TRAICIONADO POR SU AMANTE CATALINA Y DADO POR MUERTO. TRAS SER CONDENADO Y SENTENCIADO, INICIA SU VIAJE A LA PRISIÓN DE LIBERTY CITY. PERO SÓLO TIENE UN PENSAMIENTO... ¡VENGANZA! + +[USJI1] +SOBRAS + +[USJI2] +SOBRAS + +[USJI3] +SOBRAS + +[CINCAM] +Vista cinematográfica + +[LITTLE] +LITTLE T + +[NICK] +NICK LOVE + +[CO_ONE] +Paquete oculto ~1~ de ~1~ { re3 updates } { new languages } From 7272802aa1776cee13287243b4e1922c6bae4b6d Mon Sep 17 00:00:00 2001 From: IlDucci Date: Wed, 2 Dec 2020 23:37:05 +0100 Subject: [PATCH 128/129] Restored the original ordering of Spanish.txt. --- gamefiles/TEXT/spanish.gxt | Bin 237250 -> 236540 bytes utils/gxt/spanish.txt | 9153 +++++++++++++++--------------------- 2 files changed, 3909 insertions(+), 5244 deletions(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 9234eec9f86401185e88bd7f5008a474b50b5e8b..2adca1651c0769d0a36682d475008765c7395e80 100644 GIT binary patch delta 38514 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 g;oVf15BcWNpE_=B{QF$JpEX^<(WRPL9 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