From 5654347c5d511c53146fe4ce1710938b311d986e Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:50:57 +0300 Subject: 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); -- cgit v1.2.3 From b95accb8ff6a594d1a920b94823b38be3515f149 Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:52:13 +0300 Subject: 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 -- cgit v1.2.3 From 0205960a2fe13174b5dc17abf080b6821a3c883a Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:53:15 +0300 Subject: 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 ) -- cgit v1.2.3 From 7d31b7005a24dce07fe02db0bac6717951751898 Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:57:41 +0300 Subject: 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" -- cgit v1.2.3 From 7d03a6fe291ff72edcf517dda1de8aee40941019 Mon Sep 17 00:00:00 2001 From: Greg V Date: Mon, 28 Sep 2020 04:59:14 +0300 Subject: 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 -- cgit v1.2.3 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: 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; -- cgit v1.2.3 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: 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; -- cgit v1.2.3 From 922d06ab1fb1c2222b2738bd12cbc7549dc52ded Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 28 Oct 2020 05:11:34 +0300 Subject: rewrite CFO + postfx/pipeline options --- src/core/Frontend.cpp | 300 ++++++--------- 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 | 442 +++------------------- src/extras/frontendoption.cpp | 238 +++--------- src/extras/frontendoption.h | 121 ++----- 10 files changed, 1173 insertions(+), 885 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(); - - if (m_nCurrOption == option.screenOptionOrder && (option.type == FEOPTION_DYNAMIC || option.type == FEOPTION_BUILTIN_ACTION)) - if(option.buttonPressFunc) - option.buttonPressFunc(FEOPTION_ACTION_FOCUSLOSS); - - if (option.type == FEOPTION_SELECT && option.onlyApplyOnEnter && option.lastSavedValue != option.displayedValue) - option.displayedValue = *option.value = option.lastSavedValue; - } - } + CMenuScreenCustom::CMenuEntry &option = aScreens[m_nCurrScreen].m_aEntries[m_nCurrOption]; - 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 (option.m_Action == MENUACTION_CFO_DYNAMIC) + if(option.m_CFODynamic->buttonPressFunc) + option.m_CFODynamic->buttonPressFunc(FEOPTION_ACTION_FOCUSLOSS); + + 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 (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; - - if (option.displayedValue >= option.numRightTexts || option.displayedValue < 0) - option.displayedValue = 0; - - rightText = (wchar*)option.rightTexts[option.displayedValue]; - - } else if (option.type == FEOPTION_DYNAMIC) { - if (option.drawFunc) { - rightText = option.drawFunc(&isOptionDisabled, m_nCurrOption == i); - } + 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.m_CFOSelect->displayedValue >= option.m_CFOSelect->numRightTexts || option.m_CFOSelect->displayedValue < 0) + option.m_CFOSelect->displayedValue = 0; + + rightText = TheText.Get(option.m_CFOSelect->rightTexts[option.m_CFOSelect->displayedValue]); + + } 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) +void +CustomFrontendOptionsPopulate(void) { - TheCamera.bFreeCam = !!displayedValue; - FrontEndMenuManager.SaveSettings(); + // Moved to an array in MenuScreensCustom.cpp, but APIs are still available. see frontendoption.h } -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 LOAD_INI_SETTINGS +#include "ini_parser.hpp" -#ifdef PS2_ALPHA_TEST -void PS2AlphaTestChange(int8 displayedValue) +linb::ini cfg; +int CheckAndReadIniInt(const char *cat, const char *key, int original) { - 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); + const char *value = (cfg.get(cat, key, "").c_str()); + if (value && value[0] != '\0') + return atoi(value); - return selectedJoystickUnicode; + return original; } -#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) +float CheckAndReadIniFloat(const char *cat, const char *key, float original) { - 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") }; + const char *value = (cfg.get(cat, key, "").c_str()); + if (value && value[0] != '\0') + return atof(value); -#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 + return original; } -#endif -#ifdef LOAD_INI_SETTINGS -#include "ini_parser.hpp" 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,19 +1,13 @@ #include "common.h" #ifdef CUSTOM_FRONTEND_OPTIONS -#include "frontendoption.h" +#include "Frontend.h" #include "Text.h" -int numCustomFrontendOptions = 0; -FrontendOption *customFrontendOptions; +int lastOgScreen = MENUPAGES; // means no new pages +int numCustomFrontendOptions = 0; int numCustomFrontendScreens = 0; -FrontendScreen* customFrontendScreens; - -int numFrontendOptionReplacements = 0; -CMenuScreen::CMenuEntry* frontendOptionReplacements; - -int lastOgScreen = MENUPAGES; // means no new pages int optionCursor = -2; int currentMenu; @@ -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; -} - -void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, 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; + option.m_Action = action; + option.m_SaveSlot = saveSlot; + option.m_TargetMenu = targetMenu; } -void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, 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(); - 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; + 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 FrontendOptionAddBackButton(const wchar* text, bool fadeIn) +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_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); - - 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; + uint8 screenOrder = RegisterNewScreen(gxtKey, prevPage, 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 -- cgit v1.2.3 From e95516032f4e44ea35b7358f60c464c0faa1df91 Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 29 Oct 2020 19:01:09 +0100 Subject: 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() { -- cgit v1.2.3 From 57b01ac4769b0ac83150f2284f5bad87f2f166a3 Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 29 Oct 2020 19:23:59 +0100 Subject: 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 -- cgit v1.2.3 From d34d591ed36557d88d2d0485965e7f7337ed25de Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 29 Oct 2020 19:53:23 +0100 Subject: 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); -- cgit v1.2.3 From 7784ba052e3c5ea4aced693695e38caab825e053 Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 30 Oct 2020 17:24:20 +0300 Subject: 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 -- cgit v1.2.3 From ded7c8960201b3df2a5682a5347fefa9af851f49 Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 30 Oct 2020 17:36:13 +0300 Subject: 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) { -- cgit v1.2.3 From 30c0f26f171b96443b9f897c816450a281cf216c Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 31 Oct 2020 22:09:43 +0100 Subject: 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); -- cgit v1.2.3 From f73450f5418714ffdaf219ab43e159187e10adac Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 1 Nov 2020 00:49:42 +0100 Subject: 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" } -- cgit v1.2.3 From e9735f928f2c7c0675ef8ac2881da380f390576e Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 1 Nov 2020 01:09:46 +0100 Subject: 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 -- cgit v1.2.3 From db7c3bda7d13a01a3bee48b6a195a772d06e3c82 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 1 Nov 2020 01:17:14 +0100 Subject: 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" } -- cgit v1.2.3 From 3c4f166a82d5760849e0f8a02c28a46d734a6c6d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 09:20:37 +0200 Subject: 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); -- cgit v1.2.3 From 5711251b0fcf3333c2f96b48dd784fe4c6e1ba25 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 09:46:02 +0200 Subject: 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); -- cgit v1.2.3 From f21cfef8fb92a0923c6ddfa26124cf6da1fa883c Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sun, 1 Nov 2020 12:33:16 +0300 Subject: 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 -- cgit v1.2.3 From 1f5a6dab67d37af7e3686e29fc81d0f8e5bb5597 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 12:30:23 +0200 Subject: 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); -- cgit v1.2.3 From 37943a87cbafcc0a0ad0a4a5b05a20e48ddf72de Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 13:42:02 +0200 Subject: 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; -- cgit v1.2.3 From 30d1cbfecd6e9fb477a0b5672d830b871be9722d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 1 Nov 2020 13:46:12 +0200 Subject: 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 -- cgit v1.2.3 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: 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; -- cgit v1.2.3 From e587974759bd98a1f56dd752537b8ffe184b747b Mon Sep 17 00:00:00 2001 From: shfil Date: Mon, 2 Nov 2020 13:31:25 +0100 Subject: 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 -- cgit v1.2.3 From 1df6dda546aa658d456846900880ac380d0ab677 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Sat, 31 Oct 2020 23:14:28 +0100 Subject: 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() -- cgit v1.2.3 From d4c26396c7c447de00470a0ba2153ee43bc00532 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 2 Nov 2020 18:17:37 +0200 Subject: 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" -- cgit v1.2.3 From f08b9cf0338c448d182c7561cacb4a755153834d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 3 Nov 2020 15:00:48 +0200 Subject: 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. -- cgit v1.2.3 From ebddb7956c44d6d5862b6bddfc0be54d55f4a813 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 3 Nov 2020 14:37:00 +0100 Subject: 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 -- cgit v1.2.3 From b3da518ae02eb9c9a9cc3e0343438f07d6d28251 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 3 Nov 2020 16:59:37 +0100 Subject: 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; -- cgit v1.2.3 From 8224a6a38156ccba7c69b66fab3388463fc727b1 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 5 Nov 2020 17:05:16 +0200 Subject: 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 00000000..27837c2f Binary files /dev/null and b/gamefiles/models/x360btns.txd differ diff --git a/src/core/ControllerConfig.cpp b/src/core/ControllerConfig.cpp index dcc294c8..504b832c 100644 --- a/src/core/ControllerConfig.cpp +++ b/src/core/ControllerConfig.cpp @@ -2316,199 +2316,207 @@ 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 +#define VFB(b) b, +#else +#define VFB(b) #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 + +#define CONTROLLER_BUTTONS(T, O, X, Q, L1, L2, L3, R1, R2, R3, SELECT) \ + {{ \ + O, /* PED_FIREWEAPON */ \ + R2, /* PED_CYCLE_WEAPON_RIGHT */ \ + L2, /* PED_CYCLE_WEAPON_LEFT */ \ + nil, /* GO_FORWARD */ \ + nil, /* GO_BACK */ \ + nil, /* GO_LEFT */ \ + nil, /* GO_RIGHT */ \ + Q, /* PED_SNIPER_ZOOM_IN */ \ + X, /* PED_SNIPER_ZOOM_OUT */ \ + T, /* VEHICLE_ENTER_EXIT */ \ + SELECT, /* CAMERA_CHANGE_VIEW_ALL_SITUATIONS */ \ + Q, /* PED_JUMPING */ \ + X, /* PED_SPRINT */ \ + R3, /* PED_LOOKBEHIND */ \ + VFB(O) /* VEHICLE_FIREWEAPON */ \ + X, /* VEHICLE_ACCELERATE */ \ + Q, /* 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 */ \ + }, \ + { \ + O, /* PED_FIREWEAPON */ \ + R2, /* PED_CYCLE_WEAPON_RIGHT */ \ + L2, /* PED_CYCLE_WEAPON_LEFT */ \ + nil, /* GO_FORWARD */ \ + nil, /* GO_BACK */ \ + nil, /* GO_LEFT */ \ + nil, /* GO_RIGHT */ \ + Q, /* PED_SNIPER_ZOOM_IN */ \ + X, /* PED_SNIPER_ZOOM_OUT */ \ + T, /* VEHICLE_ENTER_EXIT */ \ + SELECT, /* CAMERA_CHANGE_VIEW_ALL_SITUATIONS */ \ + Q, /* PED_JUMPING */ \ + X, /* PED_SPRINT */ \ + R3, /* PED_LOOKBEHIND */ \ + VFB(O) /* VEHICLE_FIREWEAPON */ \ + X, /* VEHICLE_ACCELERATE */ \ + Q, /* VEHICLE_BRAKE */ \ + SELECT, /* 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 */ \ + }, \ + { \ + X, /* PED_FIREWEAPON */ \ + R2, /* PED_CYCLE_WEAPON_RIGHT */ \ + L2, /* PED_CYCLE_WEAPON_LEFT */ \ + nil, /* GO_FORWARD */ \ + nil, /* GO_BACK */ \ + nil, /* GO_LEFT */ \ + nil, /* GO_RIGHT */ \ + T, /* PED_SNIPER_ZOOM_IN */ \ + Q, /* PED_SNIPER_ZOOM_OUT */ \ + L1, /* VEHICLE_ENTER_EXIT */ \ + SELECT, /* CAMERA_CHANGE_VIEW_ALL_SITUATIONS */ \ + Q, /* PED_JUMPING */ \ + O, /* PED_SPRINT */ \ + R3, /* PED_LOOKBEHIND */ \ + VFB(O) /* VEHICLE_FIREWEAPON */ \ + X, /* VEHICLE_ACCELERATE */ \ + Q, /* VEHICLE_BRAKE */ \ + L3, /* VEHICLE_CHANGE_RADIO_STATION */ \ + R1, /* VEHICLE_HORN */ \ + R3, /* TOGGLE_SUBMISSIONS */ \ + T, /* 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 */ \ + T, /* 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 */ \ + Q, /* PED_SNIPER_ZOOM_IN */ \ + X, /* PED_SNIPER_ZOOM_OUT */ \ + T, /* VEHICLE_ENTER_EXIT */ \ + SELECT, /* CAMERA_CHANGE_VIEW_ALL_SITUATIONS */ \ + Q, /* PED_JUMPING */ \ + X, /* PED_SPRINT */ \ + R3, /* PED_LOOKBEHIND */ \ + VFB(R1) /* VEHICLE_FIREWEAPON */ \ + nil, /* VEHICLE_ACCELERATE */ \ + nil, /* VEHICLE_BRAKE */ \ + O, /* VEHICLE_CHANGE_RADIO_STATION */ \ + L3, /* VEHICLE_HORN */ \ + Q, /* 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 */ \ + O, /* 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 */ \ + }} + +#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 - 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 "^" +#elif defined(BUTTON_ICONS) +#define PS2_TRIANGLE "~T~" +#define PS2_CIRCLE "~O~" +#define PS2_CROSS "~X~" +#define PS2_SQUARE "~Q~" #else #define PS2_TRIANGLE "TRIANGLE" #define PS2_CIRCLE "CIRCLE" @@ -2516,199 +2524,22 @@ const char *XboxButtons[][MAX_CONTROLLERACTIONS] = #define PS2_SQUARE "SQUARE" #endif +#ifdef BUTTON_ICONS 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 + 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 - 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 +#undef CONTROLLER_BUTTONS +#undef VFB + void CControllerConfigManager::GetWideStringOfCommandKeys(uint16 action, wchar *text, uint16 leight) { #ifdef DETECT_PAD_INPUT_SWITCH diff --git a/src/core/config.h b/src/core/config.h index 9af75405..bdc5cd54 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -258,6 +258,7 @@ enum Config { #define ALT_DODO_CHEAT #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 // Hud, frontend and radar #define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better. diff --git a/src/render/Font.cpp b/src/render/Font.cpp index d0b554dd..6aceaf4b 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -224,6 +224,11 @@ wchar foreign_table[128] = { 0, 174, 165, 166, 167, 0, 168, 0, 0, 169, 170, 171, 172, 0, 0, 0, }; +#ifdef BUTTON_ICONS +CSprite2d CFont::ButtonSprite[MAX_BUTTON_ICONS]; +int CFont::PS2Symbol = BUTTON_NONE; +#endif // BUTTON_ICONS + void CFont::Initialise(void) { @@ -281,6 +286,31 @@ CFont::Initialise(void) SetAlphaFade(255.0f); SetDropShadowPosition(0); CTxdStore::PopCurrentTxd(); + +#ifdef BUTTON_ICONS + slot = CTxdStore::AddTxdSlot("buttons"); + CTxdStore::LoadTxd(slot, "MODELS/X360BTNS.TXD"); + CTxdStore::AddRef(slot); + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(slot); +#if 0 // unused + 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(); +#endif // BUTTON_ICONS } #ifdef MORE_LANGUAGES @@ -329,6 +359,11 @@ CFont::ReloadFonts(uint8 set) void CFont::Shutdown(void) { +#ifdef BUTTON_ICONS + for (int i = 0; i < MAX_BUTTON_ICONS; i++) + ButtonSprite[i].Delete(); + CTxdStore::RemoveTxdSlot(CTxdStore::FindTxdSlot("buttons")); +#endif Sprite[0].Delete(); Sprite[1].Delete(); Sprite[2].Delete(); @@ -354,7 +389,33 @@ CFont::InitPerFrame(void) #endif SetDropShadowPosition(0); NewLine = 0; +#ifdef BUTTON_ICONS + PS2Symbol = BUTTON_NONE; +#endif +} + +#ifdef BUTTON_ICONS +void +CFont::DrawButton(float x, float y) +{ + if (x <= 0.0f || x > 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); -- cgit v1.2.3 From 8614f6862050d5e13c7a351cb4fafb4b983a8390 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 5 Nov 2020 16:42:42 +0100 Subject: 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; -- cgit v1.2.3 From bd78b5ff4e4d909c7d290b2a1bc823397ca3f930 Mon Sep 17 00:00:00 2001 From: withmorten Date: Thu, 5 Nov 2020 19:57:13 +0100 Subject: 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. -- cgit v1.2.3 From f442793d201bd905c38c4861c564ba2896b8cd88 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Tue, 3 Nov 2020 18:00:10 +0100 Subject: 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 -- cgit v1.2.3 From 3b81eaa2d74b6f820f2651b6e468588b514ea5c9 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 7 Nov 2020 12:59:53 +0200 Subject: 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, -- cgit v1.2.3 From 7f4498e0f09a51bce527760c8f3ec1b94dde1e77 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 7 Nov 2020 20:54:38 +0200 Subject: 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; -- cgit v1.2.3 From 163c12608fa972e6bed225ac6cb56d0a68279f06 Mon Sep 17 00:00:00 2001 From: erorcun Date: Sat, 7 Nov 2020 18:04:01 +0300 Subject: 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 CUSTOM_FRONTEND_OPTIONS - #ifdef MENU_MAP - MENUPAGE_MAP, + MENUPAGE_MAP = 58, #endif +#ifdef CUSTOM_FRONTEND_OPTIONS + #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) -- cgit v1.2.3 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: 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; -- cgit v1.2.3 From f8367ebdef6d15d1b1892a3418ea8a1ed4df46b2 Mon Sep 17 00:00:00 2001 From: erorcun Date: Sun, 8 Nov 2020 21:11:55 +0300 Subject: 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(); -- cgit v1.2.3 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: 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; -- cgit v1.2.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: 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; -- cgit v1.2.3 From 59f9c009efd3e149b83621c61716fa8da1ee1309 Mon Sep 17 00:00:00 2001 From: erorcun Date: Tue, 10 Nov 2020 01:41:21 +0300 Subject: 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)) { -- cgit v1.2.3 From 460f3cea447296cb5757c04108b9ac6becd6c968 Mon Sep 17 00:00:00 2001 From: erorcun Date: Tue, 10 Nov 2020 02:06:59 +0300 Subject: 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 (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 (hasNativeList(m_nCurrScreen)) { + // Not split to seperate function in III as in VC, but we need it for scrollable pages :) + ProcessList(goBack, optionSelected); - 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 -- cgit v1.2.3 From 546ed0ff07cad63cb07612d8aff8d63213f71ecd Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 11 Nov 2020 09:42:30 +0100 Subject: 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 -- cgit v1.2.3 From 67e57d136862ea7823ca3c7b256214b92d738af6 Mon Sep 17 00:00:00 2001 From: erorcun Date: Wed, 11 Nov 2020 13:08:22 +0300 Subject: 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); -- cgit v1.2.3 From feeab0b74afa63376e51b1869f6e4a17fec9a420 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Wed, 11 Nov 2020 20:57:44 +0200 Subject: 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); -- cgit v1.2.3 From 8374a346e52b99552228e80726305376c1853952 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Fri, 13 Nov 2020 18:28:15 +0200 Subject: 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 -- cgit v1.2.3 From a6f5f4634c63a515196a0f650682953356cb8e18 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 14 Nov 2020 22:13:32 +0200 Subject: 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/collision/Collision.cpp | 2736 +++++++++++++++++++++++++++++++ src/collision/Collision.h | 70 + src/collision/CompressedVector.h | 36 + src/collision/TempColModels.cpp | 296 ++++ src/collision/TempColModels.h | 23 + src/collision/VuCollision.cpp | 282 ++++ src/collision/VuCollision.h | 32 + src/collision/vu0Collision.dsm | 21 + src/collision/vu0Collision_1.s | 610 +++++++ src/collision/vu0Collision_2.s | 191 +++ src/core/Collision.cpp | 3290 -------------------------------------- src/core/Collision.h | 254 --- src/core/TempColModels.cpp | 297 ---- src/core/TempColModels.h | 23 - src/core/vu0Collision.dsm | 21 - src/core/vu0Collision_1.s | 610 ------- src/core/vu0Collision_2.s | 191 --- src/entities/Physical.cpp | 24 +- 32 files changed, 4776 insertions(+), 4698 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 create mode 100644 src/collision/Collision.cpp create mode 100644 src/collision/Collision.h create mode 100644 src/collision/CompressedVector.h create mode 100644 src/collision/TempColModels.cpp create mode 100644 src/collision/TempColModels.h create mode 100644 src/collision/VuCollision.cpp create mode 100644 src/collision/VuCollision.h create mode 100644 src/collision/vu0Collision.dsm create mode 100644 src/collision/vu0Collision_1.s create mode 100644 src/collision/vu0Collision_2.s delete mode 100644 src/core/Collision.cpp delete mode 100644 src/core/Collision.h delete mode 100644 src/core/TempColModels.cpp delete mode 100644 src/core/TempColModels.h delete mode 100644 src/core/vu0Collision.dsm delete mode 100644 src/core/vu0Collision_1.s delete mode 100644 src/core/vu0Collision_2.s 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/collision/Collision.cpp b/src/collision/Collision.cpp new file mode 100644 index 00000000..41997e32 --- /dev/null +++ b/src/collision/Collision.cpp @@ -0,0 +1,2736 @@ +#include "common.h" + +#include "VuVector.h" +#include "main.h" +#include "Lists.h" +#include "Game.h" +#include "Zones.h" +#include "General.h" +#include "ZoneCull.h" +#include "World.h" +#include "Entity.h" +#include "Train.h" +#include "Streaming.h" +#include "Pad.h" +#include "DMAudio.h" +#include "Population.h" +#include "FileLoader.h" +#include "Replay.h" +#include "CutsceneMgr.h" +#include "RenderBuffer.h" +#include "SurfaceTable.h" +#include "Lines.h" +#include "Collision.h" +#include "Frontend.h" + +#ifdef VU_COLLISION +#include "VuCollision.h" + +inline int +GetVUresult(void) +{ +#ifdef GTA_PS2 + int ret; + __asm__ volatile ( + "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish + : "=r" (ret) + ); + return ret; +#else + return vi01; +#endif +} + +inline int +GetVUresult(CVuVector &point, CVuVector &normal, float &dist) +{ +#ifdef GTA_PS2 + int ret; + __asm__ volatile ( + "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish + "sqc2 vf01,(%1)\n" + "sqc2 vf02,(%2)\n" + "qmfc2 $12,vf03\n" + "sw $12,(%3)\n" + : "=r" (ret) + : "r" (&point), "r" (&normal), "r" (&dist) + : "$12" + ); + return ret; +#else + point = vf01; + normal = vf02; + dist = vf03.x; + return vi01; +#endif +} + +#endif + +eLevelName CCollision::ms_collisionInMemory; +CLinkList CCollision::ms_colModelCache; + +void +CCollision::Init(void) +{ + ms_colModelCache.Init(NUMCOLCACHELINKS); + ms_collisionInMemory = LEVEL_GENERIC; +} + +void +CCollision::Shutdown(void) +{ + ms_colModelCache.Shutdown(); +} + +void +CCollision::Update(void) +{ + CVector playerCoors; + playerCoors = FindPlayerCoors(); + eLevelName level = CTheZones::m_CurrLevel; + bool forceLevelChange = false; + + if(CTimer::GetTimeInMilliseconds() < 2000 || CCutsceneMgr::IsCutsceneProcessing()) + return; + + // hardcode a level if there are no zones + if(level == LEVEL_GENERIC){ + if(CGame::currLevel == LEVEL_INDUSTRIAL && + playerCoors.x < 400.0f){ + level = LEVEL_COMMERCIAL; + forceLevelChange = true; + }else if(CGame::currLevel == LEVEL_SUBURBAN && + playerCoors.x > -450.0f && playerCoors.y < -1400.0f){ + level = LEVEL_COMMERCIAL; + forceLevelChange = true; + }else{ + if(playerCoors.x > 800.0f){ + level = LEVEL_INDUSTRIAL; + forceLevelChange = true; + }else if(playerCoors.x < -800.0f){ + level = LEVEL_SUBURBAN; + forceLevelChange = true; + } + } + } + if(level != LEVEL_GENERIC && level != CGame::currLevel) + CGame::currLevel = level; + if(ms_collisionInMemory != CGame::currLevel) + LoadCollisionWhenINeedIt(forceLevelChange); + CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); +} + +eLevelName +GetCollisionInSectorList(CPtrList &list) +{ + CPtrNode *node; + CEntity *e; + int level; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level; + if(level != LEVEL_GENERIC) + return (eLevelName)level; + } + return LEVEL_GENERIC; +} + +// Get a level this sector is in based on collision models +eLevelName +GetCollisionInSector(CSector §) +{ + int level; + + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]); + if(level == LEVEL_GENERIC) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]); + return (eLevelName)level; +} + +void +CCollision::LoadCollisionWhenINeedIt(bool forceChange) +{ + eLevelName level, l; + bool multipleLevels; + CVector playerCoors; + CVehicle *veh; + CEntryInfoNode *ei; + int sx, sy; + int xmin, xmax, ymin, ymax; + int x, y; + + level = LEVEL_GENERIC; + + playerCoors = FindPlayerCoors(); + sx = CWorld::GetSectorIndexX(playerCoors.x); + sy = CWorld::GetSectorIndexY(playerCoors.y); + multipleLevels = false; + + veh = FindPlayerVehicle(); + if(veh && veh->IsTrain()){ + if(((CTrain*)veh)->m_nDoorState != TRAIN_DOOR_OPEN) + return; + }else if(playerCoors.z < -4.0f && !CCullZones::DoINeedToLoadCollision()) + return; + + // Figure out whose level's collisions we're most likely to be interested in + if(!forceChange){ + if(veh && veh->IsBoat()){ + // on water we expect to be between levels + multipleLevels = true; + }else{ + xmin = Max(sx - 1, 0); + xmax = Min(sx + 1, NUMSECTORS_X-1); + ymin = Max(sy - 1, 0); + ymax = Min(sy + 1, NUMSECTORS_Y-1); + + for(x = xmin; x <= xmax; x++) + for(y = ymin; y <= ymax; y++){ + l = GetCollisionInSector(*CWorld::GetSector(x, y)); + if(l != LEVEL_GENERIC){ + if(level == LEVEL_GENERIC) + level = l; + if(level != l) + multipleLevels = true; + } + } + } + + if(multipleLevels && veh && veh->IsBoat()) + for(ei = veh->m_entryInfoList.first; ei; ei = ei->next){ + level = GetCollisionInSector(*ei->sector); + if(level != LEVEL_GENERIC) + break; + } + } + + if (level == CGame::currLevel || forceChange) { +#ifdef FIX_BUGS + CTimer::Suspend(); +#else + CTimer::Stop(); +#endif + ISLAND_LOADING_IS(LOW) + { + DMAudio.SetEffectsFadeVol(0); + CPad::StopPadsShaking(); + LoadCollisionScreen(CGame::currLevel); + DMAudio.Service(); + } + + CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false); + + ISLAND_LOADING_ISNT(HIGH) + { + CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + } + ISLAND_LOADING_IS(LOW) + { + CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); + CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); + CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + CStreaming::RemoveUnusedModelsInLoadedList(); + CGame::TidyUpMemory(true, true); + CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); + } + + ms_collisionInMemory = CGame::currLevel; + CReplay::EmptyReplayBuffer(); + ISLAND_LOADING_IS(LOW) + { + if (CGame::currLevel != LEVEL_GENERIC) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); + CStreaming::RemoveUnusedBuildings(CGame::currLevel); + CStreaming::RequestBigBuildings(CGame::currLevel); + } +#ifdef NO_ISLAND_LOADING + else if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_MEDIUM) + CStreaming::RequestIslands(CGame::currLevel); +#endif + CStreaming::LoadAllRequestedModels(true); + + ISLAND_LOADING_IS(LOW) + { + CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); + + CGame::TidyUpMemory(true, true); + } +#ifdef FIX_BUGS + CTimer::Resume(); +#else + CTimer::Update(); +#endif + ISLAND_LOADING_IS(LOW) + DMAudio.SetEffectsFadeVol(127); + } +} + +#ifdef NO_ISLAND_LOADING +bool CCollision::bAlreadyLoaded = false; +#endif +void +CCollision::SortOutCollisionAfterLoad(void) +{ + if(ms_collisionInMemory == CGame::currLevel) + return; + ISLAND_LOADING_IS(LOW) + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + + if (CGame::currLevel != LEVEL_GENERIC) { +#ifdef NO_ISLAND_LOADING + if (CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_LOW) { + if (bAlreadyLoaded) { + ms_collisionInMemory = CGame::currLevel; + return; + } + bAlreadyLoaded = true; + CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL); + CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL); + CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN); + } else +#endif + CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); + if(!CGame::playingIntro) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + } + ms_collisionInMemory = CGame::currLevel; + CGame::TidyUpMemory(true, false); +} + +void +CCollision::LoadCollisionScreen(eLevelName level) +{ + static Const char *levelNames[4] = { + "", + "IND_ZON", + "COM_ZON", + "SUB_ZON" + }; + + // Why twice? + LoadingIslandScreen(levelNames[level]); + LoadingIslandScreen(levelNames[level]); +} + +// +// Test +// + + +bool +CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) +{ + float d = s1.radius + s2.radius; + return (s1.center - s2.center).MagnitudeSqr() < d*d; +} + +bool +CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) +{ + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + return true; +} + +bool +CCollision::TestLineBox(const CColLine &line, const CColBox &box) +{ + float t, x, y, z; + // If either line point is in the box, we have a collision + if(line.p0.x > box.min.x && line.p0.x < box.max.x && + line.p0.y > box.min.y && line.p0.y < box.max.y && + line.p0.z > box.min.z && line.p0.z < box.max.z) + return true; + if(line.p1.x > box.min.x && line.p1.x < box.max.x && + line.p1.y > box.min.y && line.p1.y < box.max.y && + line.p1.z > box.min.z && line.p1.z < box.max.z) + return true; + + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // same test with max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + return true; + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + return true; + } + } + return false; +} + +bool +CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) +{ + if(line.p0.x <= box.min.x) return false; + if(line.p0.y <= box.min.y) return false; + if(line.p0.x >= box.max.x) return false; + if(line.p0.y >= box.max.y) return false; + if(line.p0.z < line.p1.z){ + if(line.p0.z > box.max.z) return false; + if(line.p1.z < box.min.z) return false; + }else{ + if(line.p1.z > box.max.z) return false; + if(line.p0.z < box.min.z) return false; + } + return true; +} + +bool +CCollision::TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); + + if(GetVUresult()) + return true; + return false; +#else + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + const CVector &va = verts[tri.a].Get(); + const CVector &vb = verts[tri.b].Get(); + const CVector &vc = verts[tri.c].Get(); + CVector2D vec1, vec2, vec3, vect; + + // We do the test in 2D. With the plane direction we + // can figure out how to project the vectors. + // normal = (c-a) x (b-a) + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + // This is our triangle: + // 3-------2 + // \ P / + // \ / + // \ / + // 1 + // We can use the "2d cross product" to check on which side + // a vector is of another. Test is true if point is inside of all edges. + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + return true; +#endif +} + +// Test if line segment intersects with sphere. +// If the first point is inside the sphere this test does not register a collision! +// The code is reversed from the original code and rather ugly, see Process for a clear version. +// TODO: actually rewrite this mess +bool +CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) +{ + CVector v01 = line.p1 - line.p0; // vector from p0 to p1 + CVector v0c = sph.center - line.p0; // vector from p0 to center + float linesq = v01.MagnitudeSqr(); + // I leave in the strange -2 factors even though they serve no real purpose + float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line + // Square of tangent from p0 multiplied by line length so we can compare with projline. + // The length of the tangent would be this: Sqrt((c-p0)^2 - r^2). + // Negative if p0 is inside the sphere! This breaks the test! + float tansq = 4.0f * linesq * + (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); + float diffsq = projline*projline - tansq; + // if diffsq < 0 that means the line is a passant, so no intersection + if(diffsq < 0.0f) + return false; + // projline (negative in GTA for some reason) is the point on the line + // in the middle of the two intersection points (startin from p0). + // Sqrt(diffsq) somehow works out to be the distance from that + // midpoint to the intersection points. + // So subtract that and get rid of the awkward scaling: + float f = (-projline - Sqrt(diffsq)) / (2.0f*linesq); + // f should now be in range [0, 1] for [p0, p1] + return f >= 0.0f && f <= 1.0f; +} + +bool +CCollision::TestSphereTriangle(const CColSphere &sphere, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); + + if(GetVUresult()) + return true; + return false; +#else + // If sphere and plane don't intersect, no collision + float planedist = plane.CalcPoint(sphere.center); + if(Abs(planedist) > sphere.radius) + return false; + + const CVector &va = verts[tri.a].Get(); + const CVector &vb = verts[tri.b].Get(); + const CVector &vc = verts[tri.c].Get(); + + // calculate two orthogonal basis vectors for the triangle + CVector vec2 = vb - va; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector normal; + plane.GetNormal(normal); + CVector vec1 = CrossProduct(vec2, normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + switch(testcase){ + case 1: + // closest to a vertex + if(insideAB) dist = (sphere.center - vc).Magnitude(); + else if(insideAC) dist = (sphere.center - vb).Magnitude(); + else if(insideBC) dist = (sphere.center - va).Magnitude(); + else assert(0); + break; + case 2: + // closest to an edge + // looks like original game as DistToLine manually inlined + if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center); + else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center); + else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center); + else assert(0); + break; + case 3: + // center is in triangle + dist = Abs(planedist); + break; + default: + assert(0); + } + + return dist < sphere.radius; +#endif +} + +bool +CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough) +{ +#ifdef VU_COLLISION + CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CVuVector newline[2]; + TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) + return false; + + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(TestLineSphere(*(CColLine*)newline, model.spheres[i])) + return true; + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(TestLineBox(*(CColLine*)newline, model.boxes[i])) + return true; + } + + CalculateTrianglePlanes(&model); + int lastTest = -1; + VuTriangle vutri; + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lastTest = i; + break; + } +#ifdef FIX_BUGS + // no need to check first again + i++; +#endif + for(; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + if(GetVUresult()) + return true; + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lastTest = i; + + } + if(lastTest != -1 && GetVUresult()) + return true; + + return false; +#else + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(TestLineSphere(newline, model.spheres[i])) + return true; + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(TestLineBox(newline, model.boxes[i])) + return true; + } + + CalculateTrianglePlanes(&model); + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) + return true; + } + + return false; +#endif +} + + +// +// Process +// + +// For Spheres mindist is the squared distance to its center +// For Lines mindist is between [0,1] + +bool +CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq) +{ + CVector dist = s1.center - s2.center; + float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2 + float depth = s1.radius - d; // sphere overlap + if(d < 0.0f) d = 0.0f; // clamp to zero, i.e. if s1's center is inside s2 + // no collision if sphere is not close enough + if(d*d < mindistsq && d < s1.radius){ + dist.Normalise(); + point.point = s1.center - dist*d; + point.normal = dist; +#ifndef VU_COLLISION + point.surfaceA = s1.surface; + point.pieceA = s1.piece; + point.surfaceB = s2.surface; + point.pieceB = s2.piece; +#endif + point.depth = depth; + mindistsq = d*d; // collision radius + return true; + } + return false; +} + +bool +CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq) +{ + CVector p; + CVector dist; + + // GTA's code is too complicated, uses a huge 3x3x3 if statement + // we can simplify the structure a lot + + // first make sure we have a collision at all + if(sph.center.x + sph.radius < box.min.x) return false; + if(sph.center.x - sph.radius > box.max.x) return false; + if(sph.center.y + sph.radius < box.min.y) return false; + if(sph.center.y - sph.radius > box.max.y) return false; + if(sph.center.z + sph.radius < box.min.z) return false; + if(sph.center.z - sph.radius > box.max.z) return false; + + // Now find out where the sphere center lies in relation to all the sides + int xpos = sph.center.x < box.min.x ? 1 : + sph.center.x > box.max.x ? 2 : + 0; + int ypos = sph.center.y < box.min.y ? 1 : + sph.center.y > box.max.y ? 2 : + 0; + int zpos = sph.center.z < box.min.z ? 1 : + sph.center.z > box.max.z ? 2 : + 0; + + if(xpos == 0 && ypos == 0 && zpos == 0){ + // sphere is inside the box + p = (box.min + box.max)*0.5f; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + point.normal = dist * (1.0f/Sqrt(lensq)); + point.point = sph.center - point.normal; +#ifndef VU_COLLISION + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; +#endif + + // find absolute distance to the closer side in each dimension + float dx = dist.x > 0.0f ? + box.max.x - sph.center.x : + sph.center.x - box.min.x; + float dy = dist.y > 0.0f ? + box.max.y - sph.center.y : + sph.center.y - box.min.y; + float dz = dist.z > 0.0f ? + box.max.z - sph.center.z : + sph.center.z - box.min.z; + // collision depth is maximum of that: + if(dx > dy && dx > dz) + point.depth = dx; + else if(dy > dz) + point.depth = dy; + else + point.depth = dz; + return true; + } + }else{ + // sphere is outside. + // closest point on box: + p.x = xpos == 1 ? box.min.x : + xpos == 2 ? box.max.x : + sph.center.x; + p.y = ypos == 1 ? box.min.y : + ypos == 2 ? box.max.y : + sph.center.y; + p.z = zpos == 1 ? box.min.z : + zpos == 2 ? box.max.z : + sph.center.z; + + dist = sph.center - p; + float lensq = dist.MagnitudeSqr(); + if(lensq < mindistsq){ + float len = Sqrt(lensq); + point.point = p; + point.normal = dist * (1.0f/len); +#ifndef VU_COLLISION + point.surfaceA = sph.surface; + point.pieceA = sph.piece; + point.surfaceB = box.surface; + point.pieceB = box.piece; +#endif + point.depth = sph.radius - len; + mindistsq = lensq; + return true; + } + } + return false; +} + +bool +CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist) +{ + float mint, t, x, y, z; + CVector normal; + CVector p; + + mint = 1.0f; + // check if points are on opposite sides of min x plane + if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ + // parameter along line where we intersect + t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); + // y of intersection + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + // z of intersection + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.min.x, y, z); + normal = CVector(-1.0f, 0.0f, 0.0f); + } + } + } + + // max x plane + if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ + t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(box.max.x, y, z); + normal = CVector(1.0f, 0.0f, 0.0f); + } + } + } + + // min y plne + if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ + t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.min.y, z); + normal = CVector(0.0f, -1.0f, 0.0f); + } + } + } + + // max y plane + if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ + t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + z = line.p0.z + (line.p1.z - line.p0.z)*t; + if(z > box.min.z && z < box.max.z) + if(t < mint){ + mint = t; + p = CVector(x, box.max.y, z); + normal = CVector(0.0f, 1.0f, 0.0f); + } + } + } + + // min z plne + if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ + t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.min.z); + normal = CVector(0.0f, 0.0f, -1.0f); + } + } + } + + // max z plane + if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ + t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); + x = line.p0.x + (line.p1.x - line.p0.x)*t; + if(x > box.min.x && x < box.max.x){ + y = line.p0.y + (line.p1.y - line.p0.y)*t; + if(y > box.min.y && y < box.max.y) + if(t < mint){ + mint = t; + p = CVector(x, y, box.max.z); + normal = CVector(0.0f, 0.0f, 1.0f); + } + } + } + + if(mint >= mindist) + return false; + + point.point = p; + point.normal = normal; +#ifndef VU_COLLISION + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = box.surface; + point.pieceB = box.piece; +#endif + mindist = mint; + + return true; +} + +// If line.p0 lies inside sphere, no collision is registered. +bool +CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist) +{ + CVector v01 = line.p1 - line.p0; + CVector v0c = sphere.center - line.p0; + float linesq = v01.MagnitudeSqr(); + // project v0c onto v01, scaled by |v01| this is the midpoint of the two intersections + float projline = DotProduct(v01, v0c); + // tangent of p0 to sphere, scaled by linesq just like projline^2 + float tansq = (v0c.MagnitudeSqr() - sphere.radius*sphere.radius) * linesq; + // this works out to be the square of the distance between the midpoint and the intersections + float diffsq = projline*projline - tansq; + // no intersection + if(diffsq < 0.0f) + return false; + // point of first intersection, in range [0,1] between p0 and p1 + float t = (projline - Sqrt(diffsq)) / linesq; + // if not on line or beyond mindist, no intersection + if(t < 0.0f || t > 1.0f || t >= mindist) + return false; + point.point = line.p0 + v01*t; + point.normal = point.point - sphere.center; + point.normal.Normalise(); +#ifndef VU_COLLISION + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = sphere.surface; + point.pieceB = sphere.piece; +#endif + mindist = t; + return true; +} + +bool +CCollision::ProcessVerticalLineTriangle(const CColLine &line, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist, CStoredCollPoly *poly) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + bool res = ProcessLineTriangle(line, verts, tri, plane, point, mindist); + if(res && poly){ + poly->verts[0] = verts[tri.a].Get(); + poly->verts[1] = verts[tri.b].Get(); + poly->verts[2] = verts[tri.c].Get(); + poly->valid = true; + } + return res; +#else + float t; + CVector normal; + + const CVector &p0 = line.p0; + const CVector &va = verts[tri.a].Get(); + const CVector &vb = verts[tri.b].Get(); + const CVector &vc = verts[tri.c].Get(); + + // early out bound rect test + if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false; + if(p0.x > va.x && p0.x > vb.x && p0.x > vc.x) return false; + if(p0.y < va.y && p0.y < vb.y && p0.y < vc.y) return false; + if(p0.y > va.y && p0.y > vb.y && p0.y > vc.y) return false; + + plane.GetNormal(normal); + // if points are on the same side, no collision + if(plane.CalcPoint(p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + float h = (line.p1 - p0).z; + t = -plane.CalcPoint(p0) / (h * normal.z); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + CVector p(p0.x, p0.y, p0.z + h*t); + + CVector2D vec1, vec2, vec3, vect; + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + if(t >= mindist) return false; + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = tri.surface; + point.pieceB = 0; + if(poly){ + poly->verts[0] = va; + poly->verts[1] = vb; + poly->verts[2] = vc; + poly->valid = true; + } + mindist = t; + return true; +#endif +} + +bool +CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly) +{ +#ifdef VU_COLLISION + if(!poly->valid) + return false; + + CVuVector p0 = pos; + CVuVector p1 = pos; + p1.z = z; + + CVector v01 = poly->verts[1] - poly->verts[0]; + CVector v02 = poly->verts[2] - poly->verts[0]; + CVuVector plane = CrossProduct(v02, v01); + plane.Normalise(); + plane.w = DotProduct(plane, poly->verts[0]); + + LineToTriangleCollision(p0, p1, poly->verts[0], poly->verts[1], poly->verts[2], plane); + + CVuVector pnt; + float dist; + if(!GetVUresult(pnt, plane, dist)) +#ifdef FIX_BUGS + // perhaps not needed but be safe + return poly->valid = false; +#else + return false; +#endif + point.point = pnt; + return true; +#else + float t; + + if(!poly->valid) + return false; + + // maybe inlined? + CColTrianglePlane plane; + plane.Set(poly->verts[0], poly->verts[1], poly->verts[2]); + + const CVector &va = poly->verts[0]; + const CVector &vb = poly->verts[1]; + const CVector &vc = poly->verts[2]; + CVector p0 = pos; + CVector p1(pos.x, pos.y, z); + + // The rest is pretty much CCollision::ProcessLineTriangle + + // if points are on the same side, no collision + if(plane.CalcPoint(p0) * plane.CalcPoint(p1) > 0.0f) + return poly->valid = false; + + // intersection parameter on line + CVector normal; + plane.GetNormal(normal); + t = -plane.CalcPoint(p0) / DotProduct(p1 - p0, normal); + // find point of intersection + CVector p = p0 + (p1-p0)*t; + + CVector2D vec1, vec2, vec3, vect; + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return poly->valid = false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return poly->valid = false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return poly->valid = false; + point.point = p; + return poly->valid = true; +#endif +} + +bool +CCollision::ProcessLineTriangle(const CColLine &line, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindist) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); + + CVuVector pnt, normal; + float dist; + if(GetVUresult(pnt, normal, dist)){ + if(dist < mindist){ + point.point = pnt; + point.normal = normal; + mindist = dist; + return true; + } + } + return false; +#else + float t; + CVector normal; + plane.GetNormal(normal); + + // if points are on the same side, no collision + if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) + return false; + + // intersection parameter on line + t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); + // early out if we're beyond the mindist + if(t >= mindist) + return false; + // find point of intersection + CVector p = line.p0 + (line.p1-line.p0)*t; + + const CVector &va = verts[tri.a].Get(); + const CVector &vb = verts[tri.b].Get(); + const CVector &vc = verts[tri.c].Get(); + CVector2D vec1, vec2, vec3, vect; + + switch(plane.dir){ + case DIR_X_POS: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vc.y; vec2.y = vc.z; + vec3.x = vb.y; vec3.y = vb.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_X_NEG: + vec1.x = va.y; vec1.y = va.z; + vec2.x = vb.y; vec2.y = vb.z; + vec3.x = vc.y; vec3.y = vc.z; + vect.x = p.y; vect.y = p.z; + break; + case DIR_Y_POS: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vc.z; vec2.y = vc.x; + vec3.x = vb.z; vec3.y = vb.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Y_NEG: + vec1.x = va.z; vec1.y = va.x; + vec2.x = vb.z; vec2.y = vb.x; + vec3.x = vc.z; vec3.y = vc.x; + vect.x = p.z; vect.y = p.x; + break; + case DIR_Z_POS: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vc.x; vec2.y = vc.y; + vec3.x = vb.x; vec3.y = vb.y; + vect.x = p.x; vect.y = p.y; + break; + case DIR_Z_NEG: + vec1.x = va.x; vec1.y = va.y; + vec2.x = vb.x; vec2.y = vb.y; + vec3.x = vc.x; vec3.y = vc.y; + vect.x = p.x; vect.y = p.y; + break; + default: + assert(0); + } + if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; + if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; + if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; + if(t >= mindist) return false; + point.point = p; + point.normal = normal; + point.surfaceA = 0; + point.pieceA = 0; + point.surfaceB = tri.surface; + point.pieceB = 0; + mindist = t; + return true; +#endif +} + +bool +CCollision::ProcessSphereTriangle(const CColSphere &sphere, + const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, + CColPoint &point, float &mindistsq) +{ +#ifdef VU_COLLISION + // not used in favour of optimized loops + VuTriangle vutri; + verts[tri.a].Unpack(vutri.v0); + verts[tri.b].Unpack(vutri.v1); + verts[tri.c].Unpack(vutri.v2); + plane.Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); + + CVuVector pnt, normal; + float dist; + if(GetVUresult(pnt, normal, dist) && dist*dist < mindistsq){ + float depth = sphere.radius - dist; + if(depth > point.depth){ + point.point = pnt; + point.normal = normal; + point.depth = depth; + mindistsq = dist*dist; + return true; + } + } + return false; +#else + // If sphere and plane don't intersect, no collision + float planedist = plane.CalcPoint(sphere.center); + float distsq = planedist*planedist; + if(Abs(planedist) > sphere.radius || distsq > mindistsq) + return false; + + const CVector &va = verts[tri.a].Get(); + const CVector &vb = verts[tri.b].Get(); + const CVector &vc = verts[tri.c].Get(); + + // calculate two orthogonal basis vectors for the triangle + CVector normal; + plane.GetNormal(normal); + CVector vec2 = vb - va; + float len = vec2.Magnitude(); + vec2 = vec2 * (1.0f/len); + CVector vec1 = CrossProduct(vec2, normal); + + // We know A has local coordinate [0,0] and B has [0,len]. + // Now calculate coordinates on triangle for these two vectors: + CVector vac = vc - va; + CVector vas = sphere.center - va; + CVector2D b(0.0f, len); + CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); + CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); + + // The three triangle lines partition the space into 6 sectors, + // find out in which the center lies. + int insideAB = CrossProduct2D(s, b) >= 0.0f; + int insideAC = CrossProduct2D(c, s) >= 0.0f; + int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; + + int testcase = insideAB + insideAC + insideBC; + float dist = 0.0f; + CVector p; + switch(testcase){ + case 1: + // closest to a vertex + if(insideAB) p = vc; + else if(insideAC) p = vb; + else if(insideBC) p = va; + else assert(0); + dist = (sphere.center - p).Magnitude(); + break; + case 2: + // closest to an edge + // looks like original game as DistToLine manually inlined + if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p); + else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p); + else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p); + else assert(0); + break; + case 3: + // center is in triangle + dist = Abs(planedist); + p = sphere.center - normal*planedist; + break; + default: + assert(0); + } + + if(dist >= sphere.radius || dist*dist >= mindistsq) + return false; + + point.point = p; + point.normal = sphere.center - p; + point.normal.Normalise(); +#ifndef VU_COLLISION + point.surfaceA = sphere.surface; + point.pieceA = sphere.piece; + point.surfaceB = tri.surface; + point.pieceB = 0; +#endif + point.depth = sphere.radius - dist; + mindistsq = dist*dist; + return true; +#endif +} + +bool +CCollision::ProcessLineOfSight(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSeeThrough) +{ +#ifdef VU_COLLISION + CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CVuVector newline[2]; + TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); + + if(mindist < 1.0f) + newline[1] = newline[0] + (newline[1] - newline[0])*mindist; + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) + return false; + + float coldist = 1.0f; + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) + point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) + point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); + } + + CalculateTrianglePlanes(&model); + VuTriangle vutri; + CColTriangle *lasttri = nil; + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + break; + } +#ifdef FIX_BUGS + // no need to check first again + i++; +#endif + CVuVector pnt, normal; + float dist; + for(; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + if(GetVUresult(pnt, normal, dist)) + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + } + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + } + if(lasttri && GetVUresult(pnt, normal, dist)) + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + } + + + if(coldist < 1.0f){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + mindist *= coldist; + return true; + } + return false; +#else + static CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CColLine newline(matTransform * line.p0, matTransform * line.p1); + + // If we don't intersect with the bounding box, no chance on the rest + if(!TestLineBox(newline, model.boundingBox)) + return false; + + float coldist = mindist; + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + ProcessLineSphere(newline, model.spheres[i], point, coldist); + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + ProcessLineBox(newline, model.boxes[i], point, coldist); + } + + CalculateTrianglePlanes(&model); + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); + } + + if(coldist < mindist){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + mindist = coldist; + return true; + } + return false; +#endif +} + +bool +CCollision::ProcessVerticalLine(const CColLine &line, + const CMatrix &matrix, CColModel &model, + CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly) +{ +#ifdef VU_COLLISION + static CStoredCollPoly TempStoredPoly; + CMatrix matTransform; + int i; + + // transform line to model space + Invert(matrix, matTransform); + CVuVector newline[2]; + TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); + + if(mindist < 1.0f) + newline[1] = newline[0] + (newline[1] - newline[0])*mindist; + + if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) + return false; + + float coldist = 1.0f; + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) + point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) + point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); + } + + CalculateTrianglePlanes(&model); + TempStoredPoly.valid = false; + if(model.numTriangles){ + bool registeredCol; + CColTriangle *lasttri = nil; + VuTriangle vutri; + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + break; + } +#ifdef FIX_BUGS + // no need to check first again + i++; +#endif + CVuVector pnt, normal; + float dist; + for(; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + + CColTriangle *tri = &model.triangles[i]; + model.vertices[tri->a].Unpack(vutri.v0); + model.vertices[tri->b].Unpack(vutri.v1); + model.vertices[tri->c].Unpack(vutri.v2); + model.trianglePlanes[i].Unpack(vutri.plane); + + if(GetVUresult(pnt, normal, dist)){ + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol){ + TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); + TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); + TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); + TempStoredPoly.valid = true; + } + + LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); + lasttri = tri; + } + if(lasttri && GetVUresult(pnt, normal, dist)){ + if(dist < coldist){ + point.point = pnt; + point.normal = normal; + point.Set(0, 0, lasttri->surface, 0); + coldist = dist; + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol){ + TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); + TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); + TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); + TempStoredPoly.valid = true; + } + } + + if(coldist < 1.0f){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + if(TempStoredPoly.valid && poly){ + *poly = TempStoredPoly; + poly->verts[0] = matrix * CVector(poly->verts[0]); + poly->verts[1] = matrix * CVector(poly->verts[1]); + poly->verts[2] = matrix * CVector(poly->verts[2]); + } + mindist *= coldist; + return true; + } + return false; +#else + static CStoredCollPoly TempStoredPoly; + int i; + + // transform line to model space + // Why does the game seem to do this differently than above? + CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1)); + newline.p1.x = newline.p0.x; + newline.p1.y = newline.p0.y; + + if(!TestVerticalLineBox(newline, model.boundingBox)) + return false; + + float coldist = mindist; + for(i = 0; i < model.numSpheres; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; + ProcessLineSphere(newline, model.spheres[i], point, coldist); + } + + for(i = 0; i < model.numBoxes; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; + ProcessLineBox(newline, model.boxes[i], point, coldist); + } + + CalculateTrianglePlanes(&model); + TempStoredPoly.valid = false; + for(i = 0; i < model.numTriangles; i++){ + if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; + ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); + } + + if(coldist < mindist){ + point.point = matrix * point.point; + point.normal = Multiply3x3(matrix, point.normal); + if(TempStoredPoly.valid && poly){ + *poly = TempStoredPoly; + poly->verts[0] = matrix * poly->verts[0]; + poly->verts[1] = matrix * poly->verts[1]; + poly->verts[2] = matrix * poly->verts[2]; + } + mindist = coldist; + return true; + } + return false; +#endif +} + +enum { + MAXNUMSPHERES = 128, + MAXNUMBOXES = 32, + MAXNUMLINES = 16, + MAXNUMTRIS = 600 +}; + +#ifdef VU_COLLISION +#ifdef GTA_PS2 +#define SPR(off) ((uint8*)(0x70000000 + (off))) +#else +static uint8 fakeSPR[16*1024]; +#define SPR(off) ((uint8*)(fakeSPR + (off))) +#endif +#endif + +// This checks model A's spheres and lines against model B's spheres, boxes and triangles. +// Returns the number of A's spheres that collide. +// Returned ColPoints are in world space. +// NB: only vehicles can have col models with lines, exactly 4, one for each wheel +int32 +CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, + const CMatrix &matrixB, CColModel &modelB, + CColPoint *spherepoints, CColPoint *linepoints, float *linedists) +{ +#ifdef VU_COLLISION + CVuVector *aSpheresA = (CVuVector*)SPR(0x0000); + CVuVector *aSpheresB = (CVuVector*)SPR(0x0800); + CVuVector *aLinesA = (CVuVector*)SPR(0x1000); + int32 *aSphereIndicesA = (int32*)SPR(0x1200); + int32 *aSphereIndicesB = (int32*)SPR(0x1400); + int32 *aBoxIndicesB = (int32*)SPR(0x1600); + int32 *aTriangleIndicesB = (int32*)SPR(0x1680); + bool *aCollided = (bool*)SPR(0x1FE0); + CMatrix &matAB = *(CMatrix*)SPR(0x1FF0); + CMatrix &matBA = *(CMatrix*)SPR(0x2040); + int i, j, k; + + // From model A space to model B space + Invert(matrixB, matAB); + matAB *= matrixA; + + CVuVector bsphereAB; // bounding sphere of A in B space + TransformPoint(bsphereAB, matAB, *(RwV3d*)modelA.boundingSphere.center); // inlined + bsphereAB.w = modelA.boundingSphere.radius; + if(!TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boundingBox)) + return 0; + + // transform modelA's spheres and lines to B space + TransformPoints(aSpheresA, modelA.numSpheres, matAB, (RwV3d*)&modelA.spheres->center, sizeof(CColSphere)); + for(i = 0; i < modelA.numSpheres; i++) + aSpheresA[i].w = modelA.spheres[i].radius; + TransformPoints(aLinesA, modelA.numLines*2, matAB, (RwV3d*)&modelA.lines->p0, sizeof(CColLine)/2); + + // Test them against model B's bounding volumes + int numSpheresA = 0; + for(i = 0; i < modelA.numSpheres; i++) + if(TestSphereBox(*(CColSphere*)&aSpheresA[i], modelB.boundingBox)) + aSphereIndicesA[numSpheresA++] = i; + // No collision + if(numSpheresA == 0 && modelA.numLines == 0) + return 0; + + + // B to A space + Invert(matrixA, matBA); + matBA *= matrixB; + + // transform modelB's spheres to A space + TransformPoints(aSpheresB, modelB.numSpheres, matBA, (RwV3d*)&modelB.spheres->center, sizeof(CColSphere)); + for(i = 0; i < modelB.numSpheres; i++) + aSpheresB[i].w = modelB.spheres[i].radius; + + // Check model B against A's bounding volumes + int numSpheresB = 0; + int numBoxesB = 0; + int numTrianglesB = 0; + for(i = 0; i < modelB.numSpheres; i++) + if(TestSphereBox(*(CColSphere*)&aSpheresB[i], modelA.boundingBox)) + aSphereIndicesB[numSpheresB++] = i; + for(i = 0; i < modelB.numBoxes; i++) + if(TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boxes[i])) + aBoxIndicesB[numBoxesB++] = i; + CalculateTrianglePlanes(&modelB); + if(modelB.numTriangles){ + VuTriangle vutri; + // process the first triangle + CColTriangle *tri = &modelB.triangles[0]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[0].Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(bsphereAB, vutri); + + for(i = 1; i < modelB.numTriangles; i++){ + // set up the next triangle while VU0 is running + tri = &modelB.triangles[i]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[i].Unpack(vutri.plane); + + // check previous result + if(GetVUresult()) + aTriangleIndicesB[numTrianglesB++] = i-1; + + // kick off this one + SphereToTriangleCollisionCompressed(bsphereAB, vutri); + } + + // check last result + if(GetVUresult()) + aTriangleIndicesB[numTrianglesB++] = i-1; + } + // No collision + if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) + return 0; + + // We now have the collision volumes in A and B that are worth processing. + + // Process A's spheres against B's collision volumes + int numCollisions = 0; + spherepoints[numCollisions].depth = -1.0f; + for(i = 0; i < numSpheresA; i++){ + float coldist = 1.0e24f; + bool hasCollided = false; + CColSphere *sphA = &modelA.spheres[aSphereIndicesA[i]]; + CVuVector *vusphA = &aSpheresA[aSphereIndicesA[i]]; + + for(j = 0; j < numSpheresB; j++) + // This actually looks like something was inlined here + if(ProcessSphereSphere(*(CColSphere*)vusphA, modelB.spheres[aSphereIndicesB[j]], + spherepoints[numCollisions], coldist)){ + spherepoints[numCollisions].Set( + sphA->surface, sphA->piece, + modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); + hasCollided = true; + } + for(j = 0; j < numBoxesB; j++) + if(ProcessSphereBox(*(CColSphere*)vusphA, modelB.boxes[aBoxIndicesB[j]], + spherepoints[numCollisions], coldist)){ + spherepoints[numCollisions].Set( + sphA->surface, sphA->piece, + modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); + hasCollided = true; + } + if(numTrianglesB){ + CVuVector point, normal; + float depth; + bool registeredCol; + CColTriangle *lasttri; + + VuTriangle vutri; + // process the first triangle + k = aTriangleIndicesB[0]; + CColTriangle *tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + SphereToTriangleCollisionCompressed(*vusphA, vutri); + lasttri = tri; + + for(j = 1; j < numTrianglesB; j++){ + k = aTriangleIndicesB[j]; + // set up the next triangle while VU0 is running + tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + // check previous result + // TODO: this looks inlined but spherepoints[numCollisions] does not... + if(GetVUresult(point, normal, depth)){ + depth = sphA->radius - depth; + if(depth > spherepoints[numCollisions].depth){ + spherepoints[numCollisions].point = point; + spherepoints[numCollisions].normal = normal; + spherepoints[numCollisions].Set(depth, + sphA->surface, sphA->piece, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + hasCollided = true; + + // kick off this one + SphereToTriangleCollisionCompressed(*vusphA, vutri); + lasttri = tri; + } + + // check last result + // TODO: this looks inlined but spherepoints[numCollisions] does not... + if(GetVUresult(point, normal, depth)){ + depth = sphA->radius - depth; + if(depth > spherepoints[numCollisions].depth){ + spherepoints[numCollisions].point = point; + spherepoints[numCollisions].normal = normal; + spherepoints[numCollisions].Set(depth, + sphA->surface, sphA->piece, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + hasCollided = true; + } + + if(hasCollided){ + numCollisions++; + if(numCollisions == MAX_COLLISION_POINTS) + break; + spherepoints[numCollisions].depth = -1.0f; + } + } + for(i = 0; i < numCollisions; i++){ + // TODO: both VU0 macros + spherepoints[i].point = matrixB * spherepoints[i].point; + spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); + } + + // And the same thing for the lines in A + for(i = 0; i < modelA.numLines; i++){ + aCollided[i] = false; + CVuVector *lineA = &aLinesA[i*2]; + + for(j = 0; j < numSpheresB; j++) + if(ProcessLineSphere(*(CColLine*)lineA, modelB.spheres[aSphereIndicesB[j]], + linepoints[i], linedists[i])){ + linepoints[i].Set(0, 0, +#ifdef FIX_BUGS + modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); +#else + modelB.spheres[j].surface, modelB.spheres[j].piece); +#endif + aCollided[i] = true; + } + for(j = 0; j < numBoxesB; j++) + if(ProcessLineBox(*(CColLine*)lineA, modelB.boxes[aBoxIndicesB[j]], + linepoints[i], linedists[i])){ + linepoints[i].Set(0, 0, + modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); + aCollided[i] = true; + } + if(numTrianglesB){ + CVuVector point, normal; + float dist; + bool registeredCol; + CColTriangle *lasttri; + + VuTriangle vutri; + // process the first triangle + k = aTriangleIndicesB[0]; + CColTriangle *tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); + lasttri = tri; + + for(j = 1; j < numTrianglesB; j++){ + k = aTriangleIndicesB[j]; + // set up the next triangle while VU0 is running + CColTriangle *tri = &modelB.triangles[k]; + modelB.vertices[tri->a].Unpack(vutri.v0); + modelB.vertices[tri->b].Unpack(vutri.v1); + modelB.vertices[tri->c].Unpack(vutri.v2); + modelB.trianglePlanes[k].Unpack(vutri.plane); + + // check previous result + // TODO: this again somewhat looks inlined + if(GetVUresult(point, normal, dist)){ + if(dist < linedists[i]){ + linepoints[i].point = point; + linepoints[i].normal = normal; + linedists[i] = dist; + linepoints[i].Set(0, 0, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + aCollided[i] = true; + + // kick of this one + LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); + lasttri = tri; + } + + // check last result + if(GetVUresult(point, normal, dist)){ + if(dist < linedists[i]){ + linepoints[i].point = point; + linepoints[i].normal = normal; + linedists[i] = dist; + linepoints[i].Set(0, 0, lasttri->surface, 0); + registeredCol = true; + }else + registeredCol = false; + }else + registeredCol = false; + + if(registeredCol) + aCollided[i] = true; + } + + if(aCollided[i]){ + // TODO: both VU0 macros + linepoints[i].point = matrixB * linepoints[i].point; + linepoints[i].normal = Multiply3x3(matrixB, linepoints[i].normal); + } + } + + return numCollisions; // sphere collisions +#else + static int aSphereIndicesA[MAXNUMSPHERES]; + static int aLineIndicesA[MAXNUMLINES]; + static int aSphereIndicesB[MAXNUMSPHERES]; + static int aBoxIndicesB[MAXNUMBOXES]; + static int aTriangleIndicesB[MAXNUMTRIS]; + static bool aCollided[MAXNUMLINES]; + static CColSphere aSpheresA[MAXNUMSPHERES]; + static CColLine aLinesA[MAXNUMLINES]; + static CMatrix matAB, matBA; + CColSphere s; + int i, j; + + assert(modelA.numSpheres <= MAXNUMSPHERES); + assert(modelA.numLines <= MAXNUMLINES); + + // From model A space to model B space + matAB = Invert(matrixB, matAB); + matAB *= matrixA; + + CColSphere bsphereAB; // bounding sphere of A in B space + bsphereAB.radius = modelA.boundingSphere.radius; + bsphereAB.center = matAB * modelA.boundingSphere.center; + if(!TestSphereBox(bsphereAB, modelB.boundingBox)) + return 0; + // B to A space + matBA = Invert(matrixA, matBA); + matBA *= matrixB; + + // transform modelA's spheres and lines to B space + for(i = 0; i < modelA.numSpheres; i++){ + CColSphere &s = modelA.spheres[i]; + aSpheresA[i].Set(s.radius, matAB * s.center, s.surface, s.piece); + } + for(i = 0; i < modelA.numLines; i++) + aLinesA[i].Set(matAB * modelA.lines[i].p0, matAB * modelA.lines[i].p1); + + // Test them against model B's bounding volumes + int numSpheresA = 0; + int numLinesA = 0; + for(i = 0; i < modelA.numSpheres; i++) + if(TestSphereBox(aSpheresA[i], modelB.boundingBox)) + aSphereIndicesA[numSpheresA++] = i; + // no actual check??? + for(i = 0; i < modelA.numLines; i++) + aLineIndicesA[numLinesA++] = i; + // No collision + if(numSpheresA == 0 && numLinesA == 0) + return 0; + + // Check model B against A's bounding volumes + int numSpheresB = 0; + int numBoxesB = 0; + int numTrianglesB = 0; + for(i = 0; i < modelB.numSpheres; i++){ + s.radius = modelB.spheres[i].radius; + s.center = matBA * modelB.spheres[i].center; + if(TestSphereBox(s, modelA.boundingBox)) + aSphereIndicesB[numSpheresB++] = i; + } + for(i = 0; i < modelB.numBoxes; i++) + if(TestSphereBox(bsphereAB, modelB.boxes[i])) + aBoxIndicesB[numBoxesB++] = i; + CalculateTrianglePlanes(&modelB); + for(i = 0; i < modelB.numTriangles; i++) + if(TestSphereTriangle(bsphereAB, modelB.vertices, modelB.triangles[i], modelB.trianglePlanes[i])) + aTriangleIndicesB[numTrianglesB++] = i; + assert(numSpheresB <= MAXNUMSPHERES); + assert(numBoxesB <= MAXNUMBOXES); + assert(numTrianglesB <= MAXNUMTRIS); + // No collision + if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) + return 0; + + // We now have the collision volumes in A and B that are worth processing. + + // Process A's spheres against B's collision volumes + int numCollisions = 0; + for(i = 0; i < numSpheresA; i++){ + float coldist = 1.0e24f; + bool hasCollided = false; + + for(j = 0; j < numSpheresB; j++) + hasCollided |= ProcessSphereSphere( + aSpheresA[aSphereIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numBoxesB; j++) + hasCollided |= ProcessSphereBox( + aSpheresA[aSphereIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + spherepoints[numCollisions], coldist); + for(j = 0; j < numTrianglesB; j++) + hasCollided |= ProcessSphereTriangle( + aSpheresA[aSphereIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + spherepoints[numCollisions], coldist); + + if(hasCollided) + numCollisions++; + } + for(i = 0; i < numCollisions; i++){ + spherepoints[i].point = matrixB * spherepoints[i].point; + spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); + } + + // And the same thing for the lines in A + for(i = 0; i < numLinesA; i++){ + aCollided[i] = false; + + for(j = 0; j < numSpheresB; j++) + aCollided[i] |= ProcessLineSphere( + aLinesA[aLineIndicesA[i]], + modelB.spheres[aSphereIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numBoxesB; j++) + aCollided[i] |= ProcessLineBox( + aLinesA[aLineIndicesA[i]], + modelB.boxes[aBoxIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + for(j = 0; j < numTrianglesB; j++) + aCollided[i] |= ProcessLineTriangle( + aLinesA[aLineIndicesA[i]], + modelB.vertices, + modelB.triangles[aTriangleIndicesB[j]], + modelB.trianglePlanes[aTriangleIndicesB[j]], + linepoints[aLineIndicesA[i]], + linedists[aLineIndicesA[i]]); + } + for(i = 0; i < numLinesA; i++) + if(aCollided[i]){ + j = aLineIndicesA[i]; + linepoints[j].point = matrixB * linepoints[j].point; + linepoints[j].normal = Multiply3x3(matrixB, linepoints[j].normal); + } + + return numCollisions; // sphere collisions +#endif +} + + +// +// Misc +// + +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // Between 0 and len we're above the line. + // if not, calculate distance to endpoint + if(dot <= 0.0f) + return (*point - *l0).Magnitude(); + if(dot >= lensq) + return (*point - *l1).Magnitude(); + // distance to line + return Sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); +} + +// same as above but also return the point on the line +float +CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest) +{ + float lensq = (*l1 - *l0).MagnitudeSqr(); + float dot = DotProduct(*point - *l0, *l1 - *l0); + // find out which point we're closest to + if(dot <= 0.0f) + closest = *l0; + else if(dot >= lensq) + closest = *l1; + else + closest = *l0 + (*l1 - *l0)*(dot/lensq); + // this is the distance + return (*point - closest).Magnitude(); +} + +void +CCollision::CalculateTrianglePlanes(CColModel *model) +{ + assert(model); + if(model->numTriangles == 0) + return; + + CLink *lptr; + if(model->trianglePlanes){ + // re-insert at front so it's not removed again soon + lptr = model->GetLinkPtr(); + lptr->Remove(); + ms_colModelCache.head.Insert(lptr); + }else{ + lptr = ms_colModelCache.Insert(model); + if(lptr == nil){ + // make room if we have to, remove last in list + lptr = ms_colModelCache.tail.prev; + assert(lptr); + assert(lptr->item); + lptr->item->RemoveTrianglePlanes(); + ms_colModelCache.Remove(lptr); + // now this cannot fail + lptr = ms_colModelCache.Insert(model); + assert(lptr); + } + model->CalculateTrianglePlanes(); + model->SetLinkPtr(lptr); + } +} + +void +CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) +{ + int i; + CVector min, max; + CVector verts[8]; + CVector c; + float r; + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + min = colModel.boundingBox.min; + max = colModel.boundingBox.max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[3].x, verts[3].y, verts[3].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[2].x, verts[2].y, verts[2].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[0].x, verts[0].y, verts[0].z, + 0xFF0000FF, 0xFF0000FF); + + CLines::RenderLineWithClipping( + verts[4].x, verts[4].y, verts[4].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[5].x, verts[5].y, verts[5].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[7].x, verts[7].y, verts[7].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[6].x, verts[6].y, verts[6].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFF0000FF, 0xFF0000FF); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFF0000FF, 0xFF0000FF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFF0000FF, 0xFF0000FF); + + for(i = 0; i < colModel.numSpheres; i++){ + c = mat * colModel.spheres[i].center; + r = colModel.spheres[i].radius; + + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x-r, c.y-r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x-r, c.y+r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x+r, c.y-r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x, c.y, c.z-r, + c.x+r, c.y+r, c.z, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x-r, c.y-r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x-r, c.y+r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x+r, c.y-r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + CLines::RenderLineWithClipping( + c.x+r, c.y+r, c.z, + c.x, c.y, c.z+r, + 0xFF00FFFF, 0xFF00FFFF); + } + + for(i = 0; i < colModel.numLines; i++){ + verts[0] = colModel.lines[i].p0; + verts[1] = colModel.lines[i].p1; + + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0x00FFFFFF, 0x00FFFFFF); + } + + for(i = 0; i < colModel.numBoxes; i++){ + min = colModel.boxes[i].min; + max = colModel.boxes[i].max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[3].x, verts[3].y, verts[3].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[2].x, verts[2].y, verts[2].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[0].x, verts[0].y, verts[0].z, + 0xFFFFFFFF, 0xFFFFFFFF); + + CLines::RenderLineWithClipping( + verts[4].x, verts[4].y, verts[4].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[5].x, verts[5].y, verts[5].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[7].x, verts[7].y, verts[7].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[6].x, verts[6].y, verts[6].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFFFFFFFF, 0xFFFFFFFF); + + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[4].x, verts[4].y, verts[4].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[5].x, verts[5].y, verts[5].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[2].x, verts[2].y, verts[2].z, + verts[6].x, verts[6].y, verts[6].z, + 0xFFFFFFFF, 0xFFFFFFFF); + CLines::RenderLineWithClipping( + verts[3].x, verts[3].y, verts[3].z, + verts[7].x, verts[7].y, verts[7].z, + 0xFFFFFFFF, 0xFFFFFFFF); + } + + for(i = 0; i < colModel.numTriangles; i++){ + colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); + colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); + colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + verts[2] = mat * verts[2]; + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[1].x, verts[1].y, verts[1].z, + 0x00FF00FF, 0x00FF00FF); + CLines::RenderLineWithClipping( + verts[0].x, verts[0].y, verts[0].z, + verts[2].x, verts[2].y, verts[2].z, + 0x00FF00FF, 0x00FF00FF); + CLines::RenderLineWithClipping( + verts[1].x, verts[1].y, verts[1].z, + verts[2].x, verts[2].y, verts[2].z, + 0x00FF00FF, 0x00FF00FF); + } + + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); +} + +void +CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id) +{ + int i; + int s; + float f; + CVector verts[8]; + CVector min, max; + int r, g, b; + RwImVertexIndex *iptr; + RwIm3DVertex *vptr; + + RenderBuffer::ClearRenderBuffer(); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); + + for(i = 0; i < colModel.numTriangles; i++){ + colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); + colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); + colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); + verts[0] = mat * verts[0]; + verts[1] = mat * verts[1]; + verts[2] = mat * verts[2]; + + // game doesn't do this + r = 255; + g = 128; + b = 0; + + s = colModel.triangles[i].surface; + f = (s & 0xF)/32.0f + 0.5f; + switch(CSurfaceTable::GetAdhesionGroup(s)){ + case ADHESIVE_RUBBER: + r = f * 255.0f; + g = 0; + b = 0; + break; + case ADHESIVE_HARD: + r = f*255.0f; + g = f*255.0f; + b = f*128.0f; + break; + case ADHESIVE_ROAD: + r = f*128.0f; + g = f*128.0f; + b = f*128.0f; + break; + case ADHESIVE_LOOSE: + r = 0; + g = f * 255.0f; + b = 0; + break; + case ADHESIVE_WET: + r = 0; + g = 0; + b = f * 255.0f; + break; + default: + // this doesn't make much sense + r *= f; + g *= f; + b *= f; + } + + if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE || + s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE) + if(CTimer::GetFrameCounter() & 1){ + r = 0; + g = 0; + b = 0; + } + + if(s > SURFACE_METAL_GATE){ + r = CGeneral::GetRandomNumber(); + g = CGeneral::GetRandomNumber(); + b = CGeneral::GetRandomNumber(); + printf("Illegal surfacetype:%d on MI:%d\n", s, id); + } + + RenderBuffer::StartStoring(6, 3, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 0; iptr[4] = 2; iptr[5] = 1; + RenderBuffer::StopStoring(); + } + + for(i = 0; i < colModel.numBoxes; i++){ + min = colModel.boxes[i].min; + max = colModel.boxes[i].max; + + verts[0] = mat * CVector(min.x, min.y, min.z); + verts[1] = mat * CVector(min.x, min.y, max.z); + verts[2] = mat * CVector(min.x, max.y, min.z); + verts[3] = mat * CVector(min.x, max.y, max.z); + verts[4] = mat * CVector(max.x, min.y, min.z); + verts[5] = mat * CVector(max.x, min.y, max.z); + verts[6] = mat * CVector(max.x, max.y, min.z); + verts[7] = mat * CVector(max.x, max.y, max.z); + + s = colModel.boxes[i].surface; + f = (s & 0xF)/32.0f + 0.5f; + switch(CSurfaceTable::GetAdhesionGroup(s)){ + case ADHESIVE_RUBBER: + r = f * 255.0f; + g = 0; + b = 0; + break; + case ADHESIVE_HARD: + r = f*255.0f; + g = f*255.0f; + b = f*128.0f; + break; + case ADHESIVE_ROAD: + r = f*128.0f; + g = f*128.0f; + b = f*128.0f; + break; + case ADHESIVE_LOOSE: + r = 0; + g = f * 255.0f; + b = 0; + break; + case ADHESIVE_WET: + r = 0; + g = 0; + b = f * 255.0f; + break; + default: + // this doesn't make much sense + r *= f; + g *= f; + b *= f; + } + + if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE || + s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE) + if(CTimer::GetFrameCounter() & 1){ + r = 0; + g = 0; + b = 0; + } + + RenderBuffer::StartStoring(36, 8, &iptr, &vptr); + RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[3], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[4], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[5], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[6], r, g, b, 255); + RwIm3DVertexSetRGBA(&vptr[7], r, g, b, 255); + RwIm3DVertexSetU(&vptr[0], 0.0f); + RwIm3DVertexSetV(&vptr[0], 0.0f); + RwIm3DVertexSetU(&vptr[1], 0.0f); + RwIm3DVertexSetV(&vptr[1], 1.0f); + RwIm3DVertexSetU(&vptr[2], 1.0f); + RwIm3DVertexSetV(&vptr[2], 1.0f); + RwIm3DVertexSetU(&vptr[3], 0.0f); + RwIm3DVertexSetV(&vptr[3], 0.0f); + RwIm3DVertexSetU(&vptr[4], 0.0f); + RwIm3DVertexSetV(&vptr[4], 1.0f); + RwIm3DVertexSetU(&vptr[5], 1.0f); + RwIm3DVertexSetV(&vptr[5], 1.0f); + RwIm3DVertexSetU(&vptr[6], 0.0f); + RwIm3DVertexSetV(&vptr[6], 1.0f); + RwIm3DVertexSetU(&vptr[7], 1.0f); + RwIm3DVertexSetV(&vptr[7], 1.0f); + RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); + RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); + RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); + RwIm3DVertexSetPos(&vptr[3], verts[3].x, verts[3].y, verts[3].z); + RwIm3DVertexSetPos(&vptr[4], verts[4].x, verts[4].y, verts[4].z); + RwIm3DVertexSetPos(&vptr[5], verts[5].x, verts[5].y, verts[5].z); + RwIm3DVertexSetPos(&vptr[6], verts[6].x, verts[6].y, verts[6].z); + RwIm3DVertexSetPos(&vptr[7], verts[7].x, verts[7].y, verts[7].z); + iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; + iptr[3] = 1; iptr[4] = 3; iptr[5] = 2; + iptr[6] = 1; iptr[7] = 5; iptr[8] = 7; + iptr[9] = 1; iptr[10] = 7; iptr[11] = 3; + iptr[12] = 2; iptr[13] = 3; iptr[14] = 7; + iptr[15] = 2; iptr[16] = 7; iptr[17] = 6; + iptr[18] = 0; iptr[19] = 5; iptr[20] = 1; + iptr[21] = 0; iptr[22] = 4; iptr[23] = 5; + iptr[24] = 0; iptr[25] = 2; iptr[26] = 4; + iptr[27] = 2; iptr[28] = 6; iptr[29] = 4; + iptr[30] = 4; iptr[31] = 6; iptr[32] = 7; + iptr[33] = 4; iptr[34] = 7; iptr[35] = 5; + RenderBuffer::StopStoring(); + } + + RenderBuffer::RenderStuffInBuffer(); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); +} \ 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/collision/TempColModels.cpp b/src/collision/TempColModels.cpp new file mode 100644 index 00000000..849eb01e --- /dev/null +++ b/src/collision/TempColModels.cpp @@ -0,0 +1,296 @@ +#include "common.h" + +#include "TempColModels.h" + +CColModel CTempColModels::ms_colModelPed1; +CColModel CTempColModels::ms_colModelPed2; +CColModel CTempColModels::ms_colModelBBox; +CColModel CTempColModels::ms_colModelBumper1; +CColModel CTempColModels::ms_colModelWheel1; +CColModel CTempColModels::ms_colModelPanel1; +CColModel CTempColModels::ms_colModelBodyPart2; +CColModel CTempColModels::ms_colModelBodyPart1; +CColModel CTempColModels::ms_colModelCutObj[5]; +CColModel CTempColModels::ms_colModelPedGroundHit; +CColModel CTempColModels::ms_colModelBoot1; +CColModel CTempColModels::ms_colModelDoor1; +CColModel CTempColModels::ms_colModelBonnet1; + + +CColSphere s_aPedSpheres[3]; +CColSphere s_aPed2Spheres[3]; +CColSphere s_aPedGSpheres[4]; +#ifdef FIX_BUGS +CColSphere s_aDoorSpheres[3]; +#else +CColSphere s_aDoorSpheres[4]; +#endif +CColSphere s_aBumperSpheres[4]; +CColSphere s_aPanelSpheres[4]; +CColSphere s_aBonnetSpheres[4]; +CColSphere s_aBootSpheres[4]; +CColSphere s_aWheelSpheres[2]; +CColSphere s_aBodyPartSpheres1[2]; +CColSphere s_aBodyPartSpheres2[2]; + +void +CTempColModels::Initialise(void) +{ +#define SET_COLMODEL_SPHERES(colmodel, sphrs)\ + colmodel.numSpheres = ARRAY_SIZE(sphrs);\ + colmodel.spheres = sphrs;\ + colmodel.level = LEVEL_GENERIC;\ + colmodel.ownsCollisionVolumes = false;\ + + int i; + + 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)); + 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; + } + + // Ped Spheres + + for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) + s_aPedSpheres[i].radius = 0.35f; + + s_aPedSpheres[0].center = CVector(0.0f, 0.0f, -0.25f); + s_aPedSpheres[1].center = CVector(0.0f, 0.0f, 0.15f); + s_aPedSpheres[2].center = CVector(0.0f, 0.0f, 0.55f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aPedGSpheres); i++) { +#endif + s_aPedSpheres[i].surface = SURFACE_PED; + s_aPedSpheres[i].piece = 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 + + s_aPed2Spheres[0].radius = 0.3f; + s_aPed2Spheres[1].radius = 0.4f; + s_aPed2Spheres[2].radius = 0.3f; + + s_aPed2Spheres[0].center = CVector(0.0f, 0.35f, -0.9f); + s_aPed2Spheres[1].center = CVector(0.0f, 0.0f, -0.9f); + s_aPed2Spheres[2].center = CVector(0.0f, -0.35f, -0.9f); + + for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { + s_aPed2Spheres[i].surface = SURFACE_PED; + s_aPed2Spheres[i].piece = 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); + + // Ped ground collision + + s_aPedGSpheres[0].radius = 0.35f; + s_aPedGSpheres[1].radius = 0.35f; + s_aPedGSpheres[2].radius = 0.35f; + s_aPedGSpheres[3].radius = 0.3f; + + s_aPedGSpheres[0].center = CVector(0.0f, -0.4f, -0.9f); + s_aPedGSpheres[1].center = CVector(0.0f, -0.1f, -0.9f); + s_aPedGSpheres[2].center = CVector(0.0f, 0.25f, -0.9f); + s_aPedGSpheres[3].center = CVector(0.0f, 0.65f, -0.9f); + + s_aPedGSpheres[0].surface = SURFACE_PED; + s_aPedGSpheres[1].surface = SURFACE_PED; + s_aPedGSpheres[2].surface = SURFACE_PED; + s_aPedGSpheres[3].surface = SURFACE_PED; + s_aPedGSpheres[0].piece = 4; + s_aPedGSpheres[1].piece = 1; + s_aPedGSpheres[2].piece = 0; + s_aPedGSpheres[3].piece = 6; + + 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); + + // Door Spheres + + s_aDoorSpheres[0].radius = 0.15f; + s_aDoorSpheres[1].radius = 0.15f; + s_aDoorSpheres[2].radius = 0.25f; + + s_aDoorSpheres[0].center = CVector(0.0f, -0.25f, -0.35f); + s_aDoorSpheres[1].center = CVector(0.0f, -0.95f, -0.35f); + s_aDoorSpheres[2].center = CVector(0.0f, -0.6f, 0.25f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aDoorSpheres); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { +#endif + s_aDoorSpheres[i].surface = SURFACE_CAR_PANEL; + s_aDoorSpheres[i].piece = 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); + + // Bumper Spheres + + for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) + s_aBumperSpheres[i].radius = 0.15f; + + s_aBumperSpheres[0].center = CVector(0.85f, -0.05f, 0.0f); + s_aBumperSpheres[1].center = CVector(0.4f, 0.05f, 0.0f); + s_aBumperSpheres[2].center = CVector(-0.4f, 0.05f, 0.0f); + s_aBumperSpheres[3].center = CVector(-0.85f, -0.05f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) { + s_aBumperSpheres[i].surface = SURFACE_CAR_PANEL; + s_aBumperSpheres[i].piece = 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); + + // Panel Spheres + + for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) + s_aPanelSpheres[i].radius = 0.15f; + + s_aPanelSpheres[0].center = CVector(0.15f, 0.45f, 0.0f); + s_aPanelSpheres[1].center = CVector(0.15f, -0.45f, 0.0f); + s_aPanelSpheres[2].center = CVector(-0.15f, -0.45f, 0.0f); + s_aPanelSpheres[3].center = CVector(-0.15f, 0.45f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) { + s_aPanelSpheres[i].surface = SURFACE_CAR_PANEL; + s_aPanelSpheres[i].piece = 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); + + // Bonnet Spheres + + for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) + s_aBonnetSpheres[i].radius = 0.2f; + + s_aBonnetSpheres[0].center = CVector(-0.4f, 0.1f, 0.0f); + s_aBonnetSpheres[1].center = CVector(-0.4f, 0.9f, 0.0f); + s_aBonnetSpheres[2].center = CVector(0.4f, 0.1f, 0.0f); + s_aBonnetSpheres[3].center = CVector(0.4f, 0.9f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) { + s_aBonnetSpheres[i].surface = SURFACE_CAR_PANEL; + s_aBonnetSpheres[i].piece = 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); + + // Boot Spheres + + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) + s_aBootSpheres[i].radius = 0.2f; + + s_aBootSpheres[0].center = CVector(-0.4f, -0.1f, 0.0f); + s_aBootSpheres[1].center = CVector(-0.4f, -0.6f, 0.0f); + s_aBootSpheres[2].center = CVector(0.4f, -0.1f, 0.0f); + s_aBootSpheres[3].center = CVector(0.4f, -0.6f, 0.0f); + + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { + s_aBootSpheres[i].surface = SURFACE_CAR_PANEL; + s_aBootSpheres[i].piece = 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); + + // Wheel Spheres + + s_aWheelSpheres[0].radius = 0.35f; + s_aWheelSpheres[1].radius = 0.35f; + + s_aWheelSpheres[0].center = CVector(-0.3f, 0.0f, 0.0f); + s_aWheelSpheres[1].center = CVector(0.3f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aWheelSpheres); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { +#endif + s_aWheelSpheres[i].surface = SURFACE_WHEELBASE; + s_aWheelSpheres[i].piece = 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); + + // Body Part Spheres 1 + + s_aBodyPartSpheres1[0].radius = 0.2f; + s_aBodyPartSpheres1[1].radius = 0.2f; + + s_aBodyPartSpheres1[0].center = CVector(0.0f, 0.0f, 0.0f); + s_aBodyPartSpheres1[1].center = CVector(0.8f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres1); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { +#endif + s_aBodyPartSpheres1[i].surface = SURFACE_PED; + s_aBodyPartSpheres1[i].piece = 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); + + // Body Part Spheres 2 + + s_aBodyPartSpheres2[0].radius = 0.15f; + s_aBodyPartSpheres2[1].radius = 0.15f; + + s_aBodyPartSpheres2[0].center = CVector(0.0f, 0.0f, 0.0f); + s_aBodyPartSpheres2[1].center = CVector(0.5f, 0.0f, 0.0f); + +#ifdef FIX_BUGS + for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres2); i++) { +#else + for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { +#endif + s_aBodyPartSpheres2[i].surface = SURFACE_PED; + s_aBodyPartSpheres2[i].piece = 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); + +#undef SET_COLMODEL_SPHERES +} diff --git a/src/collision/TempColModels.h b/src/collision/TempColModels.h new file mode 100644 index 00000000..3e1dd5e1 --- /dev/null +++ b/src/collision/TempColModels.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Collision.h" + +class CTempColModels +{ +public: + static CColModel ms_colModelPed1; + static CColModel ms_colModelPed2; + static CColModel ms_colModelBBox; + static CColModel ms_colModelBumper1; + static CColModel ms_colModelWheel1; + static CColModel ms_colModelPanel1; + static CColModel ms_colModelBodyPart2; + static CColModel ms_colModelBodyPart1; + static CColModel ms_colModelCutObj[5]; + static CColModel ms_colModelPedGroundHit; + static CColModel ms_colModelBoot1; + static CColModel ms_colModelDoor1; + static CColModel ms_colModelBonnet1; + + static void Initialise(void); +}; 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/collision/vu0Collision.dsm b/src/collision/vu0Collision.dsm new file mode 100644 index 00000000..657c8b81 --- /dev/null +++ b/src/collision/vu0Collision.dsm @@ -0,0 +1,21 @@ +.align 4 +.global Vu0CollisionDmaTag +Vu0CollisionDmaTag: +DMAcnt * +MPG 0, * +.vu +.include "vu0Collision_1.s" +.EndMPG +.EndDmaData +DMAend + +.global Vu0Collision2DmaTag +Vu0Collision2DmaTag: +DMAcnt * +MPG 0, * +.vu +.include "vu0Collision_2.s" +.EndMPG +.EndDmaData +DMAend +.end diff --git a/src/collision/vu0Collision_1.s b/src/collision/vu0Collision_1.s new file mode 100644 index 00000000..055c8640 --- /dev/null +++ b/src/collision/vu0Collision_1.s @@ -0,0 +1,610 @@ +QuitAndFail: + NOP[E] IADDIU VI01, VI00, 0 + NOP NOP + + +QuitAndSucceed: + NOP[E] IADDIU VI01, VI00, 1 + NOP NOP + + +; 20 -- unused +; VF12, VF13 xyz: sphere centers +; VF14, VF15 x: sphere radii +; out: +; VI01: set when collision +; VF01: supposed to be intersection point? +; VF02: normal (pointing towards s1, not normalized) +.globl Vu0SphereToSphereCollision +Vu0SphereToSphereCollision: + SUB.xyz VF02, VF13, VF12 NOP ; dist of centers + ADD.x VF04, VF14, VF15 NOP ; s = sum of radii + MUL.xyzw VF03, VF02, VF02 NOP ; + MUL.x VF04, VF04, VF04 DIV Q, VF14x, VF04x ; square s + NOP NOP ; + NOP NOP ; + MULAx.w ACC, VF00, VF03 NOP ; + MADDAy.w ACC, VF00, VF03 NOP ; + MADDz.w VF03, VF00, VF03 NOP ; d = DistSq of centers + NOP NOP ; + MULAw.xyz ACC, VF12, VF00 NOP ; + MADDq.xyz VF01, VF02, Q NOP ; intersection, but wrong + CLIPw.xyz VF04, VF03 NOP ; compare s and d + SUB.xyz VF02, VF00, VF02 NOP ; compute normal + NOP NOP ; + NOP NOP ; + NOP FCAND VI01, 0x3 ; 0x2 cannot be set here + NOP[E] NOP ; + NOP NOP ; + + +; B8 -- unused +; VF12: +; VF13: radius +; VF14: +; VF15: box dimensions (?) +.globl Vu0SphereToAABBCollision +Vu0SphereToAABBCollision: + SUB.xyz VF03, VF12, VF14 LOI 0.5 + MULi.xyz VF15, VF15, I NOP + MUL.x VF13, VF13, VF13 NOP + SUB.xyz VF04, VF03, VF15 NOP + ADD.xyz VF05, VF03, VF15 MR32.xyzw VF16, VF15 + CLIPw.xyz VF03, VF16 MR32.xyzw VF17, VF16 + MUL.xyz VF04, VF04, VF04 NOP + MUL.xyz VF05, VF05, VF05 NOP + CLIPw.xyz VF03, VF17 MR32.xyzw VF16, VF17 + NOP FCAND VI01, 0x1 + MINI.xyz VF04, VF04, VF05 MFIR.x VF09, VI01 + NOP NOP + CLIPw.xyz VF03, VF16 FCAND VI01, 0x4 + NOP MFIR.y VF09, VI01 + NOP NOP + MULAx.w ACC, VF00, VF00 NOP + ADD.xyz VF01, VF00, VF03 FCAND VI01, 0x10 + NOP MFIR.z VF09, VI01 + NOP LOI 2 + NOP FCAND VI01, 0x30 + SUBAw.xyz ACC, VF00, VF00 IADD VI04, VI00, VI01 + ITOF0.xyz VF09, VF09 FCAND VI01, 0x300 + NOP IADD VI03, VI00, VI01 + NOP FCAND VI01, 0x3000 + NOP IADD VI02, VI00, VI01 + MADDi.xyzw VF09, VF09, I NOP + NOP IBEQ VI04, VI00, IgnoreZValue + NOP NOP + MADDAz.w ACC, VF00, VF04 NOP + MUL.z VF01, VF09, VF15 NOP +IgnoreZValue: + NOP IBEQ VI03, VI00, IgnoreYValue + NOP NOP + MADDAy.w ACC, VF00, VF04 NOP + MUL.y VF01, VF09, VF15 NOP +IgnoreYValue: + NOP IBEQ VI02, VI00, IgnoreXValue + NOP NOP + MADDAx.w ACC, VF00, VF04 NOP + MUL.x VF01, VF09, VF15 NOP +IgnoreXValue: + MADDx.w VF06, VF00, VF00 NOP + SUB.xyz VF02, VF03, VF01 NOP + ADD.xyz VF01, VF01, VF14 NOP + MULx.w VF01, VF00, VF00 NOP + CLIPw.xyz VF13, VF06 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x1 +QuitMicrocode: + NOP[E] NOP + NOP NOP + + +; 240 +.globl Vu0LineToSphereCollision +Vu0LineToSphereCollision: + SUB.xyzw VF01, VF13, VF12 NOP + SUB.xyzw VF02, VF14, VF12 NOP + MUL.xyz VF03, VF01, VF02 NOP + MUL.xyz VF04, VF01, VF01 NOP + MUL.x VF15, VF15, VF15 NOP + MUL.xyz VF02, VF02, VF02 NOP + MULAx.w ACC, VF00, VF03 NOP + MADDAy.w ACC, VF00, VF03 NOP + MADDz.w VF03, VF00, VF03 NOP + MULAx.w ACC, VF00, VF04 NOP + MADDAy.w ACC, VF00, VF04 NOP + MADDz.w VF01, VF00, VF04 NOP + MULAx.w ACC, VF00, VF02 NOP + MADDAy.w ACC, VF00, VF02 NOP + MADDz.w VF02, VF00, VF02 NOP + MULA.w ACC, VF03, VF03 NOP + MADDAx.w ACC, VF01, VF15 NOP + MSUB.w VF05, VF01, VF02 NOP + NOP NOP + NOP NOP + NOP IADDIU VI02, VI00, 0x10 + NOP FMAND VI01, VI02 + NOP IBNE VI01, VI00, QuitAndFail + NOP NOP + CLIPw.xyz VF15, VF02 SQRT Q, VF05w + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x1 + NOP IBNE VI00, VI01, LineStartInsideSphere + NOP NOP + SUBq.w VF05, VF03, Q NOP + SUB.w VF05, VF05, VF01 DIV Q, VF05w, VF01w + NOP FMAND VI01, VI02 + NOP IBNE VI01, VI00, QuitAndFail + NOP NOP + NOP FMAND VI01, VI02 + NOP IBEQ VI01, VI00, QuitAndFail + NOP NOP + ADDA.xyz ACC, VF12, VF00 NOP + MADDq.xyz VF01, VF01, Q NOP + MULx.w VF01, VF00, VF00 NOP + SUB.xyz VF02, VF01, VF14 NOP + NOP[E] NOP + NOP NOP +LineStartInsideSphere: + NOP MOVE.xyzw VF01, VF12 + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP + + +; 3C0 +.globl Vu0LineToAABBCollision +Vu0LineToAABBCollision: + SUB.xyzw VF08, VF13, VF12 LOI 0.5 + MULi.xyz VF15, VF15, I IADDIU VI08, VI00, 0x0 + SUB.xyzw VF12, VF12, VF14 NOP + SUB.xyzw VF13, VF13, VF14 NOP + NOP DIV Q, VF00w, VF08x + NOP MR32.xyzw VF03, VF15 + SUB.xyz VF06, VF15, VF12 NOP + ADD.xyz VF07, VF15, VF12 NOP + NOP NOP + CLIPw.xyz VF12, VF03 MR32.xyzw VF04, VF03 + NOP NOP + ADDq.x VF09, VF00, Q DIV Q, VF00w, VF08y + NOP NOP + CLIPw.xyz VF12, VF04 MR32.xyzw VF05, VF04 + SUB.xyz VF07, VF00, VF07 IADDIU VI06, VI00, 0xCC + NOP IADDIU VI07, VI00, 0x30 + NOP NOP + CLIPw.xyz VF12, VF05 FCGET VI02 + NOP IAND VI02, VI02, VI06 + ADDq.y VF09, VF00, Q DIV Q, VF00w, VF08z + SUB.xyz VF10, VF00, VF10 NOP + CLIPw.xyz VF13, VF03 FCGET VI03 + CLIPw.xyz VF13, VF04 IAND VI03, VI03, VI07 + CLIPw.xyz VF13, VF05 FCAND VI01, 0x3330 + NOP IBEQ VI01, VI00, StartPointInsideAABB + NOP NOP + ADDq.z VF09, VF00, Q FCGET VI04 + NOP FCGET VI05 + NOP IAND VI04, VI04, VI06 + NOP IAND VI05, VI05, VI07 + MULx.xyz VF17, VF08, VF09 NOP + MULy.xyz VF18, VF08, VF09 IADDIU VI07, VI00, 0x80 + MULz.xyz VF19, VF08, VF09 IAND VI06, VI02, VI07 + MUL.w VF10, VF00, VF00 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMaxXSide + NOP NOP + MULAx.xyz ACC, VF17, VF07 NOP + MADDw.xyz VF16, VF12, VF00 NOP + MUL.x VF10, VF07, VF09 NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF16, VF05 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x330 + NOP IBNE VI01, VI00, CheckMaxXSide + NOP NOP + MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + SUBw.x VF02, VF00, VF00 NOP +CheckMaxXSide: + MULAx.xyz ACC, VF17, VF06 IADDIU VI07, VI00, 0x40 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 + MUL.x VF10, VF06, VF09 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMinYSide + NOP NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF16, VF05 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0xCC03 + NOP IBNE VI01, VI00, CheckMinYSide + NOP NOP + MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + ADDw.x VF02, VF00, VF00 NOP +CheckMinYSide: + MULAy.xyz ACC, VF18, VF07 IADDIU VI07, VI00, 0x8 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 + MUL.y VF10, VF07, VF09 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMaxYSide + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF05 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3C0C + NOP IBNE VI01, VI00, CheckMaxYSide + NOP NOP + MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + SUBw.y VF02, VF00, VF00 NOP +CheckMaxYSide: + MULAy.xyz ACC, VF18, VF06 IADDIU VI07, VI00, 0x4 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 + MUL.y VF10, VF06, VF09 IAND VI07, VI04, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMinZSide + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF05 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3C0C + NOP IBNE VI01, VI00, CheckMinZSide + NOP NOP + MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + ADDw.y VF02, VF00, VF00 NOP +CheckMinZSide: + MULAz.xyz ACC, VF19, VF07 IADDIU VI07, VI00, 0x20 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 + MUL.z VF10, VF07, VF09 IAND VI07, VI05, VI07 + NOP NOP + NOP IBEQ VI06, VI07, CheckMaxZSide + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, CheckMaxZSide + NOP NOP + MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + SUBw.z VF02, VF00, VF00 NOP +CheckMaxZSide: + MULAz.xyz ACC, VF19, VF06 IADDIU VI07, VI00, 0x10 + MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 + MUL.z VF10, VF06, VF09 IAND VI07, VI05, VI07 + NOP NOP + NOP IBEQ VI06, VI07, DoneAllChecks + NOP NOP + CLIPw.xyz VF16, VF03 NOP + CLIPw.xyz VF16, VF04 NOP + CLIPw.xyz VF10, VF10 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, DoneAllChecks + NOP NOP + MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 + ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 + ADDw.z VF02, VF00, VF00 NOP +DoneAllChecks: + ADD.xyz VF01, VF01, VF14 IADD VI01, VI00, VI08 + NOP[E] NOP + NOP NOP +StartPointInsideAABB: + ADD.xyz VF01, VF12, VF14 WAITQ + NOP IADDIU VI01, VI00, 0x1 + NOP[E] NOP + NOP NOP + + +; 860 +.globl Vu0LineToTriangleCollisionCompressedStart +Vu0LineToTriangleCollisionCompressedStart: + ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 + ITOF0.xyzw VF14, VF14 NOP + ITOF0.xyzw VF15, VF15 NOP + ITOF0.xyzw VF16, VF16 NOP + MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 + MULi.w VF17, VF17, I NOP + MULi.xyzw VF14, VF14, I NOP + MULi.xyzw VF15, VF15, I NOP + MULi.xyzw VF16, VF16, I NOP +; fall through + +; 8A8 +; VF12: point0 +; VF13: point1 +; VF14-16: verts +; VF17: plane +; out: +; VF01: intersection point +; VF02: triangle normal +; VF03 x: intersection parameter +.globl Vu0LineToTriangleCollisionStart +Vu0LineToTriangleCollisionStart: + MUL.xyz VF10, VF17, VF12 LOI 0.5 + MUL.xyz VF11, VF17, VF13 NOP + SUB.xyz VF02, VF13, VF12 NOP ; line dist + ADD.xyz VF17, VF17, VF00 NOP + MULi.w VF03, VF00, I NOP + MULAx.w ACC, VF00, VF10 NOP + MADDAy.w ACC, VF00, VF10 IADDIU VI06, VI00, 0xE0 + MADDz.w VF10, VF00, VF10 FMAND VI05, VI06 ; -- normal sign flags, unused + MULAx.w ACC, VF00, VF11 NOP + MADDAy.w ACC, VF00, VF11 NOP + MADDz.w VF11, VF00, VF11 NOP + SUB.w VF09, VF17, VF10 NOP ; plane-pos 0 + CLIPw.xyz VF17, VF03 NOP ; compare normal against 0.5 to figure out which in which dimension to compare + NOP IADDIU VI02, VI00, 0x10 ; Sw flag + SUBA.w ACC, VF17, VF11 NOP ; plane-pos 1 + SUB.w VF08, VF11, VF10 FMAND VI01, VI02 + NOP NOP + NOP NOP + NOP FMAND VI02, VI02 + NOP IBEQ VI01, VI02, QuitAndFail ; if on same side, no collision + NOP NOP + NOP DIV Q, VF09w, VF08w ; parameter of intersection + NOP FCAND VI01, 0x3 ; check x direction + NOP IADDIU VI02, VI01, 0x7F + NOP IADDIU VI06, VI00, 0x80 + NOP IAND VI02, VI02, VI06 ; Sx flag + NOP FCAND VI01, 0xC ; check y direction + NOP IADDIU VI03, VI01, 0x3F + MULAw.xyz ACC, VF12, VF00 IADDIU VI06, VI00, 0x40 + MADDq.xyz VF01, VF02, Q IAND VI03, VI03, VI06 ; point of intersection -- Sy flag + MULx.w VF01, VF00, VF00 FCAND VI01, 0x30 ; -- check z direction + ADDq.x VF03, VF00, Q IADDIU VI04, VI01, 0x1F ; output parameter + SUB.xyz VF05, VF15, VF14 IADDIU VI06, VI00, 0x20 ; edge vectors + SUB.xyz VF08, VF01, VF14 IAND VI04, VI04, VI06 ; edge vectors -- Sz flag + SUB.xyz VF06, VF16, VF15 IADD VI06, VI02, VI03 ; edge vectors + SUB.xyz VF09, VF01, VF15 IADD VI06, VI06, VI04 ; edge vectors -- combine flags + SUB.xyz VF07, VF14, VF16 NOP ; edge vectors + SUB.xyz VF10, VF01, VF16 NOP ; edge vectors + OPMULA.xyz ACC, VF08, VF05 NOP + OPMSUB.xyz VF18, VF05, VF08 NOP ; cross1 + OPMULA.xyz ACC, VF09, VF06 NOP + OPMSUB.xyz VF19, VF06, VF09 NOP ; cross2 + OPMULA.xyz ACC, VF10, VF07 NOP + OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; cross3 + NOP NOP + NOP FMAND VI03, VI06 + NOP NOP + NOP FMAND VI04, VI06 + NOP NOP + NOP IBNE VI03, VI02, QuitAndFail ; point has to lie on the same side of all edges (i.e. inside) + NOP NOP + NOP IBNE VI04, VI02, QuitAndFail + NOP NOP + MULw.xyz VF02, VF17, VF00 IADDIU VI01, VI00, 0x1 ; success + NOP[E] NOP + NOP NOP + + +; A68 +; VF12: center +; VF14: line origin +; VF15: line vector to other point +; out: VF16 xyz: nearest point on line; w: distance to that point +DistanceBetweenSphereAndLine: + SUB.xyz VF20, VF12, VF14 NOP + MUL.xyz VF21, VF15, VF15 NOP + ADDA.xyz ACC, VF14, VF15 NOP + MSUBw.xyz VF25, VF12, VF00 NOP ; VF25 = VF12 - (VF14+VF15) + MUL.xyz VF22, VF20, VF20 NOP + MUL.xyz VF23, VF20, VF15 NOP + MULAx.w ACC, VF00, VF21 NOP + MADDAy.w ACC, VF00, VF21 NOP + MADDz.w VF21, VF00, VF21 NOP ; MagSq VF15 (line length) + MULAx.w ACC, VF00, VF23 NOP + MADDAy.w ACC, VF00, VF23 NOP + MADDz.w VF23, VF00, VF23 NOP ; dot(VF12-VF14, VF15) + MULAx.w ACC, VF00, VF22 NOP + MADDAy.w ACC, VF00, VF22 NOP + MADDz.w VF22, VF00, VF22 IADDIU VI08, VI00, 0x10 ; MagSq VF12-VF14 -- Sw bit + MUL.xyz VF25, VF25, VF25 FMAND VI08, VI08 + NOP DIV Q, VF23w, VF21w + NOP IBNE VI00, VI08, NegativeRatio + NOP NOP + ADDA.xyz ACC, VF00, VF14 NOP + MADDq.xyz VF16, VF15, Q WAITQ ; nearest point on infinte line + ADDq.x VF24, VF00, Q NOP ; ratio + NOP NOP + NOP NOP + SUB.xyz VF26, VF16, VF12 NOP + CLIPw.xyz VF24, VF00 NOP ; compare ratio to 1.0 + NOP NOP + NOP NOP + MUL.xyz VF26, VF26, VF26 NOP + NOP FCAND VI01, 0x1 + NOP IBNE VI00, VI01, RatioGreaterThanOne + NOP NOP + MULAx.w ACC, VF00, VF26 NOP + MADDAy.w ACC, VF00, VF26 NOP + MADDz.w VF16, VF00, VF26 NOP ; distance + NOP JR VI15 + NOP NOP +NegativeRatio: + ADD.xyz VF16, VF00, VF14 NOP ; return line origin + MUL.w VF16, VF00, VF22 NOP ; and DistSq to it + NOP JR VI15 + NOP NOP +RatioGreaterThanOne: + MULAx.w ACC, VF00, VF25 NOP + MADDAy.w ACC, VF00, VF25 NOP + MADDz.w VF16, VF00, VF25 NOP + ADD.xyz VF16, VF14, VF15 NOP ; return toerh line point + NOP JR VI15 + NOP NOP + + +; BE0 +.globl Vu0SphereToTriangleCollisionCompressedStart +Vu0SphereToTriangleCollisionCompressedStart: + ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 + ITOF0.xyzw VF14, VF14 NOP + ITOF0.xyzw VF15, VF15 NOP + ITOF0.xyzw VF16, VF16 NOP + MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 + MULi.w VF17, VF17, I NOP + MULi.xyzw VF14, VF14, I NOP + MULi.xyzw VF15, VF15, I NOP + MULi.xyzw VF16, VF16, I NOP +; fall through + +; C28 +; VF12: sphere +; VF14-16: verts +; VF17: plane +; out: +; VF01: intersection point +; VF02: triangle normal +; VF03 x: intersection parameter +.globl Vu0SphereToTriangleCollisionStart +Vu0SphereToTriangleCollisionStart: + MUL.xyz VF02, VF12, VF17 LOI 0.1 + ADD.xyz VF17, VF17, VF00 NOP + ADDw.x VF13, VF00, VF12 NOP + NOP NOP + MULAx.w ACC, VF00, VF02 IADDIU VI06, VI00, 0xE0 + MADDAy.w ACC, VF00, VF02 FMAND VI05, VI06 ; normal sign flags + MADDAz.w ACC, VF00, VF02 NOP + MSUB.w VF02, VF00, VF17 NOP ; center plane pos + MULi.w VF03, VF00, I MOVE.xyzw VF04, VF03 + NOP NOP + NOP NOP + CLIPw.xyz VF13, VF02 NOP ; compare dist and radius + CLIPw.xyz VF17, VF03 NOP + MULAw.xyz ACC, VF12, VF00 IADDIU VI07, VI00, 0x0 ; -- clear test case + MSUBw.xyz VF01, VF17, VF02 NOP + MULx.w VF01, VF00, VF00 FCAND VI01, 0x3 ; projected center on plane + ABS.w VF02, VF02 IBEQ VI00, VI01, QuitAndFail ; no intersection + NOP NOP + NOP FCAND VI01, 0x3 ; -- check x direction + SUB.xyz VF02, VF12, VF01 IADDIU VI02, VI01, 0x7F + NOP IADDIU VI06, VI00, 0x80 + SUB.xyz VF05, VF15, VF14 IAND VI02, VI02, VI06 + SUB.xyz VF08, VF01, VF14 FCAND VI01, 0xC ; -- check y direction + SUB.xyz VF06, VF16, VF15 IADDIU VI03, VI01, 0x3F + SUB.xyz VF09, VF01, VF15 IADDIU VI06, VI00, 0x40 + SUB.xyz VF07, VF14, VF16 IAND VI03, VI03, VI06 + SUB.xyz VF10, VF01, VF16 FCAND VI01, 0x30 ; -- check z direction + MUL.xyz VF03, VF02, VF02 IADDIU VI04, VI01, 0x1F + OPMULA.xyz ACC, VF08, VF05 IADDIU VI06, VI00, 0x20 + OPMSUB.xyz VF18, VF05, VF08 IAND VI04, VI04, VI06 + OPMULA.xyz ACC, VF09, VF06 NOP + OPMSUB.xyz VF19, VF06, VF09 IADD VI06, VI02, VI03 + OPMULA.xyz ACC, VF10, VF07 IADD VI06, VI06, VI04 ; -- combine flags + OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; -- cross 1 flags + MULAx.w ACC, VF00, VF03 IAND VI05, VI05, VI06 + MADDAy.w ACC, VF00, VF03 FMAND VI03, VI06 ; -- cross 2 flags + MADDz.w VF03, VF00, VF03 IADDIU VI08, VI00, 0x3 + NOP FMAND VI04, VI06 ; -- cross 3 flags + NOP NOP + NOP IBNE VI02, VI05, CheckSide2 + NOP RSQRT Q, VF00w, VF03w + ADD.xyz VF04, VF00, VF16 IADDIU VI07, VI07, 0x1 ; inside side 1 +CheckSide2: + NOP IBNE VI03, VI05, CheckSide3 + NOP NOP + ADD.xyz VF04, VF00, VF14 IADDIU VI07, VI07, 0x1 ; inside side 2 +CheckSide3: + NOP IBNE VI04, VI05, FinishCheckingSides + NOP NOP + ADD.xyz VF04, VF00, VF15 IADDIU VI07, VI07, 0x1 ; inside side 3 + NOP NOP + NOP IBEQ VI07, VI08, TotallyInsideTriangle + NOP NOP +FinishCheckingSides: + MUL.x VF13, VF13, VF13 IADDIU VI08, VI00, 0x2 + MULq.xyz VF02, VF02, Q WAITQ + NOP IBNE VI07, VI08, IntersectionOutsideTwoSides + NOP NOP + NOP IBEQ VI02, VI05, CheckDistanceSide2 + NOP NOP + NOP MOVE.xyzw VF15, VF05 + NOP BAL VI15, DistanceBetweenSphereAndLine + NOP NOP + NOP B ProcessLineResult + NOP NOP +CheckDistanceSide2: + NOP IBEQ VI03, VI05, CheckDistanceSide3 + NOP NOP + NOP MOVE.xyzw VF14, VF15 + NOP MOVE.xyzw VF15, VF06 + NOP BAL VI15, DistanceBetweenSphereAndLine + NOP NOP + NOP B ProcessLineResult + NOP NOP +CheckDistanceSide3: + NOP MOVE.xyzw VF14, VF16 + NOP MOVE.xyzw VF15, VF07 + NOP BAL VI15, DistanceBetweenSphereAndLine + NOP NOP + NOP B ProcessLineResult + NOP NOP +IntersectionOutsideTwoSides: + SUB.xyz VF05, VF04, VF12 NOP + ADD.xyz VF01, VF00, VF04 NOP ; col point + SUB.xyz VF02, VF12, VF04 NOP + NOP NOP + MUL.xyz VF05, VF05, VF05 NOP + NOP NOP + NOP NOP + NOP NOP + MULAx.w ACC, VF00, VF05 NOP + MADDAy.w ACC, VF00, VF05 NOP + MADDz.w VF05, VF00, VF05 NOP ; distSq to vertex + NOP NOP + NOP NOP + NOP NOP + CLIPw.xyz VF13, VF05 SQRT Q, VF05w ; compare radiusSq and distSq + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x1 + ADDq.x VF03, VF00, Q WAITQ ; dist to vertex + NOP IBEQ VI00, VI01, QuitAndFail ; too far + NOP NOP + NOP NOP + NOP DIV Q, VF00w, VF03x + MULq.xyz VF02, VF02, Q WAITQ ; col normal + NOP[E] NOP + NOP NOP +TotallyInsideTriangle: + ADDw.x VF03, VF00, VF02 WAITQ + MULq.xyz VF02, VF02, Q NOP + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP +ProcessLineResult: + CLIPw.xyz VF13, VF16 SQRT Q, VF16w + ADD.xyz VF01, VF00, VF16 NOP + SUB.xyz VF02, VF12, VF16 NOP + NOP NOP + NOP FCAND VI01, 0x1 + ADDq.x VF03, VF00, Q WAITQ + NOP IBEQ VI00, VI01, QuitAndFail + NOP NOP + NOP NOP + NOP DIV Q, VF00w, VF03x + MULq.xyz VF02, VF02, Q WAITQ + NOP[E] NOP + NOP NOP + +EndOfMicrocode: diff --git a/src/collision/vu0Collision_2.s b/src/collision/vu0Collision_2.s new file mode 100644 index 00000000..716c29ac --- /dev/null +++ b/src/collision/vu0Collision_2.s @@ -0,0 +1,191 @@ +QuitAndFail2: + NOP[E] IADDIU VI01, VI00, 0x0 + NOP NOP + + +QuitAndSucceed2: + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP + + +; 20 +GetBBVertices: + MULw.xy VF02, VF01, VF00 NOP + MUL.z VF02, VF01, VF11 NOP + MULw.xz VF03, VF01, VF00 NOP + MUL.y VF03, VF01, VF11 NOP + MULw.x VF04, VF01, VF00 NOP + MUL.yz VF04, VF01, VF11 NOP + NOP JR VI15 + NOP NOP + + +; 60 +Vu0OBBToOBBCollision: + SUBw.xyz VF11, VF00, VF00 LOI 0.5 + MULi.xyz VF12, VF12, I NOP + MULi.xyz VF13, VF13, I NOP + NOP NOP + NOP NOP + NOP MOVE.xyz VF01, VF12 + NOP BAL VI15, GetBBVertices + NOP NOP + MULAx.xyz ACC, VF14, VF01 NOP + MADDAy.xyz ACC, VF15, VF01 NOP + MADDz.xyz VF01, VF16, VF01 NOP + MULAx.xyz ACC, VF14, VF02 NOP + MADDAy.xyz ACC, VF15, VF02 NOP + MADDz.xyz VF02, VF16, VF02 NOP + MULAx.xyz ACC, VF14, VF03 NOP + MADDAy.xyz ACC, VF15, VF03 NOP + MADDz.xyz VF03, VF16, VF03 NOP + MULAx.xyz ACC, VF14, VF04 NOP + MADDAy.xyz ACC, VF15, VF04 NOP + MADDz.xyz VF04, VF16, VF04 NOP + ABS.xyz VF05, VF01 NOP + ABS.xyz VF06, VF02 NOP + ABS.xyz VF07, VF03 NOP + ABS.xyz VF08, VF04 NOP + NOP NOP + MAX.xyz VF05, VF05, VF06 NOP + NOP NOP + MAX.xyz VF07, VF07, VF08 NOP + NOP NOP + NOP NOP + NOP NOP + MAX.xyz VF05, VF05, VF07 NOP + NOP NOP + NOP NOP + NOP NOP + ADD.xyz VF09, VF05, VF13 NOP + NOP NOP + NOP NOP + NOP NOP + MULx.w VF05, VF00, VF09 NOP + MULy.w VF06, VF00, VF09 NOP + MULz.w VF07, VF00, VF09 NOP + CLIPw.xyz VF17, VF05 NOP + CLIPw.xyz VF17, VF06 NOP + CLIPw.xyz VF17, VF07 MOVE.xyz VF01, VF13 + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, QuitAndFail2 + NOP NOP + NOP BAL VI15, GetBBVertices + NOP NOP + MULAx.xyz ACC, VF18, VF01 NOP + MADDAy.xyz ACC, VF19, VF01 NOP + MADDz.xyz VF01, VF20, VF01 NOP + MULAx.xyz ACC, VF18, VF02 NOP + MADDAy.xyz ACC, VF19, VF02 NOP + MADDz.xyz VF02, VF20, VF02 NOP + MULAx.xyz ACC, VF18, VF03 NOP + MADDAy.xyz ACC, VF19, VF03 NOP + MADDz.xyz VF03, VF20, VF03 NOP + MULAx.xyz ACC, VF18, VF04 NOP + MADDAy.xyz ACC, VF19, VF04 NOP + MADDz.xyz VF04, VF20, VF04 NOP + ABS.xyz VF05, VF01 NOP + ABS.xyz VF06, VF02 NOP + ABS.xyz VF07, VF03 NOP + ABS.xyz VF08, VF04 NOP + NOP NOP + MAX.xyz VF05, VF05, VF06 NOP + NOP NOP + MAX.xyz VF07, VF07, VF08 NOP + NOP NOP + NOP NOP + NOP NOP + MAX.xyz VF05, VF05, VF07 NOP + NOP NOP + NOP NOP + NOP NOP + ADD.xyz VF09, VF05, VF12 NOP + NOP NOP + NOP NOP + NOP NOP + MULx.w VF05, VF00, VF09 NOP + MULy.w VF06, VF00, VF09 NOP + MULz.w VF07, VF00, VF09 NOP + CLIPw.xyz VF21, VF05 NOP + CLIPw.xyz VF21, VF06 NOP + CLIPw.xyz VF21, VF07 NOP + NOP NOP + NOP NOP + NOP NOP + NOP FCAND VI01, 0x3330 + NOP IBNE VI01, VI00, QuitAndFail2 + NOP NOP + SUB.xyz VF06, VF02, VF01 NOP + SUB.xyz VF07, VF03, VF01 NOP + ADD.xyz VF08, VF04, VF01 NOP + ADD.x VF09, VF00, VF12 NOP + ADD.yz VF09, VF00, VF00 NOP + ADD.y VF10, VF00, VF12 NOP + ADD.xz VF10, VF00, VF00 NOP + ADD.z VF11, VF00, VF12 IADDI VI04, VI00, 0x0 + ADD.xy VF11, VF00, VF00 IADD VI02, VI00, VI00 + OPMULA.xyz ACC, VF06, VF09 NOP + OPMSUB.xyz VF01, VF09, VF06 NOP + OPMULA.xyz ACC, VF06, VF10 NOP + OPMSUB.xyz VF02, VF10, VF06 NOP + OPMULA.xyz ACC, VF06, VF11 NOP + OPMSUB.xyz VF03, VF11, VF06 SQI.xyzw VF01, (VI02++) + OPMULA.xyz ACC, VF07, VF09 NOP + OPMSUB.xyz VF01, VF09, VF07 SQI.xyzw VF02, (VI02++) + OPMULA.xyz ACC, VF07, VF10 NOP + OPMSUB.xyz VF02, VF10, VF07 SQI.xyzw VF03, (VI02++) + OPMULA.xyz ACC, VF07, VF11 NOP + OPMSUB.xyz VF03, VF11, VF07 SQI.xyzw VF01, (VI02++) + OPMULA.xyz ACC, VF08, VF09 NOP + OPMSUB.xyz VF01, VF09, VF08 SQI.xyzw VF02, (VI02++) + OPMULA.xyz ACC, VF08, VF10 NOP + OPMSUB.xyz VF02, VF10, VF08 SQI.xyzw VF03, (VI02++) + OPMULA.xyz ACC, VF08, VF11 LOI 0.5 + OPMSUB.xyz VF01, VF11, VF08 SQI.xyzw VF01, (VI02++) + MULi.xyz VF06, VF06, I NOP + MULi.xyz VF07, VF07, I SQI.xyzw VF02, (VI02++) + MULi.xyz VF08, VF08, I NOP + MUL.xyz VF02, VF21, VF01 NOP + MUL.xyz VF03, VF12, VF01 NOP + MUL.xyz VF09, VF06, VF01 NOP + MUL.xyz VF10, VF07, VF01 NOP + MUL.xyz VF11, VF08, VF01 NOP + ABS.xyz VF03, VF03 NOP + ADDy.x VF05, VF09, VF09 NOP + ADDx.y VF05, VF10, VF10 NOP + ADDx.z VF05, VF11, VF11 NOP + NOP NOP +EdgePairLoop: + ADDz.x VF05, VF05, VF09 NOP + ADDz.y VF05, VF05, VF10 NOP + ADDy.z VF05, VF05, VF11 NOP + MULAx.w ACC, VF00, VF02 IADD VI03, VI02, VI00 + MADDAy.w ACC, VF00, VF02 LQD.xyzw VF01, (--VI02) + MADDz.w VF02, VF00, VF02 NOP + ABS.xyz VF05, VF05 NOP + MULAx.w ACC, VF00, VF03 NOP + MADDAy.w ACC, VF00, VF03 NOP + MADDAz.w ACC, VF00, VF03 NOP + MADDAx.w ACC, VF00, VF05 NOP + MADDAy.w ACC, VF00, VF05 NOP + MADDz.w VF03, VF00, VF05 NOP + ADDw.x VF04, VF00, VF02 NOP + MUL.xyz VF02, VF21, VF01 NOP + MUL.xyz VF03, VF12, VF01 NOP + MUL.xyz VF09, VF06, VF01 NOP + CLIPw.xyz VF04, VF03 NOP + MUL.xyz VF10, VF07, VF01 NOP + MUL.xyz VF11, VF08, VF01 NOP + ABS.xyz VF03, VF03 NOP + ADDy.x VF05, VF09, VF09 FCAND VI01, 0x3 + ADDx.y VF05, VF10, VF10 IBNE VI01, VI00, QuitAndFail2 + ADDx.z VF05, VF11, VF11 NOP + NOP IBNE VI03, VI00, EdgePairLoop + NOP NOP + NOP[E] IADDIU VI01, VI00, 0x1 + NOP NOP + +EndOfMicrocode2: diff --git a/src/core/Collision.cpp b/src/core/Collision.cpp deleted file mode 100644 index d8603cd8..00000000 --- a/src/core/Collision.cpp +++ /dev/null @@ -1,3290 +0,0 @@ -#include "common.h" - -#include "VuVector.h" -#include "main.h" -#include "Lists.h" -#include "Game.h" -#include "Zones.h" -#include "General.h" -#include "ZoneCull.h" -#include "World.h" -#include "Entity.h" -#include "Train.h" -#include "Streaming.h" -#include "Pad.h" -#include "DMAudio.h" -#include "Population.h" -#include "FileLoader.h" -#include "Replay.h" -#include "CutsceneMgr.h" -#include "RenderBuffer.h" -#include "SurfaceTable.h" -#include "Lines.h" -#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 -} - -inline int -GetVUresult(void) -{ -#ifdef GTA_PS2 - int ret; - __asm__ volatile ( - "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish - : "=r" (ret) - ); - return ret; -#else - return vi01; -#endif -} - -inline int -GetVUresult(CVuVector &point, CVuVector &normal, float &dist) -{ -#ifdef GTA_PS2 - int ret; - __asm__ volatile ( - "cfc2.i %0,vi01\n" // .i important! wait for VU0 to finish - "sqc2 vf01,(%1)\n" - "sqc2 vf02,(%2)\n" - "qmfc2 $12,vf03\n" - "sw $12,(%3)\n" - : "=r" (ret) - : "r" (&point), "r" (&normal), "r" (&dist) - : "$12" - ); - return ret; -#else - point = vf01; - normal = vf02; - dist = vf03.x; - return vi01; -#endif -} - -#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; - -void -CCollision::Init(void) -{ - ms_colModelCache.Init(NUMCOLCACHELINKS); - ms_collisionInMemory = LEVEL_GENERIC; -} - -void -CCollision::Shutdown(void) -{ - ms_colModelCache.Shutdown(); -} - -void -CCollision::Update(void) -{ - CVector playerCoors; - playerCoors = FindPlayerCoors(); - eLevelName level = CTheZones::m_CurrLevel; - bool forceLevelChange = false; - - if(CTimer::GetTimeInMilliseconds() < 2000 || CCutsceneMgr::IsCutsceneProcessing()) - return; - - // hardcode a level if there are no zones - if(level == LEVEL_GENERIC){ - if(CGame::currLevel == LEVEL_INDUSTRIAL && - playerCoors.x < 400.0f){ - level = LEVEL_COMMERCIAL; - forceLevelChange = true; - }else if(CGame::currLevel == LEVEL_SUBURBAN && - playerCoors.x > -450.0f && playerCoors.y < -1400.0f){ - level = LEVEL_COMMERCIAL; - forceLevelChange = true; - }else{ - if(playerCoors.x > 800.0f){ - level = LEVEL_INDUSTRIAL; - forceLevelChange = true; - }else if(playerCoors.x < -800.0f){ - level = LEVEL_SUBURBAN; - forceLevelChange = true; - } - } - } - if(level != LEVEL_GENERIC && level != CGame::currLevel) - CGame::currLevel = level; - if(ms_collisionInMemory != CGame::currLevel) - LoadCollisionWhenINeedIt(forceLevelChange); - CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); -} - -eLevelName -GetCollisionInSectorList(CPtrList &list) -{ - CPtrNode *node; - CEntity *e; - int level; - - for(node = list.first; node; node = node->next){ - e = (CEntity*)node->item; - level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level; - if(level != LEVEL_GENERIC) - return (eLevelName)level; - } - return LEVEL_GENERIC; -} - -// Get a level this sector is in based on collision models -eLevelName -GetCollisionInSector(CSector §) -{ - int level; - - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]); - if(level == LEVEL_GENERIC) - level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]); - return (eLevelName)level; -} - -void -CCollision::LoadCollisionWhenINeedIt(bool forceChange) -{ - eLevelName level, l; - bool multipleLevels; - CVector playerCoors; - CVehicle *veh; - CEntryInfoNode *ei; - int sx, sy; - int xmin, xmax, ymin, ymax; - int x, y; - - level = LEVEL_GENERIC; - - playerCoors = FindPlayerCoors(); - sx = CWorld::GetSectorIndexX(playerCoors.x); - sy = CWorld::GetSectorIndexY(playerCoors.y); - multipleLevels = false; - - veh = FindPlayerVehicle(); - if(veh && veh->IsTrain()){ - if(((CTrain*)veh)->m_nDoorState != TRAIN_DOOR_OPEN) - return; - }else if(playerCoors.z < -4.0f && !CCullZones::DoINeedToLoadCollision()) - return; - - // Figure out whose level's collisions we're most likely to be interested in - if(!forceChange){ - if(veh && veh->IsBoat()){ - // on water we expect to be between levels - multipleLevels = true; - }else{ - xmin = Max(sx - 1, 0); - xmax = Min(sx + 1, NUMSECTORS_X-1); - ymin = Max(sy - 1, 0); - ymax = Min(sy + 1, NUMSECTORS_Y-1); - - for(x = xmin; x <= xmax; x++) - for(y = ymin; y <= ymax; y++){ - l = GetCollisionInSector(*CWorld::GetSector(x, y)); - if(l != LEVEL_GENERIC){ - if(level == LEVEL_GENERIC) - level = l; - if(level != l) - multipleLevels = true; - } - } - } - - if(multipleLevels && veh && veh->IsBoat()) - for(ei = veh->m_entryInfoList.first; ei; ei = ei->next){ - level = GetCollisionInSector(*ei->sector); - if(level != LEVEL_GENERIC) - break; - } - } - - if (level == CGame::currLevel || forceChange) { -#ifdef FIX_BUGS - CTimer::Suspend(); -#else - CTimer::Stop(); -#endif - ISLAND_LOADING_IS(LOW) - { - DMAudio.SetEffectsFadeVol(0); - CPad::StopPadsShaking(); - LoadCollisionScreen(CGame::currLevel); - DMAudio.Service(); - } - - CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false); - - ISLAND_LOADING_ISNT(HIGH) - { - CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); - CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); - CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); - } - ISLAND_LOADING_IS(LOW) - { - CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); - CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); - CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); - CStreaming::RemoveUnusedModelsInLoadedList(); - CGame::TidyUpMemory(true, true); - CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); - } - - ms_collisionInMemory = CGame::currLevel; - CReplay::EmptyReplayBuffer(); - ISLAND_LOADING_IS(LOW) - { - if (CGame::currLevel != LEVEL_GENERIC) - LoadSplash(GetLevelSplashScreen(CGame::currLevel)); - CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); - CStreaming::RemoveUnusedBuildings(CGame::currLevel); - CStreaming::RequestBigBuildings(CGame::currLevel); - } -#ifdef NO_ISLAND_LOADING - else if (CMenuManager::m_PrefsIslandLoading == CMenuManager::ISLAND_LOADING_MEDIUM) - CStreaming::RequestIslands(CGame::currLevel); -#endif - CStreaming::LoadAllRequestedModels(true); - - ISLAND_LOADING_IS(LOW) - { - CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); - - CGame::TidyUpMemory(true, true); - } -#ifdef FIX_BUGS - CTimer::Resume(); -#else - CTimer::Update(); -#endif - ISLAND_LOADING_IS(LOW) - DMAudio.SetEffectsFadeVol(127); - } -} - -#ifdef NO_ISLAND_LOADING -bool CCollision::bAlreadyLoaded = false; -#endif -void -CCollision::SortOutCollisionAfterLoad(void) -{ - if(ms_collisionInMemory == CGame::currLevel) - return; - ISLAND_LOADING_IS(LOW) - CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); - - if (CGame::currLevel != LEVEL_GENERIC) { -#ifdef NO_ISLAND_LOADING - if (CMenuManager::m_PrefsIslandLoading != CMenuManager::ISLAND_LOADING_LOW) { - if (bAlreadyLoaded) { - ms_collisionInMemory = CGame::currLevel; - return; - } - bAlreadyLoaded = true; - CFileLoader::LoadCollisionFromDatFile(LEVEL_INDUSTRIAL); - CFileLoader::LoadCollisionFromDatFile(LEVEL_COMMERCIAL); - CFileLoader::LoadCollisionFromDatFile(LEVEL_SUBURBAN); - } else -#endif - CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); - if(!CGame::playingIntro) - LoadSplash(GetLevelSplashScreen(CGame::currLevel)); - } - ms_collisionInMemory = CGame::currLevel; - CGame::TidyUpMemory(true, false); -} - -void -CCollision::LoadCollisionScreen(eLevelName level) -{ - static Const char *levelNames[4] = { - "", - "IND_ZON", - "COM_ZON", - "SUB_ZON" - }; - - // Why twice? - LoadingIslandScreen(levelNames[level]); - LoadingIslandScreen(levelNames[level]); -} - -// -// Test -// - - -bool -CCollision::TestSphereSphere(const CColSphere &s1, const CColSphere &s2) -{ - float d = s1.radius + s2.radius; - return (s1.center - s2.center).MagnitudeSqr() < d*d; -} - -bool -CCollision::TestSphereBox(const CColSphere &sph, const CColBox &box) -{ - if(sph.center.x + sph.radius < box.min.x) return false; - if(sph.center.x - sph.radius > box.max.x) return false; - if(sph.center.y + sph.radius < box.min.y) return false; - if(sph.center.y - sph.radius > box.max.y) return false; - if(sph.center.z + sph.radius < box.min.z) return false; - if(sph.center.z - sph.radius > box.max.z) return false; - return true; -} - -bool -CCollision::TestLineBox(const CColLine &line, const CColBox &box) -{ - float t, x, y, z; - // If either line point is in the box, we have a collision - if(line.p0.x > box.min.x && line.p0.x < box.max.x && - line.p0.y > box.min.y && line.p0.y < box.max.y && - line.p0.z > box.min.z && line.p0.z < box.max.z) - return true; - if(line.p1.x > box.min.x && line.p1.x < box.max.x && - line.p1.y > box.min.y && line.p1.y < box.max.y && - line.p1.z > box.min.z && line.p1.z < box.max.z) - return true; - - // check if points are on opposite sides of min x plane - if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ - // parameter along line where we intersect - t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); - // y of intersection - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - // z of intersection - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // same test with max x plane - if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ - t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // min y plne - if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ - t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // max y plane - if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ - t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - return true; - } - } - - // min z plne - if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ - t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - return true; - } - } - - // max z plane - if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ - t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - return true; - } - } - return false; -} - -bool -CCollision::TestVerticalLineBox(const CColLine &line, const CColBox &box) -{ - if(line.p0.x <= box.min.x) return false; - if(line.p0.y <= box.min.y) return false; - if(line.p0.x >= box.max.x) return false; - if(line.p0.y >= box.max.y) return false; - if(line.p0.z < line.p1.z){ - if(line.p0.z > box.max.z) return false; - if(line.p1.z < box.min.z) return false; - }else{ - if(line.p1.z > box.max.z) return false; - if(line.p0.z < box.min.z) return false; - } - return true; -} - -bool -CCollision::TestLineTriangle(const CColLine &line, const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); - - if(GetVUresult()) - return true; - return false; -#else - float t; - CVector normal; - plane.GetNormal(normal); - - // if points are on the same side, no collision - if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); - // find point of intersection - CVector p = line.p0 + (line.p1-line.p0)*t; - - const CVector &va = verts[tri.a].Get(); - const CVector &vb = verts[tri.b].Get(); - const CVector &vc = verts[tri.c].Get(); - CVector2D vec1, vec2, vec3, vect; - - // We do the test in 2D. With the plane direction we - // can figure out how to project the vectors. - // normal = (c-a) x (b-a) - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - // This is our triangle: - // 3-------2 - // \ P / - // \ / - // \ / - // 1 - // We can use the "2d cross product" to check on which side - // a vector is of another. Test is true if point is inside of all edges. - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; - return true; -#endif -} - -// Test if line segment intersects with sphere. -// If the first point is inside the sphere this test does not register a collision! -// The code is reversed from the original code and rather ugly, see Process for a clear version. -// TODO: actually rewrite this mess -bool -CCollision::TestLineSphere(const CColLine &line, const CColSphere &sph) -{ - CVector v01 = line.p1 - line.p0; // vector from p0 to p1 - CVector v0c = sph.center - line.p0; // vector from p0 to center - float linesq = v01.MagnitudeSqr(); - // I leave in the strange -2 factors even though they serve no real purpose - float projline = -2.0f * DotProduct(v01, v0c); // project v0c onto line - // Square of tangent from p0 multiplied by line length so we can compare with projline. - // The length of the tangent would be this: Sqrt((c-p0)^2 - r^2). - // Negative if p0 is inside the sphere! This breaks the test! - float tansq = 4.0f * linesq * - (sph.center.MagnitudeSqr() - 2.0f*DotProduct(sph.center, line.p0) + line.p0.MagnitudeSqr() - sph.radius*sph.radius); - float diffsq = projline*projline - tansq; - // if diffsq < 0 that means the line is a passant, so no intersection - if(diffsq < 0.0f) - return false; - // projline (negative in GTA for some reason) is the point on the line - // in the middle of the two intersection points (startin from p0). - // Sqrt(diffsq) somehow works out to be the distance from that - // midpoint to the intersection points. - // So subtract that and get rid of the awkward scaling: - float f = (-projline - Sqrt(diffsq)) / (2.0f*linesq); - // f should now be in range [0, 1] for [p0, p1] - return f >= 0.0f && f <= 1.0f; -} - -bool -CCollision::TestSphereTriangle(const CColSphere &sphere, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); - - if(GetVUresult()) - return true; - return false; -#else - // If sphere and plane don't intersect, no collision - float planedist = plane.CalcPoint(sphere.center); - if(Abs(planedist) > sphere.radius) - return false; - - const CVector &va = verts[tri.a].Get(); - const CVector &vb = verts[tri.b].Get(); - const CVector &vc = verts[tri.c].Get(); - - // calculate two orthogonal basis vectors for the triangle - CVector vec2 = vb - va; - float len = vec2.Magnitude(); - vec2 = vec2 * (1.0f/len); - CVector normal; - plane.GetNormal(normal); - CVector vec1 = CrossProduct(vec2, normal); - - // We know A has local coordinate [0,0] and B has [0,len]. - // Now calculate coordinates on triangle for these two vectors: - CVector vac = vc - va; - CVector vas = sphere.center - va; - CVector2D b(0.0f, len); - CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); - CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); - - // The three triangle lines partition the space into 6 sectors, - // find out in which the center lies. - int insideAB = CrossProduct2D(s, b) >= 0.0f; - int insideAC = CrossProduct2D(c, s) >= 0.0f; - int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; - - int testcase = insideAB + insideAC + insideBC; - float dist = 0.0f; - switch(testcase){ - case 1: - // closest to a vertex - if(insideAB) dist = (sphere.center - vc).Magnitude(); - else if(insideAC) dist = (sphere.center - vb).Magnitude(); - else if(insideBC) dist = (sphere.center - va).Magnitude(); - else assert(0); - break; - case 2: - // closest to an edge - // looks like original game as DistToLine manually inlined - if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center); - else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center); - else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center); - else assert(0); - break; - case 3: - // center is in triangle - dist = Abs(planedist); - break; - default: - assert(0); - } - - return dist < sphere.radius; -#endif -} - -bool -CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough) -{ -#ifdef VU_COLLISION - CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CVuVector newline[2]; - TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) - return false; - - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - if(TestLineSphere(*(CColLine*)newline, model.spheres[i])) - return true; - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - if(TestLineBox(*(CColLine*)newline, model.boxes[i])) - return true; - } - - CalculateTrianglePlanes(&model); - int lastTest = -1; - VuTriangle vutri; - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lastTest = i; - break; - } -#ifdef FIX_BUGS - // no need to check first again - i++; -#endif - for(; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - if(GetVUresult()) - return true; - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lastTest = i; - - } - if(lastTest != -1 && GetVUresult()) - return true; - - return false; -#else - static CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CColLine newline(matTransform * line.p0, matTransform * line.p1); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(newline, model.boundingBox)) - return false; - - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - if(TestLineSphere(newline, model.spheres[i])) - return true; - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - if(TestLineBox(newline, model.boxes[i])) - return true; - } - - CalculateTrianglePlanes(&model); - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i])) - return true; - } - - return false; -#endif -} - - -// -// Process -// - -// For Spheres mindist is the squared distance to its center -// For Lines mindist is between [0,1] - -bool -CCollision::ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq) -{ - CVector dist = s1.center - s2.center; - float d = dist.Magnitude() - s2.radius; // distance from s1's center to s2 - float depth = s1.radius - d; // sphere overlap - if(d < 0.0f) d = 0.0f; // clamp to zero, i.e. if s1's center is inside s2 - // no collision if sphere is not close enough - if(d*d < mindistsq && d < s1.radius){ - dist.Normalise(); - point.point = s1.center - dist*d; - point.normal = dist; -#ifndef VU_COLLISION - point.surfaceA = s1.surface; - point.pieceA = s1.piece; - point.surfaceB = s2.surface; - point.pieceB = s2.piece; -#endif - point.depth = depth; - mindistsq = d*d; // collision radius - return true; - } - return false; -} - -bool -CCollision::ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq) -{ - CVector p; - CVector dist; - - // GTA's code is too complicated, uses a huge 3x3x3 if statement - // we can simplify the structure a lot - - // first make sure we have a collision at all - if(sph.center.x + sph.radius < box.min.x) return false; - if(sph.center.x - sph.radius > box.max.x) return false; - if(sph.center.y + sph.radius < box.min.y) return false; - if(sph.center.y - sph.radius > box.max.y) return false; - if(sph.center.z + sph.radius < box.min.z) return false; - if(sph.center.z - sph.radius > box.max.z) return false; - - // Now find out where the sphere center lies in relation to all the sides - int xpos = sph.center.x < box.min.x ? 1 : - sph.center.x > box.max.x ? 2 : - 0; - int ypos = sph.center.y < box.min.y ? 1 : - sph.center.y > box.max.y ? 2 : - 0; - int zpos = sph.center.z < box.min.z ? 1 : - sph.center.z > box.max.z ? 2 : - 0; - - if(xpos == 0 && ypos == 0 && zpos == 0){ - // sphere is inside the box - p = (box.min + box.max)*0.5f; - - dist = sph.center - p; - float lensq = dist.MagnitudeSqr(); - if(lensq < mindistsq){ - point.normal = dist * (1.0f/Sqrt(lensq)); - point.point = sph.center - point.normal; -#ifndef VU_COLLISION - point.surfaceA = sph.surface; - point.pieceA = sph.piece; - point.surfaceB = box.surface; - point.pieceB = box.piece; -#endif - - // find absolute distance to the closer side in each dimension - float dx = dist.x > 0.0f ? - box.max.x - sph.center.x : - sph.center.x - box.min.x; - float dy = dist.y > 0.0f ? - box.max.y - sph.center.y : - sph.center.y - box.min.y; - float dz = dist.z > 0.0f ? - box.max.z - sph.center.z : - sph.center.z - box.min.z; - // collision depth is maximum of that: - if(dx > dy && dx > dz) - point.depth = dx; - else if(dy > dz) - point.depth = dy; - else - point.depth = dz; - return true; - } - }else{ - // sphere is outside. - // closest point on box: - p.x = xpos == 1 ? box.min.x : - xpos == 2 ? box.max.x : - sph.center.x; - p.y = ypos == 1 ? box.min.y : - ypos == 2 ? box.max.y : - sph.center.y; - p.z = zpos == 1 ? box.min.z : - zpos == 2 ? box.max.z : - sph.center.z; - - dist = sph.center - p; - float lensq = dist.MagnitudeSqr(); - if(lensq < mindistsq){ - float len = Sqrt(lensq); - point.point = p; - point.normal = dist * (1.0f/len); -#ifndef VU_COLLISION - point.surfaceA = sph.surface; - point.pieceA = sph.piece; - point.surfaceB = box.surface; - point.pieceB = box.piece; -#endif - point.depth = sph.radius - len; - mindistsq = lensq; - return true; - } - } - return false; -} - -bool -CCollision::ProcessLineBox(const CColLine &line, const CColBox &box, CColPoint &point, float &mindist) -{ - float mint, t, x, y, z; - CVector normal; - CVector p; - - mint = 1.0f; - // check if points are on opposite sides of min x plane - if((box.min.x - line.p1.x) * (box.min.x - line.p0.x) < 0.0f){ - // parameter along line where we intersect - t = (box.min.x - line.p0.x) / (line.p1.x - line.p0.x); - // y of intersection - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - // z of intersection - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(box.min.x, y, z); - normal = CVector(-1.0f, 0.0f, 0.0f); - } - } - } - - // max x plane - if((line.p1.x - box.max.x) * (line.p0.x - box.max.x) < 0.0f){ - t = (line.p0.x - box.max.x) / (line.p0.x - line.p1.x); - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(box.max.x, y, z); - normal = CVector(1.0f, 0.0f, 0.0f); - } - } - } - - // min y plne - if((box.min.y - line.p0.y) * (box.min.y - line.p1.y) < 0.0f){ - t = (box.min.y - line.p0.y) / (line.p1.y - line.p0.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(x, box.min.y, z); - normal = CVector(0.0f, -1.0f, 0.0f); - } - } - } - - // max y plane - if((line.p0.y - box.max.y) * (line.p1.y - box.max.y) < 0.0f){ - t = (line.p0.y - box.max.y) / (line.p0.y - line.p1.y); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - z = line.p0.z + (line.p1.z - line.p0.z)*t; - if(z > box.min.z && z < box.max.z) - if(t < mint){ - mint = t; - p = CVector(x, box.max.y, z); - normal = CVector(0.0f, 1.0f, 0.0f); - } - } - } - - // min z plne - if((box.min.z - line.p0.z) * (box.min.z - line.p1.z) < 0.0f){ - t = (box.min.z - line.p0.z) / (line.p1.z - line.p0.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - if(t < mint){ - mint = t; - p = CVector(x, y, box.min.z); - normal = CVector(0.0f, 0.0f, -1.0f); - } - } - } - - // max z plane - if((line.p0.z - box.max.z) * (line.p1.z - box.max.z) < 0.0f){ - t = (line.p0.z - box.max.z) / (line.p0.z - line.p1.z); - x = line.p0.x + (line.p1.x - line.p0.x)*t; - if(x > box.min.x && x < box.max.x){ - y = line.p0.y + (line.p1.y - line.p0.y)*t; - if(y > box.min.y && y < box.max.y) - if(t < mint){ - mint = t; - p = CVector(x, y, box.max.z); - normal = CVector(0.0f, 0.0f, 1.0f); - } - } - } - - if(mint >= mindist) - return false; - - point.point = p; - point.normal = normal; -#ifndef VU_COLLISION - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = box.surface; - point.pieceB = box.piece; -#endif - mindist = mint; - - return true; -} - -// If line.p0 lies inside sphere, no collision is registered. -bool -CCollision::ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist) -{ - CVector v01 = line.p1 - line.p0; - CVector v0c = sphere.center - line.p0; - float linesq = v01.MagnitudeSqr(); - // project v0c onto v01, scaled by |v01| this is the midpoint of the two intersections - float projline = DotProduct(v01, v0c); - // tangent of p0 to sphere, scaled by linesq just like projline^2 - float tansq = (v0c.MagnitudeSqr() - sphere.radius*sphere.radius) * linesq; - // this works out to be the square of the distance between the midpoint and the intersections - float diffsq = projline*projline - tansq; - // no intersection - if(diffsq < 0.0f) - return false; - // point of first intersection, in range [0,1] between p0 and p1 - float t = (projline - Sqrt(diffsq)) / linesq; - // if not on line or beyond mindist, no intersection - if(t < 0.0f || t > 1.0f || t >= mindist) - return false; - point.point = line.p0 + v01*t; - point.normal = point.point - sphere.center; - point.normal.Normalise(); -#ifndef VU_COLLISION - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = sphere.surface; - point.pieceB = sphere.piece; -#endif - mindist = t; - return true; -} - -bool -CCollision::ProcessVerticalLineTriangle(const CColLine &line, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindist, CStoredCollPoly *poly) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - bool res = ProcessLineTriangle(line, verts, tri, plane, point, mindist); - if(res && poly){ - poly->verts[0] = verts[tri.a].Get(); - poly->verts[1] = verts[tri.b].Get(); - poly->verts[2] = verts[tri.c].Get(); - poly->valid = true; - } - return res; -#else - float t; - CVector normal; - - const CVector &p0 = line.p0; - const CVector &va = verts[tri.a].Get(); - const CVector &vb = verts[tri.b].Get(); - const CVector &vc = verts[tri.c].Get(); - - // early out bound rect test - if(p0.x < va.x && p0.x < vb.x && p0.x < vc.x) return false; - if(p0.x > va.x && p0.x > vb.x && p0.x > vc.x) return false; - if(p0.y < va.y && p0.y < vb.y && p0.y < vc.y) return false; - if(p0.y > va.y && p0.y > vb.y && p0.y > vc.y) return false; - - plane.GetNormal(normal); - // if points are on the same side, no collision - if(plane.CalcPoint(p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - float h = (line.p1 - p0).z; - t = -plane.CalcPoint(p0) / (h * normal.z); - // early out if we're beyond the mindist - if(t >= mindist) - return false; - CVector p(p0.x, p0.y, p0.z + h*t); - - CVector2D vec1, vec2, vec3, vect; - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; - if(t >= mindist) return false; - point.point = p; - point.normal = normal; - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = tri.surface; - point.pieceB = 0; - if(poly){ - poly->verts[0] = va; - poly->verts[1] = vb; - poly->verts[2] = vc; - poly->valid = true; - } - mindist = t; - return true; -#endif -} - -bool -CCollision::IsStoredPolyStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly) -{ -#ifdef VU_COLLISION - if(!poly->valid) - return false; - - CVuVector p0 = pos; - CVuVector p1 = pos; - p1.z = z; - - CVector v01 = poly->verts[1] - poly->verts[0]; - CVector v02 = poly->verts[2] - poly->verts[0]; - CVuVector plane = CrossProduct(v02, v01); - plane.Normalise(); - plane.w = DotProduct(plane, poly->verts[0]); - - LineToTriangleCollision(p0, p1, poly->verts[0], poly->verts[1], poly->verts[2], plane); - - CVuVector pnt; - float dist; - if(!GetVUresult(pnt, plane, dist)) -#ifdef FIX_BUGS - // perhaps not needed but be safe - return poly->valid = false; -#else - return false; -#endif - point.point = pnt; - return true; -#else - float t; - - if(!poly->valid) - return false; - - // maybe inlined? - CColTrianglePlane plane; - plane.Set(poly->verts[0], poly->verts[1], poly->verts[2]); - - const CVector &va = poly->verts[0]; - const CVector &vb = poly->verts[1]; - const CVector &vc = poly->verts[2]; - CVector p0 = pos; - CVector p1(pos.x, pos.y, z); - - // The rest is pretty much CCollision::ProcessLineTriangle - - // if points are on the same side, no collision - if(plane.CalcPoint(p0) * plane.CalcPoint(p1) > 0.0f) - return poly->valid = false; - - // intersection parameter on line - CVector normal; - plane.GetNormal(normal); - t = -plane.CalcPoint(p0) / DotProduct(p1 - p0, normal); - // find point of intersection - CVector p = p0 + (p1-p0)*t; - - CVector2D vec1, vec2, vec3, vect; - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return poly->valid = false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return poly->valid = false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return poly->valid = false; - point.point = p; - return poly->valid = true; -#endif -} - -bool -CCollision::ProcessLineTriangle(const CColLine &line, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindist) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(*(CVuVector*)&line.p0, *(CVuVector*)&line.p1, vutri); - - CVuVector pnt, normal; - float dist; - if(GetVUresult(pnt, normal, dist)){ - if(dist < mindist){ - point.point = pnt; - point.normal = normal; - mindist = dist; - return true; - } - } - return false; -#else - float t; - CVector normal; - plane.GetNormal(normal); - - // if points are on the same side, no collision - if(plane.CalcPoint(line.p0) * plane.CalcPoint(line.p1) > 0.0f) - return false; - - // intersection parameter on line - t = -plane.CalcPoint(line.p0) / DotProduct(line.p1 - line.p0, normal); - // early out if we're beyond the mindist - if(t >= mindist) - return false; - // find point of intersection - CVector p = line.p0 + (line.p1-line.p0)*t; - - const CVector &va = verts[tri.a].Get(); - const CVector &vb = verts[tri.b].Get(); - const CVector &vc = verts[tri.c].Get(); - CVector2D vec1, vec2, vec3, vect; - - switch(plane.dir){ - case DIR_X_POS: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vc.y; vec2.y = vc.z; - vec3.x = vb.y; vec3.y = vb.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_X_NEG: - vec1.x = va.y; vec1.y = va.z; - vec2.x = vb.y; vec2.y = vb.z; - vec3.x = vc.y; vec3.y = vc.z; - vect.x = p.y; vect.y = p.z; - break; - case DIR_Y_POS: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vc.z; vec2.y = vc.x; - vec3.x = vb.z; vec3.y = vb.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Y_NEG: - vec1.x = va.z; vec1.y = va.x; - vec2.x = vb.z; vec2.y = vb.x; - vec3.x = vc.z; vec3.y = vc.x; - vect.x = p.z; vect.y = p.x; - break; - case DIR_Z_POS: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vc.x; vec2.y = vc.y; - vec3.x = vb.x; vec3.y = vb.y; - vect.x = p.x; vect.y = p.y; - break; - case DIR_Z_NEG: - vec1.x = va.x; vec1.y = va.y; - vec2.x = vb.x; vec2.y = vb.y; - vec3.x = vc.x; vec3.y = vc.y; - vect.x = p.x; vect.y = p.y; - break; - default: - assert(0); - } - if(CrossProduct2D(vec2-vec1, vect-vec1) < 0.0f) return false; - if(CrossProduct2D(vec3-vec1, vect-vec1) > 0.0f) return false; - if(CrossProduct2D(vec3-vec2, vect-vec2) < 0.0f) return false; - if(t >= mindist) return false; - point.point = p; - point.normal = normal; - point.surfaceA = 0; - point.pieceA = 0; - point.surfaceB = tri.surface; - point.pieceB = 0; - mindist = t; - return true; -#endif -} - -bool -CCollision::ProcessSphereTriangle(const CColSphere &sphere, - const CompressedVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, - CColPoint &point, float &mindistsq) -{ -#ifdef VU_COLLISION - // not used in favour of optimized loops - VuTriangle vutri; - verts[tri.a].Unpack(vutri.v0); - verts[tri.b].Unpack(vutri.v1); - verts[tri.c].Unpack(vutri.v2); - plane.Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(*(CVuVector*)&sphere, vutri); - - CVuVector pnt, normal; - float dist; - if(GetVUresult(pnt, normal, dist) && dist*dist < mindistsq){ - float depth = sphere.radius - dist; - if(depth > point.depth){ - point.point = pnt; - point.normal = normal; - point.depth = depth; - mindistsq = dist*dist; - return true; - } - } - return false; -#else - // If sphere and plane don't intersect, no collision - float planedist = plane.CalcPoint(sphere.center); - float distsq = planedist*planedist; - if(Abs(planedist) > sphere.radius || distsq > mindistsq) - return false; - - const CVector &va = verts[tri.a].Get(); - const CVector &vb = verts[tri.b].Get(); - const CVector &vc = verts[tri.c].Get(); - - // calculate two orthogonal basis vectors for the triangle - CVector normal; - plane.GetNormal(normal); - CVector vec2 = vb - va; - float len = vec2.Magnitude(); - vec2 = vec2 * (1.0f/len); - CVector vec1 = CrossProduct(vec2, normal); - - // We know A has local coordinate [0,0] and B has [0,len]. - // Now calculate coordinates on triangle for these two vectors: - CVector vac = vc - va; - CVector vas = sphere.center - va; - CVector2D b(0.0f, len); - CVector2D c(DotProduct(vec1, vac), DotProduct(vec2, vac)); - CVector2D s(DotProduct(vec1, vas), DotProduct(vec2, vas)); - - // The three triangle lines partition the space into 6 sectors, - // find out in which the center lies. - int insideAB = CrossProduct2D(s, b) >= 0.0f; - int insideAC = CrossProduct2D(c, s) >= 0.0f; - int insideBC = CrossProduct2D(s-b, c-b) >= 0.0f; - - int testcase = insideAB + insideAC + insideBC; - float dist = 0.0f; - CVector p; - switch(testcase){ - case 1: - // closest to a vertex - if(insideAB) p = vc; - else if(insideAC) p = vb; - else if(insideBC) p = va; - else assert(0); - dist = (sphere.center - p).Magnitude(); - break; - case 2: - // closest to an edge - // looks like original game as DistToLine manually inlined - if(!insideAB) dist = DistToLine(&va, &vb, &sphere.center, p); - else if(!insideAC) dist = DistToLine(&va, &vc, &sphere.center, p); - else if(!insideBC) dist = DistToLine(&vb, &vc, &sphere.center, p); - else assert(0); - break; - case 3: - // center is in triangle - dist = Abs(planedist); - p = sphere.center - normal*planedist; - break; - default: - assert(0); - } - - if(dist >= sphere.radius || dist*dist >= mindistsq) - return false; - - point.point = p; - point.normal = sphere.center - p; - point.normal.Normalise(); -#ifndef VU_COLLISION - point.surfaceA = sphere.surface; - point.pieceA = sphere.piece; - point.surfaceB = tri.surface; - point.pieceB = 0; -#endif - point.depth = sphere.radius - dist; - mindistsq = dist*dist; - return true; -#endif -} - -bool -CCollision::ProcessLineOfSight(const CColLine &line, - const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough) -{ -#ifdef VU_COLLISION - CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CVuVector newline[2]; - TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); - - if(mindist < 1.0f) - newline[1] = newline[0] + (newline[1] - newline[0])*mindist; - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) - return false; - - float coldist = 1.0f; - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) - point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) - point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); - } - - CalculateTrianglePlanes(&model); - VuTriangle vutri; - CColTriangle *lasttri = nil; - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - break; - } -#ifdef FIX_BUGS - // no need to check first again - i++; -#endif - CVuVector pnt, normal; - float dist; - for(; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - if(GetVUresult(pnt, normal, dist)) - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - } - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - } - if(lasttri && GetVUresult(pnt, normal, dist)) - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - } - - - if(coldist < 1.0f){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - mindist *= coldist; - return true; - } - return false; -#else - static CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CColLine newline(matTransform * line.p0, matTransform * line.p1); - - // If we don't intersect with the bounding box, no chance on the rest - if(!TestLineBox(newline, model.boundingBox)) - return false; - - float coldist = mindist; - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - ProcessLineSphere(newline, model.spheres[i], point, coldist); - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - ProcessLineBox(newline, model.boxes[i], point, coldist); - } - - CalculateTrianglePlanes(&model); - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist); - } - - if(coldist < mindist){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - mindist = coldist; - return true; - } - return false; -#endif -} - -bool -CCollision::ProcessVerticalLine(const CColLine &line, - const CMatrix &matrix, CColModel &model, - CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly) -{ -#ifdef VU_COLLISION - static CStoredCollPoly TempStoredPoly; - CMatrix matTransform; - int i; - - // transform line to model space - Invert(matrix, matTransform); - CVuVector newline[2]; - TransformPoints(newline, 2, matTransform, (RwV3d*)&line.p0, sizeof(CColLine)/2); - - if(mindist < 1.0f) - newline[1] = newline[0] + (newline[1] - newline[0])*mindist; - - if(!TestLineBox(*(CColLine*)newline, model.boundingBox)) - return false; - - float coldist = 1.0f; - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - if(ProcessLineSphere(*(CColLine*)newline, model.spheres[i], point, coldist)) - point.Set(0, 0, model.spheres[i].surface, model.spheres[i].piece); - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - if(ProcessLineBox(*(CColLine*)newline, model.boxes[i], point, coldist)) - point.Set(0, 0, model.boxes[i].surface, model.boxes[i].piece); - } - - CalculateTrianglePlanes(&model); - TempStoredPoly.valid = false; - if(model.numTriangles){ - bool registeredCol; - CColTriangle *lasttri = nil; - VuTriangle vutri; - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - break; - } -#ifdef FIX_BUGS - // no need to check first again - i++; -#endif - CVuVector pnt, normal; - float dist; - for(; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - - CColTriangle *tri = &model.triangles[i]; - model.vertices[tri->a].Unpack(vutri.v0); - model.vertices[tri->b].Unpack(vutri.v1); - model.vertices[tri->c].Unpack(vutri.v2); - model.trianglePlanes[i].Unpack(vutri.plane); - - if(GetVUresult(pnt, normal, dist)){ - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol){ - TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); - TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); - TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); - TempStoredPoly.valid = true; - } - - LineToTriangleCollisionCompressed(newline[0], newline[1], vutri); - lasttri = tri; - } - if(lasttri && GetVUresult(pnt, normal, dist)){ - if(dist < coldist){ - point.point = pnt; - point.normal = normal; - point.Set(0, 0, lasttri->surface, 0); - coldist = dist; - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol){ - TempStoredPoly.verts[0] = model.vertices[lasttri->a].Get(); - TempStoredPoly.verts[1] = model.vertices[lasttri->b].Get(); - TempStoredPoly.verts[2] = model.vertices[lasttri->c].Get(); - TempStoredPoly.valid = true; - } - } - - if(coldist < 1.0f){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - if(TempStoredPoly.valid && poly){ - *poly = TempStoredPoly; - poly->verts[0] = matrix * CVector(poly->verts[0]); - poly->verts[1] = matrix * CVector(poly->verts[1]); - poly->verts[2] = matrix * CVector(poly->verts[2]); - } - mindist *= coldist; - return true; - } - return false; -#else - static CStoredCollPoly TempStoredPoly; - int i; - - // transform line to model space - // Why does the game seem to do this differently than above? - CColLine newline(MultiplyInverse(matrix, line.p0), MultiplyInverse(matrix, line.p1)); - newline.p1.x = newline.p0.x; - newline.p1.y = newline.p0.y; - - if(!TestVerticalLineBox(newline, model.boundingBox)) - return false; - - float coldist = mindist; - for(i = 0; i < model.numSpheres; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.spheres[i].surface)) continue; - ProcessLineSphere(newline, model.spheres[i], point, coldist); - } - - for(i = 0; i < model.numBoxes; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.boxes[i].surface)) continue; - ProcessLineBox(newline, model.boxes[i], point, coldist); - } - - CalculateTrianglePlanes(&model); - TempStoredPoly.valid = false; - for(i = 0; i < model.numTriangles; i++){ - if(ignoreSeeThrough && IsSeeThrough(model.triangles[i].surface)) continue; - ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly); - } - - if(coldist < mindist){ - point.point = matrix * point.point; - point.normal = Multiply3x3(matrix, point.normal); - if(TempStoredPoly.valid && poly){ - *poly = TempStoredPoly; - poly->verts[0] = matrix * poly->verts[0]; - poly->verts[1] = matrix * poly->verts[1]; - poly->verts[2] = matrix * poly->verts[2]; - } - mindist = coldist; - return true; - } - return false; -#endif -} - -enum { - MAXNUMSPHERES = 128, - MAXNUMBOXES = 32, - MAXNUMLINES = 16, - MAXNUMTRIS = 600 -}; - -#ifdef VU_COLLISION -#ifdef GTA_PS2 -#define SPR(off) ((uint8*)(0x70000000 + (off))) -#else -static uint8 fakeSPR[16*1024]; -#define SPR(off) ((uint8*)(fakeSPR + (off))) -#endif -#endif - -// This checks model A's spheres and lines against model B's spheres, boxes and triangles. -// Returns the number of A's spheres that collide. -// Returned ColPoints are in world space. -// NB: only vehicles can have col models with lines, exactly 4, one for each wheel -int32 -CCollision::ProcessColModels(const CMatrix &matrixA, CColModel &modelA, - const CMatrix &matrixB, CColModel &modelB, - CColPoint *spherepoints, CColPoint *linepoints, float *linedists) -{ -#ifdef VU_COLLISION - CVuVector *aSpheresA = (CVuVector*)SPR(0x0000); - CVuVector *aSpheresB = (CVuVector*)SPR(0x0800); - CVuVector *aLinesA = (CVuVector*)SPR(0x1000); - int32 *aSphereIndicesA = (int32*)SPR(0x1200); - int32 *aSphereIndicesB = (int32*)SPR(0x1400); - int32 *aBoxIndicesB = (int32*)SPR(0x1600); - int32 *aTriangleIndicesB = (int32*)SPR(0x1680); - bool *aCollided = (bool*)SPR(0x1FE0); - CMatrix &matAB = *(CMatrix*)SPR(0x1FF0); - CMatrix &matBA = *(CMatrix*)SPR(0x2040); - int i, j, k; - - // From model A space to model B space - Invert(matrixB, matAB); - matAB *= matrixA; - - CVuVector bsphereAB; // bounding sphere of A in B space - TransformPoint(bsphereAB, matAB, *(RwV3d*)modelA.boundingSphere.center); // inlined - bsphereAB.w = modelA.boundingSphere.radius; - if(!TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boundingBox)) - return 0; - - // transform modelA's spheres and lines to B space - TransformPoints(aSpheresA, modelA.numSpheres, matAB, (RwV3d*)&modelA.spheres->center, sizeof(CColSphere)); - for(i = 0; i < modelA.numSpheres; i++) - aSpheresA[i].w = modelA.spheres[i].radius; - TransformPoints(aLinesA, modelA.numLines*2, matAB, (RwV3d*)&modelA.lines->p0, sizeof(CColLine)/2); - - // Test them against model B's bounding volumes - int numSpheresA = 0; - for(i = 0; i < modelA.numSpheres; i++) - if(TestSphereBox(*(CColSphere*)&aSpheresA[i], modelB.boundingBox)) - aSphereIndicesA[numSpheresA++] = i; - // No collision - if(numSpheresA == 0 && modelA.numLines == 0) - return 0; - - - // B to A space - Invert(matrixA, matBA); - matBA *= matrixB; - - // transform modelB's spheres to A space - TransformPoints(aSpheresB, modelB.numSpheres, matBA, (RwV3d*)&modelB.spheres->center, sizeof(CColSphere)); - for(i = 0; i < modelB.numSpheres; i++) - aSpheresB[i].w = modelB.spheres[i].radius; - - // Check model B against A's bounding volumes - int numSpheresB = 0; - int numBoxesB = 0; - int numTrianglesB = 0; - for(i = 0; i < modelB.numSpheres; i++) - if(TestSphereBox(*(CColSphere*)&aSpheresB[i], modelA.boundingBox)) - aSphereIndicesB[numSpheresB++] = i; - for(i = 0; i < modelB.numBoxes; i++) - if(TestSphereBox(*(CColSphere*)&bsphereAB, modelB.boxes[i])) - aBoxIndicesB[numBoxesB++] = i; - CalculateTrianglePlanes(&modelB); - if(modelB.numTriangles){ - VuTriangle vutri; - // process the first triangle - CColTriangle *tri = &modelB.triangles[0]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[0].Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(bsphereAB, vutri); - - for(i = 1; i < modelB.numTriangles; i++){ - // set up the next triangle while VU0 is running - tri = &modelB.triangles[i]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[i].Unpack(vutri.plane); - - // check previous result - if(GetVUresult()) - aTriangleIndicesB[numTrianglesB++] = i-1; - - // kick off this one - SphereToTriangleCollisionCompressed(bsphereAB, vutri); - } - - // check last result - if(GetVUresult()) - aTriangleIndicesB[numTrianglesB++] = i-1; - } - // No collision - if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) - return 0; - - // We now have the collision volumes in A and B that are worth processing. - - // Process A's spheres against B's collision volumes - int numCollisions = 0; - spherepoints[numCollisions].depth = -1.0f; - for(i = 0; i < numSpheresA; i++){ - float coldist = 1.0e24f; - bool hasCollided = false; - CColSphere *sphA = &modelA.spheres[aSphereIndicesA[i]]; - CVuVector *vusphA = &aSpheresA[aSphereIndicesA[i]]; - - for(j = 0; j < numSpheresB; j++) - // This actually looks like something was inlined here - if(ProcessSphereSphere(*(CColSphere*)vusphA, modelB.spheres[aSphereIndicesB[j]], - spherepoints[numCollisions], coldist)){ - spherepoints[numCollisions].Set( - sphA->surface, sphA->piece, - modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); - hasCollided = true; - } - for(j = 0; j < numBoxesB; j++) - if(ProcessSphereBox(*(CColSphere*)vusphA, modelB.boxes[aBoxIndicesB[j]], - spherepoints[numCollisions], coldist)){ - spherepoints[numCollisions].Set( - sphA->surface, sphA->piece, - modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); - hasCollided = true; - } - if(numTrianglesB){ - CVuVector point, normal; - float depth; - bool registeredCol; - CColTriangle *lasttri; - - VuTriangle vutri; - // process the first triangle - k = aTriangleIndicesB[0]; - CColTriangle *tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - SphereToTriangleCollisionCompressed(*vusphA, vutri); - lasttri = tri; - - for(j = 1; j < numTrianglesB; j++){ - k = aTriangleIndicesB[j]; - // set up the next triangle while VU0 is running - tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - // check previous result - // TODO: this looks inlined but spherepoints[numCollisions] does not... - if(GetVUresult(point, normal, depth)){ - depth = sphA->radius - depth; - if(depth > spherepoints[numCollisions].depth){ - spherepoints[numCollisions].point = point; - spherepoints[numCollisions].normal = normal; - spherepoints[numCollisions].Set(depth, - sphA->surface, sphA->piece, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - hasCollided = true; - - // kick off this one - SphereToTriangleCollisionCompressed(*vusphA, vutri); - lasttri = tri; - } - - // check last result - // TODO: this looks inlined but spherepoints[numCollisions] does not... - if(GetVUresult(point, normal, depth)){ - depth = sphA->radius - depth; - if(depth > spherepoints[numCollisions].depth){ - spherepoints[numCollisions].point = point; - spherepoints[numCollisions].normal = normal; - spherepoints[numCollisions].Set(depth, - sphA->surface, sphA->piece, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - hasCollided = true; - } - - if(hasCollided){ - numCollisions++; - if(numCollisions == MAX_COLLISION_POINTS) - break; - spherepoints[numCollisions].depth = -1.0f; - } - } - for(i = 0; i < numCollisions; i++){ - // TODO: both VU0 macros - spherepoints[i].point = matrixB * spherepoints[i].point; - spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); - } - - // And the same thing for the lines in A - for(i = 0; i < modelA.numLines; i++){ - aCollided[i] = false; - CVuVector *lineA = &aLinesA[i*2]; - - for(j = 0; j < numSpheresB; j++) - if(ProcessLineSphere(*(CColLine*)lineA, modelB.spheres[aSphereIndicesB[j]], - linepoints[i], linedists[i])){ - linepoints[i].Set(0, 0, -#ifdef FIX_BUGS - modelB.spheres[aSphereIndicesB[j]].surface, modelB.spheres[aSphereIndicesB[j]].piece); -#else - modelB.spheres[j].surface, modelB.spheres[j].piece); -#endif - aCollided[i] = true; - } - for(j = 0; j < numBoxesB; j++) - if(ProcessLineBox(*(CColLine*)lineA, modelB.boxes[aBoxIndicesB[j]], - linepoints[i], linedists[i])){ - linepoints[i].Set(0, 0, - modelB.boxes[aBoxIndicesB[j]].surface, modelB.boxes[aBoxIndicesB[j]].piece); - aCollided[i] = true; - } - if(numTrianglesB){ - CVuVector point, normal; - float dist; - bool registeredCol; - CColTriangle *lasttri; - - VuTriangle vutri; - // process the first triangle - k = aTriangleIndicesB[0]; - CColTriangle *tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); - lasttri = tri; - - for(j = 1; j < numTrianglesB; j++){ - k = aTriangleIndicesB[j]; - // set up the next triangle while VU0 is running - CColTriangle *tri = &modelB.triangles[k]; - modelB.vertices[tri->a].Unpack(vutri.v0); - modelB.vertices[tri->b].Unpack(vutri.v1); - modelB.vertices[tri->c].Unpack(vutri.v2); - modelB.trianglePlanes[k].Unpack(vutri.plane); - - // check previous result - // TODO: this again somewhat looks inlined - if(GetVUresult(point, normal, dist)){ - if(dist < linedists[i]){ - linepoints[i].point = point; - linepoints[i].normal = normal; - linedists[i] = dist; - linepoints[i].Set(0, 0, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - aCollided[i] = true; - - // kick of this one - LineToTriangleCollisionCompressed(lineA[0], lineA[1], vutri); - lasttri = tri; - } - - // check last result - if(GetVUresult(point, normal, dist)){ - if(dist < linedists[i]){ - linepoints[i].point = point; - linepoints[i].normal = normal; - linedists[i] = dist; - linepoints[i].Set(0, 0, lasttri->surface, 0); - registeredCol = true; - }else - registeredCol = false; - }else - registeredCol = false; - - if(registeredCol) - aCollided[i] = true; - } - - if(aCollided[i]){ - // TODO: both VU0 macros - linepoints[i].point = matrixB * linepoints[i].point; - linepoints[i].normal = Multiply3x3(matrixB, linepoints[i].normal); - } - } - - return numCollisions; // sphere collisions -#else - static int aSphereIndicesA[MAXNUMSPHERES]; - static int aLineIndicesA[MAXNUMLINES]; - static int aSphereIndicesB[MAXNUMSPHERES]; - static int aBoxIndicesB[MAXNUMBOXES]; - static int aTriangleIndicesB[MAXNUMTRIS]; - static bool aCollided[MAXNUMLINES]; - static CColSphere aSpheresA[MAXNUMSPHERES]; - static CColLine aLinesA[MAXNUMLINES]; - static CMatrix matAB, matBA; - CColSphere s; - int i, j; - - assert(modelA.numSpheres <= MAXNUMSPHERES); - assert(modelA.numLines <= MAXNUMLINES); - - // From model A space to model B space - Invert(matrixB, matAB); - matAB *= matrixA; - - CColSphere bsphereAB; // bounding sphere of A in B space - bsphereAB.Set(modelA.boundingSphere.radius, matAB * modelA.boundingSphere.center); - if(!TestSphereBox(bsphereAB, modelB.boundingBox)) - return 0; - // B to A space - matBA = Invert(matrixA, matBA); - matBA *= matrixB; - - // transform modelA's spheres and lines to B space - for(i = 0; i < modelA.numSpheres; i++){ - CColSphere &s = modelA.spheres[i]; - aSpheresA[i].Set(s.radius, matAB * s.center, s.surface, s.piece); - } - for(i = 0; i < modelA.numLines; i++) - aLinesA[i].Set(matAB * modelA.lines[i].p0, matAB * modelA.lines[i].p1); - - // Test them against model B's bounding volumes - int numSpheresA = 0; - int numLinesA = 0; - for(i = 0; i < modelA.numSpheres; i++) - if(TestSphereBox(aSpheresA[i], modelB.boundingBox)) - aSphereIndicesA[numSpheresA++] = i; - // no actual check??? - for(i = 0; i < modelA.numLines; i++) - aLineIndicesA[numLinesA++] = i; - // No collision - if(numSpheresA == 0 && numLinesA == 0) - return 0; - - // Check model B against A's bounding volumes - int numSpheresB = 0; - int numBoxesB = 0; - int numTrianglesB = 0; - for(i = 0; i < modelB.numSpheres; i++){ - s.Set(modelB.spheres[i].radius, matBA * modelB.spheres[i].center); - if(TestSphereBox(s, modelA.boundingBox)) - aSphereIndicesB[numSpheresB++] = i; - } - for(i = 0; i < modelB.numBoxes; i++) - if(TestSphereBox(bsphereAB, modelB.boxes[i])) - aBoxIndicesB[numBoxesB++] = i; - CalculateTrianglePlanes(&modelB); - for(i = 0; i < modelB.numTriangles; i++) - if(TestSphereTriangle(bsphereAB, modelB.vertices, modelB.triangles[i], modelB.trianglePlanes[i])) - aTriangleIndicesB[numTrianglesB++] = i; - assert(numSpheresB <= MAXNUMSPHERES); - assert(numBoxesB <= MAXNUMBOXES); - assert(numTrianglesB <= MAXNUMTRIS); - // No collision - if(numSpheresB == 0 && numBoxesB == 0 && numTrianglesB == 0) - return 0; - - // We now have the collision volumes in A and B that are worth processing. - - // Process A's spheres against B's collision volumes - int numCollisions = 0; - for(i = 0; i < numSpheresA; i++){ - float coldist = 1.0e24f; - bool hasCollided = false; - - for(j = 0; j < numSpheresB; j++) - hasCollided |= ProcessSphereSphere( - aSpheresA[aSphereIndicesA[i]], - modelB.spheres[aSphereIndicesB[j]], - spherepoints[numCollisions], coldist); - for(j = 0; j < numBoxesB; j++) - hasCollided |= ProcessSphereBox( - aSpheresA[aSphereIndicesA[i]], - modelB.boxes[aBoxIndicesB[j]], - spherepoints[numCollisions], coldist); - for(j = 0; j < numTrianglesB; j++) - hasCollided |= ProcessSphereTriangle( - aSpheresA[aSphereIndicesA[i]], - modelB.vertices, - modelB.triangles[aTriangleIndicesB[j]], - modelB.trianglePlanes[aTriangleIndicesB[j]], - spherepoints[numCollisions], coldist); - - if(hasCollided) - numCollisions++; - } - for(i = 0; i < numCollisions; i++){ - spherepoints[i].point = matrixB * spherepoints[i].point; - spherepoints[i].normal = Multiply3x3(matrixB, spherepoints[i].normal); - } - - // And the same thing for the lines in A - for(i = 0; i < numLinesA; i++){ - aCollided[i] = false; - - for(j = 0; j < numSpheresB; j++) - aCollided[i] |= ProcessLineSphere( - aLinesA[aLineIndicesA[i]], - modelB.spheres[aSphereIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - for(j = 0; j < numBoxesB; j++) - aCollided[i] |= ProcessLineBox( - aLinesA[aLineIndicesA[i]], - modelB.boxes[aBoxIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - for(j = 0; j < numTrianglesB; j++) - aCollided[i] |= ProcessLineTriangle( - aLinesA[aLineIndicesA[i]], - modelB.vertices, - modelB.triangles[aTriangleIndicesB[j]], - modelB.trianglePlanes[aTriangleIndicesB[j]], - linepoints[aLineIndicesA[i]], - linedists[aLineIndicesA[i]]); - } - for(i = 0; i < numLinesA; i++) - if(aCollided[i]){ - j = aLineIndicesA[i]; - linepoints[j].point = matrixB * linepoints[j].point; - linepoints[j].normal = Multiply3x3(matrixB, linepoints[j].normal); - } - - return numCollisions; // sphere collisions -#endif -} - - -// -// Misc -// - -float -CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point) -{ - float lensq = (*l1 - *l0).MagnitudeSqr(); - float dot = DotProduct(*point - *l0, *l1 - *l0); - // Between 0 and len we're above the line. - // if not, calculate distance to endpoint - if(dot <= 0.0f) - return (*point - *l0).Magnitude(); - if(dot >= lensq) - return (*point - *l1).Magnitude(); - // distance to line - return Sqrt((*point - *l0).MagnitudeSqr() - dot*dot/lensq); -} - -// same as above but also return the point on the line -float -CCollision::DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest) -{ - float lensq = (*l1 - *l0).MagnitudeSqr(); - float dot = DotProduct(*point - *l0, *l1 - *l0); - // find out which point we're closest to - if(dot <= 0.0f) - closest = *l0; - else if(dot >= lensq) - closest = *l1; - else - closest = *l0 + (*l1 - *l0)*(dot/lensq); - // this is the distance - return (*point - closest).Magnitude(); -} - -void -CCollision::CalculateTrianglePlanes(CColModel *model) -{ - assert(model); - if(model->numTriangles == 0) - return; - - CLink *lptr; - if(model->trianglePlanes){ - // re-insert at front so it's not removed again soon - lptr = model->GetLinkPtr(); - lptr->Remove(); - ms_colModelCache.head.Insert(lptr); - }else{ - lptr = ms_colModelCache.Insert(model); - if(lptr == nil){ - // make room if we have to, remove last in list - lptr = ms_colModelCache.tail.prev; - assert(lptr); - assert(lptr->item); - lptr->item->RemoveTrianglePlanes(); - ms_colModelCache.Remove(lptr); - // now this cannot fail - lptr = ms_colModelCache.Insert(model); - assert(lptr); - } - model->CalculateTrianglePlanes(); - model->SetLinkPtr(lptr); - } -} - -void -CCollision::DrawColModel(const CMatrix &mat, const CColModel &colModel) -{ - int i; - CVector min, max; - CVector verts[8]; - CVector c; - float r; - - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); - - min = colModel.boundingBox.min; - max = colModel.boundingBox.max; - - verts[0] = mat * CVector(min.x, min.y, min.z); - verts[1] = mat * CVector(min.x, min.y, max.z); - verts[2] = mat * CVector(min.x, max.y, min.z); - verts[3] = mat * CVector(min.x, max.y, max.z); - verts[4] = mat * CVector(max.x, min.y, min.z); - verts[5] = mat * CVector(max.x, min.y, max.z); - verts[6] = mat * CVector(max.x, max.y, min.z); - verts[7] = mat * CVector(max.x, max.y, max.z); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[3].x, verts[3].y, verts[3].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[2].x, verts[2].y, verts[2].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[0].x, verts[0].y, verts[0].z, - 0xFF0000FF, 0xFF0000FF); - - CLines::RenderLineWithClipping( - verts[4].x, verts[4].y, verts[4].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[5].x, verts[5].y, verts[5].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[7].x, verts[7].y, verts[7].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[6].x, verts[6].y, verts[6].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFF0000FF, 0xFF0000FF); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFF0000FF, 0xFF0000FF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFF0000FF, 0xFF0000FF); - - for(i = 0; i < colModel.numSpheres; i++){ - c = mat * colModel.spheres[i].center; - r = colModel.spheres[i].radius; - - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x-r, c.y-r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x-r, c.y+r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x+r, c.y-r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x, c.y, c.z-r, - c.x+r, c.y+r, c.z, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x-r, c.y-r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x-r, c.y+r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x+r, c.y-r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - CLines::RenderLineWithClipping( - c.x+r, c.y+r, c.z, - c.x, c.y, c.z+r, - 0xFF00FFFF, 0xFF00FFFF); - } - - for(i = 0; i < colModel.numLines; i++){ - verts[0] = colModel.lines[i].p0; - verts[1] = colModel.lines[i].p1; - - verts[0] = mat * verts[0]; - verts[1] = mat * verts[1]; - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0x00FFFFFF, 0x00FFFFFF); - } - - for(i = 0; i < colModel.numBoxes; i++){ - min = colModel.boxes[i].min; - max = colModel.boxes[i].max; - - verts[0] = mat * CVector(min.x, min.y, min.z); - verts[1] = mat * CVector(min.x, min.y, max.z); - verts[2] = mat * CVector(min.x, max.y, min.z); - verts[3] = mat * CVector(min.x, max.y, max.z); - verts[4] = mat * CVector(max.x, min.y, min.z); - verts[5] = mat * CVector(max.x, min.y, max.z); - verts[6] = mat * CVector(max.x, max.y, min.z); - verts[7] = mat * CVector(max.x, max.y, max.z); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[3].x, verts[3].y, verts[3].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[2].x, verts[2].y, verts[2].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[0].x, verts[0].y, verts[0].z, - 0xFFFFFFFF, 0xFFFFFFFF); - - CLines::RenderLineWithClipping( - verts[4].x, verts[4].y, verts[4].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[5].x, verts[5].y, verts[5].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[7].x, verts[7].y, verts[7].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[6].x, verts[6].y, verts[6].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFFFFFFFF, 0xFFFFFFFF); - - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[4].x, verts[4].y, verts[4].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[5].x, verts[5].y, verts[5].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[2].x, verts[2].y, verts[2].z, - verts[6].x, verts[6].y, verts[6].z, - 0xFFFFFFFF, 0xFFFFFFFF); - CLines::RenderLineWithClipping( - verts[3].x, verts[3].y, verts[3].z, - verts[7].x, verts[7].y, verts[7].z, - 0xFFFFFFFF, 0xFFFFFFFF); - } - - for(i = 0; i < colModel.numTriangles; i++){ - colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); - colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); - colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); - verts[0] = mat * verts[0]; - verts[1] = mat * verts[1]; - verts[2] = mat * verts[2]; - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[1].x, verts[1].y, verts[1].z, - 0x00FF00FF, 0x00FF00FF); - CLines::RenderLineWithClipping( - verts[0].x, verts[0].y, verts[0].z, - verts[2].x, verts[2].y, verts[2].z, - 0x00FF00FF, 0x00FF00FF); - CLines::RenderLineWithClipping( - verts[1].x, verts[1].y, verts[1].z, - verts[2].x, verts[2].y, verts[2].z, - 0x00FF00FF, 0x00FF00FF); - } - - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); -} - -void -CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id) -{ - int i; - int s; - float f; - CVector verts[8]; - CVector min, max; - int r, g, b; - RwImVertexIndex *iptr; - RwIm3DVertex *vptr; - - RenderBuffer::ClearRenderBuffer(); - RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil); - - for(i = 0; i < colModel.numTriangles; i++){ - colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a); - colModel.GetTrianglePoint(verts[1], colModel.triangles[i].b); - colModel.GetTrianglePoint(verts[2], colModel.triangles[i].c); - verts[0] = mat * verts[0]; - verts[1] = mat * verts[1]; - verts[2] = mat * verts[2]; - - // game doesn't do this - r = 255; - g = 128; - b = 0; - - s = colModel.triangles[i].surface; - f = (s & 0xF)/32.0f + 0.5f; - switch(CSurfaceTable::GetAdhesionGroup(s)){ - case ADHESIVE_RUBBER: - r = f * 255.0f; - g = 0; - b = 0; - break; - case ADHESIVE_HARD: - r = f*255.0f; - g = f*255.0f; - b = f*128.0f; - break; - case ADHESIVE_ROAD: - r = f*128.0f; - g = f*128.0f; - b = f*128.0f; - break; - case ADHESIVE_LOOSE: - r = 0; - g = f * 255.0f; - b = 0; - break; - case ADHESIVE_WET: - r = 0; - g = 0; - b = f * 255.0f; - break; - default: - // this doesn't make much sense - r *= f; - g *= f; - b *= f; - } - - if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE || - s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE) - if(CTimer::GetFrameCounter() & 1){ - r = 0; - g = 0; - b = 0; - } - - if(s > SURFACE_METAL_GATE){ - r = CGeneral::GetRandomNumber(); - g = CGeneral::GetRandomNumber(); - b = CGeneral::GetRandomNumber(); - printf("Illegal surfacetype:%d on MI:%d\n", s, id); - } - - RenderBuffer::StartStoring(6, 3, &iptr, &vptr); - RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); - RwIm3DVertexSetU(&vptr[0], 0.0f); - RwIm3DVertexSetV(&vptr[0], 0.0f); - RwIm3DVertexSetU(&vptr[1], 0.0f); - RwIm3DVertexSetV(&vptr[1], 1.0f); - RwIm3DVertexSetU(&vptr[2], 1.0f); - RwIm3DVertexSetV(&vptr[2], 1.0f); - RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); - RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); - RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); - iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; - iptr[3] = 0; iptr[4] = 2; iptr[5] = 1; - RenderBuffer::StopStoring(); - } - - for(i = 0; i < colModel.numBoxes; i++){ - min = colModel.boxes[i].min; - max = colModel.boxes[i].max; - - verts[0] = mat * CVector(min.x, min.y, min.z); - verts[1] = mat * CVector(min.x, min.y, max.z); - verts[2] = mat * CVector(min.x, max.y, min.z); - verts[3] = mat * CVector(min.x, max.y, max.z); - verts[4] = mat * CVector(max.x, min.y, min.z); - verts[5] = mat * CVector(max.x, min.y, max.z); - verts[6] = mat * CVector(max.x, max.y, min.z); - verts[7] = mat * CVector(max.x, max.y, max.z); - - s = colModel.boxes[i].surface; - f = (s & 0xF)/32.0f + 0.5f; - switch(CSurfaceTable::GetAdhesionGroup(s)){ - case ADHESIVE_RUBBER: - r = f * 255.0f; - g = 0; - b = 0; - break; - case ADHESIVE_HARD: - r = f*255.0f; - g = f*255.0f; - b = f*128.0f; - break; - case ADHESIVE_ROAD: - r = f*128.0f; - g = f*128.0f; - b = f*128.0f; - break; - case ADHESIVE_LOOSE: - r = 0; - g = f * 255.0f; - b = 0; - break; - case ADHESIVE_WET: - r = 0; - g = 0; - b = f * 255.0f; - break; - default: - // this doesn't make much sense - r *= f; - g *= f; - b *= f; - } - - if(s == SURFACE_TRANSPARENT_CLOTH || s == SURFACE_METAL_CHAIN_FENCE || - s == SURFACE_TRANSPARENT_STONE || s == SURFACE_SCAFFOLD_POLE) - if(CTimer::GetFrameCounter() & 1){ - r = 0; - g = 0; - b = 0; - } - - RenderBuffer::StartStoring(36, 8, &iptr, &vptr); - RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[1], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[2], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[3], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[4], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[5], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[6], r, g, b, 255); - RwIm3DVertexSetRGBA(&vptr[7], r, g, b, 255); - RwIm3DVertexSetU(&vptr[0], 0.0f); - RwIm3DVertexSetV(&vptr[0], 0.0f); - RwIm3DVertexSetU(&vptr[1], 0.0f); - RwIm3DVertexSetV(&vptr[1], 1.0f); - RwIm3DVertexSetU(&vptr[2], 1.0f); - RwIm3DVertexSetV(&vptr[2], 1.0f); - RwIm3DVertexSetU(&vptr[3], 0.0f); - RwIm3DVertexSetV(&vptr[3], 0.0f); - RwIm3DVertexSetU(&vptr[4], 0.0f); - RwIm3DVertexSetV(&vptr[4], 1.0f); - RwIm3DVertexSetU(&vptr[5], 1.0f); - RwIm3DVertexSetV(&vptr[5], 1.0f); - RwIm3DVertexSetU(&vptr[6], 0.0f); - RwIm3DVertexSetV(&vptr[6], 1.0f); - RwIm3DVertexSetU(&vptr[7], 1.0f); - RwIm3DVertexSetV(&vptr[7], 1.0f); - RwIm3DVertexSetPos(&vptr[0], verts[0].x, verts[0].y, verts[0].z); - RwIm3DVertexSetPos(&vptr[1], verts[1].x, verts[1].y, verts[1].z); - RwIm3DVertexSetPos(&vptr[2], verts[2].x, verts[2].y, verts[2].z); - RwIm3DVertexSetPos(&vptr[3], verts[3].x, verts[3].y, verts[3].z); - RwIm3DVertexSetPos(&vptr[4], verts[4].x, verts[4].y, verts[4].z); - RwIm3DVertexSetPos(&vptr[5], verts[5].x, verts[5].y, verts[5].z); - RwIm3DVertexSetPos(&vptr[6], verts[6].x, verts[6].y, verts[6].z); - RwIm3DVertexSetPos(&vptr[7], verts[7].x, verts[7].y, verts[7].z); - iptr[0] = 0; iptr[1] = 1; iptr[2] = 2; - iptr[3] = 1; iptr[4] = 3; iptr[5] = 2; - iptr[6] = 1; iptr[7] = 5; iptr[8] = 7; - iptr[9] = 1; iptr[10] = 7; iptr[11] = 3; - iptr[12] = 2; iptr[13] = 3; iptr[14] = 7; - iptr[15] = 2; iptr[16] = 7; iptr[17] = 6; - iptr[18] = 0; iptr[19] = 5; iptr[20] = 1; - iptr[21] = 0; iptr[22] = 4; iptr[23] = 5; - iptr[24] = 0; iptr[25] = 2; iptr[26] = 4; - iptr[27] = 2; iptr[28] = 6; iptr[29] = 4; - iptr[30] = 4; iptr[31] = 6; iptr[32] = 7; - iptr[33] = 4; iptr[34] = 7; iptr[35] = 5; - RenderBuffer::StopStoring(); - } - - RenderBuffer::RenderStuffInBuffer(); - RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); - RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); - 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; -} 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/core/TempColModels.cpp b/src/core/TempColModels.cpp deleted file mode 100644 index f6796909..00000000 --- a/src/core/TempColModels.cpp +++ /dev/null @@ -1,297 +0,0 @@ -#include "common.h" - -#include "TempColModels.h" -#include "SurfaceTable.h" - -CColModel CTempColModels::ms_colModelPed1; -CColModel CTempColModels::ms_colModelPed2; -CColModel CTempColModels::ms_colModelBBox; -CColModel CTempColModels::ms_colModelBumper1; -CColModel CTempColModels::ms_colModelWheel1; -CColModel CTempColModels::ms_colModelPanel1; -CColModel CTempColModels::ms_colModelBodyPart2; -CColModel CTempColModels::ms_colModelBodyPart1; -CColModel CTempColModels::ms_colModelCutObj[5]; -CColModel CTempColModels::ms_colModelPedGroundHit; -CColModel CTempColModels::ms_colModelBoot1; -CColModel CTempColModels::ms_colModelDoor1; -CColModel CTempColModels::ms_colModelBonnet1; - - -CColSphere s_aPedSpheres[3]; -CColSphere s_aPed2Spheres[3]; -CColSphere s_aPedGSpheres[4]; -#ifdef FIX_BUGS -CColSphere s_aDoorSpheres[3]; -#else -CColSphere s_aDoorSpheres[4]; -#endif -CColSphere s_aBumperSpheres[4]; -CColSphere s_aPanelSpheres[4]; -CColSphere s_aBonnetSpheres[4]; -CColSphere s_aBootSpheres[4]; -CColSphere s_aWheelSpheres[2]; -CColSphere s_aBodyPartSpheres1[2]; -CColSphere s_aBodyPartSpheres2[2]; - -void -CTempColModels::Initialise(void) -{ -#define SET_COLMODEL_SPHERES(colmodel, sphrs)\ - colmodel.numSpheres = ARRAY_SIZE(sphrs);\ - colmodel.spheres = sphrs;\ - colmodel.level = LEVEL_GENERIC;\ - colmodel.ownsCollisionVolumes = false;\ - - 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.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].level = LEVEL_GENERIC; - } - - // Ped Spheres - - for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) - s_aPedSpheres[i].radius = 0.35f; - - s_aPedSpheres[0].center = CVector(0.0f, 0.0f, -0.25f); - s_aPedSpheres[1].center = CVector(0.0f, 0.0f, 0.15f); - s_aPedSpheres[2].center = CVector(0.0f, 0.0f, 0.55f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aPedSpheres); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aPedGSpheres); i++) { -#endif - s_aPedSpheres[i].surface = SURFACE_PED; - 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); - SET_COLMODEL_SPHERES(ms_colModelPed1, s_aPedSpheres); - - // Ped 2 Spheres - - s_aPed2Spheres[0].radius = 0.3f; - s_aPed2Spheres[1].radius = 0.4f; - s_aPed2Spheres[2].radius = 0.3f; - - s_aPed2Spheres[0].center = CVector(0.0f, 0.35f, -0.9f); - s_aPed2Spheres[1].center = CVector(0.0f, 0.0f, -0.9f); - s_aPed2Spheres[2].center = CVector(0.0f, -0.35f, -0.9f); - - for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { - s_aPed2Spheres[i].surface = SURFACE_PED; - 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); - - SET_COLMODEL_SPHERES(ms_colModelPed2, s_aPed2Spheres); - - // Ped ground collision - - s_aPedGSpheres[0].radius = 0.35f; - s_aPedGSpheres[1].radius = 0.35f; - s_aPedGSpheres[2].radius = 0.35f; - s_aPedGSpheres[3].radius = 0.3f; - - s_aPedGSpheres[0].center = CVector(0.0f, -0.4f, -0.9f); - s_aPedGSpheres[1].center = CVector(0.0f, -0.1f, -0.9f); - s_aPedGSpheres[2].center = CVector(0.0f, 0.25f, -0.9f); - s_aPedGSpheres[3].center = CVector(0.0f, 0.65f, -0.9f); - - s_aPedGSpheres[0].surface = SURFACE_PED; - s_aPedGSpheres[1].surface = SURFACE_PED; - s_aPedGSpheres[2].surface = SURFACE_PED; - s_aPedGSpheres[3].surface = SURFACE_PED; - s_aPedGSpheres[0].piece = 4; - s_aPedGSpheres[1].piece = 1; - 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); - - SET_COLMODEL_SPHERES(ms_colModelPedGroundHit, s_aPedGSpheres); - - // Door Spheres - - s_aDoorSpheres[0].radius = 0.15f; - s_aDoorSpheres[1].radius = 0.15f; - s_aDoorSpheres[2].radius = 0.25f; - - s_aDoorSpheres[0].center = CVector(0.0f, -0.25f, -0.35f); - s_aDoorSpheres[1].center = CVector(0.0f, -0.95f, -0.35f); - s_aDoorSpheres[2].center = CVector(0.0f, -0.6f, 0.25f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aDoorSpheres); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aPed2Spheres); i++) { -#endif - s_aDoorSpheres[i].surface = SURFACE_CAR_PANEL; - 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); - - SET_COLMODEL_SPHERES(ms_colModelDoor1, s_aDoorSpheres); - - // Bumper Spheres - - for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) - s_aBumperSpheres[i].radius = 0.15f; - - s_aBumperSpheres[0].center = CVector(0.85f, -0.05f, 0.0f); - s_aBumperSpheres[1].center = CVector(0.4f, 0.05f, 0.0f); - s_aBumperSpheres[2].center = CVector(-0.4f, 0.05f, 0.0f); - s_aBumperSpheres[3].center = CVector(-0.85f, -0.05f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aBumperSpheres); i++) { - s_aBumperSpheres[i].surface = SURFACE_CAR_PANEL; - 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); - - SET_COLMODEL_SPHERES(ms_colModelBumper1, s_aBumperSpheres); - - // Panel Spheres - - for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) - s_aPanelSpheres[i].radius = 0.15f; - - s_aPanelSpheres[0].center = CVector(0.15f, 0.45f, 0.0f); - s_aPanelSpheres[1].center = CVector(0.15f, -0.45f, 0.0f); - s_aPanelSpheres[2].center = CVector(-0.15f, -0.45f, 0.0f); - s_aPanelSpheres[3].center = CVector(-0.15f, 0.45f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aPanelSpheres); i++) { - s_aPanelSpheres[i].surface = SURFACE_CAR_PANEL; - 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); - - SET_COLMODEL_SPHERES(ms_colModelPanel1, s_aPanelSpheres); - - // Bonnet Spheres - - for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) - s_aBonnetSpheres[i].radius = 0.2f; - - s_aBonnetSpheres[0].center = CVector(-0.4f, 0.1f, 0.0f); - s_aBonnetSpheres[1].center = CVector(-0.4f, 0.9f, 0.0f); - s_aBonnetSpheres[2].center = CVector(0.4f, 0.1f, 0.0f); - s_aBonnetSpheres[3].center = CVector(0.4f, 0.9f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aBonnetSpheres); i++) { - s_aBonnetSpheres[i].surface = SURFACE_CAR_PANEL; - 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); - - SET_COLMODEL_SPHERES(ms_colModelBonnet1, s_aBonnetSpheres); - - // Boot Spheres - - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) - s_aBootSpheres[i].radius = 0.2f; - - s_aBootSpheres[0].center = CVector(-0.4f, -0.1f, 0.0f); - s_aBootSpheres[1].center = CVector(-0.4f, -0.6f, 0.0f); - s_aBootSpheres[2].center = CVector(0.4f, -0.1f, 0.0f); - s_aBootSpheres[3].center = CVector(0.4f, -0.6f, 0.0f); - - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { - s_aBootSpheres[i].surface = SURFACE_CAR_PANEL; - 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); - - SET_COLMODEL_SPHERES(ms_colModelBoot1, s_aBootSpheres); - - // Wheel Spheres - - s_aWheelSpheres[0].radius = 0.35f; - s_aWheelSpheres[1].radius = 0.35f; - - s_aWheelSpheres[0].center = CVector(-0.3f, 0.0f, 0.0f); - s_aWheelSpheres[1].center = CVector(0.3f, 0.0f, 0.0f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aWheelSpheres); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { -#endif - s_aWheelSpheres[i].surface = SURFACE_WHEELBASE; - 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); - - SET_COLMODEL_SPHERES(ms_colModelWheel1, s_aWheelSpheres); - - // Body Part Spheres 1 - - s_aBodyPartSpheres1[0].radius = 0.2f; - s_aBodyPartSpheres1[1].radius = 0.2f; - - s_aBodyPartSpheres1[0].center = CVector(0.0f, 0.0f, 0.0f); - s_aBodyPartSpheres1[1].center = CVector(0.8f, 0.0f, 0.0f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres1); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { -#endif - s_aBodyPartSpheres1[i].surface = SURFACE_PED; - 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); - - SET_COLMODEL_SPHERES(ms_colModelBodyPart1, s_aBodyPartSpheres1); - - // Body Part Spheres 2 - - s_aBodyPartSpheres2[0].radius = 0.15f; - s_aBodyPartSpheres2[1].radius = 0.15f; - - s_aBodyPartSpheres2[0].center = CVector(0.0f, 0.0f, 0.0f); - s_aBodyPartSpheres2[1].center = CVector(0.5f, 0.0f, 0.0f); - -#ifdef FIX_BUGS - for (i = 0; i < ARRAY_SIZE(s_aBodyPartSpheres2); i++) { -#else - for (i = 0; i < ARRAY_SIZE(s_aBootSpheres); i++) { -#endif - s_aBodyPartSpheres2[i].surface = SURFACE_PED; - 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); - - SET_COLMODEL_SPHERES(ms_colModelBodyPart2, s_aBodyPartSpheres2); - -#undef SET_COLMODEL_SPHERES -} diff --git a/src/core/TempColModels.h b/src/core/TempColModels.h deleted file mode 100644 index 3e1dd5e1..00000000 --- a/src/core/TempColModels.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "Collision.h" - -class CTempColModels -{ -public: - static CColModel ms_colModelPed1; - static CColModel ms_colModelPed2; - static CColModel ms_colModelBBox; - static CColModel ms_colModelBumper1; - static CColModel ms_colModelWheel1; - static CColModel ms_colModelPanel1; - static CColModel ms_colModelBodyPart2; - static CColModel ms_colModelBodyPart1; - static CColModel ms_colModelCutObj[5]; - static CColModel ms_colModelPedGroundHit; - static CColModel ms_colModelBoot1; - static CColModel ms_colModelDoor1; - static CColModel ms_colModelBonnet1; - - static void Initialise(void); -}; diff --git a/src/core/vu0Collision.dsm b/src/core/vu0Collision.dsm deleted file mode 100644 index 657c8b81..00000000 --- a/src/core/vu0Collision.dsm +++ /dev/null @@ -1,21 +0,0 @@ -.align 4 -.global Vu0CollisionDmaTag -Vu0CollisionDmaTag: -DMAcnt * -MPG 0, * -.vu -.include "vu0Collision_1.s" -.EndMPG -.EndDmaData -DMAend - -.global Vu0Collision2DmaTag -Vu0Collision2DmaTag: -DMAcnt * -MPG 0, * -.vu -.include "vu0Collision_2.s" -.EndMPG -.EndDmaData -DMAend -.end diff --git a/src/core/vu0Collision_1.s b/src/core/vu0Collision_1.s deleted file mode 100644 index 055c8640..00000000 --- a/src/core/vu0Collision_1.s +++ /dev/null @@ -1,610 +0,0 @@ -QuitAndFail: - NOP[E] IADDIU VI01, VI00, 0 - NOP NOP - - -QuitAndSucceed: - NOP[E] IADDIU VI01, VI00, 1 - NOP NOP - - -; 20 -- unused -; VF12, VF13 xyz: sphere centers -; VF14, VF15 x: sphere radii -; out: -; VI01: set when collision -; VF01: supposed to be intersection point? -; VF02: normal (pointing towards s1, not normalized) -.globl Vu0SphereToSphereCollision -Vu0SphereToSphereCollision: - SUB.xyz VF02, VF13, VF12 NOP ; dist of centers - ADD.x VF04, VF14, VF15 NOP ; s = sum of radii - MUL.xyzw VF03, VF02, VF02 NOP ; - MUL.x VF04, VF04, VF04 DIV Q, VF14x, VF04x ; square s - NOP NOP ; - NOP NOP ; - MULAx.w ACC, VF00, VF03 NOP ; - MADDAy.w ACC, VF00, VF03 NOP ; - MADDz.w VF03, VF00, VF03 NOP ; d = DistSq of centers - NOP NOP ; - MULAw.xyz ACC, VF12, VF00 NOP ; - MADDq.xyz VF01, VF02, Q NOP ; intersection, but wrong - CLIPw.xyz VF04, VF03 NOP ; compare s and d - SUB.xyz VF02, VF00, VF02 NOP ; compute normal - NOP NOP ; - NOP NOP ; - NOP FCAND VI01, 0x3 ; 0x2 cannot be set here - NOP[E] NOP ; - NOP NOP ; - - -; B8 -- unused -; VF12: -; VF13: radius -; VF14: -; VF15: box dimensions (?) -.globl Vu0SphereToAABBCollision -Vu0SphereToAABBCollision: - SUB.xyz VF03, VF12, VF14 LOI 0.5 - MULi.xyz VF15, VF15, I NOP - MUL.x VF13, VF13, VF13 NOP - SUB.xyz VF04, VF03, VF15 NOP - ADD.xyz VF05, VF03, VF15 MR32.xyzw VF16, VF15 - CLIPw.xyz VF03, VF16 MR32.xyzw VF17, VF16 - MUL.xyz VF04, VF04, VF04 NOP - MUL.xyz VF05, VF05, VF05 NOP - CLIPw.xyz VF03, VF17 MR32.xyzw VF16, VF17 - NOP FCAND VI01, 0x1 - MINI.xyz VF04, VF04, VF05 MFIR.x VF09, VI01 - NOP NOP - CLIPw.xyz VF03, VF16 FCAND VI01, 0x4 - NOP MFIR.y VF09, VI01 - NOP NOP - MULAx.w ACC, VF00, VF00 NOP - ADD.xyz VF01, VF00, VF03 FCAND VI01, 0x10 - NOP MFIR.z VF09, VI01 - NOP LOI 2 - NOP FCAND VI01, 0x30 - SUBAw.xyz ACC, VF00, VF00 IADD VI04, VI00, VI01 - ITOF0.xyz VF09, VF09 FCAND VI01, 0x300 - NOP IADD VI03, VI00, VI01 - NOP FCAND VI01, 0x3000 - NOP IADD VI02, VI00, VI01 - MADDi.xyzw VF09, VF09, I NOP - NOP IBEQ VI04, VI00, IgnoreZValue - NOP NOP - MADDAz.w ACC, VF00, VF04 NOP - MUL.z VF01, VF09, VF15 NOP -IgnoreZValue: - NOP IBEQ VI03, VI00, IgnoreYValue - NOP NOP - MADDAy.w ACC, VF00, VF04 NOP - MUL.y VF01, VF09, VF15 NOP -IgnoreYValue: - NOP IBEQ VI02, VI00, IgnoreXValue - NOP NOP - MADDAx.w ACC, VF00, VF04 NOP - MUL.x VF01, VF09, VF15 NOP -IgnoreXValue: - MADDx.w VF06, VF00, VF00 NOP - SUB.xyz VF02, VF03, VF01 NOP - ADD.xyz VF01, VF01, VF14 NOP - MULx.w VF01, VF00, VF00 NOP - CLIPw.xyz VF13, VF06 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x1 -QuitMicrocode: - NOP[E] NOP - NOP NOP - - -; 240 -.globl Vu0LineToSphereCollision -Vu0LineToSphereCollision: - SUB.xyzw VF01, VF13, VF12 NOP - SUB.xyzw VF02, VF14, VF12 NOP - MUL.xyz VF03, VF01, VF02 NOP - MUL.xyz VF04, VF01, VF01 NOP - MUL.x VF15, VF15, VF15 NOP - MUL.xyz VF02, VF02, VF02 NOP - MULAx.w ACC, VF00, VF03 NOP - MADDAy.w ACC, VF00, VF03 NOP - MADDz.w VF03, VF00, VF03 NOP - MULAx.w ACC, VF00, VF04 NOP - MADDAy.w ACC, VF00, VF04 NOP - MADDz.w VF01, VF00, VF04 NOP - MULAx.w ACC, VF00, VF02 NOP - MADDAy.w ACC, VF00, VF02 NOP - MADDz.w VF02, VF00, VF02 NOP - MULA.w ACC, VF03, VF03 NOP - MADDAx.w ACC, VF01, VF15 NOP - MSUB.w VF05, VF01, VF02 NOP - NOP NOP - NOP NOP - NOP IADDIU VI02, VI00, 0x10 - NOP FMAND VI01, VI02 - NOP IBNE VI01, VI00, QuitAndFail - NOP NOP - CLIPw.xyz VF15, VF02 SQRT Q, VF05w - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x1 - NOP IBNE VI00, VI01, LineStartInsideSphere - NOP NOP - SUBq.w VF05, VF03, Q NOP - SUB.w VF05, VF05, VF01 DIV Q, VF05w, VF01w - NOP FMAND VI01, VI02 - NOP IBNE VI01, VI00, QuitAndFail - NOP NOP - NOP FMAND VI01, VI02 - NOP IBEQ VI01, VI00, QuitAndFail - NOP NOP - ADDA.xyz ACC, VF12, VF00 NOP - MADDq.xyz VF01, VF01, Q NOP - MULx.w VF01, VF00, VF00 NOP - SUB.xyz VF02, VF01, VF14 NOP - NOP[E] NOP - NOP NOP -LineStartInsideSphere: - NOP MOVE.xyzw VF01, VF12 - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP - - -; 3C0 -.globl Vu0LineToAABBCollision -Vu0LineToAABBCollision: - SUB.xyzw VF08, VF13, VF12 LOI 0.5 - MULi.xyz VF15, VF15, I IADDIU VI08, VI00, 0x0 - SUB.xyzw VF12, VF12, VF14 NOP - SUB.xyzw VF13, VF13, VF14 NOP - NOP DIV Q, VF00w, VF08x - NOP MR32.xyzw VF03, VF15 - SUB.xyz VF06, VF15, VF12 NOP - ADD.xyz VF07, VF15, VF12 NOP - NOP NOP - CLIPw.xyz VF12, VF03 MR32.xyzw VF04, VF03 - NOP NOP - ADDq.x VF09, VF00, Q DIV Q, VF00w, VF08y - NOP NOP - CLIPw.xyz VF12, VF04 MR32.xyzw VF05, VF04 - SUB.xyz VF07, VF00, VF07 IADDIU VI06, VI00, 0xCC - NOP IADDIU VI07, VI00, 0x30 - NOP NOP - CLIPw.xyz VF12, VF05 FCGET VI02 - NOP IAND VI02, VI02, VI06 - ADDq.y VF09, VF00, Q DIV Q, VF00w, VF08z - SUB.xyz VF10, VF00, VF10 NOP - CLIPw.xyz VF13, VF03 FCGET VI03 - CLIPw.xyz VF13, VF04 IAND VI03, VI03, VI07 - CLIPw.xyz VF13, VF05 FCAND VI01, 0x3330 - NOP IBEQ VI01, VI00, StartPointInsideAABB - NOP NOP - ADDq.z VF09, VF00, Q FCGET VI04 - NOP FCGET VI05 - NOP IAND VI04, VI04, VI06 - NOP IAND VI05, VI05, VI07 - MULx.xyz VF17, VF08, VF09 NOP - MULy.xyz VF18, VF08, VF09 IADDIU VI07, VI00, 0x80 - MULz.xyz VF19, VF08, VF09 IAND VI06, VI02, VI07 - MUL.w VF10, VF00, VF00 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMaxXSide - NOP NOP - MULAx.xyz ACC, VF17, VF07 NOP - MADDw.xyz VF16, VF12, VF00 NOP - MUL.x VF10, VF07, VF09 NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF16, VF05 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x330 - NOP IBNE VI01, VI00, CheckMaxXSide - NOP NOP - MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - SUBw.x VF02, VF00, VF00 NOP -CheckMaxXSide: - MULAx.xyz ACC, VF17, VF06 IADDIU VI07, VI00, 0x40 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 - MUL.x VF10, VF06, VF09 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMinYSide - NOP NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF16, VF05 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0xCC03 - NOP IBNE VI01, VI00, CheckMinYSide - NOP NOP - MULx.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.yz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - ADDw.x VF02, VF00, VF00 NOP -CheckMinYSide: - MULAy.xyz ACC, VF18, VF07 IADDIU VI07, VI00, 0x8 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 - MUL.y VF10, VF07, VF09 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMaxYSide - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF05 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3C0C - NOP IBNE VI01, VI00, CheckMaxYSide - NOP NOP - MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - SUBw.y VF02, VF00, VF00 NOP -CheckMaxYSide: - MULAy.xyz ACC, VF18, VF06 IADDIU VI07, VI00, 0x4 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI02, VI07 - MUL.y VF10, VF06, VF09 IAND VI07, VI04, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMinZSide - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF05 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3C0C - NOP IBNE VI01, VI00, CheckMinZSide - NOP NOP - MULy.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xz VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - ADDw.y VF02, VF00, VF00 NOP -CheckMinZSide: - MULAz.xyz ACC, VF19, VF07 IADDIU VI07, VI00, 0x20 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 - MUL.z VF10, VF07, VF09 IAND VI07, VI05, VI07 - NOP NOP - NOP IBEQ VI06, VI07, CheckMaxZSide - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, CheckMaxZSide - NOP NOP - MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - SUBw.z VF02, VF00, VF00 NOP -CheckMaxZSide: - MULAz.xyz ACC, VF19, VF06 IADDIU VI07, VI00, 0x10 - MADDw.xyz VF16, VF12, VF00 IAND VI06, VI03, VI07 - MUL.z VF10, VF06, VF09 IAND VI07, VI05, VI07 - NOP NOP - NOP IBEQ VI06, VI07, DoneAllChecks - NOP NOP - CLIPw.xyz VF16, VF03 NOP - CLIPw.xyz VF16, VF04 NOP - CLIPw.xyz VF10, VF10 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, DoneAllChecks - NOP NOP - MULz.w VF10, VF00, VF10 IADDIU VI08, VI00, 0x1 - ADD.xy VF02, VF00, VF00 MOVE.xyzw VF01, VF16 - ADDw.z VF02, VF00, VF00 NOP -DoneAllChecks: - ADD.xyz VF01, VF01, VF14 IADD VI01, VI00, VI08 - NOP[E] NOP - NOP NOP -StartPointInsideAABB: - ADD.xyz VF01, VF12, VF14 WAITQ - NOP IADDIU VI01, VI00, 0x1 - NOP[E] NOP - NOP NOP - - -; 860 -.globl Vu0LineToTriangleCollisionCompressedStart -Vu0LineToTriangleCollisionCompressedStart: - ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 - ITOF0.xyzw VF14, VF14 NOP - ITOF0.xyzw VF15, VF15 NOP - ITOF0.xyzw VF16, VF16 NOP - MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 - MULi.w VF17, VF17, I NOP - MULi.xyzw VF14, VF14, I NOP - MULi.xyzw VF15, VF15, I NOP - MULi.xyzw VF16, VF16, I NOP -; fall through - -; 8A8 -; VF12: point0 -; VF13: point1 -; VF14-16: verts -; VF17: plane -; out: -; VF01: intersection point -; VF02: triangle normal -; VF03 x: intersection parameter -.globl Vu0LineToTriangleCollisionStart -Vu0LineToTriangleCollisionStart: - MUL.xyz VF10, VF17, VF12 LOI 0.5 - MUL.xyz VF11, VF17, VF13 NOP - SUB.xyz VF02, VF13, VF12 NOP ; line dist - ADD.xyz VF17, VF17, VF00 NOP - MULi.w VF03, VF00, I NOP - MULAx.w ACC, VF00, VF10 NOP - MADDAy.w ACC, VF00, VF10 IADDIU VI06, VI00, 0xE0 - MADDz.w VF10, VF00, VF10 FMAND VI05, VI06 ; -- normal sign flags, unused - MULAx.w ACC, VF00, VF11 NOP - MADDAy.w ACC, VF00, VF11 NOP - MADDz.w VF11, VF00, VF11 NOP - SUB.w VF09, VF17, VF10 NOP ; plane-pos 0 - CLIPw.xyz VF17, VF03 NOP ; compare normal against 0.5 to figure out which in which dimension to compare - NOP IADDIU VI02, VI00, 0x10 ; Sw flag - SUBA.w ACC, VF17, VF11 NOP ; plane-pos 1 - SUB.w VF08, VF11, VF10 FMAND VI01, VI02 - NOP NOP - NOP NOP - NOP FMAND VI02, VI02 - NOP IBEQ VI01, VI02, QuitAndFail ; if on same side, no collision - NOP NOP - NOP DIV Q, VF09w, VF08w ; parameter of intersection - NOP FCAND VI01, 0x3 ; check x direction - NOP IADDIU VI02, VI01, 0x7F - NOP IADDIU VI06, VI00, 0x80 - NOP IAND VI02, VI02, VI06 ; Sx flag - NOP FCAND VI01, 0xC ; check y direction - NOP IADDIU VI03, VI01, 0x3F - MULAw.xyz ACC, VF12, VF00 IADDIU VI06, VI00, 0x40 - MADDq.xyz VF01, VF02, Q IAND VI03, VI03, VI06 ; point of intersection -- Sy flag - MULx.w VF01, VF00, VF00 FCAND VI01, 0x30 ; -- check z direction - ADDq.x VF03, VF00, Q IADDIU VI04, VI01, 0x1F ; output parameter - SUB.xyz VF05, VF15, VF14 IADDIU VI06, VI00, 0x20 ; edge vectors - SUB.xyz VF08, VF01, VF14 IAND VI04, VI04, VI06 ; edge vectors -- Sz flag - SUB.xyz VF06, VF16, VF15 IADD VI06, VI02, VI03 ; edge vectors - SUB.xyz VF09, VF01, VF15 IADD VI06, VI06, VI04 ; edge vectors -- combine flags - SUB.xyz VF07, VF14, VF16 NOP ; edge vectors - SUB.xyz VF10, VF01, VF16 NOP ; edge vectors - OPMULA.xyz ACC, VF08, VF05 NOP - OPMSUB.xyz VF18, VF05, VF08 NOP ; cross1 - OPMULA.xyz ACC, VF09, VF06 NOP - OPMSUB.xyz VF19, VF06, VF09 NOP ; cross2 - OPMULA.xyz ACC, VF10, VF07 NOP - OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; cross3 - NOP NOP - NOP FMAND VI03, VI06 - NOP NOP - NOP FMAND VI04, VI06 - NOP NOP - NOP IBNE VI03, VI02, QuitAndFail ; point has to lie on the same side of all edges (i.e. inside) - NOP NOP - NOP IBNE VI04, VI02, QuitAndFail - NOP NOP - MULw.xyz VF02, VF17, VF00 IADDIU VI01, VI00, 0x1 ; success - NOP[E] NOP - NOP NOP - - -; A68 -; VF12: center -; VF14: line origin -; VF15: line vector to other point -; out: VF16 xyz: nearest point on line; w: distance to that point -DistanceBetweenSphereAndLine: - SUB.xyz VF20, VF12, VF14 NOP - MUL.xyz VF21, VF15, VF15 NOP - ADDA.xyz ACC, VF14, VF15 NOP - MSUBw.xyz VF25, VF12, VF00 NOP ; VF25 = VF12 - (VF14+VF15) - MUL.xyz VF22, VF20, VF20 NOP - MUL.xyz VF23, VF20, VF15 NOP - MULAx.w ACC, VF00, VF21 NOP - MADDAy.w ACC, VF00, VF21 NOP - MADDz.w VF21, VF00, VF21 NOP ; MagSq VF15 (line length) - MULAx.w ACC, VF00, VF23 NOP - MADDAy.w ACC, VF00, VF23 NOP - MADDz.w VF23, VF00, VF23 NOP ; dot(VF12-VF14, VF15) - MULAx.w ACC, VF00, VF22 NOP - MADDAy.w ACC, VF00, VF22 NOP - MADDz.w VF22, VF00, VF22 IADDIU VI08, VI00, 0x10 ; MagSq VF12-VF14 -- Sw bit - MUL.xyz VF25, VF25, VF25 FMAND VI08, VI08 - NOP DIV Q, VF23w, VF21w - NOP IBNE VI00, VI08, NegativeRatio - NOP NOP - ADDA.xyz ACC, VF00, VF14 NOP - MADDq.xyz VF16, VF15, Q WAITQ ; nearest point on infinte line - ADDq.x VF24, VF00, Q NOP ; ratio - NOP NOP - NOP NOP - SUB.xyz VF26, VF16, VF12 NOP - CLIPw.xyz VF24, VF00 NOP ; compare ratio to 1.0 - NOP NOP - NOP NOP - MUL.xyz VF26, VF26, VF26 NOP - NOP FCAND VI01, 0x1 - NOP IBNE VI00, VI01, RatioGreaterThanOne - NOP NOP - MULAx.w ACC, VF00, VF26 NOP - MADDAy.w ACC, VF00, VF26 NOP - MADDz.w VF16, VF00, VF26 NOP ; distance - NOP JR VI15 - NOP NOP -NegativeRatio: - ADD.xyz VF16, VF00, VF14 NOP ; return line origin - MUL.w VF16, VF00, VF22 NOP ; and DistSq to it - NOP JR VI15 - NOP NOP -RatioGreaterThanOne: - MULAx.w ACC, VF00, VF25 NOP - MADDAy.w ACC, VF00, VF25 NOP - MADDz.w VF16, VF00, VF25 NOP - ADD.xyz VF16, VF14, VF15 NOP ; return toerh line point - NOP JR VI15 - NOP NOP - - -; BE0 -.globl Vu0SphereToTriangleCollisionCompressedStart -Vu0SphereToTriangleCollisionCompressedStart: - ITOF0.xyzw VF17, VF17 LOI 0.000244140625 ; 1.0/4096.0 - ITOF0.xyzw VF14, VF14 NOP - ITOF0.xyzw VF15, VF15 NOP - ITOF0.xyzw VF16, VF16 NOP - MULi.xyz VF17, VF17, I LOI 0.0078125 ; 1.0/128.0 - MULi.w VF17, VF17, I NOP - MULi.xyzw VF14, VF14, I NOP - MULi.xyzw VF15, VF15, I NOP - MULi.xyzw VF16, VF16, I NOP -; fall through - -; C28 -; VF12: sphere -; VF14-16: verts -; VF17: plane -; out: -; VF01: intersection point -; VF02: triangle normal -; VF03 x: intersection parameter -.globl Vu0SphereToTriangleCollisionStart -Vu0SphereToTriangleCollisionStart: - MUL.xyz VF02, VF12, VF17 LOI 0.1 - ADD.xyz VF17, VF17, VF00 NOP - ADDw.x VF13, VF00, VF12 NOP - NOP NOP - MULAx.w ACC, VF00, VF02 IADDIU VI06, VI00, 0xE0 - MADDAy.w ACC, VF00, VF02 FMAND VI05, VI06 ; normal sign flags - MADDAz.w ACC, VF00, VF02 NOP - MSUB.w VF02, VF00, VF17 NOP ; center plane pos - MULi.w VF03, VF00, I MOVE.xyzw VF04, VF03 - NOP NOP - NOP NOP - CLIPw.xyz VF13, VF02 NOP ; compare dist and radius - CLIPw.xyz VF17, VF03 NOP - MULAw.xyz ACC, VF12, VF00 IADDIU VI07, VI00, 0x0 ; -- clear test case - MSUBw.xyz VF01, VF17, VF02 NOP - MULx.w VF01, VF00, VF00 FCAND VI01, 0x3 ; projected center on plane - ABS.w VF02, VF02 IBEQ VI00, VI01, QuitAndFail ; no intersection - NOP NOP - NOP FCAND VI01, 0x3 ; -- check x direction - SUB.xyz VF02, VF12, VF01 IADDIU VI02, VI01, 0x7F - NOP IADDIU VI06, VI00, 0x80 - SUB.xyz VF05, VF15, VF14 IAND VI02, VI02, VI06 - SUB.xyz VF08, VF01, VF14 FCAND VI01, 0xC ; -- check y direction - SUB.xyz VF06, VF16, VF15 IADDIU VI03, VI01, 0x3F - SUB.xyz VF09, VF01, VF15 IADDIU VI06, VI00, 0x40 - SUB.xyz VF07, VF14, VF16 IAND VI03, VI03, VI06 - SUB.xyz VF10, VF01, VF16 FCAND VI01, 0x30 ; -- check z direction - MUL.xyz VF03, VF02, VF02 IADDIU VI04, VI01, 0x1F - OPMULA.xyz ACC, VF08, VF05 IADDIU VI06, VI00, 0x20 - OPMSUB.xyz VF18, VF05, VF08 IAND VI04, VI04, VI06 - OPMULA.xyz ACC, VF09, VF06 NOP - OPMSUB.xyz VF19, VF06, VF09 IADD VI06, VI02, VI03 - OPMULA.xyz ACC, VF10, VF07 IADD VI06, VI06, VI04 ; -- combine flags - OPMSUB.xyz VF20, VF07, VF10 FMAND VI02, VI06 ; -- cross 1 flags - MULAx.w ACC, VF00, VF03 IAND VI05, VI05, VI06 - MADDAy.w ACC, VF00, VF03 FMAND VI03, VI06 ; -- cross 2 flags - MADDz.w VF03, VF00, VF03 IADDIU VI08, VI00, 0x3 - NOP FMAND VI04, VI06 ; -- cross 3 flags - NOP NOP - NOP IBNE VI02, VI05, CheckSide2 - NOP RSQRT Q, VF00w, VF03w - ADD.xyz VF04, VF00, VF16 IADDIU VI07, VI07, 0x1 ; inside side 1 -CheckSide2: - NOP IBNE VI03, VI05, CheckSide3 - NOP NOP - ADD.xyz VF04, VF00, VF14 IADDIU VI07, VI07, 0x1 ; inside side 2 -CheckSide3: - NOP IBNE VI04, VI05, FinishCheckingSides - NOP NOP - ADD.xyz VF04, VF00, VF15 IADDIU VI07, VI07, 0x1 ; inside side 3 - NOP NOP - NOP IBEQ VI07, VI08, TotallyInsideTriangle - NOP NOP -FinishCheckingSides: - MUL.x VF13, VF13, VF13 IADDIU VI08, VI00, 0x2 - MULq.xyz VF02, VF02, Q WAITQ - NOP IBNE VI07, VI08, IntersectionOutsideTwoSides - NOP NOP - NOP IBEQ VI02, VI05, CheckDistanceSide2 - NOP NOP - NOP MOVE.xyzw VF15, VF05 - NOP BAL VI15, DistanceBetweenSphereAndLine - NOP NOP - NOP B ProcessLineResult - NOP NOP -CheckDistanceSide2: - NOP IBEQ VI03, VI05, CheckDistanceSide3 - NOP NOP - NOP MOVE.xyzw VF14, VF15 - NOP MOVE.xyzw VF15, VF06 - NOP BAL VI15, DistanceBetweenSphereAndLine - NOP NOP - NOP B ProcessLineResult - NOP NOP -CheckDistanceSide3: - NOP MOVE.xyzw VF14, VF16 - NOP MOVE.xyzw VF15, VF07 - NOP BAL VI15, DistanceBetweenSphereAndLine - NOP NOP - NOP B ProcessLineResult - NOP NOP -IntersectionOutsideTwoSides: - SUB.xyz VF05, VF04, VF12 NOP - ADD.xyz VF01, VF00, VF04 NOP ; col point - SUB.xyz VF02, VF12, VF04 NOP - NOP NOP - MUL.xyz VF05, VF05, VF05 NOP - NOP NOP - NOP NOP - NOP NOP - MULAx.w ACC, VF00, VF05 NOP - MADDAy.w ACC, VF00, VF05 NOP - MADDz.w VF05, VF00, VF05 NOP ; distSq to vertex - NOP NOP - NOP NOP - NOP NOP - CLIPw.xyz VF13, VF05 SQRT Q, VF05w ; compare radiusSq and distSq - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x1 - ADDq.x VF03, VF00, Q WAITQ ; dist to vertex - NOP IBEQ VI00, VI01, QuitAndFail ; too far - NOP NOP - NOP NOP - NOP DIV Q, VF00w, VF03x - MULq.xyz VF02, VF02, Q WAITQ ; col normal - NOP[E] NOP - NOP NOP -TotallyInsideTriangle: - ADDw.x VF03, VF00, VF02 WAITQ - MULq.xyz VF02, VF02, Q NOP - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP -ProcessLineResult: - CLIPw.xyz VF13, VF16 SQRT Q, VF16w - ADD.xyz VF01, VF00, VF16 NOP - SUB.xyz VF02, VF12, VF16 NOP - NOP NOP - NOP FCAND VI01, 0x1 - ADDq.x VF03, VF00, Q WAITQ - NOP IBEQ VI00, VI01, QuitAndFail - NOP NOP - NOP NOP - NOP DIV Q, VF00w, VF03x - MULq.xyz VF02, VF02, Q WAITQ - NOP[E] NOP - NOP NOP - -EndOfMicrocode: diff --git a/src/core/vu0Collision_2.s b/src/core/vu0Collision_2.s deleted file mode 100644 index 716c29ac..00000000 --- a/src/core/vu0Collision_2.s +++ /dev/null @@ -1,191 +0,0 @@ -QuitAndFail2: - NOP[E] IADDIU VI01, VI00, 0x0 - NOP NOP - - -QuitAndSucceed2: - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP - - -; 20 -GetBBVertices: - MULw.xy VF02, VF01, VF00 NOP - MUL.z VF02, VF01, VF11 NOP - MULw.xz VF03, VF01, VF00 NOP - MUL.y VF03, VF01, VF11 NOP - MULw.x VF04, VF01, VF00 NOP - MUL.yz VF04, VF01, VF11 NOP - NOP JR VI15 - NOP NOP - - -; 60 -Vu0OBBToOBBCollision: - SUBw.xyz VF11, VF00, VF00 LOI 0.5 - MULi.xyz VF12, VF12, I NOP - MULi.xyz VF13, VF13, I NOP - NOP NOP - NOP NOP - NOP MOVE.xyz VF01, VF12 - NOP BAL VI15, GetBBVertices - NOP NOP - MULAx.xyz ACC, VF14, VF01 NOP - MADDAy.xyz ACC, VF15, VF01 NOP - MADDz.xyz VF01, VF16, VF01 NOP - MULAx.xyz ACC, VF14, VF02 NOP - MADDAy.xyz ACC, VF15, VF02 NOP - MADDz.xyz VF02, VF16, VF02 NOP - MULAx.xyz ACC, VF14, VF03 NOP - MADDAy.xyz ACC, VF15, VF03 NOP - MADDz.xyz VF03, VF16, VF03 NOP - MULAx.xyz ACC, VF14, VF04 NOP - MADDAy.xyz ACC, VF15, VF04 NOP - MADDz.xyz VF04, VF16, VF04 NOP - ABS.xyz VF05, VF01 NOP - ABS.xyz VF06, VF02 NOP - ABS.xyz VF07, VF03 NOP - ABS.xyz VF08, VF04 NOP - NOP NOP - MAX.xyz VF05, VF05, VF06 NOP - NOP NOP - MAX.xyz VF07, VF07, VF08 NOP - NOP NOP - NOP NOP - NOP NOP - MAX.xyz VF05, VF05, VF07 NOP - NOP NOP - NOP NOP - NOP NOP - ADD.xyz VF09, VF05, VF13 NOP - NOP NOP - NOP NOP - NOP NOP - MULx.w VF05, VF00, VF09 NOP - MULy.w VF06, VF00, VF09 NOP - MULz.w VF07, VF00, VF09 NOP - CLIPw.xyz VF17, VF05 NOP - CLIPw.xyz VF17, VF06 NOP - CLIPw.xyz VF17, VF07 MOVE.xyz VF01, VF13 - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, QuitAndFail2 - NOP NOP - NOP BAL VI15, GetBBVertices - NOP NOP - MULAx.xyz ACC, VF18, VF01 NOP - MADDAy.xyz ACC, VF19, VF01 NOP - MADDz.xyz VF01, VF20, VF01 NOP - MULAx.xyz ACC, VF18, VF02 NOP - MADDAy.xyz ACC, VF19, VF02 NOP - MADDz.xyz VF02, VF20, VF02 NOP - MULAx.xyz ACC, VF18, VF03 NOP - MADDAy.xyz ACC, VF19, VF03 NOP - MADDz.xyz VF03, VF20, VF03 NOP - MULAx.xyz ACC, VF18, VF04 NOP - MADDAy.xyz ACC, VF19, VF04 NOP - MADDz.xyz VF04, VF20, VF04 NOP - ABS.xyz VF05, VF01 NOP - ABS.xyz VF06, VF02 NOP - ABS.xyz VF07, VF03 NOP - ABS.xyz VF08, VF04 NOP - NOP NOP - MAX.xyz VF05, VF05, VF06 NOP - NOP NOP - MAX.xyz VF07, VF07, VF08 NOP - NOP NOP - NOP NOP - NOP NOP - MAX.xyz VF05, VF05, VF07 NOP - NOP NOP - NOP NOP - NOP NOP - ADD.xyz VF09, VF05, VF12 NOP - NOP NOP - NOP NOP - NOP NOP - MULx.w VF05, VF00, VF09 NOP - MULy.w VF06, VF00, VF09 NOP - MULz.w VF07, VF00, VF09 NOP - CLIPw.xyz VF21, VF05 NOP - CLIPw.xyz VF21, VF06 NOP - CLIPw.xyz VF21, VF07 NOP - NOP NOP - NOP NOP - NOP NOP - NOP FCAND VI01, 0x3330 - NOP IBNE VI01, VI00, QuitAndFail2 - NOP NOP - SUB.xyz VF06, VF02, VF01 NOP - SUB.xyz VF07, VF03, VF01 NOP - ADD.xyz VF08, VF04, VF01 NOP - ADD.x VF09, VF00, VF12 NOP - ADD.yz VF09, VF00, VF00 NOP - ADD.y VF10, VF00, VF12 NOP - ADD.xz VF10, VF00, VF00 NOP - ADD.z VF11, VF00, VF12 IADDI VI04, VI00, 0x0 - ADD.xy VF11, VF00, VF00 IADD VI02, VI00, VI00 - OPMULA.xyz ACC, VF06, VF09 NOP - OPMSUB.xyz VF01, VF09, VF06 NOP - OPMULA.xyz ACC, VF06, VF10 NOP - OPMSUB.xyz VF02, VF10, VF06 NOP - OPMULA.xyz ACC, VF06, VF11 NOP - OPMSUB.xyz VF03, VF11, VF06 SQI.xyzw VF01, (VI02++) - OPMULA.xyz ACC, VF07, VF09 NOP - OPMSUB.xyz VF01, VF09, VF07 SQI.xyzw VF02, (VI02++) - OPMULA.xyz ACC, VF07, VF10 NOP - OPMSUB.xyz VF02, VF10, VF07 SQI.xyzw VF03, (VI02++) - OPMULA.xyz ACC, VF07, VF11 NOP - OPMSUB.xyz VF03, VF11, VF07 SQI.xyzw VF01, (VI02++) - OPMULA.xyz ACC, VF08, VF09 NOP - OPMSUB.xyz VF01, VF09, VF08 SQI.xyzw VF02, (VI02++) - OPMULA.xyz ACC, VF08, VF10 NOP - OPMSUB.xyz VF02, VF10, VF08 SQI.xyzw VF03, (VI02++) - OPMULA.xyz ACC, VF08, VF11 LOI 0.5 - OPMSUB.xyz VF01, VF11, VF08 SQI.xyzw VF01, (VI02++) - MULi.xyz VF06, VF06, I NOP - MULi.xyz VF07, VF07, I SQI.xyzw VF02, (VI02++) - MULi.xyz VF08, VF08, I NOP - MUL.xyz VF02, VF21, VF01 NOP - MUL.xyz VF03, VF12, VF01 NOP - MUL.xyz VF09, VF06, VF01 NOP - MUL.xyz VF10, VF07, VF01 NOP - MUL.xyz VF11, VF08, VF01 NOP - ABS.xyz VF03, VF03 NOP - ADDy.x VF05, VF09, VF09 NOP - ADDx.y VF05, VF10, VF10 NOP - ADDx.z VF05, VF11, VF11 NOP - NOP NOP -EdgePairLoop: - ADDz.x VF05, VF05, VF09 NOP - ADDz.y VF05, VF05, VF10 NOP - ADDy.z VF05, VF05, VF11 NOP - MULAx.w ACC, VF00, VF02 IADD VI03, VI02, VI00 - MADDAy.w ACC, VF00, VF02 LQD.xyzw VF01, (--VI02) - MADDz.w VF02, VF00, VF02 NOP - ABS.xyz VF05, VF05 NOP - MULAx.w ACC, VF00, VF03 NOP - MADDAy.w ACC, VF00, VF03 NOP - MADDAz.w ACC, VF00, VF03 NOP - MADDAx.w ACC, VF00, VF05 NOP - MADDAy.w ACC, VF00, VF05 NOP - MADDz.w VF03, VF00, VF05 NOP - ADDw.x VF04, VF00, VF02 NOP - MUL.xyz VF02, VF21, VF01 NOP - MUL.xyz VF03, VF12, VF01 NOP - MUL.xyz VF09, VF06, VF01 NOP - CLIPw.xyz VF04, VF03 NOP - MUL.xyz VF10, VF07, VF01 NOP - MUL.xyz VF11, VF08, VF01 NOP - ABS.xyz VF03, VF03 NOP - ADDy.x VF05, VF09, VF09 FCAND VI01, 0x3 - ADDx.y VF05, VF10, VF10 IBNE VI01, VI00, QuitAndFail2 - ADDx.z VF05, VF11, VF11 NOP - NOP IBNE VI03, VI00, EdgePairLoop - NOP NOP - NOP[E] IADDIU VI01, VI00, 0x1 - NOP NOP - -EndOfMicrocode2: 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; -- cgit v1.2.3 From ad10d3e64e317a60c4c7c481354ef9c2b39922f2 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 15 Nov 2020 22:07:44 +0100 Subject: 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 -- cgit v1.2.3 From ac29ae6e23ac174adf03acb85749533e601ec5d0 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sun, 15 Nov 2020 23:06:09 +0100 Subject: 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 e7f714b2..1054ca12 100644 Binary files a/gamefiles/TEXT/american.gxt and b/gamefiles/TEXT/american.gxt differ 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] -- cgit v1.2.3 From f0071c094aeacdd5fc8dd4f45911ebbc719811e0 Mon Sep 17 00:00:00 2001 From: withmorten Date: Mon, 16 Nov 2020 00:07:27 +0100 Subject: 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 }, }, -- cgit v1.2.3 From 207f8576d83c54d80a05a983798ce1d4bcb34f91 Mon Sep 17 00:00:00 2001 From: withmorten Date: Mon, 16 Nov 2020 00:21:04 +0100 Subject: 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 -- cgit v1.2.3 From abcda2ce29877cdd60fad383ec098b174fbcc11f Mon Sep 17 00:00:00 2001 From: withmorten Date: Mon, 16 Nov 2020 00:41:03 +0100 Subject: 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; -- cgit v1.2.3 From 2f9a905c613aacf12a3bc059eb1c8876d8c3bc86 Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 09:41:39 +0100 Subject: 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; } -- cgit v1.2.3 From 5335b46cbb83e80e88d99f6963670050920e5f3e Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 09:48:02 +0100 Subject: 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 ) { -- cgit v1.2.3 From b508458f372ba125c0d40d3f2aed27701b2cf7be Mon Sep 17 00:00:00 2001 From: Nikolay Date: Mon, 16 Nov 2020 15:13:30 +0300 Subject: 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)){ -- cgit v1.2.3 From 3b1debaa0d5341bdb954654503424fb12b529894 Mon Sep 17 00:00:00 2001 From: erorcun Date: Mon, 16 Nov 2020 15:28:10 +0300 Subject: 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 ) -- cgit v1.2.3 From f33ed2892a7a083d10c89b93b0122c6b4100a9a2 Mon Sep 17 00:00:00 2001 From: erorcun Date: Mon, 16 Nov 2020 15:49:00 +0300 Subject: 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; } -- cgit v1.2.3 From 6bc2ed74fec6e60d1d379dc36f271c457448d3e7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 16 Nov 2020 14:56:07 +0200 Subject: 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; -- cgit v1.2.3 From a802ad5c271f15fc9acaacdfa55fb6a318c1c893 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 16 Nov 2020 15:05:02 +0200 Subject: 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 -- cgit v1.2.3 From 3564b85b4e354272cea8a8217f9e27827a043d7a Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 22:43:15 +0100 Subject: 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 -- cgit v1.2.3 From 19d943031481f83d662c74ee3202a8fbaed22fa2 Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 16 Nov 2020 22:57:37 +0100 Subject: 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); -- cgit v1.2.3 From 82b0103c6789041b721b1de30746ce21a556ab4d Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 10:27:55 +0100 Subject: 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 | 13 ++-- src/extras/shaders/neoRimSkin.vert | 15 ++--- 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 | 17 +++-- 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, 566 insertions(+), 184 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; - -out vec4 v_color; -out vec2 v_tex0; -out float v_fog; +VSIN(ATTRIB_POS) vec3 in_pos; + +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; - -out vec4 v_color; -out vec2 v_tex0; -out float v_fog; +VSIN(ATTRIB_POS) vec3 in_pos; + +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; - -out vec4 v_color; -out vec4 v_reflcolor; -out vec2 v_tex0; -out vec2 v_tex1; -out float v_fog; +VSIN(ATTRIB_POS) vec3 in_pos; + +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 -- cgit v1.2.3 From 498a2795d9a2c42e7321d5c711bdc7e851e27ea1 Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Wed, 18 Nov 2020 10:38:31 +0100 Subject: 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' -- cgit v1.2.3 From 9826fdf6d5a324b316e59a34feeb0da9ffca56cc Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 11:16:02 +0100 Subject: 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 -- cgit v1.2.3 From 91f9c7938ee3d2f68002cfc9ab9733f7e358c503 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 12:38:47 +0100 Subject: CPed review part1,2 re3 --- src/peds/Ped.cpp | 624 ++++++++++++++++++++++++--------------------------- src/peds/PedChat.cpp | 53 +++-- 2 files changed, 316 insertions(+), 361 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 ((veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) == 0 - || veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) == 0) { - m_vehEnterType = CAR_DOOR_RF; - posToOpen = rfPos; - return; - } + 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)) - 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) { - - 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 (!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 (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); + 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) { + 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 + SetObjective(OBJECTIVE_NONE); + } else { + SetObjective(OBJECTIVE_GOTO_CHAR_ON_FOOT, m_leader); + SetObjectiveTimer(0); } - 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 -- cgit v1.2.3 From cf3308c66e1f4bc881f511b55ac60b3644df7a84 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 18 Nov 2020 13:46:58 +0100 Subject: 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" -- cgit v1.2.3 From 808f7c46f1df9acaf8d00ebde7cb1925e1d27f94 Mon Sep 17 00:00:00 2001 From: erorcun Date: Thu, 19 Nov 2020 02:09:04 +0300 Subject: 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 } /* -- cgit v1.2.3 From 02c7f8381b81732645ed92fda0c5a66d0f1db265 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 19 Nov 2020 16:23:52 +0100 Subject: 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 00000000..5508096b Binary files /dev/null and b/src/extras/shaders/screenDroplet_PS.cso differ diff --git a/src/extras/shaders/screenDroplet_PS.hlsl b/src/extras/shaders/screenDroplet_PS.hlsl new file mode 100644 index 00000000..4d41da68 --- /dev/null +++ b/src/extras/shaders/screenDroplet_PS.hlsl @@ -0,0 +1,17 @@ +struct VS_out { + float4 Position : POSITION; + float2 TexCoord0 : TEXCOORD0; + float2 TexCoord1 : TEXCOORD1; + float4 Color : COLOR0; +}; + +sampler2D tex0 : register(s0); +sampler2D tex1 : register(s1); + +float4 main(VS_out input) : COLOR +{ + float4 color = input.Color; + color *= tex2D(tex0, input.TexCoord0.xy); + color *= tex2D(tex1, input.TexCoord1.xy); + return color; +} diff --git a/src/extras/shaders/screenDroplet_PS.inc b/src/extras/shaders/screenDroplet_PS.inc new file mode 100644 index 00000000..c2055188 --- /dev/null +++ b/src/extras/shaders/screenDroplet_PS.inc @@ -0,0 +1,29 @@ +static unsigned char screenDroplet_PS_cso[] = { + 0x00, 0x02, 0xff, 0xff, 0xfe, 0xff, 0x2c, 0x00, 0x43, 0x54, 0x41, 0x42, + 0x1c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, + 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x01, 0x00, 0x06, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x30, + 0x00, 0xab, 0xab, 0xab, 0x04, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x78, 0x31, + 0x00, 0xab, 0xab, 0xab, 0x04, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x5f, 0x32, + 0x5f, 0x30, 0x00, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x20, 0x28, 0x52, 0x29, 0x20, 0x48, 0x4c, 0x53, 0x4c, 0x20, 0x53, 0x68, + 0x61, 0x64, 0x65, 0x72, 0x20, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, + 0x72, 0x20, 0x39, 0x2e, 0x32, 0x39, 0x2e, 0x39, 0x35, 0x32, 0x2e, 0x33, + 0x31, 0x31, 0x31, 0x00, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x03, 0xb0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x03, 0xb0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x0f, 0x90, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, + 0x00, 0x08, 0x0f, 0xa0, 0x1f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x90, + 0x01, 0x08, 0x0f, 0xa0, 0x42, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, + 0x00, 0x00, 0xe4, 0xb0, 0x00, 0x08, 0xe4, 0xa0, 0x42, 0x00, 0x00, 0x03, + 0x01, 0x00, 0x0f, 0x80, 0x01, 0x00, 0xe4, 0xb0, 0x01, 0x08, 0xe4, 0xa0, + 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x80, + 0x00, 0x00, 0xe4, 0x90, 0x05, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x80, + 0x01, 0x00, 0xe4, 0x80, 0x00, 0x00, 0xe4, 0x80, 0x01, 0x00, 0x00, 0x02, + 0x00, 0x08, 0x0f, 0x80, 0x00, 0x00, 0xe4, 0x80, 0xff, 0xff, 0x00, 0x00 +}; diff --git a/src/extras/shaders/screenDroplet_fs_gl.inc b/src/extras/shaders/screenDroplet_fs_gl.inc new file mode 100644 index 00000000..dd393b02 --- /dev/null +++ b/src/extras/shaders/screenDroplet_fs_gl.inc @@ -0,0 +1,20 @@ +const char *screenDroplet_frag_src = +"uniform sampler2D tex0;\n" +"uniform sampler2D tex1;\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 color;\n" +" color = v_color*texture(tex0, vec2(v_tex0.x, 1.0-v_tex0.y));\n" +" color *= texture(tex1, vec2(v_tex1.x, 1.0-v_tex1.y));\n" + +" FRAGCOLOR(color);\n" +"}\n" + +; diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp index a8afaf6c..71f223d7 100644 --- a/src/objects/ParticleObject.cpp +++ b/src/objects/ParticleObject.cpp @@ -8,6 +8,7 @@ #include "Camera.h" #include "Game.h" #include "DMAudio.h" +#include "screendroplets.h" CParticleObject gPObjectArray[MAX_PARTICLEOBJECTS]; @@ -18,6 +19,8 @@ CParticleObject *CParticleObject::pUnusedListHead; CAudioHydrant List[MAX_AUDIOHYDRANTS]; +CAudioHydrant *CAudioHydrant::Get(int n) { return &List[n]; } + bool CAudioHydrant::Add(CParticleObject *particleobject) { @@ -247,6 +250,9 @@ CParticleObject::AddObject(uint16 type, CVector const &pos, CVector const &targe pobj->m_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 -- cgit v1.2.3 From 9e45feb4fa0a841b1d059bcab8507fd80708d6e7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 19 Nov 2020 21:12:20 +0200 Subject: 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 | 22640 +++++++++++++---------------------------- 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, 16002 insertions(+), 15993 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,11416 +283,3884 @@ 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++; + 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 (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) - weapon.m_eWeaponState = WEAPONSTATE_READY; - - return weaponType; + if (m_pFire) + m_pFire->Extinguish(); + CPopulation::UpdatePedCount((ePedType)m_nPedType, true); + DMAudio.DestroyEntity(m_audioEntityId); } -static RwObject* -RemoveAllModelCB(RwObject *object, void *data) +void +CPed::Initialise(void) { - RpAtomic *atomic = (RpAtomic*)object; - if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { - RpClumpRemoveAtomic(RpAtomicGetClump(atomic), atomic); - RpAtomicDestroy(atomic); - } - return object; + debug("Initialising CPed...\n"); + CPedType::Initialise(); + LoadFightData(); + SetAnimOffsetForEnterOrExitVehicle(); + debug("CPed ready\n"); } -static PedOnGroundState -CheckForPedsOnGroundToAttack(CPed *attacker, CPed **pedOnGround) +void +CPed::SetModelIndex(uint32 mi) { - 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); + 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); - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - attacker->m_fRotationCur = CGeneral::LimitRadianAngle(attacker->m_fRotationCur); + // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. + (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; - angleDiff = Abs(angleToFace - attacker->m_fRotationCur); +#ifdef PED_SKIN + if(modelInfo->GetHitColModel() == nil) + modelInfo->CreateHitColModelSkinned(GetClump()); +#endif +} - if (angleDiff > PI) - angleDiff = 2 * PI - angleDiff; +void +CPed::SetPedStats(ePedStats pedStat) +{ + m_pedStats = CPedStats::ms_apPedStats[pedStat]; +} - currentPedState = currentPed->m_nPedState; +void +CPed::BuildPedLists(void) +{ + if (((CTimer::GetFrameCounter() + m_randomSeed) % 16) == 0) { + CVector centre = CEntity::GetBoundCentre(); + CRect rect(centre.x - 20.0f, + centre.y - 20.0f, + centre.x + 20.0f, + centre.y + 20.0f); + int xstart = CWorld::GetSectorIndexX(rect.left); + int ystart = CWorld::GetSectorIndexY(rect.top); + int xend = CWorld::GetSectorIndexX(rect.right); + int yend = CWorld::GetSectorIndexY(rect.bottom); + gnNumTempPedList = 0; - 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; + for(int y = ystart; y <= yend; y++) { + for(int x = xstart; x <= xend; x++) { + for (CPtrNode *pedPtrNode = CWorld::GetSector(x,y)->m_lists[ENTITYLIST_PEDS].first; pedPtrNode; pedPtrNode = pedPtrNode->next) { + CPed *ped = (CPed*)pedPtrNode->item; + if (ped != this && !ped->bInVehicle) { + float dist = (ped->GetPosition() - GetPosition()).Magnitude2D(); + if (nThreatReactionRangeMultiplier * 30.0f > dist) { + gapTempPedList[gnNumTempPedList] = ped; + gnNumTempPedList++; + assert(gnNumTempPedList < ARRAY_SIZE(gapTempPedList)); + } } } - } 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; - } } } - } + gapTempPedList[gnNumTempPedList] = nil; + SortPeds(gapTempPedList, 0, gnNumTempPedList - 1); + for (m_numNearPeds = 0; m_numNearPeds < ARRAY_SIZE(m_nearPeds); m_numNearPeds++) { + CPed *ped = gapTempPedList[m_numNearPeds]; + if (!ped) + break; - 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; + m_nearPeds[m_numNearPeds] = ped; + } + for (int pedToClear = m_numNearPeds; pedToClear < ARRAY_SIZE(m_nearPeds); pedToClear++) + m_nearPeds[pedToClear] = nil; } else { - currentPed = nil; - stateToReturn = NO_PED; + 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++; + } } - - 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) +CPed::OurPedCanSeeThisOne(CEntity *target) { - return m_nPedState == PED_FALL || - m_nPedState == PED_DIVE_AWAY || - m_nPedState == PED_DIE || - m_nPedState == PED_DEAD; -} + CColPoint colpoint; + CEntity *ent; -bool -CPed::CanSetPedState(void) -{ - return !DyingOrDead() && m_nPedState != PED_ARRESTED && !EnteringCar() && m_nPedState != PED_STEAL_CAR; -} + CVector2D dist = CVector2D(target->GetPosition()) - CVector2D(GetPosition()); -bool -CPed::IsPedInControl(void) -{ - return m_nPedState <= PED_STATES_NO_AI - && !bIsInTheAir && !bIsLanding - && m_fHealth > 0.0f; -} + // Check if target is behind ped + if (DotProduct2D(dist, CVector2D(GetForward())) < 0.0f) + return false; -bool -CPed::CanStrafeOrMouseControl(void) -{ -#ifdef FREE_CAM - if (CCamera::bFreeCam) + // Check if target is too far away + if (dist.Magnitude() >= 40.0f) 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; + + // 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::AddWeaponModel(int id) +CPed::SortPeds(CPed **list, int min, int max) { - RpAtomic *atm; + if (min >= max) + return; - if (id != -1) { -#ifdef PED_SKIN - if (IsClumpSkinned(GetClump())) { - if (m_pWeaponModel) - RemoveWeaponModel(-1); + CVector leftDiff, rightDiff; + CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); + float middleDist = middleDiff.Magnitude(); - 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); + 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--; } - m_wepModelID = id; } + SortPeds(list, min, left); + SortPeds(list, right, max); } void -CPed::AimGun(void) +CPed::SetMoveState(eMoveState state) { - 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); - } - } + m_nMoveState = state; } void -CPed::ApplyHeadShot(eWeaponType weaponType, CVector pos, bool evenOnPlayer) +CPed::SetMoveAnim(void) { - CVector pos2 = CVector( - pos.x, - pos.y, - pos.z + 0.1f - ); - - if (!IsPlayer() || evenOnPlayer) { - ++CStats::HeadsPopped; + if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) + return; - // 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); - // } + if (m_nMoveState == PEDMOVE_NONE) { + m_nStoredMoveState = PEDMOVE_NONE; + return; + } - bBodyPartJustCameOff = true; - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 150; + AssocGroupId animGroupToUse; + if (m_leader && m_leader->IsPlayer()) + animGroupToUse = ASSOCGRP_PLAYER; + else + animGroupToUse = m_animGroup; - CParticle::AddParticle(PARTICLE_TEST, pos2, - CVector(0.0f, 0.0f, 0.0f), nil, 0.2f, 0, 0, 0, 0); + 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 (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); + 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; - 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); + 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)) { -static RwObject* -SetPedAtomicVisibilityCB(RwObject* object, void* data) -{ - if (data == nil) - RpAtomicSetFlags((RpAtomic*)object, 0); - return object; -} + if (!(assoc->flags & ASSOC_FADEOUTWHENDONE)) { + assoc->blendDelta = -2.0f; + assoc->flags |= ASSOC_DELETEFADEDOUT; + } + } -static RwFrame* -RecurseFrameChildrenVisibilityCB(RwFrame* frame, void* data) -{ - RwFrameForAllObjects(frame, SetPedAtomicVisibilityCB, data); - RwFrameForAllChildren(frame, RecurseFrameChildrenVisibilityCB, nil); - return frame; -} + ClearAimFlag(); + ClearLookFlag(); + } -void -CPed::RemoveBodyPart(PedNode nodeId, int8 direction) -{ - RwFrame *frame; - CVector pos; + switch (m_nMoveState) { + case PEDMOVE_STILL: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_IDLE_STANCE, 4.0f); + break; + case PEDMOVE_WALK: + animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_WALK, 1.0f); + 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); + break; + default: + break; + } - 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); + if (animAssoc) { + if (m_leader) { + CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); + if (!walkAssoc) + walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); - 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); + 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; } - bBodyPartJustCameOff = true; - m_bodyPartBleeding = nodeId; } - } else { - printf("Trying to remove ped component"); } } void -CPed::SetLookFlag(CEntity *target, bool keepTryingToLook) +CPed::StopNonPartialAnims(void) { - 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; - } - } -} + CAnimBlendAssociation *assoc; -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; - } + for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->flags &= ~ASSOC_RUNNING; } } void -CPed::SetLookTimer(int time) +CPed::RestartNonPartialAnims(void) { - if (CTimer::GetTimeInMilliseconds() > m_lookTimer) { - m_lookTimer = CTimer::GetTimeInMilliseconds() + time; + CAnimBlendAssociation *assoc; + + for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { + if (!assoc->IsPartial()) + assoc->SetRun(); } } -bool -CPed::OurPedCanSeeThisOne(CEntity *target) +void +CPed::SetStoredState(void) { - 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; + if (m_nLastPedState != PED_NONE || !CanPedReturnToState()) + return; - // 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); + if (m_nPedState == PED_WANDER_PATH) { + bFindNewNodeAfterStateRestore = true; + if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) + m_nMoveState = PEDMOVE_WALK; + } +#ifdef VC_PED_PORTS + if (m_nPedState != PED_IDLE) +#endif + { + m_nLastPedState = m_nPedState; + if (m_nMoveState >= m_nPrevMoveState) + m_nPrevMoveState = m_nMoveState; + } } void -CPed::Avoid(void) +CPed::RestorePreviousState(void) { - CPed *nearestPed; - - if(m_pedStats->m_temper > m_pedStats->m_fear && m_pedStats->m_temper > 50) + if(!CanSetPedState() || m_nPedState == PED_FALL) 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) { + if (m_nPedState == PED_GETUP && !bGetUpAnimStarted) + return; - // 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; + if (InVehicle()) { + m_nPedState = PED_DRIVING; + m_nLastPedState = PED_NONE; + } else { + if (m_nLastPedState == PED_NONE) { + if (!IsPlayer() && CharCreatedBy != MISSION_CHAR && m_objective == OBJECTIVE_NONE) { + if (SetWanderPath(CGeneral::GetRandomNumber() & 7) != 0) + return; + } + SetIdle(); + return; + } - m_fRotationDest += DEGTORAD(45.0f); - if (!bIsLooking) { - SetLookFlag(nearestPed, false); - SetLookTimer(CGeneral::GetRandomNumberInRange(500, 800)); + switch (m_nLastPedState) { + case PED_IDLE: + SetIdle(); + break; + case PED_WANDER_PATH: + m_nPedState = PED_WANDER_PATH; + bIsRunning = false; + if (bFindNewNodeAfterStateRestore) { + if (m_pNextPathNode) { + CVector diff = m_pNextPathNode->GetPosition() - GetPosition(); + if (diff.MagnitudeSqr() < sq(7.0f)) { + SetMoveState(PEDMOVE_WALK); + break; } } } - } + SetWanderPath(CGeneral::GetRandomNumber() & 7); + break; + default: + m_nPedState = m_nLastPedState; + SetMoveState((eMoveState) m_nPrevMoveState); + break; } + m_nLastPedState = PED_NONE; } } -void -CPed::ClearAimFlag(void) +uint32 +CPed::ScanForThreats(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 + 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; } + + 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; + } - 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(); + if (CPedType::GetFlag(shooter->m_nPedType) & fearFlags) { + m_threatEntity = shooter; + m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + return CPedType::GetFlag(shooter->m_nPedType); } } -} - -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); - } + 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; - newAnim->SetFinishCallback(FinishedAttackCB, ped); - return; + 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]; - case ANIM_FIGHT_PPUNCH: - attackAssoc->blendDelta = -8.0f; - attackAssoc->flags |= ASSOC_DELETEFADEDOUT; - ped->ClearAttack(); - return; + // 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); - 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); + 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]; + } + } } - break; - default: - break; + } } - } - - if (!ped->bIsAttacking) - ped->ClearAttack(); -} +#else + bool weSawOurEnemy = false; + bool weMaySeeOurEnemy = false; + float closestEnemyDist = 60.0f; + if ((CTimer::GetFrameCounter() + (uint8)m_randomSeed + 16) & 4) { -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; + for (int i = 0; i < m_numNearPeds; ++i) { + if (CharCreatedBy == RANDOM_CHAR && m_nearPeds[i]->CharCreatedBy == MISSION_CHAR && !m_nearPeds[i]->IsPlayer()) { + continue; + } - if (reloadAnimAssoc) { - if (!IsPlayer() || ((CPlayerPed*)this)->m_bHaveTargetSelected) - ClearAttack(); + // 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); - return; - } + if (flagsOfSomePed & fearFlags) { + if (m_nearPeds[i]->m_fHealth > 0.0f) { - if (CTimer::GetTimeInMilliseconds() < m_shootTimer) - attackShouldContinue = true; + // 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 (!weaponAnimAssoc) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_Anim2ToPlay); - delayBetweenAnimAndFire = ourWeapon->m_fAnim2FrameFire; + 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; - // Long throw granade, molotov - if (!weaponAnimAssoc && ourWeapon->m_bThrow) { - weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WEAPON_THROWU); - delayBetweenAnimAndFire = 0.2f; - } + // 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 (!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); + 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]; - weaponAnimAssoc->SetFinishCallback(FinishedAttackCB, this); - weaponAnimAssoc->SetRun(); - - if (weaponAnimAssoc->currentTime == weaponAnimAssoc->hierarchy->totalLength) - weaponAnimAssoc->SetCurrentTime(0.0f); + CPed *driver = nearVeh->pDriver; + if (driver) { - if (IsPlayer()) { - ((CPlayerPed*)this)->m_fAttackButtonCounter = 0.0f; - ((CPlayerPed*)this)->m_bHaveTargetSelected = false; + // 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 + float driverDistSqr = (driver->GetPosition() - ourPos).MagnitudeSqr2D(); +#else + float driverDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); +#endif + if (sq(closestPedDist) > driverDistSqr) { + closestPedDist = Sqrt(driverDistSqr); + pedToFearFrom = nearVeh->pDriver; + } } } - } else - FinishedAttackCB(nil, this); - - return; + } } - } + m_threatEntity = pedToFearFrom; + if (m_threatEntity) + m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); - 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; +#ifdef FIX_BUGS + if (pedToFearFrom) + flagsOfSomePed = CPedType::GetFlag(((CPed*)m_threatEntity)->m_nPedType); else - m_pedIK.m_flags &= ~CPedIK::AIMS_WITH_ARM; - } + flagsOfSomePed = 0; +#endif - if (weaponAnimTime <= delayBetweenAnimAndFire || weaponAnimTime - weaponAnimAssoc->timeStep > delayBetweenAnimAndFire || !weaponAnimAssoc->IsRunning()) { - if (weaponAnimAssoc->speed < 1.0f) - weaponAnimAssoc->speed = 1.0f; + return flagsOfSomePed; + } +} - } 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; +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; } - - 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(); +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; } + } +} - 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); - } +void +CPed::ClearLookFlag(void) { + if (bIsLooking) { + bIsLooking = false; + bIsRestoringLook = true; + bShakeFist = false; - weaponAnimAssoc->speed = 0.5f; + m_pedIK.m_flags &= ~CPedIK::LOOKAROUND_HEAD_ONLY; + if (IsPlayer()) + m_lookTimer = CTimer::GetTimeInMilliseconds() + 2000; + else + m_lookTimer = CTimer::GetTimeInMilliseconds() + 4000; - if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) { - weaponAnimAssoc->callbackType = 0; - } + 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) +{ + CVector lookPos; - attackShouldContinue = false; + if (m_lookTimer && CTimer::GetTimeInMilliseconds() > m_lookTimer) { + ClearLookFlag(); + } else if (m_nPedState == PED_DRIVING) { + m_pedIK.m_flags |= CPedIK::LOOKAROUND_HEAD_ONLY; } - if (ourWeaponType == WEAPONTYPE_SHOTGUN) { - weaponAnimTime = weaponAnimAssoc->currentTime; - firePos = ourWeapon->m_vecFireOffset; + if (m_pLookTarget) { + + if (!bShakeFist && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { + + CAnimBlendAssociation *fuckUAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FUCKU); + if (fuckUAssoc) { + + float animTime = fuckUAssoc->currentTime; + if (animTime > 4.0f / 30.0f && animTime - fuckUAssoc->timeStep > 4.0f / 30.0f) { + + bool lookingToCop = false; + if (m_pLookTarget->GetModelIndex() == MI_POLICE + || m_pLookTarget->IsPed() && ((CPed*)m_pLookTarget)->m_nPedType == PEDTYPE_COP) { - if (weaponAnimTime > 1.0f && weaponAnimTime - weaponAnimAssoc->timeStep <= 1.0f && weaponAnimAssoc->IsRunning()) { - TransformToNode(firePos, PED_HANDR); + lookingToCop = true; + } - CVector gunshellPos( - firePos.x - 0.6f * GetForward().x, - firePos.y - 0.6f * GetForward().y, - firePos.z - 0.15f * GetUp().z - ); + if (IsPlayer() && (m_pedStats->m_temper >= 52 || lookingToCop)) { + AddWeaponModel(MI_FINGERS); + ((CPlayerPed*)this)->AnnoyPlayerPed(true); - CVector2D gunshellRot( - GetRight().x, - GetRight().y - ); + } else if ((CGeneral::GetRandomNumber() & 3) == 0) { + AddWeaponModel(MI_FINGERS); + } + } + } + } - gunshellRot.Normalise(); - GetWeapon()->AddGunshell(this, gunshellPos, gunshellRot, 0.025f); + if (m_pLookTarget->IsPed()) { + ((CPed*)m_pLookTarget)->m_pedIK.GetComponentPosition((RwV3d*) &lookPos, PED_MID); + } else { + lookPos = m_pLookTarget->GetPosition(); } - } -#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; + + if (!m_pedIK.LookAtPosition(lookPos)) { + if (!bKeepTryingToLook) { + ClearLookFlag(); } + return; } - } -#endif - animLoopEnd = ourWeapon->m_fAnimLoopEnd; - if (ourWeaponFire == WEAPON_FIRE_MELEE && weaponAnimAssoc->animId == ourWeapon->m_Anim2ToPlay) - animLoopEnd = 3.4f/6.0f; - weaponAnimTime = weaponAnimAssoc->currentTime; + if (!bShakeFist || bIsAimingGun || bIsRestoringGun) + return; + + if (m_lookTimer - CTimer::GetTimeInMilliseconds() >= 1000) + return; + + bool notRocketLauncher = false; + bool notTwoHanded = false; + AnimationId animToPlay = NUM_ANIMS; + + if (!GetWeapon()->IsType2Handed()) + notTwoHanded = true; + + if (notTwoHanded && GetWeapon()->m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER) + notRocketLauncher = true; + + if (IsPlayer() && notRocketLauncher) { - // Anim loop end, either start the loop again or finish the attack - if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) { + if (m_pLookTarget->IsPed()) { - if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd - && (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_shootTimer) - && GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) { + if (m_pedStats->m_temper >= 49 && ((CPed*)m_pLookTarget)->m_nPedType != PEDTYPE_COP) { - 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); + // FIX: Unreachable and meaningless condition +#ifndef FIX_BUGS + if (m_pedStats->m_temper < 47) +#endif + animToPlay = ANIM_FIGHT_PPUNCH; } else { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f); + animToPlay = ANIM_FUCKU; } - } else { - if (weaponAnim == ourWeapon->m_Anim2ToPlay) - weaponAnimAssoc->SetCurrentTime(0.1f); - else - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_Anim2ToPlay, 8.0f); + } else if (m_pedStats->m_temper > 49 || m_pLookTarget->GetModelIndex() == MI_POLICE) { + animToPlay = ANIM_FUCKU; } -#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(); + } else if (notRocketLauncher && (CGeneral::GetRandomNumber() & 1)) { + animToPlay = ANIM_FUCKU; + } - // 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; - } - } + if (animToPlay != NUM_ANIMS) { + CAnimBlendAssociation *newAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); - // 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 (newAssoc) { + newAssoc->flags |= ASSOC_FADEOUTWHENDONE; + newAssoc->flags |= ASSOC_DELETEFADEDOUT; + if (newAssoc->animId == ANIM_FUCKU) + newAssoc->SetDeleteCallback(FinishFuckUCB, this); } } + bShakeFist = false; + return; + } else if (999999.0f == m_fLookDirection) { + ClearLookFlag(); + } else if (!m_pedIK.LookInDirection(m_fLookDirection, 0.0f)) { + if (!bKeepTryingToLook) + ClearLookFlag(); } - 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) +CPed::RestoreHeadPosition(void) { - 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); + if (m_pedIK.RestoreLookAt()) { + bIsRestoringLook = false; } } -// Only used while deciding which gun ped should switch to, if no ammo left. -bool -CPed::SelectGunIfArmed(void) +void +CPed::SetAimFlag(float angle) { - 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; + 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::Duck(void) +CPed::SetAimFlag(CEntity *to) { - if (CTimer::GetTimeInMilliseconds() > m_duckTimer) - ClearDuck(); + 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::ClearDuck(void) +CPed::ClearAimFlag(void) { - CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_DOWN); - if (!animAssoc) { - animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DUCK_LOW); - - if (!animAssoc) { - bIsDucking = false; - return; - } + 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 (!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); - } + if (IsPlayer()) + ((CPlayerPed*)this)->m_fFPSMoveHeading = 0.0f; } void -CPed::ClearPointGunAt(void) +CPed::AimGun(void) { - CAnimBlendAssociation *animAssoc; - CWeaponInfo *weaponInfo; + CVector vector; - 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; + if (m_pSeekTarget) { + if (m_pSeekTarget->IsPed()) { + ((CPed*)m_pSeekTarget)->m_pedIK.GetComponentPosition(vector, PED_MID); + } else { + vector = m_pSeekTarget->GetPosition(); } -#ifndef VC_PED_PORTS - } -#endif -} + Say(SOUND_PED_ATTACK); -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); - } + bCanPointGunAtTarget = m_pedIK.PointGunAtPosition(vector); + if (m_pLookTarget != m_pSeekTarget) { + SetLookFlag(m_pSeekTarget, true); } - 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); + if (IsPlayer()) { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, ((CPlayerPed*)this)->m_fFPSMoveHeading); + } else { + bCanPointGunAtTarget = m_pedIK.PointGunInDirection(m_fLookDirection, 0.0f); } } -#endif } void -CPed::RestartNonPartialAnims(void) +CPed::RestoreGunPosition(void) { - CAnimBlendAssociation *assoc; - - for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (!assoc->IsPartial()) - assoc->SetRun(); + 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::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) +CPed::ScanForInterestingStuff(void) { - CAnimBlendAssociation *quickJackedAssoc; - CVehicle *vehicle; - CPed *ped = (CPed*)arg; + if (!IsPedInControl()) + 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; + if (m_objective != OBJECTIVE_NONE) + return; - if (vehicle) { - vehicle->m_nGettingOutFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); + if (CharCreatedBy == MISSION_CHAR) + return; - if (vehicle->pDriver == ped) { - vehicle->RemoveDriver(); - if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) - vehicle->m_nDoorLock = CARLOCK_UNLOCKED; + LookForSexyPeds(); + LookForSexyCars(); + if (LookForInterestingNodes()) + return; - if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) - vehicle->ChangeLawEnforcerState(false); - } else { - vehicle->RemovePassenger(ped); - } - } - ped->bInVehicle = false; - if (ped->IsPlayer()) - AudioManager.PlayerJustLeftCar(); + if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { + if (CGeneral::GetRandomNumber() % 100 < 10) { + int mostExpensiveVehAround = -1; + int bestMonetaryValue = 0; -#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 + CVector pos = GetPosition(); + int16 lastVehicle; + CEntity *vehicles[8]; + CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - if (quickJackedAssoc) { - dragAssoc->SetDeleteCallback(PedSetQuickDraggedOutCarPositionCB, ped); - } else { - dragAssoc->SetDeleteCallback(PedSetDraggedOutCarPositionCB, ped); - if (ped->CanSetPedState()) - CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_GETUP1, 1000.0f); - } + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; - ped->ReplaceWeaponWhenExitingVehicle(); + 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]; - ped->m_nStoredMoveState = PEDMOVE_NONE; - ped->bVehExitWillBeInstant = false; -} + if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) + break; -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; + 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; } } - 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; + if (m_nPedState == PED_WANDER_PATH) { +#ifndef VC_PED_PORTS + if (CTimer::GetTimeInMilliseconds() > m_standardTimer) { - case CAR_DOOR_LR: - vehDoorPos = vehModel->m_positions[CAR_POS_BACKSEAT]; - vehDoorPos.x = -(vehDoorPos.x + seatOffset); - break; + // += 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])) { - default: - vehDoorPos = vehModel->GetFrontSeatPosn(); - vehDoorOffset = CVector(0.0f, 0.0f, 0.0f); + 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 } - 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; + // 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()) { - localPos = GetLocalPositionToOpenCarDoor(veh, component, 1.0f); - vehDoorPos = Multiply3x3(veh->GetMatrix(), localPos) + veh->GetPosition(); + 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); -/* - // Not used. - CVector localVehDoorOffset; + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; - if (veh->bIsVan && (component == VEHICLE_ENTER_REAR_LEFT || component == VEHICLE_ENTER_REAR_RIGHT)) { - localVehDoorOffset = vecPedVanRearDoorAnimOffset; - } else { - if (veh->bIsLow) { - localVehDoorOffset = vecPedCarDoorLoAnimOffset; - } else { - localVehDoorOffset = vecPedCarDoorAnimOffset; + 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); - vehDoorPosWithoutOffset = Multiply3x3(veh->GetMatrix(), localPos + localVehDoorOffset) + veh->GetPosition(); -*/ - return vehDoorPos; -} + for (int i = 0; i < lastVehicle; i++) { + CVehicle* veh = (CVehicle*)vehicles[i]; -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; + 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; + } + } + } + } + } } -void -CPed::LineUpPedWithCar(PedLineUpPhase phase) +bool +CPed::WillChat(CPed *stranger) { - 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; + if (m_pNextPathNode && m_pLastPathNode) { + if (m_pNextPathNode != m_pLastPathNode && ThePaths.TestCrossesRoad(m_pNextPathNode, m_pLastPathNode)) { + return false; } - bChangedSeat = true; } - if (phase == LINE_UP_TO_CAR_START) { - m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); - } - CVehicle *veh = m_pMyVehicle; + 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; +} - // Not quite right, IsUpsideDown func. checks for <= -0.9f. - if (veh->GetUp().z <= -0.8f) - vehIsUpsideDown = 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_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(); + if (m_fRotationCur - PI > limitedRotDest) { + limitedRotDest += 2 * PI; + } else if(PI + m_fRotationCur < limitedRotDest) { + limitedRotDest -= 2 * PI; } - } 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(); + 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_fRotationDest = veh->GetForward().Heading(); + m_fRotationCur += headAmount; } } - 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; - } - } + CVector2D forward(Sin(m_fRotationCur), Cos(m_fRotationCur)); - CVector neededPos; + 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 (phase == LINE_UP_TO_CAR_2) { - neededPos = GetPosition(); + if (CTimer::GetTimeStep() >= 0.01f) { + m_moved = m_moved * (1 / CTimer::GetTimeStep()); } else { - neededPos = GetPositionToOpenCarDoor(veh, m_vehEnterType, seatPosMult); + m_moved = m_moved * (1 / 100.0f); } - CVector autoZPos = neededPos; - - if (veh->bIsInWater) { - if (veh->m_vehType == VEHICLE_TYPE_BOAT && veh->IsUpsideDown()) - autoZPos.z += 1.0f; - } else { - CPedPlacement::FindZCoorForPed(&autoZPos); - } + if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam()) + || FindPlayerPed() != this || !CanStrafeOrMouseControl()) + return; - if (phase == LINE_UP_TO_CAR_END || phase == LINE_UP_TO_CAR_2) { - neededPos.z = GetPosition().z; + float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur); + float pedSpeed = m_moved.Magnitude(); + float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur); - // Getting out - if (!veh->bIsBus || (veh->bIsBus && vehIsUpsideDown)) { - float nextZSpeed = m_vecMoveSpeed.z - GRAVITY * CTimer::GetTimeStep(); + if (localWalkAngle < -0.5f * PI) { + localWalkAngle += PI; + } else if (localWalkAngle > 0.5f * PI) { + localWalkAngle -= PI; + } - // 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); - } - } + // 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; } - if (autoZPos.z > neededPos.z) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + CAnimBlendAssociation *fightAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE); #ifdef VC_PED_PORTS - if (multExtractedFromAnim) { - neededPos.z += (autoZPos.z - neededPos.z) * zBlend; - } else { + if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc && !bIsDucking) { +#else + if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) { #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 + LimbOrientation newUpperLegs; + newUpperLegs.yaw = localWalkAngle; + + if (newUpperLegs.yaw < -DEGTORAD(100.0f)) { + newUpperLegs.yaw += PI; + } else if (newUpperLegs.yaw > DEGTORAD(100.0f)) { + newUpperLegs.yaw -= PI; } -#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 - } + 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; - bool stillGettingInOut = false; - if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer) - stillGettingInOut = veh->m_vehType != VEHICLE_TYPE_BOAT || bOnBoat; + CPad *pad0 = CPad::GetPad(0); + float leftRight = pad0->GetPedWalkLeftRight(); + float upDown = pad0->GetPedWalkUpDown(); + float &angle = ((CPlayerPed*)this)->m_fWalkAngle; - if (!stillGettingInOut) { - m_fRotationCur = m_fRotationDest; + if (upDown != 0.0f) { + angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown); } else { - float limitedDest = CGeneral::LimitRadianAngle(m_fRotationDest); - float timeUntilStateChange = (m_nPedStateTimer - CTimer::GetTimeInMilliseconds())/600.0f; + 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; - if (timeUntilStateChange <= 0.0f) { - m_vecOffsetSeek.x = 0.0f; - m_vecOffsetSeek.y = 0.0f; + 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); } - m_vecOffsetSeek.z = 0.0f; + // 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(); - neededPos -= timeUntilStateChange * m_vecOffsetSeek; + velocityChange = 0.02f * reactionForce + m_moved; - if (PI + m_fRotationCur < limitedDest) { - limitedDest -= 2 * PI; - } else if (m_fRotationCur - PI > limitedDest) { - limitedDest += 2 * PI; + float reactionAndVelocityDotProd = DotProduct2D(reactionForce, velocityChange); + // they're in same direction + if (reactionAndVelocityDotProd < 0.0f) { + velocityChange -= reactionAndVelocityDotProd * reactionForce; } - m_fRotationCur -= (m_fRotationCur - limitedDest) * (1.0f - timeUntilStateChange); + } 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 (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; + 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); } -static void -particleProduceFootDust(CPed *ped, CVector const &pos, float size, int times) +void +CPed::ClearAll(void) { - 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); + if (!IsPedInControl() && m_nPedState != PED_DEAD) + return; - 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); - } + 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 - 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); - } + ClearAimFlag(); + ClearLookFlag(); #endif + bIsPointingGunAt = false; + bRenderPedInCar = true; + bKnockedUpIntoAir = false; + m_pCollidingEntity = nil; } void -CPed::PlayFootSteps(void) +CPed::ProcessBuoyancy(void) { - if (bDoBloodyFootprints) { - if (m_bloodyFootprintCountOrDeathTime > 0 && m_bloodyFootprintCountOrDeathTime < 300) { - m_bloodyFootprintCountOrDeathTime--; - - if (m_bloodyFootprintCountOrDeathTime == 0) - bDoBloodyFootprints = false; - } - } + 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 (!bIsStanding) + if (bInVehicle) return; - CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); - CAnimBlendAssociation *walkRunAssoc = nil; - float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; + CVector buoyancyPoint; + CVector buoyancyImpulse; - 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; - } - } +#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 -#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); + 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); - { - 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); - } - } + 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 - - - 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; + m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + m_nPedState = PED_IDLE; + return; + } } } - if (CWeather::Rain <= 0.1f || CCullZones::CamNoRain() || CCullZones::PlayerNoRain()) { - if(IsPlayer()) - particleProduceFootDust(this, footPos, 0.0f, 4); + 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 - else if(stepPart == 2) + 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 - 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 - { - 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; + } else + return; + } else + bTouchingWater = false; - if (particleSize < 0.25f) - particleSize = 0.25f; + if (nGenerateWaterCircles && CTimer::GetTimeInMilliseconds() >= nGenerateWaterCircles) { + CVector pos = GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(pos, &level, false)) + pos.z = level; - 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); + 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 - 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)); + 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 + } } } -} - -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; + if (nGenerateRaindrops && CTimer::GetTimeInMilliseconds() >= nGenerateRaindrops) { + CVector pos = GetPosition(); + float level = 0.0f; + if (CWaterLevel::GetWaterLevel(pos, &level, false)) + pos.z = level; - return false; + 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 + } + } } -// Some kind of binary sort void -CPed::SortPeds(CPed **list, int min, int max) +CPed::ProcessControl(void) { - if (min >= max) + CColPoint foundCol; + CEntity *foundEnt = nil; + + if (m_nZoneLevel > LEVEL_GENERIC && m_nZoneLevel != CCollision::ms_collisionInMemory) return; - CVector leftDiff, rightDiff; - CVector middleDiff = GetPosition() - list[(max + min) / 2]->GetPosition(); - float middleDist = middleDiff.Magnitude(); + int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); + if (!bFadeOut) { + if (alpha < 255) { + alpha += 16; + if (alpha > 255) + alpha = 255; + } + } else { + alpha -= 8; + if (alpha < 0) + alpha = 0; + } - 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); + CVisibilityPlugins::SetClumpAlpha(GetClump(), alpha); + bIsShooting = false; + BuildPedLists(); + bIsInWater = false; + ProcessBuoyancy(); - do { - leftDiff = GetPosition() - list[left]->GetPosition(); - leftDist = leftDiff.Magnitude(); - } while (middleDist < leftDist && left--); + if (m_nPedState != PED_ARRESTED) { + if (m_nPedState == PED_DEAD) { + DeadPedMakesTyresBloody(); +#ifndef VC_PED_PORTS + if (CGame::nastyGame) { +#else + if (CGame::nastyGame && !bIsInWater) { +#endif + uint32 remainingBloodyFpTime = CTimer::GetTimeInMilliseconds() - m_bloodyFootprintCountOrDeathTime; + float timeDependentDist; + if (remainingBloodyFpTime >= 2000) { + if (remainingBloodyFpTime <= 7000) + timeDependentDist = (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f; + else + timeDependentDist = 0.75f; + } else { + timeDependentDist = 0.0f; + } - if (right <= left) { - CPed *ped = list[right]; - list[right] = list[left]; - list[left] = ped; - right++; - left--; - } - } - SortPeds(list, min, left); - SortPeds(list, right, max); -} + for (int i = 0; i < m_numNearPeds; ++i) { + CPed *nearPed = m_nearPeds[i]; + if (!nearPed->DyingOrDead()) { + CVector dist = nearPed->GetPosition() - GetPosition(); + if (dist.MagnitudeSqr() < sq(timeDependentDist)) { + nearPed->m_bloodyFootprintCountOrDeathTime = 200; + nearPed->bDoBloodyFootprints = true; + if (nearPed->IsPlayer()) { + if (!nearPed->bIsLooking && nearPed->m_nPedState != PED_ATTACK) { + int16 camMode = TheCamera.Cams[TheCamera.ActiveCam].Mode; + if (camMode != CCam::MODE_SNIPER + && camMode != CCam::MODE_ROCKETLAUNCHER + && camMode != CCam::MODE_M16_1STPERSON + && camMode != CCam::MODE_1STPERSON + && camMode != CCam::MODE_HELICANNON_1STPERSON + && !TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn()) { -void -CPed::BuildPedLists(void) -{ - if (((CTimer::GetFrameCounter() + m_randomSeed) % 16) == 0) { - CVector centre = CEntity::GetBoundCentre(); - CRect rect(centre.x - 20.0f, - centre.y - 20.0f, - centre.x + 20.0f, - centre.y + 20.0f); - int xstart = CWorld::GetSectorIndexX(rect.left); - int ystart = CWorld::GetSectorIndexY(rect.top); - int xend = CWorld::GetSectorIndexX(rect.right); - int yend = CWorld::GetSectorIndexY(rect.bottom); - gnNumTempPedList = 0; + nearPed->SetLookFlag(this, true); + nearPed->SetLookTimer(500); + } + } + } + } + } + } - for(int y = ystart; y <= yend; y++) { - for(int x = xstart; x <= xend; x++) { - for (CPtrNode *pedPtrNode = CWorld::GetSector(x,y)->m_lists[ENTITYLIST_PEDS].first; pedPtrNode; pedPtrNode = pedPtrNode->next) { - CPed *ped = (CPed*)pedPtrNode->item; - if (ped != this && !ped->bInVehicle) { - float dist = (ped->GetPosition() - GetPosition()).Magnitude2D(); - if (nThreatReactionRangeMultiplier * 30.0f > dist) { - gapTempPedList[gnNumTempPedList] = ped; - gnNumTempPedList++; - assert(gnNumTempPedList < ARRAY_SIZE(gapTempPedList)); + if (remainingBloodyFpTime > 2000) { + CVector bloodPos = GetPosition(); + if (remainingBloodyFpTime - 2000 >= 5000) { + if (!m_deadBleeding) { + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, + 0.75f, 0.0f, 0.0f, -0.75f, 255, 255, 0, 0, 4.0f, 40000, 1.0f); + m_deadBleeding = true; } + } else { + CShadows::StoreStaticShadow( + (uintptr)this + 17, SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, + (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f, 0.0f, + 0.0f, (remainingBloodyFpTime - 2000) / 5000.0f * -0.75f, + 255, 255, 0, 0, 4.0f, 1.0f, 40.0f, false, 0.0f); } } } - } - gapTempPedList[gnNumTempPedList] = nil; - SortPeds(gapTempPedList, 0, gnNumTempPedList - 1); - for (m_numNearPeds = 0; m_numNearPeds < ARRAY_SIZE(m_nearPeds); m_numNearPeds++) { - CPed *ped = gapTempPedList[m_numNearPeds]; - if (!ped) - break; + if (ServiceTalkingWhenDead()) + ServiceTalking(); - m_nearPeds[m_numNearPeds] = ped; - } - 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; +#ifdef VC_PED_PORTS + if (bIsInWater) { + bIsStanding = false; + bWasStanding = false; + CPhysical::ProcessControl(); } - 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; +#endif + return; + } + + bWasStanding = false; + if (bIsStanding) { + if (!CWorld::bForceProcessControl) { + if (m_pCurrentPhysSurface && m_pCurrentPhysSurface->bIsInSafePosition) { + bWasPostponed = true; + return; } - // 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++; + } } - } -} -void -CPed::SetPedStats(ePedStats pedStat) -{ - m_pedStats = CPedStats::ms_apPedStats[pedStat]; -} + if (!IsPedInControl() || m_nWaitState != WAITSTATE_FALSE || 0.01f * CTimer::GetTimeStep() <= m_fDistanceTravelled + || (m_nStoredMoveState != PEDMOVE_WALK && m_nStoredMoveState != PEDMOVE_RUN && m_nStoredMoveState != PEDMOVE_SPRINT)) + m_panicCounter = 0; + else if (m_panicCounter < 50) + ++m_panicCounter; -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); + if (m_fHealth <= 1.0f && m_nPedState <= PED_STATES_NO_AI && !bIsInTheAir && !bIsLanding) + SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - // This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. - (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta; + bCollidedWithMyVehicle = false; -#ifdef PED_SKIN - if(modelInfo->GetHitColModel() == nil) - modelInfo->CreateHitColModelSkinned(GetClump()); + CEntity *collidingEnt = m_pDamageEntity; +#ifndef VC_PED_PORTS + if (!bUsesCollision || m_fDamageImpulse <= 0.0f || m_nPedState == PED_DIE || !collidingEnt) { +#else + if (!bUsesCollision || ((!collidingEnt || m_fDamageImpulse <= 0.0f) && (!IsPlayer() || !bIsStuck)) || m_nPedState == PED_DIE) { #endif -} - -void -CPed::RemoveLighting(bool reset) -{ - CRenderer::RemoveVehiclePedLights(this, reset); -} + bHitSomethingLastFrame = false; + if (m_nPedStateTimer <= 500 && bIsInTheAir) { + if (m_nPedStateTimer) + m_nPedStateTimer--; + } else if (m_nPedStateTimer < 1001) { + m_nPedStateTimer = 0; + } + } else { + if (m_panicCounter == 50 && IsPedInControl()) { + SetWaitState(WAITSTATE_STUCK, nil); + // Leftover + /* + if (m_nPedType < PEDTYPE_COP) { -bool -CPed::SetupLighting(void) -{ - ActivateDirectional(); - SetAmbientColoursForPedsCarsAndObjects(); + } else { -#ifndef MASTER - // Originally this was being called through iteration of Sectors, but putting it here is better. - if (GetDebugDisplay() != 0 && !IsPlayer()) - DebugRenderOnePedText(); + } + */ +#ifndef VC_PED_PORTS + } else { +#else + } else if (collidingEnt) { #endif + switch (collidingEnt->GetType()) + { + case ENTITY_TYPE_BUILDING: + case ENTITY_TYPE_OBJECT: + { + CBaseModelInfo *collidingModel = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex()); + CColModel *collidingCol = collidingModel->GetColModel(); + if (collidingEnt->IsObject() && ((CObject*)collidingEnt)->m_nSpecialCollisionResponseCases != COLLRESPONSE_FENCEPART + || collidingCol->boundingBox.max.x < 3.0f + && collidingCol->boundingBox.max.y < 3.0f) { - 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); -} + if (!IsPlayer()) { + SetDirectionToWalkAroundObject(collidingEnt); + break; + } + } + if (IsPlayer()) { + bHitSomethingLastFrame = true; + break; + } -void -CPed::CalculateNewOrientation(void) -{ - if (CReplay::IsPlayingBack() || !IsPedInControl()) - return; + float angleToFaceWhenHit = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, + GetPosition().y, + m_vecDamageNormal.x + GetPosition().x, + m_vecDamageNormal.y + GetPosition().y); - SetHeading(m_fRotationCur); -} + float neededTurn = Abs(m_fRotationCur - angleToFaceWhenHit); -float -CPed::WorkOutHeadingForMovingFirstPerson(float offset) -{ - if (!IsPlayer()) - return 0.0f; + if (neededTurn > PI) + neededTurn = TWOPI - neededTurn; - CPad *pad0 = CPad::GetPad(0); - float leftRight = pad0->GetPedWalkLeftRight(); - float upDown = pad0->GetPedWalkUpDown(); - float &angle = ((CPlayerPed*)this)->m_fWalkAngle; + float oldDestRot = CGeneral::LimitRadianAngle(m_fRotationDest); - 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; - } + if (m_pedInObjective && + (m_objective == OBJECTIVE_GOTO_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT)) { - return CGeneral::LimitRadianAngle(offset + angle); -} + if (m_pedInObjective->IsPlayer() + && (neededTurn < DEGTORAD(20.0f) || m_panicCounter > 10)) { + if (CanPedJumpThis(collidingEnt)) { + SetJump(); + } else if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT) { + SetWaitState(WAITSTATE_LOOK_ABOUT, nil); + } else { + SetWaitState(WAITSTATE_PLAYANIM_TAXI, nil); + m_headingRate = 0.0f; + SetLookFlag(m_pedInObjective, true); + SetLookTimer(3000); + Say(SOUND_PED_TAXI_CALL); + } + } else { + m_pLookTarget = m_pedInObjective; + m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); + TurnBody(); + } + } else { + if (m_nPedType != PEDTYPE_COP && neededTurn < DEGTORAD(15.0f) && m_nWaitState == WAITSTATE_FALSE) { + if ((m_nStoredMoveState == PEDMOVE_RUN || m_nStoredMoveState == PEDMOVE_SPRINT) && m_vecDamageNormal.z < 0.3f) { + CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN); + if (!runAssoc) + runAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT); -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 (runAssoc && runAssoc->blendAmount > 0.9f && runAssoc->IsRunning()) { + SetWaitState(WAITSTATE_HITWALL, nil); + } + } + } + if (m_nPedState == PED_FLEE_POS) { + CVector2D fleePos = collidingEnt->GetPosition(); + uint32 oldFleeTimer = m_fleeTimer; + SetFlee(fleePos, 5000); + if (oldFleeTimer != m_fleeTimer) + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 500; - if (m_fRotationCur - PI > limitedRotDest) { - limitedRotDest += 2 * PI; - } else if(PI + m_fRotationCur < limitedRotDest) { - limitedRotDest -= 2 * PI; - } + } else { + if (m_nPedState == PED_FLEE_ENTITY && (neededTurn < DEGTORAD(25.0f) || m_panicCounter > 10)) { + m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; + m_collidingEntityWhileFleeing = collidingEnt; + m_collidingEntityWhileFleeing->RegisterReference((CEntity **) &m_collidingEntityWhileFleeing); - if (IsPlayer() && m_nPedState == PED_ATTACK) - headAmount /= 4.0f; + uint8 currentDir = Floor((PI + m_fRotationCur) / DEGTORAD(45.0f)); + uint8 nextDir; + ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, currentDir, &nextDir); - float neededTurn = limitedRotDest - m_fRotationCur; - if (neededTurn <= headAmount) { - if (neededTurn > (-headAmount)) - m_fRotationCur += neededTurn; - else - m_fRotationCur -= headAmount; - } else { - m_fRotationCur += headAmount; - } - } + } else { + if (neededTurn < DEGTORAD(60.0f)) { + CVector posToHead = m_vecDamageNormal * 4.0f; + posToHead.z = 0.0f; + posToHead += GetPosition(); + int closestNodeId = ThePaths.FindNodeClosestToCoors(posToHead, PATH_PED, + 999999.9f, false, false); + float angleToFace; - CVector2D forward(Sin(m_fRotationCur), Cos(m_fRotationCur)); + if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS) { + if (m_nPedState != PED_SEEK_POS && m_nPedState != PED_SEEK_CAR) { + if (m_nPedState == PED_WANDER_PATH) { + m_pNextPathNode = &ThePaths.m_pathNodes[closestNodeId]; + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + m_pNextPathNode->GetX(), m_pNextPathNode->GetY(), + GetPosition().x, GetPosition().y); + } else { + if (ThePaths.m_pathNodes[closestNodeId].GetX() == 0.0f + || ThePaths.m_pathNodes[closestNodeId].GetY() == 0.0f) { + posToHead = (3.0f * m_vecDamageNormal) + GetPosition(); + posToHead.x += (CGeneral::GetRandomNumber() % 512) / 250.0f - 1.0f; + posToHead.y += (CGeneral::GetRandomNumber() % 512) / 250.0f - 1.0f; + } else { + posToHead.x = ThePaths.m_pathNodes[closestNodeId].GetX(); + posToHead.y = ThePaths.m_pathNodes[closestNodeId].GetY(); + } + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + posToHead.x, posToHead.y, + GetPosition().x, GetPosition().y); - 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 (m_nPedState != PED_FOLLOW_PATH) + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 500; + } + } else { + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + ThePaths.m_pathNodes[closestNodeId].GetX(), + ThePaths.m_pathNodes[closestNodeId].GetY(), + GetPosition().x, + GetPosition().y); - if (CTimer::GetTimeStep() >= 0.01f) { - m_moved = m_moved * (1 / CTimer::GetTimeStep()); - } else { - m_moved = m_moved * (1 / 100.0f); - } + CVector2D distToNode = ThePaths.m_pathNodes[closestNodeId].GetPosition() - GetPosition(); + CVector2D distToSeekPos = m_vecSeekPos - GetPosition(); - if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam()) - || FindPlayerPed() != this || !CanStrafeOrMouseControl()) - return; + if (DotProduct2D(distToNode, distToSeekPos) < 0.0f) { + m_fRotationCur = m_fRotationDest; + break; + } + } + } else { + float angleToFaceAwayDamage = CGeneral::GetRadianAngleBetweenPoints( + m_vecDamageNormal.x, + m_vecDamageNormal.y, + 0.0f, + 0.0f); - float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur); - float pedSpeed = m_moved.Magnitude(); - float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur); + if (angleToFaceAwayDamage < m_fRotationCur) + angleToFaceAwayDamage += TWOPI; - if (localWalkAngle < -0.5f * PI) { - localWalkAngle += PI; - } else if (localWalkAngle > 0.5f * PI) { - localWalkAngle -= PI; - } + float neededTurn = angleToFaceAwayDamage - m_fRotationCur; - // 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; - } + if (neededTurn <= PI) { + angleToFace = 0.5f * neededTurn + m_fRotationCur; + m_fRotationCur += DEGTORAD(m_pedStats->m_headingChangeRate) * 2.0f; + } else { + angleToFace = m_fRotationCur - (TWOPI - neededTurn) * 0.5f; + m_fRotationCur -= DEGTORAD(m_pedStats->m_headingChangeRate) * 2.0f; + } - 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; + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 200; + if (m_nPedType == PEDTYPE_COP) { + if (m_pedInObjective) { + float angleToLookCriminal = CGeneral::GetRadianAngleBetweenPoints( + m_pedInObjective->GetPosition().x, + m_pedInObjective->GetPosition().y, + GetPosition().x, + GetPosition().y); - if (newUpperLegs.yaw < -DEGTORAD(100.0f)) { - newUpperLegs.yaw += PI; - } else if (newUpperLegs.yaw > DEGTORAD(100.0f)) { - newUpperLegs.yaw -= PI; - } + angleToLookCriminal = CGeneral::LimitRadianAngle(angleToLookCriminal); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); - 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); + if (angleToLookCriminal < angleToFace) + angleToLookCriminal += TWOPI; - 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 neededTurnToCriminal = angleToLookCriminal - angleToFace; -bool -CPed::CanBeDeleted(void) -{ - if (bInVehicle) - return false; + if (neededTurnToCriminal > DEGTORAD(150.0f) && neededTurnToCriminal < DEGTORAD(210.0f)) { + ((CCopPed*)this)->m_bStopAndShootDisabledZone = true; + } + } + } + } + m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); - switch (CharCreatedBy) { - case RANDOM_CHAR: - return true; - case MISSION_CHAR: - return false; - default: - return true; - } -} + if (m_fRotationCur - PI > m_fRotationDest) { + m_fRotationDest += TWOPI; + } else if (PI + m_fRotationCur < m_fRotationDest) { + m_fRotationDest -= TWOPI; + } -bool -CPed::CanPedDriveOff(void) -{ - if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) - return false; + if (oldDestRot == m_fRotationDest && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 200; + m_fRotationDest += HALFPI; + } + } + } + } + } - 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; -} + if (m_nPedState != PED_WANDER_PATH && m_nPedState != PED_FLEE_ENTITY) + m_pNextPathNode = nil; + + bHitSomethingLastFrame = true; + break; + } + case ENTITY_TYPE_VEHICLE: + { + CVehicle* collidingVeh = ((CVehicle*)collidingEnt); + float collidingVehSpeedSqr = collidingVeh->m_vecMoveSpeed.MagnitudeSqr(); + if (collidingVeh == m_pMyVehicle) + bCollidedWithMyVehicle = true; #ifdef VC_PED_PORTS -bool -CPed::CanPedJumpThis(CEntity *unused, CVector *damageNormal = nil) -{ - if (m_nSurfaceTouched == SURFACE_WATER) - return true; + float oldHealth = m_fHealth; + bool playerSufferSound = false; - CVector pos = GetPosition(); - CVector forwardOffset = GetForward(); - if (damageNormal && damageNormal->z > 0.17f) { - if (damageNormal->z > 0.9f) - return false; + if (collidingVehSpeedSqr <= 1.0f / 400.0f) { + if (IsPedInControl() + && (!IsPlayer() + || m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT + || m_objective == OBJECTIVE_RUN_TO_AREA + || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)) { - 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; - } + if (collidingVeh != m_pCurrentPhysSurface || IsPlayer()) { + if (!bVehEnterDoorIsBlocked) { + if (collidingVeh->GetStatus() != STATUS_PLAYER || CharCreatedBy == MISSION_CHAR) { - 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); + // VC calls SetDirectionToWalkAroundVehicle instead if ped is in PED_SEEK_CAR. + SetDirectionToWalkAroundObject(collidingVeh); + CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; + } else { + if (CTimer::GetTimeInMilliseconds() >= CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer + || m_nPedStateTimer >= CTimer::GetTimeInMilliseconds()) { - return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); -} -#endif + // VC calls SetDirectionToWalkAroundVehicle instead if ped is in PED_SEEK_CAR. + SetDirectionToWalkAroundObject(collidingVeh); + CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; -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; -} + } else if (m_fleeFrom != collidingVeh) { + SetFlee(collidingVeh, 4000); + bUsePedNodeSeek = false; + SetMoveState(PEDMOVE_WALK); + } + } + } + } else { + float angleLeftToCompleteTurn = Abs(m_fRotationCur - m_fRotationDest); + if (angleLeftToCompleteTurn < 0.01f && CanPedJumpThis(collidingVeh)) { + SetJump(); + } + } + } else if (IsPlayer() && !bIsInTheAir) { -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 (IsPedInControl() && ((CPlayerPed*)this)->m_fMoveSpeed == 0.0f + && !bIsLooking && CTimer::GetTimeInMilliseconds() > m_lookTimer && collidingVeh->pDriver) { - if (neededAngle < 0.0f) - neededAngle += TWOPI; - else if (neededAngle > TWOPI) - neededAngle -= TWOPI; + ((CPlayerPed*)this)->AnnoyPlayerPed(false); + SetLookFlag(collidingVeh, true); + SetLookTimer(1300); - float ourAngle = m_fRotationCur; - if (ourAngle < 0.0f) - ourAngle += TWOPI; - else if (ourAngle > TWOPI) - ourAngle -= TWOPI; + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + if (weaponType == WEAPONTYPE_UNARMED + || weaponType == WEAPONTYPE_BASEBALLBAT + || weaponType == WEAPONTYPE_COLT45 + || weaponType == WEAPONTYPE_UZI) { + bShakeFist = true; + } + } else { + SetLookFlag(collidingVeh, true); + SetLookTimer(500); + } + } + } else { + float adjustedImpulse = m_fDamageImpulse; + if (IsPlayer()) { + if (bIsStanding) { + float forwardVecAndDamageDirDotProd = DotProduct(m_vecAnimMoveDelta.y * GetForward(), m_vecDamageNormal); + if (forwardVecAndDamageDirDotProd < 0.0f) { + adjustedImpulse = forwardVecAndDamageDirDotProd * m_fMass + m_fDamageImpulse; + if (adjustedImpulse < 0.0f) + adjustedImpulse = 0.0f; + } + } + } + if (m_fMass / 20.0f < adjustedImpulse) + DMAudio.PlayOneShot(collidingVeh->m_audioEntityId, SOUND_CAR_PED_COLLISION, adjustedImpulse); - float neededTurn = Abs(neededAngle - ourAngle); + if (IsPlayer()) { + if (adjustedImpulse > 20.0f) + adjustedImpulse = 20.0f; - return neededTurn < threshold || TWOPI - threshold < neededTurn; -} + if (adjustedImpulse > 5.0f) { + if (adjustedImpulse <= 13.0f) + playerSufferSound = true; + else + Say(SOUND_PED_DAMAGE); + } -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; -} + CColModel* collidingCol = CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(); + CVector colMinVec = collidingCol->boundingBox.min; + CVector colMaxVec = collidingCol->boundingBox.max; -void -CPed::SetMoveState(eMoveState state) -{ - m_nMoveState = state; -} + CVector vehColCenterDist = collidingVeh->GetMatrix() * ((colMinVec + colMaxVec) * 0.5f) - GetPosition(); -void -CPed::SetObjectiveTimer(int time) -{ - if (time == 0) { - m_objectiveTimer = 0; - } else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) { - m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time; - } -} + // TLVC = To look vehicle center -void -CPed::ForceStoredObjective(eObjective objective) -{ - if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - m_prevObjective = m_objective; - return; - } + float angleToVehFront = collidingVeh->GetForward().Heading(); + float angleDiffFromLookingFrontTLVC = angleToVehFront - vehColCenterDist.Heading(); + angleDiffFromLookingFrontTLVC = CGeneral::LimitRadianAngle(angleDiffFromLookingFrontTLVC); - 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; - } -} + // I don't know why do we use that + float vehTopRightHeading = Atan2(colMaxVec.x - colMinVec.x, colMaxVec.y - colMinVec.y); -void -CPed::SetStoredObjective(void) -{ - if (m_objective == m_prevObjective) - return; + CVector vehDist = GetPosition() - collidingVeh->GetPosition(); + vehDist.Normalise(); - 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; - } -} + float vehRightVecAndSpeedDotProd; -void -CPed::RestorePreviousObjective(void) -{ - if (m_objective == OBJECTIVE_NONE) - return; + if (Abs(angleDiffFromLookingFrontTLVC) >= vehTopRightHeading && Abs(angleDiffFromLookingFrontTLVC) < PI - vehTopRightHeading) { + if (angleDiffFromLookingFrontTLVC <= 0.0f) { + vehRightVecAndSpeedDotProd = DotProduct(collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); - 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; + // vehRightVecAndSpeedDotProd < 0.1f = Vehicle being overturned or spinning to it's right? + if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { - if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT) { - m_objective = OBJECTIVE_NONE; - if (m_pMyVehicle) - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + // Car's right faces towards us and isn't coming directly to us + if (DotProduct(collidingVeh->GetRight(), GetForward()) < 0.0f + && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { + SetEvasiveStep(collidingVeh, 1); + } + } + } else { + vehRightVecAndSpeedDotProd = DotProduct(-1.0f * collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); - } else { - m_objective = m_prevObjective; - m_prevObjective = OBJECTIVE_NONE; - } - bObjectiveCompleted = false; -} + if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { + if (DotProduct(collidingVeh->GetRight(), GetForward()) > 0.0f + && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { + SetEvasiveStep(collidingVeh, 1); + } + } + } + } else { + vehRightVecAndSpeedDotProd = DotProduct(vehDist, collidingVeh->m_vecMoveSpeed); + } -void -CPed::SetLeader(CEntity *leader) -{ - m_leader = (CPed*)leader; + if (vehRightVecAndSpeedDotProd <= 0.1f) { + if (m_nPedState != PED_FIGHT) { + SetLookFlag(collidingVeh, true); + SetLookTimer(700); + } + } else { + bIsStanding = false; + CVector2D collidingEntMoveDir = -collidingVeh->m_vecMoveSpeed; + int dir = GetLocalDirection(collidingEntMoveDir); + SetFall(1000, (AnimationId)(dir + ANIM_KO_SKID_FRONT), false); - if(m_leader) - m_leader->RegisterReference((CEntity **)&m_leader); -} + float damage; + if (collidingVeh->m_modelIndex == MI_TRAIN) { + damage = 50.0f; + } else { + damage = 20.0f; + } -void -CPed::SetObjective(eObjective newObj, void *entity) -{ - if (DyingOrDead()) - return; + InflictDamage(collidingVeh, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, dir); + Say(SOUND_PED_DAMAGE); + } + } else { + KillPedWithCar(collidingVeh, m_fDamageImpulse); + } + + /* VC specific + if (m_pCollidingEntity != collidingEnt) + bPushedAlongByCar = true; + */ + } + if (m_fHealth < oldHealth && playerSufferSound) + Say(SOUND_PED_HIT); +#else + if (collidingVehSpeedSqr <= 1.0f / 400.0f) { + if (!IsPedInControl() + || IsPlayer() + && m_objective != OBJECTIVE_GOTO_AREA_ON_FOOT + && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER + && m_objective != OBJECTIVE_RUN_TO_AREA) { - if (m_prevObjective == newObj) { - // Why? - if (m_prevObjective != OBJECTIVE_NONE) - return; - } + if (IsPlayer() && !bIsInTheAir) { - if (entity == this) - return; + if (IsPedInControl() + && ((CPlayerPed*)this)->m_fMoveSpeed == 0.0f + && !bIsLooking + && CTimer::GetTimeInMilliseconds() > m_lookTimer + && collidingVeh->pDriver) { - 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; + ((CPlayerPed*)this)->AnnoyPlayerPed(false); + SetLookFlag(collidingVeh, true); + SetLookTimer(1300); - 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; + eWeaponType weaponType = GetWeapon()->m_eWeaponType; + if (weaponType == WEAPONTYPE_UNARMED + || weaponType == WEAPONTYPE_BASEBALLBAT + || weaponType == WEAPONTYPE_COLT45 + || weaponType == WEAPONTYPE_UZI) { + bShakeFist = true; + } + } else { + SetLookFlag(collidingVeh, true); + SetLookTimer(500); + } + } - break; - case OBJECTIVE_SET_LEADER: - if (m_leader == entity) - return; + } else if (!bVehEnterDoorIsBlocked) { + if (collidingVeh->GetStatus() != STATUS_PLAYER || CharCreatedBy == MISSION_CHAR) { - break; - default: - break; - } - } else { - if ((newObj == OBJECTIVE_LEAVE_CAR -#ifdef VC_PED_PORTS - || newObj == OBJECTIVE_LEAVE_CAR_AND_DIE -#endif - ) && !bInVehicle) - return; - } + SetDirectionToWalkAroundObject(collidingVeh); -#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; - } + } else if (CTimer::GetTimeInMilliseconds() >= CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer + || m_nPedStateTimer >= CTimer::GetTimeInMilliseconds()) { - switch (newObj) { - case OBJECTIVE_WAIT_IN_CAR_THEN_GET_OUT: + SetDirectionToWalkAroundObject(collidingVeh); + CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; - // 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; - } - } - } + } else if (m_fleeFrom != collidingVeh) { + SetFlee(collidingVeh, 4000); + bUsePedNodeSeek = false; + SetMoveState(PEDMOVE_WALK); + } + } + } else { + DMAudio.PlayOneShot(collidingVeh->m_audioEntityId, SOUND_CAR_PED_COLLISION, m_fDamageImpulse); + if (IsPlayer()) { + CColModel *collidingCol = CModelInfo::GetModelInfo(collidingVeh->GetModelIndex())->GetColModel(); + CVector colMinVec = collidingCol->boundingBox.min; + CVector colMaxVec = collidingCol->boundingBox.max; - break; - case OBJECTIVE_ENTER_CAR_AS_PASSENGER: - case OBJECTIVE_ENTER_CAR_AS_DRIVER: - if (m_nMoveState == PEDMOVE_STILL) - SetMoveState(PEDMOVE_RUN); + CVector vehColCenterDist = collidingVeh->GetMatrix() * ((colMinVec + colMaxVec) * 0.5f) - GetPosition(); - 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; - } -} + // TLVC = To look vehicle center -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(); + float angleToVehFront = collidingVeh->GetForward().Heading(); + float angleDiffFromLookingFrontTLVC = angleToVehFront - vehColCenterDist.Heading(); + angleDiffFromLookingFrontTLVC = CGeneral::LimitRadianAngle(angleDiffFromLookingFrontTLVC); - 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); - } -} + // I don't know why do we use that + float vehTopRightHeading = Atan2(colMaxVec.x - colMinVec.x, colMaxVec.y - colMinVec.y); -void -CPed::SetObjective(eObjective newObj) -{ - if (DyingOrDead()) - return; + CVector vehDist = GetPosition() - collidingVeh->GetPosition(); + vehDist.Normalise(); - 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; - } - } -} - -// 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(); -} + float vehRightVecAndSpeedDotProd; -bool -CPed::IsGangMember(void) -{ - return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; -} + if (Abs(angleDiffFromLookingFrontTLVC) >= vehTopRightHeading && Abs(angleDiffFromLookingFrontTLVC) < PI - vehTopRightHeading) { + if (angleDiffFromLookingFrontTLVC <= 0.0f) { + vehRightVecAndSpeedDotProd = DotProduct(collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); -void -CPed::InformMyGangOfAttack(CEntity *attacker) -{ - CPed *attackerPed; + // vehRightVecAndSpeedDotProd < 0.1f = Vehicle being overturned or spinning to it's right? + if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { - if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS) - return; + // Car's right faces towards us and isn't coming directly to us + if (DotProduct(collidingVeh->GetRight(), GetForward()) < 0.0f + && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { + SetEvasiveStep(collidingVeh, 1); + } + } + } else { + vehRightVecAndSpeedDotProd = DotProduct(-1.0f * collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); - if (attacker->IsPed()) { - attackerPed = (CPed*)attacker; - } else { - if (!attacker->IsVehicle()) - return; + if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { + if (DotProduct(collidingVeh->GetRight(), GetForward()) > 0.0f + && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { + SetEvasiveStep(collidingVeh, 1); + } + } + } + } else { + vehRightVecAndSpeedDotProd = DotProduct(vehDist, collidingVeh->m_vecMoveSpeed); + } - attackerPed = ((CVehicle*)attacker)->pDriver; - if (!attackerPed) - return; - } + if (vehRightVecAndSpeedDotProd <= 0.1f) { + if (m_nPedState != PED_FIGHT) { + SetLookFlag(collidingVeh, true); + SetLookTimer(700); + } + } else { + bIsStanding = false; + CVector2D collidingEntMoveDir = -collidingVeh->m_vecMoveSpeed; + int dir = GetLocalDirection(collidingEntMoveDir); + SetFall(1000, (AnimationId)(dir + ANIM_KO_SKID_FRONT), false); + CPed *driver = collidingVeh->pDriver; - if (attackerPed->m_nPedType == PEDTYPE_COP) - return; + float damage; + if (driver && driver->IsPlayer()) { + damage = vehRightVecAndSpeedDotProd * 1000.0f; + } else if (collidingVeh->GetModelIndex() == MI_TRAIN) { + damage = 50.0f; + } else { + damage = 20.0f; + } - 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); + InflictDamage(collidingVeh, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, dir); + Say(SOUND_PED_DAMAGE); + } + } else { + KillPedWithCar(collidingVeh, m_fDamageImpulse); + } + } +#endif + break; + } + case ENTITY_TYPE_PED: + { + CollideWithPed((CPed*)collidingEnt); + if (((CPed*)collidingEnt)->IsPlayer()) { + CPlayerPed *player = ((CPlayerPed*)collidingEnt); + Say(SOUND_PED_CHAT); + if (m_nMoveState > PEDMOVE_STILL && player->IsPedInControl()) { + if (player->m_fMoveSpeed < 1.0f) { + if (!player->bIsLooking) { + if (CTimer::GetTimeInMilliseconds() > player->m_lookTimer) { + player->AnnoyPlayerPed(false); + player->SetLookFlag(this, true); + player->SetLookTimer(1300); + eWeaponType weapon = player->GetWeapon()->m_eWeaponType; + if (weapon == WEAPONTYPE_UNARMED + || weapon == WEAPONTYPE_BASEBALLBAT + || weapon == WEAPONTYPE_COLT45 + || weapon == WEAPONTYPE_UZI) { + player->bShakeFist = true; + } + } + } + } + } + } + break; + } + default: + break; + } } - } - } -} - -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--; - + CVector forceDir; + if (!bIsInTheAir && m_nPedState != PED_JUMP #ifdef VC_PED_PORTS - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) - RestorePreviousObjective(); + && m_fDamageImpulse > 0.0f #endif + ) { - veh->m_nGettingInFlags &= ~GetCarDoorFlag(m_vehEnterType); - } + forceDir = m_vecDamageNormal; + forceDir.z = 0.0f; + if (!bIsStanding) { + forceDir *= 4.0f; + } else { + forceDir *= 0.5f; + } - bUsesCollision = true; + ApplyMoveForce(forceDir); + } + if ((bIsInTheAir && !DyingOrDead()) +#ifdef VC_PED_PORTS + || (!bIsStanding && !bWasStanding && m_nPedState == PED_FALL) +#endif + ) { + if (m_nPedStateTimer > 0 && m_nPedStateTimer <= 1000) { + forceDir = GetPosition() - m_vecHitLastPos; + } else { + m_nPedStateTimer = 0; + m_vecHitLastPos = GetPosition(); + forceDir = CVector(0.0f, 0.0f, 0.0f); + } - ReplaceWeaponWhenExitingVehicle(); + CVector offsetToCheck; + m_nPedStateTimer++; - if (DyingOrDead()) { - if (m_pVehicleAnim) { - m_pVehicleAnim->blendDelta = -4.0f; - m_pVehicleAnim->flags |= ASSOC_DELETEFADEDOUT; - m_pVehicleAnim->flags &= ~ASSOC_RUNNING; - } - } else - SetIdle(); + float adjustedTs = Max(CTimer::GetTimeStep(), 0.01f); - m_pVehicleAnim = nil; - - if (veh) { + CPad *pad0 = CPad::GetPad(0); + if ((m_nPedStateTimer <= 50.0f / (4.0f * adjustedTs) || m_nPedStateTimer * 0.01f <= forceDir.MagnitudeSqr()) + && (m_nCollisionRecords <= 1 || m_nPedStateTimer <= 50.0f / (2.0f * adjustedTs) || m_nPedStateTimer * 1.0f / 250.0f <= Abs(forceDir.z))) { + + if (m_nCollisionRecords == 1 && m_aCollisionRecords[0] != nil && m_aCollisionRecords[0]->IsBuilding() + && m_nPedStateTimer > 50.0f / (2.0f * adjustedTs) && m_nPedStateTimer * 1.0f / 250.0f > Abs(forceDir.z)) { + offsetToCheck.x = -forceDir.y; #ifdef VC_PED_PORTS - if (veh->AutoPilot.m_nCruiseSpeed == 0 && veh->VehicleCreatedBy == RANDOM_VEHICLE) + offsetToCheck.z = 1.0f; #else - if (veh->AutoPilot.m_nCruiseSpeed == 0) + offsetToCheck.z = 0.0f; #endif - veh->AutoPilot.m_nCruiseSpeed = 17; - } -} + offsetToCheck.y = forceDir.x; + offsetToCheck.Normalise(); -void -CPed::ReactToAttack(CEntity *attacker) -{ - if (IsPlayer() && attacker->IsPed()) { - InformMyGangOfAttack(attacker); - SetLookFlag(attacker, true); - SetLookTimer(700); - return; - } + CVector posToCheck = GetPosition() + offsetToCheck; -#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)) { + // These are either obstacle or ground to land, I don't know which one. + float obstacleForFlyingZ, obstacleForFlyingOtherDirZ; + CColPoint obstacleForFlying, obstacleForFlyingOtherDir; - if (m_pMyVehicle->VehicleCreatedBy == RANDOM_VEHICLE - && (m_pMyVehicle->GetStatus() == STATUS_SIMPLE || m_pMyVehicle->GetStatus() == STATUS_PHYSICS) - && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) { + // Check is there any room for being knocked up in reverse direction of force + if (CWorld::ProcessVerticalLine(posToCheck, -20.0f, obstacleForFlying, foundEnt, true, false, false, false, false, false, nil)) { + obstacleForFlyingZ = obstacleForFlying.point.z; + } else { + obstacleForFlyingZ = 500.0f; + } + + posToCheck = GetPosition() - offsetToCheck; - 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; - } + // Now check for direction of force this time + if (CWorld::ProcessVerticalLine(posToCheck, -20.0f, obstacleForFlyingOtherDir, foundEnt, true, false, false, false, false, false, nil)) { + obstacleForFlyingOtherDirZ = obstacleForFlyingOtherDir.point.z; + } else { + obstacleForFlyingOtherDirZ = 501.0f; + } +#ifdef VC_PED_PORTS + uint8 flyDir = 0; + float feetZ = GetPosition().z - FEET_OFFSET; + if ((obstacleForFlyingZ <= feetZ || obstacleForFlyingOtherDirZ >= 500.0f) && (obstacleForFlyingZ <= feetZ || obstacleForFlyingOtherDirZ <= feetZ)) { + if (obstacleForFlyingOtherDirZ > feetZ && obstacleForFlyingZ < 499.0f) + flyDir = 2; + } else { + flyDir = 1; + } - 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); + if (flyDir != 0 && !bSomeVCflag1) { + SetPosition((flyDir == 2 ? obstacleForFlyingOtherDir.point : obstacleForFlying.point)); + GetMatrix().GetPosition().z += FEET_OFFSET; + GetMatrix().UpdateRW(); + SetLanding(); + bIsStanding = true; + } +#endif + if (obstacleForFlyingZ < obstacleForFlyingOtherDirZ) { + offsetToCheck *= -1.0f; + } + offsetToCheck.z = 1.0f; + forceDir = 4.0f * offsetToCheck; + forceDir.z = 4.0f; + ApplyMoveForce(forceDir); - float limitedLookDir = CGeneral::LimitRadianAngle(m_fLookDirection); - float currentRot = m_fRotationCur; + GetMatrix().GetPosition() += 0.25f * offsetToCheck; - if (currentRot - PI > limitedLookDir) - limitedLookDir += 2 * PI; - else if (PI + currentRot < limitedLookDir) - limitedLookDir -= 2 * PI; + m_fRotationCur = CGeneral::GetRadianAngleBetweenPoints(offsetToCheck.x, offsetToCheck.y, 0.0f, 0.0f); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + m_fRotationDest = m_fRotationCur; + SetHeading(m_fRotationCur); - float neededTurn = currentRot - limitedLookDir; - m_fRotationDest = limitedLookDir; + if (m_nPedState != PED_FALL && !bIsPedDieAnimPlaying) { + SetFall(1000, ANIM_KO_SKID_BACK, true); + } + bIsInTheAir = false; + } else if (m_vecDamageNormal.z > 0.4f) { +#ifndef VC_PED_PORTS + forceDir = m_vecDamageNormal; + forceDir.z = 0.0f; + forceDir.Normalise(); + ApplyMoveForce(2.0f * forceDir); +#else + if (m_nPedState == PED_JUMP) { + if (m_nWaitTimer <= 2000) { + if (m_nWaitTimer < 1000) + m_nWaitTimer += CTimer::GetTimeStep() * 0.02f * 1000.0f; + } else { + m_nWaitTimer = 0; + } + } + forceDir = m_vecDamageNormal; + forceDir.z = 0.0f; + forceDir.Normalise(); + if (m_nPedState != PED_JUMP || m_nWaitTimer >= 300) { + ApplyMoveForce(2.0f * forceDir); + } else { + ApplyMoveForce(-4.0f * forceDir); + } +#endif + } + } else if ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 3) & 7) { + if (IsPlayer() && m_nPedState != PED_JUMP && pad0->JumpJustDown()) { + int16 padWalkX = pad0->GetPedWalkLeftRight(); + int16 padWalkY = pad0->GetPedWalkUpDown(); + if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -padWalkX, padWalkY); + m_fRotationDest -= TheCamera.Orientation; + m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); + m_fRotationCur = m_fRotationDest; + SetHeading(m_fRotationCur); + } + SetJump(); + m_nPedStateTimer = 0; + m_vecHitLastPos = GetPosition(); - if (Abs(neededTurn) > 0.05f) { - turnDone = false; - currentRot -= neededTurn * 0.2f; - } + // Why? forceDir is unused after this point. + forceDir = CVector(0.0f, 0.0f, 0.0f); + } else if (IsPlayer()) { + int16 padWalkX = pad0->GetPedWalkLeftRight(); + int16 padWalkY = pad0->GetPedWalkUpDown(); + if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { + m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -padWalkX, padWalkY); + m_fRotationDest -= TheCamera.Orientation; + m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); + m_fRotationCur = m_fRotationDest; + SetHeading(m_fRotationCur); + } + CAnimBlendAssociation *jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_GLIDE); - m_fRotationCur = currentRot; - m_fLookDirection = limitedLookDir; - return turnDone; -} + if (!jumpAssoc) + jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_GLIDE); -void -CPed::Chat(void) -{ - // We're already looking to our partner - if (bIsLooking && TurnBody()) - ClearLookFlag(); + if (jumpAssoc) { + jumpAssoc->blendDelta = -3.0f; + jumpAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + if (m_nPedState == PED_JUMP) + m_nPedState = PED_IDLE; + } else { + CAnimBlendAssociation *jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_GLIDE); - if (!m_pLookTarget || !m_pLookTarget->IsPed()) { - ClearChat(); - return; - } + if (!jumpAssoc) + jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_GLIDE); - CPed *partner = (CPed*) m_pLookTarget; + if (jumpAssoc) { + jumpAssoc->blendDelta = -3.0f; + jumpAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } + } else { + offsetToCheck = GetPosition(); + offsetToCheck.z += 0.5f; - 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; + if (CWorld::ProcessVerticalLine(offsetToCheck, GetPosition().z - FEET_OFFSET, foundCol, foundEnt, true, true, false, true, false, false, nil)) { +#ifdef VC_PED_PORTS + if (!bSomeVCflag1 || FEET_OFFSET + foundCol.point.z < GetPosition().z) { + GetMatrix().GetPosition().z = FEET_OFFSET + foundCol.point.z; + GetMatrix().UpdateRW(); + if (bSomeVCflag1) + bSomeVCflag1 = false; + } +#else + GetMatrix().GetPosition().z = FEET_OFFSET + foundCol.point.z; + GetMatrix().UpdateRW(); +#endif + SetLanding(); + bIsStanding = true; + } + } + } else if (m_nPedStateTimer < 1001) { + m_nPedStateTimer = 0; } - 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); + if (bIsDucking) + Duck(); - 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; + if (bStartWanderPathOnFoot) { + if (IsPedInControl()) { + ClearAll(); + SetWanderPath(m_nPathDir); + bStartWanderPathOnFoot = false; + } else if (m_nPedState == PED_DRIVING) { + bWanderPathAfterExitingCar = true; + SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); + } } - 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); - } -} + if (!bIsStanding && m_vecMoveSpeed.z > 0.25f) { + float airResistance = Pow(0.95f, CTimer::GetTimeStep()); -#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); + m_vecMoveSpeed *= airResistance; + } +#ifdef VC_PED_PORTS + if (IsPlayer() || !bIsStanding || m_vecMoveSpeed.x != 0.0f || m_vecMoveSpeed.y != 0.0f || m_vecMoveSpeed.z != 0.0f + || (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) + || m_vecAnimMoveDelta.x != 0.0f || m_vecAnimMoveDelta.y != 0.0f + || m_nPedState == PED_JUMP + || bIsInTheAir + || m_pCurrentPhysSurface) { - 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; - } + CPhysical::ProcessControl(); + } else { + bHasContacted = false; + bIsInSafePosition = false; + bWasPostponed = false; + bHasHitWall = false; + m_nCollisionRecords = 0; + bHasCollided = false; + m_nDamagePieceType = 0; + m_fDamageImpulse = 0.0f; + m_pDamageEntity = nil; + m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f); + m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f); + } +#else + CPhysical::ProcessControl(); #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); - } + if (m_nPedState != PED_DIE || bIsPedDieAnimPlaying) { + if (m_nPedState != PED_DEAD) { + CalculateNewVelocity(); + CalculateNewOrientation(); + } + UpdatePosition(); + PlayFootSteps(); + if (IsPedInControl() && !bIsStanding && !m_pDamageEntity && CheckIfInTheAir()) { + SetInTheAir(); +#ifdef VC_PED_PORTS + bSomeVCflag1 = false; #endif - SetIdle(); - - gPhoneInfo.m_aPhones[m_phoneId].m_nState = PHONE_STATE_FREE; -#ifndef PEDS_REPORT_CRIMES_ON_PHONE - m_phoneId = -1; + } +#ifdef VC_PED_PORTS + if (bSomeVCflag1) { + CVector posToCheck = GetPosition(); + posToCheck.z += 0.9f; + if (!CWorld::TestSphereAgainstWorld(posToCheck, 0.2f, this, true, true, false, true, false, false)) + bSomeVCflag1 = false; + } #endif + ProcessObjective(); + if (!bIsAimingGun) { + if (bIsRestoringGun) + RestoreGunPosition(); + } else { + AimGun(); + } - // Because SetWanderPath is now done async in ReportPhonePutDownCB -#ifdef PEDS_REPORT_CRIMES_ON_PHONE - return false; -#else - return true; -#endif -} + if (bIsLooking) { + MoveHeadToLook(); + } else if (bIsRestoringLook) { + RestoreHeadPosition(); + } -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 (bIsInTheAir) + InTheAir(); - if (m_facePhoneStart) { - m_lookTimer = 0; - SetLookFlag(phoneDir, true); - m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; - m_facePhoneStart = false; - } + if (bUpdateAnimHeading) { + if (m_nPedState != PED_GETUP && m_nPedState != PED_FALL) { + m_fRotationCur -= HALFPI; + m_fRotationDest = m_fRotationCur; + bUpdateAnimHeading = 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; - } + if (m_nWaitState != WAITSTATE_FALSE) + Wait(); - 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); + if (m_nPedState != PED_IDLE) { + CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); + if(idleAssoc) { + idleAssoc->blendDelta = -8.0f; + idleAssoc->flags |= ASSOC_DELETEFADEDOUT; + } + } - SetLookFlag(phoneDir, false); - phoneDir = CGeneral::LimitAngle(phoneDir); - m_moved = CVector2D(0.0f, 0.0f); + switch (m_nPedState) { + case PED_IDLE: + Idle(); + break; + case PED_LOOK_ENTITY: + case PED_LOOK_HEADING: + Look(); + break; + case PED_WANDER_RANGE: + WanderRange(); + CheckAroundForPossibleCollisions(); + break; + case PED_WANDER_PATH: + WanderPath(); + break; + case PED_SEEK_POS: + case PED_SEEK_ENTITY: + case PED_PURSUE: + case PED_SNIPER_MODE: + case PED_ROCKET_MODE: + case PED_DUMMY: + case PED_FACE_PHONE: + case PED_MAKE_CALL: + case PED_MUG: + case PED_AI_CONTROL: + case PED_FOLLOW_ROUTE: + case PED_CPR: + case PED_SOLICIT: + case PED_BUY_ICECREAM: + case PED_STEP_AWAY: + case PED_UNKNOWN: + case PED_STATES_NO_AI: + case PED_JUMP: + case PED_STAGGER: + case PED_DIVE_AWAY: + case PED_STATES_NO_ST: + case PED_ARREST_PLAYER: + case PED_PASSENGER: + case PED_TAXI_PASSENGER: + case PED_OPEN_DOOR: + case PED_DEAD: + case PED_DRAG_FROM_CAR: + case PED_EXIT_CAR: + case PED_STEAL_CAR: + break; + case PED_ENTER_CAR: + case PED_CARJACK: + { +#ifdef CANCELLABLE_CAR_ENTER + if (!IsPlayer() || !m_pVehicleAnim) + break; - if (currentRot - 180.0f > phoneDir) - phoneDir += 2 * 180.0f; - else if (180.0f + currentRot < phoneDir) - phoneDir -= 2 * 180.0f; + CPad *pad = CPad::GetPad(0); - float neededTurn = currentRot - phoneDir; + if (pad->ArePlayerControlsDisabled()) + break; - 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 -} + int vehAnim = m_pVehicleAnim->animId; -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; -} + static bool cancelJack = false; + int16 padWalkX = pad->GetPedWalkLeftRight(); + int16 padWalkY = pad->GetPedWalkUpDown(); + if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { + if (vehAnim == ANIM_CAR_OPEN_LHS || vehAnim == ANIM_CAR_OPEN_RHS || vehAnim == ANIM_COACH_OPEN_L || vehAnim == ANIM_COACH_OPEN_R || + vehAnim == ANIM_VAN_OPEN_L || vehAnim == ANIM_VAN_OPEN) { -#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; + if (!m_pMyVehicle->pDriver) { + cancelJack = false; + bCancelEnteringCar = true; + } else + cancelJack = true; + } else if (vehAnim == ANIM_CAR_QJACK && m_pVehicleAnim->GetTimeLeft() > 0.75f) { + cancelJack = true; + } else if (vehAnim == ANIM_CAR_PULLOUT_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_RHS || vehAnim == ANIM_CAR_PULLOUT_RHS) { + bCancelEnteringCar = true; + cancelJack = false; + } + } + if (cancelJack && vehAnim == ANIM_CAR_QJACK && m_pVehicleAnim->GetTimeLeft() > 0.75f && m_pVehicleAnim->GetTimeLeft() < 0.78f) { + cancelJack = false; + QuitEnteringCar(); + RestorePreviousObjective(); + } + if (cancelJack && (vehAnim == ANIM_CAR_PULLOUT_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_RHS || vehAnim == ANIM_CAR_PULLOUT_RHS)) { + cancelJack = false; + bCancelEnteringCar = true; + } +#endif + break; + } + case PED_FLEE_POS: + ms_vec2DFleePosition.x = m_fleeFromPosX; + ms_vec2DFleePosition.y = m_fleeFromPosY; + Flee(); + break; + case PED_FLEE_ENTITY: + if (!m_fleeFrom) { + SetIdle(); + break; + } - for (i = 0; i < NUMEVENTS; i++) { - if (gaEvent[i].type == EVENT_NULL || gaEvent[i].type > EVENT_CAR_SET_ON_FIRE) - continue; + if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) + break; - // 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; + ms_vec2DFleePosition = m_fleeFrom->GetPosition(); + Flee(); + break; + case PED_FOLLOW_PATH: + FollowPath(); + break; + case PED_PAUSE: + Pause(); + break; + case PED_ATTACK: + Attack(); + break; + case PED_FIGHT: + Fight(); + break; + case PED_CHAT: + Chat(); + break; + case PED_AIM_GUN: + if (m_pPointGunAt && m_pPointGunAt->IsPed() +#ifdef FIX_BUGS + && !GetWeapon()->IsTypeMelee() +#endif + && ((CPed*)m_pPointGunAt)->CanSeeEntity(this, CAN_SEE_ENTITY_ANGLE_THRESHOLD * 2)) { + ((CPed*)m_pPointGunAt)->ReactToPointGun(this); + } + PointGunAt(); + break; + case PED_SEEK_CAR: + SeekCar(); + break; + case PED_SEEK_IN_BOAT: + SeekBoatPosition(); + break; + case PED_INVESTIGATE: + InvestigateEvent(); + break; + case PED_ON_FIRE: + if (IsPlayer()) + break; - if (victim && gaEvent[i].entityRef != victimRef) - continue; + if (CTimer::GetTimeInMilliseconds() <= m_fleeTimer) { + if (m_fleeFrom) { + ms_vec2DFleePosition = m_fleeFrom->GetPosition(); + } else { + ms_vec2DFleePosition.x = m_fleeFromPosX; + ms_vec2DFleePosition.y = m_fleeFromPosY; + } + Flee(); + } else { + if (m_pFire) + m_pFire->Extinguish(); + } + break; + case PED_FALL: + Fall(); + break; + case PED_GETUP: + SetGetUp(); + break; + case PED_ENTER_TRAIN: + EnterTrain(); + break; + case PED_EXIT_TRAIN: + ExitTrain(); + break; + case PED_DRIVING: + { + if (!m_pMyVehicle) { + bInVehicle = false; + FlagToDestroyWhenNextProcessed(); + return; + } - if (gaEvent[i].criminal != player) - continue; + if (m_pMyVehicle->pDriver != this || m_pMyVehicle->IsBoat()) { + LookForSexyPeds(); + LookForSexyCars(); + break; + } - dist = (GetPosition() - gaEvent[i].posn).Magnitude(); - if (dist < mindist) { - mindist = dist; - event = i; - } - } + if (m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE || !m_pMyVehicle->pDriver->IsPlayer()) { + break; + } - 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; - } - } - } + CPad* pad = CPad::GetPad(0); - return event; -} +#ifdef CAR_AIRBREAK + if (!pad->ArePlayerControlsDisabled()) { + if (pad->GetHorn()) { + float c = Cos(m_fRotationCur); + float s = Sin(m_fRotationCur); + m_pMyVehicle->GetRight() = CVector(1.0f, 0.0f, 0.0f); + m_pMyVehicle->GetForward() = CVector(0.0f, 1.0f, 0.0f); + m_pMyVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f); + if (pad->GetAccelerate()) { + m_pMyVehicle->ApplyMoveForce(GetForward() * 30.0f); + } else if (pad->GetBrake()) { + m_pMyVehicle->ApplyMoveForce(-GetForward() * 30.0f); + } else { + int16 lr = pad->GetSteeringLeftRight(); + if (lr < 0) { + //m_pMyVehicle->ApplyTurnForce(20.0f * -GetRight(), GetForward()); + m_pMyVehicle->ApplyMoveForce(-GetRight() * 30.0f); + } else if (lr > 0) { + m_pMyVehicle->ApplyMoveForce(GetRight() * 30.0f); + } else { + m_pMyVehicle->ApplyMoveForce(0.0f, 0.0f, 50.0f); + } + } + } + } #endif + float steerAngle = m_pMyVehicle->m_fSteerAngle; + CAnimBlendAssociation *lDriveAssoc; + CAnimBlendAssociation *rDriveAssoc; + CAnimBlendAssociation *lbAssoc; + CAnimBlendAssociation *sitAssoc; + if (m_pMyVehicle->bLowVehicle) { + sitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT); -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; + if (!sitAssoc || sitAssoc->blendAmount < 1.0f) { + break; + } - 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; - } + lDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_L); + lbAssoc = nil; + rDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_R); + } else { + sitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT); - if (actualEntity) { - m_pEventEntity = actualEntity; - m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); - bGonnaInvestigateEvent = true; - } else - bGonnaInvestigateEvent = false; + if (!sitAssoc || sitAssoc->blendAmount < 1.0f) { + break; + } - 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; - } + lDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_L); + rDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_R); + lbAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); - bGonnaInvestigateEvent = false; - return false; -} + if (lbAssoc && + TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON + && TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_LEFT) { + lbAssoc->blendDelta = -1000.0f; + } + } -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; -} + CAnimBlendAssociation *driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); -PointBlankNecessity -CPed::CheckForPointBlankPeds(CPed *pedToVerify) -{ - float pbDistance = 1.1f; - if (GetWeapon()->IsType2Handed()) - pbDistance = 1.6f; + if (!driveByAssoc) + driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); - for (int i = 0; i < m_numNearPeds; i++) { - CPed *nearPed = m_nearPeds[i]; + if (m_pMyVehicle->bLowVehicle || m_pMyVehicle->m_fGasPedal >= 0.0f || driveByAssoc) { + if (steerAngle == 0.0f || driveByAssoc) { + if (lDriveAssoc) + lDriveAssoc->blendAmount = 0.0f; + if (rDriveAssoc) + rDriveAssoc->blendAmount = 0.0f; - if (!pedToVerify || pedToVerify == nearPed) { + } else if (steerAngle <= 0.0f) { + if (lDriveAssoc) + lDriveAssoc->blendAmount = 0.0f; - CVector diff = nearPed->GetPosition() - GetPosition(); - if (diff.Magnitude() < pbDistance) { + if (rDriveAssoc) + rDriveAssoc->blendAmount = clamp(steerAngle * -100.0f / 61.0f, 0.0f, 1.0f); + else if (m_pMyVehicle->bLowVehicle) + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_LOW_R); + else + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_R); - float neededAngle = CGeneral::GetRadianAngleBetweenPoints( - nearPed->GetPosition().x, nearPed->GetPosition().y, - GetPosition().x, GetPosition().y); - neededAngle = CGeneral::LimitRadianAngle(neededAngle); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); + } else { + if (rDriveAssoc) + rDriveAssoc->blendAmount = 0.0f; - float neededTurn = Abs(neededAngle - m_fRotationCur); + if (lDriveAssoc) + lDriveAssoc->blendAmount = clamp(steerAngle * 100.0f / 61.0f, 0.0f, 1.0f); + else if (m_pMyVehicle->bLowVehicle) + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_LOW_L); + else + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_L); + } - if (neededTurn > PI) - neededTurn = 2*PI - neededTurn; + if (lbAssoc) + lbAssoc->blendDelta = -4.0f; + } else { + + if ((TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON + || TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking != LOOKING_LEFT) + && (!lbAssoc || lbAssoc->blendAmount < 1.0f)) { + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LB, 4.0f); + } + } + break; + } + case PED_DIE: + Die(); + break; + case PED_HANDS_UP: + if (m_pedStats->m_temper <= 50) { + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSCOWER)) { + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER); + Say(SOUND_PED_HANDS_COWER); + } + } else if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSUP)) { + CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSUP); + Say(SOUND_PED_HANDS_UP); + } + break; + default: break; + } + SetMoveAnim(); + if (bPedIsBleeding) { + if (CGame::nastyGame) { + if (!(CTimer::GetFrameCounter() & 3)) { + CVector cameraDist = GetPosition() - TheCamera.GetPosition(); + if (cameraDist.MagnitudeSqr() < sq(50.0f)) { - if (nearPed->OnGroundOrGettingUp() || nearPed->m_nPedState == PED_DIVE_AWAY) - return NO_POINT_BLANK_PED; + float length = (CGeneral::GetRandomNumber() & 127) * 0.0015f + 0.15f; + CVector bloodPos( + ((CGeneral::GetRandomNumber() & 127) - 64) * 0.007f, + ((CGeneral::GetRandomNumber() & 127) - 64) * 0.007f, + 1.0f); + bloodPos += GetPosition(); - if (neededTurn < CAN_SEE_ENTITY_ANGLE_THRESHOLD) { - if (pedToVerify == nearPed) - return POINT_BLANK_FOR_WANTED_PED; - else - return POINT_BLANK_FOR_SOMEONE_ELSE; + CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, length, 0.0f, + 0.0f, -length, 255, 255, 0, 0, 4.0f, (CGeneral::GetRandomNumber() & 4095) + 2000, 1.0f); + } + } } } + ServiceTalking(); + if (bInVehicle && !m_pMyVehicle) + bInVehicle = false; +#ifndef VC_PED_PORTS + m_pCurrentPhysSurface = nil; +#endif + } else { + if (bIsStanding && (!m_pCurrentPhysSurface || IsPlayer()) + || bIsInWater || !bUsesCollision) { + SetDead(); + } + m_pCurrentPhysSurface = nil; } } - return NO_POINT_BLANK_PED; } -bool -CPed::CheckIfInTheAir(void) +int32 +CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) { - if (bInVehicle) - return false; + bool collidedWithBoat = false; + bool belowTorsoCollided = false; + float gravityEffect = -0.15f * CTimer::GetTimeStep(); + CColPoint intersectionPoint; + CColLine ourLine; - CVector pos = GetPosition(); - CColPoint foundColPoint; - CEntity *foundEntity; + CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); + CColModel *hisCol = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex())->GetColModel(); - 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; -} + if (!bUsesCollision) + return false; -void -CPed::ClearAll(void) -{ - if (!IsPedInControl() && m_nPedState != PED_DEAD) - return; + if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) + collidedWithBoat = true; - 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; + // ofc we're not vehicle + if (!m_bIsVehicleBeingShifted && !bSkipLineCol #ifdef VC_PED_PORTS - ClearPointGunAt(); -#else - ClearAimFlag(); - ClearLookFlag(); + && !collidingEnt->IsPed() #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; - + ) { + if (!bCollisionProcessed) { #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 + 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 - 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; + m_vecMoveSpeed.z = 0.0f; + bIsStanding = true; + } else { + m_collPoly.valid = false; + m_fCollisionSpeed = 0.0f; + bHitSteepSlope = false; + } + } } - } - weaponAssoc->blendDelta = -8.0f; - weaponAssoc->flags &= ~ASSOC_RUNNING; - weaponAssoc->flags |= ASSOC_DELETEFADEDOUT; - weaponAssoc->SetDeleteCallback(FinishedAttackCB, this); -} - -void -CPed::StopNonPartialAnims(void) -{ - CAnimBlendAssociation *assoc; - for (assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); assoc; assoc = RpAnimBlendGetNextAssociation(assoc)) { - if (!assoc->IsPartial()) - assoc->flags &= ~ASSOC_RUNNING; - } -} + if (!bStillOnValidPoly) { + CVector potentialCenter = GetPosition(); + potentialCenter.z = GetPosition().z - 0.52f; -void -CPed::SetStoredState(void) -{ - if (m_nLastPedState != PED_NONE || !CanPedReturnToState()) - return; + // 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 (m_nPedState == PED_WANDER_PATH) { - bFindNewNodeAfterStateRestore = true; - if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) - m_nMoveState = PEDMOVE_WALK; - } + 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 (m_nPedState != PED_IDLE) + 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_nLastPedState = m_nPedState; - if (m_nMoveState >= m_nPrevMoveState) - m_nPrevMoveState = m_nMoveState; - } -} + 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) { -void -CPed::SetDie(AnimationId animId, float delta, float speed) -{ - CPlayerPed *player = FindPlayerPed(); - if (player == this) { - if (!player->m_bCanBeDamaged) - return; - } + 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; - m_threatEntity = nil; - if (DyingOrDead()) - return; + 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); + } - if (m_nPedState == PED_FALL || m_nPedState == PED_GETUP) - delta *= 0.5f; + InflictDamage(collidingEnt, WEAPONTYPE_FALL, damage, PEDPIECE_TORSO, dir); + if (IsPlayer() && damage2 > 5.0f) + Say(SOUND_PED_LAND); - 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(); - } + } 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); - 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; + 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); - dieAssoc->flags &= ~ASSOC_FADEOUTWHENDONE; - if (dieAssoc->IsRunning()) { - dieAssoc->SetFinishCallback(FinishDieAnimCB, this); - bIsPedDieAnimPlaying = true; + } 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; + } + } } } - Say(SOUND_PED_DEATH); - if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK) - QuitEnteringCar(); - if (!bInVehicle) - StopNonPartialAnims(); + 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); - m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); + 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; } -bool -CPed::InflictDamage(CEntity *damagedBy, eWeaponType method, float damage, ePedPieceTypes pedPiece, uint8 direction) +static void +particleProduceFootSplash(CPed *ped, CVector const &pos, float size, int times) { - 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; +#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); - player->AnnoyPlayerPed(false); + 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 +} - 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; +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; + } +} - float healthImpact; - if (IsPlayer()) - healthImpact = damage * 0.33f; - else - healthImpact = damage * m_pedStats->m_defendWeakness; +void +CPed::PlayFootSteps(void) +{ + if (bDoBloodyFootprints) { + if (m_bloodyFootprintCountOrDeathTime > 0 && m_bloodyFootprintCountOrDeathTime < 300) { + m_bloodyFootprintCountOrDeathTime--; - 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 (m_bloodyFootprintCountOrDeathTime == 0) + bDoBloodyFootprints = 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; + if (!bIsStanding) + return; - 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; + CAnimBlendAssociation *assoc = RpAnimBlendClumpGetFirstAssociation(GetClump()); + CAnimBlendAssociation *walkRunAssoc = nil; + float walkRunAssocBlend = 0.0f, idleAssocBlend = 0.0f; - 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; + 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; } } - if (m_fArmour != 0.0f && method != WEAPONTYPE_DROWNING) { - if (player == this) - CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss = CTimer::GetTimeInMilliseconds(); +#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); + } - if (healthImpact < m_fArmour) { - m_fArmour = m_fArmour - healthImpact; - healthImpact = 0.0f; - } else { - healthImpact = healthImpact - m_fArmour; - m_fArmour = 0.0f; + { + 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 (healthImpact != 0.0f) { - if (player == this) - CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss = CTimer::GetTimeInMilliseconds(); + 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; - m_lastWepDam = method; - } + if (currentTime >= stepStart && currentTime - walkRunAssoc->timeStep < stepStart) + stepPart = 1; + else if (currentTime >= stepEnd && currentTime - walkRunAssoc->timeStep < stepEnd) + stepPart = 2; - if (m_fHealth - healthImpact >= 1.0f && !willLinger) { - m_fHealth -= healthImpact; - return false; - } + 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); - 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); - } + CVector forward = GetForward(); + + footPos.z -= 0.1f; + footPos += 0.2f * forward; + + if (bDoBloodyFootprints) { + CVector2D top(forward * 0.26f); + CVector2D right(GetRight() * 0.14f); - CPed *driverOfVeh = m_pMyVehicle->pDriver; - if (driverOfVeh && driverOfVeh != this && damagedBy) - driverOfVeh->ReactToAttack(damagedBy); + 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 (damagedBy == FindPlayerPed() || damagedBy && damagedBy == FindPlayerVehicle()) { - CDarkel::RegisterKillByPlayer(this, method, headShot); - m_threatEntity = FindPlayerPed(); + if (m_bloodyFootprintCountOrDeathTime <= 20) { + m_bloodyFootprintCountOrDeathTime = 0; + bDoBloodyFootprints = false; } else { - CDarkel::RegisterKillNotByPlayer(this, method); + 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 - m_fHealth = 1.0f; - return false; + { + particleProduceFootSplash(this, footPos, 0.15f, 4); + } } - 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 (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 (damagedBy == player || damagedBy && damagedBy == FindPlayerVehicle()) { + if (particleSize < 0.25f) + particleSize = 0.25f; - // 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; + if (particleSize > 0.75f) + particleSize = 0.75f; - return true; - } -} + CVector particlePos = GetPosition() + GetForward() * 0.3f; + particlePos.z -= 1.2f; -void -CPed::ClearFlee(void) -{ - RestorePreviousState(); - bUsePedNodeSeek = false; - m_standardTimer = 0; - m_fleeTimer = 0; -} + CVector particleDir = m_vecMoveSpeed * -0.75f; -void -CPed::ClearFall(void) -{ - SetGetUp(); + 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::SetGetUp(void) +// Actually GetLocalDirectionTo(Turn/Look) +int +CPed::GetLocalDirection(const CVector2D &posOffset) { - if (m_nPedState == PED_GETUP && bGetUpAnimStarted) - return; + int direction; + float angle; - if (!CanSetPedState()) - return; + for (angle = posOffset.Heading() - m_fRotationCur + DEGTORAD(45.0f); angle < 0.0f; angle += TWOPI); - 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)) { + for (direction = RADTODEG(angle)/90.0f; direction > 3; direction -= 4); - bGetUpAnimStarted = false; - if (IsPlayer()) - InflictDamage(nil, WEAPONTYPE_RUNOVERBYCAR, CTimer::GetTimeStep(), PEDPIECE_TORSO, 0); - else { - if (!CPad::GetPad(0)->ArePlayerControlsDisabled()) - return; + // 0-forward, 1-left, 2-backward, 3-right. + return direction; +} - 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; - } +#ifdef NEW_WALK_AROUND_ALGORITHM +CVector +LocalPosForWalkAround(CVector2D colMin, CVector2D colMax, int walkAround, uint32 enterDoorNode, bool itsVan) { + switch (walkAround) { + case 0: + if (enterDoorNode == CAR_DOOR_LF) + return CVector(colMin.x, colMax.y - 1.0f, 0.0f); + case 1: + return CVector(colMin.x, colMax.y, 0.0f); + case 2: + case 3: + if (walkAround == 3 && enterDoorNode == CAR_DOOR_RF) + return CVector(colMax.x, colMax.y - 1.0f, 0.0f); - 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); + return CVector(colMax.x, colMax.y, 0.0f); + case 4: + if (enterDoorNode == CAR_DOOR_RR && !itsVan) + return CVector(colMax.x, colMin.y + 1.0f, 0.0f); + case 5: + return CVector(colMax.x, colMin.y, 0.0f); + case 6: + case 7: + if (walkAround == 7 && enterDoorNode == CAR_DOOR_LR && !itsVan) + return CVector(colMin.x, colMin.y + 1.0f, 0.0f); - animAssoc->SetFinishCallback(PedGetupCB,this); - } else { - m_fHealth = 0.0f; - SetDie(NUM_ANIMS, 4.0f, 0.0f); + return CVector(colMin.x, colMin.y, 0.0f); + default: + return CVector(0.0f, 0.0f, 0.0f); } } -void -CPed::ClearInvestigateEvent(void) +bool +CanWeSeeTheCorner(CVector2D dist, CVector2D fwdOffset) { - 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; + // because fov isn't important if dist is more then 5 unit, we want shortest way + if (dist.Magnitude() > 5.0f) + return true; - bGonnaInvestigateEvent = false; - m_pEventEntity = nil; - ClearLookFlag(); - RestorePreviousState(); - if(m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) - SetMoveState(PEDMOVE_WALK); + if (DotProduct2D(dist, fwdOffset) < 0.0f) + return false; + + return true; } +#endif +// This function looks completely same on VC. void -CPed::ClearLeader(void) +CPed::SetDirectionToWalkAroundObject(CEntity *obj) { - if (!m_leader) + float distLimitForTimer = 8.0f; + CColModel *objCol = CModelInfo::GetModelInfo(obj->GetModelIndex())->GetColModel(); + CVector objColMin = objCol->boundingBox.min; + CVector objColMax = objCol->boundingBox.max; + CVector objColCenter = (objColMin + objColMax) / 2.0f; + CMatrix objMat(obj->GetMatrix()); + float dirToSet = obj->GetForward().Heading(); + bool goingToEnterCarAndItsVan = false; + bool goingToEnterCar = false; + bool objUpsideDown = false; + + float checkIntervalInDist = (objColMax.y - objColMin.y) * 0.1f; + float checkIntervalInTime; + + if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) 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; +#ifndef PEDS_REPORT_CRIMES_ON_PHONE + if (CharCreatedBy != MISSION_CHAR && obj->GetModelIndex() == MI_PHONEBOOTH1) { + bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; + SetFindPathAndFlee(obj, 5000, !isRunning); + return; } -} +#endif -void -CPed::ClearLook(void) -{ - RestorePreviousState(); - ClearLookFlag(); -} + CVector2D adjustedColMin(objColMin.x - 0.35f, objColMin.y - 0.35f); + CVector2D adjustedColMax(objColMax.x + 0.35f, objColMax.y + 0.35f); -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) { + checkIntervalInDist = Max(checkIntervalInDist, 0.5f); + checkIntervalInDist = Min(checkIntervalInDist, (objColMax.z - objColMin.z) / 2.0f); + checkIntervalInDist = Min(checkIntervalInDist, (adjustedColMax.x - adjustedColMin.x) / 2.0f); - if (m_pMyVehicle->pDriver != this) { -#if defined VC_PED_PORTS || defined FIX_BUGS - if(!IsPlayer()) -#endif - bWanderPathAfterExitingCar = true; + if (objMat.GetUp().z < 0.0f) + objUpsideDown = true; - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } -#ifdef VC_PED_PORTS - m_nLastPedState = PED_NONE; -#endif + if (obj->GetModelIndex() != MI_TRAFFICLIGHTS && obj->GetModelIndex() != MI_SINGLESTREETLIGHTS1 && obj->GetModelIndex() != MI_SINGLESTREETLIGHTS2) { + objColCenter = obj->GetMatrix() * objColCenter; + } else { + checkIntervalInDist = 0.4f; + if (objMat.GetUp().z <= 0.57f) { + + // Specific calculations for traffic lights, didn't get a bit. + adjustedColMin.x = 1.2f * (adjustedColMin.x < adjustedColMin.y ? adjustedColMin.x : adjustedColMin.y); + adjustedColMax.x = 1.2f * (adjustedColMax.x > adjustedColMax.y ? adjustedColMax.x : adjustedColMax.y); + adjustedColMin.y = 1.2f * objColMin.z; + adjustedColMax.y = 1.2f * objColMax.z; + dirToSet = objMat.GetUp().Heading(); + objMat.SetUnity(); + objMat.RotateZ(dirToSet); + objMat.GetPosition() += obj->GetPosition(); + objColCenter = obj->GetPosition(); } else { - SetIdle(); - SetMoveState(PEDMOVE_STILL); + objColCenter.x = adjustedColMax.x - 0.25f; + objColCenter = obj->GetMatrix() * objColCenter; + distLimitForTimer = 0.75f; } - } else { - bClearObjective = true; + objUpsideDown = false; } -} + float oldRotDest = m_fRotationDest; +#ifndef NEW_WALK_AROUND_ALGORITHM + float angleToFaceObjCenter = (objColCenter - GetPosition()).Heading(); + float angleDiffBtwObjCenterAndForward = CGeneral::LimitRadianAngle(dirToSet - angleToFaceObjCenter); + float objTopRightHeading = Atan2(adjustedColMax.x - adjustedColMin.x, adjustedColMax.y - adjustedColMin.y); +#endif -void -CPed::ClearPause(void) -{ - RestorePreviousState(); -} + if (IsPlayer()) { + if (FindPlayerPed()->m_fMoveSpeed <= 0.0f) + checkIntervalInTime = 0.0f; + else + checkIntervalInTime = 2.0f / FindPlayerPed()->m_fMoveSpeed; + } else { + switch (m_nMoveState) { + case PEDMOVE_WALK: + checkIntervalInTime = 2.0f; + break; + case PEDMOVE_RUN: + checkIntervalInTime = 0.5f; + break; + case PEDMOVE_SPRINT: + checkIntervalInTime = 0.5f; + break; + default: + checkIntervalInTime = 0.0f; + break; + } + } + if (m_pSeekTarget == obj && obj->IsVehicle()) { + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER + || m_objective == OBJECTIVE_SOLICIT_VEHICLE) { + goingToEnterCar = true; + if (IsPlayer()) + checkIntervalInTime = 0.0f; -void -CPed::ClearSeek(void) -{ - SetIdle(); - bRunningToPhone = false; -} + if (((CVehicle*)obj)->bIsVan) + goingToEnterCarAndItsVan = true; + } + } -bool -CPed::SetWanderPath(int8 pathStateDest) -{ - uint8 nextPathState; + int entityOnTopLeftOfObj = 0; + int entityOnBottomLeftOfObj = 0; + int entityOnTopRightOfObj = 0; + int entityOnBottomRightOfObj = 0; - if (IsPedInControl()) { - if (bKindaStayInSamePlace) { - SetIdle(); - return false; - } else { - m_nPathDir = pathStateDest; - if (pathStateDest == 0) - pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); + if (CTimer::GetTimeInMilliseconds() > m_collidingThingTimer || m_collidingEntityWhileFleeing != obj) { + bool collidingThingChanged = true; + CEntity *obstacle; - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &nextPathState); +#ifndef NEW_WALK_AROUND_ALGORITHM + if (!obj->IsVehicle() || objUpsideDown) { + collidingThingChanged = false; + } else { +#else + CVector cornerToGo = CVector(10.0f, 10.0f, 10.0f); + int dirToGo; + m_walkAroundType = 0; + int iWouldPreferGoingBack = 0; // 1:left 2:right +#endif + float adjustedCheckInterval = 0.7f * checkIntervalInDist; + CVector posToCheck; - // 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; + // Top left of obj + posToCheck.x = adjustedColMin.x + adjustedCheckInterval; + posToCheck.y = adjustedColMax.y - adjustedCheckInterval; + posToCheck.z = 0.0f; + posToCheck = objMat * posToCheck; + posToCheck.z += 0.6f; + obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, + true, true, false, true, false, false); + if (obstacle) { + if (obstacle->IsBuilding()) { + entityOnTopLeftOfObj = 1; + } else if (obstacle->IsVehicle()) { + entityOnTopLeftOfObj = 2; + } else { + entityOnTopLeftOfObj = 3; } - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &nextPathState); } +#ifdef NEW_WALK_AROUND_ALGORITHM + else { + CVector tl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMax.y, 0.0f) - GetPosition(); + if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { + cornerToGo = tl; + m_walkAroundType = 1; - // 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; -} + if (m_vehEnterType == CAR_DOOR_LR) + iWouldPreferGoingBack = 1; + } else if(CanWeSeeTheCorner(tl, GetForward())){ + cornerToGo = tl; + dirToGo = GetLocalDirection(tl); + if (dirToGo == 1) + m_walkAroundType = 0; // ALL of the next turns will be right turn + else if (dirToGo == 3) + m_walkAroundType = 1; // ALL of the next turns will be left turn + } + } +#endif -void -CPed::RestorePreviousState(void) -{ - if(!CanSetPedState() || m_nPedState == PED_FALL) - return; + // Top right of obj + posToCheck.x = adjustedColMax.x - adjustedCheckInterval; + posToCheck.y = adjustedColMax.y - adjustedCheckInterval; + posToCheck.z = 0.0f; + posToCheck = objMat * posToCheck; + posToCheck.z += 0.6f; + obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, + true, true, false, true, false, false); + if (obstacle) { + if (obstacle->IsBuilding()) { + entityOnTopRightOfObj = 1; + } else if (obstacle->IsVehicle()) { + entityOnTopRightOfObj = 2; + } else { + entityOnTopRightOfObj = 3; + } + } +#ifdef NEW_WALK_AROUND_ALGORITHM + else { + CVector tr = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMax.y, 0.0f) - GetPosition(); + if (tr.Magnitude2D() < cornerToGo.Magnitude2D()) { + if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { + cornerToGo = tr; + m_walkAroundType = 2; - if (m_nPedState == PED_GETUP && !bGetUpAnimStarted) - return; + if (m_vehEnterType == CAR_DOOR_RR) + iWouldPreferGoingBack = 2; + } else if (CanWeSeeTheCorner(tr, GetForward())) { + cornerToGo = tr; + dirToGo = GetLocalDirection(tr); + if (dirToGo == 1) + m_walkAroundType = 2; // ALL of the next turns will be right turn + else if (dirToGo == 3) + m_walkAroundType = 3; // ALL of the next turns will be left turn + } + } + } +#endif - if (InVehicle()) { - m_nPedState = PED_DRIVING; - m_nLastPedState = PED_NONE; - } else { - if (m_nLastPedState == PED_NONE) { - if (!IsPlayer() && CharCreatedBy != MISSION_CHAR && m_objective == OBJECTIVE_NONE) { - if (SetWanderPath(CGeneral::GetRandomNumber() & 7) != 0) - return; + // Bottom right of obj + posToCheck.x = adjustedColMax.x - adjustedCheckInterval; + posToCheck.y = adjustedColMin.y + adjustedCheckInterval; + posToCheck.z = 0.0f; + posToCheck = objMat * posToCheck; + posToCheck.z += 0.6f; + obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, + true, true, false, true, false, false); + if (obstacle) { + if (obstacle->IsBuilding()) { + entityOnBottomRightOfObj = 1; + } else if (obstacle->IsVehicle()) { + entityOnBottomRightOfObj = 2; + } else { + entityOnBottomRightOfObj = 3; + } } - SetIdle(); - return; - } +#ifdef NEW_WALK_AROUND_ALGORITHM + else { + CVector br = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMin.y, 0.0f) - GetPosition(); + if (iWouldPreferGoingBack == 2) + m_walkAroundType = 4; + else if (br.Magnitude2D() < cornerToGo.Magnitude2D()) { + if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { + cornerToGo = br; + m_walkAroundType = 5; + } else if (CanWeSeeTheCorner(br, GetForward())) { + cornerToGo = br; + dirToGo = GetLocalDirection(br); + if (dirToGo == 1) + m_walkAroundType = 4; // ALL of the next turns will be right turn + else if (dirToGo == 3) + m_walkAroundType = 5; // ALL of the next turns will be left turn + } + } + } +#endif - switch (m_nLastPedState) { - case PED_IDLE: - SetIdle(); - break; - case PED_WANDER_PATH: - m_nPedState = PED_WANDER_PATH; - bIsRunning = false; - if (bFindNewNodeAfterStateRestore) { - if (m_pNextPathNode) { - CVector diff = m_pNextPathNode->GetPosition() - GetPosition(); - if (diff.MagnitudeSqr() < sq(7.0f)) { - SetMoveState(PEDMOVE_WALK); - break; - } + // Bottom left of obj + posToCheck.x = adjustedColMin.x + adjustedCheckInterval; + posToCheck.y = adjustedColMin.y + adjustedCheckInterval; + posToCheck.z = 0.0f; + posToCheck = objMat * posToCheck; + posToCheck.z += 0.6f; + obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, + true, true, false, true, false, false); + if (obstacle) { + if (obstacle->IsBuilding()) { + entityOnBottomLeftOfObj = 1; + } else if (obstacle->IsVehicle()) { + entityOnBottomLeftOfObj = 2; + } else { + entityOnBottomLeftOfObj = 3; + } + } +#ifdef NEW_WALK_AROUND_ALGORITHM + else { + CVector bl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMin.y, 0.0f) - GetPosition(); + if (iWouldPreferGoingBack == 1) + m_walkAroundType = 7; + else if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) { + if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { + cornerToGo = bl; + m_walkAroundType = 6; + } else if (CanWeSeeTheCorner(bl, GetForward())) { + cornerToGo = bl; + dirToGo = GetLocalDirection(bl); + if (dirToGo == 1) + m_walkAroundType = 6; // ALL of the next turns will be right turn + else if (dirToGo == 3) + m_walkAroundType = 7; // ALL of the next turns will be left turn } } - SetWanderPath(CGeneral::GetRandomNumber() & 7); - break; - default: - m_nPedState = m_nLastPedState; - SetMoveState((eMoveState) m_nPrevMoveState); - break; + } +#else } - m_nLastPedState = PED_NONE; - } -} -void -CPed::SetAimFlag(CEntity *to) -{ - 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 - } - - 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); - } - } 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 (soundId != NO_SND) - DMAudio.PlayOneShot(m_audioEntityId, soundId, 0.0f); -} - -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::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); - - 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; -} - -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() -#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; -#else - if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X; -#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 (!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 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) -{ - 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); - } - } - } - } - } - } - } - } - } -} - -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::MoveHeadToLook(void) -{ - CVector lookPos; - - if (m_lookTimer && CTimer::GetTimeInMilliseconds() > m_lookTimer) { - ClearLookFlag(); - } else if (m_nPedState == PED_DRIVING) { - m_pedIK.m_flags |= CPedIK::LOOKAROUND_HEAD_ONLY; - } - - if (m_pLookTarget) { - - if (!bShakeFist && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED) { - - CAnimBlendAssociation *fuckUAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FUCKU); - if (fuckUAssoc) { - - float animTime = fuckUAssoc->currentTime; - if (animTime > 4.0f / 30.0f && animTime - fuckUAssoc->timeStep > 4.0f / 30.0f) { - - bool lookingToCop = false; - if (m_pLookTarget->GetModelIndex() == MI_POLICE - || m_pLookTarget->IsPed() && ((CPed*)m_pLookTarget)->m_nPedType == PEDTYPE_COP) { - - lookingToCop = true; - } - - if (IsPlayer() && (m_pedStats->m_temper >= 52 || lookingToCop)) { - AddWeaponModel(MI_FINGERS); - ((CPlayerPed*)this)->AnnoyPlayerPed(true); - - } else if ((CGeneral::GetRandomNumber() & 3) == 0) { - AddWeaponModel(MI_FINGERS); - } - } - } - } - - if (m_pLookTarget->IsPed()) { - ((CPed*)m_pLookTarget)->m_pedIK.GetComponentPosition((RwV3d*) &lookPos, PED_MID); - } else { - lookPos = m_pLookTarget->GetPosition(); - } - - if (!m_pedIK.LookAtPosition(lookPos)) { - if (!bKeepTryingToLook) { - ClearLookFlag(); - } - return; - } - - if (!bShakeFist || bIsAimingGun || bIsRestoringGun) - return; - - if (m_lookTimer - CTimer::GetTimeInMilliseconds() >= 1000) - return; - - bool notRocketLauncher = false; - bool notTwoHanded = false; - AnimationId animToPlay = NUM_ANIMS; - - if (!GetWeapon()->IsType2Handed()) - notTwoHanded = true; - - if (notTwoHanded && GetWeapon()->m_eWeaponType != WEAPONTYPE_ROCKETLAUNCHER) - notRocketLauncher = true; - - if (IsPlayer() && notRocketLauncher) { - - if (m_pLookTarget->IsPed()) { - - if (m_pedStats->m_temper >= 49 && ((CPed*)m_pLookTarget)->m_nPedType != PEDTYPE_COP) { - - // FIX: Unreachable and meaningless condition -#ifndef FIX_BUGS - if (m_pedStats->m_temper < 47) -#endif - animToPlay = ANIM_FIGHT_PPUNCH; - } else { - animToPlay = ANIM_FUCKU; - } - } else if (m_pedStats->m_temper > 49 || m_pLookTarget->GetModelIndex() == MI_POLICE) { - animToPlay = ANIM_FUCKU; - } - } else if (notRocketLauncher && (CGeneral::GetRandomNumber() & 1)) { - animToPlay = ANIM_FUCKU; - } - - if (animToPlay != NUM_ANIMS) { - CAnimBlendAssociation *newAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToPlay, 4.0f); - - if (newAssoc) { - newAssoc->flags |= ASSOC_FADEOUTWHENDONE; - newAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (newAssoc->animId == ANIM_FUCKU) - newAssoc->SetDeleteCallback(FinishFuckUCB, this); - } - } - bShakeFist = false; - return; - } else if (999999.0f == m_fLookDirection) { - ClearLookFlag(); - } else if (!m_pedIK.LookInDirection(m_fLookDirection, 0.0f)) { - if (!bKeepTryingToLook) - ClearLookFlag(); - } -} - -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::Pause(void) -{ - m_moved = CVector2D(0.0f, 0.0f); - if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) - ClearPause(); -} - -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::ProcessControl(void) -{ - CColPoint foundCol; - CEntity *foundEnt = nil; - - if (m_nZoneLevel > LEVEL_GENERIC && m_nZoneLevel != CCollision::ms_collisionInMemory) - return; - - int alpha = CVisibilityPlugins::GetClumpAlpha(GetClump()); - if (!bFadeOut) { - if (alpha < 255) { - alpha += 16; - if (alpha > 255) - alpha = 255; - } - } else { - alpha -= 8; - if (alpha < 0) - alpha = 0; - } - - CVisibilityPlugins::SetClumpAlpha(GetClump(), alpha); - bIsShooting = false; - BuildPedLists(); - bIsInWater = false; - ProcessBuoyancy(); - - if (m_nPedState != PED_ARRESTED) { - if (m_nPedState == PED_DEAD) { - DeadPedMakesTyresBloody(); -#ifndef VC_PED_PORTS - if (CGame::nastyGame) { -#else - if (CGame::nastyGame && !bIsInWater) { -#endif - uint32 remainingBloodyFpTime = CTimer::GetTimeInMilliseconds() - m_bloodyFootprintCountOrDeathTime; - float timeDependentDist; - if (remainingBloodyFpTime >= 2000) { - if (remainingBloodyFpTime <= 7000) - timeDependentDist = (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f; - else - timeDependentDist = 0.75f; - } else { - timeDependentDist = 0.0f; - } - - for (int i = 0; i < m_numNearPeds; ++i) { - CPed *nearPed = m_nearPeds[i]; - if (!nearPed->DyingOrDead()) { - CVector dist = nearPed->GetPosition() - GetPosition(); - if (dist.MagnitudeSqr() < sq(timeDependentDist)) { - nearPed->m_bloodyFootprintCountOrDeathTime = 200; - nearPed->bDoBloodyFootprints = true; - if (nearPed->IsPlayer()) { - if (!nearPed->bIsLooking && nearPed->m_nPedState != PED_ATTACK) { - int16 camMode = TheCamera.Cams[TheCamera.ActiveCam].Mode; - if (camMode != CCam::MODE_SNIPER - && camMode != CCam::MODE_ROCKETLAUNCHER - && camMode != CCam::MODE_M16_1STPERSON - && camMode != CCam::MODE_1STPERSON - && camMode != CCam::MODE_HELICANNON_1STPERSON - && !TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn()) { - - nearPed->SetLookFlag(this, true); - nearPed->SetLookTimer(500); - } - } - } - } - } - } - - if (remainingBloodyFpTime > 2000) { - CVector bloodPos = GetPosition(); - if (remainingBloodyFpTime - 2000 >= 5000) { - if (!m_deadBleeding) { - CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, - 0.75f, 0.0f, 0.0f, -0.75f, 255, 255, 0, 0, 4.0f, 40000, 1.0f); - m_deadBleeding = true; - } - } else { - CShadows::StoreStaticShadow( - (uintptr)this + 17, SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, - (remainingBloodyFpTime - 2000) / 5000.0f * 0.75f, 0.0f, - 0.0f, (remainingBloodyFpTime - 2000) / 5000.0f * -0.75f, - 255, 255, 0, 0, 4.0f, 1.0f, 40.0f, false, 0.0f); - } - } - } - if (ServiceTalkingWhenDead()) - ServiceTalking(); - -#ifdef VC_PED_PORTS - if (bIsInWater) { - bIsStanding = false; - bWasStanding = false; - CPhysical::ProcessControl(); - } -#endif - return; - } - - bWasStanding = false; - if (bIsStanding) { - if (!CWorld::bForceProcessControl) { - if (m_pCurrentPhysSurface && m_pCurrentPhysSurface->bIsInSafePosition) { - bWasPostponed = true; - return; - } - } - } - - if (!IsPedInControl() || m_nWaitState != WAITSTATE_FALSE || 0.01f * CTimer::GetTimeStep() <= m_fDistanceTravelled - || (m_nStoredMoveState != PEDMOVE_WALK && m_nStoredMoveState != PEDMOVE_RUN && m_nStoredMoveState != PEDMOVE_SPRINT)) - m_panicCounter = 0; - else if (m_panicCounter < 50) - ++m_panicCounter; - - if (m_fHealth <= 1.0f && m_nPedState <= PED_STATES_NO_AI && !bIsInTheAir && !bIsLanding) - SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); - - bCollidedWithMyVehicle = false; - - CEntity *collidingEnt = m_pDamageEntity; -#ifndef VC_PED_PORTS - if (!bUsesCollision || m_fDamageImpulse <= 0.0f || m_nPedState == PED_DIE || !collidingEnt) { -#else - if (!bUsesCollision || ((!collidingEnt || m_fDamageImpulse <= 0.0f) && (!IsPlayer() || !bIsStuck)) || m_nPedState == PED_DIE) { -#endif - bHitSomethingLastFrame = false; - if (m_nPedStateTimer <= 500 && bIsInTheAir) { - if (m_nPedStateTimer) - m_nPedStateTimer--; - } else if (m_nPedStateTimer < 1001) { - m_nPedStateTimer = 0; - } - } else { - if (m_panicCounter == 50 && IsPedInControl()) { - SetWaitState(WAITSTATE_STUCK, nil); - // Leftover - /* - if (m_nPedType < PEDTYPE_COP) { - - } else { - - } - */ -#ifndef VC_PED_PORTS - } else { -#else - } else if (collidingEnt) { -#endif - switch (collidingEnt->GetType()) - { - case ENTITY_TYPE_BUILDING: - case ENTITY_TYPE_OBJECT: - { - CBaseModelInfo *collidingModel = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex()); - CColModel *collidingCol = collidingModel->GetColModel(); - if (collidingEnt->IsObject() && ((CObject*)collidingEnt)->m_nSpecialCollisionResponseCases != COLLRESPONSE_FENCEPART - || collidingCol->boundingBox.max.x < 3.0f - && collidingCol->boundingBox.max.y < 3.0f) { - - if (!IsPlayer()) { - SetDirectionToWalkAroundObject(collidingEnt); - break; - } - } - if (IsPlayer()) { - bHitSomethingLastFrame = true; - break; - } - - float angleToFaceWhenHit = CGeneral::GetRadianAngleBetweenPoints( - GetPosition().x, - GetPosition().y, - m_vecDamageNormal.x + GetPosition().x, - m_vecDamageNormal.y + GetPosition().y); - - float neededTurn = Abs(m_fRotationCur - angleToFaceWhenHit); - - if (neededTurn > PI) - neededTurn = TWOPI - neededTurn; - - float oldDestRot = CGeneral::LimitRadianAngle(m_fRotationDest); - - if (m_pedInObjective && - (m_objective == OBJECTIVE_GOTO_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT)) { - - if (m_pedInObjective->IsPlayer() - && (neededTurn < DEGTORAD(20.0f) || m_panicCounter > 10)) { - if (CanPedJumpThis(collidingEnt)) { - SetJump(); - } else if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT) { - SetWaitState(WAITSTATE_LOOK_ABOUT, nil); - } else { - SetWaitState(WAITSTATE_PLAYANIM_TAXI, nil); - m_headingRate = 0.0f; - SetLookFlag(m_pedInObjective, true); - SetLookTimer(3000); - Say(SOUND_PED_TAXI_CALL); - } - } else { - m_pLookTarget = m_pedInObjective; - m_pLookTarget->RegisterReference((CEntity **) &m_pLookTarget); - TurnBody(); - } - } else { - if (m_nPedType != PEDTYPE_COP && neededTurn < DEGTORAD(15.0f) && m_nWaitState == WAITSTATE_FALSE) { - if ((m_nStoredMoveState == PEDMOVE_RUN || m_nStoredMoveState == PEDMOVE_SPRINT) && m_vecDamageNormal.z < 0.3f) { - CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN); - if (!runAssoc) - runAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT); - - if (runAssoc && runAssoc->blendAmount > 0.9f && runAssoc->IsRunning()) { - SetWaitState(WAITSTATE_HITWALL, nil); - } - } - } - if (m_nPedState == PED_FLEE_POS) { - CVector2D fleePos = collidingEnt->GetPosition(); - uint32 oldFleeTimer = m_fleeTimer; - SetFlee(fleePos, 5000); - if (oldFleeTimer != m_fleeTimer) - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 500; - - } else { - if (m_nPedState == PED_FLEE_ENTITY && (neededTurn < DEGTORAD(25.0f) || m_panicCounter > 10)) { - m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; - m_collidingEntityWhileFleeing = collidingEnt; - m_collidingEntityWhileFleeing->RegisterReference((CEntity **) &m_collidingEntityWhileFleeing); - - uint8 currentDir = Floor((PI + m_fRotationCur) / DEGTORAD(45.0f)); - uint8 nextDir; - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, currentDir, &nextDir); - - } else { - if (neededTurn < DEGTORAD(60.0f)) { - CVector posToHead = m_vecDamageNormal * 4.0f; - posToHead.z = 0.0f; - posToHead += GetPosition(); - int closestNodeId = ThePaths.FindNodeClosestToCoors(posToHead, PATH_PED, - 999999.9f, false, false); - float angleToFace; - - if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_KILL_CHAR_ANY_MEANS) { - if (m_nPedState != PED_SEEK_POS && m_nPedState != PED_SEEK_CAR) { - if (m_nPedState == PED_WANDER_PATH) { - m_pNextPathNode = &ThePaths.m_pathNodes[closestNodeId]; - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - m_pNextPathNode->GetX(), m_pNextPathNode->GetY(), - GetPosition().x, GetPosition().y); - } else { - if (ThePaths.m_pathNodes[closestNodeId].GetX() == 0.0f - || ThePaths.m_pathNodes[closestNodeId].GetY() == 0.0f) { - posToHead = (3.0f * m_vecDamageNormal) + GetPosition(); - posToHead.x += (CGeneral::GetRandomNumber() % 512) / 250.0f - 1.0f; - posToHead.y += (CGeneral::GetRandomNumber() % 512) / 250.0f - 1.0f; - } else { - posToHead.x = ThePaths.m_pathNodes[closestNodeId].GetX(); - posToHead.y = ThePaths.m_pathNodes[closestNodeId].GetY(); - } - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - posToHead.x, posToHead.y, - GetPosition().x, GetPosition().y); - - if (m_nPedState != PED_FOLLOW_PATH) - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 500; - } - } else { - angleToFace = CGeneral::GetRadianAngleBetweenPoints( - ThePaths.m_pathNodes[closestNodeId].GetX(), - ThePaths.m_pathNodes[closestNodeId].GetY(), - GetPosition().x, - GetPosition().y); - - CVector2D distToNode = ThePaths.m_pathNodes[closestNodeId].GetPosition() - GetPosition(); - CVector2D distToSeekPos = m_vecSeekPos - GetPosition(); - - if (DotProduct2D(distToNode, distToSeekPos) < 0.0f) { - m_fRotationCur = m_fRotationDest; - break; - } - } - } else { - float angleToFaceAwayDamage = CGeneral::GetRadianAngleBetweenPoints( - m_vecDamageNormal.x, - m_vecDamageNormal.y, - 0.0f, - 0.0f); - - if (angleToFaceAwayDamage < m_fRotationCur) - angleToFaceAwayDamage += TWOPI; - - float neededTurn = angleToFaceAwayDamage - m_fRotationCur; - - if (neededTurn <= PI) { - angleToFace = 0.5f * neededTurn + m_fRotationCur; - m_fRotationCur += DEGTORAD(m_pedStats->m_headingChangeRate) * 2.0f; - } else { - angleToFace = m_fRotationCur - (TWOPI - neededTurn) * 0.5f; - m_fRotationCur -= DEGTORAD(m_pedStats->m_headingChangeRate) * 2.0f; - } - - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 200; - if (m_nPedType == PEDTYPE_COP) { - if (m_pedInObjective) { - float angleToLookCriminal = CGeneral::GetRadianAngleBetweenPoints( - m_pedInObjective->GetPosition().x, - m_pedInObjective->GetPosition().y, - GetPosition().x, - GetPosition().y); - - angleToLookCriminal = CGeneral::LimitRadianAngle(angleToLookCriminal); - angleToFace = CGeneral::LimitRadianAngle(angleToFace); - - if (angleToLookCriminal < angleToFace) - angleToLookCriminal += TWOPI; - - float neededTurnToCriminal = angleToLookCriminal - angleToFace; - - if (neededTurnToCriminal > DEGTORAD(150.0f) && neededTurnToCriminal < DEGTORAD(210.0f)) { - ((CCopPed*)this)->m_bStopAndShootDisabledZone = true; - } - } - } - } - m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace); - - if (m_fRotationCur - PI > m_fRotationDest) { - m_fRotationDest += TWOPI; - } else if (PI + m_fRotationCur < m_fRotationDest) { - m_fRotationDest -= TWOPI; - } - - if (oldDestRot == m_fRotationDest && CTimer::GetTimeInMilliseconds() > m_nPedStateTimer) { - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 200; - m_fRotationDest += HALFPI; - } - } - } - } - } - - if (m_nPedState != PED_WANDER_PATH && m_nPedState != PED_FLEE_ENTITY) - m_pNextPathNode = nil; - - bHitSomethingLastFrame = true; - break; - } - case ENTITY_TYPE_VEHICLE: - { - CVehicle* collidingVeh = ((CVehicle*)collidingEnt); - float collidingVehSpeedSqr = collidingVeh->m_vecMoveSpeed.MagnitudeSqr(); - - if (collidingVeh == m_pMyVehicle) - bCollidedWithMyVehicle = true; -#ifdef VC_PED_PORTS - float oldHealth = m_fHealth; - bool playerSufferSound = false; - - if (collidingVehSpeedSqr <= 1.0f / 400.0f) { - if (IsPedInControl() - && (!IsPlayer() - || m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT - || m_objective == OBJECTIVE_RUN_TO_AREA - || m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER)) { - - if (collidingVeh != m_pCurrentPhysSurface || IsPlayer()) { - if (!bVehEnterDoorIsBlocked) { - if (collidingVeh->GetStatus() != STATUS_PLAYER || CharCreatedBy == MISSION_CHAR) { - - // VC calls SetDirectionToWalkAroundVehicle instead if ped is in PED_SEEK_CAR. - SetDirectionToWalkAroundObject(collidingVeh); - CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; - } else { - if (CTimer::GetTimeInMilliseconds() >= CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer - || m_nPedStateTimer >= CTimer::GetTimeInMilliseconds()) { - - // VC calls SetDirectionToWalkAroundVehicle instead if ped is in PED_SEEK_CAR. - SetDirectionToWalkAroundObject(collidingVeh); - CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; - - } else if (m_fleeFrom != collidingVeh) { - SetFlee(collidingVeh, 4000); - bUsePedNodeSeek = false; - SetMoveState(PEDMOVE_WALK); - } - } - } - } else { - float angleLeftToCompleteTurn = Abs(m_fRotationCur - m_fRotationDest); - if (angleLeftToCompleteTurn < 0.01f && CanPedJumpThis(collidingVeh)) { - SetJump(); - } - } - } else if (IsPlayer() && !bIsInTheAir) { - - if (IsPedInControl() && ((CPlayerPed*)this)->m_fMoveSpeed == 0.0f - && !bIsLooking && CTimer::GetTimeInMilliseconds() > m_lookTimer && collidingVeh->pDriver) { - - ((CPlayerPed*)this)->AnnoyPlayerPed(false); - SetLookFlag(collidingVeh, true); - SetLookTimer(1300); - - eWeaponType weaponType = GetWeapon()->m_eWeaponType; - if (weaponType == WEAPONTYPE_UNARMED - || weaponType == WEAPONTYPE_BASEBALLBAT - || weaponType == WEAPONTYPE_COLT45 - || weaponType == WEAPONTYPE_UZI) { - bShakeFist = true; - } - } else { - SetLookFlag(collidingVeh, true); - SetLookTimer(500); - } - } - } else { - float adjustedImpulse = m_fDamageImpulse; - if (IsPlayer()) { - if (bIsStanding) { - float forwardVecAndDamageDirDotProd = DotProduct(m_vecAnimMoveDelta.y * GetForward(), m_vecDamageNormal); - if (forwardVecAndDamageDirDotProd < 0.0f) { - adjustedImpulse = forwardVecAndDamageDirDotProd * m_fMass + m_fDamageImpulse; - if (adjustedImpulse < 0.0f) - adjustedImpulse = 0.0f; - } - } - } - if (m_fMass / 20.0f < adjustedImpulse) - DMAudio.PlayOneShot(collidingVeh->m_audioEntityId, SOUND_CAR_PED_COLLISION, adjustedImpulse); - - if (IsPlayer()) { - if (adjustedImpulse > 20.0f) - adjustedImpulse = 20.0f; - - if (adjustedImpulse > 5.0f) { - if (adjustedImpulse <= 13.0f) - playerSufferSound = true; - else - Say(SOUND_PED_DAMAGE); - } - - CColModel* collidingCol = CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(); - CVector colMinVec = collidingCol->boundingBox.min; - CVector colMaxVec = collidingCol->boundingBox.max; - - CVector vehColCenterDist = collidingVeh->GetMatrix() * ((colMinVec + colMaxVec) * 0.5f) - GetPosition(); - - // TLVC = To look vehicle center - - float angleToVehFront = collidingVeh->GetForward().Heading(); - float angleDiffFromLookingFrontTLVC = angleToVehFront - vehColCenterDist.Heading(); - angleDiffFromLookingFrontTLVC = CGeneral::LimitRadianAngle(angleDiffFromLookingFrontTLVC); - - // I don't know why do we use that - float vehTopRightHeading = Atan2(colMaxVec.x - colMinVec.x, colMaxVec.y - colMinVec.y); - - CVector vehDist = GetPosition() - collidingVeh->GetPosition(); - vehDist.Normalise(); - - float vehRightVecAndSpeedDotProd; - - if (Abs(angleDiffFromLookingFrontTLVC) >= vehTopRightHeading && Abs(angleDiffFromLookingFrontTLVC) < PI - vehTopRightHeading) { - if (angleDiffFromLookingFrontTLVC <= 0.0f) { - vehRightVecAndSpeedDotProd = DotProduct(collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); - - // vehRightVecAndSpeedDotProd < 0.1f = Vehicle being overturned or spinning to it's right? - if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { - - // Car's right faces towards us and isn't coming directly to us - if (DotProduct(collidingVeh->GetRight(), GetForward()) < 0.0f - && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { - SetEvasiveStep(collidingVeh, 1); - } - } - } else { - vehRightVecAndSpeedDotProd = DotProduct(-1.0f * collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); - - if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { - if (DotProduct(collidingVeh->GetRight(), GetForward()) > 0.0f - && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { - SetEvasiveStep(collidingVeh, 1); - } - } - } - } else { - vehRightVecAndSpeedDotProd = DotProduct(vehDist, collidingVeh->m_vecMoveSpeed); - } - - if (vehRightVecAndSpeedDotProd <= 0.1f) { - if (m_nPedState != PED_FIGHT) { - SetLookFlag(collidingVeh, true); - SetLookTimer(700); - } - } else { - bIsStanding = false; - CVector2D collidingEntMoveDir = -collidingVeh->m_vecMoveSpeed; - int dir = GetLocalDirection(collidingEntMoveDir); - SetFall(1000, (AnimationId)(dir + ANIM_KO_SKID_FRONT), false); - - float damage; - if (collidingVeh->m_modelIndex == MI_TRAIN) { - damage = 50.0f; - } else { - damage = 20.0f; - } - - InflictDamage(collidingVeh, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, dir); - Say(SOUND_PED_DAMAGE); - } - } else { - KillPedWithCar(collidingVeh, m_fDamageImpulse); - } - - /* VC specific - if (m_pCollidingEntity != collidingEnt) - bPushedAlongByCar = true; - */ - } - if (m_fHealth < oldHealth && playerSufferSound) - Say(SOUND_PED_HIT); -#else - if (collidingVehSpeedSqr <= 1.0f / 400.0f) { - if (!IsPedInControl() - || IsPlayer() - && m_objective != OBJECTIVE_GOTO_AREA_ON_FOOT - && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER - && m_objective != OBJECTIVE_RUN_TO_AREA) { - - if (IsPlayer() && !bIsInTheAir) { - - if (IsPedInControl() - && ((CPlayerPed*)this)->m_fMoveSpeed == 0.0f - && !bIsLooking - && CTimer::GetTimeInMilliseconds() > m_lookTimer - && collidingVeh->pDriver) { - - ((CPlayerPed*)this)->AnnoyPlayerPed(false); - SetLookFlag(collidingVeh, true); - SetLookTimer(1300); - - eWeaponType weaponType = GetWeapon()->m_eWeaponType; - if (weaponType == WEAPONTYPE_UNARMED - || weaponType == WEAPONTYPE_BASEBALLBAT - || weaponType == WEAPONTYPE_COLT45 - || weaponType == WEAPONTYPE_UZI) { - bShakeFist = true; - } - } else { - SetLookFlag(collidingVeh, true); - SetLookTimer(500); - } - } - - } else if (!bVehEnterDoorIsBlocked) { - if (collidingVeh->GetStatus() != STATUS_PLAYER || CharCreatedBy == MISSION_CHAR) { - - SetDirectionToWalkAroundObject(collidingVeh); - - } else if (CTimer::GetTimeInMilliseconds() >= CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer - || m_nPedStateTimer >= CTimer::GetTimeInMilliseconds()) { - - SetDirectionToWalkAroundObject(collidingVeh); - CWorld::Players[CWorld::PlayerInFocus].m_nLastBumpPlayerCarTimer = m_nPedStateTimer; - - } else if (m_fleeFrom != collidingVeh) { - SetFlee(collidingVeh, 4000); - bUsePedNodeSeek = false; - SetMoveState(PEDMOVE_WALK); - } - } - } else { - DMAudio.PlayOneShot(collidingVeh->m_audioEntityId, SOUND_CAR_PED_COLLISION, m_fDamageImpulse); - if (IsPlayer()) { - CColModel *collidingCol = CModelInfo::GetModelInfo(collidingVeh->GetModelIndex())->GetColModel(); - CVector colMinVec = collidingCol->boundingBox.min; - CVector colMaxVec = collidingCol->boundingBox.max; - - CVector vehColCenterDist = collidingVeh->GetMatrix() * ((colMinVec + colMaxVec) * 0.5f) - GetPosition(); - - // TLVC = To look vehicle center - - float angleToVehFront = collidingVeh->GetForward().Heading(); - float angleDiffFromLookingFrontTLVC = angleToVehFront - vehColCenterDist.Heading(); - angleDiffFromLookingFrontTLVC = CGeneral::LimitRadianAngle(angleDiffFromLookingFrontTLVC); - - // I don't know why do we use that - float vehTopRightHeading = Atan2(colMaxVec.x - colMinVec.x, colMaxVec.y - colMinVec.y); - - CVector vehDist = GetPosition() - collidingVeh->GetPosition(); - vehDist.Normalise(); - - float vehRightVecAndSpeedDotProd; - - if (Abs(angleDiffFromLookingFrontTLVC) >= vehTopRightHeading && Abs(angleDiffFromLookingFrontTLVC) < PI - vehTopRightHeading) { - if (angleDiffFromLookingFrontTLVC <= 0.0f) { - vehRightVecAndSpeedDotProd = DotProduct(collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); - - // vehRightVecAndSpeedDotProd < 0.1f = Vehicle being overturned or spinning to it's right? - if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { - - // Car's right faces towards us and isn't coming directly to us - if (DotProduct(collidingVeh->GetRight(), GetForward()) < 0.0f - && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { - SetEvasiveStep(collidingVeh, 1); - } - } - } else { - vehRightVecAndSpeedDotProd = DotProduct(-1.0f * collidingVeh->GetRight(), collidingVeh->m_vecMoveSpeed); - - if (collidingVehSpeedSqr > 1.0f / 100.0f && vehRightVecAndSpeedDotProd < 0.1f) { - if (DotProduct(collidingVeh->GetRight(), GetForward()) > 0.0f - && DotProduct(vehDist, collidingVeh->m_vecMoveSpeed) > 0.0f) { - SetEvasiveStep(collidingVeh, 1); - } - } - } - } else { - vehRightVecAndSpeedDotProd = DotProduct(vehDist, collidingVeh->m_vecMoveSpeed); - } - - if (vehRightVecAndSpeedDotProd <= 0.1f) { - if (m_nPedState != PED_FIGHT) { - SetLookFlag(collidingVeh, true); - SetLookTimer(700); - } - } else { - bIsStanding = false; - CVector2D collidingEntMoveDir = -collidingVeh->m_vecMoveSpeed; - int dir = GetLocalDirection(collidingEntMoveDir); - SetFall(1000, (AnimationId)(dir + ANIM_KO_SKID_FRONT), false); - CPed *driver = collidingVeh->pDriver; - - float damage; - if (driver && driver->IsPlayer()) { - damage = vehRightVecAndSpeedDotProd * 1000.0f; - } else if (collidingVeh->GetModelIndex() == MI_TRAIN) { - damage = 50.0f; - } else { - damage = 20.0f; - } - - InflictDamage(collidingVeh, WEAPONTYPE_RAMMEDBYCAR, damage, PEDPIECE_TORSO, dir); - Say(SOUND_PED_DAMAGE); - } - } else { - KillPedWithCar(collidingVeh, m_fDamageImpulse); - } - } -#endif - break; - } - case ENTITY_TYPE_PED: - { - CollideWithPed((CPed*)collidingEnt); - if (((CPed*)collidingEnt)->IsPlayer()) { - CPlayerPed *player = ((CPlayerPed*)collidingEnt); - Say(SOUND_PED_CHAT); - if (m_nMoveState > PEDMOVE_STILL && player->IsPedInControl()) { - if (player->m_fMoveSpeed < 1.0f) { - if (!player->bIsLooking) { - if (CTimer::GetTimeInMilliseconds() > player->m_lookTimer) { - player->AnnoyPlayerPed(false); - player->SetLookFlag(this, true); - player->SetLookTimer(1300); - eWeaponType weapon = player->GetWeapon()->m_eWeaponType; - if (weapon == WEAPONTYPE_UNARMED - || weapon == WEAPONTYPE_BASEBALLBAT - || weapon == WEAPONTYPE_COLT45 - || weapon == WEAPONTYPE_UZI) { - player->bShakeFist = true; - } - } - } - } - } - } - break; - } - default: - break; - } - } - CVector forceDir; - if (!bIsInTheAir && m_nPedState != PED_JUMP -#ifdef VC_PED_PORTS - && m_fDamageImpulse > 0.0f -#endif - ) { - - forceDir = m_vecDamageNormal; - forceDir.z = 0.0f; - if (!bIsStanding) { - forceDir *= 4.0f; - } else { - forceDir *= 0.5f; - } - - ApplyMoveForce(forceDir); - } - if ((bIsInTheAir && !DyingOrDead()) -#ifdef VC_PED_PORTS - || (!bIsStanding && !bWasStanding && m_nPedState == PED_FALL) -#endif - ) { - if (m_nPedStateTimer > 0 && m_nPedStateTimer <= 1000) { - forceDir = GetPosition() - m_vecHitLastPos; - } else { - m_nPedStateTimer = 0; - m_vecHitLastPos = GetPosition(); - forceDir = CVector(0.0f, 0.0f, 0.0f); - } - - CVector offsetToCheck; - m_nPedStateTimer++; - - float adjustedTs = Max(CTimer::GetTimeStep(), 0.01f); - - CPad *pad0 = CPad::GetPad(0); - if ((m_nPedStateTimer <= 50.0f / (4.0f * adjustedTs) || m_nPedStateTimer * 0.01f <= forceDir.MagnitudeSqr()) - && (m_nCollisionRecords <= 1 || m_nPedStateTimer <= 50.0f / (2.0f * adjustedTs) || m_nPedStateTimer * 1.0f / 250.0f <= Abs(forceDir.z))) { - - if (m_nCollisionRecords == 1 && m_aCollisionRecords[0] != nil && m_aCollisionRecords[0]->IsBuilding() - && m_nPedStateTimer > 50.0f / (2.0f * adjustedTs) && m_nPedStateTimer * 1.0f / 250.0f > Abs(forceDir.z)) { - offsetToCheck.x = -forceDir.y; -#ifdef VC_PED_PORTS - offsetToCheck.z = 1.0f; -#else - offsetToCheck.z = 0.0f; -#endif - offsetToCheck.y = forceDir.x; - offsetToCheck.Normalise(); - - CVector posToCheck = GetPosition() + offsetToCheck; - - // These are either obstacle or ground to land, I don't know which one. - float obstacleForFlyingZ, obstacleForFlyingOtherDirZ; - CColPoint obstacleForFlying, obstacleForFlyingOtherDir; - - // Check is there any room for being knocked up in reverse direction of force - if (CWorld::ProcessVerticalLine(posToCheck, -20.0f, obstacleForFlying, foundEnt, true, false, false, false, false, false, nil)) { - obstacleForFlyingZ = obstacleForFlying.point.z; - } else { - obstacleForFlyingZ = 500.0f; - } - - posToCheck = GetPosition() - offsetToCheck; - - // Now check for direction of force this time - if (CWorld::ProcessVerticalLine(posToCheck, -20.0f, obstacleForFlyingOtherDir, foundEnt, true, false, false, false, false, false, nil)) { - obstacleForFlyingOtherDirZ = obstacleForFlyingOtherDir.point.z; - } else { - obstacleForFlyingOtherDirZ = 501.0f; - } -#ifdef VC_PED_PORTS - uint8 flyDir = 0; - float feetZ = GetPosition().z - FEET_OFFSET; - if ((obstacleForFlyingZ <= feetZ || obstacleForFlyingOtherDirZ >= 500.0f) && (obstacleForFlyingZ <= feetZ || obstacleForFlyingOtherDirZ <= feetZ)) { - if (obstacleForFlyingOtherDirZ > feetZ && obstacleForFlyingZ < 499.0f) - flyDir = 2; - } else { - flyDir = 1; - } - - if (flyDir != 0 && !bSomeVCflag1) { - SetPosition((flyDir == 2 ? obstacleForFlyingOtherDir.point : obstacleForFlying.point)); - GetMatrix().GetPosition().z += FEET_OFFSET; - GetMatrix().UpdateRW(); - SetLanding(); - bIsStanding = true; - } -#endif - if (obstacleForFlyingZ < obstacleForFlyingOtherDirZ) { - offsetToCheck *= -1.0f; - } - offsetToCheck.z = 1.0f; - forceDir = 4.0f * offsetToCheck; - forceDir.z = 4.0f; - ApplyMoveForce(forceDir); - - GetMatrix().GetPosition() += 0.25f * offsetToCheck; - - m_fRotationCur = CGeneral::GetRadianAngleBetweenPoints(offsetToCheck.x, offsetToCheck.y, 0.0f, 0.0f); - m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - m_fRotationDest = m_fRotationCur; - SetHeading(m_fRotationCur); - - if (m_nPedState != PED_FALL && !bIsPedDieAnimPlaying) { - SetFall(1000, ANIM_KO_SKID_BACK, true); - } - bIsInTheAir = false; - } else if (m_vecDamageNormal.z > 0.4f) { -#ifndef VC_PED_PORTS - forceDir = m_vecDamageNormal; - forceDir.z = 0.0f; - forceDir.Normalise(); - ApplyMoveForce(2.0f * forceDir); -#else - if (m_nPedState == PED_JUMP) { - if (m_nWaitTimer <= 2000) { - if (m_nWaitTimer < 1000) - m_nWaitTimer += CTimer::GetTimeStep() * 0.02f * 1000.0f; - } else { - m_nWaitTimer = 0; - } - } - forceDir = m_vecDamageNormal; - forceDir.z = 0.0f; - forceDir.Normalise(); - if (m_nPedState != PED_JUMP || m_nWaitTimer >= 300) { - ApplyMoveForce(2.0f * forceDir); - } else { - ApplyMoveForce(-4.0f * forceDir); - } -#endif - } - } else if ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 3) & 7) { - if (IsPlayer() && m_nPedState != PED_JUMP && pad0->JumpJustDown()) { - int16 padWalkX = pad0->GetPedWalkLeftRight(); - int16 padWalkY = pad0->GetPedWalkUpDown(); - if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -padWalkX, padWalkY); - m_fRotationDest -= TheCamera.Orientation; - m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); - m_fRotationCur = m_fRotationDest; - SetHeading(m_fRotationCur); - } - SetJump(); - m_nPedStateTimer = 0; - m_vecHitLastPos = GetPosition(); - - // Why? forceDir is unused after this point. - forceDir = CVector(0.0f, 0.0f, 0.0f); - } else if (IsPlayer()) { - int16 padWalkX = pad0->GetPedWalkLeftRight(); - int16 padWalkY = pad0->GetPedWalkUpDown(); - if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -padWalkX, padWalkY); - m_fRotationDest -= TheCamera.Orientation; - m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest); - m_fRotationCur = m_fRotationDest; - SetHeading(m_fRotationCur); - } - CAnimBlendAssociation *jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_GLIDE); - - if (!jumpAssoc) - jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_GLIDE); - - if (jumpAssoc) { - jumpAssoc->blendDelta = -3.0f; - jumpAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - if (m_nPedState == PED_JUMP) - m_nPedState = PED_IDLE; - } else { - CAnimBlendAssociation *jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_JUMP_GLIDE); - - if (!jumpAssoc) - jumpAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_GLIDE); - - if (jumpAssoc) { - jumpAssoc->blendDelta = -3.0f; - jumpAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - } else { - offsetToCheck = GetPosition(); - offsetToCheck.z += 0.5f; - - if (CWorld::ProcessVerticalLine(offsetToCheck, GetPosition().z - FEET_OFFSET, foundCol, foundEnt, true, true, false, true, false, false, nil)) { -#ifdef VC_PED_PORTS - if (!bSomeVCflag1 || FEET_OFFSET + foundCol.point.z < GetPosition().z) { - GetMatrix().GetPosition().z = FEET_OFFSET + foundCol.point.z; - GetMatrix().UpdateRW(); - if (bSomeVCflag1) - bSomeVCflag1 = false; - } -#else - GetMatrix().GetPosition().z = FEET_OFFSET + foundCol.point.z; - GetMatrix().UpdateRW(); -#endif - SetLanding(); - bIsStanding = true; - } - } - } else if (m_nPedStateTimer < 1001) { - m_nPedStateTimer = 0; - } - } - - if (bIsDucking) - Duck(); - - if (bStartWanderPathOnFoot) { - if (IsPedInControl()) { - ClearAll(); - SetWanderPath(m_nPathDir); - bStartWanderPathOnFoot = false; - } else if (m_nPedState == PED_DRIVING) { - bWanderPathAfterExitingCar = true; - SetObjective(OBJECTIVE_LEAVE_CAR, m_pMyVehicle); - } - } - - if (!bIsStanding && m_vecMoveSpeed.z > 0.25f) { - float airResistance = Pow(0.95f, CTimer::GetTimeStep()); - - m_vecMoveSpeed *= airResistance; - } -#ifdef VC_PED_PORTS - if (IsPlayer() || !bIsStanding || m_vecMoveSpeed.x != 0.0f || m_vecMoveSpeed.y != 0.0f || m_vecMoveSpeed.z != 0.0f - || (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) - || m_vecAnimMoveDelta.x != 0.0f || m_vecAnimMoveDelta.y != 0.0f - || m_nPedState == PED_JUMP - || bIsInTheAir - || m_pCurrentPhysSurface) { - - CPhysical::ProcessControl(); - } else { - bHasContacted = false; - bIsInSafePosition = false; - bWasPostponed = false; - bHasHitWall = false; - m_nCollisionRecords = 0; - bHasCollided = false; - m_nDamagePieceType = 0; - m_fDamageImpulse = 0.0f; - m_pDamageEntity = nil; - m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f); - m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f); - } -#else - CPhysical::ProcessControl(); -#endif - if (m_nPedState != PED_DIE || bIsPedDieAnimPlaying) { - if (m_nPedState != PED_DEAD) { - CalculateNewVelocity(); - CalculateNewOrientation(); - } - UpdatePosition(); - PlayFootSteps(); - if (IsPedInControl() && !bIsStanding && !m_pDamageEntity && CheckIfInTheAir()) { - SetInTheAir(); -#ifdef VC_PED_PORTS - bSomeVCflag1 = false; -#endif - } -#ifdef VC_PED_PORTS - if (bSomeVCflag1) { - CVector posToCheck = GetPosition(); - posToCheck.z += 0.9f; - if (!CWorld::TestSphereAgainstWorld(posToCheck, 0.2f, this, true, true, false, true, false, false)) - bSomeVCflag1 = false; - } -#endif - ProcessObjective(); - if (!bIsAimingGun) { - if (bIsRestoringGun) - RestoreGunPosition(); - } else { - AimGun(); - } - - if (bIsLooking) { - MoveHeadToLook(); - } else if (bIsRestoringLook) { - RestoreHeadPosition(); - } - - if (bIsInTheAir) - InTheAir(); - - if (bUpdateAnimHeading) { - if (m_nPedState != PED_GETUP && m_nPedState != PED_FALL) { - m_fRotationCur -= HALFPI; - m_fRotationDest = m_fRotationCur; - bUpdateAnimHeading = false; - } - } - - if (m_nWaitState != WAITSTATE_FALSE) - Wait(); - - if (m_nPedState != PED_IDLE) { - CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); - if(idleAssoc) { - idleAssoc->blendDelta = -8.0f; - idleAssoc->flags |= ASSOC_DELETEFADEDOUT; - } - } - - switch (m_nPedState) { - case PED_IDLE: - Idle(); - break; - case PED_LOOK_ENTITY: - case PED_LOOK_HEADING: - Look(); - break; - case PED_WANDER_RANGE: - WanderRange(); - CheckAroundForPossibleCollisions(); - break; - case PED_WANDER_PATH: - WanderPath(); - break; - case PED_SEEK_POS: - case PED_SEEK_ENTITY: - case PED_PURSUE: - case PED_SNIPER_MODE: - case PED_ROCKET_MODE: - case PED_DUMMY: - case PED_FACE_PHONE: - case PED_MAKE_CALL: - case PED_MUG: - case PED_AI_CONTROL: - case PED_FOLLOW_ROUTE: - case PED_CPR: - case PED_SOLICIT: - case PED_BUY_ICECREAM: - case PED_STEP_AWAY: - case PED_UNKNOWN: - case PED_STATES_NO_AI: - case PED_JUMP: - case PED_STAGGER: - case PED_DIVE_AWAY: - case PED_STATES_NO_ST: - case PED_ARREST_PLAYER: - case PED_PASSENGER: - case PED_TAXI_PASSENGER: - case PED_OPEN_DOOR: - case PED_DEAD: - case PED_DRAG_FROM_CAR: - case PED_EXIT_CAR: - case PED_STEAL_CAR: - break; - case PED_ENTER_CAR: - case PED_CARJACK: - { -#ifdef CANCELLABLE_CAR_ENTER - if (!IsPlayer() || !m_pVehicleAnim) - break; - - CPad *pad = CPad::GetPad(0); - - if (pad->ArePlayerControlsDisabled()) - break; - - int vehAnim = m_pVehicleAnim->animId; - - static bool cancelJack = false; - int16 padWalkX = pad->GetPedWalkLeftRight(); - int16 padWalkY = pad->GetPedWalkUpDown(); - if (Abs(padWalkX) > 0.0f || Abs(padWalkY) > 0.0f) { - if (vehAnim == ANIM_CAR_OPEN_LHS || vehAnim == ANIM_CAR_OPEN_RHS || vehAnim == ANIM_COACH_OPEN_L || vehAnim == ANIM_COACH_OPEN_R || - vehAnim == ANIM_VAN_OPEN_L || vehAnim == ANIM_VAN_OPEN) { - - if (!m_pMyVehicle->pDriver) { - cancelJack = false; - bCancelEnteringCar = true; - } else - cancelJack = true; - } else if (vehAnim == ANIM_CAR_QJACK && m_pVehicleAnim->GetTimeLeft() > 0.75f) { - cancelJack = true; - } else if (vehAnim == ANIM_CAR_PULLOUT_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_RHS || vehAnim == ANIM_CAR_PULLOUT_RHS) { - bCancelEnteringCar = true; - cancelJack = false; - } - } - if (cancelJack && vehAnim == ANIM_CAR_QJACK && m_pVehicleAnim->GetTimeLeft() > 0.75f && m_pVehicleAnim->GetTimeLeft() < 0.78f) { - cancelJack = false; - QuitEnteringCar(); - RestorePreviousObjective(); - } - if (cancelJack && (vehAnim == ANIM_CAR_PULLOUT_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_LHS || vehAnim == ANIM_CAR_PULLOUT_LOW_RHS || vehAnim == ANIM_CAR_PULLOUT_RHS)) { - cancelJack = false; - bCancelEnteringCar = true; - } -#endif - break; - } - case PED_FLEE_POS: - ms_vec2DFleePosition.x = m_fleeFromPosX; - ms_vec2DFleePosition.y = m_fleeFromPosY; - Flee(); - break; - case PED_FLEE_ENTITY: - if (!m_fleeFrom) { - SetIdle(); - break; - } - - if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) - break; - - ms_vec2DFleePosition = m_fleeFrom->GetPosition(); - Flee(); - break; - case PED_FOLLOW_PATH: - FollowPath(); - break; - case PED_PAUSE: - Pause(); - break; - case PED_ATTACK: - Attack(); - break; - case PED_FIGHT: - Fight(); - break; - case PED_CHAT: - Chat(); - break; - case PED_AIM_GUN: - if (m_pPointGunAt && m_pPointGunAt->IsPed() -#ifdef FIX_BUGS - && !GetWeapon()->IsTypeMelee() -#endif - && ((CPed*)m_pPointGunAt)->CanSeeEntity(this, CAN_SEE_ENTITY_ANGLE_THRESHOLD * 2)) { - ((CPed*)m_pPointGunAt)->ReactToPointGun(this); - } - PointGunAt(); - break; - case PED_SEEK_CAR: - SeekCar(); - break; - case PED_SEEK_IN_BOAT: - SeekBoatPosition(); - break; - case PED_INVESTIGATE: - InvestigateEvent(); - break; - case PED_ON_FIRE: - if (IsPlayer()) - break; - - if (CTimer::GetTimeInMilliseconds() <= m_fleeTimer) { - if (m_fleeFrom) { - ms_vec2DFleePosition = m_fleeFrom->GetPosition(); - } else { - ms_vec2DFleePosition.x = m_fleeFromPosX; - ms_vec2DFleePosition.y = m_fleeFromPosY; - } - Flee(); - } else { - if (m_pFire) - m_pFire->Extinguish(); - } - break; - case PED_FALL: - Fall(); - break; - case PED_GETUP: - SetGetUp(); - break; - case PED_ENTER_TRAIN: - EnterTrain(); - break; - case PED_EXIT_TRAIN: - ExitTrain(); - break; - case PED_DRIVING: - { - if (!m_pMyVehicle) { - bInVehicle = false; - FlagToDestroyWhenNextProcessed(); - return; - } - - if (m_pMyVehicle->pDriver != this || m_pMyVehicle->IsBoat()) { - LookForSexyPeds(); - LookForSexyCars(); - break; - } - - if (m_pMyVehicle->m_vehType == VEHICLE_TYPE_BIKE || !m_pMyVehicle->pDriver->IsPlayer()) { - break; - } - - CPad* pad = CPad::GetPad(0); - -#ifdef CAR_AIRBREAK - if (!pad->ArePlayerControlsDisabled()) { - if (pad->GetHorn()) { - float c = Cos(m_fRotationCur); - float s = Sin(m_fRotationCur); - m_pMyVehicle->GetRight() = CVector(1.0f, 0.0f, 0.0f); - m_pMyVehicle->GetForward() = CVector(0.0f, 1.0f, 0.0f); - m_pMyVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f); - if (pad->GetAccelerate()) { - m_pMyVehicle->ApplyMoveForce(GetForward() * 30.0f); - } else if (pad->GetBrake()) { - m_pMyVehicle->ApplyMoveForce(-GetForward() * 30.0f); - } else { - int16 lr = pad->GetSteeringLeftRight(); - if (lr < 0) { - //m_pMyVehicle->ApplyTurnForce(20.0f * -GetRight(), GetForward()); - m_pMyVehicle->ApplyMoveForce(-GetRight() * 30.0f); - } else if (lr > 0) { - m_pMyVehicle->ApplyMoveForce(GetRight() * 30.0f); - } else { - m_pMyVehicle->ApplyMoveForce(0.0f, 0.0f, 50.0f); - } - } - } - } -#endif - float steerAngle = m_pMyVehicle->m_fSteerAngle; - CAnimBlendAssociation *lDriveAssoc; - CAnimBlendAssociation *rDriveAssoc; - CAnimBlendAssociation *lbAssoc; - CAnimBlendAssociation *sitAssoc; - if (m_pMyVehicle->bLowVehicle) { - sitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSIT); - - if (!sitAssoc || sitAssoc->blendAmount < 1.0f) { - break; - } - - lDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_L); - lbAssoc = nil; - rDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_LOW_R); - } else { - sitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SIT); - - if (!sitAssoc || sitAssoc->blendAmount < 1.0f) { - break; - } - - lDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_L); - rDriveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVE_R); - lbAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LB); - - if (lbAssoc && - TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON - && TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking == LOOKING_LEFT) { - lbAssoc->blendDelta = -1000.0f; - } - } - - CAnimBlendAssociation *driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_L); - - if (!driveByAssoc) - driveByAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_DRIVEBY_R); - - if (m_pMyVehicle->bLowVehicle || m_pMyVehicle->m_fGasPedal >= 0.0f || driveByAssoc) { - if (steerAngle == 0.0f || driveByAssoc) { - if (lDriveAssoc) - lDriveAssoc->blendAmount = 0.0f; - if (rDriveAssoc) - rDriveAssoc->blendAmount = 0.0f; - - } else if (steerAngle <= 0.0f) { - if (lDriveAssoc) - lDriveAssoc->blendAmount = 0.0f; - - if (rDriveAssoc) - rDriveAssoc->blendAmount = clamp(steerAngle * -100.0f / 61.0f, 0.0f, 1.0f); - else if (m_pMyVehicle->bLowVehicle) - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_LOW_R); - else - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_R); - - } else { - if (rDriveAssoc) - rDriveAssoc->blendAmount = 0.0f; - - if (lDriveAssoc) - lDriveAssoc->blendAmount = clamp(steerAngle * 100.0f / 61.0f, 0.0f, 1.0f); - else if (m_pMyVehicle->bLowVehicle) - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_LOW_L); - else - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_DRIVE_L); - } - - if (lbAssoc) - lbAssoc->blendDelta = -4.0f; - } else { - - if ((TheCamera.Cams[TheCamera.ActiveCam].Mode != CCam::MODE_1STPERSON - || TheCamera.Cams[TheCamera.ActiveCam].DirectionWasLooking != LOOKING_LEFT) - && (!lbAssoc || lbAssoc->blendAmount < 1.0f)) { - CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LB, 4.0f); - } - } - break; - } - case PED_DIE: - Die(); - break; - case PED_HANDS_UP: - if (m_pedStats->m_temper <= 50) { - if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSCOWER)) { - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER); - Say(SOUND_PED_HANDS_COWER); - } - } else if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HANDSUP)) { - CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_HANDSUP); - Say(SOUND_PED_HANDS_UP); - } - break; - default: break; - } - SetMoveAnim(); - if (bPedIsBleeding) { - if (CGame::nastyGame) { - if (!(CTimer::GetFrameCounter() & 3)) { - CVector cameraDist = GetPosition() - TheCamera.GetPosition(); - if (cameraDist.MagnitudeSqr() < sq(50.0f)) { - - float length = (CGeneral::GetRandomNumber() & 127) * 0.0015f + 0.15f; - CVector bloodPos( - ((CGeneral::GetRandomNumber() & 127) - 64) * 0.007f, - ((CGeneral::GetRandomNumber() & 127) - 64) * 0.007f, - 1.0f); - bloodPos += GetPosition(); - - CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos, length, 0.0f, - 0.0f, -length, 255, 255, 0, 0, 4.0f, (CGeneral::GetRandomNumber() & 4095) + 2000, 1.0f); - } - } - } - } - ServiceTalking(); - if (bInVehicle && !m_pMyVehicle) - bInVehicle = false; -#ifndef VC_PED_PORTS - m_pCurrentPhysSurface = nil; -#endif - } else { - if (bIsStanding && (!m_pCurrentPhysSurface || IsPlayer()) - || bIsInWater || !bUsesCollision) { - SetDead(); - } - m_pCurrentPhysSurface = nil; - } - } -} - -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::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 -#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::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()) { -#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::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 (entityOnTopLeftOfObj && entityOnTopRightOfObj && entityOnBottomRightOfObj && entityOnBottomLeftOfObj) { + collidingThingChanged = false; + entityOnTopLeftOfObj = 0; + entityOnBottomLeftOfObj = 0; + entityOnTopRightOfObj = 0; + entityOnBottomRightOfObj = 0; } - 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); + if (!collidingThingChanged) { + m_walkAroundType = 0; } 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) - { - 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(); + if (Abs(angleDiffBtwObjCenterAndForward) >= objTopRightHeading) { + if (PI - objTopRightHeading >= Abs(angleDiffBtwObjCenterAndForward)) { + if ((angleDiffBtwObjCenterAndForward <= 0.0f || objUpsideDown) && (angleDiffBtwObjCenterAndForward < 0.0f || !objUpsideDown)) { + if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { + m_walkAroundType = 0; + } else { + if (CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) >= 0.0f) { + if (entityOnBottomRightOfObj == 1 || entityOnBottomRightOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { + m_walkAroundType = 1; + } else if (entityOnBottomLeftOfObj == 1 || entityOnBottomLeftOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { + m_walkAroundType = 1; + } + } else { + if (entityOnTopRightOfObj == 1 || entityOnTopRightOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { + m_walkAroundType = 4; + } else if (entityOnTopLeftOfObj == 1 || entityOnTopLeftOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { + m_walkAroundType = 4; + } + } + } + } else { + if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { + m_walkAroundType = 0; + } else { + if (CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) <= 0.0f) { + if (entityOnBottomLeftOfObj == 1 || entityOnBottomLeftOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { + m_walkAroundType = 2; + } else if (entityOnBottomRightOfObj == 1 || entityOnBottomRightOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { + m_walkAroundType = 2; + } + } else { + if (entityOnTopLeftOfObj == 1 || entityOnTopLeftOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { + m_walkAroundType = 3; + } else if (entityOnTopRightOfObj == 1 || entityOnTopRightOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { + m_walkAroundType = 3; + } + } + } + } + } else if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) < 0.0f) { + if (entityOnTopLeftOfObj == 1 || entityOnTopLeftOfObj && !entityOnTopRightOfObj && !entityOnBottomRightOfObj) { + m_walkAroundType = 3; + } + } else if (entityOnTopRightOfObj == 1 || entityOnTopRightOfObj && !entityOnTopLeftOfObj && !entityOnBottomLeftOfObj) { + m_walkAroundType = 4; + } + } else if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) + || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { + if (entityOnBottomLeftOfObj == 1 || entityOnBottomLeftOfObj && !entityOnTopRightOfObj && !entityOnBottomRightOfObj) { + m_walkAroundType = 2; + } + } else if (entityOnBottomRightOfObj == 1 || entityOnBottomRightOfObj && !entityOnTopLeftOfObj && !entityOnBottomLeftOfObj) { + m_walkAroundType = 1; } else { - driver->m_pMyVehicle = veh; - driver->PositionPedOutOfCollision(); - driver->m_pMyVehicle = nil; + m_walkAroundType = 0; } - 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; + m_collidingEntityWhileFleeing = obj; + m_collidingEntityWhileFleeing->RegisterReference((CEntity**) &m_collidingEntityWhileFleeing); - if (ped->IsPlayer() && ((CPlayerPed*)ped)->m_bAdrenalineActive) - ((CPlayerPed*)ped)->ClearAdrenaline(); + // TODO: This random may need to be changed. + m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 512 + CGeneral::GetRandomNumber(); - 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; + CVector localPosToHead; - ped->m_nPedState = PED_DRIVING; - ped->StopNonPartialAnims(); - return; +#ifdef NEW_WALK_AROUND_ALGORITHM + int nextWalkAround = m_walkAroundType; + if (m_walkAroundType % 2 == 0) { + nextWalkAround += 2; + if (nextWalkAround > 6) + nextWalkAround = 0; + } else { + nextWalkAround -= 2; + if (nextWalkAround < 0) + nextWalkAround = 7; } - if (ped->m_pVehicleAnim) - ped->m_pVehicleAnim->blendDelta = -1000.0f; + CVector nextPosToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, nextWalkAround, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); + bool nextRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), nextPosToHead, true, true, true, true, true, true, false); - ped->bDoBloodyFootprints = false; - if (veh->m_nAlarmState == -1) - veh->m_nAlarmState = 15000; + if(nextRouteIsClear) + m_walkAroundType = nextWalkAround; + else { + CVector posToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); + bool currentRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), posToHead, + true, true, true, true, true, true, false); - 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 + /* Either; + * - Some obstacle came in and it's impossible to reach current destination + * - We reached to the destination, but since next route is not clear, we're turning around us + */ + if (!currentRouteIsClear || + ((posToHead - GetPosition()).Magnitude2D() < 0.8f && + !CWorld::GetIsLineOfSightClear(GetPosition() + GetForward(), nextPosToHead, + true, true, true, true, true, true, false))) { + + // Change both target and direction (involves changing even/oddness) + if (m_walkAroundType % 2 == 0) { + m_walkAroundType -= 2; + if (m_walkAroundType < 0) + m_walkAroundType = 7; + else + m_walkAroundType += 1; + } else { + m_walkAroundType += 2; + if (m_walkAroundType > 7) + m_walkAroundType = 0; + else + m_walkAroundType -= 1; } } } - // 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); + localPosToHead = LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); +#else + if (Abs(angleDiffBtwObjCenterAndForward) < objTopRightHeading) { + if (goingToEnterCar) { + if (goingToEnterCarAndItsVan) { + if (m_vehEnterType == CAR_DOOR_LR || m_vehEnterType == CAR_DOOR_RR) + return; + } + if (m_vehEnterType != CAR_DOOR_LF && m_vehEnterType != CAR_DOOR_LR && (!entityOnBottomRightOfObj || entityOnBottomLeftOfObj)) { + m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); + localPosToHead.x = adjustedColMax.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } else { + m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); + localPosToHead.x = adjustedColMin.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } + } else { + if (m_walkAroundType != 1 && m_walkAroundType != 4 + && (m_walkAroundType || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) <= 0.0f)) { - if (!veh->bEngineOn) { - veh->bEngineOn = true; - DMAudio.PlayOneShot(ped->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); + m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); + localPosToHead.x = adjustedColMax.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } else { + m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); + localPosToHead.x = adjustedColMin.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } } - if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && ped->CharCreatedBy == RANDOM_CHAR - && ped != FindPlayerPed() && ped->m_nPedType != PEDTYPE_EMERGENCY) { + } else { + if (PI - objTopRightHeading >= Abs(angleDiffBtwObjCenterAndForward)) { + if (angleDiffBtwObjCenterAndForward <= 0.0f) { + if (!goingToEnterCar || !goingToEnterCarAndItsVan || m_vehEnterType != CAR_DOOR_LR && m_vehEnterType != CAR_DOOR_RR) { + if (goingToEnterCar) { + if (m_vehEnterType == CAR_DOOR_RF || (m_vehEnterType == CAR_DOOR_RR && !goingToEnterCarAndItsVan)) + return; + } + if (m_walkAroundType == 4 || m_walkAroundType == 3 + || !m_walkAroundType && CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { - 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) { + m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); + localPosToHead.x = adjustedColMax.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } else { + m_fRotationDest = dirToSet; + localPosToHead.x = adjustedColMax.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMax.y; + } + } else { + m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); + localPosToHead.x = adjustedColMax.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } + } else if (goingToEnterCar && goingToEnterCarAndItsVan && (m_vehEnterType == CAR_DOOR_LR || m_vehEnterType == CAR_DOOR_RR)) { + m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); + localPosToHead.x = adjustedColMin.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } else { + if (goingToEnterCar) { + if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR && !goingToEnterCarAndItsVan) + return; + } + if (m_walkAroundType == 1 || m_walkAroundType == 2 + || !m_walkAroundType && CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { - 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; + m_fRotationDest = dirToSet; + localPosToHead.x = adjustedColMin.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMax.y; + } else { + m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); + localPosToHead.x = adjustedColMin.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMin.y; + } + } + } else { + if (goingToEnterCar && (!goingToEnterCarAndItsVan || m_vehEnterType != CAR_DOOR_LR && m_vehEnterType != CAR_DOOR_RR)) { + if (m_vehEnterType != CAR_DOOR_LF && m_vehEnterType != CAR_DOOR_LR && (!entityOnTopRightOfObj || entityOnTopLeftOfObj)) { - ped->RestorePreviousObjective(); - } + m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); + localPosToHead.x = adjustedColMax.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMax.y; + } else { + m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); + localPosToHead.x = adjustedColMin.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMax.y; + } + } else { + if (m_walkAroundType == 2 || m_walkAroundType == 3 + || !m_walkAroundType && CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { - } 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; + m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); + localPosToHead.x = adjustedColMax.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMax.y; + } else { + m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); + localPosToHead.x = adjustedColMin.x; + localPosToHead.z = 0.0f; + localPosToHead.y = adjustedColMax.y; + } } } - 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 } +#endif + if (objUpsideDown) + localPosToHead.x = localPosToHead.x * -1.0f; - 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); - } + localPosToHead = objMat * localPosToHead; + m_actionX = localPosToHead.x; + m_actionY = localPosToHead.y; + localPosToHead -= GetPosition(); + m_fRotationDest = CGeneral::LimitRadianAngle(localPosToHead.Heading()); - if (veh->pDriver == ped) { - if (veh->bLowVehicle) { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); + if (m_fRotationDest != m_fRotationCur && bHitSomethingLastFrame) { + if (m_fRotationDest == oldRotDest) { + m_fRotationDest = oldRotDest; } else { - ped->m_pVehicleAnim = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); + m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); } - } 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); + float dist = localPosToHead.Magnitude2D(); + if (dist < 0.5f) + dist = 0.5f; - veh->bHasBeenOwnedByPlayer = true; - } - ped->bChangedSeat = true; + if (dist > distLimitForTimer) + dist = distLimitForTimer; + m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 280.0f * dist * checkIntervalInTime; } -void -CPed::PedSetInTrainCB(CAnimBlendAssociation* animAssoc, void* arg) +bool +CPed::IsPedInControl(void) { - 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); + return m_nPedState <= PED_STATES_NO_AI + && !bIsInTheAir && !bIsLanding + && m_fHealth > 0.0f; } -void -CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) +bool +CPed::IsPedShootable(void) { - /* - CPed *ped = (CPed*)arg; - - if (ped->m_nPedState == PED_STAGGER) - // nothing - */ + return m_nPedState <= PED_STATES_NO_ST; } -// It's "CPhoneInfo::ProcessNearestFreePhone" in PC IDB but that's not true, someone made it up. bool -CPed::RunToReportCrime(eCrimeType crimeToReport) +CPed::UseGroundColModel(void) { -#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 + return m_nPedState == PED_FALL || + m_nPedState == PED_DIVE_AWAY || + m_nPedState == PED_DIE || + m_nPedState == PED_DEAD; +} - CVector pos = GetPosition(); - int phoneId = gPhoneInfo.FindNearestFreePhone(&pos); +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; +} - if (phoneId == -1) - return false; +bool +CPed::CanSetPedState(void) +{ + return !DyingOrDead() && m_nPedState != PED_ARRESTED && !EnteringCar() && m_nPedState != PED_STEAL_CAR; +} - CPhone *phone = &gPhoneInfo.m_aPhones[phoneId]; -#ifndef PEDS_REPORT_CRIMES_ON_PHONE - if (phone->m_nState != PHONE_STATE_FREE) +bool +CPed::CanStrafeOrMouseControl(void) +{ +#ifdef FREE_CAM + if (CCamera::bFreeCam) 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; + 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::RegisterThreatWithGangPeds(CEntity *attacker) +CPed::PedGetupCB(CAnimBlendAssociation* animAssoc, void* arg) { - 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; + CPed* ped = (CPed*)arg; - for (int j = 0; j < lastVehicle; ++j) { - CVehicle *nearVeh = (CVehicle*) vehicles[j]; + if (ped->m_nPedState == PED_GETUP) + RpAnimBlendClumpSetBlendDeltas(ped->GetClump(), ASSOC_PARTIAL, -1000.0f); - if (nearVeh->VehicleCreatedBy != MISSION_VEHICLE) { - CPed *nearVehDriver = nearVeh->pDriver; + ped->bFallenDown = false; + animAssoc->blendDelta = -1000.0f; + if (ped->m_nPedState == PED_GETUP) + ped->RestorePreviousState(); - if (nearVehDriver && nearVehDriver != this && nearVehDriver->m_nPedType == m_nPedType) { + if (ped->m_nPedState != PED_FLEE_POS && ped->m_nPedState != PED_FLEE_ENTITY) + ped->SetMoveState(PEDMOVE_STILL); + else + ped->SetMoveState(PEDMOVE_RUN); - 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; - } - } - } - } - } - } + ped->SetMoveAnim(); + ped->bGetUpAnimStarted = false; } void -CPed::ReactToPointGun(CEntity *entWithGun) +CPed::PedLandCB(CAnimBlendAssociation* animAssoc, void* arg) { - 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; + CPed* ped = (CPed*)arg; - 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); - } + animAssoc->blendDelta = -1000.0f; + ped->bIsLanding = false; - if (m_nPedType == PEDTYPE_COP) { - if (pedWithGun->IsPlayer()) { - ((CPlayerPed*)pedWithGun)->m_pWanted->SetWantedLevelNoDrop(2); - if (bCrouchWhenShooting || bKindaStayInSamePlace) { - SetDuck(CGeneral::GetRandomNumberInRange(1000, 3000)); - return; - } - } - } + if (ped->m_nPedState == PED_JUMP) + ped->RestorePreviousState(); +} - 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); - } +void +CPed::PedStaggerCB(CAnimBlendAssociation* animAssoc, void* arg) +{ + /* + CPed *ped = (CPed*)arg; - 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; - } - } - } + if (ped->m_nPedState == PED_STAGGER) + // nothing + */ } void @@ -11857,1850 +4211,1098 @@ CPed::PedSetOutCarCB(CAnimBlendAssociation *animAssoc, void *arg) ped->SetMoveState(PEDMOVE_RUN); ped->Say(SOUND_PED_FLEE_RUN); } - startedToRun = true; + 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::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; +} + +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; - // This is not a good way to do this... - ped->m_nLastPedState = PED_WANDER_PATH; + ped->m_nPedState = PED_DRIVING; + ped->StopNonPartialAnims(); + return; + } - } 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; + if (ped->m_pVehicleAnim) + ped->m_pVehicleAnim->blendDelta = -1000.0f; - } else if (ped->bGonnaKillTheCarJacker) { + ped->bDoBloodyFootprints = false; + if (veh->m_nAlarmState == -1) + veh->m_nAlarmState = 15000; - // 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; + 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); } - 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)); + 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 - else { - ped->m_nPedState = PED_IDLE; + 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 (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; - } - } + 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; } - 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->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->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 (!veh->bEngineOn) { + veh->bEngineOn = true; + DMAudio.PlayOneShot(ped->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); } - if (CGarages::IsPointWithinAnyGarage(ped->GetPosition())) - veh->bLightsOn = false; - } + if (ped->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && ped->CharCreatedBy == RANDOM_CHAR + && ped != FindPlayerPed() && ped->m_nPedType != PEDTYPE_EMERGENCY) { - if (ped->IsPlayer()) - AudioManager.PlayerJustLeftCar(); + 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) { - ped->ReplaceWeaponWhenExitingVehicle(); + 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->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 + ped->RestorePreviousObjective(); + } - if (createdBy == MISSION_CHAR && !startedToRun) - ped->SetMoveState(PEDMOVE_WALK); + } 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 } -} -// It was inlined in III but not in VC. -inline void -CPed::ReplaceWeaponWhenExitingVehicle(void) -{ - eWeaponType weaponType = GetWeapon()->m_eWeaponType; + veh->m_nGettingInFlags &= ~GetCarDoorFlag(ped->m_vehEnterType); - // 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); - } -} + if (veh->bIsBus && !veh->m_nGettingInFlags) + ((CAutomobile*)veh)->SetBusDoorTimer(1000, 1); -// 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); + 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); } -} -void -CPed::PedSetOutTrainCB(CAnimBlendAssociation *animAssoc, void *arg) -{ - CPed *ped = (CPed*)arg; + 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; - CVehicle *veh = ped->m_pMyVehicle; + // 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 (ped->m_pVehicleAnim) - ped->m_pVehicleAnim->blendDelta = -1000.0f; + if (!veh->bHasBeenOwnedByPlayer && veh->VehicleCreatedBy != MISSION_VEHICLE) + CEventList::RegisterEvent(EVENT_STEAL_CAR, EVENT_ENTITY_VEHICLE, veh, ped, 1500); - 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); + veh->bHasBeenOwnedByPlayer = true; + } + ped->bChangedSeat = true; } bool -CPed::PlacePedOnDryLand(void) +CPed::CanBeDeleted(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)) + if (bInVehicle) 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; + switch (CharCreatedBy) { + case RANDOM_CHAR: + return true; + case MISSION_CHAR: + return false; + default: 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::AddWeaponModel(int id) { - 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()) { + RpAtomic *atm; -#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); + if (id != -1) { +#ifdef PED_SKIN + if (IsClumpSkinned(GetClump())) { + if (m_pWeaponModel) + RemoveWeaponModel(-1); -#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); + m_pWeaponModel = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + } else #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); - } + { + atm = (RpAtomic*)CModelInfo::GetModelInfo(id)->CreateInstance(); + RwFrameDestroy(RpAtomicGetFrame(atm)); + RpAtomicSetFrame(atm, m_pFrames[PED_HANDR]->frame); + RpClumpAddAtomic(GetClump(), atm); } + m_wepModelID = id; } - if (ped->m_nLastPedState == PED_IDLE) - ped->m_nLastPedState = PED_WANDER_PATH; } -bool -CPed::PositionPedOutOfCollision(void) +static RwObject* +RemoveAllModelCB(RwObject *object, void *data) { - 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); + RpAtomic *atomic = (RpAtomic*)object; + if (CVisibilityPlugins::GetAtomicModelInfo(atomic)) { + RpClumpRemoveAtomic(RpAtomicGetClump(atomic), atomic); + RpAtomicDestroy(atomic); } - return true; + return object; } -bool -CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) +void +CPed::RemoveWeaponModel(int modelId) { - 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; - } + // 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 (!foundIt) - return false; + if (weapon.m_eWeaponState == WEAPONSTATE_OUT_OF_AMMO) + weapon.m_eWeaponState = WEAPONSTATE_READY; - helperPos = GetPosition() - foundPos; - helperPos.z = 0.0f; - if (helperPos.MagnitudeSqr() <= sq(0.5f)) - return false; + return weaponType; +} - pos->x = foundPos.x; - pos->y = foundPos.y; - return true; +// Some kind of VC leftover I think +int +CPed::GetWeaponSlot(eWeaponType weaponType) +{ + if (HasWeapon(weaponType)) + return weaponType; + else + return -1; } void -CPed::Render(void) +CPed::SetCurrentWeapon(uint32 weaponType) { - 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; - } + CWeaponInfo *weaponInfo; + if (HasWeapon(weaponType)) { + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(weaponInfo->m_nModelId); - CEntity::Render(); + m_currentWeapon = weaponType; -#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); + weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + AddWeaponModel(weaponInfo->m_nModelId); } -#endif } -#ifdef PED_SKIN -static RpMaterial* -SetLimbAlphaCB(RpMaterial *material, void *data) +void +CPed::GrantAmmo(eWeaponType weaponType, uint32 ammo) { - ((RwRGBA*)RpMaterialGetColor(material))->alpha = *(uint8*)data; - return material; + if (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal += ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; + } } void -CPed::renderLimb(int node) +CPed::SetAmmo(eWeaponType weaponType, uint32 ammo) { - 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 (HasWeapon(weaponType)) { + GetWeapon(weaponType).m_nAmmoTotal = ammo; + } else { + GetWeapon(weaponType).Initialise(weaponType, ammo); + m_maxWeaponTypeAllowed++; } - 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) +CPed::ClearWeapons(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; - } + CWeaponInfo *currentWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(currentWeapon->m_nModelId); - 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) { + m_maxWeaponTypeAllowed = WEAPONTYPE_BASEBALLBAT; + m_currentWeapon = WEAPONTYPE_UNARMED; - 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; + 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; + } +} - 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) { +void +CPed::PreRender(void) +{ + CShadows::StoreShadowForPed(this, + CTimeCycle::m_fShadowDisplacementX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowDisplacementY[CTimeCycle::m_CurrentStoredValue], + CTimeCycle::m_fShadowFrontX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowFrontY[CTimeCycle::m_CurrentStoredValue], + CTimeCycle::m_fShadowSideX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowSideY[CTimeCycle::m_CurrentStoredValue]); - if (m_nPedState != PED_ARREST_PLAYER) - SetIdle(); +#ifdef PED_SKIN + if(IsClumpSkinned(GetClump())){ + UpdateRpHAnim(); - 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) { + if(bBodyPartJustCameOff && m_bodyPartBleeding == PED_HEAD){ + // scale head to 0 if shot off + RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); + int32 idx = RpHAnimIDGetIndex(hier, ConvertPedNode2BoneTag(PED_HEAD)); + RwMatrix *head = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; + RwV3d zero = { 0.0f, 0.0f, 0.0f }; + RwMatrixScale(head, &zero, rwCOMBINEPRECONCAT); + } + } +#endif - ((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 (bBodyPartJustCameOff && bIsPedDieAnimPlaying && m_bodyPartBleeding != -1 && (CTimer::GetFrameCounter() & 7) > 3) { + CVector bloodDir(0.0f, 0.0f, 0.0f); + CVector bloodPos(0.0f, 0.0f, 0.0f); - if (m_pedInObjective->EnteringCar()) - wepRangeAdjusted = 2.0f; + TransformToNode(bloodPos, m_bodyPartBleeding); - if (bUsePedNodeSeek) { - CVector bestCoords(0.0f, 0.0f, 0.0f); - m_vecSeekPos = m_pedInObjective->GetPosition(); + switch (m_bodyPartBleeding) { + case PED_HEAD: + bloodDir = 0.1f * GetUp(); + break; + case PED_UPPERARML: + bloodDir = 0.04f * GetUp() - 0.04f * GetRight(); + break; + case PED_UPPERARMR: + bloodDir = 0.04f * GetUp() - 0.04f * GetRight(); + break; + case PED_UPPERLEGL: + bloodDir = 0.04f * GetUp() + 0.05f * GetForward(); + break; + case PED_UPPERLEGR: + bloodDir = 0.04f * GetUp() + 0.05f * GetForward(); + break; + default: + bloodDir = CVector(0.0f, 0.0f, 0.0f); + break; + } - if (!m_pNextPathNode) - FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); + for(int i = 0; i < 4; i++) + CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, bloodDir, nil, 0.0f, 0, 0, 0, 0); + } + if (CWeather::Rain > 0.3f && TheCamera.SoundDistUp > 15.0f) { + if ((TheCamera.GetPosition() - GetPosition()).Magnitude() < 25.0f) { + bool doSplashUp = true; + CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); + CVector speed = FindPlayerSpeed(); - if (m_pNextPathNode) - m_vecSeekPos = m_pNextPathNode->GetPosition(); + if (Abs(speed.x) <= 0.05f && Abs(speed.y) <= 0.05f) { + if (!OnGround() && m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT) { + if (!IsPedHeadAbovePos(0.3f) || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED)) { + doSplashUp = false; + } + } else + doSplashUp = false; + } else + doSplashUp = false; - 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(); + if (doSplashUp && ourCol->numSpheres > 0) { + for(int i = 0; i < ourCol->numSpheres; i++) { + CColSphere *sphere = &ourCol->spheres[i]; + CVector splashPos; + switch (sphere->piece) { + case PEDPIECE_LEFTARM: + case PEDPIECE_RIGHTARM: + case PEDPIECE_HEAD: + splashPos = GetMatrix() * ourCol->spheres[i].center; + splashPos.z += 0.7f * sphere->radius; + splashPos.x += CGeneral::GetRandomNumberInRange(-0.15f, 0.15f); + splashPos.y += CGeneral::GetRandomNumberInRange(-0.15f, 0.15f); + CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, splashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 0, 0, CGeneral::GetRandomNumber() & 1, 0); + break; + default: 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); +void +CPed::Render(void) +{ + if (bInVehicle && m_nPedState != PED_EXIT_CAR && m_nPedState != PED_DRAG_FROM_CAR) { + if (!bRenderPedInCar) + return; - SetAttackTimer(time); - bObstacleShowedUpDuringKillObjective = false; + float camDistSq = (TheCamera.GetPosition() - GetPosition()).MagnitudeSqr(); + if (camDistSq > SQR(25.0f * TheCamera.LODDistMultiplier)) + return; + } - } 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; - } - } + CEntity::Render(); - 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; - } - } - } - } +#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 (distWithTargetSc < 2.5f && wepRange > 5.0f - && wepInfo->m_eWeaponFire != WEAPON_FIRE_MELEE) { +void +CPed::CheckAroundForPossibleCollisions(void) +{ + CVector ourCentre, objCentre; + CEntity *objects[8]; + int16 maxObject; - 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; + if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) + return; - 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); - } + 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; - } - 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; + } + object->GetBoundCentre(objCentre); + float radius = object->GetBoundRadius(); + if (radius > 4.5f || radius < 1.0f) + radius = 1.0f; - break; - } + // Developers gave up calculating Z diff. later according to asm. + float diff = CVector(ourCentre - objCentre).MagnitudeSqr2D(); - 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 + 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 - && (CharCreatedBy != MISSION_CHAR || m_carInObjective->pDriver->CharCreatedBy != RANDOM_CHAR) + if (m_nPedState == PED_AIM_GUN) + ClearPointGunAt(); + + m_nLastPedState = PED_NONE; #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); + m_nPedState = PED_IDLE; + SetMoveState(PEDMOVE_STILL); + } + if (m_nWaitState == WAITSTATE_FALSE) { + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000, 4000); + } +} + +void +CPed::Idle(void) +{ + CVehicle *veh = m_pMyVehicle; + if (veh && veh->m_nGettingOutFlags && m_vehEnterType) { - 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 (veh->m_nGettingOutFlags & GetCarDoorFlag(m_vehEnterType)) { - 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; - } - } + 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; } - 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); + CAnimBlendAssociation *armedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED); + CAnimBlendAssociation *unarmedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE); + int waitTime; - TurnBody(); - if (m_carInObjective->m_fHealth <= 0.0f) { - ClearLookFlag(); - bScriptObjectiveCompleted = true; - break; - } + if (m_nMoveState == PEDMOVE_STILL) { - 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) { + eWeaponType curWeapon = GetWeapon()->m_eWeaponType; + if (!armedIdleAssoc || + CTimer::GetTimeInMilliseconds() <= m_nWaitTimer && curWeapon != WEAPONTYPE_UNARMED && curWeapon != WEAPONTYPE_MOLOTOV && curWeapon != WEAPONTYPE_GRENADE) { - float safeDistance; - if (wepRange <= 5.0f) - safeDistance = 3.0f; - else - safeDistance = wepRange * 0.25f; + if ((!GetWeapon()->IsType2Handed() || curWeapon == WEAPONTYPE_SHOTGUN) && curWeapon != WEAPONTYPE_BASEBALLBAT + || !unarmedIdleAssoc || unarmedIdleAssoc->blendAmount <= 0.95f || m_nWaitState != WAITSTATE_FALSE || CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { - 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 + m_moved = CVector2D(0.0f, 0.0f); + return; } - 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; + 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); +} - if (!m_pNextPathNode) - FindBestCoordsFromNodes(m_vecSeekPos, &bestCoords); +void +CPed::ClearPause(void) +{ + RestorePreviousState(); +} - if (m_pNextPathNode) - m_vecSeekPos = m_pNextPathNode->GetPosition(); - } - SetSeek(m_vecSeekPos, m_distanceToCountSeekDone); - } - } +void +CPed::Pause(void) +{ + m_moved = CVector2D(0.0f, 0.0f); + if (CTimer::GetTimeInMilliseconds() > m_leaveCarTimer) + ClearPause(); +} - 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); +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 + ) + 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; - 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); + bIsInTheAir = true; + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_GLIDE, 4.0f); - if (walkAssoc) - walkAssoc->speed = 1.3f; - } - } else { - ClearObjective(); - SetWanderPath(CGeneral::GetRandomNumber() & 7); - } - } else { + 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 - m_objective = OBJECTIVE_NONE; + || bIsStanding #endif - ClearObjective(); + ) + SetLanding(); + } else { + if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL)) { + if (m_vecMoveSpeed.z < -0.1f) + CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_FALL, 4.0f); } - 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; + } + } +} + +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::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); } -#endif + return; } - 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(); + 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 { - SetWanderPath(CGeneral::GetRandomNumber() & 7); + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f); } - ClearAimFlag(); - ClearLookFlag(); + 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) { @@ -13710,3688 +5312,3156 @@ CPed::SetShootTimer(uint32 time) } void -CPed::SetSeekCar(CVehicle *car, uint32 doorNode) +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 (m_nPedState == PED_SEEK_CAR) + if (!IsPedInControl()) return; -#ifdef VC_PED_PORTS - if (!CanSetPedState() || m_nPedState == PED_DRIVING) + if (m_nPedState == PED_SEEK_ENTITY && m_pSeekTarget == seeking) 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; + 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::SetSeekBoatPosition(CVehicle *boat) +CPed::ClearSeek(void) { - 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; + SetIdle(); + bRunningToPhone = false; } -void -CPed::SetExitTrain(CVehicle* train) +bool +CPed::Seek(void) { - if (m_nPedState == PED_EXIT_TRAIN || train->GetStatus() != STATUS_TRAIN_NOT_MOVING || !((CTrain*)train)->Doors[0].IsFullyOpen()) - return; + float distanceToCountItDone = m_distanceToCountSeekDone; + eMoveState nextMove = PEDMOVE_NONE; - /* - // 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(); -} + if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { -#ifdef NEW_WALK_AROUND_ALGORITHM -CVector -LocalPosForWalkAround(CVector2D colMin, CVector2D colMax, int walkAround, uint32 enterDoorNode, bool itsVan) { - switch (walkAround) { - case 0: - if (enterDoorNode == CAR_DOOR_LF) - return CVector(colMin.x, colMax.y - 1.0f, 0.0f); - case 1: - return CVector(colMin.x, colMax.y, 0.0f); - case 2: - case 3: - if (walkAround == 3 && enterDoorNode == CAR_DOOR_RF) - return CVector(colMax.x, colMax.y - 1.0f, 0.0f); + 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)) { - return CVector(colMax.x, colMax.y, 0.0f); - case 4: - if (enterDoorNode == CAR_DOOR_RR && !itsVan) - return CVector(colMax.x, colMin.y + 1.0f, 0.0f); - case 5: - return CVector(colMax.x, colMin.y, 0.0f); - case 6: - case 7: - if (walkAround == 7 && enterDoorNode == CAR_DOOR_LR && !itsVan) - return CVector(colMin.x, colMin.y + 1.0f, 0.0f); + CEntity *obstacle = CWorld::TestSphereAgainstWorld(m_vecSeekPos, 0.4f, nil, + false, true, false, false, false, false); - return CVector(colMin.x, colMin.y, 0.0f); - default: - return CVector(0.0f, 0.0f, 0.0f); + 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; + } + } + } + } } -} -bool -CanWeSeeTheCorner(CVector2D dist, CVector2D fwdOffset) -{ - // because fov isn't important if dist is more then 5 unit, we want shortest way - if (dist.Magnitude() > 5.0f) - return true; + if (!m_pSeekTarget && m_nPedState == PED_SEEK_ENTITY) + ClearSeek(); - if (DotProduct2D(dist, fwdOffset) < 0.0f) + 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; } -#endif -// This function looks completely same on VC. void -CPed::SetDirectionToWalkAroundObject(CEntity *obj) +CPed::SetFlee(CVector2D const &from, int time) { - float distLimitForTimer = 8.0f; - CColModel *objCol = CModelInfo::GetModelInfo(obj->GetModelIndex())->GetColModel(); - CVector objColMin = objCol->boundingBox.min; - CVector objColMax = objCol->boundingBox.max; - CVector objColCenter = (objColMin + objColMax) / 2.0f; - CMatrix objMat(obj->GetMatrix()); - float dirToSet = obj->GetForward().Heading(); - bool goingToEnterCarAndItsVan = false; - bool goingToEnterCar = false; - bool objUpsideDown = false; + if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer || !IsPedInControl() || bKindaStayInSamePlace) + return; - float checkIntervalInDist = (objColMax.y - objColMin.y) * 0.1f; - float checkIntervalInTime; + if (m_nPedState != PED_FLEE_ENTITY) { + SetStoredState(); + m_nPedState = PED_FLEE_POS; + SetMoveState(PEDMOVE_RUN); + m_fleeFromPosX = from.x; + m_fleeFromPosY = from.y; + } - if (m_nMoveState == PEDMOVE_NONE || m_nMoveState == PEDMOVE_STILL) - return; + bUsePedNodeSeek = true; + m_pNextPathNode = nil; + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; -#ifndef PEDS_REPORT_CRIMES_ON_PHONE - if (CharCreatedBy != MISSION_CHAR && obj->GetModelIndex() == MI_PHONEBOOTH1) { - bool isRunning = m_nMoveState == PEDMOVE_RUN || m_nMoveState == PEDMOVE_SPRINT; - SetFindPathAndFlee(obj, 5000, !isRunning); - return; + 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; } -#endif +} - CVector2D adjustedColMin(objColMin.x - 0.35f, objColMin.y - 0.35f); - CVector2D adjustedColMax(objColMax.x + 0.35f, objColMax.y + 0.35f); +void +CPed::SetFlee(CEntity *fleeFrom, int time) +{ + if (!IsPedInControl() || bKindaStayInSamePlace || !fleeFrom) + return; - checkIntervalInDist = Max(checkIntervalInDist, 0.5f); - checkIntervalInDist = Min(checkIntervalInDist, (objColMax.z - objColMin.z) / 2.0f); - checkIntervalInDist = Min(checkIntervalInDist, (adjustedColMax.x - adjustedColMin.x) / 2.0f); + SetStoredState(); + m_nPedState = PED_FLEE_ENTITY; + bUsePedNodeSeek = true; + SetMoveState(PEDMOVE_RUN); + m_fleeFrom = fleeFrom; + m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom); - if (objMat.GetUp().z < 0.0f) - objUpsideDown = true; + if (time <= 0) + m_fleeTimer = 0; + else + m_fleeTimer = CTimer::GetTimeInMilliseconds() + time; - if (obj->GetModelIndex() != MI_TRAFFICLIGHTS && obj->GetModelIndex() != MI_SINGLESTREETLIGHTS1 && obj->GetModelIndex() != MI_SINGLESTREETLIGHTS2) { - objColCenter = obj->GetMatrix() * objColCenter; - } else { - checkIntervalInDist = 0.4f; - if (objMat.GetUp().z <= 0.57f) { + float angleToFace = CGeneral::GetRadianAngleBetweenPoints( + GetPosition().x, GetPosition().y, + fleeFrom->GetPosition().x, fleeFrom->GetPosition().y); - // Specific calculations for traffic lights, didn't get a bit. - adjustedColMin.x = 1.2f * (adjustedColMin.x < adjustedColMin.y ? adjustedColMin.x : adjustedColMin.y); - adjustedColMax.x = 1.2f * (adjustedColMax.x > adjustedColMax.y ? adjustedColMax.x : adjustedColMax.y); - adjustedColMin.y = 1.2f * objColMin.z; - adjustedColMax.y = 1.2f * objColMax.z; - dirToSet = objMat.GetUp().Heading(); - objMat.SetUnity(); - objMat.RotateZ(dirToSet); - objMat.GetPosition() += obj->GetPosition(); - objColCenter = obj->GetPosition(); - } else { - objColCenter.x = adjustedColMax.x - 0.25f; - objColCenter = obj->GetMatrix() * objColCenter; - distLimitForTimer = 0.75f; - } - objUpsideDown = false; + 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; } - float oldRotDest = m_fRotationDest; -#ifndef NEW_WALK_AROUND_ALGORITHM - float angleToFaceObjCenter = (objColCenter - GetPosition()).Heading(); - float angleDiffBtwObjCenterAndForward = CGeneral::LimitRadianAngle(dirToSet - angleToFaceObjCenter); - float objTopRightHeading = Atan2(adjustedColMax.x - adjustedColMin.x, adjustedColMax.y - adjustedColMin.y); -#endif +} - if (IsPlayer()) { - if (FindPlayerPed()->m_fMoveSpeed <= 0.0f) - checkIntervalInTime = 0.0f; - else - checkIntervalInTime = 2.0f / FindPlayerPed()->m_fMoveSpeed; - } else { - switch (m_nMoveState) { - case PEDMOVE_WALK: - checkIntervalInTime = 2.0f; - break; - case PEDMOVE_RUN: - checkIntervalInTime = 0.5f; - break; - case PEDMOVE_SPRINT: - checkIntervalInTime = 0.5f; - break; - default: - checkIntervalInTime = 0.0f; - break; - } - } - if (m_pSeekTarget == obj && obj->IsVehicle()) { - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER - || m_objective == OBJECTIVE_SOLICIT_VEHICLE) { - goingToEnterCar = true; - if (IsPlayer()) - checkIntervalInTime = 0.0f; +void +CPed::ClearFlee(void) +{ + RestorePreviousState(); + bUsePedNodeSeek = false; + m_standardTimer = 0; + m_fleeTimer = 0; +} - if (((CVehicle*)obj)->bIsVan) - goingToEnterCarAndItsVan = true; +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; } - } - - int entityOnTopLeftOfObj = 0; - int entityOnBottomLeftOfObj = 0; - int entityOnTopRightOfObj = 0; - int entityOnBottomRightOfObj = 0; - if (CTimer::GetTimeInMilliseconds() > m_collidingThingTimer || m_collidingEntityWhileFleeing != obj) { - bool collidingThingChanged = true; - CEntity *obstacle; + if (mayFinishFleeing) { + eMoveState moveState = m_nMoveState; + ClearFlee(); -#ifndef NEW_WALK_AROUND_ALGORITHM - if (!obj->IsVehicle() || objUpsideDown) { - collidingThingChanged = false; - } else { -#else - CVector cornerToGo = CVector(10.0f, 10.0f, 10.0f); - int dirToGo; - m_walkAroundType = 0; - int iWouldPreferGoingBack = 0; // 1:left 2:right -#endif - float adjustedCheckInterval = 0.7f * checkIntervalInDist; - CVector posToCheck; + if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE || m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS) + RestorePreviousObjective(); - // Top left of obj - posToCheck.x = adjustedColMin.x + adjustedCheckInterval; - posToCheck.y = adjustedColMax.y - adjustedCheckInterval; - posToCheck.z = 0.0f; - posToCheck = objMat * posToCheck; - posToCheck.z += 0.6f; - obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, - true, true, false, true, false, false); - if (obstacle) { - if (obstacle->IsBuilding()) { - entityOnTopLeftOfObj = 1; - } else if (obstacle->IsVehicle()) { - entityOnTopLeftOfObj = 2; - } else { - entityOnTopLeftOfObj = 3; - } + 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); } -#ifdef NEW_WALK_AROUND_ALGORITHM - else { - CVector tl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMax.y, 0.0f) - GetPosition(); - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { - cornerToGo = tl; - m_walkAroundType = 1; + return; + } + m_fleeTimer = CTimer::GetTimeInMilliseconds() + 5000; + } - if (m_vehEnterType == CAR_DOOR_LR) - iWouldPreferGoingBack = 1; - } else if(CanWeSeeTheCorner(tl, GetForward())){ - cornerToGo = tl; - dirToGo = GetLocalDirection(tl); - if (dirToGo == 1) - m_walkAroundType = 0; // ALL of the next turns will be right turn - else if (dirToGo == 3) - m_walkAroundType = 1; // ALL of the next turns will be left turn - } - } -#endif + if (bUsePedNodeSeek) { + CPathNode *realLastNode = nil; + uint8 nextDirection = 0; + uint8 curDirectionShouldBe = 9; // means not defined yet - // Top right of obj - posToCheck.x = adjustedColMax.x - adjustedCheckInterval; - posToCheck.y = adjustedColMax.y - adjustedCheckInterval; - posToCheck.z = 0.0f; - posToCheck = objMat * posToCheck; - posToCheck.z += 0.6f; - obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, - true, true, false, true, false, false); - if (obstacle) { - if (obstacle->IsBuilding()) { - entityOnTopRightOfObj = 1; - } else if (obstacle->IsVehicle()) { - entityOnTopRightOfObj = 2; - } else { - entityOnTopRightOfObj = 3; - } - } -#ifdef NEW_WALK_AROUND_ALGORITHM - else { - CVector tr = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMax.y, 0.0f) - GetPosition(); - if (tr.Magnitude2D() < cornerToGo.Magnitude2D()) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { - cornerToGo = tr; - m_walkAroundType = 2; + if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds() + && m_collidingThingTimer < CTimer::GetTimeInMilliseconds()) { - if (m_vehEnterType == CAR_DOOR_RR) - iWouldPreferGoingBack = 2; - } else if (CanWeSeeTheCorner(tr, GetForward())) { - cornerToGo = tr; - dirToGo = GetLocalDirection(tr); - if (dirToGo == 1) - m_walkAroundType = 2; // ALL of the next turns will be right turn - else if (dirToGo == 3) - m_walkAroundType = 3; // ALL of the next turns will be left turn - } - } - } -#endif + if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) { - // Bottom right of obj - posToCheck.x = adjustedColMax.x - adjustedCheckInterval; - posToCheck.y = adjustedColMin.y + adjustedCheckInterval; - posToCheck.z = 0.0f; - posToCheck = objMat * posToCheck; - posToCheck.z += 0.6f; - obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, - true, true, false, true, false, false); - if (obstacle) { - if (obstacle->IsBuilding()) { - entityOnBottomRightOfObj = 1; - } else if (obstacle->IsVehicle()) { - entityOnBottomRightOfObj = 2; - } else { - entityOnBottomRightOfObj = 3; + 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; } } -#ifdef NEW_WALK_AROUND_ALGORITHM - else { - CVector br = obj->GetMatrix() * CVector(adjustedColMax.x, adjustedColMin.y, 0.0f) - GetPosition(); - if (iWouldPreferGoingBack == 2) - m_walkAroundType = 4; - else if (br.Magnitude2D() < cornerToGo.Magnitude2D()) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { - cornerToGo = br; - m_walkAroundType = 5; - } else if (CanWeSeeTheCorner(br, GetForward())) { - cornerToGo = br; - dirToGo = GetLocalDirection(br); - if (dirToGo == 1) - m_walkAroundType = 4; // ALL of the next turns will be right turn - else if (dirToGo == 3) - m_walkAroundType = 5; // ALL of the next turns will be left turn - } + + 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); } -#endif + } - // Bottom left of obj - posToCheck.x = adjustedColMin.x + adjustedCheckInterval; - posToCheck.y = adjustedColMin.y + adjustedCheckInterval; - posToCheck.z = 0.0f; - posToCheck = objMat * posToCheck; - posToCheck.z += 0.6f; - obstacle = CWorld::TestSphereAgainstWorld(posToCheck, checkIntervalInDist, obj, - true, true, false, true, false, false); - if (obstacle) { - if (obstacle->IsBuilding()) { - entityOnBottomLeftOfObj = 1; - } else if (obstacle->IsVehicle()) { - entityOnBottomLeftOfObj = 2; - } else { - entityOnBottomLeftOfObj = 3; - } + if (!m_pNextPathNode) { + if (curDirectionShouldBe == 9) { + curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y); } -#ifdef NEW_WALK_AROUND_ALGORITHM - else { - CVector bl = obj->GetMatrix() * CVector(adjustedColMin.x, adjustedColMin.y, 0.0f) - GetPosition(); - if (iWouldPreferGoingBack == 1) - m_walkAroundType = 7; - else if (bl.Magnitude2D() < cornerToGo.Magnitude2D()) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { - cornerToGo = bl; - m_walkAroundType = 6; - } else if (CanWeSeeTheCorner(bl, GetForward())) { - cornerToGo = bl; - dirToGo = GetLocalDirection(bl); - if (dirToGo == 1) - m_walkAroundType = 6; // ALL of the next turns will be right turn - else if (dirToGo == 3) - m_walkAroundType = 7; // ALL of the next turns will be left turn - } - } + 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(); } -#else } + return; + } - if (entityOnTopLeftOfObj && entityOnTopRightOfObj && entityOnBottomRightOfObj && entityOnBottomLeftOfObj) { - collidingThingChanged = false; - entityOnTopLeftOfObj = 0; - entityOnBottomLeftOfObj = 0; - entityOnTopRightOfObj = 0; - entityOnBottomRightOfObj = 0; + 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 (!collidingThingChanged) { - m_walkAroundType = 0; + 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 { - if (Abs(angleDiffBtwObjCenterAndForward) >= objTopRightHeading) { - if (PI - objTopRightHeading >= Abs(angleDiffBtwObjCenterAndForward)) { - if ((angleDiffBtwObjCenterAndForward <= 0.0f || objUpsideDown) && (angleDiffBtwObjCenterAndForward < 0.0f || !objUpsideDown)) { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_RF || m_vehEnterType == CAR_DOOR_RR)) { - m_walkAroundType = 0; - } else { - if (CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) >= 0.0f) { - if (entityOnBottomRightOfObj == 1 || entityOnBottomRightOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { - m_walkAroundType = 1; - } else if (entityOnBottomLeftOfObj == 1 || entityOnBottomLeftOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { - m_walkAroundType = 1; - } - } else { - if (entityOnTopRightOfObj == 1 || entityOnTopRightOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { - m_walkAroundType = 4; - } else if (entityOnTopLeftOfObj == 1 || entityOnTopLeftOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { - m_walkAroundType = 4; - } - } - } - } else { - if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR)) { - m_walkAroundType = 0; - } else { - if (CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) <= 0.0f) { - if (entityOnBottomLeftOfObj == 1 || entityOnBottomLeftOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { - m_walkAroundType = 2; - } else if (entityOnBottomRightOfObj == 1 || entityOnBottomRightOfObj && !entityOnTopLeftOfObj && !entityOnTopRightOfObj) { - m_walkAroundType = 2; - } - } else { - if (entityOnTopLeftOfObj == 1 || entityOnTopLeftOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { - m_walkAroundType = 3; - } else if (entityOnTopRightOfObj == 1 || entityOnTopRightOfObj && !entityOnBottomRightOfObj && !entityOnBottomLeftOfObj) { - m_walkAroundType = 3; - } - } - } - } - } else if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) - || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) < 0.0f) { - if (entityOnTopLeftOfObj == 1 || entityOnTopLeftOfObj && !entityOnTopRightOfObj && !entityOnBottomRightOfObj) { - m_walkAroundType = 3; - } - } else if (entityOnTopRightOfObj == 1 || entityOnTopRightOfObj && !entityOnTopLeftOfObj && !entityOnBottomLeftOfObj) { - m_walkAroundType = 4; - } - } else if (goingToEnterCar && (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR) - || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { - if (entityOnBottomLeftOfObj == 1 || entityOnBottomLeftOfObj && !entityOnTopRightOfObj && !entityOnBottomRightOfObj) { - m_walkAroundType = 2; - } - } else if (entityOnBottomRightOfObj == 1 || entityOnBottomRightOfObj && !entityOnTopLeftOfObj && !entityOnBottomLeftOfObj) { - m_walkAroundType = 1; - } else { - m_walkAroundType = 0; - } + // 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); } -#endif } - m_collidingEntityWhileFleeing = obj; - m_collidingEntityWhileFleeing->RegisterReference((CEntity**) &m_collidingEntityWhileFleeing); +} - // TODO: This random may need to be changed. - m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 512 + CGeneral::GetRandomNumber(); +bool +CPed::SetWanderPath(int8 pathStateDest) +{ + uint8 nextPathState; - CVector localPosToHead; + if (IsPedInControl()) { + if (bKindaStayInSamePlace) { + SetIdle(); + return false; + } else { + m_nPathDir = pathStateDest; + if (pathStateDest == 0) + pathStateDest = CGeneral::GetRandomNumberInRange(1, 7); -#ifdef NEW_WALK_AROUND_ALGORITHM - int nextWalkAround = m_walkAroundType; - if (m_walkAroundType % 2 == 0) { - nextWalkAround += 2; - if (nextWalkAround > 6) - nextWalkAround = 0; + 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 { - nextWalkAround -= 2; - if (nextWalkAround < 0) - nextWalkAround = 7; + m_nPathDir = pathStateDest; + bStartWanderPathOnFoot = true; + return false; } +} - CVector nextPosToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, nextWalkAround, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); - bool nextRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), nextPosToHead, true, true, true, true, true, true, 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; - if(nextRouteIsClear) - m_walkAroundType = nextWalkAround; - else { - CVector posToHead = objMat * LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); - bool currentRouteIsClear = CWorld::GetIsLineOfSightClear(GetPosition(), posToHead, - true, true, true, true, true, true, false); + // 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; - /* Either; - * - Some obstacle came in and it's impossible to reach current destination - * - We reached to the destination, but since next route is not clear, we're turning around us - */ - if (!currentRouteIsClear || - ((posToHead - GetPosition()).Magnitude2D() < 0.8f && - !CWorld::GetIsLineOfSightClear(GetPosition() + GetForward(), nextPosToHead, - true, true, true, true, true, true, false))) { + CPathNode *previousLastNode = m_pLastPathNode; + uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; - // Change both target and direction (involves changing even/oddness) - if (m_walkAroundType % 2 == 0) { - m_walkAroundType -= 2; - if (m_walkAroundType < 0) - m_walkAroundType = 7; - else - m_walkAroundType += 1; - } else { - m_walkAroundType += 2; - if (m_walkAroundType > 7) - m_walkAroundType = 0; - else - m_walkAroundType -= 1; - } + // 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; } - localPosToHead = LocalPosForWalkAround(adjustedColMin, adjustedColMax, m_walkAroundType, goingToEnterCar ? m_vehEnterType : 0, goingToEnterCarAndItsVan); -#else - if (Abs(angleDiffBtwObjCenterAndForward) < objTopRightHeading) { - if (goingToEnterCar) { - if (goingToEnterCarAndItsVan) { - if (m_vehEnterType == CAR_DOOR_LR || m_vehEnterType == CAR_DOOR_RR) - return; - } - if (m_vehEnterType != CAR_DOOR_LF && m_vehEnterType != CAR_DOOR_LR && (!entityOnBottomRightOfObj || entityOnBottomLeftOfObj)) { - m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); - localPosToHead.x = adjustedColMax.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; - } else { - m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); - localPosToHead.x = adjustedColMin.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; + 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 { - if (m_walkAroundType != 1 && m_walkAroundType != 4 - && (m_walkAroundType || CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) <= 0.0f)) { - - m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); - localPosToHead.x = adjustedColMax.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; - } else { - m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); - localPosToHead.x = adjustedColMin.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; + 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; + } } } - } else { - if (PI - objTopRightHeading >= Abs(angleDiffBtwObjCenterAndForward)) { - if (angleDiffBtwObjCenterAndForward <= 0.0f) { - if (!goingToEnterCar || !goingToEnterCarAndItsVan || m_vehEnterType != CAR_DOOR_LR && m_vehEnterType != CAR_DOOR_RR) { - if (goingToEnterCar) { - if (m_vehEnterType == CAR_DOOR_RF || (m_vehEnterType == CAR_DOOR_RR && !goingToEnterCarAndItsVan)) - return; - } - if (m_walkAroundType == 4 || m_walkAroundType == 3 - || !m_walkAroundType && CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { + } - m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); - localPosToHead.x = adjustedColMax.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; - } else { - m_fRotationDest = dirToSet; - localPosToHead.x = adjustedColMax.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMax.y; - } - } else { - m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); - localPosToHead.x = adjustedColMax.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; - } - } else if (goingToEnterCar && goingToEnterCarAndItsVan && (m_vehEnterType == CAR_DOOR_LR || m_vehEnterType == CAR_DOOR_RR)) { - m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); - localPosToHead.x = adjustedColMin.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; - } else { - if (goingToEnterCar) { - if (m_vehEnterType == CAR_DOOR_LF || m_vehEnterType == CAR_DOOR_LR && !goingToEnterCarAndItsVan) - return; - } - if (m_walkAroundType == 1 || m_walkAroundType == 2 - || !m_walkAroundType && CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { + 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. - m_fRotationDest = dirToSet; - localPosToHead.x = adjustedColMin.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMax.y; - } else { - m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); - localPosToHead.x = adjustedColMin.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMin.y; - } - } - } else { - if (goingToEnterCar && (!goingToEnterCarAndItsVan || m_vehEnterType != CAR_DOOR_LR && m_vehEnterType != CAR_DOOR_RR)) { - if (m_vehEnterType != CAR_DOOR_LF && m_vehEnterType != CAR_DOOR_LR && (!entityOnTopRightOfObj || entityOnTopLeftOfObj)) { + // 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 - m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); - localPosToHead.x = adjustedColMax.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMax.y; - } else { - m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); - localPosToHead.x = adjustedColMin.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMax.y; - } - } else { - if (m_walkAroundType == 2 || m_walkAroundType == 3 - || !m_walkAroundType && CGeneral::LimitRadianAngle(m_fRotationDest - angleToFaceObjCenter) > 0.0f) { + // Move forward 1.25 meters + CVector2D testPosition = CVector2D(GetPosition()) + forward*1.25f; - m_fRotationDest = CGeneral::LimitRadianAngle(dirToSet - HALFPI); - localPosToHead.x = adjustedColMax.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMax.y; - } else { - m_fRotationDest = CGeneral::LimitRadianAngle(HALFPI + dirToSet); - localPosToHead.x = adjustedColMin.x; - localPosToHead.z = 0.0f; - localPosToHead.y = adjustedColMax.y; + // 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)); + } + } } } } } -#endif - if (objUpsideDown) - localPosToHead.x = localPosToHead.x * -1.0f; +} - localPosToHead = objMat * localPosToHead; - m_actionX = localPosToHead.x; - m_actionY = localPosToHead.y; - localPosToHead -= GetPosition(); - m_fRotationDest = CGeneral::LimitRadianAngle(localPosToHead.Heading()); +bool +CPed::SeekFollowingPath(CVector *unused) +{ + return m_nCurPathNode <= m_nPathNodes && m_nPathNodes; +} - if (m_fRotationDest != m_fRotationCur && bHitSomethingLastFrame) { - if (m_fRotationDest == oldRotDest) { - m_fRotationDest = oldRotDest; - } else { - m_fRotationDest = CGeneral::LimitRadianAngle(PI + dirToSet); - } +bool +CPed::SetFollowPath(CVector dest) +{ + if (m_nPedState == PED_FOLLOW_PATH) + return false; + + if (FindPlayerPed() != this) + return false; + + if ((dest - GetPosition()).Magnitude() <= 2.0f) + return false; + + CVector pointPoses[7]; + int16 pointsFound; + CPedPath::CalcPedRoute(0, GetPosition(), dest, pointPoses, &pointsFound, 7); + for(int i = 0; i < pointsFound; i++) { + m_stPathNodeStates[i].x = pointPoses[i].x; + m_stPathNodeStates[i].y = pointPoses[i].y; } - float dist = localPosToHead.Magnitude2D(); - if (dist < 0.5f) - dist = 0.5f; + m_nCurPathNode = 0; + m_nPathNodes = pointsFound; + if (m_nPathNodes < 1) + return false; - if (dist > distLimitForTimer) - dist = distLimitForTimer; - m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 280.0f * dist * checkIntervalInTime; + SetStoredState(); + m_nPedState = PED_FOLLOW_PATH; + SetMoveState(PEDMOVE_WALK); + return true; } -int32 -CPed::ProcessEntityCollision(CEntity *collidingEnt, CColPoint *collidingPoints) +void +CPed::FollowPath(void) { - bool collidedWithBoat = false; - bool belowTorsoCollided = false; - float gravityEffect = -0.15f * CTimer::GetTimeStep(); - CColPoint intersectionPoint; - CColLine ourLine; + 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; + } - CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); - CColModel *hisCol = CModelInfo::GetModelInfo(collidingEnt->GetModelIndex())->GetColModel(); + while (v4 < maxNodeIndex) + v4++; - if (!bUsesCollision) - return false; + } +*/ + if (Seek()) { + m_nCurPathNode++; + if (m_nCurPathNode == m_nPathNodes) + RestorePreviousState(); + } +} - if (collidingEnt->IsVehicle() && ((CVehicle*)collidingEnt)->IsBoat()) - collidedWithBoat = true; +void +CPed::SetEvasiveStep(CEntity *reason, uint8 animType) +{ + AnimationId stepAnim; - // 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 + if (m_nPedState == PED_STEP_AWAY || !IsPedInControl() || ((IsPlayer() || !bRespondsToThreats) && animType == 0)) + return; - m_vecMoveSpeed.z = 0.0f; - bIsStanding = true; - } else { - m_collPoly.valid = false; - m_fCollisionSpeed = 0.0f; - bHitSteepSlope = false; - } - } + 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; } + } +} - if (!bStillOnValidPoly) { - CVector potentialCenter = GetPosition(); - potentialCenter.z = GetPosition().z - 0.52f; +void +CPed::SetEvasiveDive(CPhysical *reason, uint8 onlyRandomJump) +{ + if (!IsPedInControl() || !bRespondsToThreats) + return; - // 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); + CAnimBlendAssociation *animAssoc; + float angleToFace, neededTurn; + bool handsUp = false; - 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) { + angleToFace = m_fRotationCur; + CVehicle *veh = (CVehicle*) reason; + if (reason->IsVehicle() && veh->m_vehType == VEHICLE_TYPE_CAR && veh->m_nCarHornTimer != 0 && !IsPlayer()) { + onlyRandomJump = true; + } - 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) { + 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 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; + 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; + } - 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); - } + angleToFace = CGeneral::GetRadianAngleBetweenPoints( + reason->GetPosition().x, reason->GetPosition().y, + GetPosition().x, GetPosition().y); + angleToFace = CGeneral::LimitRadianAngle(angleToFace); + m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur); - InflictDamage(collidingEnt, WEAPONTYPE_FALL, damage, PEDPIECE_TORSO, dir); - if (IsPlayer() && damage2 > 5.0f) - Say(SOUND_PED_LAND); + // 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); - } 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); + // Let's turn our back to the "reason" + angleToFace += PI; - 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); + if (angleToFace > PI) + angleToFace -= 2 * PI; - } 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; - } + // 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 - } else { - bOnBoat = false; - } - } + + 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); } - 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 (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; - if (ourCollidedSpheres > 0 && (collidingEnt->IsBuilding() || collidingEnt->GetIsStatic())) { - bHasHitWall = true; - } + 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 (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; - } + 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); } } - return ourCollidedSpheres; +#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::SetFormation(eFormation type) +CPed::PedEvadeCB(CAnimBlendAssociation* animAssoc, void* arg) { - // 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; + 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(); + } } - m_pedFormation = type; } void -CPed::SetFollowRoute(int16 currentPoint, int16 routeType) +CPed::SetDie(AnimationId animId, float delta, float speed) { - 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()); -} + CPlayerPed *player = FindPlayerPed(); + if (player == this) { + if (!player->m_bCanBeDamaged) + return; + } -// "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); - } + 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(); } -} -bool -CPed::WillChat(CPed *stranger) -{ - if (m_pNextPathNode && m_pLastPathNode) { - if (m_pNextPathNode != m_pLastPathNode && ThePaths.TestCrossesRoad(m_pNextPathNode, m_pLastPathNode)) { - return false; + 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; } } - 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; + + Say(SOUND_PED_DEATH); + if (m_nLastPedState == PED_ENTER_CAR || m_nLastPedState == PED_CARJACK) + QuitEnteringCar(); + if (!bInVehicle) + StopNonPartialAnims(); + + m_bloodyFootprintCountOrDeathTime = CTimer::GetTimeInMilliseconds(); } void -CPed::SetEnterTrain(CVehicle *train, uint32 unused) +CPed::FinishDieAnimCB(CAnimBlendAssociation *animAssoc, void *arg) { - 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); + CPed *ped = (CPed*)arg; - 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(); - } + if (ped->bIsPedDieAnimPlaying) + ped->bIsPedDieAnimPlaying = false; } void -CPed::SetDuck(uint32 time) +CPed::SetDead(void) { - if (bIsDucking || CTimer::GetTimeInMilliseconds() <= m_duckTimer) - return; + bUsesCollision = false; - 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; - } + 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::SeekBoatPosition(void) +CPed::Die(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(); + // UNUSED: This is a perfectly empty function. } void -CPed::SetEnterCar(CVehicle *car, uint32 unused) +CPed::SetChat(CEntity *chatWith, uint32 time) { - 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); - } + 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::SetRadioStation(void) +CPed::Chat(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 + // We're already looking to our partner + if (bIsLooking && TurnBody()) + ClearLookFlag(); - if (IsPlayer() || !m_pMyVehicle || m_pMyVehicle->pDriver != this) + if (!m_pLookTarget || !m_pLookTarget->IsPed()) { + ClearChat(); 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; + 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 { - for (orderInCat = 0; orderInCat < 4; orderInCat++) { - if (m_pMyVehicle->m_nRadioStation == radiosPerRadioCategories[category][orderInCat]) - break; + + 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 (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]; - } + if (m_standardTimer && CTimer::GetTimeInMilliseconds() > m_standardTimer) { + ClearChat(); + m_standardTimer = CTimer::GetTimeInMilliseconds() + 30000; } } -inline bool -CPed::IsNotInWreckedVehicle() +void +CPed::ClearChat(void) { - return m_pMyVehicle != nil && m_pMyVehicle->GetStatus() != STATUS_WRECKED; + 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 -CPed::PreRender(void) +ReportPhonePickUpCB(CAnimBlendAssociation* assoc, void* arg) { - CShadows::StoreShadowForPed(this, - CTimeCycle::m_fShadowDisplacementX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowDisplacementY[CTimeCycle::m_CurrentStoredValue], - CTimeCycle::m_fShadowFrontX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowFrontY[CTimeCycle::m_CurrentStoredValue], - CTimeCycle::m_fShadowSideX[CTimeCycle::m_CurrentStoredValue], CTimeCycle::m_fShadowSideY[CTimeCycle::m_CurrentStoredValue]); + CPed* ped = (CPed*)arg; + ped->m_nMoveState = PEDMOVE_STILL; + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_IDLE_STANCE, 8.0f); -#ifdef PED_SKIN - if(IsClumpSkinned(GetClump())){ - UpdateRpHAnim(); + if (assoc->blendAmount > 0.5f && ped) { + CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_PHONE_TALK, 8.0f); + } +} - if(bBodyPartJustCameOff && m_bodyPartBleeding == PED_HEAD){ - // scale head to 0 if shot off - RpHAnimHierarchy *hier = GetAnimHierarchyFromSkinClump(GetClump()); - int32 idx = RpHAnimIDGetIndex(hier, ConvertPedNode2BoneTag(PED_HEAD)); - RwMatrix *head = &RpHAnimHierarchyGetMatrixArray(hier)[idx]; - RwV3d zero = { 0.0f, 0.0f, 0.0f }; - RwMatrixScale(head, &zero, rwCOMBINEPRECONCAT); - } +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 - if (bBodyPartJustCameOff && bIsPedDieAnimPlaying && m_bodyPartBleeding != -1 && (CTimer::GetFrameCounter() & 7) > 3) { - CVector bloodDir(0.0f, 0.0f, 0.0f); - CVector bloodPos(0.0f, 0.0f, 0.0f); +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); - TransformToNode(bloodPos, m_bodyPartBleeding); + if (m_facePhoneStart) { + m_lookTimer = 0; + SetLookFlag(phoneDir, true); + m_lookTimer = CTimer::GetTimeInMilliseconds() + 3000; + m_facePhoneStart = false; + } - switch (m_bodyPartBleeding) { - case PED_HEAD: - bloodDir = 0.1f * GetUp(); - break; - case PED_UPPERARML: - bloodDir = 0.04f * GetUp() - 0.04f * GetRight(); - break; - case PED_UPPERARMR: - bloodDir = 0.04f * GetUp() - 0.04f * GetRight(); - break; - case PED_UPPERLEGL: - bloodDir = 0.04f * GetUp() + 0.05f * GetForward(); - break; - case PED_UPPERLEGR: - bloodDir = 0.04f * GetUp() + 0.05f * GetForward(); - break; - default: - bloodDir = CVector(0.0f, 0.0f, 0.0f); - break; - } + 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; + } - for(int i = 0; i < 4; i++) - CParticle::AddParticle(PARTICLE_BLOOD_SPURT, bloodPos, bloodDir, nil, 0.0f, 0, 0, 0, 0); + 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; } - if (CWeather::Rain > 0.3f && TheCamera.SoundDistUp > 15.0f) { - if ((TheCamera.GetPosition() - GetPosition()).Magnitude() < 25.0f) { - bool doSplashUp = true; - CColModel *ourCol = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel(); - CVector speed = FindPlayerSpeed(); +#endif +} +bool +CPed::MakePhonecall(void) +{ +#ifdef PEDS_REPORT_CRIMES_ON_PHONE + if (!IsPlayer() && CTimer::GetTimeInMilliseconds() > m_phoneTalkTimer - 7000 && bRunningToPhone) { - if (Abs(speed.x) <= 0.05f && Abs(speed.y) <= 0.05f) { - if (!OnGround() && m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT) { - if (!IsPedHeadAbovePos(0.3f) || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED)) { - doSplashUp = false; - } - } else - doSplashUp = false; - } else - doSplashUp = false; + FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(m_crimeToReportOnPhone, GetPosition(), + (m_crimeToReportOnPhone == CRIME_POSSESSION_GUN ? (uintptr)m_threatEntity : (uintptr)m_victimOfPlayerCrime), false); - if (doSplashUp && ourCol->numSpheres > 0) { - for(int i = 0; i < ourCol->numSpheres; i++) { - CColSphere *sphere = &ourCol->spheres[i]; - CVector splashPos; - switch (sphere->piece) { - case PEDPIECE_LEFTARM: - case PEDPIECE_RIGHTARM: - case PEDPIECE_HEAD: - splashPos = GetMatrix() * ourCol->spheres[i].center; - splashPos.z += 0.7f * sphere->radius; - splashPos.x += CGeneral::GetRandomNumberInRange(-0.15f, 0.15f); - splashPos.y += CGeneral::GetRandomNumberInRange(-0.15f, 0.15f); - CParticle::AddParticle(PARTICLE_RAIN_SPLASHUP, splashPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 0, 0, CGeneral::GetRandomNumber() & 1, 0); - break; - default: - break; - } - } - } - } + 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::ProcessBuoyancy(void) +CPed::Teleport(CVector pos) { - 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); + CWorld::Remove(this); + SetPosition(pos); + bIsStanding = false; + m_nPedStateTimer = 0; + m_actionX = 0.0f; + m_actionY = 0.0f; + m_pDamageEntity = nil; + CWorld::Add(this); +} - if (bInVehicle) +void +CPed::SetSeekCar(CVehicle *car, uint32 doorNode) +{ + if (m_nPedState == PED_SEEK_CAR) return; - CVector buoyancyPoint; - CVector buoyancyImpulse; +#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; + +} -#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 +void +CPed::SeekCar(void) +{ + CVehicle *vehToSeek = m_carInObjective; + CVector dest(0.0f, 0.0f, 0.0f); + if (!vehToSeek) { + RestorePreviousState(); + return; + } - 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; + if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + if (m_vehEnterType && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { + if (IsRoomToBeCarJacked()) { + dest = GetPositionToOpenCarDoor(vehToSeek, m_vehEnterType); + } else if (m_nPedType == PEDTYPE_COP) { + dest = GetPositionToOpenCarDoor(vehToSeek, CAR_DOOR_RF); + } else { + SetMoveState(PEDMOVE_STILL); + } + } else + GetNearestDoor(vehToSeek, dest); + } else { + if (m_hitRecoverTimer > CTimer::GetTimeInMilliseconds()) { + SetMoveState(PEDMOVE_STILL); 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; - } + if (vehToSeek->GetModelIndex() == MI_COACH) { + GetNearestDoor(vehToSeek, dest); + } else { + if (vehToSeek->IsTrain()) { + if (vehToSeek->GetStatus() != STATUS_TRAIN_NOT_MOVING) { + RestorePreviousObjective(); + RestorePreviousState(); + 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()); + if (!GetNearestTrainDoor(vehToSeek, dest)) { + RestorePreviousObjective(); + RestorePreviousState(); + return; } - 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 { + if (!GetNearestPassengerDoor(vehToSeek, dest)) { + if (vehToSeek->m_nNumPassengers == vehToSeek->m_nNumMaxPassengers) { + RestorePreviousObjective(); + RestorePreviousState(); + } else { + SetMoveState(PEDMOVE_STILL); + } + bVehEnterDoorIsBlocked = true; + return; } + bVehEnterDoorIsBlocked = false; } - } 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); + if (dest.x == 0.0f && dest.y == 0.0f) { +#ifdef FIX_BUGS + if ((!IsPlayer() && CharCreatedBy != MISSION_CHAR) || vehToSeek->VehicleCreatedBy != MISSION_VEHICLE || vehToSeek->pDriver || !vehToSeek->CanPedOpenLocks(this)) { #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)); + if ((!IsPlayer() && CharCreatedBy != MISSION_CHAR) || vehToSeek->VehicleCreatedBy != MISSION_VEHICLE || vehToSeek->pDriver) { #endif + RestorePreviousState(); + if (IsPlayer()) { + ClearObjective(); + } else if (CharCreatedBy == RANDOM_CHAR) { + m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; } + SetMoveState(PEDMOVE_STILL); + TheCamera.ClearPlayerWeaponMode(); + CCarCtrl::RemoveFromInterestingVehicleList(vehToSeek); + return; + } + dest = vehToSeek->GetPosition(); + if (bCollidedWithMyVehicle) { + WarpPedIntoCar(m_pMyVehicle); + return; } } - - 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); + bool foundBetterPosToSeek = PossiblyFindBetterPosToSeekCar(&dest, vehToSeek); + m_vecSeekPos = dest; + float distToDestSqr = (m_vecSeekPos - GetPosition()).MagnitudeSqr(); +#ifndef VC_PED_PORTS + if (bIsRunning) + SetMoveState(PEDMOVE_RUN); #else - CParticleObject::AddObject(POBJECT_SPLASHES_AROUND, pos, CVector(0.0f, 0.0f, 0.0f), 4.5f, 2500, CRGBA(0,0,0,0), true); + if (bIsRunning || + vehToSeek->pDriver && distToDestSqr > sq(2.0f) && (Abs(vehToSeek->m_vecMoveSpeed.x) > 0.01f || Abs(vehToSeek->m_vecMoveSpeed.y) > 0.01f)) + SetMoveState(PEDMOVE_RUN); #endif + else if (distToDestSqr < sq(2.0f)) + SetMoveState(PEDMOVE_WALK); + + if (distToDestSqr >= 1.0f) + bCanPedEnterSeekedCar = false; + else if (2.0f * vehToSeek->GetColModel()->boundingBox.max.x > distToDestSqr) + bCanPedEnterSeekedCar = true; + + if (vehToSeek->m_nGettingInFlags & GetCarDoorFlag(m_vehEnterType)) + bVehEnterDoorIsBlocked = true; + else + bVehEnterDoorIsBlocked = false; + + // Arrived to the car + if (Seek()) { + if (!foundBetterPosToSeek) { + if (1.5f + GetPosition().z > dest.z && GetPosition().z - 0.5f < dest.z) { + if (vehToSeek->IsTrain()) { + SetEnterTrain(vehToSeek, m_vehEnterType); + } else { + m_fRotationCur = m_fRotationDest; + if (!bVehEnterDoorIsBlocked) { + vehToSeek->SetIsStatic(false); + if (m_objective == OBJECTIVE_SOLICIT_VEHICLE) { + SetSolicit(1000); + } else if (m_objective == OBJECTIVE_BUY_ICE_CREAM) { + SetBuyIceCream(); + } else if (vehToSeek->m_nNumGettingIn < vehToSeek->m_nNumMaxPassengers + 1 + && vehToSeek->CanPedEnterCar()) { + + switch (vehToSeek->GetStatus()) { + case STATUS_PLAYER: + case STATUS_SIMPLE: + case STATUS_PHYSICS: + case STATUS_PLAYER_DISABLED: + if (!vehToSeek->bIsBus && (!m_leader || m_leader != vehToSeek->pDriver) && + (m_vehEnterType == CAR_DOOR_LF && vehToSeek->pDriver || m_vehEnterType == CAR_DOOR_RF && vehToSeek->pPassengers[0] || m_vehEnterType == CAR_DOOR_LR && vehToSeek->pPassengers[1] || m_vehEnterType == CAR_DOOR_RR && vehToSeek->pPassengers[2])) { + SetCarJack(vehToSeek); + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && m_vehEnterType != CAR_DOOR_LF) + vehToSeek->pDriver->bFleeAfterExitingCar = true; + } else { + SetEnterCar(vehToSeek, m_vehEnterType); + } + break; + case STATUS_ABANDONED: + if (m_vehEnterType == CAR_DOOR_RF && vehToSeek->pPassengers[0]) { + if (vehToSeek->pPassengers[0]->bDontDragMeOutCar) { + if (IsPlayer()) + SetEnterCar(vehToSeek, m_vehEnterType); + } else { + SetCarJack(vehToSeek); + } + } else { + SetEnterCar(vehToSeek, m_vehEnterType); + } + break; + case STATUS_WRECKED: + SetIdle(); + break; + default: + return; + } + } else { + RestorePreviousState(); + } + } else { + SetMoveState(PEDMOVE_STILL); + } + } + } } } } -void -CPed::SetSolicit(uint32 time) +bool +CPed::CheckForExplosions(CVector2D &area) { - if (m_nPedState == PED_SOLICIT || !IsPedInControl() || !m_carInObjective) - return; + 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; - 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; + 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; } - if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { - m_standardTimer = CTimer::GetTimeInMilliseconds() + time; + if (actualEntity) { + m_pEventEntity = actualEntity; + m_pEventEntity->RegisterReference((CEntity **) &m_pEventEntity); + bGonnaInvestigateEvent = true; + } else + bGonnaInvestigateEvent = false; - if(!m_carInObjective->bIsVan && !m_carInObjective->bIsBus) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_HOOKERTALK, 4.0f); + 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; + } - m_nPedState = PED_SOLICIT; + 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; } -bool -CPed::SetFollowPath(CVector dest) +CPed * +CPed::CheckForDeadPeds(void) { - if (m_nPedState == PED_FOLLOW_PATH) - return false; - - if (FindPlayerPed() != this) - return false; - - if ((dest - GetPosition()).Magnitude() <= 2.0f) - return false; - - CVector pointPoses[7]; - int16 pointsFound; - CPedPath::CalcPedRoute(0, GetPosition(), dest, pointPoses, &pointsFound, 7); - for(int i = 0; i < pointsFound; i++) { - m_stPathNodeStates[i].x = pointPoses[i].x; - m_stPathNodeStates[i].y = pointPoses[i].y; + 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; +} - m_nCurPathNode = 0; - m_nPathNodes = pointsFound; - if (m_nPathNodes < 1) - return false; +bool +CPed::IsPlayer(void) const +{ + return m_nPedType == PEDTYPE_PLAYER1 || m_nPedType == PEDTYPE_PLAYER2 || + m_nPedType == PEDTYPE_PLAYER3 || m_nPedType == PEDTYPE_PLAYER4; +} - SetStoredState(); - m_nPedState = PED_FOLLOW_PATH; - SetMoveState(PEDMOVE_WALK); - return true; +bool +CPed::IsGangMember(void) const +{ + return m_nPedType >= PEDTYPE_GANG1 && m_nPedType <= PEDTYPE_GANG9; } -void -AddYardieDoorSmoke(CVehicle *veh, uint32 doorNode) +bool +CPed::IsPointerValid(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; - } + int pedIndex = CPools::GetPedPool()->GetIndex(this) >> 8; + if (pedIndex < 0 || pedIndex >= NUMPEDS) + return false; - 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()); - } + if (m_entryInfoList.first || FindPlayerPed() == this) + return true; + + return false; } -// wantedDoorNode = 0 means that func. will determine it void -CPed::SetExitCar(CVehicle *veh, uint32 wantedDoorNode) +CPed::SetPedPositionInCar(void) { - 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) + if (CReplay::IsPlayingBack()) 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; - } - } - } + if (bChangedSeat) { + bool notYet = false; + if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LOW_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LOW_LHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SHUFFLE_RHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSHUFFLE_RHS) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE_L) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN_L) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_L) + || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_R)) { + notYet = true; + } + if (notYet) { + LineUpPedWithCar(LINE_UP_TO_CAR_START); + bChangedSeat = false; + return; } } - 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; + CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(m_pMyVehicle->GetModelIndex()); + CMatrix newMat(m_pMyVehicle->GetMatrix()); + CVector seatPos; + if (m_pMyVehicle->pDriver == this) { + seatPos = vehModel->GetFrontSeatPosn(); + if (!m_pMyVehicle->IsBoat() && m_pMyVehicle->m_vehType != VEHICLE_TYPE_BIKE) + seatPos.x = -seatPos.x; - teleportNeeded = true; - } - } - if (m_nPedState == PED_FLEE_POS) { - m_nLastPedState = PED_FLEE_POS; - m_nPrevMoveState = PEDMOVE_RUN; - SetMoveState(PEDMOVE_SPRINT); + } else if (m_pMyVehicle->pPassengers[0] == this) { + seatPos = vehModel->GetFrontSeatPosn(); + } else if (m_pMyVehicle->pPassengers[1] == this) { + seatPos = vehModel->m_positions[CAR_POS_BACKSEAT]; + seatPos.x = -seatPos.x; + } else { + if (m_pMyVehicle->pPassengers[2] == this) { + seatPos = vehModel->m_positions[CAR_POS_BACKSEAT]; } else { - m_nLastPedState = PED_IDLE; - m_nPrevMoveState = PEDMOVE_STILL; - SetMoveState(PEDMOVE_STILL); + seatPos = vehModel->GetFrontSeatPosn(); } + } + newMat.GetPosition() += Multiply3x3(newMat, seatPos); + // Already done below (SetTranslate(0.0f, 0.0f, 0.0f)) + // tempMat.SetUnity(); - 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; + // Rear seats on vans don't face to front, so rotate them HALFPI. + if (m_pMyVehicle->bIsVan) { + CMatrix tempMat; + if (m_pMyVehicle->pPassengers[1] == this) { + m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI; + tempMat.SetTranslate(0.0f, 0.0f, 0.0f); + tempMat.RotateZ(-HALFPI); + newMat = newMat * tempMat; + } else if (m_pMyVehicle->pPassengers[2] == this) { + m_fRotationCur = m_pMyVehicle->GetForward().Heading() + HALFPI; + tempMat.SetTranslate(0.0f, 0.0f, 0.0f); + tempMat.RotateZ(HALFPI); + newMat = newMat * tempMat; } 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); + m_fRotationCur = m_pMyVehicle->GetForward().Heading(); + } + } else { + m_fRotationCur = m_pMyVehicle->GetForward().Heading(); + } + GetMatrix() = newMat; +} - 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); +void +CPed::LookForSexyPeds(void) +{ + if ((!IsPedInControl() && m_nPedState != PED_DRIVING) + || m_lookTimer >= CTimer::GetTimeInMilliseconds() || m_nPedType != PEDTYPE_CIVMALE) + return; - 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); + 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_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); - } } + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; } void -CPed::ScanForInterestingStuff(void) +CPed::LookForSexyCars(void) { - if (!IsPedInControl()) - return; + CEntity *vehicles[8]; + CVehicle *veh; + int foundVehId = 0; + int bestPriceYet = 0; + int16 lastVehicle; - if (m_objective != OBJECTIVE_NONE) + if (!IsPedInControl() && m_nPedState != PED_DRIVING) return; - if (CharCreatedBy == MISSION_CHAR) - return; + if (m_lookTimer < CTimer::GetTimeInMilliseconds()) { + CWorld::FindObjectsInRange(GetPosition(), 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); - LookForSexyPeds(); - LookForSexyCars(); - if (LookForInterestingNodes()) - return; + 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); - if (m_nPedType == PEDTYPE_CRIMINAL && m_hitRecoverTimer < CTimer::GetTimeInMilliseconds()) { - if (CGeneral::GetRandomNumber() % 100 < 10) { - int mostExpensiveVehAround = -1; - int bestMonetaryValue = 0; + m_lookTimer = CTimer::GetTimeInMilliseconds() + 10000; + } +} - CVector pos = GetPosition(); - int16 lastVehicle; - CEntity *vehicles[8]; - CWorld::FindObjectsInRange(pos, 10.0f, true, &lastVehicle, 6, vehicles, false, true, false, false, false); +bool +CPed::LookForInterestingNodes(void) +{ + CBaseModelInfo *model; + CPtrNode *ptrNode; + CVector effectDist; + C2dEffect *effect; + CMatrix *objMat; - for (int i = 0; i < lastVehicle; i++) { - CVehicle* veh = (CVehicle*)vehicles[i]; + if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) & 7 || CTimer::GetTimeInMilliseconds() <= m_standardTimer) { + return false; + } + bool found = false; + uint8 randVal = CGeneral::GetRandomNumber() % 256; - 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]; + 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 - if ((nearPed->GetPosition() - GetPosition()).MagnitudeSqr() > sq(7.0f)) - break; + 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 - 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; + 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; + } + } + } } } - 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; + 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; + } } } } } - } -#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; + 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; + } } } } } - } 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; + 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 (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 (!found) + return false; - 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; - } - } - } - } + 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 ATTRACTORTYPE_STARE: + SetInvestigateEvent(EVENT_SHOPSTALL, effectPos, 1.0f, + CGeneral::GetRandomNumberInRange(8000, 10 * effect->attractor.probability + 8500), + angleToFace); + break; + default: + return true; } + return true; } -uint32 -CPed::ScanForThreats(void) +void +CPed::SetWaitState(eWaitState state, void *time) { - 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; - } - - 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; - } + AnimationId waitAnim = NUM_ANIMS; + CAnimBlendAssociation *animAssoc; - if (CPedType::GetFlag(shooter->m_nPedType) & fearFlags) { - m_threatEntity = shooter; - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); - return CPedType::GetFlag(shooter->m_nPedType); - } - } + if (!IsPedInControl()) + return; - 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; + if (state != m_nWaitState) + FinishedWaitCB(nil, this); - 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]; + 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); - // 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 (time) + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time; + else + m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000,5000); - if (CPedType::GetFlag(nearPed->m_nPedType) & fearFlags) { - if (nearPed->m_fHealth > 0.0f && OurPedCanSeeThisOne(m_nearPeds[i])) { - // FIX: Taken from VC + 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 - float nearPedDistSqr = (nearPed->GetPosition() - ourPos).MagnitudeSqr2D(); -#else - float nearPedDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); #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) { - - for (int i = 0; i < m_numNearPeds; ++i) { - if (CharCreatedBy == RANDOM_CHAR && m_nearPeds[i]->CharCreatedBy == MISSION_CHAR && !m_nearPeds[i]->IsPlayer()) { - continue; - } - - // 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)) { + 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 (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]; - } - } - } - } - } - } - } + 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 - 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 + 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 - float driverDistSqr = (driver->GetPosition() - ourPos).MagnitudeSqr2D(); -#else - float driverDistSqr = (CVector2D(ourPos) - explosionPos).MagnitudeSqr(); + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); #endif - if (sq(closestPedDist) > driverDistSqr) { - closestPedDist = Sqrt(driverDistSqr); - pedToFearFrom = nearVeh->pDriver; - } - } - } - } - } - m_threatEntity = pedToFearFrom; - if (m_threatEntity) - m_threatEntity->RegisterReference((CEntity **) &m_threatEntity); + 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 - if (pedToFearFrom) - flagsOfSomePed = CPedType::GetFlag(((CPed*)m_threatEntity)->m_nPedType); - else - flagsOfSomePed = 0; + animAssoc->SetFinishCallback(RestoreHeadingRateCB, this); #endif - - return flagsOfSomePed; + break; + default: + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); + return; } + m_nWaitState = state; } void -CPed::SeekCar(void) +CPed::Wait(void) { - CVehicle *vehToSeek = m_carInObjective; - CVector dest(0.0f, 0.0f, 0.0f); - if (!vehToSeek) { - RestorePreviousState(); + AnimationId mustHaveAnim = NUM_ANIMS; + CAnimBlendAssociation *animAssoc; + CPed *pedWeLook; + + if (DyingOrDead()) { + m_nWaitState = WAITSTATE_FALSE; + RestoreHeadingRate(); return; } - if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - if (m_vehEnterType && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) { - if (IsRoomToBeCarJacked()) { - dest = GetPositionToOpenCarDoor(vehToSeek, m_vehEnterType); - } else if (m_nPedType == PEDTYPE_COP) { - dest = GetPositionToOpenCarDoor(vehToSeek, CAR_DOOR_RF); - } else { - SetMoveState(PEDMOVE_STILL); - } - } else - GetNearestDoor(vehToSeek, dest); - } else { - if (m_hitRecoverTimer > CTimer::GetTimeInMilliseconds()) { - SetMoveState(PEDMOVE_STILL); - return; - } - if (vehToSeek->GetModelIndex() == MI_COACH) { - GetNearestDoor(vehToSeek, dest); - } else { - if (vehToSeek->IsTrain()) { - if (vehToSeek->GetStatus() != STATUS_TRAIN_NOT_MOVING) { - RestorePreviousObjective(); - RestorePreviousState(); - return; - } - if (!GetNearestTrainDoor(vehToSeek, dest)) { - RestorePreviousObjective(); - RestorePreviousState(); - return; - } - } else { - if (!GetNearestPassengerDoor(vehToSeek, dest)) { - if (vehToSeek->m_nNumPassengers == vehToSeek->m_nNumMaxPassengers) { - RestorePreviousObjective(); - RestorePreviousState(); - } else { - SetMoveState(PEDMOVE_STILL); - } - bVehEnterDoorIsBlocked = true; - return; - } - bVehEnterDoorIsBlocked = false; - } - } - } + switch (m_nWaitState) { - if (dest.x == 0.0f && dest.y == 0.0f) { -#ifdef FIX_BUGS - if ((!IsPlayer() && CharCreatedBy != MISSION_CHAR) || vehToSeek->VehicleCreatedBy != MISSION_VEHICLE || vehToSeek->pDriver || !vehToSeek->CanPedOpenLocks(this)) { -#else - if ((!IsPlayer() && CharCreatedBy != MISSION_CHAR) || vehToSeek->VehicleCreatedBy != MISSION_VEHICLE || vehToSeek->pDriver) { -#endif - RestorePreviousState(); - if (IsPlayer()) { - ClearObjective(); - } else if (CharCreatedBy == RANDOM_CHAR) { - m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000; + case WAITSTATE_TRAFFIC_LIGHTS: + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + if (CTrafficLights::LightForPeds() == PED_LIGHTS_WALK) { + m_nWaitState = WAITSTATE_FALSE; + SetMoveState(PEDMOVE_WALK); + } } - SetMoveState(PEDMOVE_STILL); - TheCamera.ClearPlayerWeaponMode(); - CCarCtrl::RemoveFromInterestingVehicleList(vehToSeek); - return; - } - dest = vehToSeek->GetPosition(); - if (bCollidedWithMyVehicle) { - WarpPedIntoCar(m_pMyVehicle); - return; - } - } - bool foundBetterPosToSeek = PossiblyFindBetterPosToSeekCar(&dest, vehToSeek); - m_vecSeekPos = dest; - float distToDestSqr = (m_vecSeekPos - GetPosition()).MagnitudeSqr(); -#ifndef VC_PED_PORTS - if (bIsRunning) - SetMoveState(PEDMOVE_RUN); -#else - if (bIsRunning || - vehToSeek->pDriver && distToDestSqr > sq(2.0f) && (Abs(vehToSeek->m_vecMoveSpeed.x) > 0.01f || Abs(vehToSeek->m_vecMoveSpeed.y) > 0.01f)) - SetMoveState(PEDMOVE_RUN); -#endif - else if (distToDestSqr < sq(2.0f)) - SetMoveState(PEDMOVE_WALK); - - if (distToDestSqr >= 1.0f) - bCanPedEnterSeekedCar = false; - else if (2.0f * vehToSeek->GetColModel()->boundingBox.max.x > distToDestSqr) - bCanPedEnterSeekedCar = true; - - if (vehToSeek->m_nGettingInFlags & GetCarDoorFlag(m_vehEnterType)) - bVehEnterDoorIsBlocked = true; - else - bVehEnterDoorIsBlocked = false; + break; - // Arrived to the car - if (Seek()) { - if (!foundBetterPosToSeek) { - if (1.5f + GetPosition().z > dest.z && GetPosition().z - 0.5f < dest.z) { - if (vehToSeek->IsTrain()) { - SetEnterTrain(vehToSeek, m_vehEnterType); - } else { - m_fRotationCur = m_fRotationDest; - if (!bVehEnterDoorIsBlocked) { - vehToSeek->SetIsStatic(false); - if (m_objective == OBJECTIVE_SOLICIT_VEHICLE) { - SetSolicit(1000); - } else if (m_objective == OBJECTIVE_BUY_ICE_CREAM) { - SetBuyIceCream(); - } else if (vehToSeek->m_nNumGettingIn < vehToSeek->m_nNumMaxPassengers + 1 - && vehToSeek->CanPedEnterCar()) { + 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); - switch (vehToSeek->GetStatus()) { - case STATUS_PLAYER: - case STATUS_SIMPLE: - case STATUS_PHYSICS: - case STATUS_PLAYER_DISABLED: - if (!vehToSeek->bIsBus && (!m_leader || m_leader != vehToSeek->pDriver) && - (m_vehEnterType == CAR_DOOR_LF && vehToSeek->pDriver || m_vehEnterType == CAR_DOOR_RF && vehToSeek->pPassengers[0] || m_vehEnterType == CAR_DOOR_LR && vehToSeek->pPassengers[1] || m_vehEnterType == CAR_DOOR_RR && vehToSeek->pPassengers[2])) { - SetCarJack(vehToSeek); - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER && m_vehEnterType != CAR_DOOR_LF) - vehToSeek->pDriver->bFleeAfterExitingCar = true; - } else { - SetEnterCar(vehToSeek, m_vehEnterType); - } - break; - case STATUS_ABANDONED: - if (m_vehEnterType == CAR_DOOR_RF && vehToSeek->pPassengers[0]) { - if (vehToSeek->pPassengers[0]->bDontDragMeOutCar) { - if (IsPlayer()) - SetEnterCar(vehToSeek, m_vehEnterType); - } else { - SetCarJack(vehToSeek); - } - } else { - SetEnterCar(vehToSeek, m_vehEnterType); - } - break; - case STATUS_WRECKED: - SetIdle(); - break; - default: - return; - } - } else { - RestorePreviousState(); - } - } else { - SetMoveState(PEDMOVE_STILL); - } + 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; -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; + 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); } - 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); + break; + + case WAITSTATE_HITWALL: + if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) { + if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) { + m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500; } + } else { + m_nWaitState = WAITSTATE_FALSE; } - } - } 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; + 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(); } - } - } 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; + 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 { - 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; + m_nWaitState = WAITSTATE_FALSE; } - if (fall) { - SetFall(500, hitAnim, 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 { - CAnimBlendAssociation *hitAssoc = RpAnimBlendClumpGetAssociation(GetClump(), hitAnim); - if (!hitAssoc || hitAssoc->blendDelta < 0.0f) - hitAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, hitAnim, 8.0f); + animAssoc->flags |= ASSOC_DELETEFADEDOUT; + CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f); + } - hitAssoc->SetCurrentTime(0.0f); - hitAssoc->SetRun(); - hitAssoc->flags |= ASSOC_FADEOUTWHENDONE; + 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; } -#endif } - Say(SOUND_PED_DEFEND); - } else { - Say(SOUND_PED_DEFEND); - switch (hitLevel) { - case HITLEVEL_GROUND: - m_curFightMove = FIGHTMOVE_HITONFLOOR; + + AnimationId animToPlay; + + switch (CGeneral::GetRandomNumber() & 3) { + case 0: + animToPlay = ANIM_ROAD_CROSS; 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; + case 1: + animToPlay = ANIM_IDLE_TIRED; 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; - } + case 2: + animToPlay = ANIM_XPRESS_SCRATCH; + break; + case 3: + animToPlay = ANIM_TURN_180; 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(); + 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; } - 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; } - } - } -} + break; -void -CPed::UpdateFromLeader(void) -{ - if (CTimer::GetTimeInMilliseconds() <= m_objectiveTimer) - return; + case WAITSTATE_PLAYANIM_HANDSUP: + mustHaveAnim = ANIM_HANDSUP; + + case WAITSTATE_PLAYANIM_HANDSCOWER: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_HANDSCOWER; - if (!m_leader) - return; + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + pedWeLook = (CPed*) m_pLookTarget; - CVector leaderDist; - if (m_leader->InVehicle()) - leaderDist = m_leader->m_pMyVehicle->GetPosition() - GetPosition(); - else - leaderDist = m_leader->GetPosition() - GetPosition(); + if ((!m_pLookTarget || !m_pLookTarget->IsPed() || pedWeLook->m_pPointGunAt) + && m_nPedState != PED_FLEE_ENTITY + && m_nPedState != PED_ATTACK + && CTimer::GetTimeInMilliseconds() <= m_nWaitTimer + && animAssoc) { - if (leaderDist.Magnitude() > 30.0f) { - if (IsPedInControl()) { - SetObjective(OBJECTIVE_NONE); - SetIdle(); - SetMoveState(PEDMOVE_STILL); - } - SetLeader(nil); - return; - } + 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; - if (IsPedInControl()) { - if (m_nWaitState == WAITSTATE_PLAYANIM_TAXI) - WarpPedToNearLeaderOffScreen(); + case WAITSTATE_PLAYANIM_TAXI: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_IDLE_TAXI; - 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); + case WAITSTATE_PLAYANIM_CHAT: + if (mustHaveAnim == NUM_ANIMS) + mustHaveAnim = ANIM_IDLE_CHAT; - return; - } - if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - RestorePreviousObjective(); - RestorePreviousState(); + if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) { + animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim); + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; } + m_nWaitState = WAITSTATE_FALSE; } - 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; +#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(); - 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; - 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(); } void -CPed::UpdatePosition(void) +CPed::FinishedWaitCB(CAnimBlendAssociation *animAssoc, void *arg) { - if (CReplay::IsPlayingBack() || !bIsStanding) - return; + CPed *ped = (CPed*)arg; - CVector2D velocityChange; + ped->m_nWaitTimer = 0; + ped->RestoreHeadingRate(); + ped->Wait(); +} - SetHeading(m_fRotationCur); - if (m_pCurrentPhysSurface) { - CVector2D velocityOfSurface; - if (!IsPlayer() && m_pCurrentPhysSurface->IsVehicle() && ((CVehicle*)m_pCurrentPhysSurface)->IsBoat()) { +void +CPed::RestoreHeadingRate(void) +{ + m_headingRate = m_pedStats->m_headingChangeRate; +} - // It seems R* didn't like m_vecOffsetFromPhysSurface for boats - CVector offsetToSurface = GetPosition() - m_pCurrentPhysSurface->GetPosition(); - offsetToSurface.z -= FEET_OFFSET; +void +CPed::RestoreHeadingRateCB(CAnimBlendAssociation *assoc, void *arg) +{ + ((CPed*)arg)->m_headingRate = ((CPed*)arg)->m_pedStats->m_headingChangeRate; +} - CVector surfaceMoveVelocity = m_pCurrentPhysSurface->m_vecMoveSpeed; - CVector surfaceTurnVelocity = CrossProduct(m_pCurrentPhysSurface->m_vecTurnSpeed, offsetToSurface); +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; +} - // 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); +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 { - velocityOfSurface = m_pCurrentPhysSurface->GetSpeed(m_vecOffsetFromPhysSurface); + m_fRotationDest = m_carInObjective->GetForward().Heading() + HALFPI; } - // 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; + if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + time; - 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(!m_carInObjective->bIsVan && !m_carInObjective->bIsBus) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_HOOKERTALK, 4.0f); - if (speedChange > changeMult) { - velocityChange = velocityChange * (changeMult / speedChange); + m_nPedState = PED_SOLICIT; } } - m_vecMoveSpeed.x += velocityChange.x; - m_vecMoveSpeed.y += velocityChange.y; } void -CPed::SetPedPositionInCar(void) +CPed::Solicit(void) { - if (CReplay::IsPlayingBack()) - return; - - if (bChangedSeat) { - bool notYet = false; - if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LHS) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_GETIN_LOW_LHS) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LHS) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_CLOSEDOOR_LOW_LHS) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_SHUFFLE_RHS) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_LSHUFFLE_RHS) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE_L) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_CLOSE) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN_L) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_VAN_GETIN) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_L) - || RpAnimBlendClumpGetAssociation(GetClump(), ANIM_COACH_IN_R)) { - notYet = true; - } - if (notYet) { - LineUpPedWithCar(LINE_UP_TO_CAR_START); - bChangedSeat = false; - return; - } - } - CVehicleModelInfo *vehModel = (CVehicleModelInfo *)CModelInfo::GetModelInfo(m_pMyVehicle->GetModelIndex()); - CMatrix newMat(m_pMyVehicle->GetMatrix()); - CVector seatPos; - if (m_pMyVehicle->pDriver == this) { - seatPos = vehModel->GetFrontSeatPosn(); - if (!m_pMyVehicle->IsBoat() && m_pMyVehicle->m_vehType != VEHICLE_TYPE_BIKE) - seatPos.x = -seatPos.x; - - } else if (m_pMyVehicle->pPassengers[0] == this) { - seatPos = vehModel->GetFrontSeatPosn(); - } else if (m_pMyVehicle->pPassengers[1] == this) { - seatPos = vehModel->m_positions[CAR_POS_BACKSEAT]; - seatPos.x = -seatPos.x; - } else { - if (m_pMyVehicle->pPassengers[2] == this) { - seatPos = vehModel->m_positions[CAR_POS_BACKSEAT]; - } else { - seatPos = vehModel->GetFrontSeatPosn(); - } - } - newMat.GetPosition() += Multiply3x3(newMat, seatPos); - // Already done below (SetTranslate(0.0f, 0.0f, 0.0f)) - // tempMat.SetUnity(); + if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { + CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); + SetMoveState(PEDMOVE_STILL); - // Rear seats on vans don't face to front, so rotate them HALFPI. - if (m_pMyVehicle->bIsVan) { - CMatrix tempMat; - if (m_pMyVehicle->pPassengers[1] == this) { - m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI; - tempMat.SetTranslate(0.0f, 0.0f, 0.0f); - tempMat.RotateZ(-HALFPI); - newMat = newMat * tempMat; - } else if (m_pMyVehicle->pPassengers[2] == this) { - m_fRotationCur = m_pMyVehicle->GetForward().Heading() + HALFPI; - tempMat.SetTranslate(0.0f, 0.0f, 0.0f); - tempMat.RotateZ(HALFPI); - newMat = newMat * tempMat; - } else { - m_fRotationCur = m_pMyVehicle->GetForward().Heading(); + // 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_fRotationCur = m_pMyVehicle->GetForward().Heading(); + m_pVehicleAnim = nil; + SetLeader(m_carInObjective->pDriver); } - GetMatrix() = newMat; -} - -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) +void +CPed::SetBuyIceCream(void) { - RwFrame *newFrame = RwFrameCreate(); - RwFrameAddChild((RwFrame*)data, newFrame); - RwFrameTransform(newFrame, RwFrameGetMatrix(frame), rwCOMBINEREPLACE); - RwFrameForAllObjects(frame, CloneAtomicToFrameCB, newFrame); - RwFrameForAllChildren(frame, RecurseFrameChildrenToCloneCB, newFrame); - return newFrame; -} + if (m_nPedState == PED_BUY_ICECREAM || !IsPedInControl()) + return; -CObject* -CPed::SpawnFlyingComponent(int pedNode, int8 direction) -{ - if (CObject::nNoTempObjects >= NUMTEMPOBJECTS) - return nil; + if (!m_carInObjective) + return; -#ifdef PED_SKIN - assert(!IsClumpSkinned(GetClump())); -#endif +#ifdef FIX_ICECREAM - 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; + // 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; } - 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; +#endif - CVector localForcePos, forceDir; + // Side of the Ice Cream van + m_fRotationDest = m_carInObjective->GetForward().Heading() - HALFPI; - 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(); + if (Abs(m_fRotationDest - m_fRotationCur) < HALFPI) { + m_standardTimer = CTimer::GetTimeInMilliseconds() + 3000; + m_nPedState = PED_BUY_ICECREAM; } - obj->ApplyTurnForce(forceDir, localForcePos); - CWorld::Add(obj); - - return obj; } -void -CPed::WarpPedIntoCar(CVehicle *car) +bool +CPed::PossiblyFindBetterPosToSeekCar(CVector *pos, CVehicle *veh) { - bInVehicle = true; - m_pMyVehicle = car; - m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); - m_carInObjective = car; - m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); - m_nPedState = PED_DRIVING; - bUsesCollision = false; - bIsInTheAir = false; - bVehExitWillBeInstant = true; - if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { - car->SetDriver(this); - car->pDriver->RegisterReference((CEntity **) &car->pDriver); + bool foundIt = false; - } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { - for (int i = 0; i < 4; i++) { - if (!car->pPassengers[i]) { - car->pPassengers[i] = this; - car->pPassengers[i]->RegisterReference((CEntity **) &car->pPassengers[i]); - break; - } - } - } else - return; + CVector helperPos = GetPosition(); + helperPos.z = pos->z - 0.5f; - if (IsPlayer()) { - car->SetStatus(STATUS_PLAYER); - AudioManager.PlayerJustGotInCar(); - CCarCtrl::RegisterVehicleOfInterest(car); - } else { - car->SetStatus(STATUS_PHYSICS); - } + CVector foundPos = *pos; + foundPos.z -= 0.5f; - CWorld::Remove(this); - SetPosition(car->GetPosition()); - CWorld::Add(this); + // 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)) { - if (car->bIsAmbulanceOnDuty) { - car->bIsAmbulanceOnDuty = false; - --CCarCtrl::NumAmbulancesOnDuty; - } - if (car->bIsFireTruckOnDuty) { - car->bIsFireTruckOnDuty = false; - --CCarCtrl::NumFiretrucksOnDuty; - } - if (!car->bEngineOn) { - car->bEngineOn = true; - DMAudio.PlayOneShot(car->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); - } + CColModel *vehCol = veh->GetModelInfo()->GetColModel(); + CVector *colMin = &vehCol->boundingBox.min; + CVector *colMax = &vehCol->boundingBox.max; -#ifdef VC_PED_PORTS - RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); + 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); - // VC uses AddInCarAnims but we don't have that - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, car->GetDriverAnim(), 100.0f); - RemoveWeaponWhenEnteringVehicle(); -#else - if (car->IsBoat()) { -#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 - CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); - RemoveWeaponModel(ourWeapon->m_nModelId); - } else { - // Because we can use Uzi for drive by - RemoveWeaponWhenEnteringVehicle(); + leftRearPos = veh->GetMatrix() * leftRearPos; + rightRearPos = veh->GetMatrix() * rightRearPos; + leftFrontPos = veh->GetMatrix() * leftFrontPos; + rightFrontPos = veh->GetMatrix() * rightFrontPos; - if (car->bLowVehicle) - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); - else - m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); + // 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; + } + } } -#endif + if (!foundIt) + return false; - StopNonPartialAnims(); - if (car->bIsBus) - bRenderPedInCar = false; + helperPos = GetPosition() - foundPos; + helperPos.z = 0.0f; + if (helperPos.MagnitudeSqr() <= sq(0.5f)) + return false; - bChangedSeat = true; + pos->x = foundPos.x; + pos->y = foundPos.y; + return true; } void -CPed::SetObjective(eObjective newObj, CVector dest) +CPed::SetLeader(CEntity *leader) { - if (DyingOrDead()) - return; + m_leader = (CPed*)leader; - if (m_prevObjective != OBJECTIVE_NONE && m_prevObjective == newObj) - return; + if(m_leader) + m_leader->RegisterReference((CEntity **)&m_leader); +} - 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 +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; } -#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; - } + 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); - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); + return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false); +} +#endif - m_objective = newObj; +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::SetMoveAnim(void) +CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg) { - if (m_nStoredMoveState == m_nMoveState || !IsPedInControl()) - return; + CPed *ped = (CPed*)arg; - if (m_nMoveState == PEDMOVE_NONE) { - m_nStoredMoveState = PEDMOVE_NONE; + if (ped->m_nPedState != PED_JUMP) 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; + CVector forward(0.15f * ped->GetForward() + ped->GetPosition()); + forward.z += CModelInfo::GetModelInfo(ped->GetModelIndex())->GetColModel()->spheres->center.z + 0.25f; - 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); - } - } + 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 (!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); - break; - case PEDMOVE_WALK: - animAssoc = CAnimManager::BlendAnimation(GetClump(), animGroupToUse, ANIM_WALK, 1.0f); - 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); - break; - default: - break; - } + if (obstacle) { + animAssoc->flags |= ASSOC_DELETEFADEDOUT; - if (animAssoc) { - if (m_leader) { - CAnimBlendAssociation *walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_WALK); - if (!walkAssoc) - walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_RUN); + // 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; + } - if (!walkAssoc) - walkAssoc = RpAnimBlendClumpGetAssociation(m_leader->GetClump(), ANIM_SPRINT); + float velocityFromAnim = 0.1f; + CAnimBlendAssociation *sprintAssoc = RpAnimBlendClumpGetAssociation(ped->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; - } + 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; } } -} -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(); + 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 + ) { - 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; +#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 } - m_pMyVehicle = (CVehicle*)m_pSeekTarget; - m_pMyVehicle->RegisterReference((CEntity**) &m_pMyVehicle); - ((CVehicle*)m_pSeekTarget)->m_nNumGettingIn++; - bUsesCollision = false; - CVector doorOpenPos = GetPositionToOpenCarDoor(car, m_vehEnterType); + ped->bIsStanding = false; + ped->bIsInTheAir = true; + animAssoc->blendDelta = -1000.0f; + CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_JUMP_GLIDE); - // Because buses have stairs - if (!m_pMyVehicle->bIsBus) - zDiff = Max(0.0f, doorOpenPos.z - GetPosition().z); + if (ped->bDoBloodyFootprints) { + CVector bloodPos(0.0f, 0.0f, 0.0f); + ped->TransformToNode(bloodPos, PED_FOOTL); - 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); + bloodPos.z -= 0.1f; + bloodPos += 0.2f * ped->GetForward(); - PedSetInCarCB(nil, this); - bVehExitWillBeInstant = true; -#else + 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); -#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 + bloodPos = CVector(0.0f, 0.0f, 0.0f); + ped->TransformToNode(bloodPos, PED_FOOTR); - 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); + 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 { - 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); + ped->m_bloodyFootprintCountOrDeathTime -= 40; } - m_pVehicleAnim->SetFinishCallback(PedAnimAlignCB, this); - car->AutoPilot.m_nCruiseSpeed = 0; } } void -CPed::WanderPath(void) +CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg) { - 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; + CPed *ped = (CPed*)arg; - // 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; + ped->bResetWalkAnims = true; + ped->bIsLanding = false; - CPathNode *previousLastNode = m_pLastPathNode; - uint8 randVal = (m_randomSeed + 3 * CTimer::GetFrameCounter()) % 100; + animAssoc->blendDelta = -1000.0f; +} - // We don't prefer 180-degree turns in normal situations - uint8 dirWeWouldntPrefer = m_nPathDir; - if (dirWeWouldntPrefer <= 3) - dirWeWouldntPrefer += 4; - else - dirWeWouldntPrefer -= 4; +void +CPed::FinishHitHeadCB(CAnimBlendAssociation *animAssoc, void *arg) +{ + CPed *ped = (CPed*)arg; - 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; + if (animAssoc) { + animAssoc->blendDelta = -4.0f; + animAssoc->flags |= ASSOC_DELETEFADEDOUT; } - m_pLastPathNode = m_pNextPathNode; - ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode, - m_nPathDir, &dirToSet); + if (ped->m_nPedState == PED_JUMP) + ped->RestorePreviousState(); - uint8 tryCount = 0; + ped->bIsLanding = false; +} - // NB: SetWanderPath checks for m_nPathDir == dirToStartWith, this one checks for tryCount > 7 - while (!m_pNextPathNode) { - tryCount++; - m_nPathDir = (m_nPathDir + 1) % 8; +bool +CPed::CanPedDriveOff(void) +{ + if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds()) + return false; - // 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; - } - } + 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; +} - 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); +// 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; } } -bool -CPed::WarpPedToNearEntityOffScreen(CEntity *warpTo) +void +CPed::SetRadioStation(void) { - 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); + 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 (Abs(zCorrectedPos.z - warpToPos.z) >= 3.0f && Abs(zCorrectedPos.z - appropriatePos.z) >= 3.0f) - continue; + if (IsPlayer() || !m_pMyVehicle || m_pMyVehicle->pDriver != this) + return; - 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); + 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; } } - 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); + 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]; } } - m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 3000; - return teleported; } void -CPed::SetCarJack_AllClear(CVehicle *car, uint32 doorNode, uint32 doorFlag) +CPed::WarpPedIntoCar(CVehicle *car) { - 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); + bInVehicle = true; + m_pMyVehicle = car; + m_pMyVehicle->RegisterReference((CEntity **) &m_pMyVehicle); + m_carInObjective = car; + m_carInObjective->RegisterReference((CEntity **) &m_carInObjective); + m_nPedState = PED_DRIVING; bUsesCollision = false; + bIsInTheAir = false; + bVehExitWillBeInstant = true; + if (m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER) { + car->SetDriver(this); + car->pDriver->RegisterReference((CEntity **) &car->pDriver); - 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) + } else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER) { + for (int i = 0; i < 4; i++) { + if (!car->pPassengers[i]) { + car->pPassengers[i] = this; + car->pPassengers[i]->RegisterReference((CEntity **) &car->pPassengers[i]); + break; + } + } + } else 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; - } + if (IsPlayer()) { + car->SetStatus(STATUS_PLAYER); + AudioManager.PlayerJustGotInCar(); + CCarCtrl::RegisterVehicleOfInterest(car); + } else { + car->SetStatus(STATUS_PHYSICS); } -#ifdef VC_PED_PORTS - ClearPointGunAt(); -#endif - bObjectiveCompleted = false; - if (IsTemporaryObjective(m_objective)) { - m_prevObjective = newObj; - } else { - if (m_objective != newObj) - SetStoredObjective(); + CWorld::Remove(this); + SetPosition(car->GetPosition()); + CWorld::Add(this); - m_objective = newObj; + if (car->bIsAmbulanceOnDuty) { + car->bIsAmbulanceOnDuty = false; + --CCarCtrl::NumAmbulancesOnDuty; } - - 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; + if (car->bIsFireTruckOnDuty) { + car->bIsFireTruckOnDuty = false; + --CCarCtrl::NumFiretrucksOnDuty; + } + if (!car->bEngineOn) { + car->bEngineOn = true; + DMAudio.PlayOneShot(car->m_audioEntityId, SOUND_CAR_ENGINE_START, 1.0f); } -} -void -CPed::SetCarJack(CVehicle* car) -{ - uint8 doorFlag; - eDoors door; - CPed *pedInSeat = nil; +#ifdef VC_PED_PORTS + RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f); - if (car->IsBoat()) - return; + // VC uses AddInCarAnims but we don't have that + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, car->GetDriverAnim(), 100.0f); + RemoveWeaponWhenEnteringVehicle(); +#else + if (car->IsBoat()) { +#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 + CWeaponInfo *ourWeapon = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType); + RemoveWeaponModel(ourWeapon->m_nModelId); + } else { + // Because we can use Uzi for drive by + RemoveWeaponWhenEnteringVehicle(); - 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->bLowVehicle) + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_LSIT, 100.0f); + else + m_pVehicleAnim = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_CAR_SIT, 100.0f); } +#endif - if(car->bIsBus) - pedInSeat = car->pDriver; + StopNonPartialAnims(); + if (car->bIsBus) + bRenderPedInCar = false; - 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); + bChangedSeat = true; } -void -CPed::Solicit(void) + +#ifdef PEDS_REPORT_CRIMES_ON_PHONE +// returns event id, parameter is optional +int32 +CPed::CheckForPlayerCrimes(CPed *victim) { - if (m_standardTimer >= CTimer::GetTimeInMilliseconds() && m_carInObjective) { - CVector doorPos = GetPositionToOpenCarDoor(m_carInObjective, m_vehEnterType, 0.0f); - SetMoveState(PEDMOVE_STILL); + int i; + float dist; + float mindist = 60.0f; + CPlayerPed *player = FindPlayerPed(); + int32 victimRef = (victim ? CPools::GetPedRef(victim) : 0); + int event = -1; - // Game uses GetAngleBetweenPoints and converts it to radian - m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints( - doorPos.x, doorPos.y, - GetPosition().x, GetPosition().y); + for (i = 0; i < NUMEVENTS; i++) { + if (gaEvent[i].type == EVENT_NULL || gaEvent[i].type > EVENT_CAR_SET_ON_FIRE) + continue; - if (m_fRotationDest < 0.0f) { - m_fRotationDest = m_fRotationDest + TWOPI; - } else if (m_fRotationDest > TWOPI) { - m_fRotationDest = m_fRotationDest - TWOPI; + // 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 ((GetPosition() - doorPos).MagnitudeSqr() <= 1.0f) - return; - CAnimBlendAssociation *talkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_CAR_HOOKERTALK); - if (talkAssoc) { - talkAssoc->blendDelta = -1000.0f; - talkAssoc->flags |= ASSOC_DELETEFADEDOUT; + 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; + } } - 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); } + + return event; +} +#endif + +#ifdef PED_SKIN +static RpMaterial* +SetLimbAlphaCB(RpMaterial *material, void *data) +{ + ((RwRGBA*)RpMaterialGetColor(material))->alpha = *(uint8*)data; + return material; } -// Seperate function in VC, more logical. Not sure is it inlined in III. void -CPed::SetExitBoat(CVehicle *boat) +CPed::renderLimb(int node) { -#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); + 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; } - 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(); + 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 #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) { -- cgit v1.2.3 From 6b6b600cee9bda19d10868b5263cf477043ce56a Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sat, 21 Nov 2020 21:12:47 +0300 Subject: 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 -- cgit v1.2.3 From 07303c62d12959927cbb72d4beb131f2647350fa Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 22 Nov 2020 00:13:07 +0100 Subject: 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; + } + } + } + }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; } - if (unk == 3 && ++curCount >= count) - 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; -- cgit v1.2.3 From d24e1ee5926a1d29633c62f2f29f9112b76b5a08 Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sun, 22 Nov 2020 02:29:17 +0300 Subject: 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 -- cgit v1.2.3 From 222e7f56ffa950427b45a342f3ea795d639cba19 Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sun, 22 Nov 2020 02:31:52 +0300 Subject: 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 -- cgit v1.2.3 From f010777e580a4f2bdbfca9dbe037700822f34a88 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 22 Nov 2020 23:10:41 +0200 Subject: 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(); -- cgit v1.2.3 From c814a0a1a6b0f71842306052fbdadb06de7883cb Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 22 Nov 2020 23:11:55 +0200 Subject: 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; } -- cgit v1.2.3 From 103b8fb426e7e5555d58cfeeff0ace64fb4b54f6 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sun, 22 Nov 2020 23:24:38 +0200 Subject: 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 || -- cgit v1.2.3 From b6da31cfaa021559939ed596d18a27f4db6acebc Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 23 Nov 2020 09:38:51 +0100 Subject: 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); -- cgit v1.2.3 From 833bf4a619c7bd40ea69731abe3d31770815d863 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 23 Nov 2020 18:59:50 +0200 Subject: 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); -- cgit v1.2.3 From bd3d09fef53680389bd6ef856eb0669e31fba1d7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 24 Nov 2020 02:15:57 +0200 Subject: 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; +} -- cgit v1.2.3 From 70d8bdc0879c341f2d020544ef3b807bdee89833 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 24 Nov 2020 15:20:41 +0100 Subject: 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; -- cgit v1.2.3 From 88baa9ce5f22a788a1033040040185001a87f922 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 25 Nov 2020 20:03:44 +0100 Subject: 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); + } +}; -- cgit v1.2.3 From 4ddc35634160da5779c46ab63a5b3d351af50b83 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 25 Nov 2020 22:49:50 +0100 Subject: 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 -- cgit v1.2.3 From 491274f188c953ae0528248a7fcbe25fb78701f7 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Thu, 26 Nov 2020 18:11:55 +0200 Subject: 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(); }; -- cgit v1.2.3 From d857758c167ee06840ec806524191e95ff37f98a Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 26 Nov 2020 16:47:19 +0100 Subject: 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; - FrontEndMenuManager.m_bWantToRestart = true; -#else + WANT_TO_LOAD = false; 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())){ -- cgit v1.2.3 From 8c275c3e01059beb60fcdeb9bc599c762d949eab Mon Sep 17 00:00:00 2001 From: erorcun Date: Fri, 27 Nov 2020 00:37:09 +0300 Subject: Update README.md --- README.md | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 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). -- cgit v1.2.3 From f50a53e2907bcadd5c89781c4d9c025a45c8a113 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Fri, 27 Nov 2020 19:18:51 +0300 Subject: 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 -- cgit v1.2.3 From 18d0fd2e48ab093b953f26b67b769a2d8ab67040 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 28 Nov 2020 15:13:06 +0200 Subject: 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 -- cgit v1.2.3 From ad48b9cde01522938590aab444bb09275ff5359d Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Sat, 28 Nov 2020 16:29:45 +0200 Subject: 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; -- cgit v1.2.3 From a8035b64662e9b9fe6689ec60e5087ff95bc2672 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 28 Nov 2020 16:16:15 +0100 Subject: 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); -- cgit v1.2.3 From b1a431a740c9bde92e9169c041909cebfa705ae5 Mon Sep 17 00:00:00 2001 From: withmorten Date: Sat, 28 Nov 2020 17:57:10 +0100 Subject: 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 /* -- cgit v1.2.3 From 52826966993a4d91afcbda44ee2e3c9966f9087d Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 29 Nov 2020 11:36:26 +0100 Subject: 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; -- cgit v1.2.3 From 566282057abbc8e9d5f331c8125a38b00b39fee0 Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 29 Nov 2020 11:37:06 +0100 Subject: 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 -- cgit v1.2.3 From d5bc382cb51c5ef5af618377d190e6f34e893314 Mon Sep 17 00:00:00 2001 From: aap Date: Sun, 29 Nov 2020 12:26:34 +0100 Subject: 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 -- cgit v1.2.3 From 8f05ccd6c4608172ae4c9a589d2b2c4ce915eb2c Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Mon, 30 Nov 2020 02:15:03 +0300 Subject: small garages revision + small template stuff --- src/control/Garages.cpp | 190 ++++++++++++++++++++++++++---------------------- 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, 133 insertions(+), 106 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,34 +1408,32 @@ 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)); + 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, TheText.Get(MessageIDString)); - } - else { - CMessages::InsertNumberInString(TheText.Get(MessageIDString), MessageNumberInString, -1, -1, -1, -1, -1, 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::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); - } + CFont::SetColor(CRGBA(89, 115, 150, 255)); + CFont::PrintString(SCREEN_WIDTH / 2, y_offset - SCREEN_SCALE_Y(40.0f), gUString); } else { - 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::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 - SCREEN_SCALE_Y(40.0f), gUString); + 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) +void CGarage::RefreshDoorPointers(bool bCreate) { - 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)) + bool bNeedToFindDoorEntities = bCreate || m_bRecreateDoorOnNextRefresh; + m_bRecreateDoorOnNextRefresh = false; + if (m_pDoor1) { + if (m_bDoor1IsDummy) { + if (CPools::GetDummyPool()->IsFreeSlot(CPools::GetDummyPool()->GetJustIndex_NoFreeAssert((CDummy*)m_pDoor1))) bNeedToFindDoorEntities = true; - if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex())) - return 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((CObject*)pDoor))) - return true; - if (nIndex != (CPools::GetObjectPool()->GetIndex((CObject*)pDoor) & 0x7F)) + if (CPools::GetObjectPool()->IsFreeSlot(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert((CObject*)m_pDoor1))) bNeedToFindDoorEntities = true; - if (!CGarages::IsModelIndexADoor(pDoor->GetModelIndex())) - return 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; + } } } - return bNeedToFindDoorEntities; -} - -void CGarage::RefreshDoorPointers(bool bCreate) -{ - bool bNeedToFindDoorEntities = true; - if (!bCreate && !m_bRecreateDoorOnNextRefresh) - bNeedToFindDoorEntities = false; - m_bRecreateDoorOnNextRefresh = false; - if (DoINeedToRefreshPointer(m_pDoor1, m_bDoor1IsDummy, m_bDoor1PoolIndex)) - bNeedToFindDoorEntities = true; - if (DoINeedToRefreshPointer(m_pDoor2, m_bDoor2IsDummy, m_bDoor2PoolIndex)) - 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); -- cgit v1.2.3 From 4b9fb631fc1b250a1e353da2e319d49371573bcc Mon Sep 17 00:00:00 2001 From: aap Date: Mon, 30 Nov 2020 23:44:58 +0100 Subject: 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); -- cgit v1.2.3 From 2c59e1c8945a5c6de6415611d4f1dbc720790d73 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 00:22:57 +0100 Subject: 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 - 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 -- cgit v1.2.3 From 6eb0fd52d7f36623ca78d6717fcbd64fd3e7ecd9 Mon Sep 17 00:00:00 2001 From: Zach Charo Date: Mon, 30 Nov 2020 19:08:15 -0600 Subject: 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; // -- cgit v1.2.3 From d6fab1bc53627d55391d10a557a9e0cbcd11ac6d Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 10:12:42 +0100 Subject: 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){ -- cgit v1.2.3 From b8bc54640d80db3d0c0a6392a0858d83a09e8304 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 17:24:56 +0100 Subject: fix cam-fix --- src/core/Camera.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 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; +#ifdef FIX_BUGS + // from VC. to high values bug out spawns + LODDistMultiplier = Min(LODDistMultiplier, 2.2f); +#endif #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 -- cgit v1.2.3 From 83bbb631d1105502fb3c5b3af90578226ba35583 Mon Sep 17 00:00:00 2001 From: aap Date: Tue, 1 Dec 2020 17:42:18 +0100 Subject: 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 - 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); -- cgit v1.2.3 From e33ab44b7d179a59887200fe6d22c15fa557c5e2 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 1 Dec 2020 22:08:05 +0200 Subject: 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 -- cgit v1.2.3 From 4980386e9ab8020e3bde3447330f85d84adca3df Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 11:54:35 +0100 Subject: 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 0fdccce3..06ad194a 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ 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 -- cgit v1.2.3 From 1a30d94523230fed15679861520881f903364f44 Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 16:00:41 +0100 Subject: 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 06ad194a..13aa6f29 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ 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] -- cgit v1.2.3 From 9461998304219f91b3b24484d0cee5b5c5d4523c Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Mon, 23 Nov 2020 22:46:07 +0200 Subject: 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 -- cgit v1.2.3 From 0b20fd7e77dafc34cf9eebc3ffd25318a7d81476 Mon Sep 17 00:00:00 2001 From: Sergeanur Date: Tue, 1 Dec 2020 22:35:53 +0200 Subject: 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(); -- cgit v1.2.3 From fda58fb1dfaba95c72f564d155560abd8d10b794 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Wed, 2 Dec 2020 02:34:51 +0300 Subject: 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 -- cgit v1.2.3 From 4b9f1680a376d1b9b968078e09dd76dc7404d645 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Wed, 2 Dec 2020 02:41:05 +0300 Subject: 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 -- cgit v1.2.3 From fba657ff0c77b343ac854a5aed16385a6c77492c Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 2 Dec 2020 10:38:27 +0100 Subject: 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; -- cgit v1.2.3 From 50bf0f27a00eec43c1b92a9a0ae81b5916442ba2 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 2 Dec 2020 12:58:29 +0100 Subject: 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* -- cgit v1.2.3 From 448ba9b7e86e93581df7813bb5250168b5813c72 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 2 Dec 2020 13:08:30 +0100 Subject: 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 -- cgit v1.2.3 From 3c24505990a9a71210b2328c366b43e6f2fd94bc Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 09:34:09 +0100 Subject: 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; -- cgit v1.2.3 From 13cefd329390c119126af6dcf0558ceb7c720e59 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:04:59 +0100 Subject: more PS2 stuff; memory movement done --- src/collision/TempColModels.cpp | 2 +- src/core/Game.cpp | 250 +++++++++++++++++++++++++++++++++++++++- src/core/World.cpp | 38 +++--- src/core/config.h | 10 +- src/modelinfo/BaseModelInfo.h | 4 +- src/modelinfo/SimpleModelInfo.h | 12 ++ src/vehicles/Heli.cpp | 9 ++ 7 files changed, 295 insertions(+), 30 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; - - 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; + static CColModel OurColModel; + + 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 -- cgit v1.2.3 From 955698d2d37688b86568ee9633cac64bcc01db17 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:05:28 +0100 Subject: 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: -- cgit v1.2.3 From a6c4d9b77cce5a7709e8ab23ab019e91ea0ab798 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:07:16 +0100 Subject: 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: -- cgit v1.2.3 From a442ad198af051614e587ef0537842da9993f53d Mon Sep 17 00:00:00 2001 From: shfil Date: Thu, 3 Dec 2020 16:48:04 +0100 Subject: 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) | -- cgit v1.2.3 From 5bed7afd790c0d023b5ce31703f4edf6abded9f8 Mon Sep 17 00:00:00 2001 From: aap Date: Thu, 3 Dec 2020 16:56:32 +0100 Subject: 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) { -- cgit v1.2.3 From 9714a3776996d97e680cea575967a1d6041f5723 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 4 Dec 2020 01:12:58 +0100 Subject: 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; } -- cgit v1.2.3 From 466eee84e76214a3300f3183f5025140c036e431 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 4 Dec 2020 10:23:04 +0100 Subject: 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 -- cgit v1.2.3 From 28a942735cbcb329b572a20504b05d88e1364db6 Mon Sep 17 00:00:00 2001 From: aap Date: Sat, 5 Dec 2020 14:50:54 +0100 Subject: 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 -- cgit v1.2.3 From efb28b888d4ed89e1f8fc770a66ddfd7e03f4942 Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sat, 5 Dec 2020 22:26:45 +0300 Subject: 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: -- cgit v1.2.3 From 14eb0cd286483dd14ac110658360ecd76199390c Mon Sep 17 00:00:00 2001 From: Nikolay Date: Sun, 6 Dec 2020 15:27:42 +0300 Subject: 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()) >= -- cgit v1.2.3 From 3a66b178876498e02d7aa349b3b8c4754c42ba18 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 20:25:26 +0100 Subject: inttypes.h is part of the C++ standard, so prefix it --- src/extras/debugmenu.cpp | 2 +- src/extras/inttypes.h | 216 ---------------------------------------------- src/extras/re3_inttypes.h | 216 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+), 217 deletions(-) delete mode 100644 src/extras/inttypes.h create mode 100644 src/extras/re3_inttypes.h 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/inttypes.h deleted file mode 100644 index bf0c53e2..00000000 --- a/src/extras/inttypes.h +++ /dev/null @@ -1,216 +0,0 @@ -#define PRId8 "hhd" -#define PRId16 "hd" -#define PRId32 "ld" -#define PRId64 "lld" - -#define PRIdFAST8 "hhd" -#define PRIdFAST16 "hd" -#define PRIdFAST32 "ld" -#define PRIdFAST64 "lld" - -#define PRIdLEAST8 "hhd" -#define PRIdLEAST16 "hd" -#define PRIdLEAST32 "ld" -#define PRIdLEAST64 "lld" - -#define PRIdMAX "lld" -#define PRIdPTR "lld" - -#define PRIi8 "hhi" -#define PRIi16 "hi" -#define PRIi32 "li" -#define PRIi64 "lli" - -#define PRIiFAST8 "hhi" -#define PRIiFAST16 "hi" -#define PRIiFAST32 "li" -#define PRIiFAST64 "lli" - -#define PRIiLEAST8 "hhi" -#define PRIiLEAST16 "hi" -#define PRIiLEAST32 "li" -#define PRIiLEAST64 "lli" - -#define PRIiMAX "lli" -#define PRIiPTR "lli" - -#define PRIo8 "hho" -#define PRIo16 "ho" -#define PRIo32 "lo" -#define PRIo64 "llo" - -#define PRIoFAST8 "hho" -#define PRIoFAST16 "ho" -#define PRIoFAST32 "lo" -#define PRIoFAST64 "llo" - -#define PRIoLEAST8 "hho" -#define PRIoLEAST16 "ho" -#define PRIoLEAST32 "lo" -#define PRIoLEAST64 "llo" - -#define PRIoMAX "llo" -#define PRIoPTR "llo" - -#define PRIu8 "hhu" -#define PRIu16 "hu" -#define PRIu32 "lu" -#define PRIu64 "llu" - -#define PRIuFAST8 "hhu" -#define PRIuFAST16 "hu" -#define PRIuFAST32 "lu" -#define PRIuFAST64 "llu" - -#define PRIuLEAST8 "hhu" -#define PRIuLEAST16 "hu" -#define PRIuLEAST32 "lu" -#define PRIuLEAST64 "llu" - -#define PRIuMAX "llu" -#define PRIuPTR "llu" - -#define PRIx8 "hhx" -#define PRIx16 "hx" -#define PRIx32 "lx" -#define PRIx64 "llx" - -#define PRIxFAST8 "hhx" -#define PRIxFAST16 "hx" -#define PRIxFAST32 "lx" -#define PRIxFAST64 "llx" - -#define PRIxLEAST8 "hhx" -#define PRIxLEAST16 "hx" -#define PRIxLEAST32 "lx" -#define PRIxLEAST64 "llx" - -#define PRIxMAX "llx" -#define PRIxPTR "llx" - -#define PRIX8 "hhX" -#define PRIX16 "hX" -#define PRIX32 "lX" -#define PRIX64 "llX" - -#define PRIXFAST8 "hhX" -#define PRIXFAST16 "hX" -#define PRIXFAST32 "lX" -#define PRIXFAST64 "llX" - -#define PRIXLEAST8 "hhX" -#define PRIXLEAST16 "hX" -#define PRIXLEAST32 "lX" -#define PRIXLEAST64 "llX" - -#define PRIXMAX "llX" -#define PRIXPTR "llX" - - /* SCAN FORMAT MACROS */ -#define SCNd8 "hhd" -#define SCNd16 "hd" -#define SCNd32 "ld" -#define SCNd64 "lld" - -#define SCNdFAST8 "hhd" -#define SCNdFAST16 "hd" -#define SCNdFAST32 "ld" -#define SCNdFAST64 "lld" - -#define SCNdLEAST8 "hhd" -#define SCNdLEAST16 "hd" -#define SCNdLEAST32 "ld" -#define SCNdLEAST64 "lld" - -#define SCNdMAX "lld" -#define SCNdPTR "lld" - -#define SCNi8 "hhi" -#define SCNi16 "hi" -#define SCNi32 "li" -#define SCNi64 "lli" - -#define SCNiFAST8 "hhi" -#define SCNiFAST16 "hi" -#define SCNiFAST32 "li" -#define SCNiFAST64 "lli" - -#define SCNiLEAST8 "hhi" -#define SCNiLEAST16 "hi" -#define SCNiLEAST32 "li" -#define SCNiLEAST64 "lli" - -#define SCNiMAX "lli" -#define SCNiPTR "lli" - -#define SCNo8 "hho" -#define SCNo16 "ho" -#define SCNo32 "lo" -#define SCNo64 "llo" - -#define SCNoFAST8 "hho" -#define SCNoFAST16 "ho" -#define SCNoFAST32 "lo" -#define SCNoFAST64 "llo" - -#define SCNoLEAST8 "hho" -#define SCNoLEAST16 "ho" -#define SCNoLEAST32 "lo" -#define SCNoLEAST64 "llo" - -#define SCNoMAX "llo" -#define SCNoPTR "llo" - -#define SCNu8 "hhu" -#define SCNu16 "hu" -#define SCNu32 "lu" -#define SCNu64 "llu" - -#define SCNuFAST8 "hhu" -#define SCNuFAST16 "hu" -#define SCNuFAST32 "lu" -#define SCNuFAST64 "llu" - -#define SCNuLEAST8 "hhu" -#define SCNuLEAST16 "hu" -#define SCNuLEAST32 "lu" -#define SCNuLEAST64 "llu" - -#define SCNuMAX "llu" -#define SCNuPTR "llu" - -#define SCNx8 "hhx" -#define SCNx16 "hx" -#define SCNx32 "lx" -#define SCNx64 "llx" - -#define SCNxFAST8 "hhx" -#define SCNxFAST16 "hx" -#define SCNxFAST32 "lx" -#define SCNxFAST64 "llx" - -#define SCNxLEAST8 "hhx" -#define SCNxLEAST16 "hx" -#define SCNxLEAST32 "lx" -#define SCNxLEAST64 "llx" - -#define SCNxMAX "llx" -#define SCNxPTR "llx" - -#define SCNX8 "hhX" -#define SCNX16 "hX" -#define SCNX32 "lX" -#define SCNX64 "llX" - -#define SCNXFAST8 "hhX" -#define SCNXFAST16 "hX" -#define SCNXFAST32 "lX" -#define SCNXFAST64 "llX" - -#define SCNXLEAST8 "hhX" -#define SCNXLEAST16 "hX" -#define SCNXLEAST32 "lX" -#define SCNXLEAST64 "llX" - -#define SCNXMAX "llX" -#define SCNXPTR "llX" \ No newline at end of file diff --git a/src/extras/re3_inttypes.h b/src/extras/re3_inttypes.h new file mode 100644 index 00000000..bf0c53e2 --- /dev/null +++ b/src/extras/re3_inttypes.h @@ -0,0 +1,216 @@ +#define PRId8 "hhd" +#define PRId16 "hd" +#define PRId32 "ld" +#define PRId64 "lld" + +#define PRIdFAST8 "hhd" +#define PRIdFAST16 "hd" +#define PRIdFAST32 "ld" +#define PRIdFAST64 "lld" + +#define PRIdLEAST8 "hhd" +#define PRIdLEAST16 "hd" +#define PRIdLEAST32 "ld" +#define PRIdLEAST64 "lld" + +#define PRIdMAX "lld" +#define PRIdPTR "lld" + +#define PRIi8 "hhi" +#define PRIi16 "hi" +#define PRIi32 "li" +#define PRIi64 "lli" + +#define PRIiFAST8 "hhi" +#define PRIiFAST16 "hi" +#define PRIiFAST32 "li" +#define PRIiFAST64 "lli" + +#define PRIiLEAST8 "hhi" +#define PRIiLEAST16 "hi" +#define PRIiLEAST32 "li" +#define PRIiLEAST64 "lli" + +#define PRIiMAX "lli" +#define PRIiPTR "lli" + +#define PRIo8 "hho" +#define PRIo16 "ho" +#define PRIo32 "lo" +#define PRIo64 "llo" + +#define PRIoFAST8 "hho" +#define PRIoFAST16 "ho" +#define PRIoFAST32 "lo" +#define PRIoFAST64 "llo" + +#define PRIoLEAST8 "hho" +#define PRIoLEAST16 "ho" +#define PRIoLEAST32 "lo" +#define PRIoLEAST64 "llo" + +#define PRIoMAX "llo" +#define PRIoPTR "llo" + +#define PRIu8 "hhu" +#define PRIu16 "hu" +#define PRIu32 "lu" +#define PRIu64 "llu" + +#define PRIuFAST8 "hhu" +#define PRIuFAST16 "hu" +#define PRIuFAST32 "lu" +#define PRIuFAST64 "llu" + +#define PRIuLEAST8 "hhu" +#define PRIuLEAST16 "hu" +#define PRIuLEAST32 "lu" +#define PRIuLEAST64 "llu" + +#define PRIuMAX "llu" +#define PRIuPTR "llu" + +#define PRIx8 "hhx" +#define PRIx16 "hx" +#define PRIx32 "lx" +#define PRIx64 "llx" + +#define PRIxFAST8 "hhx" +#define PRIxFAST16 "hx" +#define PRIxFAST32 "lx" +#define PRIxFAST64 "llx" + +#define PRIxLEAST8 "hhx" +#define PRIxLEAST16 "hx" +#define PRIxLEAST32 "lx" +#define PRIxLEAST64 "llx" + +#define PRIxMAX "llx" +#define PRIxPTR "llx" + +#define PRIX8 "hhX" +#define PRIX16 "hX" +#define PRIX32 "lX" +#define PRIX64 "llX" + +#define PRIXFAST8 "hhX" +#define PRIXFAST16 "hX" +#define PRIXFAST32 "lX" +#define PRIXFAST64 "llX" + +#define PRIXLEAST8 "hhX" +#define PRIXLEAST16 "hX" +#define PRIXLEAST32 "lX" +#define PRIXLEAST64 "llX" + +#define PRIXMAX "llX" +#define PRIXPTR "llX" + + /* SCAN FORMAT MACROS */ +#define SCNd8 "hhd" +#define SCNd16 "hd" +#define SCNd32 "ld" +#define SCNd64 "lld" + +#define SCNdFAST8 "hhd" +#define SCNdFAST16 "hd" +#define SCNdFAST32 "ld" +#define SCNdFAST64 "lld" + +#define SCNdLEAST8 "hhd" +#define SCNdLEAST16 "hd" +#define SCNdLEAST32 "ld" +#define SCNdLEAST64 "lld" + +#define SCNdMAX "lld" +#define SCNdPTR "lld" + +#define SCNi8 "hhi" +#define SCNi16 "hi" +#define SCNi32 "li" +#define SCNi64 "lli" + +#define SCNiFAST8 "hhi" +#define SCNiFAST16 "hi" +#define SCNiFAST32 "li" +#define SCNiFAST64 "lli" + +#define SCNiLEAST8 "hhi" +#define SCNiLEAST16 "hi" +#define SCNiLEAST32 "li" +#define SCNiLEAST64 "lli" + +#define SCNiMAX "lli" +#define SCNiPTR "lli" + +#define SCNo8 "hho" +#define SCNo16 "ho" +#define SCNo32 "lo" +#define SCNo64 "llo" + +#define SCNoFAST8 "hho" +#define SCNoFAST16 "ho" +#define SCNoFAST32 "lo" +#define SCNoFAST64 "llo" + +#define SCNoLEAST8 "hho" +#define SCNoLEAST16 "ho" +#define SCNoLEAST32 "lo" +#define SCNoLEAST64 "llo" + +#define SCNoMAX "llo" +#define SCNoPTR "llo" + +#define SCNu8 "hhu" +#define SCNu16 "hu" +#define SCNu32 "lu" +#define SCNu64 "llu" + +#define SCNuFAST8 "hhu" +#define SCNuFAST16 "hu" +#define SCNuFAST32 "lu" +#define SCNuFAST64 "llu" + +#define SCNuLEAST8 "hhu" +#define SCNuLEAST16 "hu" +#define SCNuLEAST32 "lu" +#define SCNuLEAST64 "llu" + +#define SCNuMAX "llu" +#define SCNuPTR "llu" + +#define SCNx8 "hhx" +#define SCNx16 "hx" +#define SCNx32 "lx" +#define SCNx64 "llx" + +#define SCNxFAST8 "hhx" +#define SCNxFAST16 "hx" +#define SCNxFAST32 "lx" +#define SCNxFAST64 "llx" + +#define SCNxLEAST8 "hhx" +#define SCNxLEAST16 "hx" +#define SCNxLEAST32 "lx" +#define SCNxLEAST64 "llx" + +#define SCNxMAX "llx" +#define SCNxPTR "llx" + +#define SCNX8 "hhX" +#define SCNX16 "hX" +#define SCNX32 "lX" +#define SCNX64 "llX" + +#define SCNXFAST8 "hhX" +#define SCNXFAST16 "hX" +#define SCNXFAST32 "lX" +#define SCNXFAST64 "llX" + +#define SCNXLEAST8 "hhX" +#define SCNXLEAST16 "hX" +#define SCNXLEAST32 "lX" +#define SCNXLEAST64 "llX" + +#define SCNXMAX "llX" +#define SCNXPTR "llX" \ No newline at end of file -- cgit v1.2.3 From 12d3893fe9454cac13d14c39abcb829fd43caabe Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 6 Dec 2020 20:26:40 +0100 Subject: 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 { -- cgit v1.2.3 From 13de842236b6ddb3067ca4b275857f9df2b7f1ab Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 11:54:35 +0100 Subject: 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 13aa6f29..06ad194a 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ diff --git a/utils/gxt/spanish.txt b/utils/gxt/spanish.txt index 22063c35..e7dc1537 100644 --- a/utils/gxt/spanish.txt +++ b/utils/gxt/spanish.txt @@ -8026,6 +8026,255 @@ 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] -- cgit v1.2.3 From 5b88cddb9f21fd0fbaa15d328e8e2c306be2561a Mon Sep 17 00:00:00 2001 From: IlDucci Date: Sun, 29 Nov 2020 16:00:41 +0100 Subject: 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 06ad194a..13aa6f29 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ 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] -- cgit v1.2.3 From c53a8b8c9de7d71910034e395f9c2353c19a35b2 Mon Sep 17 00:00:00 2001 From: IlDucci Date: Wed, 2 Dec 2020 17:02:19 +0100 Subject: 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 | 11362 ++++++++++++++++++++++++------------------- 2 files changed, 6337 insertions(+), 5025 deletions(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 13aa6f29..9234eec9 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ 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. - -[HELP9_A] -Pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar~w~ el rifle de francotirador. - -[HELP10] -Esta insignia indica que estás buscado por la policía. - -[HELP11] -Cuantas más insignias tengas mayor será tu grado de peligrosidad asignado en la búsqueda y captura. - -[HELP13] -Algunas veces puedes necesitar utilizar caminos no mostrados en el radar. - -[TIMER] -Esta es una misión cronometrada, debes completarla antes de que el temporizador llegue a cero. - -[MISTY1] -~r~¡Misty es carne de depósito de cadáveres! - -[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! +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~. -[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 +[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~. -[PAGEB2] -Uzi entregada en escondite +[HELP9_A] +Pulsa el~h~ botón ~k~~PED_FIREWEAPON~ ~w~para ~h~disparar~w~ el fusil de francotirador. -[PAGEB3] -Armadura personal entregada en escondite +[HELP9_B] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. -[PAGEB4] -Escopeta entregada en escondite +[HELP9_C] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. -[PAGEB5] -granadas entregadas en escondite +[HELP10] +Esta insignia indica que la policía va a por ti. -[PAGEB6] -molotovs entregados en escondite +[HELP11] +Cuantas más insignias tengas, más peligroso te considerarán. -[PAGEB7] -AK47 entregada en escondite +[HELP12] +Entra en la señal azul para comenzar una misión. -[PAGEB8] -Rifle de francotirador entregado en escondite +[HELP13] +Algunas veces tendrás que usar caminos no mostrados en el radar. -[PAGEB9] -M16 entregado en escondite +[HELP14] +Para conseguir un arma, pasa sobre ella. No puedes recogerlas estando dentro de un vehículo. -[PAGEB10] -Lanzacohetes entregado en escondite +[HELP15] +Cuando vayas a pie mantén pulsado el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para~h~ mirar atrás~w~. -[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,6895 +145,8166 @@ 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. -[DAM] -DAÑO: +{ WEAPON CONTROLS TUTORIAL } -[KILLS] -MUERTES: +[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. -[FARES] -TARIFAS: +[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... -[BULL] -LINGOTES: +[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... -[EVID] -PRUEBAS: +[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... -[HEALTH] -ESTADO DEL COCHE: +[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. -[COLLECT] -RECOGIDOS: +[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] -Conduce tu vehículo a la tienda de bombas para poner una ~h~bomba~w~. Coste - ~h~1.000$. +Mete tu vehículo en la tienda de ~h~bombas~w~ para poner una. Coste: ~h~1.000$~w~. [SAVE1] -Atraviesa la puerta para ~h~guardar la partida ~w~. No puedes guardas durante una misión. +Pasa por la puerta para ~h~guardar la partida~w~. No podrás guardar durante una misión. [SAVE2] -Cualquier vehículo dejado en este garaje será almacenado cuando la partida sea guardada. +Cualquier vehículo que dejes en este garaje se conservará al guardar la partida. [AMMU] -Ve dentro del depósito de Municiones para comprar un arma. +Entra a la tienda Ammu-Nation para comprar armas. [BRIDGE1] -Cuando el Puente Callahan esté reparado podrás conducir hasta la isla Staunton. +Cuando el puente Callahan esté reparado podrás conducir hasta Staunton Island. [TUNNEL] -Cuando el túnel Porter esté abierto podrás conducir hasta la isla Staunton. +Cuando el túnel Porter esté abierto podrás conducir hasta Staunton Island. -[LUIGI] -MISIONES DE LUIGI +[TIMER] +Esta es una misión cronometrada, debes completarla antes de que el temporizador llegue a cero. -[TONI] -MISIONES DE TONI +[GARAGE] +Mete el vehículo dentro del garaje y luego sal caminando. -[JOEY] -MISIONES DE JOEY +[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. -[FRANK] -MISIONES DE SALVATORE +[S_PROM2] +Puedes alojar un vehículo en el garaje de al lado al guardar tu partida. -[DIABLO] -MISIONES DE DIABLO +[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 -[ASUKA] -MISIONES DE ASUKA +[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. -[B_SITE] -MISIONES SUBURBANAS DE ASUKA +[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~. -[KENJI] -MISIONES DE KENJI +[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. -[RAY] -MISIONES DE RAY +[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. -[LOVE] -MISIONES DE LOVE +[HORN1] +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. -[YARDIE] -MISIONES DE YARDIE +[HORN2] +Pulsa el ~h~botón L1~w~ para tocar el ~h~claxon. -[HOOD] -MISIONES DE HOOD +[HORN3] +Pulsa el ~h~botón R1~w~ para tocar el ~h~claxon. -[CITYZON] -Liberty City +[HORN4] +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. -[IND_ZON] -Portland +[RADIO_A] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[PORT_W] -Punta Callahan +[RADIO_B] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[PORT_S] -Embarcadero Atlantic +[RADIO_C] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[PORT_E] -Puerto de Portland +[RADIO_D] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[PORT_I] -Trenton +[SIREN_1] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[S_VIEW] -Mirador de Portland +[SIREN_2] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[CHINA] -Chinatown +[SIREN_3] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[EASTBAY] -Playa de Portland +[SIREN_4] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[LITTLEI] -Saint Mark's +[BOATIN1] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. -[REDLIGH] -Distrito Red Light +[BOATIN3] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. -[TOWERS] -Altos de Hepburn +[BOATIN2] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. -[HARWOOD] -Harwood +[BOATIN4] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. -[ROADBR1] -Puerto de Callahan +[GREN_1] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. -[ROADBR2] -Puerto de Callahan +[GREN_2] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. -[TUNNELP] -Túnel Porter +[GREN_3] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. -[BOMB1] -Garaje de 8-Ball +[TUBE1] +Cuando el metro abra, podrás coger un tren hasta Staunton Island. -[COM_ZON] -Isla Staunton +[TUBE2] +Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al Aeropuerto Internacional Francis. -[STADIUM] -Aspatria +[TUBE_2] +Para subirte a un vagón, pulsa el ~h~botón Entrar al vehículo~w~. -[HOSPI_2] -Rockford +[SPRAY_4] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. -[UNIVERS] -Campus de Liberty +[SPRAY_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. -[CONSTRU] -Fuerte Staunton +[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. -[PARK] -Belleville Park +[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. -[COM_EAS] -Newport +[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. -[SHOPING] -Punta de Bedford +[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. -[YAKUSA] -Torrington +[RCHELP] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. -[SUB_ZON] -Costa de Vale +[RCHELPA] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. -[AIRPORT] -Aeropuerto internacional +[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. -[PROJECT] -Jardines de Wichita +[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. -[SUB_IND] -Cala de la Cúspide +[CRUSH] +Aparca en la zona señalada y sal de tu vehículo para que sea triturado. -[SWANKS] -Bosque de Cedros +[GARAGE1] +~g~Sal del vehículo y aléjate caminando. -[BIG_DAM] -Presa Cochrane +[PBOAT_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. -[SUB_ZO2] -Costa de Vale +[PBOAT_2] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. -[SUB_ZO3] -Costa de Vale +{ ============================================================================================================================ } +{ ================= PAGER MESSAGES, INDICATING THAT THE PLAYER HAS UNLOCKED WEAPONS AND ITEMS IN ITS HIDEOUT ================= } +{ ============================================================================================================================ } -[CAR_1] -Ambulancia +[PAGEB1] +Pistola ya disponible en tu guarida. -[CAR_2] -Camión de bomberos +[PAGEB2] +Uzi ya disponible en tu guarida. -[CAR_3] -Policía +[PAGEB3] +Chaleco antibalas ya disponible en tu guarida. -[CAR_4] -Oficial +[PAGEB4] +Escopeta ya disponible en tu guarida. -[CAR_5] -Cuartel +[PAGEB5] +Granadas ya disponibles en tu guarida. -[CAR_6] -Rinoceronte +[PAGEB6] +Molotovs ya disponibles en tu guarida. -[CAR_7] -Coche del FBI +[PAGEB7] +AK47 ya disponible en tu guarida. -[CAR_8] -Securicar +[PAGEB8] +Fusil de francotirador ya disponible en tu guarida. -[CAR_9] -Moonbeam +[PAGEB9] +M16 ya disponible en tu guarida. -[CAR_10] -Coach +[PAGEB10] +Lanzacohetes ya disponible en tu guarida. -[CAR_11] -Flatbed +[PAGEB11] +Lanzallamas ya disponible en tu guarida. -[CAR_12] -Rápido +[PAGEB12] +Soborno policial ya disponible en tu guarida. -[CAR_13] -Trashmaster +[PAGEB13] +Salud ya disponible en tu guarida. -[CAR_14] -Patriot +[PAGEB14] +Adrenalina ya disponible en tu guarida. -[CAR_15] -Sr. Whoopee +{ ==================================================================================================================== } +{ ================= PAGER MESSAGES, INDICATING THAT GUNS HAVE BEEN UNLOCKED AT THE AMMU-NATION STORE ================= } +{ ==================================================================================================================== } -[CAR_16] -Mule +[COLT_IN] +¡La pistola ya está disponible en la tienda Ammu-Nation! -[CAR_17] -Yankee +[UZI_IN] +¡La Uzi ya está disponible en la tienda Ammu-Nation! -[CAR_18] -Pony +{ ================================================================================================== } +{ ================= PAGER MESSAGES THAT APPEAR WHEN CERTAIN CAR SHOPS ARE UNLOCKED ================= } +{ ================================================================================================== } -[CAR_19] -Bobcat +[IMPEXPP] +Garaje de Importación/Exportación, puerto de Portland. Requerimos varios vehículos; revisa nuestro tablón de notas para saber más. -[CAR_20] -Rumpo +[VANHSTP] +¿Quieres abrir algún Securicar? Llévalo a nuestro garaje en el puerto de Portland. -[CAR_21] -Blista +[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. -[CAR_22] -Dodo +{ =============================================================== } +{ ================= RAMPAGE SUBMISSIONS STRINGS ================= } +{ =============================================================== } -[CAR_23] -Bus +[RAMPAGE] +¡MASACRE! -[CAR_24] -Sentinel +[RAMP_P] +¡MASACRE COMPLETADA! -[CAR_25] -Cheetah +[RAMP_F] +MASACRE FALLIDA -[CAR_26] -Banshee +[RAMP_A] +¡TODAS LAS MASACRES COMPLETADAS! -[CAR_27] -Aguijón +{ Pager messages } -[CAR_28] -Infernus +[PAGE_00] +. -[CAR_29] -Esperanto +[PAGE_01] +¡Mata a ~1~ Diablos en 120 segundos! -[CAR_30] -Kuruma +[PAGE_02] +¡Destruye ~1~ vehículos en 120 segundos! -[CAR_31] -Stretch +[PAGE_03] +¡Mata a ~1~ mafiosos en 120 segundos! -[CAR_32] -Perennial +[PAGE_04] +¡Mata a ~1~ Tríadas en 120 segundos! -[CAR_33] -Landstalker +[PAGE_05] +¡Mata a ~1~ Tríadas en 120 segundos! -[CAR_34] -Manana +[PAGE_06] +¡Destruye ~1~ vehículos en 120 segundos! -[CAR_35] -Idaho +[PAGE_07] +¡Revienta ~1~ cabezas jamaicanas en 120 segundos! -[CAR_36] -Semental +[PAGE_08] +¡Quema a ~1~ yakuzas en 120 segundos! -[CAR_37] -Taxi +[PAGE_09] +¡Destruye ~1~ vehículos en 120 segundos! -[CAR_38] -Cabbie +[PAGE_10] +¡Destruye ~1~ vehículos en 120 segundos! -[CAR_39] -Buggy +[PAGE_11] +¡Aniquila a ~1~ jamaicanos en 120 segundos! -[LUIGIS] -Casa de Luigi +[PAGE_12] +¡Quema a ~1~ yakuzas en 120 segundos! -[GOAWAY] -~g~¡Ya estás en una misión! +[PAGE_13] +¡Vuela a ~1~ jamaicanos en 120 segundos! -[LUIGGO] -~g~Luigi está entrevistando a algunas chicas nuevas -¡Vuelve más tarde! +[PAGE_14] +¡Fríe a ~1~ colombianos en 120 segundos! -[JOEYGO] -~g~Joey's está en la ciudad con Misty. ¡Pásate más tarde! +[PAGE_15] +¡Machaca a ~1~ Hoods en 120 segundos! -[TONIGO] -~g~Toni ha llevado a su mamá a la ópera -¡Llama en otro momento! +[PAGE_16] +¡Destruye ~1~ vehículos en 120 segundos! -[KEMUGO] -~g~Maria y Kemuri están muy ocupadas en este momento - ¡Pásate más tarde! +[PAGE_17] +¡Arrolla a ~1~ colombianos con un coche en 120 segundos! -[KENJGO] -~g~Kenji ha ido a encuentro con los Yakuza -¡Llama en otro momento! +[PAGE_18] +¡Destruye ~1~ vehículos disparando desde otro en 120 segundos! -[RAYGO] -~g~Ray tiene otros servicios por los que rondar -¡Inténtalo de nuevo más tarde! +[PAGE_19] +¡Revienta ~1~ cabezas colombianas en 120 segundos! -[LOVEGO] -~g~Donald Love tiene otros asuntos que atender -¡Pide una cita más tarde! +[PAGE_20] +¡Decapita a ~1~ Hoods en 120 segundos! -[KENSGO] -~g~¡Kenji está ocupado! -¡Llama más tarde! +{ ======================================================== } +{ ================= PERCENTAGE BAR TEXTS ================= } +{ ======================================================== } -[ASUSGO] -~g~¡Asuka no está disponible en este momento! +[DAM] +DAÑO: -[HOODGO] -~g~Los Capos no están disponibles en este momento! +[KILLS] +MUERTES: -[WRONGT1] -~g~Vuelve entre las 05:00 y las 21:00 para un trabajo +[FARES] +CARRERAS: -[WRONGT2] -~g~Vuelve entre las 06:00 y las 14:00 para un trabajo +[BULL] +LINGOTES: -[WRONGT3] -~g~Vuelve entre las 15:00 y las 00:00 para un trabajo +[EVID] +PRUEBAS: -[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. +[HEALTH] +ESTADO DEL COCHE: -[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... +[COLLECT] +RECOGIDOS: -[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... +{ ================================================================================== } +{ ================= POSSIBLY MAP SCREEN INDICATIONS, MISSING IN PC ================= } +{ ================================================================================== } -[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... +[LUIGI] +MISIONES DE LUIGI -[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. +[TONI] +MISIONES DE TONI -[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. +[JOEY] +MISIONES DE JOEY -[GUN_4A] -Mientras que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~ puedes caminar o correr mientras mantienes fijado un objetivo. +[FRANK] +MISIONES DE SALVATORE -[GUN_4B] -Mientras que mantienes pulsado el ~h~ botón ~k~~PED_LOCK_TARGET~ ~w~ puedes caminar o correr mientras mantienes fijado un objetivo. +[DIABLO] +MISIONES DE DIABLO -[GUN_5] -Puedes practicar el apuntar y disparar en estos objetivos de papel. Cuando hayas terminado retoma la misión. +[ASUKA] +MISIONES DE ASUKA -[TAXI1] -~g~ Busca la tarifa. +[B_SITE] +MISIONES SUBURBANAS DE ASUKA -[FARE1] -~g~Destino ~w~'Club Sex Kitten Miau' ~g~en Redlight. +[KENJI] +MISIONES DE KENJI -[FARE2] -~g~Destino ~w~'Supa Save' ~g~en el Mirador de Portland. +[RAY] +MISIONES DE RAY -[FARE3] -~g~Destino ~w~la 'sala de la vieja escuela' ~g~en Chinatown. +[LOVE] +MISIONES DE LOVE -[FARE4] -~g~Destino ~w~el 'Café Greasy Joe' ~g~en Punta Callahan. +[YARDIE] +MISIONES DE JAMAICANOS -[FARE5] -~g~Destino ~w~'depósito de Municiones' ~g~en Redlight. +[HOOD] +MISIONES DE HOOD -[FARE6] -~g~Destino ~w~'Autos de crédito fácil' ~g~en Saint Mark. +{ =========================================================== } +{ ================= LIBERTY CITY AREA NAMES ================= } +{ =========================================================== } -[FARE7] -~g~Destino ~w~'Bar de topless de Woody' ~g~en Redlight. +[CITYZON] +Liberty City -[FARE8] -~g~Destino ~w~'Restaurante Marcos' ~g~en Saint Mark. +[IND_ZON] +Portland -[FARE9] -~g~Destino ~w~'garaje de importación y exportación' ~g~en Portland Harbor. +[PORT_W] +Callahan Point -[FARE10] -~g~Destino ~w~'Punk Noodles' ~g~en Chinatown. +[PORT_S] +Muelle Atlantic -[FARE12] -~g~Destino ~w~'Estadio de Fútbol' ~g~en Aspatria. +[PORT_E] +Puerto de Portland -[FARE13] -~g~Destino ~w~'La iglesia' ~g~en Punta de Bedford +[PORT_I] +Trenton -[FARE14] -~g~Destino ~w~'El Casino' ~g~en Torrington +[S_VIEW] +Portland View -[FARE15] -~g~Destino ~w~'Universidad Liberty' ~g~en el Campus de Liberty +[CHINA] +Chinatown -[FARE16] -~g~Destino ~w~'Centro comercial' ~g~en la zona de Belleville Park +[EASTBAY] +Playa de Portland -[FARE17] -~g~Destino ~w~'Muso' ~g~en Newport +[LITTLEI] +Saint Mark's -[FARE18] -~g~Destino ~w~'Edificio de AmCo' ~g~en Torrington +[REDLIGH] +Barrio rojo -[FARE19] -~g~Destino ~w~'Bolt Burgers' ~g~en Punta de Bedford +[TOWERS] +Cerros de Hepburn -[FARE20] -~g~Destino ~w~'El parque' ~g~en Belleville +[HARWOOD] +Harwood -[FARE21] -~g~Destino ~w~'Aeropuerto internacional de Francis' +[ROADBR1] +Puente Callahan -[FARE22] -~g~Destino ~w~'el dique de Cochrane' +[ROADBR2] +Puente Callahan -[FARE24] -~g~Destino ~w~'El hospital' ~g~en la Cúspide de la Cala +[TUNNELP] +Túnel Porter -[FARE25] -~g~Destino ~w~'El parque' ~g~en la Costa de Vale +[BOMB1] +Taller de 8-Ball -[FARE26] -~g~Destino ~w~'Torres del Noroeste' ~g~en los Jardines de Wichita +[COM_ZON] +Staunton Island -[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! +[STADIUM] +Aspatria -[TSCORE2] -$~1~ +[HOSPI_2] +Rockford -[IN_ROW] -~1~ ¡Prima EN UNA FILA! $~1~ +[UNIVERS] +Campus de Liberty -[TTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. +[CONSTRU] +Fort Staunton -[TTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. +[PARK] +Parque Belleville -[ATUTOR2] -~g~Conduce CON CUIDADO a los pacientes hasta el hospital. Cada golpe reduce sus posibilidades de supervivencia. +[COM_EAS] +Newport -[A_TIME] -+~1~ segundos - -[A_FULL] -~r~¡¡Ambulancia completa!! +[SHOPING] +Bedford Point -[A_RANGE] -~g~La radio de la ambulancia está fuera de alcance, ¡acércate hasta un hospital! +[YAKUSA] +Torrington -[FTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. +[SUB_ZON] +Shoreside Vale -[FTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del coche de bomberos. +[AIRPORT] +Aeropuerto Int. Francis -[F_PASS1] -¡Fuego apagado! +[PROJECT] +Wichita Gardens -[F_RANGE] -~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate hasta una estación de bomberos! +[SUB_IND] +Pike Creek -[C_BREIF] -~g~Sospechoso visto por última vez en la zona ~a~. +[SWANKS] +Cedar Grove -[C_RANGE] -~g~La radio de la policía está fuera de alcance, ¡acércate a una comisaría! +[BIG_DAM] +Presa Cochrane -[DODO_FT] -¡Huiste por ~1~ segundos! +[SUB_ZO2] +Shoreside Vale -[EBAL_A] -Conozco un lugar al borde del distrito Red Light donde podemos escondernos, +[SUB_ZO3] +Shoreside Vale -[EBAL_A1] -pero mis manos están hechas un desastre de modo que será mejor que conduzcas tú, hermano. +[TRAIN_1] +Estación Kurowski -[EBAL_1] -Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. +[TRAIN_2] +Estación Rothwell -[EBAL_1B] -Pulsa el ~h~ botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. +[TRAIN_3] +Estación Baillie -[EBAL_2] -~g~¡Vuelve al coche! +[SUBWAY1] +Estación Portland -[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! +[SUBWAY2] +Estación Rockford -[EBAL_D] -Conozco un tipo, tiene contactos, su nombre es Luigi. +[SUBWAY3] +Estación Staunton sur -[EBAL_D1] -Él y yo nos conocemos de antes de modo que probablemente podríamos conseguirte algún trabajo. Venga, vamos hacia allí. +[SUBWAY4] +Terminal Shoreside -[EBAL_E] -Venga, vamos a pasarnos por allí y te presentaré. +{ ================================================= } +{ ================= VEHICLE NAMES ================= } +{ ================================================= } -[EBAL_I] -El jefe saldrá para veros dentro de poco... +[CAR_1] +Ambulancia -[EBAL_J] -8-Ball tiene un asunto arriba. +[AMBULAN] +Ambulancia -[EBAL_K] -Quizás puedes hacerme un favor +[CAR_2] +Camión de bomberos -[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í. +[FIRETRK] +Camión de bomberos -[EBAL_N] -¡Así que mantén tus manos sobre el volante +[CAR_3] +Coche patrulla -[EBAL_4] -~r~¡8-Ball está muerto! +[POLICAR] +Coche patrulla -[EBAL_5] -~g~¡Consigue un vehículo! +[CAR_4] +Enforcer -[EBAL_6] -~g~¡Recoge a Misty! +[ENFORCR] +Enforcer -[LM1] -'LAS CHICAS DE LUIGI' +[CAR_5] +Barracks -[LM2] -'NO PEGUES A MI ZORRA' +[BARRCKS] +Barracks OL -[LM3] -'LLEVA A MISTY POR MÍ' +[CAR_6] +Rhino -[LM5] -'EL BAILE DE LA POLICÍA' +[RHINO] +Rhino -[LM1_2] -~g~Lleva a Misty al Club de Luigi. +[CAR_7] +Coche del FBI -[LM1_3] -~g~Toca el claxon para conseguir que la chica entre en el coche. +[FBICAR] +Coche del FBI -[LM1_6] -~g~¡Vuelve al coche! +[CAR_8] +Securicar -[LM1_7] -Detén el vehículo junto a Misty y déjala subir. +[SECURI] +Securicar -[LM1_8] -Puedes ir y ver a Luigi en busca de más trabajo o ver que se cuece en Liberty City. +[CAR_9] +Moonbeam -[LM2_A] -Hay un nuevo tipo importante en la ciudad que responde al nombre de AZOTE. +[MOONBM] +Moonbeam -[LM2_E] -Algún tipo listo ha estado mostrando esta basura a mis chicas abajo en el puerto de Portland. +[CAR_10] +Coach -[LM2_B] -¡Ve y muéstrale un bate de béisbol en su cara! +[COACH] +Coach -[LM2_G] -¡Quiero una compensación por este insulto! +[CAR_11] +Flatbed -[LM2_1] -~g~Coge su coche y haz que lo vuelvan a rociar. +[FLATBED] +Flatbed -[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! +[CAR_12] +Linerunner -[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~! +[LINERUN] +Linerunner -[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~! +[CAR_13] +Trashmaster -[LM2_3] -~g~¡Esconde el coche en el garaje de Luigi! +[TRASHM] +Trashmaster -[LM2_4] -~g~¡Vuelve a rociar el coche! +[CAR_14] +Patriot -[LM3_A] -Hey, tengo que hablar contigo... De acuerdo Mick, hablaré contigo más tarde. +[PATRIOT] +Patriot -[LM3_B] -¿Cómo te vá, chico? +[CAR_15] +Mr. Whoopee -[LM3_C] -El hijo del Don, Joey Leone, quiere un poco de acción de su chica de siempre, Misty. +[WHOOPEE] +Mr. Whoopee -[LM3_D] -Ve a recogerla en los Altos de Hepburn... +[CAR_16] +Mule -[LM3_E] -pero cuidado, ésa es la turba del Diablo. +[MULE] +Mule -[LM3_F] -Luego llévala hasta el garaje de él en Trenton y hazlo rápido, +[CAR_17] +Yankee -[LM3_H] -¡así que mantén la vista sobre la carretera y lejos de Misty! +[YANKEE] +Yankee -[LM3_1D] -Pulsa el ~h~ botón L3 ~w~ para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. +[CAR_18] +Pony -[LM3_2] -~g~Lleva a Misty a Joey's. +[PONY] +Pony -[LM3_4] -~g~¡Ve a recoger a Misty! +[CAR_19] +Bobcat -[LM3_5] -Ahora trabajas de forma regular para Luigi, ¿no? Ya era hora de que tuviese un conductor en el que pudiésemos confiar! +[BOBCAT] +Bobcat -[LM3_7] -Estaré contigo en un minuto, bujía. +[CAR_20] +Rumpo -[LM3_10] -~g~¡Coge un vehículo! +[RUMPO] +Rumpo -[LM4_B] -Ve y ocúpate de las cosas por mí. +[CAR_21] +Blista -[LM4_C] -Si necesitas una pieza ve a la puerta trasera del depósito de Municiones en el lado contrario al metro. +[BLISTA] +Blista -[LM5_A] -El baile de la policía se está celebrando en la sala de la vieja escuela cerca del puente +[CAR_22] +Dodo -[LM5_B] -y parece que están buscando un poco de acción a la 'antigua usanza'. +[DODO] +Dodo -[LM5_C] -Ahora tengo chicas por toda la ciudad, pateando las calles. +[CAR_23] +Autobús -[LM5_D] -Llévalas al baile, harán bulto. +[BUS] +Autobús -[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. +[CAR_24] +Sentinel -[LM5_2] -~r~¡Una de las chicas de Luigi es un saco de grasa! +[SENTINL] +Sentinel -[LM5_3] -~g~¡Necesitas un coche! +[CAR_25] +Cheetah -[LM5_4] -~g~Recoge a las chicas que trabajan en St. Marks. +[CHEETAH] +Cheetah -[LM5_5] -~g~Lleva a las chicas al Baile de la Policía! +[CAR_26] +Banshee -[LM5_8] -~g~Chicas trabajando en el Baile: ~1~ +[BANSHEE] +Banshee -[JM2] -'DESPEDIDA A LEE CHONG 'EL GORDO'' +[CAR_27] +Stinger -[JM4] -'EL CHOFER DE CIPRIANI' +[STINGER] +Stinger -[JM5] -'LA MOFETA MUERTA EN EL MALETERO' +[CAR_28] +Infernus -[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'. +[INFERNS] +Infernus -[JM1_2] -~g~Vuelve a aparcar el coche en el restaurante de Marco. +[CAR_29] +Esperanto -[JM1_3] -~g~¡Activa la bomba del coche y luego sal de ahí! +[ESPERAN] +Esperanto -[JM1_4] -~g~¡Estás destrozando el vehículo! ¡Repáralo! +[CAR_30] +Kuruma -[JM1_5] -~g~¡La bomba del coche no está colocada! +[KURUMA] +Kuruma -[JM1_6] -~g~Vuelve a colocar el coche en la posición correcta. +[CAR_31] +Stretch -[JM1_8A] -~y~¡Hey, es mi gran hombre! +[STRETCH] +Stretch -[JM1_8B] -~y~La tienda de bombas está automatizada. Simplemente entra conduciendo, detén tu coche y la tienda hará el resto. +[CAR_32] +Perennial -[JM1_8C] -~y~Ten, tu primer coche puede salirte gratis, pero después de eso te costará dinero. +[PEREN] +Perennial -[JM2_A] -Lee Chong 'el Gordo' está dando palizas para una nueva banda de Colombia... o Colorado... o algo así.... +[CAR_33] +Landstalker -[JM2_B] -La verdad es que no estoy seguro. De todas formas, quién necesita detalles. +[LANDSTK] +Landstalker -[JM2_D] -Esa rata a vendido su último refrito. +[CAR_34] +Mañana -[JM2_E] -¡Quiero que le liquides! +[MANANA] +Mañana -[JM2_G] -Equípate con una nueve, sabes dónde está, ¿verdad? +[CAR_35] +Idaho -[JM2_H] -Bueno, recuerda, vigila tu espalda en China Town, es territorio de las Tríadas. +[IDAHO] +Idaho -[JM3_A] -De acuerdo vamos a por la furgoneta de la paga. +[CAR_36] +Stallion -[JM3_B] -Sale de China Town todos los días. +[STALION] +Stallion -[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. +[CAR_37] +Taxi -[JM3_D] -Ahora golpéala fuerte y los imbéciles de los guardias de seguridad se achicarán. +[TAXI] +Taxi -[JM3_E] -Luego llévala al almacén en los muelles y mis chicos se encargarán desde ahí. +[CAR_38] +Cabbie -[JM3_F] -Bueno, no estarán haciendo sus rondas todo el día, de modo que no pierdas el tiempo. +[CABBIE] +Cabbie -[JM3_1] -~g~Lleva la furgoneta al almacén. +[CAR_39] +Buggy -[JM3_2] -~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. +[BFINJC] +BF Injection -[JM4_B] -¡Oh! ¡Aquí está el tipo del que te hablaba! +[PREDATR] +Predator -[JM4_C] -De acuerdo, escucha. Este tío no es italiano y no es un mecánico, pero puede arreglar las cosas. +[TRAIN] +Tren -[JM4_D] -Este es el Capo, Toni Cipriani. +[HELI] +Helicóptero -[JM4_E] -Sí, soy Toni Cipriani +[RCBANDT] +Bandit RC -[JM4_F] -Bien, llévale al restaurante de Mamá en St Marks. +[BELLYUP] +Furgoneta de las Tríadas -[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? +[MRWONGS] +Mr Wongs -[JM4_2] -¡Espera aquí! Mantén el motor en marcha. Esto no es una visita social. +[MAFIACR] +Sentinel de la mafia -[JM4_3] -¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! +[YARDICR] +Lobo jamaicano -[JM4_4] -Las Tríadas creen que pueden meterse conmigo, las Tríadas, ¡CONMIGO! +[YAKUZCR] +Stinger de la yakuza -[JM4_6] -¡Hey vigila el coche! Dije que nada de numeritos. +[DIABLCR] +Stallion de los Diablos -[JM4_7] -~g~Lleva a Toni al restaurante de su mamá. +[COLOMCR] +Cruiser del cártel -[JM4_8] -~r~¡Toni ha sido liquidado! +[HOODSCR] +Rumpo XL de los hood -[JM5_A] -¡Cojonudo! Estupendo. +[AEROPL] +Avioneta -[JM5_B] -De acuerdo, ¡justo el tipo con el que necesito hablar! +[SPEEDER] +Speeder -[JM5_D] -Uno de los Forellis pensó que era un tipo listo, de modo que se llevó lo que estaba buscando. +[REEFER] +Reefer -[JM5_E] -Lleva el cuerpo a la trituradora en Harwood, ¿de acuerdo? +[PANLANT] +Panlantic -[JM5_1] -~g~¡Llévalo a la trituradora! +[BORGNIN] +Borgnine -[JM5_2] -~g~¡Son los hermanos Forelli! +[TOYZ] +TOYZ -[JM6_A] -Debe ser todo un viajecito, ¿eh? +{ ======================================================= } +{ ================= RADIO STATION NAMES ================= } +{ ======================================================= } -[JM6_B] -De acuerdo, escucha. Lleva un coche hasta la casa franca en St. Marks y recoge a algunos de los míos. +[FEA_FM0] +HEAD RADIO -[JM6_C] -Están atracando un banco y necesitan un conductor. +[HEAD] +Head Radio -[JM6_D] -Di mi palabra de que eras el hombre, de modo que no fastidies esto. +[FEA_FM1] +DOUBLE CLEF FM -[JM6_E] -Llévales al banco antes de las cinco en punto, ni un minuto después. +[DBL_CLF] +Double Clef FM -[JM6_2] -Mantén el motor en marcha, entraremos y saldremos enseguida. +[FEA_FM2] +K-JAH RADIO -[JM6_3] -¡¡¡Sácanos de aquí!! +[K_JAH] +K-Jah Radio -[JM6_4] -¡¡¡Líbrate de los polis y llévanos a la casa franca!! +[FEA_FM3] +RISE FM -[JM6_6] -~g~¡Ve y consigue un vehículo menos llamativo! +[RISE] +Rise FM -[JM6_7] -~g~¡Necesitas a los 3 para robar el banco! +[FEA_FM4] +LIPS 106 -[TM1] -'SACANDO LA COLADA' +[LIPS] +Lips 106 -[TM2] -'EL ENCARGO' +[FEA_FM5] +GAME FM -[TM3] -'SALVATORE HA CONVOCADO UNA REUNIÓN' +[GAM_FM] +Game Radio FM -[TM4] -'TRÍADAS Y TRIBULACIONES' +[FEA_FM6] +MSX FM -[TM5] -'EL PEZ GLOBO' +[MSX_FM] +MSX FM -[TONI_P] -¡Tengo un trabajo urgente para ti! -Toni +[FEA_FM7] +FLASHBACK 95.6 -[TM1_A] -~w~Toma asiento, chico, siéntate. +[FLASHB] +Flashback 95.6 -[TM1_B] -~w~Así que la lavandería no pagará protección, ¿eh? +[FEA_FM8] +CHATTERBOX FM -[TM1_C] -~w~¿Las Tríadas creen que pueden meterse conmigo? +[CHAT] +Chatterbox FM -[TM1_D] -~w~Vamos a enseñar a esos aspirantes a tipos duros lo que significa ser un tipo duro. +{ ============================================================================================================== } +{ ================= STRINGS RELATED TO GARAGES (BOMB SHOP, SPRAY SHOP, IMPORT/EXPORT, CRUSHER) ================= } +{ ============================================================================================================== } -[TM1_E] -~w~Sí, enséñales algo de respeto. Ningún hijo mío recibe de nadie de las Tríadas. +[GA_1] +¡Hala! ¡Demasiado peligroso para mi gusto! -[TM1_F] -~w~Tu padre, Dios acoja su alma, no aguantó ninguna mierda de las Tríadas en Sicilia. +[GA_1A] +Vuelve cuando no estés tan ocupado... -[TM1_G] -~w~Lo siento Ma. Sí Ma. +[GA_2] +He cambiado el motor y la mano de pintura. ¡La poli no te reconocerá! -[TM1_H] -~w~Quiero que destruyas sus furgonetas de lavandería +[GA_3] +¡Ya no es gratis! ¡La mano de pintura son 1.000 dólares! -[TM1_I] -~w~y destroces a cualquiera de las Tríadas que se interponga en tu camino. +[GA_4] +Una bomba de coche vale 1.000 dólares. -[TM1_J] -~w~8-Ball puede suministrarte lo que necesites. +[GA_5] +Tu coche ya tiene una bomba instalada. -[TM2_A] -~w~TONI ha salido a machacar a la gente o a intentarlo. +[GA_6] +Apárcalo, prepáralo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! -[TM2_AA] -Nunca será tan duro como su padre, te dejó una nota en la mesa. +[GA_6B] +¡Apárcalo, prepáralo tocando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! -[TM2_B] -~w~La lavandería ha aceptado pagar. ¡Lo hiciste realmente bien, chico! +[GA_7] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. -[TM2_C] -~w~Ve a recoger el dinero y tráelo de vuelta aquí. Cuidado con las Tríadas. +[GA_7B] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. -[TM2_D] -~w~Pueden estar metiéndote un petardo por el culo, y no mancharse. +[GA_8] +Utiliza el detonador para activar la bomba. -[TM2_E] -~w~¡Nadie, quiero decir nadie, se mete con TONI CIPRIANI! +[GA_9] +Ha conseguido ~1~ de los 10 coches especiales. -[TM2_1] -~g~¡¡Devuélvele el dinero a Toni!! +[GA_10] +Buen trabajo. Aquí tienes tus ~1~ dólares. -[TM2_2] -~g~¡Los dejaste tiesos a todos! +[GA_11] +Ya tenemos este modelo. ¡No nos sirve para nada! -[TM3_MA] -~w~¡No sé dónde está! +[GA_12] +Bomba armada -[TM3_MB] -~w~Te juro que ese chico mío a veces no se conoce a sí mismo. +[GA_13] +Eres todo un profesional. Completa la lista y conseguirás una recompensa. -[TM3_MC] -~w~Ahora bien, su padre era diferente. Siempre en la cumbre, al cargo de todo, valiente... +[GA_14] +Ya están todos los coches. ¡Estupendo! Toma un detallito. -[TM3_A] -~w~Don Salvatore ha convocado una reunión. +[GA_15] +Espero que te guste el nuevo color. -[TM3_B] -~w~Necesito que recojas la limusina y a su chico, Joey, del garaje. +[GA_16] +Esta mano de pintura es gratuita. -[TM3_C] -~w~Luego recoge a Luigi en su club, vuelve aquí y recógeme a mí, +[GA_19] +No nos interesa ese modelo. -[TM3_D] -~w~luego todos iremos juntos a la casa del jefe. +[GA_20] +Tenemos de esos más de los que necesitamos. Lo siento, tío, no hay trato. -[TM3_E] -~w~Esos Tríadas, no saben cuándo parar. +[GA_21] +No puedes guardar más coches en este garaje. -[TM3_F] -~w~Quieren una guerra. Tendrán una guerra. +[CR_1] +La grúa no puede levantar este vehículo. -[TM3_G] -~w~Ahora en marcha. +{ ============================================================================================ } +{ ================= MESSAGES TO INDICATE THAT MISSIONS ARE NOT YET AVAILABLE ================= } +{ ============================================================================================ } -[TM3_1] -~g~Coge el Stretch de Joey's. +[GOAWAY] +~g~¡Ya estás en una misión! -[TM3_2] -~g~Ahora ve a recoger a Luigi. +[LUIGGO] +~g~Luigi está entrevistando a unas chicas nuevas... ¡Vuelve más tarde! -[TM3_3] -~g~Ahora ve a recoger a Toni. +[JOEYGO] +~g~Joey ha salido con Misty. ¡Pásate más tarde! -[TM3_4] -~g~Lleva a los mafiosos hasta la casa de Salvatore. +[TONIGO] +~g~Toni ha llevado a su mamá a la ópera... ¡Llama en otro momento! -[TM3_5] -~y~¡¡Es una emboscada de las Tríadas!! +[KEMUGO] +~g~María y Kemuri están muy liadas... ¡Pásate más tarde! -[TM4_B] -~w~¡Estamos en GUERRA! Las Tríadas tienen una fábrica de pescado como fachada. +[KENJGO] +~g~Kenji está reunido con la yakuza, ¡llama en otro momento! -[TM4_C] -~w~La mayor parte de sus negocios se pierde en el mercado de pescado de Chinatown. +[RAYGO] +~g~Ray tiene otros baños por los que rondar, ¡ven en otro momento! -[TM4_D] -~w~Esa lavandería todavía nos debe por la protección. +[LOVEGO] +~g~Donald Love tiene otros asuntos que atender. ¡Pide una cita más tarde! -[TM4_E] -~w~Consideran que las Tríadas les están protegiendo ahora, así que digo que les demos su merecido castigo. +[KENSGO] +~g~¡Kenji está ocupado! ¡Llama más tarde! -[TM4_F] -~w~¡Toma a esos chicos y golpea a los Señores de la Guerra de las Tríadas! +[ASUSGO] +~g~¡Asuka no está disponible en este momento! -[TM4_G] -~w~Demonios, si tienes la oportunidad, revienta también a algunos de sus soldados. +[HOODGO] +~g~¡Los Hoods no pueden atenderte en este momento! -[TM4_GAT] -~g~Necesitas un 'Camión para pescado Tríada' para entrar. +[WRONGT1] +~g~Vuelve entre las 05:00 y las 21:00 para buscar trabajo. -[TM5_A] -TEXT NO LONGER REQUIRED +[WRONGT2] +~g~Vuelve entre las 06:00 y las 14:00 para buscar trabajo. -[TM5_B] -~w~Ya he tenido bastante de esta mierda. +[WRONGT3] +~g~Vuelve entre las 15:00 y las 00:00 para buscar trabajo. -[TM5_C] -~w~¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! +{ ============================================================================ } +{ ================= SUBTITLES FOR THE AMMU-NATION SHOP CLERK ================= } +{ ============================================================================ } -[TM5_D] -8-Ball ha instalado una bomba en un camión de la basura. +[AMMU_A] +Luigi dijo que necesitabas una pipa... -[TM5_E] -~w~Tiene un temporizador, así que si la lías no quedarán evidencias. Vete y toma ese camión de basura. +[AMMU_B] +Joey me pidió que te armáramos... -[TM5_F] -~w~¡Cuidado, 8-Ball dice que es muy sensible y que cualquier movimiento puede hacerlo estallar! +[AMMU_C] +Ve a la parte de atrás. Te dejé un nueve en el patio. -[TM5_G] -~w~Su fábrica de pescado abrirá sus puertas a un camión de basura, así que puedes conducirlo allí directamente. +[AMMU_D] +Tengo todo lo necesario para defender tu casa. -[TM5_H] -~w~Aparca entre las latas de gas y ¡sal pitando de ese infierno! +[AMMU_E] +¿También quieres una licencia? -[TM5_I] -~w~Quiero que llueva trozos de caballa. +[AMMU_F] +No necesito tu documentación, pareces de fiar. -[TM5_J] -~w~Esto es realmente bíblico, nada de bajo presupuesto. +{ ==================================================================================================================== } +{ ==================================================================================================================== } +{ =============================================== SIDE MISSION STRINGS =============================================== } +{ ==================================================================================================================== } +{ ==================================================================================================================== } -[FM2] -CORTANDO LA HIERBA +{ ==================================================================== } +{ ================= TAXI/CABBIE SIDE MISSION STRINGS ================= } +{ ==================================================================== } -[FM4] -ÚLTIMOS DESEOS +[TAXI_M] +'TAXISTA' -[FM1_A] -~w~Yo y los chicos queremos hablar de negocios +[TSCORE2] +$~1~ -[FM1_B] -~w~Así que esta tarde vas a vigilar a mi chica. +[IN_ROW] +¡~1~ CONSECUTIVOS! $~1~ -[FM1_C] -~w~¡OYE, MARÍA! ¡MUEVE ESE CULO! +[TAXIH1] +Para cerca de un peatón señalado para recogerlo, luego condúcelo a su destino antes de que se acabe el tiempo. -[FM1_D] -~w~El grandísimo estúpido hace esto todo el tiempo. +[TAXI1] +~g~Busca un cliente. -[FM1_E] -~w~Y aquí está ella ¡La primera y única Reina de Saba! +[TAXI2] +~r~¡Se te acabó el tiempo! -[FM1_F] -~w~¿Qué hacíais ahí arriba? +[TAXI3] +~r~¡Tu pasajero ha salido corriendo! -[FM1_G] -~w~Fuera lo que fuera, seguro que me cuesta dinero. +[TAXI4] +¡Carrera terminada! -[FM1_H] -~w~Bueno, no pensarás que me voy a quedar a conversar ¿no? +[TAXI5] +¡VIAJE RÁPIDO! -[FM1_I] -~w~Métete en ese coche y cierra la bocaza. +[TAXI6] +Misión de taxi terminada -[FM1_J] -~w~Llévate la limusina, pero devuélvela de una pieza ¿me has oído? +[TAXI7] +~r~Tu coche está destrozado, haz que lo reparen. -[FM1_K] -~w~Y vigílala, puede causarte problemas. +[FARE1] +~g~Ve al ~w~club Sex Kitten Meeouch ~g~en el barrio rojo. -[FM1_L] -~w~¡Sí, sí, sí! Estoy segura de que tu nuevo perrito faldero tiene todo previsto. +[FARE2] +~g~Ve a ~w~Supa Save ~g~en Portland View. -[FM1_M] -~w~¿Pues no es fuerte y grande? +[FARE3] +~g~Ve a ~w~la sala Clásica ~g~en Chinatown. -[FM1_N] -~w~¡Eh, Fido, vayamos a visitar a Chico y hacer una fiestecita! +[FARE4] +~g~Ve a la ~w~cafetería Greasy Joe ~g~en Callahan Point. -[FM1_P] -~g~Ese de ahí es Chico, párate cerca. +[FARE5] +~g~Ve a la ~w~tienda de armas Ammu-Nation ~g~en el barrio rojo. -[FM1_S] -~w~Ahí vas, señora. +[FARE6] +~g~Ve a ~w~Easy Credit Autos ~g~en Saint Mark's. -[FM1_TT] -~w~¡ES UNA REDADA POLICIAL! +[FARE7] +~g~Ve al ~w~bar de topless de Woody ~g~en el barrio rojo. -[FM1_1] -~g~¡Vuelve al Stretch! +[FARE8] +~g~Ve al ~w~restaurante Marcos ~g~en Saint Mark's. -[FM1_2] -~g~¡Entra en el Stretch! +[FARE9] +~g~Ve al ~w~taller de importación y exportación ~g~en el puerto de Portland. -[FM1_3] -~r~Si abandonas a María y Salvatore te zurrará, vuelve y recógela. +[FARE10] +~g~Ve a ~w~Punk Noodles ~g~en Chinatown. -[FM1_4] -~g~¡Te has deshecho de la mujer del Don! ¡Vuelve al almacén y espera a María! +[FARE11] +~g~Ve a la ~w~zona en obras~g~ de Fort Staunton. -[FM1_5] -~g~¡Lleva a María sana y salva con Salvatore! +[FARE12] +~g~Ve al ~w~estadio de fútbol ~g~en Aspatria. -[FM1_6] -~g~¡Chico no estará allí para siempre, lleva a María al muelle! +[FARE13] +~g~Ve a la ~w~iglesia ~g~de Bedford Point. -[FM1_7] -~r~¡María está muerta! A Salvatore no le va a gustar nada... +[FARE14] +~g~Ve al ~w~casino ~g~de Torrington. -[FM1_8] -~r~¡Te cargaste al proveedor de Maria! +[FARE15] +~g~Ve a la ~w~universidad ~g~en el Campus de Liberty. -[FM2_J] -Déjanos solos un minuto. +[FARE16] +~g~Ve al ~w~centro comercial ~g~en la zona del parque Belleville. -[FM2_A] -El Cartel colombiano está haciendo SPANK en algún lugar de Liberty. +[FARE17] +~g~Ve al ~w~museo ~g~de Newport. -[FM2_K] -pero no sabemos dónde y parece como si supieran todo lo que hacemos antes de que lo hagamos. +[FARE18] +~g~Ve al ~w~edificio de AmCo ~g~en Torrington. -[FM2_L] -Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. +[FARE19] +~g~Ve a ~w~Bolt Burgers ~g~en Bedford Point. -[FM2_M] -Ha estado malgastando más dinero del que gana. +[FARE20] +~g~Ve al ~w~parque ~g~de Belleville. -[FM2_N] -Normalmente toma un taxi de vuelta a casa tras el trabajo. Así que síguele. +[FARE21] +~g~Ve al ~w~Aeropuerto Internacional Francis. -[FM2_O] -Y si nos está traicionando... mátalo. +[FARE22] +~g~Ve a la ~w~presa Cochrane~g~. -[FM2_F] -Aquí viene nuestro amiguito. El señor Bocazas en persona. +[FARE23] +~g~Ve al ~w~taller de importación/exportación~g~ en el distrito de la presa Cochrane. -[FM2_G] -¿Te han seguido? Sabes que lo que pasa aquí es nuestro pequeño secreto. +[FARE24] +~g~Ve al ~w~hospital ~g~de Pike Creek. -[FM2_H] -No... no. No me han seguido. ¿Tienes mi mercancía? +[FARE25] +~g~Ve al ~w~parque ~g~de Shoreside Vale. -[FM2_I] -Aquí está tu SPANK, soplón, ahora habla. +[FARE26] +~g~Ve a las ~w~Torres del Noroeste ~g~de Wichita Gardens. -[FM2_P] -OK, así que los de Leone libran una guerra en dos frentes. +[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! -[FM2_Q] -Tienen una guerra territorial con las Tríadas y no hay signos de que ninguno se vaya a rendir. +[TTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. -[FM2_R] -Mientras tanto Joey Leone se ha hecho mala sangre con los Forellis. +[TTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. -[FM2_S] -Cada día que pasa pierden hombres e influencia en la ciudad. +{ ============================================================================= } +{ ================= AMBULANCE/PARAMEDIC SIDE MISSIONS STRINGS ================= } +{ ============================================================================= } -[FM2_T] -Salvatore es cada vez más peligroso y paranoico. Sospecha de todos y de todo. +[AMBUL_M] +'SANITARIO' -[FM2_U] -Con lealtades como la tuya, por qué tendría que preocuparse. +[A_SAVES] +GENTE SALVADA: ~1~ -[FM2_1] -~g~¡Ahí está Curly Bob! +[ATUTOR2] +~g~Conduce a los pacientes hasta el hospital con mucho cuidado. Cada golpe reducirá sus posibilidades de supervivencia. -[FM2_2] -~g~¡Curly ha salido del club, síguele! +[A_TIME] ++~1~ segundos -[FM2_5] -~g~Llévale al Puerto Portland. +[A_FULL] +~r~¡Ambulancia llena! -[FM2_6] -~r~¡Curly no entrará en un taxi accidentado! +[A_RANGE] +~g~La radio de la ambulancia está fuera de cobertura, ¡acércate a un hospital! -[FM2_7] -~r~¡Curly se ha esfumado! ¡Ya no hay encuentro! +[A_COMP1] +¡Misiones de sanitario completadas! -[FM2_8] -~g~¡Golpea a Curly Bob! +[A_CANC] +~r~¡Misión de sanitario cancelada! -[FM2_9] -~r~¡Curly Bob está muerto! +[A_COMP3] +¡Misiones de sanitario completadas! ¡Ahora no te cansarás al correr! -[FM2_10] -~r~¡Curly se largó! +[ATUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. -[FM2_11] -~g~Aparca frente al club de Luigi, Curly Bob saldrá pronto. +[ATUTOR3] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. -[FM2_12] -~r~¡Os ha dado esquinazo! +[ALEVEL] +Nivel de misión de sanitario: ~1~ -[FM3_A] -~w~Tenemos que terminar con esos bastardos colombianos, +[A_FAIL1] +Misión de sanitario terminada. -[FM3_B] -~w~pero mientras estamos en guerra con las Tríadas no somos lo bastante fuertes. +[A_FAIL2] +~r~¡Tu falta de rapidez ha sido fatal para el paciente! -[FM3_C] -~w~El Cartel tiene fondos ilimitados procedentes de esa mierda de SPANK. +[A_FAIL3] +~r~¡El paciente está muerto! -[FM3_D] -~w~si les atacamos abiertamente, fregarán el suelo con nosotros. +[A_PASS] +¡Rescatado! -[FM3_E] -~w~Deben estar haciendo SPANK en ese barco grande al que os llevó Curly. +[A_COMP2] +¡Nunca te cansarás! -[FM3_F] -~w~Así que tenemos que usar las cabezas, o mejor, una cabeza. La tuya. +{ ============================================================================ } +{ ================= FIRE TRUCK/FIREMEN SIDE MISSIONS STRINGS ================= } +{ ============================================================================ } -[FM3_G] -~w~Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal hacia mí, Salvatore Leone. +[FIRE_M] +'BOMBERO' -[FM3_H] -~w~Si haces esto por mí, serás todo un hombre, cualquier cosa que quieras. +[F_EXTIN] +INCENDIOS: -[FM3_I] -~w~Ve a ver a 8-Ball, necesitas su experiencia para volar ese barco. +[FTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. -[FM3_8A] -~w~¡Eh, hombre! Salvatore ha llamado, +[FTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. -[FM3_8B] -~w~pero un trabajo como este necesita muchos fuegos artificiales. +[F_PASS1] +¡Fuego apagado! -[FM3_8D] -~w~pero sabes que conmigo consigues mucho a cambio de tu pasta. +[F_FAIL1] +¡Misión del camión de bomberos terminada! -[FM3_8E] -~w~De acuerdo, ¡vamos a hacerlo! +[F_CANC] +~r~¡Misión del camión de bomberos cancelada! -[FM3_8F] -~w~Puedo hacer detonar este pequeño, pero aún no puedo usar una pieza con estas manos. +[F_RANGE] +~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate a una estación de bomberos! -[FM3_8G] -~w~¡Toma, este rifle te ayudará a reventar algunas cabezas! +[F_FAIL2] +~r~¡Llegas demasiado tarde! -[FM3_4] -~g~¡Para el coche y deja que 8-Ball salga! +[F_START] +~g~Informe de vehículo en llamas en: ~a~. Ve y extingue el fuego. -[FM3_7] -~r~¡¡8-Ball se ha helado! +{ ============================================================================== } +{ ================= POLICE CAR/VIGILANTE SIDE MISSIONS STRINGS ================= } +{ ============================================================================== } -[FM3_8] -~r~¡Los guardias han sido alertados! +[COP_M] +'JUSTICIERO' -[FM4_A] -~w~Es mi limpiador favorito. +[C_KILLS] +CRIMINALES ABATIDOS: ~1~ -[FM4_B] -~w~Estoy orgulloso de ti, hijo, sacudiste la mierda de esas pelotas grasientas. +[LEGAL] +~g~¡Elimina la amenaza criminal! -[FM4_C] -~w~Tengo un trabajito más para ti antes de que podamos celebrarlo. +[C_BREIF] +~g~Sospechoso visto por última vez en: ~a~. -[FM4_D] -~w~Hay un coche a la vuelta del edificio del club de Luigi. +[C_RANGE] +~g~La radio de la policía está fuera de cobertura, ¡acércate a una comisaría! -[FM4_E] -~w~El interior está pringado de sesos. +[C_PASS] +¡AMENAZA ELIMINADA! -[FM4_F] -~w~Tuvimos que ayudar a un tipo a que se decidiera, y fue un poco -er- sucio. +[CTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. -[FM4_H] -~w~Llévalo a la trituradora antes de que los polis lo encuentren. +[CTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. -[AM3] -'SANGRA PAPARAZZI' +[COPCART] +~g~Tienes ~1~ segundos para volver a un vehículo de la policía antes de que termine la misión. -[AM4] -'DÍA DE PAGA PARA RAY' +[C_FAIL] +¡Misión de justiciero terminada! -[AM5] -'TANNER DOS CARAS' +[C_CANC] +~r~¡Misión de justiciero cancelada! -[AM1_A] -Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, +[C_ESCP] +~r~¡El sospechoso ha escapado! -[AM1_B] -de negocios o de lo que sea. Pongamos las cartas sobre la mesa. +[C_TIME] +~r~¡Tu trabajo como defensor de la ley ha terminado! -[AM1_C] -Yo soy Yakuza y sé que trabajas para la familia de Salvatore Leone. +[C_VIGIL] +¡PREMIO POR JUSTICIERO! -[AM1_D] -Puedo darte trabajo en nuestra organización, +{ ======================================================================== } +{ ================= CHECKPOINT RUN SIDE MISSIONS STRINGS ================= } +{ ======================================================================== } -[AM1_E] -Pero primero debes demostrarme que has cortado todos tus lazos con la Mafia. +[T4X4_1] +'PATIO DE RECREO' -[AM1_G] -Asegúrate de que no llega vivo a su club. +[T4X4_1A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~15~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -[AM1_H] -Mientras tanto María y yo nos pondremos al día por los viejos tiempos. +[T4X4_1B] +¡~1~ de 15! -[AM1_I] -Oh.. Asuka, tienes masajista. +[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. -[AM1_J] -Eso no es un masajista. +[T4X4_2] +'UN PASEO POR EL PARQUE' -[AM1_1] -~g~¡Salvatore está saliendo del club de Luigi! +[T4X4_2A] +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~12~g~ puntos de control! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -[AM1_2] -~r~¡Te han descubierto! +[T4X4_2B] +¡~1~ de 12! -[AM1_3] -~r~¡Has perdido a Salvatore! +[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. -[AM1_4] -~r~Buen intento, ¡has asustado al objetivo! ¿Y te llamas a ti mismo pistolero? +[T4X4_3] +'¡AGARRADO!' -[AM1_5] -~g~Ve al Distrito de la Luz Roja y espera a que Salvatore salga del club. +[T4X4_3A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~20~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -[AM1_7] -~r~Salvatore está en casa, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar Chacal! +[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. -[AM1_8] -~g~Salvatore saldrá del club del Luigi aproximadamente a las ~1~:~1~ +[T4X4_3C] +¡~1~ de 20! -[AM2_4] -~g~¡Te han visto venir como a un elefante al galope! +[MM_1] +'CAOS EN EL APARCAMIENTO' -[AM3_A] -Un periodista ha estado metiendo sus narices por aquí. +[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. -[AM3_B] -María y yo nos hemos tomado unas pequeñas vacaciones juntos hasta que puedas librarte de ese mirón pervertido. +[MM_1_B] +¡~1~ de 20! -[AM4_A] -¡Es mi guapo manitas! +[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. -[AM4_B] -María está muy ocupada en este momento, pero le diré que has llamado. +[T4X4_F] +~r~¡Te has escapado! ¿Demasiado difícil para ti? -[AM4_C] -¿Quién es? ¿Asuka? Ya sé que he sido una niña traviesa, ¡pero es que necesitaba mear! ¿Vale? +{ ============================================================================ } +{ ================= RC CAR DESTRUCTION SIDE MISSIONS STRINGS ================= } +{ ============================================================================ } -[AM4_D] -Es el momento de que te encuentres con nuestro hombre dentro del DPL. +[RC1] +'DESTRUCCIÓN DE LOS DIABLOS' -[AM4_E] -Aquí está su pago por el último trabajito que hizo para nosotros. +[RC2] +'LA MASACRE DE LA MAFIA' -[AM4_F] -El es comprensiblemente cauteloso. +[RC3] +'CALAMIDAD EN EL CASINO' -[AM4_G] -Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. +[RC4] +'EXTERMINIO DE RUMPOS' -[AM5_A] -María y yo hemos ido de compras. +[RC_1] +¡Tienes 2 minutos para destruir todos los coches de los Diablos que puedas! -[AM5_B] -¡Nuestra fuente en la policía nos ha informado de que uno de nuestros conductores es un extrañamente animado poli camuflado! +[RC_2] +¡Tienes 2 minutos para destruir todos los coches de la mafia que puedas! -[AM5_C] -El es un inútil fuera de su coche así que lo hemos marcado con un seguidor. +[RC_3] +¡Tienes 2 minutos para destruir todos los coches de la yakuza que puedas! -[AM5_D] -¡Hazle sangrar! +[RC_4] +¡Tienes 2 minutos para destruir todos los coches de los jamaicanos que puedas! -[AM5_1] -¡Tanner está sobre ti! +[RC_5] +¡Tienes 2 minutos para destruir todos los coches de los Hood que puedas! -[AS1] -'CEBO' +[RC_6] +¡Tienes 2 minutos para destruir todos los coches del cártel que puedas! -[AS2] -'MARCHANDO UN EXPRESO' +{ ==================================================================================================================== } +{ ==================================================================================================================== } +{ ================================================ MAIN STORY STRINGS ================================================ } +{ ==================================================================================================================== } +{ ==================================================================================================================== } -[AS4] -'RESCATE' +{ ================================================== } +{ ================= OPENING SCENES ================= } +{ ================================================== } -[AS1_A] -~w~Parece que Miguel piensa que le maltrato +{ Catalina, colombiana } -[AS1_B] -~w~Pero él ha revelado cuánto teme Catalina tu búsqueda de revancha. +[BETRA_A] +Lo siento, cariño. -[AS2_A] -~w~Infravaloramos los planes de Catalina para el SPANK +[BETRA_B] +Soy una chica ambiciosa, ¿y tú? -[AS2_B] -~w~Va mucho más allá de los Yardies vendiéndolo en las esquinas. +[BETRA_C] +Un Don Nadie. -[AS2_D] -~w~Han vendido SPANK en puestos callejeros. +{ Newspaper clip. Only PAPER1 is used } -[AS2_1] -¡¡Todos los puestos de expreso en Portland destruidos!! +[PAPER1] +CRIMINAL HERIDO DE BALA POR SU NOVIA Y CÓMPLICE; EL TRIBUNAL ENCUENTRA CULPABLE AL ATRACADOR CON UN VEREDICTO UNÁNIME. -[AS2_2] -~g~¡¡Todos los puestos de expreso en Staunton Island destruidos!! +[PAPER2] +¡DIEZ AÑOS POR AMOR! -[AS2_3] -~g~¡¡Todos los puestos de expreso en Shoreside Vale destruidos!! +[PAPER3] +* -[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! +{ Cutscene where the Colombians kidnap the Old Oriental Gentlemen. Claude and 8-Ball escape from the van. } -[AS2_6] -~g~¡Todavía hay puestos de expreso en Shoreside Vale! +{ Libery City News broadcaster } -[AS2_7] -~g~¡Todavía hay puestos de expreso en Staunton Island! +[JAILB_V] +Hoy, Liberty City se ha visto conmocionada. -[AS2_8] -~g~¡Todavía hay puestos de expreso en Portland! +[JAILB_A] +La policía y los servicios de emergencia lidian con las consecuencias -[AS2_9] -~g~¡Todavía hay puestos de expreso en Portland y en Shoreside Vale! +[JAILB_B] +de un ataque devastador a un convoy policial ocurrido esta mañana. -[AS2_10] -~g~¡Todavía hay puestos de expreso en Portland y en Staunton Island! +[JAILB_C] +No se ha informado de quiénes eran los prisioneros trasladados en el convoy -[AS2_12] -~g~¡Cruza los distritos de Liberty para buscar puestos de ~b~Marchando un Expreso! +[JAILB_D] +y ningún grupo ha reconocido la autoría. -[AS3_A] -~W~¿Lo apretamos un poco más o esperamos a que se vuelva negro y caiga? +[JAILB_E] +El convoy abandonó las oficinas de la policía esta mañana -[AS3_B] -~w~Dale un pinchazo rápido... +[JAILB_F] +para hacer una transferencia de reos a la penitenciaría de Liberty. -[AS3_D] -~w~¡Mi manitas! +[JAILB_G] +El ataque se produjo en el puente Callahan, -[AS3_E] -~w~Me aburría, así que vine a hacer compañía a Asuka. +[JAILB_H] +dejando pocos testigos y al puente seriamente dañado. -[AS3_1] -~g~Busca un ~r~bote~g~ y ve al ~b~boya del aeropuerto! +[JAILB_I] +Se cree que algunos de los convictos han perecido en la explosión -[AS3_3] -~g~Espera a que el ~y~avión~g~ comience a acercarse! +[JAILB_J] +posterior al ataque inicial. -[AS3_5] -~g~¡Recupera la carga! +[JAILB_W] +Pasadas las horas se hizo evidente que el ataque era obra de profesionales, -[AS3_4] -~g~¡¡Usa un lanzador de cohetes para derribar ~y~el avión~g~!! +[JAILB_K] +ya que la identificación de los prófugos se complicó -[AS3_2] -~b~¡Ve al boya del aeropuerto! ~y~¡¡El avión se está acercando!! +[JAILB_L] +cuando piratas informáticos atacaron las bases de datos de la policía. -[AS3_6] -~g~~1~ DE 8 +[JAILB_O] +Con el retraso del proyecto del túnel Porter, -[KM1] -'KANBU REVIENTA' +[JAILB_P] +este desastre deja a Portland aislada del resto de la ciudad. -[KM3] -'TRATO SIGILOSO' +[JAILB_M] +* -[KM4] -'SHIMA' +[JAILB_N] +* -[KM5] -'HEROÍNA' +[JAILB_X] +En una declaración realizada hoy previamente, -[KM1_A] -Mi hermana habla muy bien de ti, +{ Colombian thug } -[KM1_E] -aunque todavía debo convencerme de que un gaijin puede ofrecerme algo más que contratiempos. +[JAILB_Q] +¡Vamos! -[KM1_B] -Tal vez puedas ayudar con una situación que me tiene en desventaja. +[JAILB_R] +¡Señor pendejo! -[KM1_F] -Desde luego que el fracaso lleva consigo su propia desgracia. +[JAILB_S] +No nos importará matarte. -[KM1_C] -Un Yakuza Kanbu está bajo custodia esperando ser trasladado y juzgado. +{ Police officer } -[KM1_G] -Es un valioso miembro de la familia. +[JAILB_T] +Os vais a arrepentir. -[KM1_H] -Libéralo y llévatelo al dojo de Bedford Point. +{ Colombian thug } -[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. +[JAILB_U] +Bien, bien, piérdete. -[KM1_1] -~g~¡Roba un coche de la pasma! +{ ======================================================================= } +{ ================= MISSION: GIVE ME LIBERTY (NO OWNER) ================= } +{ ======================================================================= } -[KM1_2] -~g~¡Carga el coche con una bomba! +{ TITLE } -[KM1_3] -~g~Ahora llévalo al dojo Yakuza. +[EBAL] +'DAME LIBERTAD' -[KM1_5] -~g~Vale, ahora ve a la comisaría. +{ 8-Ball } -[KM1_6] -~g~¡Pon una bomba en el coche! +[EBAL_A] +Conozco un lugar en las afueras del barrio rojo donde podemos escondernos, -[KM1_7] -~g~¡Sólo vehículos de policía autorizados! +[EBAL_A1] +pero mis manos están destrozadas, así que conduce tú, hermano. -[KM1_9] -~r~No usaste un coche bomba para destruir la pared. +{ Mission instructions } -[KM1_10] -~r~El Yakuza Kanbu está muerto - ¡y tu honor también! +[EBAL_1] +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. -[KM1_11] -~r~¡Trajiste la desgracia a ti mismo! +[EBAL_1B] +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. -[KM2_A] -Es imposible sobreestimar la importancia del protocolo en esta sección de trabajo. +[EBAL_2] +~g~¡Vuelve al coche! -[KM2_B] -Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca tuve la oportunidad de devolver su amabilidad. +[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! -[KM2_C] -Su punto débil son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. +{ 8-Ball } -[KM2_F] -Mi honor lo demanda. +[EBAL_B] +Es aquí, ¡entremos y cambiémonos de ropa! -[KM2_2] -~g~Coche entregado. +{ 8-Ball } -[KM3_A] -Cuando los problemas acechan, el tonto les da la espalda, mientras el hombre sabio los enfrenta. +[EBAL_D] +Conozco a un tipo con contactos, se llama Luigi. -[KM3_B] -El Cartel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. +[EBAL_D1] +Somos viejos amigos, así que podremos buscarte curro. Vamos a verlo. -[KM3_C] -Ahora están negociando con los jamaicanos para humillarnos aún más. +{ 8-Ball } -[KM3_D] -Están cerrando un trato en toda la ciudad. +[EBAL_E] +Venga, vamos a pasarnos por allí y te presentaré. -[KM3_F] -Llévate a uno de mis hombres, roba un coche Yardie y ve a presentar tus respetos a los colombianos. +{ 8-Ball } -[KM3_E] -Nuestro honor demanda que no dejes a nadie vivo. +[EBAL_G] +Este es el club de Luigi. Vamos a la parte de atrás, a la puerta de servicio. -[KM3_2] -~g~Ve y recoge a tu contacto. +{ ============================================================================ } +{ ================= MISSION: LUIGI'S GIRLS (LUIGI GOTERELLI) ================= } +{ ============================================================================ } -[KM3_3] -~g~¡La reunión está teniendo lugar en el estacionamiento del hospital de Rockford! +{ TITLE } -[KM3_4] -~r~¡Han escapado! +[LM1] +'LAS CHICAS DE LUIGI' -[KM3_6] -~g~¡Mátalos, mátalos a todos! +{ Premission cutscene } -[KM3_8] -~g~¡Necesitas un coche Yardie para hacer el trabajo! +{ 8-Ball } -[KM3_9] -~r~Uno de los colombianos está muerto, se acabó el trato. +[EBAL_H] +Espera, tío, que voy a hablar con Luigi. -[KM3_10] -~r~¡El contacto está muerto! +{ Mick (unused) } -[KM4_A] -Para ser verdaderamente fuerte es importante que nunca demuestres debilidad. +[EBAL_I] +El jefe os recibirá enseguida... -[KM4_C] -Ve y recolecta el dinero inmediatamente, para que podamos ingresarlo en las cuentas del casino. +{ Luigi } -[KM4_1] -¡No puedo pagarte y no lo haría aunque pudiera! +[EBAL_J] +8-Ball que ocuparse de una cosa arriba. -[KM4_9] -¡Una banda de jóvenes acaban de arrasar el local! ¡Se han llevado todo! +[EBAL_K] +Quizá puedas hacerme un favor. -[KM4_2] -No servís para nada. +[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í. -[KM4_10] -De todas maneras, ¡qué clase de Yakuza eres TÚ? +[EBAL_M] +¡Recuerda: nadie se mete con mis chicas! -[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. +[EBAL_N] +¡Así que no quites las manos del volante! -[KM4_4] -~g~¡Castiga a la banda responsable y recupera el dinero de la protección! +[EBAL_O] +Si no la cagas, puede que haya más trabajo para ti. ¡Ahora largo! -[KM4_7] -~r~¡El tendero la acaba de palmar! +{ Misty } -[KM4_5] -Donald Love desea que te dejes caer en su jardín de té para que podáis hablar. +[LM1_9] +Hola, soy Misty. -[KM4_6] -¡Aquí está todo el dinero! +{ Mission instructions } -[KM4_8] -~g~¡Maletín recolectado! +[EBAL_4] +~r~¡8-Ball ha muerto! -[KM5_A] -¡TÚ! ¡Qué adecuado que elijas este momento para enseñar tu cara culo! +[EBAL_5] +~g~¡Consigue un vehículo! -[KM5_B] -Parece que tus intentos para disuadir a los jamaicanos +[EBAL_6] +~g~¡Recoge a Misty! -[KM5_B1] -que se conviertan en chicos malos en el Cartel, ¡son totalmente inadecuados! +[LM1_2] +~g~Lleva a Misty al club de Luigi. -[KM5_C] -¡Los camellos Yardie se alinean en las calles de Liberty vendiendo paquetes de SPANK como si fueran perritos calientes! +[LM1_3] +~g~Toca el claxon para que la chica entre en el coche. -[KM5_D] -Estos cerdos del Cartel se están riendo de nosotros, ¡en mi cara! +[LM1_6] +~g~¡Vuelve al coche! -[KM5_E] -¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene una base segura! +[MISTY1] +~r~¡Misty está para el arrastre! -[KM5_F] -¡¡¡Entierra estos sacos de basura y lava tu vergüenza en ríos de la sangre de nuestros enemigos!!! +[LM1_7] +Detén el vehículo junto a Misty y déjala subir. -[KM5_3] -~r~Fallaste al matar al menos a ~1~ yardies. +{ Post-mission instructions } -[KM5_4] -~g~Felicitaciones, mataste a ~1~ yardies. +[LM1_8] +Puedes ir a ver a Luigi y buscar más trabajo o darte un paseo por Liberty City. -[KM5_5] -~g~Enhorabuena, mataste ~1~ yardies. ~1~$ EXTRA +[LM1_8A] +Si quieres ganar un dinerillo extra, siempre puedes ''coger prestado'' un taxi... -[RM1] -'SILENCIA AL SOPLÓN' +{ ====================================================================================== } +{ ================= MISSION: DON'T SPANK MA BITCH UP (LUIGI GOTERELLI) ================= } +{ ====================================================================================== } -[RM3] -'POCA EVIDENCIA' +{ TITLE } -[RM4] -'DE PESCA' +[LM2] +'NO DROGUES A MI ZORRA' -[RM5] -'PASTA DE YESO' +{ Premission cutscene } -[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. +{ Mick } -[RM1_E] -Incendia ese lugar, eso les hará salir y podrás cazarlos, asegúrate de que no hable con nadie. +[LM2_C] +Luigi dijo que... que te diera esto... -[RM1_1] -~g~Comprueba la casa de protección de testigos. +[LM2_D] +toma, toma, para ti. -[RM1_2] -~g~¡Saca a McAffrey! +{ Luigi (letter) } -[RM2_A1] -¡Eh tú, el chaval de ahí! +[LM2_A] +Hay una nueva droga en la ciudad llamada SPANK. -[RM2_A] -Un viejo colega del ejército lleva un asunto en Rockford. +[LM2_E] +Algún listillo ha estado dando esta basura a mis chicas en el puerto de Portland. -[RM2_D] -Va a necesitar algún respaldo y a cambio te dará cualquier herramienta que compres a precios de ganga. +[LM2_B] +¡Ve y dale con un bate de béisbol en su cara! -[RM2_E] -Ray se adelantó al llamar....pero pensé que serías algo más. +[LM2_F] +Luego coge su coche y repíntalo. -[RM2_F] -Bien, tres armas son mejor que una, así que hazte con lo que necesites. +[LM2_G] +¡Quiero una compensación por este insulto! -[RM2_G] -~g~¡Ve a echar un vistazo a Phil! +{ Mission instructions } -[RM2_H] -~r~¡¡Han matado a Phil!! +[LM2_1] +~g~Coge su coche y haz que cambien su pintura. -[RM2_L] -¡Hey! ¡Si hubiera estado de tu bando en Nicaragua quizás todavía conservaría mi brazo! +[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! -[RM2_N] -No te preocupes por el dinero. Ahora lárgate de aquí, yo entretendré a los polis. +[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! -[RM3_D] -Están llevando la prueba por toda la ciudad. +[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! -[RM3_E] -Vas a tener que deshacerte del coche y recoger hasta la última prueba que quede por ahí. +[LM2_3] +~g~¡Mete el coche en el garaje de Luigi! -[RM3_F] -Cuando lo tengas todo, déjalo en el coche y préndele fuego. +[LM2_4] +~g~¡Vuelve a pintar el coche! -[RM3_G] -Lo vamos a llevar mucho mejor sin este chico. +{ ================================================================================= } +{ ================= MISSION: DRIVE MISTY FOR ME (LUIGI GOTERELLI) ================= } +{ ================================================================================= } -[RM3_1] -~g~Deja la prueba en un coche y después préndele fuego. +{ TITLE } -[RM3_4] -~g~¡El Fiscal ha retirado la prueba! +[LM3] +'LLEVA A MISTY POR MÍ' -[RM3_6] -~r~¡Las fotos habrán acabado con toda posibilidad de Libertad! +{ Premission cutscene } -[RM3_7] -~g~¡Ahora préndele fuego al coche! +{ Luigi } -[RM4_A] -Creo que mi socio es una rata. +[LM3_A] +Hola, tengo que hablar contigo... Bueno, Mick, ya hablaremos. -[RM4_C] -Casi todas las noches sale a pescar con su barca cerca del faro que hay en Portland Rock. +[LM3_B] +¿Cómo te va, chico? -[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! +[LM3_C] +El hijo del Don, Joey Leone, quiere fiesta con su chica de siempre, Misty. -[RM4_1] -~g~Vete y roba una barca de la policía. +[LM3_D] +Recógela en los cerros de Hepburn, -[RM4_2] -~g~¡Vete al faro y 'liquida' al socio de Ray! +[LM3_E] +pero cuidado, ese es territorio de los Diablos. -[RM5_A] -¡Inútil de mierda! +[LM3_F] +Luego llévala rapidito hasta su taller en Trenton, -[RM5_A1] -¡Eres un absoluto imbécil! Tengo el culo a tiro y ni siquiera eres capaz de matar a una maldita mosca. +[LM3_G] +que a Joey no le gusta esperar. Recuerda, tienes un pie dentro... -[RM5_B] -¡Te he pagado una pasta para que mates al testigo y aún sigue vivo! +[LM3_H] +¡así que estate pendiente del camino y no de Misty! -[RM5_B1] -¡Y hoy va a declarar ante los Federales! +{ Mission instructions } -[RM5_C] -Le van a llevar de un momento a otro del Hospital General Carson a Rockford. +[LM3_1D] +Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. -[RM5_D] -Si se chiva, yo canto.... +[LM3_2] +~g~Lleva a Misty al local de Joey. -[RM5_E] -¡así que vete y haz el trabajo por el que se te pagó! +[LM3_4] +~g~¡Recoge a Misty! -[RM5_1] -~g~¡¡Detén la ambulancia!! +[LM3_10] +~g~¡Consigue un vehículo! -[RM5_2] -~g~¡¡Te han chafado!! +[LM3_11] +~g~Misty no irá en un autobús, ¡hazte con otro vehículo! -[RM5_3] -~g~¡Ha sido una trampa! +[LM3_1A] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. -[RM5_4] -~g~¡¡Las balas no van a atravesar ese chaleco antibalas!! +[LM3_1B] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. -[RM5_5] -~g~¡¡Ese chaleco antibalas es a prueba de fuego!! +[LM3_1C] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. -[RM5_7] -~r~¡¡Han llevado al testigo!! +{ Misty } -[RM5_8] -~g~¡¡El testigo se ha ahogado!! +[LM3_5] +Ahora trabajas para Luigi, ¿no? ¡Ya era hora de que tuviese un conductor de confianza! -[LOVE2] -'¡EXTERMINA A WAKA-GASHIRA!' +{ Postmission cutscene } -[LOVE3] -'UNA GOTA EN EL OCÉANO' +{ Misty } -[LOVE1_A] -Antes que nada, déjame que te agradezca que te hayas ocupado de ese asunto personal. +[LM3_6] +¡Joey...! -[LOVE1_F] -La gente tiende a malinterpretar las cosas últimamente. +[LM3_6A] +¿Voy a jugar con tu paquetín otra vez? -[LOVE1_D] -Están intentando sacarme más de lo pactado, pero no soy precisamente partidario de revisar los tratos. +{ Joey } -[LOVE1_E] -Un trato es un trato, así que no van a ver ni un duro mío. +[LM3_7] +Estaré contigo en un minuto, bujía mía. -[LOVE1_G] -Ve a rescatar a mi amigo, haz lo que haga falta. +[LM3_8] +Hola, soy Joey. -[LOVE1_2] -~g~Rescata al Anciano Caballero Oriental. +[LM3_9] +Luigi dijo que eras de fiar, así que vuelve más tarde, -[LOVE1_3] -~g~Lleva de vuelta al edificio de Donal Love al Anciano Caballero Oriental. +[LM3_9A] +que tendré trabajo para ti. -[LOVE1_4] -~g~El Anciano Caballero Oriental debe estar en uno de los aparcamientos.... +[LM3_9B] +¿De acuerdo? -[LOVE1_6] -~r~¡Las tripas del Anciano Caballero Oriental están esparcidas por las calles! +{ =============================================================================== } +{ ================= MISSION: PUMP-ACTION PIMP (LUIGI GOTERELLI) ================= } +{ =============================================================================== } -[LOVE1_7] -~g~Sólo se abrirá la puerta para un coche de la Banda Colombiana. +{ TITLE } -[LOVE2_A] -No hay nada como una de esas guerras de bandas pasadas de moda para hacer que bajen los precios de la vivienda, +[LM4] +'UN CHULO Y SU ESCOPETA' -[LOVE2_B] -excepto desencadenar una plaga......pero eso sería llegar demasiado lejos en este caso. +{ Premission cutscene } -[LOVE2_C] -He observado que Yakuza y los Colombianos no son precisamente buenos amigos. +{ Luigi } -[LOVE2_D] -Vamos a aprovechar las posibilidades de negocio que se presentan. +[LM4_A] +Algún Diablo de las narices ha estado vendiendo a sus putitas en mi territorio. -[LOVE2_E] -Quiero que mates a Kanji Kase, el WAKA-cuchillera de Yakuza. +[LM4_B] +Ve y resuélvelo de mi parte. -[LOVE2_F] -Kenji está asistiendo a una reunión en lo alto del aparcamiento de los almacenes de Newport. +[LM4_C] +Si necesitas un arma, ve a la puerta trasera de la tienda Ammu-Nation que está enfrente del metro. -[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. +{ ============================================================================ } +{ ================= MISSION: THE FUZZ BALL (LUIGI GOTERELLI) ================= } +{ ============================================================================ } -[LOVE2_1] -~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! +{ TITLE } -[LOVE2_2] -~g~¡Ahora ve a los ~p~almacenes de Newport~g~ y cárgate a Kenji! +[LM5] +'EL BAILE DE LA POLICÍA' -[LOVE2_3] -~r~¡Si lo haces sin un coche del Cartel te identificarán! +{ Premission cutscene } -[LOVE2_4] -~r~¡¡El Yakuza te ha identificado!! +{ Luigi } -[LOVE2_6] -~r~¡¡Has matado a todos los testigos!! +[LM5_A] +El baile de la policía se está celebrando en la sala Clásica, cerca del puente, -[LOVE3_A] -En estos días de hipocresía moral ciertos artículos pueden resultar difíciles de importar. +[LM5_B] +y parece que tienen ganas de una fiesta más ''clásica''. -[LOVE3_C] -Echará varios paquetes en el agua. +[LM5_C] +Tengo chicas haciendo la calles. -[LOVE3_D] -Asegúrate de que los recoges antes que nadie más lo haga. +[LM5_D] +Llévalas al baile, sacarán una buena tajada. -[LOVE3_1] -~g~¡Consigue una ~r~barca~g~ y sigue al ~y~avión~g~! +[LM5_E] +Saca todo el dinero que puedas a los polis antes de que se lo beban. -[LOVE4] -'GRAN LADRÓN AÉREO' +{ Mission instructions } -[LOVE5] -'SERVICIO DE ESCOLTA' +[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. -[LOVE4_A] -Gracias por hacerte con esos paquetes, pero no eran más que una trampa. +[LM5_2] +~r~¡Te has cargado a una de las chicas de Luigi! -[LOVE4_B] -Lo siento, pero a veces así son los negocios. +[LM5_3] +~g~¡Necesitas un coche! -[LOVE4_C] -Mi objetivo real se ocultaba por completo en el avión. +[LM5_4] +~g~Recoge a las chicas que trabajan en Saint Mark's. -[LOVE4_F] -Tengo sobornados a los oficiales. +[LM5_5] +~g~¡Lleva a las chicas al baile de la policía! -[LOVE4_1] -~r~¡Está aquí el Cartel Colombiano!! +[LM5_7] +~g~¡Si hay menos de cuatro chicas trabajando en el ~p~baile de la policía~g~, Luigi no estará contento! -[LOVE4_2] -~g~¡Ha desaparecido el paquete! Sigue la pista a los colombianos y recupéralo. +[LM5_8] +~g~Chicas trabajando en el baile: ~1~ -[LOVE4_3] -~g~¿Construcción Panlántica ...? +[LM5_9] +CHICAS: -[LOVE4_5] -~g~El paquete debería estar en el avión.... +{ ============================================================================== } +{ ================= MISSION: MIKE LIPS LAST LUNCH (JOEY LEONE) ================= } +{ ============================================================================== } -[LOVE4_6] -~g~¡Sube en el ascensor a lo alto de la torre! +{ TITLE } -[LOVE5_B] -Mi amigo Oriental va a necesitar una escolta mientras trata de comprobar si mi última adquisición es auténtica o no. +[JM1] +'EL ÚLTIMO ALMUERZO DE MIKE ''LABIOS'' ' -[LOVE5_1] -~g~¡Vamos! +{ Premission cutscene } -[LOVE5_2] -~g~¡Vas a necesitar un coche! +{ Misty } -[LOVE5_3] -~g~¡Sigue hasta que puedas encontrar la salida del túnel! +[JM1_A] +Jo, me aburro, ¿cuándo me la vas a meter? -[LOVE5_4] -~r~¡Protege el camión! +{ Joey } -[RM6] -'HOMBRE SEÑALADO' +[JM1_B] +Dame un momento, cariño, que tengo un asuntillo que tratar. -[RM6_A] -¿No te han seguido? Bien. +[JM1_C] +Tengo un trabajito para ti, colega. -[RM6_B] -Así de fácil, ¡no tengo dónde meterme y me estoy empezando a hundir aquí mismo! +[JM1_D] +Los hermanos Forelli me deben dinero desde hace mucho tiempo -[RM6_D] -Soy un hombre señalado, así que tengo que largarme de aquí. +[JM1_E] +y hay que enseñarles respeto. -[RM6_E] -¡Consigue que no pierda mi vuelo en el aeropuerto y haré que haya merecido la pena tu trabajo! +[JM1_F] +Labios Forelli está atiborrándose en el restaurante de Saint Mark's, -[RM6_666] -Cuida de mi Patriot a prueba de balas. Nos vemos en Miami, Ray +[JM1_G] +así que róbale el coche y llévalo al taller de bombas de 8-Ball en Harwood. -[CAT1] -'RESCATE' +[JM1_H] +Conoces a 8-Ball, ¿verdad? -[CAT2] -'EL INTERCAMBIO' +[JM1_I] +En cuanto esté cargado con una bomba, aparca el coche donde lo encontraste. -[CAT1_A] -Tengo a la preciosa María. No creo que quieras que su cara parezca como si se hubiera enfadado con el carnicero. +[JM1_J] +Luego salte y disfruta del espectáculo. -[CAT2_F] -Me he roto una uña y se me ha estropeado el peinado. Es increíble. ¡Me había costado 50 $! +[JM1_K] +Pero cuidado, no va a estar comiendo toda la vida. -[CAT2_G] -Tenía tanto miedo, pero entonces me dije a mí misma, ahora eres una gran chica. +{ Mission instructions } -[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, +[JM1_1] +~g~Lleva el coche de Forelli al taller que tiene 8-Ball al norte, tras Easy Credit Autos. -[CAT2_I] -porque su marido a vuelto a enredar por ahí y..... +[JM1_2] +~g~Vuelve a aparcar el coche frente al restaurante de Marco. -[CAT1_C] -XXXX +[JM1_3] +~g~¡Activa la bomba del coche y luego sal de ahí! -[CAT1_D] -XXXX +[JM1_4] +~g~¡Te estás cargando el coche! ¡Repáralo! -[CAT1_E] -XXXX +[JM1_5] +~g~¡La bomba del coche no está activada! -[CAT1_F] -¡Ve a donde está Catalina antes de que se acabe el tiempo! +[JM1_6] +~g~Vuelve a aparcar el coche en el sitio correcto. -[CAT1_G] -XXXX +[JM1_7] +~g~¡Cierra la puerta del coche! ¡Se dará cuenta! -[CAT1_H] -XXXX +{ 8-Ball's messages, not voiced } -[CAT1_I] -XXXX +[JM1_8A] +~y~¡Ey, pero si es mi colega! -[CAT1_J] -XXXX +[JM1_8B] +~y~El taller de bombas está automatizado. Solo tienes que meter el coche, pararlo y el taller hará el resto. -[CAT1_K] -XXXX +[JM1_8C] +~y~Ten, tu primer coche es gratis, pero los siguientes te los cobraré. -[CAT1_L] -XXXX +{ ===================================================================================== } +{ ================= MISSION: FAREWELL 'CHUNKY' LEE CHONG (JOEY LEONE) ================= } +{ ===================================================================================== } -[AS4_1] -XXXX +{ TITLE } -[CAT_MON] -~g~Todavía no tienes suficiente dinero. Necesitas 500.000 $. +[JM2] +'DESPEDIDA A LEE CHONG ''EL GORDO''' -[BITCH_D] -~g~¡María está muerta! +{ Premission cutscene } -[WEATHER] -FORZAR EL CLIMA +{ Joey } -[WEATHE2] -CLIMA NORMAL +[JM2_A] +Lee Chong ''el Gordo'' está traficando SPANK para una nueva banda de Colombia... o Colorado... O como se llame. -[8001] -¡¡Has fallado miserablemente!! +[JM2_B] +No me acuerdo. El caso es que no importa. -[1000] -ESTÁS MUERTO +[JM2_C] +Tiene un puesto de fideos en Chinatown. -[1001] -ESTÁS MUERTO +[JM2_D] +Ese cabrito ha vendido su último fideo. -[1002] -ESTÁS MUERTO +[JM2_E] +¡Lo quiero muerto! -[1003] -ESTÁS MUERTO +[JM2_F] +Si necesitas una pipa, ve a la parte de atrás del Ammu-Nation que está enfrente del metro. -[1004] -ESTÁS MUERTO +[JM2_G] +Búscate un nueve, queda claro, ¿no? -[1005] -AVERIADO +[JM2_H] +Y recuerda, ve con ojo en Chinatown: es territorio de las Tríadas. -[1006] -AVERIADO +{ =================================================================== } +{ ================= MISSION: VAN HEIST (JOEY LEONE) ================= } +{ =================================================================== } -[1007] -AVERIADO +{ TITLE } -[1008] -AVERIADO +[JM3] +'EL ROBO DE LA FURGONETA' -[1009] -AVERIADO +{ Premission cutscene } -[GA_4] -Las bombas de coche valen 1000 $ cada una +{ Joey } -[GA_5] -Tu coche ya tiene instalada una bomba. +[JM3_A] +Vamos a asaltar un furgón blindado. -[GA_6] -Apárcalo, prepáralo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL POR PATAS! +[JM3_B] +Sale de Chinatown todos los días. -[GA_7] -Arma con el ~h~botón ~k~~PED_FIREWEAPON~~w~. La bomba estallará cuando se arranque el motor. +[JM3_C] +Las balas ni siquiera abollarán el furgón, así que coge un coche y échalo de la carretera. -[GA_8] -Utiliza el detonador para activar la bomba. +[JM3_D] +Si lo zurras bien, los imbéciles de los guardias se achantarán. -[GA_9] -Ha conseguido ~1~de los 10 coches especiales +[JM3_E] +Luego llévalo al almacén de los muelles y mis chicos se encargarán desde ahí. -[GA_10] -Buen ejemplar. Aquí tienes tus ~1~$ +[JM3_F] +El furgón no estará fuera todo el día, así que no pierdas el tiempo. -[GA_11] -Las ruedas ya están listas. ¡No sirve para nada! +{ Mission instructions } -[GA_12] -Bomba armada +[JM3_1] +~g~Lleva el furgón al almacén. -[GA_13] -Entregado como un profesional. Completa la lista y conseguirás una bonificación. +[JM3_2] +~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. -[GA_14] -Todos los coches. ¡ESTUPENDO! Aquí hay algo para ti. +{ ============================================================================== } +{ ================= MISSION: CIPRIANI'S CHAUFFEUR (JOEY LEONE) ================= } +{ ============================================================================== } -[GA_15] -Espero que te guste el nuevo color. +{ TITLE } -[GA_16] -Repintarlo es adicional. +[JM4] +'EL CHÓFER DE CIPRIANI' -[GA_19] -No nos interesa ese modelo. +{ Premission cutscene } -[GA_20] -Tenemos de esos más de los que podamos ocuparnos. Lo siento, tío, no hay negocio. +{ Joey } -[CR_1] -La grúa no puede levantar este vehículo. +[JM4_A] +Sí, Toni, ya está a punto. Ahora es una delicia, ¿sabes? -[PU_MONY] -No tienes suficiente dinero. +[JM4_B] +¡Ah, aquí está el tío que te decía! -[CO_ALL] -Los tienes todos. Aquí hay algo para ti... +[JM4_C] +Bueno, este no es italiano ni tampoco mecánico, pero sabe arreglar cosas. -[PAUSED] -JUEGO EN PAUSA GAME PAUSED +[JM4_D] +Este es el capo de papá, Toni Cipriani. -[HEALTH1] -¡Lárgate de aquí! Estás completamente sano. +{ Toni } -[HEALTH2] -La salud cuesta dinero. +[JM4_E] +Sí, soy Toni Cipriani. -[HEALTH3] -Te pondré como nuevo. +{ Joey } -[HEALTH4] -Eso te va a costar 250 $. +[JM4_F] +Llévale al restaurante de Mamma en Saint Mark's, ¿va? -[FEB_STA] -Estadísticas +[JM4_G] +Oye, estoy planeando un curro que necesita un buen conductor, pásate por aquí más tarde, ¿estamos? -[FEB_BRI] -Informes +{ Mission instructions } -[FEB_CON] -Controles +[JM4_7] +~g~Lleva a Toni al restaurante de Mamma. -[FEB_AUD] -Sonido +[JM4_8] +~r~¡Han liquidado a Toni! -[FEB_DIS] -Pantalla +{ Toni, cutscene right after the premission one } -[FEB_LAN] -Idioma +[JM4_10] +Vale, chaval, llévame primero a la lavandería de Chinatown, tengo un asunto del que ocuparme. -[FEP_STA] -ESTADÍSTICAS +[JM4_11] +Las lavanderas no están pagando por su protección. -[FEP_BRI] -INFORMES +[JM4_12] +Y ojo con el coche, Joey acaba de arreglar esta chatarra. -[FEP_CON] -CONTROLES +[JM4_13] +Así que con cuidado, ¿vale? -[FEP_AUD] -SONIDO +{ Toni, when bumping the car } -[FEP_DIS] -PANTALLA +[JM4_6] +¡Mi coche! Dije que con cuidado. -[FEP_LAN] -IDIOMA +{ Toni, when reaching the laundry } -[FEF_ST1] -¿Quién es el malo? +[JM4_2] +¡Espera aquí! Deja el motor en marcha. Esta no es una visita social. -[FEF_ST2] -Cuánta destrucción has producido +[JM4_3] +¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! -[FEF_BR1] -¿Has perdido el hilo? +{ Toni, after escaping and finishing the mission } -[FEF_CO1] -¿Necesitas más control, pirado? +[JM4_4] +Las Tríadas creen que pueden meterse conmigo. ¡Las Tríadas, CONMIGO! -[FEF_CO2] -Elige la mejor configuración del mando para tu estilo de juego +[JM4_5] +Pasa más tarde y les daremos algo que lavar... ¡Su propia ropa manchada de sangre! -[FEF_SA1] -¡Mantén tu sitio en el bloque! +{ ================================================================================= } +{ ================= MISSION: DEAD SKUNK IN THE TRUNK (JOEY LEONE) ================= } +{ ================================================================================= } -[FEF_SA2] -Guarda y carga tus partidas +{ TITLE } -[FEF_AU1] -¡Pon el volumen a tope! +[JM5] +'FIAMBRE EN EL MALETERO' -[FEF_AU2] -Elige una emisora de radio y un efecto de sonido +{ Premission cutscene } -[FEF_DI1] -¡Cambia el juego! +{ Joey } -[FEF_DI2] -Personaliza el juego para tu televisión +[JM5_A] +Guapo, muy guapo... -[FEF_LA1] -¿Qué dices de los willis? +[JM5_B] +¡Justo te estaba buscando! -[FEF_LA2] -Elige la forma de hablar que prefieras +[JM5_C] +Vale, hay un coche cargado con un fiambre en el bar cercano a Callahan Point. -[FEB_PMB] -Informes de la Misión Previa: +[JM5_D] +Uno de los Forelli se las daba de mafioso y se llevó su merecido. -[FEC_NA] -No Disponible +[JM5_E] +Lleva el cuerpo a la trituradora en Harwood, ¿vale? -[FEC_CWL] -Cambiar al Arma izquierda +{ Mission instructions } -[FEC_CWR] -Cambiar al Arma izquierda +[JM5_1] +~g~¡Llévalo a la trituradora! -[FEC_LOF] -Mirar hacia delante +[JM5_2] +~g~¡Son los hermanos Forelli! -[FEC_TAR] -Objetivo +{ ===================================================================== } +{ ================= MISSION: THE GETAWAY (JOEY LEONE) ================= } +{ ===================================================================== } -[FEC_MOV] -Movimiento +{ TITLE } -[FEC_CAM] -Modos de Cámara +[JM6] +'LA HUIDA' -[FEC_PAU] -Pausa +{ Premission cutscene } -[FEC_ENV] -Entrar al vehículo +{ Joey } -[FEC_JUM] -Saltar +[JM6_A] +Vaya cochazo, ¿eh? -[FEC_ATT] -Ataque o Arma de Fuego +[JM6_B] +Bueno, escucha. Lleva un coche a la casa franca de Saint Mark's y recoge a unos colegas. -[FEC_RUN] -Correr +[JM6_C] +Van a atracar un banco y necesitan un conductor. -[FEC_FPC] -Cámara en primera persona +[JM6_D] +Di mi palabra de que eras su hombre, así que no la cagues. -[FEC_LL] -Mirar a la izquierda +[JM6_E] +Llévales al banco antes de las cinco en punto, ni un minuto después. -[FEC_LB1] -Mirar +{ Thief's dialogues } -[FEC_LB2] -detrás +[JM6_1] +Llévanos al banco de la avenida principal. -[FEC_LB] -Mirar detrás +[JM6_2] +Mantén el motor en marcha, entraremos y saldremos enseguida. -[FEC_LR] -Mirar a la derecha +[JM6_3] +¡Sácanos de aquí! -[FEC_HOR] -Bocina +[JM6_4] +¡Líbrate de la poli y llévanos a la casa franca! -[FEC_VES] -Control del vehículo +{ Mission instructions } -[FEC_RSC] -Cambiar de emisora de Radio +[JM6_5] +~g~Necesitas un vehículo de fuga, ¡idiota! -[FEC_BRA] -Freno o Marcha Atrás +[JM6_6] +~g~¡Busca un vehículo menos llamativo! -[FEC_HAB] -Freno de mano +[JM6_7] +~g~¡Necesitas a los 3 para robar el banco! -[FEC_CAW] -Arma del coche +[JM6_8] +~r~¡Has perdido a todos los ladrones! -[FEC_ACC] -Acelerar +{ ===================================================================== } +{ ================= MISSION: THE CROOK (MARTY CHONKS) ================= } +{ ===================================================================== } -[FEC_SMT] -Activar misión especial +{ TITLE } -[FEC_CCF] -Configuración: +[MEA1] +'EL CRIMINAL' -[FEC_CF1] -Ajuste1 +{ Pager message to indicate Chonks' missions are activated } -[FEC_CF2] -Ajuste2 +[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. -[FEC_CF3] -Ajuste3 +{ Premission cutscene } -[FEC_CF4] -Ajuste4 +{ Marty } -[FEC_CDP] -Pantalla del mando: +[MEA1_B] +Me llamo Chonks, Marty Chonks. -[FEC_ONF] -A Pie +[MEA1_C] +Soy el dueño de la fábrica de comestibles Bitch'n' Dog que está a la vuelta de la esquina. -[FEC_INC] -En Coche +[MEA1_D] +Tengo problemas económicos, pero, ¿y quién no? -[FEC_VIB] -Vibración: +[MEA1_E] +He quedado con el director de mi banco. -[FEA_OUT] -Salida: +[MEA1_F] +Es un chorizo que no para de inflar los intereses del préstamo para sacarme una buena tajada. -[FEA_ST] -Estéreo +[MEA1_G] +Coge mi coche, búscale y tráelo de vuelta. -[FEA_MNO] -Mono +[MEA1_H] +¡Tengo una sorpresita para ese parásito chupasangre! -[FEA_NON] -Ninguna +{ Mission instructions } -[FEA_FM0] -HEAD RADIO +[MEA1_B3] +~g~Reúnete con el director del banco. -[FEA_FM1] -DOUBLE CLEFF FM +[MEA1_B6] +~g~Lleva el coche a la trituradora para eliminar las pruebas, allí sal del coche y la grúa lo recogerá. -[FEA_FM2] -K-JAH RADIO +[MEA1_1] +~r~¡El director del banco está muerto! -[FEA_FM3] -RISE FM +[MEA1_2] +~r~¡Te dijeron que trituraras el coche! -[FEA_FM4] -LIPS 106 +[MEA1_3] +~g~¡Sal del coche! -[FEA_FM5] -GAME FM +[MEA1_4] +~r~¡Has abandonado al director del banco! -[FEA_FM6] -MSX FM +[MEA1_B5] +UNUSED -[FEA_FM7] -FLASHBACK 95.6 +{ Bank Manager, when picking him up } -[FEA_FM8] -CHATTERBOX 109 +[MEA1_B4] +Ah, te envió el Sr. Chonks, ¿verdad? Visitemos a nuestro amigo. -[FED_DBG] -Menú de Depuración +{ ======================================================================= } +{ ================= MISSION: THE THIEVES (MARTY CHONKS) ================= } +{ ======================================================================= } -[FED_RID] -Recargar IDE +{ TITLE } -[FED_RIP] -Recargar IPL +[MEA2] +'LOS LADRONES' -[FED_PAH] -Analizar pila +{ Premission cutscene } -[FED_RCD] -CCullZones::RecalculateCullZoneData +{ Marty } -[FED_DFL] -CTheScripts::DbgFlag +[MEA2_A] +Contraté a unos ladrones para que entraran en mi piso -[FED_DLS] -Activada la Luz de Depuración Blanca Grande +[MEA2_B] +y robaran cuanto pillaran para que yo pudiera reclamar a la aseguradora. -[FED_SPR] -Mostrar Grupos de Carretera Ped +[MEA2_C] +Ahora los muy cabritos me amenazan con delatarme -[FED_SCR] -Mostrar Grupos de Carretera de Coches +[MEA2_D] +si no les doy una parte. -[FED_SCZ] -Mostrar Zonas 'A escoger' +[MEA2_E] +¿Te lo puedes creer? -[FED_DSR] -Compilar las Solicitudes de Streaming +[MEA2_F] +He dejado un coche dentro de la fábrica. -[FED_SCP] -gbShowCollisionPolys +[MEA2_G] +Ve a recogerles con él en su territorio, en el barrio rojo. -[FEM_MCM] -Memory Card Menu +[MEA2_H] +Luego tráelos a la fábrica para que conozcan la opinión de Marty. -[FEM_RMC] -Registrar MemCard Uno +{ Mission instructions } -[FEM_TFM] -Probar Formato de MemCard Uno +[MEA2_B3] +~g~Reúnete con los ladrones. -[FEM_TUM] -Probar Memcard Uno SinFormato +[MEA2_B4] +~g~Llévalos a la fábrica de comestibles Bitch'n'Dog. -[FEM_CRD] -Crear Dir Raiz +[MEA2_B5] +UNUSED -[FEM_CLI] -Crear y Cargar Iconos +[MEA2_B6] +~g~Haz que repinten el coche para borrar las pruebas. -[FEM_FFF] -Llenar Primer Archivo con Necedades +[MEA2_1] +~r~¡Te dijeron que trituraras el vehículo! -[FEM_SOG] -Guardar Sólo El Juego +[MEA2_2] +~r~¡Un ladrón ha muerto! -[FEM_CES] -Comprobar Cada 0kBpara Guardar +[MEA2_3] +~g~Lleva el coche de vuelta a la fábrica. -[FEM_STG] -Guardar El Juego +[MEA2_4] +~r~¡Has dejado atrás a un ladrón! -[FEM_STS] -Guardar El Juego bajo el nombre GTA3 +{ ==================================================================== } +{ ================= MISSION: THE WIFE (MARTY CHONKS) ================= } +{ ==================================================================== } -[FEM_CPD] -Crear copia protegida del directorio Revista +{ TITLE } -[FEM_MC2] -Memory Card Menu 2 +[MEA3] +'LA MUJER' -[FEM_TS] -Probar Guardar: +{ Premission cutscene } -[FEM_TL] -Probar Guardar: +{ Marty } -[FEM_TD] -Probar Borrar: +[MEA3_A] +El negocio se irá a pique si no consigo un pastizal muy pronto. -[PL_STAT] -Estadísticas del jugador +[MEA3_B] +Mi esposa tiene un seguro de vida y ella no ha hecho más que vaciarme los bolsillos. -[PE_WAST] -Personas que has dilapilado +[MEA3_C] +He dejado un coche donde siempre. -[PE_WSOT] -Personas dilapiladas por otros +[MEA3_D] +Ve a por a mi esposa a Classic Nails y tráela a la fábrica. -[CAR_EXP] -Coches explotados +{ Mission instructions } -[TM_BUST] -Tiempos no conseguidos +[MEA3_B3] +~g~Recoge a la Sra. Chonks. -[M_WASTE] -Hombres civiles dilapilados +[MEA3_B6] +~g~Llévate el coche y tíralo al mar, así eliminaremos las pruebas. -[F_WASTE] -Mujeres civiles dilapiladas +[MEA3_1] +~r~¡La mujer está muerta! -[PIG_WST] -Polis dilapilados +[MEA3_2] +~r~¡Se suponía que debías tirar el coche al agua! -[GNG_WST] -Miembros de bandas dilapilados +[MEA3_3] +~r~¡Has dejado atrás a su mujer! -[MED_WST] -Personal médico dilapilado +[MEA3_B5] +UNUSED -[FIRE_WS] -Bomberos empleados +{ Marty's wife, when picking her up } -[DED_CRI] -Criminales dilapilado +[MEA3_B4] +¿Marty quiere verme? Bueno, pues que sea rápido, porque tengo que ir a la peluquería. -[DED_DED] -Vagos dilapilados +{ ===================================================================== } +{ ================= MISSION: HER LOVER (MARTY CHONKS) ================= } +{ ===================================================================== } -[DED_HOK] -Prostitutas dilapiladas +{ TITLE } -[HEL_DST] -Helicópteros destruidos +[MEA4] +'SU AMANTE' -[PER_COM] -Porcentaje cumplido +{ Premission cutscene } -[KGS_EXP] -Kgs de explosivos empleados +{ Marty } -[ACCURA] -Puntería +[MEA4_A] +Mierda, ¡tengo problemas! -[ELBURRO] -Mejor tiempo de Turismo en segundos +[MEA4_B] +Resulta que mi esposa salía con uno al que debo dinero. -[CAR_CRU] -Coches destrozados +[MEA4_C] +¡Se ha cabreado y ahora quiere vengarse! -[HED_EX] -Cabezas explotadas +[MEA4_D] +He aceptado verle, -[TM_DED] -Visitas al hospital +[MEA4_E] +y piensa que voy a devolverle el dinero. -[DAYSPS] -Días de juego transcurridos +[MEA4_F] +Pero creo -[MMRAIN] -mm de lluvia caídos +[MEA4_G] +¡que los perros de Liberty van a disfrutar de un nuevo sabor este mes! -[MXCARD] -Máx. dist. Salto INSANO (pies) +{ Mission instructions } -[MXCARJ] -Máx. altitud Salto INSANO (pies) +[MEA4_B3] +~g~Recoge al amante de su mujer. -[MXCARDM] -Máx. dist. Salto INSANO (metros) +[MEA4_1] +~r~¡Carlos está muerto! -[MXCARJM] -Máx. altura Salto INSANO (metros) +[MEA4_2] +~r~¡Marty Chonks ha muerto! -[MXFLIP] -Máx. vueltas Salto INSANO +[MEA4_3] +~r~¡Has abandonado a Carlos, el usurero! -[MXJUMP] -Máx. rotación Salto INSANO +{ Carlos, when picking him up } -[BSTSTU] -Mejor maniobra INSANA hasta ahora: +[MEA4_B4] +¿Marty te envía? Vale, le voy a enseñar a ese sinvergüenza el significado de la palabra negocio. -[INSTUN] -Maniobra Insana +{ Postmission cutscene } -[PRINST] -Maniobra insana perfecta +{ Marty } -[DBINST] -Maniobra insana doble +[MEA4_B5] +¡Carl, hola! Ehhh... Necesito más tiempo para conseguir tu dinero. -[DBPINS] -Maniobra insana doble perfecta +[MEA4_B7] +Pero si pasas por mi oficina... -[TRINST] -Maniobra insana triple +{ Carlos } -[PRTRST] -Maniobra insana triple perfecta +[MEA4_B6] +Ya es muy tarde, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé de tu negocio... -[QUINST] -Maniobra insana cuádruple +{ =============================================================== } +{ ================= MISSION: TURISMO (EL BURRO) ================= } +{ =============================================================== } -[PQUINS] -Maniobra insana cuádruple perfecta +{ TITLE } -[NOSTUC] -Ninguna maniobra insana completada +[DIAB1] +'TURISMO' -[NOUNIF] -Saltos Únicos completados +{ Pager message that tells the player El Burro's missions are now available } -[NOUNGM] -Total de Saltos Únicos +[DIAB1_A] +El Burro quiere ofrecerte una oportunidad. Ve al teléfono público de los cerros de Hepburn si te interesa. -[NMISON] -Misiones intentadas +{ Premission cutscene } -[NMMISP] -Misiones conseguidas +{ El Burro, portorriqueño } -[PASDRO] -Pasajeros tirados en marcha +[DIAB1_B] +Al habla El Burro, de los Diablos. -[MONTAX] -Dinero conseguido en taxi +[DIAB1_D] +Eres nuevo en Liberty, pero ya te estás ganando una reputación en las calles. -[DAYPLC] -Gasto diario en policias +[DIAB1_E] +Hay una carrera que empezará junto a la sala Clásica, cerca del puente Callahan. -[CRIMRA] -Porcentaje criminal: +[DIAB1_F] +Consíguete un buen carro y el primero que pase por todos los puntos de control se llevará el premio. -[GMSTOR] -Almacén de Juego +{ Mission instructions } -[PREBRF] -Informes Previos +[DIAB1_1] +~g~3... 2... 1... ¡ADELANTE! -[CNTLS] -Controles +[DIAB1_4] +~g~Hazte con un coche rápido y ve a la parrilla de salida. -[MUSMEN] -Música / Efectos Especiales +[DIAB1_3] +~r~No sabes ganar ni una rifa, ¡FRACASADO! -[GAMSET] -Ajustes del Juego +[DIAB1_2] +~g~Felicidades, has ganado con un tiempo increíble de ~1~ segundos. -[LANGUA] -Idioma +[DIAB1_5] +TIEMPO DE CARRERA: -[DSPLAY] -Pantalla +{ Pager message after succeeding this mission } -[DEBUGM] -Menú de Depuración +[DIAB1_C] +Se te da bien correr. Pásate por el teléfono público y puede que El Burro tenga trabajo para ti. -[QUITOP] -Salir de las Opciones +{ ============================================================================ } +{ ================= MISSION: I SCREAM, YOU SCREAM (EL BURRO) ================= } +{ ============================================================================ } -[CONTRL] -Configuración de Control +{ TITLE } -[SET1EN] -Ajuste 1. Activado +[DIAB2] +'IRA HELADA' -[SET1] -Ajuste 1. +{ Premission cutscene } -[SET2EN] -Ajuste 2. Activado +{ El Burro, portorriqueño } -[SET2] -Ajuste 2 +[DIAB2_A] +¡Empecé mi negocio de entretenimiento exótico sin nada más que lo que cabía en mis pantalones de cuero! -[SET3EN] -Ajuste 3. Activado +[DIAB2_B] +Una banda de roñosos amenazó con quitarme a mi protagonista si no les pago. -[SET3] -Ajuste 3 +[DIAB2_C] +Amenazaron al hombre equivocado, amigo. -[SET4EN] -Ajuste 4. Activado +[DIAB2_D] +Su debilidad son los helados. -[SET4] -Ajuste 4 +[DIAB2_E] +Hazte con la bomba que dejé en Harwood, -[GOBACK] -Volver +[DIAB2_F] +secuestra la camioneta del heladero mientras hace su ronda -[SOUND] -SONIDO +[DIAB2_G] +y engaña a esos idiotas con esa musiquita. -[MUSVOL] -Volumen de la Música +[DIAB2_H] +Se esconden en un almacén del muelle Atlantic. -[SFXVOL] -Volumen de los Efectos Especiales +{ Mission instructions } -[SCROPT] -OPCIONES DE PANTALLA +[DIAB2_1] +~g~Recoge el maletín en Harwood. -[CTRSCR] -Centrar Pantalla +[DIAB2_2] +~g~Encuentra un camión de helados. -[SCRFOR] -Formato de Pantalla +[DIAB2_3] +~g~Aparca el camión de helados en el muelle Atlantic. -[GMSVLQ] -JUEGO GUARDAR-CARGAR-SALIR +[DIAB2_4] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. -[GMREST] -Reiniciar Juego +[DIAB2_6] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. -[GMLOAD] -Cargar Juego +[DIAB2_7] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. -[NOGMSV] -Sólo puedes guardar desde tu escondite. +[DIAB2_5] +~g~Sal del camión y luego usa el mando a distancia para detonarlo. -[DLFILE] -Borrar Archivos de Grand Theft Auto III +{ ===================================================================== } +{ ================= MISSION: TRIAL BY FIRE (EL BURRO) ================= } +{ ===================================================================== } -[CHFILE] -ELEGIR ARCHIVO A CARGAR +{ TITLE } -[CHCDLD] -Elegir Tarjeta desde la que Cargar +[DIAB3] +'A LA HOGUERA' -[CDUNFR] -Tarjeta sin formato. +{ Premission cutscene } -[CHFIDL] -ELIGE UN ARCHIVO A BORRAR +{ El Burro, portorriqueño } -[SVCONF] -CONFIRMACIÓN DE GURDAR +[DIAB3_A] +¡Unas Tríadas insolentes robaron mi lindo carro anoche, -[SVFNAM] -El nombre de tu archivo guardado es +[DIAB3_B] +lo destrozaron y lo quemaron! -[SAVEDN] -Error. Fallo al guardar. +[DIAB3_C] +En el baúl había algunas de mis más preciadas posesiones sobre burros... -[LANGSL] -SELECCIÓN DEL IDIOMA +[DIAB3_D] +Objetos de coleccionista irremplazables, amigo. -[ENGLIS] -Inglés +[DIAB3_E] +Escondí un arma en el borde de Chinatown. -[GERMAN] -Alemán +[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. -[ITALIA] -Italiano +[DIAB3_G] +¡Arriba! -[FRENCH] -Francés +{ Mission instructions, in large text } -[SPAIN] -Español +[DIAB3_1] +MATA A 25 TRÍADAS -[RELIDE] -ReLoadIde +{ ===================================================================== } +{ ================= MISSION: BIG 'N' VEINY (EL BURRO) ================= } +{ ===================================================================== } -[RELIPE] -ReLoadIpl +{ TITLE } -[PARSHP] -Analizar Pila +[DIAB4] +'GRANDE Y VENOSO' -[DBGFON] -Activado CTheScripts::DbgFlag +{ Premission cutscene } -[DBFOFF] -Desactivado CTheScripts::DbgFlag +{ El Burro, portorriqueño } -[BGWHON] -Activada Luz Blanca Grande de Depuración +[DIAB4_A] +¡Un ladrón oportunista robó una camioneta con mi última publicación! -[BGWOFF] -Desactivada Luz Blanca Grande de Depuración +[DIAB4_B] +Pero ese idiota drogado de SPANK dejó las puertas de atrás abiertas, -[DSTRON] -Activadas Solicitudes de Depuración de Streaming +[DIAB4_C] +¡y ahora mi literatura para adultos -[DSTROFF] -Desactivadas Solicitudes de Depuración de Streaming +[DIAB4_D] +tan bellamente producida, tan gustosamente fotografiada, está siendo esparcida por toda Liberty! -[PDRGON] -Activado ShowPedRoadGroups +[DIAB4_E] +Toma la camioneta y sigue el rastro de los volúmenes 1, 2 y 3 de Donkey Does Dallas, -[PRGOFF] -Desactivado ShowPedRoadGroups +[DIAB4_F] +tomándolos por el camino. -[CRRGON] -Activado ShowCarRoadGroups +[DIAB4_G] +¡Cuando alcances a ese bandido espaciado con SPANK, chíngatelo! -[CRGOFF] -Desactivado ShowCarRoadGroups +[DIAB4_H] +Luego reparte mis revistas XXX por el barrio rojo. -[CLZOON] -Activado Mostrar Zonas a escoger +{ Mission instructions } -[CLZOOF] -Desactivado Mostrar Zonas a escoger +[DIAB4_1] +~g~Lleva la furgoneta a la parte de atrás de Revistas XXX. -[SHPLON] -gbShowCollisionPolys Sí +{ =================================================================================== } +{ ================= MISSION: TAKING OUT THE LAUNDRY (TONI CIPRIANI) ================= } +{ =================================================================================== } -[SHPLOF] -gbShowCollisionPolys No +{ TITLE } -[CULREC] -CCullZones::RecalculateCullZoneData() +[TM1] +'SACANDO LA COLADA' -[FORMM1] -FormatMemCard 1 (materialprueba) +{ Pager message that tells the player Toni's missions are available } -[UNFRM1] -UnFormatMemCard 1 (materialprueba) +[TONI_P] +¡Tengo un trabajo urgente para ti! -Toni -[GORLEV] -Nivel Gore +{ Premission cutscene } -[SICASS] -Joder de mala manera +{ Toni } -[SICSIC] -Cabrón fastidioso +[TM1_A] +Siéntate, chico, siéntate de una vez. -[SCASSL] -Seleccionado Joder de mala manera +[TM1_B] +La lavandería no quiere pagar la protección, ¿eh? -[SCSCSL] -Seleccionado Cabrón fastidioso +[TM1_C] +¿Las Tríadas creen que pueden meterse conmigo? -[PRVMEN] -Informes de Misiones Previas +[TM1_D] +¡Esos aspirantes a tipos duros van a saber lo que es ser un tipo duro! -[DOSVGM] -¿Deseas guardar el juego? +{ Toni's Mamma } -[FORMEN] -Menú de Formato +[TM1_E] +¡Eso, enséñales respeto! ¡Las Tríadas no se ríen de ninguno de mis hijos! -[MEMTST] -Pantalla MemoryCardTest +[TM1_F] +Tu padre, Dios acoja su alma, no toleraba ni media a las Tríadas en Sicilia. -[REGCAR] -Registrar MemoryCard Uno +{ Toni } -[TEFONE] -Probar Formato de MemCard Uno +[TM1_G] +Lo siento, mamá. Sí, mamá. -[TEUFON] -Probar MemCard Uno sin formato +[TM1_H] +Quiero que te cargues sus furgonetas de lavandería -[CRROOT] -CreateRootDir +[TM1_I] +y a cualquiera de las Tríadas que se cruce en tu camino. -[CRLDIC] -Crear y Cargar Iconos +[TM1_J] +8-Ball te dará lo que necesites. -[FLFSGF] -Llenar Primer Archivo Con Necedades +{ ======================================================================== } +{ ================= MISSION: THE PICK-UP (TONI CIPRIANI) ================= } +{ ======================================================================== } -[PUSAVE] -Guardar Sólo el juego +{ TITLE } -[CHEVOK] -CheckEveryOkB4Save +[TM2] +'LA ENTREGA' -[SVGMON] -SaveTheGame +{ Premission cutscene } -[CNTSAV] -No se puede guardar el juego. En una misión. +{ Toni's Mamma } -[CNCSAV] -No se puede guardar el juego. Estás en un coche +[TM2_A] +Toni ha salido a partir cabezas, o a intentarlo... -[CRMGSV] -Crear directorio de revista con protección de copia +[TM2_AA] +Nunca será tan duro como su padre. Te dejó una nota en la mesa. -[MGSVNC] -No Creado MagazineDirectory +{ Toni (letter) } -[MGSVCN] -Creado MagazineDirectory +[TM2_B] +La lavandería ya quiere pagar. ¡Buen trabajo, chico! -[YES] -Sí +[TM2_C] +Ve a por el dinero y tráelo aquí. Cuidado con las Tríadas. -[NO] -No +[TM2_D] +Puede que intenten metértela doblada, pero no te dejes. -[X] -x +[TM2_E] +¡Nadie, quiero decir nadie, se mete con Toni Cipriani! -[LAST] -Último Mensaje +{ Mission instructions } -[FEDS_XB] -Seleccionar +[TM2_1] +~g~¡Lleva el dinero a Toni! -[FEDS_ST] -Botón START - CONTINUAR +[TM2_2] +~g~¡Los dejaste tiesos a todos! -[FEST_OO] -de +[TM2_3] +~g~¡Es una trampa! ¡Liquidadlos a todos! -[FEC_TUC] -Control de Torreón +{ ========================================================================================= } +{ ================= MISSION: SALVATORE'S CALLED A MEETING (TONI CIPRIANI) ================= } +{ ========================================================================================= } -[FEC_SM3] -Activador de Misión Espacial (botón R3) +{ TITLE } -[FEC_RS3] -Cambiar de emisora de Radio (botón L3) +[TM3] +'SALVATORE HA CONVOCADO UNA REUNIÓN' -[FEC_HO3] -Bocina (botón L3) +{ Premission cutscene } -[DIAB1] -'TURISMO' +{ Toni's Mamma } -[DIAB2] -'YO GRITO, TU GRITAS' +[TM3_MA] +¡No sé dónde está! -[DIAB3] -'JUICIO POR FUEGO' +[TM3_MB] +Te juro que mi hijo a veces no sabe lo que hace. -[DIAB4] -'GRANDE Y VENOSO' +[TM3_MC] +Ahora bien, su padre era diferente. Siempre en la cumbre, pendiente de todo, valiente... -[DIAB1_A] -El burro quiere ofrecerte una oportunidad. Ve al teléfono público de Hepburn Heights si quieres más información. +{ Toni (letter) } -[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. +[TM3_A] +Don Salvatore ha convocado una reunión. -[DIAB1_1] -~g~3...2...1... ¡VAMOS VAMOS VAMOS! +[TM3_B] +Necesito que vayas a por la limusina y su hijo, Joey, a su taller. -[DIAB1_4] -~g~Hazte con un coche rápido y ve a la cuadrícula de inicio. +[TM3_C] +Luego recoge a Luigi en su club, ven a buscarme, -[DIAB1_3] -~r~No podrías ganar ni una rifa, ¡FRACASADO! +[TM3_D] +y nos iremos todos juntos a la casa del jefe. -[DIAB1_2] -~g~Felicidades, ganaste con un tiempo increíble de ~1~ segundo. +[TM3_E] +Los de las Tríadas no saben cuándo parar... -[FIRST] -~g~ Primero (or ~g~1o) +[TM3_F] +Si quieren guerra, la tendrán. -[SECOND] -~g~ Segundo (or ~g~2o) +[TM3_G] +Ponte en marcha. -[THIRD] -~g~ Tercero (or ~g~3o) +{ Mission instructions } -[FOURTH] -~g~ Cuarto (or ~g~4o) +[TM3_1] +~g~Ve al taller de Joey a por la limusina. -[DIAB2_1] -~g~ Recoge el maletín en Harwood. +[TM3_2] +~g~Recoge a Luigi. -[DIAB2_2] -~g~ Encuentra una furgoneta de helados. +[TM3_3] +~g~Ahora recoge a Toni. -[DIAB2_3] -~g~ Aparca la furgoneta de helados en Atlantic Quays. +[TM3_4] +~g~Lleva a los mafiosos a la casa de Salvatore. -[DIAB2_4] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. +[TM3_A1] +~r~¡Joey está frito! -[DIAB2_6] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. +[TM3_A2] +~r~¡Joey y Luigi han sido incinerados! -[DIAB2_7] -~g~ Pulsa el ~w~ botón ~k~~VEHICLE_HORN~~g~ para activar el jingle del helado. +[TM3_A3] +~r~¡Joey, Luigi y Toni están calcinados! -[DIAB2_5] -~g~ Sal de la furgoneta y luego usa el mando a distancia para detonar la furgoneta del helado. +{ Toni, when the Triads ambush } -[YD1] -'PELEA BLING-BLING' +[TM3_5] +~y~¡Es una emboscada de las Tríadas! -[YD2] -'JINETE CON UZI' +{ Postmission cutscene } -[YD3] -'REUNIÓN DE COCHES DE GANGSTERS' +{ Toni } -[YD4] -'LLEGÓ EL REINADO' +[TM3_H] +Buen trabajo, chaval, muy bueno. -[YD_P] -El Rey Courtney quiere hablarte. ¡¡Ve al teléfono público de Aspatria!! +[TM3_I] +Vente, te presentaré al Don. -[YD1_A] -~w~Este es el Rey Courtney +{ Salvatore } -[YD1_A1] -~w~Mi banda Yardie necesita un conductor y tú tienes reputación de ser hábil al volante. +[TM3_J] +¡Hola! ¡Luigi! -[YD1_B] -~w~Ve al basurero que hay detrás del estadio y en un coche espera a los otros candidatos. +{ Luigi } -[YD1_C] -~w~Tengo hombres vigilando los puestos de control en todo Staunton. +[TM3_K] +Mis chicas te han echado de menos, Salvatore. Hace mucho que no te vemos. -[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. +{ Salvatore } -[YD1_D1] -~w~Si ganas más puestos de control que cualquier otro conductor, podría tener algo de trabajo para ti. +[TM3_L] +Diles que en cuanto resolvamos este desafortunado incidente -[YD1_E] -~g~Preparado para una carrera! +[TM3_M] +iremos todos al club para celebrarlo, ¿vale? -[YD1_F] -~g~Te saltaste el comienzo -¡Me gusta tu estilo!! +[TM3_N] +¡Mi niño! -[YD1_G] -~r~Esto es una CARRERA DE COCHES. ¡Necesitas un COCHE, idiota! +{ Joey } -[YD1GO] -~g~VAMOS!! +[TM3_N2] +¿Cómo lo llevas, papá? -[YD1_1] -~r~1 +{ Salvatore } -[YD1_2] -~r~2 +[TM3_O] +¿Has encontrado ya una buena mujer? -[YD1_3] -~r~3 +[TM3_P] +Tu madre, que en paz descanse, se retorcería en la tumba -[YD1_BON] -¡¡1.000$!! +[TM3_Q] +si te viera sin una mujer. -[Y1_1ST] -~G~¡Llegaste el primero con ~1~ exitosos puestos de control! +{ Joey } -[Y1_2ND] -~y~Segundo con ~1~ exitosos puestos de control. ~y~Cerca, pero ¡no eres el mejor! +[TM3_R] +Lo sé, papá, estoy en ello. -[Y1_3RD] -~r~Tercero con ~1~ exitosos puestos de control. ~r~¡Creí que dijiste que eras bueno! +{ Salvatore } -[Y1_LAST] -~r~¡Fuiste el último! ~r~¡Malgastaste mi tiempo, IDIOTA! +[TM3_S] +¡Toni! ¿Cómo está tu madre? -[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! +[TM3_T] +Es una gran mujer, ¿sabes? Fuerte, ''firenze''. -[Y1_J2ND] -~r~Empatado el segundo con ~1~ exitosos puestos de control. ¡Conduces como un mono loco! +{ Toni } -[Y1JLAST] -~r~¡Empatado el último! Hablas como un conductor, pero conduces como un hablador! +[TM3_U] +Está bien, estupendamente. -[Y1_TEST] -COCHE AL AGUA!! +{ Salvatore } -[YD2_A] -~w~Necesito ver si eres capaz de hacer mi trabajo sucio. +[TM3_V] +Fantástico, fantástico. Bien, muchachos, entrad mientras yo hablo con nuestro nuevo amigo. -[YD2_A1] -~w~A ver si se puede confiar en ti. +[TM3_W] +Tienes un gran futuro por delante, hijo mío... -[YD2_B] -~w~Dos de mis chicos estarán allí en cualquier momento para llevarte de paseo, +{ ==================================================================================== } +{ ================= MISSION: TRIADS AND TRIBULATIONS (TONI CIPRIANI) ================= } +{ ==================================================================================== } -[YD2_B1] -~w~a ver si eres quien dices que eres. +{ TITLE } -[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. +[TM4] +'TRÍADAS Y TRIBULACIONES' -[YD2_CC] -~w~Toma, necesitaras una 'pieza' +{ Premission cutscene } -[YD2_D] -~w~Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te entren dudas. +{ Toni's Mamma } -[YD2_E] -~w~¡Vamos a conducir! +[TM4_A] +Ah, eres tú. Toni no está. -[YD2_F] -~r~Ha obtenido la libertad bajo fianza con nuestra pasta, ¡dispara a su culo amarillo!!! +[TM4_A2] +Pero te ha dejado una de sus cartitas de amor. -[YD2_G1] -~w~Hepburn Heights... Vamos a matar algunos asquerosos Diablos... +{ Toni } -[YD2_G2] -~w~Pero recuerda, ~r~¡No salgas de este coche!! +[TM4_B] +¡Esto es la guerra! Las Tríadas tienen una piscifactoría como tapadera. -[YD2_H] -~w~VALE, Llévanos de vuelta a territorio Yardie! VAMOS VAMOS VAMOS!!! +[TM4_C] +Casi todos sus negocios pasan por la lonja de Chinatown. -[YD2_L] -~w~¡Lo hiciste bien, Reaperman! +[TM4_D] +La lavandería todavía no ha pagado la protección. -[YD2_M] -~r~¡Ha destrozado mi coche! ¡Liquidale! +[TM4_E] +Creen que está protegida por las Tríadas, así que creo que se merecen un castigo. -[YD2_N] -~w~¡Vuelve a poner tu culo en este coche! +[TM4_F] +¡Llévate a estos chicos y elimina a los líderes de las Tríadas! -[YD3_A] -Quiero que empujes algunos coches de gangsters +[TM4_G] +Qué narices, si ves la oportunidad, cárgate también a unos cuántos de sus soldados. -[YD3_A1] -para que podamos dar el golpe en territorio enemigo. +{ Mission instructions } -[YD3_B] -Necesito un Mafia Sentinel, +[TM4_GAT] +~g~Necesitas un camión de pescado de las Tríadas para entrar. -[YD3_B1] -un Yakuza Stinger y un +{ ====================================================================== } +{ ================= MISSION: BLOW FISH (TONI CIPRIANI) ================= } +{ ====================================================================== } -[YD3_B2] -Diablo Stallion para poder dar a cualquier gangster de Liberty. +{ TITLE } -[YD3_C] -Déjales en el garaje de Newport y recuerda, +[TM5] +'LLUVIA DE PECES' -[YD3_C1] -¡¡aniquilados no nos son de utilidad !! +{ Premission cutscene } -[YD3_D] -Nivel de texto sobrante +{ Toni } -[YD3_E] -~r~¡Ya le has dado a un coche de gangsters, diablo! +[TM5_B] +Vale, ya me he hartado de esta mierda. -[YD3_F] -~r~¡Ya le has dado a un coche de gangsters Mafia! +[TM5_C] +¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! -[YD3_G] -~r~¡Ya le has dado a un coche de gangsters Yakuza! +[TM5_D] +8-Ball ha instalado una bomba en un camión de la basura. -[YD3_H] -~g~¡Coche de gangsters Diablo empujado! +[TM5_E] +Tiene un temporizador, así que si la lías no quedará nada de ti. Ve a por el camión. -[YD3_I] -~g~¡Coche de gangsters Mafia empujado! +[TM5_F] +¡Cuidado, 8-Ball dice que es muy sensible y que cualquier golpe puede hacerlo estallar! -[YD3_J] -~g~¡Coche de gangsters Yakuza empujado! +[TM5_G] +Su piscifactoría abrirá sus puertas a uno de sus camiones, así que podrás entrar sin más. -[YD3_K] -~r~¡El coche está casi destrozado!¡Haz que lo reparen! +[TM5_H] +¡Aparca entre los tanques de gas y lárgate de ahí! -[YD3_L] -~g~¡Llevalo al ~p~ garaje! +[TM5_I] +Quiero que llueva pescado. -[YD3_M] -~r~¡Lo volcaste! ¡Consigue otro! +[TM5_J] +En plan bíblico, nada de bajo presupuesto. -[YD4_A] -¡Escucha! +{ ======================================================================== } +{ ================= MISSION: CHAPERONE (SALVATORE LEONE) ================= } +{ ======================================================================== } -[YD4_A1] -Pásate por Bedford Point. +{ TITLE } -[YD4_A2] -¡Hay un cargamento en un viejo coche y lo necesito pronto! +[FM1] +'CARABINA' -[YD4_B] -CARTA: He oído que has sido un chico aplicado. Bien, yo he sido una chica aplicada. +{ Pager message, appears when Toni's missions have not been complete } -[YD4_C] -Creo que es hora de que seas testigo del poder real del ¡'SPANK'! Besos y abrazos, Catalina, xxx +[FRANGO] +~g~¡Salvatore quiere que ayudes primero a Toni a ocuparse de las Tríadas! -[YD4_D] -POSDATA: ¡¡MUERE PEEG DOG, MUERE!! +{ Premission cutscene } -[YD4_1] -¡¡Te hemos pellado necio!! +{ Salvatore } -[YD4_2] -¡¡Destruye las furgonetas de SPANK +[FM1_A] +Mis chicos y yo queremos hablar de negocios, -[HM_1] -'DINERO UZI' +[FM1_B] +así que esta tarde vas a cuidar de mi chica. -[HM_2] -'TOYMINATOR' +[FM1_C] +¡OYE, MARÍA! ¡MUEVE ESE CULO! -[HM_3] -'PREPARADO PARA ESTALLAR' +[FM1_D] +La muy idiota siempre hace lo mismo. -[HM_5] -'REDOBLE' +[FM1_E] +Y aquí está, ¡la primera y única reina de Saba! -[HOOD1_A] -Ve al teléfono público de Wichita Gardens y hablaremos de negocios. +[FM1_F] +¿Qué hacías arriba? -[HM1_A] -¡Tío, Soy D-Ice de los Red Jacks! +[FM1_G] +Fuera lo que fuera, seguro que me cuesta dinero. -[HM1_C] -Esos jovenes macarras, salen a la calle y no tienen nada más que pistolas y SPANK en sus cabezas. +{ Maria } -[HM1_3] -~g~Los 'Nines' tienen su territorio en Wichita Gardens. +[FM1_H] +Bueno, no pensarás que estoy aquí para conversar, ¿o sí? -[HM2_3] -Si golpeas las ruedas de un vehículo el RC buggy ¡se detonará! +{ Salvatore } -[HM2_4] -Si se sale fuera de cobertura el RC buggy ¡se detonará! +[FM1_I] +Métete en el coche y cierra el pico. -[HM2_5] -~r~¡Fuera de cobertura! +[FM1_J] +Llévate la limusina, pero devuélvela de una pieza, ¿me has oído? -[HM3_1] -~g~Ve al garaje pero pon atención porque si el coche se daña demasiado ¡explotará! +[FM1_K] +Y cuidado con ella, es una lianta. -[HM3_2] -~g~Lleva el coche de vuelta, tiene que estar en perfectas condiciones ¡sin daños! +{ Maria } -[HM3_3] -~g~¡Haz que reparen el coche! +[FM1_L] +¡Sí, sí, sí! Seguro que tu nuevo perrito faldero tiene todo previsto. -[HM4_D] -~g~¡Hazte con un vehículo! +[FM1_M] +¿No es fuerte y grande? -[HM4_E] -NO MAS TEXTO REQUERIDO +[FM1_N] +¡Oye, tú, vamos a ver a Chico para que nos dé unas pirulas! -[HM4_1] -~g~Dirígete al lugar donde el cargamento ha sido esparcido, necesitas conseguir 30 lingotes de oro. +[FM1_O] +Creo que está en la estación de ferrocarril del muelle de Chinatown. -[HM4_2] -~g~Recuerda, cuando el vehículo es demasiado pesado y lento ve al garaje y deja el cargamento. +{ Mission instructions } -[HM5_3] -~r~¡Te han dicho que uses sólo un bate de béisbol! +[FM1_1] +~g~¡Vuelve al Stretch! -[HM5_4] -~r~¡Tu contacto está muerto! +[FM1_2] +~g~¡Entra en el Stretch! -[MEA1] -'EL CRIMINAL' +[FM1_3] +~r~Si abandonas a María, Salvatore hará que te maten. Vuelve y recógela. -[MEA2] -'LOS LADRONES' +[FM1_4] +~g~¡Has dejado a la chica del Don tirada! ¡Vuelve al almacén y espera a María! -[MEA3] -'LA MUJER' +[FM1_5] +~g~¡Lleva a María sana y salva con Salvatore! -[MEA4] -'SU AMANTE' +[FM1_6] +~g~¡Chico no estará esperando todo el día, lleva a María al muelle! -[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. +[FM1_7] +~r~¡María está muerta! A Salvatore le va a sentar muy mal... -[MEA1_B3] -~g~Ve y reúnete con el Director del Banco. +[FM1_8] +~r~¡Te cargaste al camello de María! -[MEA1_B6] -~g~Lleva el coche a la trituradora para eliminar las evidencias, sal del coche y la grúa lo recogerá. +[FM1_P] +~g~Ese de ahí es Chico, párate cerca. -[MEA1_1] -~r~¡El director del banco está muerto! +[FM1_9] +~g~La fiesta es allí. Deja a María enfrente. -[MEA1_2] -~r~¡Te dijeron que trituraras el coche! +[FM1_10] +~g~Has abandonado a María, vuelve y recógela. -[MEA1_3] -~g~¡Sal del coche! +{ Cutscene when the player finds Chico } -[MEA1_4] -~r~Has dejado atrás al director del banco! +{ Chico, mexicano } -[MEA2_B3] -~g~Ve a encontrarte con los ladrones. +[FM1_Q] +¡Ay, mira, es mi chica favorita! -[MEA2_B4] -~g~Llévalos a la fábrica de comestibles Bitch'n'Dog +[FM1_Q1] +¿Quieres un poco de diversión? ¿Un poco de... hmmm, de SPANK? -[MEA2_B6] -~g~Haz que repinten el coche para eliminar cualquier evidencia. +{ Maria } -[MEA2_1] -~r~¡Te dijeron que trituraras el vehículo! +[FM1_R] +Hola, Chico. No, solo lo de siempre. -[MEA2_2] -~r~¡Un ladrón ha muerto! +{ Chico, mexicano } -[MEA2_4] -~r~¡Has dejado atrás a un ladrón! +[FM1_S] +Aquí tienes, señorita. -[MEA3_B3] -~g~Ve y recoge a la Sra. Chonks +[FM1_S1] +Ey, deberías echar un vistazo a la fiesta del almacén en el lado este del muelle Atlantic. -[MEA3_B6] -~g~Llévate el coche y tíralo al mar, así eliminaremos cualquier evidencia. +{ Maria } -[MEA3_1] -~r~¡La mujer está muerta! +[FM1_T] +Gracias, Chico, nos vemos. -[MEA3_2] -~r~¡Se suponía que ibas a tirar el vehículo al agua! +{ Chico, mexicano } -[MEA3_3] -~r~¡Has dejado atrás a su mujer! +[FM1_U] +Gracias y disfruta. Es buen material. -[MEA4_B3] -~g~Recoge al amante de su mujer. +{ Maria } -[MEA4_B6] -Es demasiado tarde para eso, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé del negocio... +[FM1_V] +¡Venga, tú, vamos a ver esa fiesta! -[MEA4_1] -~r~¡Carlos está muerto! +{ Cutscene when the player takes Maria to the party } -[MEA4_3] -~r~¡Has dejado atrás a Carlos el prestamista! +{ Maria } -[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~. +[FM1_W] +Oye, tú, espera aquí y quédate pendiente del coche mientras yo voy a menear el esqueleto, ¿vale? -[LOVE6_1] -~g~¡Ahora llévate a los policías lejos del almacén! +{ Police dispatcher } -[LOVE6_2] -~r~¡No conseguiste llevar lejos a la policía! +[FM1_SS] +~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: asistan redada de narcóticos en el muelle Atlantic. -[RM4_3] -¡El socio de Ray ha escapado! +{ Warehouse's guard } -[RM6_C] -La CIA parece tener intereses creados con el SPANK +[FM1_TT] +¡UNA REDADA! -[RM6_C1] -y a ellos no les gusta que nos metamos con el Cartel. +{ Maria } -[C_PASS] -¡AMENAZA ELIMINADA! +[FM1_X] +¡Vale, tú, salgamos de aquí! ¡Uaaah! -[CTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilante. +{ Cutscene when the player takes Maria back to Salvatore's home } -[CTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o no misiones Vigilante. +{ Maria } -[COPCART] -~g~Tienes ~1~ segundos para retornar a un vehículo de la policía antes de que termine la misión. +[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. -[C_FAIL] -¡Misión Vigilante terminada! +[FM1_AA] +Bueno, será mejor que me vaya. Espero que nos veamos pronto. -[C_CANC] -~r~¡Misión Vigilante cancelada! +{ ================================================================================ } +{ ================= MISSION: CUTTING THE GRASS (SALVATORE LEONE) ================= } +{ ================================================================================ } -[C_ESCP] -~r~¡El sospechoso ha escapado! +{ TITLE } -[C_TIME] -~r~¡Tu trabajo como defensor de la ley ha terminado! +[FM2] +'CORTANDO LA HIERBA' -[C_VIGIL] -¡¡BONO VIGILANTE!! +{ Premission cutscene } -[A_FAIL2] -~r~¡Tu falta de urgencia ha sido fatal para el paciente! +{ Salvatore } -[A_FAIL3] -~r~¡¡El paciente está muerto!! +[FM2_J] +Déjanos a solas un momento. -[A_PASS] -¡Rescatado! +[FM2_A] +El cártel colombiano fabrica SPANK en Liberty, -[F_FAIL2] -~r~¡Llegas demasiado tarde! +[FM2_K] +pero no sabemos dónde y parece como si supieran qué vamos a hacer antes de que lo pensemos. -[A_COMP2] -¡Nunca te cansarás! +[FM2_B] +¡Tenemos a un chivato! -[RM2_M] -Si necesitas un poco de pólvora pasa por aquí y coge lo que necesites de las taquillas. +[FM2_L] +Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. -[HEAL_A] -Tu ~h~salud ~w~ está marcada en naraja en la parte superior derecha de la pantalla. +[FM2_M] +Ha estado gastando más dinero del que gana. -[YD1_CNT] -¡~1~ de 15! +[FM2_C] +No está ni chuleando ni traficando, así que estará cantando. -[FM1_9] -~g~Esa de allí es la fiesta, deja a María enfrente. +[FM2_N] +Suele ir del trabajo a casa en taxi, así que síguelo. -[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. +[FM2_O] +Y si nos está vendiendo... mátalo. -[FM1_AA] -~w~Oh, será mejor que me vaya. Espero que nos veamos pronto. +{ Mission instructions } -[NOCONTE] -Por favor vuelve a conectar el mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) al puerto de mando 1 para continuar. +[FM2_1] +~g~¡Ahí está Curly Bob! -[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). +[FM2_2] +~g~¡Curly ha salido del club, síguelo! -[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). +[FM2_5] +~g~Llévale al puerto de Portland. -[WRONGCD] -Disco incorrecto. Por favor inserta el disco correcto. +[FM2_6] +~r~¡Curly no se meterá en un taxi cascado! -[NOCD] -La bandeja del disco está vacía. Por favor inserta un disco. +[FM2_7] +~r~¡Curly se ha asustado! ¡Han cancelado la reunión! -[OPENCD] -La bandeja del disco está abierta. Por favor ciera la bandeja de disco. +[FM2_8] +~g~¡Elimina a Curly Bob! -[CDERROR] -Error al leer el DVD de Grand Theft Auto III +[FM2_9] +~r~¡Curly Bob la ha espichado! -[RESTART] -Empezando una juego nuevo +[FM2_10] +~r~¡Curly se ha largado! -[GA_3] -¡No hay más freebies. 1000$ para repintar! +[FM2_11] +~g~Aparca enfrente del club de Luigi; Curly Bob saldrá pronto. -[GA_1] -¡Uauhh! ¡No toco nada TAN caliente! +[FM2_12] +~r~¡Te ha dado esquinazo! -[GA_1A] -Regresa cuando no estés tan ocupado... +[FM2_14] +~r~¡Te acercaste demasiado y asustaste a Curly! -[S_PROM2] -El garaje de al lado puede alojar un vehículo cuando tú guardas tu partida. +[FM2_15] +~g~No te acerques mucho, ¡o Curly sospechará! -[STOCK] -mercancía agotada +[FM2_16] +ASUSTÓMETRO: -[FM1_O] -~w~Creo que está en la estación de ferrocarril del muelle de Chinatown. +{ Cutscene that appears when successfully following Curly Bob } -[EBAL_B] -Este es el lugar, justo aquí, dejemos la calle y ¡encontremos un cambio de ropas! +{ Miguel, colombiano } -[EBAL_G] -Este es el club de Luigi. Vamos por la parte de atrás y usemos la puerta de servicio. +[FM2_F] +Aquí viene nuestro amiguito. El señor Bocazas en persona. -[AM4_3] -¡Tú debes de ser el nuevo chico de los recados de Asuka! +{ Catalina, colombiana } -[AM4_4] -¿Tienes el dinero? ¿Está todo aquí? +[FM2_G] +¿Te han seguido? Ya sabes que esto es nuestro secretito. -[AM4_5] -Ya sé lo que estás pensando, otro policía corrupto. +{ Curly Bob } -[AM4_6] -Bueno, éste es un mundo corrupto. +[FM2_H] +No, no, no me han seguido. ¿Tienes lo mío? -[AM4_7] -Sólo porque perdí un par de socios, esos mamones de asuntos internos han empezado a meter las narices. +{ Catalina, colombiana } -[AM4_8] -Cuento con que pueden pillarme. +[FM2_I] +Toma tu SPANK, soplón, ahora habla. -[AM4_9] -Bien, esta ciudad es una gran alcantarilla. +{ Curly Bob } -[AM4_10] -Pero voy a necesitar un poco de ayuda fuera del sindicato. +[FM2_P] +Vale, los Leone libran una guerra en dos frentes. -[AM4_11] -Y si estás interesado ya sabes dónde encontrarme. +[FM2_Q] +Tienen una guerra territorial con las Tríadas y no parece que ninguno se vaya a rendir. -[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. +[FM2_R] +Mientras tanto, Joey Leone ha cabreado a los Forelli. -[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. +[FM2_S] +Cada día pierden más hombres e influencia. -[KM2_1] -~g~Repara el coche, tiene que estar en perfecto estado. +[FM2_T] +Salvatore se está volviendo peligroso y paranoico. Sospecha de todos y de todo. -[LM3_6] -Joey... +{ Catalina, colombiana } -[LM3_6A] -¿Voy a jugar contigo otra vez? +[FM2_U] +Con lo leales que son algunos, ¿de qué tendría que preocuparse? -[LM3_9A] -debe de haber algo de trabajo para ti. +{ ================================================================================== } +{ ================= MISSION: BOMB DA BASE: ACT I (SALVATORE LEONE) ================= } +{ ================================================================================== } -[LM3_9B] -¿De acuerdo? +{ TITLE } -[AWAY2] -~r~Se escaparon. +[FM21] +'BASE FUERA: ACTO I' -[AWAY] -~r~¡Se ha pirado de aquí! +{ Premission cutscene } -[JM6_1] -Ve al banco de la avenida principal. +{ Salvatore } -[GA_6B] -Aparca, selecciónalo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y ¡ADELANTE! +[FM3_A] +Tenemos que despachar a esos puñeteros colombianos, -[GA_7B] -Armar con ~h~botón ~k~~PED_FIREWEAPON~~w~. La bomba explotará cuando el motor sea arrancado. +[FM3_B] +pero mientras estemos en guerra con las Tríadas, no tendremos la fuerza necesaria. -[BAT1] -~g~¡Coge el bate! +[FM3_C] +El cártel tiene fondos ilimitados gracias a esa mierda del SPANK. -[EBAL_O] -Si no estropeas esto, puede que haya más trabajo para ti. Ahora ¡vete de aquí! +[FM3_D] +Si les atacamos abiertamente, nos harán picadillo. -[HELP9_B] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~ el rifle del francotirador. +[FM3_E] +Estarán fabricando el SPANK en ese barco grande al que te llevó Curly. -[HELP9_C] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ disparar ~w~ el rifle del francotirador. +[FM3_F] +Así que tenemos que actuar con cuidado, o mejor dicho, tú tienes que hacerlo. -[JM6_8] -~r~¡Has perdido a todos los ladrones! +[FM3_G] +Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal para mí, Salvatore Leone. -[COLT_IN] -¡La pistola está ahora en el almacén de Munición! +[FM3_H] +Si haces esto por mí, serás como de la familia. Todo lo que quieras. -[TAXI2] -~r~¡Se te acabó el tiempo! +[FM3_I] +Ve a ver a 8-Ball, necesitarás su ayuda para volar ese barco. -[TAXI3] -~r~¡Tu pasajero se marchó aterrorizado! +{ =================================================================================== } +{ ================= MISSION: BOMB DA BASE: ACT II (SALVATORE LEONE) ================= } +{ =================================================================================== } -[TAXI7] -~r~Tu coche está destrozado, haz que lo reparen. +{ TITLE } -[TAXI4] -¡Tarifa completa! +[FM3] +'BASE FUERA: ACTO II' -[TAXI5] -¡¡DE VELOCIDAD!! +{ Premission cutscene, when not having 100.000 $ } -[TAXI6] -Misión de taxi terminada +{ 8-Ball } -[FRANGO] -~g~¡Salvatore quiere que ayudes a Toni a tratar con los Triad primero! +[FM3_8A] +¡Hombre, colega! Salvatore me avisó, -[PAGEB12] -Policía Bribe entregado en el escondite +[FM3_8B] +pero este trabajo va a necesitar muchos fuegos artificiales. -[PAGEB13] -Salud entregada en el escondite +[FM3_8C] +Necesitaré 100.000 $ para cubrir gastos, -[PAGEB14] -Adrenalina entregada en el escondite +[FM3_8D] +pero ya sabes que conmigo valdrá la pena. -[KM1_4] -~g~¡Necesitas un coche de policía para hacer el trabajo! +[FM3_CC] +Regresa cuando tengas el dinero. -[CAT1_B] -trae 500.000 a la Villa en Cedar Grove. +{ Premission cutscene, when having 100.000 $ } -[JM2_C] -Tiene un puesto de fideos en China Town. +{ 8-Ball } -[RM6_1] -Aquí está la llave de la cerradura. +[FM3_8E] +Venga, ¡vamos allá! -[RM6_2] -Encontrarás algo de dinero en metálico y 'suministros' que he almacenado en caso de que las cosas se pongan feas. +[FM3_8F] +Puedo reventar el barco, pero aún no puedo usar una pipa con estas manos. -[RM6_3] -Nos vemos pronto. +[FM3_8G] +¡Toma, este fusil te ayudará a volar unas cuántas cabezas! -[FE_INIP] -Iniciando y cargando el Menú de Pausa... Por favor espera. +{ 8-Ball, when reaching the boat area } -[FESZ_CA] -Cancelar +[FM3_8I] +Encuentra una posición elevada. Entraré cuando dispares el primer tiro. -[FESZ_QU] -Abandonar +{ Mission instructions } -[FESZ_L1] -¡Partida guardada con éxito! +[FM3_4] +~g~¡Para el coche y deja que 8-Ball salga! -[FESZ_L2] -Tu nombre guardado es: +[FM3_7] +~r~¡8-Ball ha pasado a mejor vida! -[FESZ_OK] -ACEPTAR +[FM3_8] +~r~¡Los guardias han sido alertados! -[FES_NGA] -Partida nueva +{ ============================================================================ } +{ ================= MISSION: LAST REQUESTS (SALVATORE LEONE) ================= } +{ ============================================================================ } -[FES_CAN] -Cancelar +{ TITLE } -[FESZ_QL] -Todo progreso en tu partida actual no guardado será perdido. ¿Proceder con la carga? +[FM4] +'ÚLTIMA VOLUNTAD' -[FESZ_QD] -¿Quieres borrar esta partida guardada? +{ Premission cutscene } -[FESZ_QO] -¿Quieres sobreescribir este partida guardado? +{ Salvatore } -[FESZ_QR] -¿Estás seguro de que quieres empezar una nueva partida? Todo progreso desde la última partida guardada será perdido. ¿Proceder? +[FM4_A] +¡Mi socio favorito! -[FESZ_QS] -¿QUIERES GUARDAR? +[FM4_B] +Estoy orgulloso de ti, hijo, pusiste finos a esos sudacas. -[SLONFP] -Puerto 1. Archivo protegido. +[FM4_C] +Tengo un trabajito más para ti antes de que podamos celebrarlo. -[T4X4_1] -'LUGAR DE JUEGOS DEL PATRIOTA' +[FM4_D] +Hay un coche a la vuelta del edificio del club de Luigi. -[T4X4_2] -'UN PASEO POR EL PARQUE' +[FM4_E] +El interior está pringado de sesos. -[T4X4_3] -'AGARRADO!' +[FM4_F] +Tuvimos que ayudar a un tipo a que se decidiera y fue un poco... sucio. -[MM_1] -'DISTURBIO DE DIFERENTES NIVELES' +[FM4_H] +Llévalo a la trituradora antes de que lo encuentre la pasma. -[T4X4_1A] -~g~Tienes ~y~5 minutos ~g~ para conseguir ~y~ 15~g~ puestos de control. ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN +{ Pager message, appears right after getting into the target car } -[T4X4_1B] -¡~1~ de 15! +[FM4_1] +Soy María. ¡El coche es una trampa! Estoy en el lado sur del puente Callahan. -[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~. +{ Cutscene after reaching Maria } -[T4X4_2A] -¡¡~g~Tienes ~y~2 minutos ~g~ para conseguir ~y~12~g~ puestos de control!! ~g~Puedes conseguirlos en ~y~ CUALQUIER ORDEN. +{ Maria } -[T4X4_2B] -¡~1~ de 12! +[FM4_2] +Mira, Salvatore cree que se la estamos jugando, -[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~ +[FM4_3] +así que te vendió al cártel para llegar a un trato. -[T4X4_3A] -~g~Tienes ~y~5 minutos ~g~ para conseguir ~y~20~g~ puestos de control. ~g~Puedes conseguirlos en ~y~CUALQUIER ORDEN. +[FM4_4] +No podía permitírselo, o sea, lo peor es... -[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~. +[FM4_4B] +que yo tengo la culpa, porque le dije que somos pareja. -[T4X4_3C] -¡~1~ de 20! +[FM4_5] +¡No me preguntes por qué, no lo sé! -[T4X4_F] -¡~r~Saliste bajo fianza! ¿Demasiado duro para ti? +[FM4_6] +Mira, la mafia te quiere muerto y yo también tengo que salir de aquí. -[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. +[FM4_6B] +¡He visto demasiados asesinatos, demasiada sangre! -[MM_1_B] -¡~1~ de 20! +[FM4_7] +Es una amiga mía, ¿vale?, una vieja amiga... Es Asuka, es de fiar. -[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. +{ Asuka } -[FM2_14] -~r~¡Estuviste muy cerca y asustaste a Curly! +[FM4_8] +Vamos, dejémonos de discursos. -[FM2_15] -~g~No te acerques demasiado o Curly ¡sospechará algo! +[FM4_9] +Mejor nos vamos antes de que haya más italianos histéricos con intenciones menos amistosas. -[UPSIDE] -~r~¡Giraste las ruedas! +{ Postmission cutscene } -[FM2_16] -ASUSTOMETRO: +{ Maria } -[LM3_11] -~g~Misty no irá en el autobús,¡hazte con otro vehículo! +[LRQC_1] +Asuka y yo tenemos que hablar... -[LANDSTK] -Landstalker +[LRQC_2] +¿Por qué no te das una vuelta? -[IDAHO] -Idaho +{ Asuka } -[STINGER] -Stinger +[LRQC_3] +Necesitarás un escondite. -[LINERUN] -Linerunner +[LRQC_4] +Hay un almacén en la orilla de Belleville que podría servirte. -[PEREN] -Perennial +[LRQC_5] +Regresa a mi apartamento cuando estés listo -[SENTINL] -Sentinel +[LRQC_6] +y podremos tener una charla. -[PATRIOT] -Patriot +{ ========================================================================================== } +{ ================= MISSION: SAYONARA SALVATORE (ASUKA KASEN, FIRST BATCH) ================= } +{ ========================================================================================== } -[FIRETRK] -Coche de bomberos +{ TITLE } -[TRASHM] -Trashmaster +[AM1] +'SAYONARA, SALVATORE' -[STRETCH] -Stretch +{ Premission cutscene } -[MANANA] -Manana +{ Asuka } -[INFERNS] -Infernus +[AM1_A] +Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, -[BLISTA] -Blista +[AM1_B] +sea de negocios u otra. Pongamos las cartas sobre la mesa. -[PONY] -Pony +[AM1_C] +Soy yakuza y sé que trabajaste para la familia de Salvatore Leone. -[MULE] -Mule +[AM1_D] +Puedo darte trabajo en nuestra organización, -[CHEETAH] -Cheetah +[AM1_E] +pero primero debes demostrarme que has cortado todos tus lazos con la mafia. -[AMBULAN] -Ambulancia +{ Alternative subtitles that appear depending if the hour is single-digit or double digit, to make them uniform } -[FBICAR] -F.B.I. +[AM1_F] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (~1~:~1~) -[MOONBM] -Moonbeam +[AM1_K] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (0~1~:~1~) -[ESPERAN] -Esperanto +[AM1_G] +Asegúrate de que no salga con vida. -[TAXI] -Taxi +[AM1_H] +Mientras tanto María y yo nos pondremos al día. -[KURUMA] -Kuruma +{ Maria } -[BOBCAT] -Bobcat +[AM1_I] +Uy, Asuka, tienes un masajeador... -[WHOOPEE] -Mr Whoopee +{ Asuka } -[BFINJC] -Inyección BF +[AM1_J] +Eso no es un masajeador. -[POLICAR] -Policía +{ Mission instructions } -[ENFORCR] -Enforcer +[AM1_1] +~g~¡Salvatore está saliendo del club de Luigi! -[SECURI] -Securicar +[AM1_2] +~r~¡Te han descubierto! -[BANSHEE] -Banshee +[AM1_3] +~r~¡Has perdido a Salvatore! -[PREDATR] -Predator +[AM1_4] +~r~Muy bonito, ¡has asustado al objetivo! ¿Y te consideras un asesino? -[BUS] -Bus +[AM1_5] +~g~Ve al barrio rojo y espera a que Salvatore salga del club. -[RHINO] -Rhino +[AM1_6] +~g~Si te dejas ver por el club de Luigi, ¡la mafia te descubrirá! -[BARRCKS] -Barracas OL +[AM1_7] +~r~Salvatore está en su casita, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar ''Chacal''! -[TRAIN] -Tren +[AM1_8] +~g~Salvatore saldrá del club de Luigi sobre las ~1~:~1~. -[HELI] -Helicóptero +[AM1_10] +~g~Salvatore saldrá del club de Luigi sobre las 0~1~:~1~. -[DODO] -Dodo +[AM1_9] +~r~¡Salvatore ha vuelto a meterse en el club de Luigi! -[COACH] -Coach +{ ========================================================================================== } +{ ================= MISSION: UNDER SURVEILLANCE (ASUKA KASEN, FIRST BATCH) ================= } +{ ========================================================================================== } -[CABBIE] -Cabbie +{ TITLE } -[STALION] -Stallion +[AM2] +'BAJO VIGILANCIA' -[RUMPO] -Rumpo +{ Premission cutscene } -[RCBANDT] -Bandido RC +{ Asuka } -[BELLYUP] -Triad +[AM2_A] +La muerte de Salvatore es una placentera noticia, -[MRWONGS] -Mr Wongs +[AM2_A2] +eres un asesino eficaz. Eso me gusta en un hombre. -[MAFIACR] -Mafia +[AM2_B] +Este es mi hermano Kenji. -[YARDICR] -Yardie +{ Kenji } -[YAKUZCR] -Yakuza +[AM2_C] +Asuka tiene un trabajito para ti, pero cuando acabes, pásate por mi casino y podremos hablar. -[DIABLCR] -Diablo +{ Asuka } -[COLOMCR] -Cartel +[AM2_D] +Típico de Kenji, siempre está detrás de mis juguetes. -[HOODSCR] -Hoods +{ The voiced dialogue doesn't match the English subtitles for the following strings } -[AEROPL] -Avioneta +[AM2_E] +Mi contacto en la policía me dice que el FBI ha montado un operativo de vigilancia -[SPEEDER] -Veloz +[AM2_E2] +en varios puntos de la ciudad. -[REEFER] -Chaquetón +[AM2_F] +No tenemos tiempo para contactar con nadie y evitar que nos incriminen. -[PANLANT] -Panlantic +[AM2_G] +Liquida a esos polis espías, pero cuidado: tendrán apoyo. -[FLATBED] -Flatbed +{ Mission instructions } -[YANKEE] -Yankee +[AM2_4] +~g~¡Has irrumpido como un elefante en una cacharrería! -[BORGNIN] -Borgnine +{ ======================================================================================= } +{ ================= MISSION: PAPARAZZI PURGE (ASUKA KASEN, FIRST BATCH) ================= } +{ ======================================================================================= } -[TOYZ] -TOYZ +{ TITLE } -[FEST_DF] -Distancia recorrida a pié (millas) +[AM3] +'PURGA DE PAPARAZZIS' -[FEST_DC] -Distancia recorrida en coche (millas) +{ Premission cutscene } -[FESTDFM] -Distancia recorrida a pié (m) +{ Asuka (letter) } -[FESTDCM] -Distancia recorrida en coche (m) +[AM3_A] +Un periodista ha estado husmeando por aquí. -[FEST_R1] -Área de juego Patriota en segundos +[AM3_B] +María y yo nos ido de vacaciones juntas hasta que puedas librarte de ese mirón pervertido. -[FEST_R2] -Un paseo por el Parque en segundos +[AM3_C] +Ahora mismo estará probablemente en la bahía. ¡Roba una lancha de la policía y hunde su carrera! -[FEST_R3] -¡Agarrado! en segundos +{ ======================================================================================= } +{ ================= MISSION: PAY DAY FOR RAY (ASUKA KASEN, FIRST BATCH) ================= } +{ ======================================================================================= } -[FEST_RM] -Disturbio en el multiniveles en segundos +{ TITLE } -[FEST_LS] -Gente salvada en una ambulancia +[AM4] +'LA PAGA DE RAY' -[FEST_CC] -Criminales matados en Misión Vigilante +{ Premission cutscene } -[FEST_FE] -Total de fuegos extinguidos +{ Asuka } -[FEST_LF] -Vuelo más largo en Dodo +[AM4_A] +¡Si es guapo manitas! -[FEST_BD] -Mejor idoneo para desconectar la bomba +[AM4_B] +María está un poquito liada, pero le diré que has venido. -[FEST_RP] -Rampas pasadas +{ Maria } -[FEST_MP] -Misiones pasada +[AM4_C] +¿Quién es, Asuka? Sé que he sido muy traviesa, ¡pero necesito mear! ¿Vale? -[FEST_BB] -Pelea bling-bling: +{ Asuka } -[FEST_H0] -Máximos puestos de control +[AM4_D] +Es hora de que conozcas a nuestro espía en la policía. -[FEST_GC] -Total de Coches de gangsters: +[AM4_E] +Aquí está su pago por el último trabajito que hizo para nosotros. -[FEST_H1] -Destrucción Diablo +[AM4_F] +Él es comprensiblemente cauteloso. -[FEST_H2] -Masacre de Mafia +[AM4_G] +Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. -[FEST_H3] -Calamidad en el Casino +{ Ray, on each payphone } -[FEST_H4] -Destructor Rumpo +[AM4_1A] +Ve a la cabina al oeste del Parque Belleville. -[USJI1] -TEXTO NO MAS REQUERIDO +[AM4_1B] +Ve a la cabina del Campus de Liberty. -[USJI2] -TEXTO NO MAS REQUERIDO +[AM4_1C] +Ve a la cabina al sur del Parque Belleville. -[USJI3] -TEXTO NO MAS REQUERIDO +[AM4_1D] +Ven a verme a los baños públicos del parque. -[USJ] -¡BONO DE ACROBACIA UNICA! +{ Postmission cutscene } -[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$ +{ Ray } -[HM1_1] -~g~Congela 20 Purpura Nines en 2 minutos 30 segundos. +[AM4_3] +¡Tú debes de ser el nuevo chico de los recados de Asuka! -[KM1_8A] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ activar la bomba, ~w~ recuerda apartarte del camino. +[AM4_4] +¿Tienes el dinero? ¿Está todo? -[KM1_8D] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~ activar la bomba, ~w~ recuerda apártarte del camino. +[AM4_5] +Ya sé lo que estás pensando, otro policía corrupto. -[KM1_12] -~g~¡Llévalo al dojo pero deshazte primero de los policías! +[AM4_6] +Bueno, éste es un mundo corrupto. -[RATNG1] -Carterista +[AM4_7] +Pierdo a un par de socios y esos idiotas de asuntos internos empiezan a meter las narices. -[RATNG2] -Querido +[AM4_8] +¡Y seguro que les llega mi olor! -[RATNG3] -Ladrón +[AM4_9] +¡Pues esta ciudad es una gran alcantarilla! -[RATNG4] -Chorizo +[AM4_10] +Pero voy a necesitar un ayudita ajena al cuerpo. -[RATNG5] -Goon +[AM4_11] +Si estás interesado, ya sabes dónde encontrarme. -[RATNG6] -Hombre sobre ruedas +{ ======================================================================================== } +{ ================= MISSION: TWO-FACED TANNER (ASUKA KASEN, FIRST BATCH) ================= } +{ ======================================================================================== } -[RATNG7] -Músculos de alquiler +{ TITLE } -[RATNG8] -Reparador +[AM5] +'TANNER EL TRAIDOR' -[RATNG9] -Asociado +{ Premission cutscene } -[RATNG10] -Limpiador +{ Asuka (letter) } -[RATNG11] -Asesino +[AM5_A] +María y yo hemos ido de compras. -[RATNG12] -Hombre diestro +[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! -[RATNG13] -Ejecutor +[AM5_C] +Fuera de su coche no sabe hacer casi nada, así que le hemos puesto un localizador. -[RATNG14] -Capo +[AM5_D] +¡Haz que sufra! -[RATNG15] -Jefe +{ Mission instructions } -[1010] -~r~Tu vehículo está volcado +[AM5_1] +¡Tanner te ha pillado! -[1011] -~r~Tu vehículo está volcado +{ ========================================================================= } +{ ================= MISSION: KANBU BUST-OUT (KENJI KASEN) ================= } +{ ========================================================================= } -[1012] -~r~Tu vehículo está volcado +{ TITLE } -[1013] -~r~Tu vehículo está volcado +[KM1] +'LA FUGA DEL KANBU' -[1014] -~r~Tu vehículo está volcado +{ Premission cutscene } -[JM4_10] -VALE, Chaval. Llévame a la lavandería de Chinatown primero, tengo un negocio del que ocuparme. +{ Kenji } -[JM4_11] -Esas mujeres que lavan no están recibiendo su dinero de protección. +[KM1_A] +Mi hermana te tiene en gran estima, -[JM4_12] -Y vigila el coche, Joey acaba de arreglar ese montón de basura +[KM1_E] +pero yo debo convencerme de que un gaijin puede ofrecerme algo más que desilusiones. -[JM4_13] -Entonces no me vengas con cuentos, ¿VALE? +[KM1_B] +Tal vez puedas ayudar con una situación que me tiene en desventaja. -[KM4_11] -~g~¡Llévate el dinero de vuelta al casino! +[KM1_F] +Por supuesto, el fracaso conllevará una desgracia. -[FEF_BR2] -Encuéntralo de nuevo leyendo cualquier informe de misión conseguido hasta la fecha. +[KM1_C] +Un kanbu, o jefe de la yakuza, está bajo custodia a la espera de juicio. -[TRAIN_1] -Estación Kurowski +[KM1_G] +Es un miembro importante de la familia. -[TRAIN_2] -Estación Rothwell +[KM1_H] +Libéralo y llévatelo al dojo de Bedford Point. -[TRAIN_3] -Estación Baillie +{ Pager message that appears after completing this mission } -[SUBWAY1] -Estación Portland +[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. -[SUBWAY2] -Estación Rockford +{ Mission instructions } -[SUBWAY3] -Estación Staunton South +[KM1_1] +~g~¡Roba un coche de la policía! -[SUBWAY4] -Terminal Shoreside +[KM1_2] +~g~¡Instala una bomba en el coche! -[MEA4_2] -~r~¡Marty Chonks está muerta! +[KM1_3] +~g~Ahora llévalo al dojo de la yakuza. -[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. +[KM1_4] +~g~¡Necesitas un coche de policía para hacer el trabajo! -[JM4_A] -Sí, lo sé Toni, la he puesto a tono. Ella está a punto, ¿sabes lo que de digo? +[KM1_5] +~g~Ahora ve a la comisaría. -[JM4_5] -Pasa más tarde y les daremos algo para que lave, ¡sus propias ropas manchadas de sangre! +[KM1_6] +~g~¡Pon una bomba en el coche! -[AMMU_A] -Luigi dijo que tú necesitabas una pieza... +[KM1_7] +~g~¡Sólo pueden entrar vehículos de policía autorizados! -[AMMU_B] -Joey me dijo que te armáramos... +[KM1_8A] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. -[AMMU_C] -Así que ve por la parte de atrás de la tienda. Te dejé un nueve en el patio. +[KM1_8D] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. -[AMMU_D] -Te conseguí todas las defensas necesarias para la casa. +[KM1_9] +~r~No destruiste la pared con un coche bomba. -[AMMU_E] -¿También quieres una licencia? +[KM1_10] +~r~El kanbu está muerto, ¡y tu honor también! -[AMMU_F] -No necesito ver ningún documento, pareces de fiar. +[KM1_11] +~r~¡La policía te ha seguido! -[DETON] -DETONACION: +[KM1_12] +~g~¡Llévalo al dojo, pero deshazte primero de la policía! -[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. +[KM1_13] +¡Mete el vehículo en el garaje! -[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. +{ =========================================================================== } +{ ================= MISSION: GRAND THEFT AUTO (KENJI KASEN) ================= } +{ =========================================================================== } -[RECORD] -~g~¡¡NUEVO RECORD!! +{ TITLE } -[NRECORD] -~r~¡NO HAY NUEVO RECORD! +[KM2] +'ROBO DE VEHÍCULOS' -[RCHELP] -Pulsa botón ~k~~PED_FIREWEAPON~, o conduce el coche de RC hasta las ruedas de un coche para detonarlo. +{ Premission cutscene } -[RCHELPA] -Pulsa el botón ~k~~PED_FIREWEAPON~, o conduce el coche RC hasta unas ruedas de coche para detonarlo. +{ Kenji } -[RC_1] -¡Tienes 2 minutos para volar cuantos coches de gangsters Diablo sean posibles! +[KM2_A] +Es imposible sobreestimar la importancia del protocolo en este trabajo. -[RC_2] -¡Tienes 2 minutos para bolar cuantos coches de gangsters Mafia sean posibles! +[KM2_B] +Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca pude corresponder su amabilidad. -[RC_3] -Tienes 2 minutos para bolar cuantos coches de gangsters Yakuza sean posibles! +[KM2_C] +Su debilidad son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. -[RC_4] -¡Tienes 2 minutos para volar cuantos coches de gangsters Yardie sean posibles! +[KM2_D] +No hace falta decir que debemos darle los coches como un regalo, para pagar mi deuda con él. -[RC_5] -Tienes 2 minutos para volar cuantos coches de gangsters Hood sean posibles! +[KM2_E] +Debes obtener los coches de la lista y llevarlos a un garaje que hay tras el aparcamiento de Newport. -[RC_6] -Tienes 2 minutos para volar cuantos coches de gangsters Cartel sean posibles! +[KM2_F] +Mi honor lo exige. -[RAMPAGE] -¡¡ATAQUE!! +{ Mission instructions } -[RAMP_P] -¡ATAQUE COMPLETADO! +[KM2_1] +~g~Repara el coche, tiene que estar en perfecto estado. -[RAMP_F] -ATAQUE FALLIDO +[KM2_2] +~g~Coche entregado. -[PAGE_00] -. +[KM2_3] +~g~Recuerda que los ~r~coches ~g~tienen que estar en perfecto estado para ser aceptados en el ~p~garaje~g~. -[PAGE_01] -¡Mata ~1~ Diablo en 120 segundos! +{ ===================================================================== } +{ ================= MISSION: DEAL STEAL (KENJI KASEN) ================= } +{ ===================================================================== } -[PAGE_02] -¡Destruye ~1~ vehículo en 120 segundos! +{ TITLE } -[PAGE_03] -¡Mata ~1~ Mafia en 120 segundos! +[KM3] +'UN MAL TRATO' -[PAGE_04] -¡Mata ~1~ Tríadas en 120 segundos! +{ Premission cutscene } -[PAGE_05] -¡Mata ~1~ Tríada en 120 segundos! +{ Kenji } -[PAGE_06] -¡Destruye ~1~ vehículo en 120 segundos! +[KM3_A] +Cuando los problemas acechan, el tonto les da la espalda, mientras que el sabio los enfrenta. -[PAGE_07] -¡Revienta ~1~ cabezas Yardie en 120 segundos! +[KM3_B] +El cártel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. -[PAGE_08] -¡Quema ~1~ Yakuza en 120 segundos! +[KM3_C] +Ahora están negociando con los jamaicanos para humillarnos aún más. -[PAGE_09] -¡Destruye ~1~ vehículo en 120 segundos! +[KM3_D] +Están cerrando un trato en la ciudad. -[PAGE_10] -¡Destruye ~1~ vehículo en 120 segundos! +[KM3_F] +Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus respetos a los colombianos. -[PAGE_11] -¡Aniquila ~1~ Yardie en 120 segundos! +[KM3_E] +¡Nuestro honor exige que no dejes a nadie vivo! -[PAGE_12] -¡Quema ~1~ Yakuza en 120 segundos! +{ Mission instructions } -[PAGE_13] -¡Vuela ~1~ Yardie en 120 segundos! +[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. -[PAGE_14] -¡Fríe ~1~ Colombianos en 120 segundos! +[KM3_2] +~g~Recoge a tu contacto. -[PAGE_15] -¡Machaca ~1~ Hood en 120 segundos! +[KM3_3] +~g~¡La reunión está teniendo lugar en el aparcamiento del hospital de Rockford! -[PAGE_16] -¡Destruye ~1~ vehículo en 120 segundos! +[KM3_4] +~r~¡Han escapado! -[PAGE_17] -¡Machaca ~1~ Colombianos con un coche en 120 segundos! +[KM3_5] +~g~Toca el claxon para empezar con el trato. -[PAGE_18] -¡Conduce por ahí en coche y destruye ~1~ vehículo en 120 segundos! +[KM3_6] +~g~¡Mátalos, mátalos a todos! -[PAGE_19] -¡Corta ~1~ cabezas colombiana en 120 segundos! +[KM3_7] +¡Es una trampa de la yakuza, tío! -[PAGE_20] -¡Córtale la cabeza a ~1~ Hoods en 120 segundos! +[KM3_8] +~g~¡Necesitas un coche de los jamaicanos para este trabajo! -[JM1_A] -Ey, estoy aburrida, ¿cuándo vas a tomarme? +[KM3_9] +~r~Uno de los colombianos ha muerto, se ha cancelado el trato. -[JM1_B] -En un momento, cariño, tengo un pequeño negocio del que ocuparme. +[KM3_10] +~r~¡El contacto está muerto! -[JM1_C] -Tengo un pequeño trabajo para ti, colega. +[KM3_11] +~g~El cártel ha sido atacado y el maletín no ha sido recuperado. -[JM1_D] -Los hermanos Forelli me deben dinero desde hace mucho tiempo +[KM3_12] +~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. -[JM1_E] -y ellos necesitan que alguien les enseñe un poco de respeto. +[KM3_13] +~g~Lleva el maletín de vuelta al casino. -[JM1_F] -Labios Forelli está poniéndose como un cerdo en el St Marks Bistro +[KM3_14] +~r~¡Te han descubierto, han cancelado el trato! -[JM1_G] -así que roba su coche y llévalo a la tienda de bombas 8-Ball en Harwood. +{ ================================================================ } +{ ================= MISSION: SHIMA (KENJI KASEN) ================= } +{ ================================================================ } -[JM1_H] -Conoces 8-Ball, ¿verdad? +{ TITLE } -[JM1_I] -Una vez que esté cargado con una bomba, ve a aparcar el coche donde lo encontraste. +[KM4] +'SHIMA' -[JM1_J] -Luego siéntate y contempla todo el espectáculo. +{ Premission cutscene } -[JM1_K] -Pero cuidado, no va a estar comiendo toda la vida. +{ Kenji } -[CAT2_A1] -¡Vamos, perra estúpida! +[KM4_A] +Para ser verdaderamente fuerte, es importante no mostrar debilidad. -[CAT2_A] -La verdadera cuestión es, lo que quieres es ¿rescatar a María o llevarme a mí de vuelta? +[KM4_B] +El negocio es lo bastante afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. -[CAT2_B] -Bueno, tengo noticias para ti, +[KM4_C] +Hazte con el dinero inmediatamente para que podamos ingresarlo en las cuentas del casino. -[CAT2_B2] -dispararte será un placer pero salir contigo fue sólo un asunto de negocios. +{ Cutscene after going to Uncle BJ's Deli & Groceries } -[CAT2_C] -¡Eres muy peccino, amigo! +{ Male shop owner } -[CAT2_D] -Echame el dinero +[KM4_1] +¡No puedo pagarte y no lo haría aunque pudiera! -[CAT2_E] -Has sido un chico aplicado! +[KM4_9] +¡Una banda de chavales acaba de arrasar el local! ¡Se han llevado todo! -[CAT2_E2] -Pero no has aprendido, yo no soy de fiar +[KM4_2] +¡Sois inútiles! -[CAT2_E3] -Mata al idiota +[KM4_10] +Además, ¿qué clase de yakuza eres tú? -[CAT2_J] -Atrapa esta cosa en el aire! +{ Unused strings? } -[HM5_1] -Tío, Ice dijo que vendría. Hay reglas. Bates sólo. No armas, no coches. +[KM4_3] +No pago a matones como vosotros para esto. Si quisiera esta clase de protección, llamaría a la policía, demonios. -[HM5_5] -Esta es una batalla por el respeto, ¿vale? +[KM4_6] +¡Aquí está todo el dinero! -[HELP14] -Para conseguir armas pasa sobre ellas. Estas no pueden conseguirse cuando se está dentro de un vehículo. +{ Pager message that tells the player Donald Love's missions are available } -[CRUSH] -Aparca en el área señalada y sal de tu vehículo. El vehículo será entonces triturado. +[KM4_5] +Donald Love desea que te pases por su jardín de té para tener una charla. -[DIAB2_B] -Una banda de infames me ha amenazado con quitarme mi afiliación si no les pago una parte. +{ Mission instructions } -[DIAB2_C] -Amenazaron al hombre equivocado, amigo. +[KM4_4] +~g~¡Castiga a la banda responsable y recupera el ~b~dinero de la protección~g~! -[DIAB2_D] -Ellos tienen debilidad por el helado. +[KM4_7] +~r~¡El tendero la acaba de palmar! -[DIAB2_E] -Consigue la bomba que he ocultado en Harwood, +[KM4_8] +~g~¡Maletín recolectado! -[DIAB2_F] -secuestra la furgoneta habitual de los helados en sus rondas. +[KM4_11] +~g~¡Lleva el dinero de vuelta al casino! -[DIAB2_G] -y seduce a esos idiotas para que caigan en su ruina con el jeengle-jeengle +{ ===================================================================== } +{ ================= MISSION: SMACK DOWN (KENJI KASEN) ================= } +{ ===================================================================== } -[DIAB2_H] -Se ocultan en un almacén de Atlantic Quay +{ TITLE } -[DIAB3_A] -Algunas Tríadas insolentes robaron mi bonito coche anoche, +[KM5] +'CONTRINCANTES TRAFICANTES' -[DIAB3_B] -destrózalo y deja que se queme. +{ Premission cutscene } -[DIAB3_C] -Algunos de mi más preciosos artículos sobre burros estaban en el maletero - +{ Kenji } -[DIAB3_D] -objetos de colección que son irremplazables, amigo. +[KM5_A] +¡Tú! ¡Qué oportuno por tu parte que muestres ahora tu despreciable cara! -[DIAB3_E] -He escondido un arma punzante en el borde de Chinatown. +[KM5_B] +¡Parece que tus intentos para disuadir a los jamaicanos -[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. +[KM5_B1] +de convertirse en aliados del cártel han sido totalmente inútiles! -[DIAB3_1] -MATA 25 TRIADS +[KM5_C] +¡Los traficantes jamaicanos están llenando las calles de Liberty, vendiendo SPANK como si fueran perritos calientes! -[DIAB4_A] -¡Un ladrón oportunista ha robado mi furgoneta donde llevaba mis últimas publicaciones periodísticas! +[KM5_D] +Estos cerdos del cártel se están riendo de nosotros, ¡de mí! -[DIAB4_B] -Pero ese idiota colgado de SPANK ha dejado las puertas de atrás abiertas +[KM5_E] +¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene un buen motivo! -[DIAB4_C] -y ahora toda mi bellamente editada, +[KM5_F] +¡Arrolla a estos canallas y lava tu vergüenza en el río de la sangre de nuestros enemigos! -[DIAB4_D] -literatura para adultos con tan buen gusto fotografiada está siendo esparcida por todo Liberty! +{ Mission instructions } -[DIAB4_E] -Coge la furgoneta y sigue el sendero de Donkey Does Dallas volúmenes 1,2 y 3 +[KM5_1] +~g~¡TRAFICANTE LIQUIDADO! -[DIAB4_F] -conseguido según vas. +[KM5_2] +~g~Uno de los jamaicanos se ha ido. -[DIAB4_G] -Cuando hayas seguido el sendero de ese ladronzuelo con cabeza de SPANK, acaba con él! +[KM5_3] +~r~No has matado a ~1~ jamaicanos. -[DIAB4_H] -Luego reparte mi material de Revistas XXX en el Red Light District (Distrito de la luz roja) +[KM5_4] +~g~Enhorabuena, has matado a ~1~ jamaicanos. -[DIAB4_1] -~g~Lleva la furgoneta a la parte de atrás de Revistas XXX +[KM5_5] +~g~Enhorabuena, has matado a ~1~ jamaicanos. ~1~$ ADICIONALES -[HM1_E] -Quiero mostrarle a esos perros macarras cómo funciona un verdadero tiroteo desde un vehículo +[KM5_6] +~g~Debes matar a al menos 8 traficantes jamaicanos. -[HM1_H] -¡Llévate a esos nueve fuera de aquí!! +[KM5_7] +~g~¡Mátalos rápido! En cuanto vendan el SPANK se retirarán de las calles. -[HM2_A] -Esos Nines me están presionando. +{ ================================================================================= } +{ ================= MISSION: BLING-BLING SCRAMBLE (KING COURTNEY) ================= } +{ ================================================================================= } -[HM2_B] -Esos perros tienen coches blindados y están traficando con SPANK... +{ TITLE } -[HM2_C] -y colocándoselo a los hermanos sin pudor. +[YD1] +'CORRE A POR LA PASTA' -[HM2_D] -Hay un coche aparcado arriba de la calle. +{ Pager message that appears when the Yardies missions are available } -[HM2_E] -Hay algo de material allí dentro para poner a esos mariquitas en su sitio... +[YD_P] +El Rey Courtney quiere hablarte. ¡Ve al teléfono público de Aspatria! -[HM3_A] -Algún effa ha cableado mis ruedas para bolarlas. +{ Premission cutscene } -[HM3_B] -Si pierdo esas ruedas, mi reputación en la calle estará muerta. +{ King Courtney } -[HM3_C] -Coge mi coche y llévalo al garaje de St Marks, ¿vale tío? +[YD1_A] +Habla el rey Courtney. -[HM3_D] -Déjales difundir eso, déjales que se ocupen de esa bomba. +[YD1_A1] +Mi banda jamaicana necesita un conductor y tú tienes reputación de ser bueno. -[HM3_E] -Los relojes están avanzando y el cableado está liado. +[YD1_B] +Ve en un coche al basurero que hay detrás del estadio y a los otros candidatos. -[HM3_F] -Otro fallo más y esa cosa podría volar. +[YD1_C] +Tengo hombres vigilando puntos de control por toda Staunton. -[HM3_G] -¡Ahora muévelo! +[YD1_D] +El primer conductor que llegue a un punto de control se lleva mil pavos, y así de punto a punto. -[HM4_A] -Tío, un vuelo de la Reserva federal se acaba de estrellar en el Francis International. +[YD1_D1] +Si ganas más puntos de control que los demás, podría tener trabajo para ti. -[HM4_B] -Hay platino por toda la pista. +{ Mission instructions } -[HM4_C] -Consigue un coche y agarra todo lo que puedas. +[YD1_E] +~g~¡Prepárate! -[HM4_F] -Puedes dejar el marrón en uno de mis garajes. +[YD1_F] +~g~Te has saltado la salida. ¡Me gusta tu estilo! -[HM4_G] -Este platino es muy pesado y va a hacer que tus ruedas se muevan más despacio. +[YD1_G] +~r~Esto es una carrera DE COCHES. ¡Necesitas un COCHE, idiota! -[HM4_H] -Así que haz repartos regulares en el garaje. +[YD1GO] +~g~¡VAMOS! -[HM5_A] -Esos Nines se han quedado con pocos costrosos... +[YD1_1] +~r~1 -[HM5_B] -pero todavía quieren seguir. +[YD1_2] +~r~2 -[HM5_C] -Aceptaron un cuerpo a cuerpo. . +[YD1_3] +~r~3 -[HM5_D] -Uno de sus gangsters contra dos de los nuestros, o mejor... +[YD1_BON] +¡1.000$! -[HM5_E] -dos de vosotros +[Y1_1ST] +~G~¡Has quedado primero con ~1~ puntos de control! -[HM5_F] -Yo os apoyaré pero... +[Y1_2ND] +~y~Eres el segundo con ~1~ puntos de control. ~y~¡Casi, pero no! -[HM5_G] -La vista de mi libertad bajo fianza no es hasta dentro de tres meses, +[Y1_3RD] +~r~Eres el tercero con ~1~ puntos de control. ~r~¿No decías que eras bueno? -[HM5_H] -¿sabes lo que te digo? +[Y1_LAST] +~r~¡Has quedado el último! ~r~¡Me has hecho perder el tiempo, IDIOTA! -[HM5_I] -Ve y reúnete con mi hermano pequeño, +[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! -[HM5_J] -Te enseñará dónde están peleando por una causa justa. +[Y1_J2ND] +~r~Has empatado el segundo con ~1~ puntos de control. ¡Conduces como un mono loco! -[MEA1_B] -El nombre es Chonks, Marty Chonks. +[Y1JLAST] +~r~¡Has empatado el último! ¡Hablas como un conductor, pero conduces como un hablador! -[MEA1_C] -Soy el dueño de la fábrica de comestibles Bitchin' Dog que está a la vuelta de la esquina. +[Y1_TEST] +¡COCHE AL AGUA! -[MEA1_D] -Tengo problemas económicos, pero ¡ey!, y quién no, ¿verdad? +[YD1_CNT] +¡~1~ de 15! -[MEA1_E] -Voy a reunirme con el director de mi banco más tarde. +{ ====================================================================== } +{ ================= MISSION: UZI RIDER (KING COURTNEY) ================= } +{ ====================================================================== } -[MEA1_F] -Es un tramposo bastardo que sigue engordando los pagos del préstamo para llevarse una buena porción. +{ TITLE } -[MEA1_G] -Coge mi coche, ve a buscarle y traelé de vuelta. +[YD2] +'JINETE CON UZI' -[MEA1_H] -¡¡Tengo una pequeña sorpresa para ese parasito chupasangres!! +{ Premission cutscene } -[MEA2_A] -Contraté algunos ladrones para que entraran en mi apartamento... +{ King Courtney } -[MEA2_C] -Los bastardos ladrones amenazan con contárselo a la compañía de seguros, +[YD2_A] +Necesito ver si eres capaz de hacer mi trabajo sucio, -[MEA2_D] -si no les doy una parte +[YD2_A1] +si se puede confiar en ti. -[MEA2_E] -¿Puedes creerlo? +[YD2_B] +Dos de mis chicos llegarán allí enseguida para llevarte de paseo, -[MEA2_F] -He dejado un coche dentro de las puertas de la fábrica. +[YD2_B1] +a ver si eres quien dices que eres. -[MEA2_G] -Úsalo para ir a recogerles en su territorio en el Red Light District. +{ Dialogue from Yardie after reaching you } -[MEA2_H] -Luego traelos de vuelta a la fábrica de manera que pueda hacerles ver el punto de vista de Marty. +[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. -[MEA3_A] -El negocio se va a hundir a no ser que me haga con una buena cantidad de dinero muy pronto. +[YD2_D] +Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te eches atrás. -[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. +[YD2_CC] +Toma, necesitarás una pipa. -[MEA3_C] -He dejado un coche en el lugar habitual +{ Dialogue from Yardie after entering the car } -[MEA3_D] -Ve a recoger a mi esposa en Classic Nails y traela de vuelta a la fábrica. +[YD2_E] +¡Conduce! -[MEA4_A] -Diablos,¡tengo problemas! +{ Dialogue from Yardie when trying to get out of the car } -[MEA4_B] -Resulta que mi esposa estaba viéndose con un tipo a quien le debo dinero. - -[MEA4_C] -¡Parece muy enfadado y está tratando de recuperar su dinero! - -[MEA4_E] -cree que voy a devolverle el dinero... - -[MEA4_F] -pero yo creo que... +[YD2_F] +~r~Se quiere escapar, ¡cárgatelo! -[MEA4_G] -¡los perros de Liberty van a disfrutar de un nuevo sabor este mes! +{ Dialogue from Yardie after reaching the objective area } -[WELCOME] -BIENVENIDO A +[YD2_G1] +Los cerros de Hepburn... Vamos a matar a algunos asquerosos Diablos... -[HM1_2] -~g~Hazte con un vehículo, y recuerda que sólo cuentan los asesinatos con Uzi desde el coche. +[YD2_G2] +Pero recuerda, ~r~¡no salgas de este coche! -[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. +{ Dialogue from Yardie after killing the targets } -[LRQC_1] -Asuka y yo vamos a tener que hablar, uh, +[YD2_H] +¡Vale, ya está! ¡Llévanos de vuelta a territorio jamaicano! ¡Vamos, vamos, vamos! -[LRQC_2] -¿Por qué no das un paseo por ahí? +{ Dialogue from Yardie after taking them to the final goal } -[LRQC_3] -Necesitas un lugar para esconderte +[YD2_L] +¡Eres la Muerte personificada! -[LRQC_4] -Hay un almacén en la orilla de Belleville que puede tener lo que necesitas. +{ Dialogue from Yardie after trashing the car } -[LRQC_5] -Regresa a mi apartamento cuando estés listo, +[YD2_M] +~r~¡Ha destrozado mi coche! ¡Liquídale! -[LRQC_6] -y podemos tener una pequeña charla. +{ Dialogue from Yardie when you are allowed to leave the car, but you must be in it } -[JM6_5] -~g~Necesitas un vehículo para escapar, ¡idiota! +[YD2_N] +¡Vuelve al coche! -[JM2_F] -Si necesitas una pieza ve por detrás de AmmuNation, enfrente del metro. +{ ============================================================================= } +{ ================= MISSION: GANGCAR ROUND-UP (KING COURTNEY) ================= } +{ ============================================================================= } -[LOVE4_7] -~g~Hay una zona de construcción en Staunton Island, puede que llevaran el paquete allí. +{ TITLE } -[LOVE4_8] -~g~Necesitarás un coche para abrir el garaje. +[YD3] +'COLECCIONANDO COCHES DE BANDAS' -[TSCORE] -GANANCIAS: ~1~ $ +{ Premission cutscene } -[AM1_9] -~r~¡Salvatore ha escapado de vuelta al club de Luigi! +{ King Courtney } -[AM1_6] -~g~Si te dejas ver por el club de Luigi, ¡la Mafia te encontrará! +[YD3_A] +Quiero que robes coches de otras bandas -[TM2_3] -~g~¡Es una trampa! ¡Liquidadlos a todos! +[YD3_A1] +para que podamos atacar sus territorios. -[FM4_1] -Esta es María. ¡El coche es una trampa! Encuéntrame en el lado sur de Callahan Bridge. +[YD3_B] +Necesito un Mafia Sentinel, -[JM1_7] -~g~¡Cierra la puerta del coche! ¡Se dará cuenta! +[YD3_B1] +un Yakuza Stinger y un -[KM5_1] -~g~¡¡TRAFICANTE DESMENUZADO!! +[YD3_B2] +Diablo Stallion para que podamos ir a por cualquier banda de Liberty. -[KM5_6] -~g~Debes matar al menos 8 traficantes Yardie. +[YD3_C] +Déjalos en el garaje de Newport y recuerda, -[KM5_7] -~g~¡Mátalos rápido! Una vez que venden el SPANK se retiran de las calles. +[YD3_C1] +¡dañados no nos sirven de nada! -[RM3_8] -~r~¡¡El coche es un señuelo!! +[YD3_D] +UNUSED -[LM3_8] -Hola, soy Joey. +{ Mission instructions } -[LM3_9] -Luigi dijo que tú eras de fiar, así que vuelve más tarde, +[YD3_E] +~r~¡Ya has entregado un coche de los Diablos! -[KM3_5] -~g~Toca el claxon para poder hacer el trato. +[YD3_F] +~r~¡Ya has entregado un coche de la mafia! -[LOVE7] -DESAPARICION DEL AMOR +[YD3_G] +~r~¡Ya has entregado un coche de la yakuza! -[LOVE2_5] -~g~¡Kenji es carne de parachoques! ¡Sal de Newport y deshazte del coche! +[YD3_H] +~g~¡Coche de los Diablos entregado! -[AS2_11] -~g~ ~1~ DE 9! +[YD3_I] +~g~¡Coche de la mafia entregado! -[GARAGE1] -~g~Sal del vehículo y camina afuera. +[YD3_J] +~g~¡Coche de la yakuza entregado! -[KM3_11] -~g~El Cartel ha sido atacado y el maletín no ha sido recuperado. +[YD3_K] +~r~¡El coche está casi destrozado! ¡Haz que lo reparen! -[KM3_12] -~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. +[YD3_L] +~g~¡Llévalo al ~p~garaje~g~! -[KM3_13] -~g~Lleva el maletín de vuelta al casino. +[YD3_M] +~r~¡Has volcado el vehículo! ¡Consigue otro! -[RM5_6] -~g~¡Ha salido en libertad bajo fianza! ¡¡Destruye su chaleco salvavidas con un vehículo o una explosión!! +{ ========================================================================= } +{ ================= MISSION: KINGDOM COME (KING COURTNEY) ================= } +{ ========================================================================= } -[PBOAT_1] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones del barco. +{ TITLE } -[PBOAT_2] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones del barco. +[YD4] +'POR LOS AIRES' -[DIAB1_B] -Este es El Burro de los Diablos. +{ Premission cutscene } -[DIAB1_D] -Ahora estás en Liberty, pero ya te estás ganando una reputación en las calles. +{ King Courtney } -[DIAB1_E] -Hay una carrera en la calle que empieza en la vieja escuela cerca de Callahan Bridge. +[YD4_A] +¡Escucha! -[DIAB1_F] -Consíguete unas ruedas y el primero que pase por todos los checkpoints gana el premio. +[YD4_A1] +Mueve el culo a Bedford Point. -[HM2_1] -Usa los buggies RC para destruir los coches blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~ para detonar. +[YD4_A2] +¡Hay un cargamento en una tartana que necesito pronto! -[HM2_1A] -Usa los buggies RC para destruir los coches blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para detonar. +{ Cutscene after entering the target car } -[HM2_2] -~r~¡Fallaste en la destrucción de los coches blindados! +{ Catalina, colombiana } -[HM2_6] -~g~¡Coche blindado destrozado! +[YD4_B] +CARTA: Dicen que estuviste entretenido. Igual que yo. -[RM3_A] -Conozco un hombre muy importante en la ciudad, un tipo suave, +[YD4_C] +¡Es hora de que seas testigo del verdadero poder del 'SPANK'! Con mucho amor, Catalina. -[RM3_H] -con gustos exóticos y el suficiente dinero para pagárselos. +[YD4_D] +P.D. ¡MUERE, BASURA, MUERE! -[RM3_B] -Está involucrado en un asunto legal y la acusación tiene fotos de él muy comprometedoras +{ Mission instructions } -[RM3_C] -en una fiesta en la morgue o algo así. +[YD4_1] +~g~¡Son psicópatas adictos al SPANK! -[LOVE6_A] -Una lección en negocios, amigo mío. +[YD4_2] +~g~¡Destruye las furgonetas de SPANK! -[LOVE6_E] -Si tienes una mercancía única, el mundo y su mujer tratarán de quitártela de tus garras. +{ ============================================================================== } +{ ================= MISSION: SILENCE THE SNEAK (RAY MACHOWSKI) ================= } +{ ============================================================================== } -[LOVE6_C] -Equipos SWAT han acordonado el área alrededor de mi asociado y el paquete. +{ TITLE } -[LOVE6_D] -Ve hacia allí, recoge la furgoneta y actúa como un señuelo. +[RM1] +'SILENCIA AL SOPLÓN' -[LOVE6_F] -Mantenles ocupados y él podrá escaparse bien. +{ Premission cutscene } -[AM3_C] -¡Está probablemente afuera en la bahía mientras lees esto! ¡Roba un barco de policía, y hunde su carrera! +{ Ray } -[FESZ_UC] -CANCELAR +[RM1_A] +¡Ese canalla de McAffrey...! ¡Aceptó más sobornos que nadie, -[FEDS_SM] -L1,R1-CAMBIAR MENU Mientras se busque un menú en particular: +[RM1_B] +se piensa que le darán la pensión completa si se convierte en un testigo de cargo! -[FEDS_AS] -;=-CAMBIAR SELECCION +[RM1_C] +¡Y ha cantado! -[FEDSAS2] -<>-CAMBIAR SELECCION +[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. -[FEDS_SS] -L1,R1-CAMBIAR SELECCION +[RM1_E] +Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con nadie. -[FEDSSC1] -;-MOVIMIENTO MAS RAPIDO +{ Mission instructions } -[FEDSSC2] -=-DETENER MOVIMIENTO +[RM1_1] +~g~Ve a la casa de protección de testigos. -[MEA2_3] -~g~Traer el coche de vuelta a la fábrica. +[RM1_2] +~g~¡Cárgate a McAffrey! [RM1_3] -~r~¡McAffrey se escapó! +~r~¡McAffrey se ha escapado! [RM1_4] -~g~¡Has usado todas las granadas! ¡Consigue más en Ammunation! +~g~¡Has usado todas las granadas! ¡Consigue más en la tienda Ammu-Nation! [RM1_5] -~g~¡Vuelve y quema la casa de seguridad! +~g~¡Vuelve y quema la casa franca! -[RM6_4] -~g~ Pásate por la taquilla y consigue el cargamento de Ray. +{ ========================================================================== } +{ ================= MISSION: ARMS SHORTAGE (RAY MACHOWSKI) ================= } +{ ========================================================================== } -[RM6_5] -~g~La CIA tiene el puente bajo vigilancia, encuentra otra ruta para pasar +{ TITLE } -[HM2_F] -y destroza todo su material blindado. +[RM2] +'ESCASEZ DE MANOS' -[HM_4] -'LINGOTES DE ORO' +{ Premission cutscene } -[MEA2_B5] -TEXTO NO MAS REQUERIDO +{ Ray } -[MEA1_B5] -TEXTO NO MAS REQUERIDO +[RM2_A1] +¡Chico, estoy aquí! -[MEA3_B5] -TEXTO NO MAS REQUERIDO +[RM2_A] +Un viejo colega del ejército tiene un negocio en Rockford. -[MEA4_B7] -pero si pasas por mi oficina... +[RM2_B] +Combatimos juntos en Nicaragua, cuando el país sabía lo que hacía. -[MEA3_B4] -¿ Marty quiere verme? Bueno, pues que sea rápido porque tengo que ir a la peluquerí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. -[KM3_7] -¡Es una trampa Yakuza, tío! +[RM2_D] +Va a necesitar respaldo y a cambio te venderá material de todo tipo a precios de ganga. -[FES_LOF] -Fallo al cargar. +[RM2_D1] +Iría yo mismo, pero la ciática ya está en sus trece... ¡Cof, cof! Así que... buena suerte. -[P1INSA] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. ~1~K de espacio disponible para guardar. ~1~K necesario. +{ Cutscene, appears when finding Phil } -[P1INSN] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. No hay espacio disponible para guardar. Por favor borra algunos archivos. +{ Phil } -[FES_SLO] -GUARDAR ARCHIVO +[RM2_E] +Ray me avisó... Pero pensé que vendría más gente. -[FES_ISC] -ESTA CORRUPTO +[RM2_E1] +¡No puedo creer que esos mamones amarillos me hayan vuelto a dejar con el culo al aire! -[FESZ_TI] -GUARDAR Z1 +[RM2_F] +Bueno, tres brazos son mejor que uno, así que sírvete. -[FESZ_SA] -Guardar Partida +[RM2_F1] +¡Los colombianos llegarán en cualquier momento! -[P1NOIN] -No hay memory card (PS2) insertada en la ranura para MEMORY CARD 1 +{ Dialogue from Phil, when the Colombians arrive } -[P1INSE] -Memory card (PS2) insertada en la ranura para MEMORY CARD 1. +[RM2_K] +Maldita sea, ¡están aquí! ¡FUEGO A DISCRECIÓN! -[MC_LDFL] -¡Error al cargar! +{ Dialogue from Phil, when the Colombians are killed } -[MC_NWRE] -Ahora, reinicio de partida +[RM2_L] +¡Caray! ¡Si hubieras estado a mi lado en Nicaragua, a lo mejor conservaría el brazo! -[LOVE6_3] -~g~Tienes ~1~ segundo para volver al Securicar antes de que falles en la misión. +[RM2_M] +Si necesitas armas nuevas, pasa por aquí y coge lo que necesites de las taquillas. -[LOVE6_4] -~r~¡Te deshiciste del Securicar señuelo! +[RM2_N] +Deja el dinero en el suelo. Ahora vete, ya me ocupo yo de la poli. -[HELP1] -Detente en el centro del marcador azul. +{ Mission instructions } -[HELP12] -Vaya hasta el centro del marcador azul para dar comienzo una misión. +[RM2_G] +~g~¡Ve a ver a Phil! -[HJSTAT] -Distancia: ~1~. ~1~m. Altura: ~1~.~1~m. Vueltas: ~1~. Rotación: ~1~_ +[RM2_H] +~r~¡Han matado a Phil! -[HJSTATW] -Distancia: ~1~.~1~m. Altura: ~1~.~1~m. Vueltas: ~1~. Rotación: ~1~_ Y, ¡qué buen aterrizaje! +{ ========================================================================== } +{ ================= MISSION: EVIDENCE DASH (RAY MACHOWSKI) ================= } +{ ========================================================================== } -[DIAB1_5] -TIEMPO DE CARRERA +{ TITLE } -[LOVE3_4] -~r~¡Has destruído el avión!! +[RM3] +'FALTA DE PRUEBAS' -[F_FAIL1] -¡Misión de coche de bomberos terminada! +{ Premission cutscene } -[F_CANC] -~r~ ¡Misión de coche de bomberos cancelada! +{ Ray } -[F_EXTIN] -FUEGOS: +[RM3_A] +Conozco a un pez gordo de la ciudad, un tipo muy cándido, -[A_COMP1] -¡Misión de paramédicos completada! +[RM3_H] +con, digamos... gustos exóticos y el dinero para pagárselos. -[A_CANC] -~r~¡Misión de paramédicos cancelada! +[RM3_B] +Está involucrado en un asunto legal y la fiscalía tiene fotos de él muy comprometedoras -[A_COMP3] -¡Misión de paramédicos completada! ¡Nunca te cansarás cuando estés corriendo! +[RM3_C] +en una fiesta en la morgue o algo así. -[ATUTOR] -Pulsa el ~h~ botón ~k~~TOGGLE_SUBMISSIONS~~w~ para conectar o desconectar misiones de paramédico. +[RM3_D] +Están transportando las pruebas por la ciudad. -[ATUTOR3] -Pulsa el ~h~ botón ~k~~TOGGLE_SUBMISSIONS~~w~ para conectar o desconectar misiones de paramédico. +[RM3_E] +Tendrás que embestir al coche y recoger hasta la última prueba que se le caiga. -[ALEVEL] -Nivel de misión de paramédico ~1~ +[RM3_F] +En cuanto tengas todas, déjalas en tu coche y préndele fuego. -[A_FAIL1] -Misión de paramédico terminada. +[RM3_G] +Cuando acabes, nos irá mucho mejor, chico. -[FEST_HA] -Nivel más alto de misión de paramédico +{ Mission instructions } -[A_SAVES] -GENTE SALVADA: ~1~ +[RM3_1] +~g~Deja las pruebas en un coche y después préndele fuego. -[C_KILLS] -CRIMINALES MATADOS: ~1~ +[RM3_4] +~g~¡Al fiscal se le ha caído una prueba! -[HM1_B] -Tengo un problema, están tratando de camelarme. +[RM3_5] +~g~Tienes ~1~ de 6 paquetes de pruebas. -[AM2_A] -La muerte de Salvatore es una placentera noticia, +[RM3_6] +~r~¡Las fotos circularán por toda la ciudad! -[AM2_A2] -eres un asesino eficaz - Eso me gusta en un hombre. +[RM3_7] +~g~¡Ahora préndele fuego al coche! -[AM2_B] -Este es mi hermano Kenji. +[RM3_8] +~r~¡El coche es un señuelo! -[AM2_C] -Asuka tiene un pequeño trabajo para ti, pero cuando hayas terminado, pásate por mi casino y podremos hablar. +{ ========================================================================= } +{ ================= MISSION: GONE FISHING (RAY MACHOWSKI) ================= } +{ ========================================================================= } -[AM2_D] -Justo como Kenji, siempre tratando de jugar con mis juguetes. +{ TITLE } -[AM2_E] -Mi fuente en la policía me dice que la Mafia está acechando nuestros intereses en la ciudad +[RM4] +'DE PESCA' -[AM2_E2] -con el propósito de localizarte. +{ Premission cutscene } -[AM2_F] -No podemos continuar con nuestras operaciones hasta que entablen negociaciones. +{ Ray } -[AM2_G] -Liquida a esos estúpidos espías y acaba con esta vendetta de una vez por todas. +[RM4_A] +Creo que mi socio es un soplón. -[F_START] -~g~Informe de vehículo en llamas en el ~a~área. Ve y extingue el fuego. +[RM4_B] +Tenemos que cerrarle la boca para siempre. -[AM4_1A] -Ve al teléfono de West Belleville Park. +[RM4_C] +Casi todas las noches sale a pescar con su lancha cerca del faro que hay en Portland Rock. -[AM4_1B] -Ve al teléfono de Liberty Campus. +[RM4_D] +¡Roba una lancha de la policía y asegúrate de que se le acaben las ganas de dar puñaladas traperas! -[AM4_1C] -Ve al teléfono de South Belleville Park. +[RM4_E] +¡Quiero que se vaya a dormir con los peces, en vez de comérselos! -[AM4_1D] -Encuéntrame en el bloque del baño en el parque. +{ Mission instructions } -[HJSTATF] -Distancia:~1~pies. Altura: ~1~pies. Vueltas: ~1~. Rotación: ~1~_ +[RM4_1] +~g~Ve y roba una lancha de la policía. -[HJSTAWF] -Distancia: ~1~pies. Altura: ~1~pies. Vueltas: ~1~. Rotación: ~1~_. Y, ¡qué buen aterrizaje! +[RM4_2] +~g~¡Ve al faro y ''hunde'' al socio de Ray! -[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. +[RM4_3] +~r~¡El socio de Ray ha escapado! -[HM1_D] -'Nueves' es su etiqueta y púrpura es su bandera y cada día ellos sacuden sus colores... +{ ============================================================================ } +{ ================= MISSION: PLASTER BLASTER (RAY MACHOWSKI) ================= } +{ ============================================================================ } -[HM1_G] -otro día más que los 'Jacks' parecen blanditos. +{ TITLE } -[MEA2_B] -y roba lo que encuentres para que así pueda reclamarle al seguro como haces tú. +[RM5] +'DESESCAYOLADOR' -[TM3_H] -~w~Te lo montaste bien allí, chaval, muy bien. +{ Premission cutscene } -[TM3_I] -~w~Vamos, te presentaré al Don. +{ Ray } -[TM3_J] -~w~¡Eeeyyyy! ¡Luigi! +[RM5_A] +¡Inútil de mierda! -[TM3_K] -~w~Oh, mis chicas han estado echándote de menos mucho tiempo, Salvatore, has estado fuera mucho tiempo. +[RM5_A1] +¡La has cagado! Me la estoy jugando y ni siquiera eres capaz de matar a una maldita mosca. -[TM3_L] -~w~Diles que una vez que nos hayamos ocupado de este desgraciado incidente, +[RM5_B] +¡Te pagué una pasta para matar al testigo y aún sigue vivo! -[TM3_M] -~w~iremos todos al club para celebrar, ¿vale? +[RM5_B1] +¡Y hoy va a declarar ante los federales! -[TM3_N] -~w~Ese es mi chico +[RM5_C] +Está a punto de ser trasladado del hospital general Carson, en Rockford. -[TM3_N2] -~w~¿Cómo lo llevas, papá? +[RM5_D] +Si él canta, yo canto... -[TM3_O] -~w~¿Has encontrado ya una buena mujer? +[RM5_E] +¡así que termina el trabajo por el que te pagué! -[TM3_P] -~w~Ey, tu madre, que en paz descanse, se retorcería en la tumba +{ Mission instructions } -[TM3_Q] -~w~si te viera sin una mujer. +[RM5_1] +~g~Intercepta la ambulancia. -[TM3_R] -~w~Lo sé, papá, me estoy ocupando de eso. +[RM5_2] +~g~¡Te han descubierto! -[TM3_S] -~w~¡TONI! ¿Cómo está tu madre? +[RM5_3] +~g~¡Era un señuelo! -[TM3_T] -~w~Ella es una gran mujer, ¿sabes? Fuerte. Firenze. +[RM5_4] +~g~¡Las balas no penetran en esa escayola de cuerpo entero! -[TM3_U] -~w~Ella está bien... estupenda. +[RM5_5] +~g~¡Esa escayola de cuerpo entero es ignífugo! -[TM3_V] -~w~Fantástico, fantástico. Ahora escuchadme, chavales, entrad dentro mientras yo hablo aquí con nuestro nuevo amigo. +[RM5_6] +~g~¡Ha salido de la ambulancia! ¡Cárgate su escayola con un vehículo o una explosión! -[TM3_W] -~w~No veo más que cosas buenas para ti, hijo mío... +[RM5_7] +~r~¡El testigo está a salvo! -[RM1_A] -Esa bola de mierda, McAffrey, aceptó más sobornos que nadie. +[RM5_8] +~g~¡El testigo se ha ahogado! -[RM1_B] -Cree que va a conseguir una rebaja honorable de sus cargos si ofrece evidencias del estado +{ ======================================================================= } +{ ================= MISSION: MARKED MAN (RAY MACHOWSKI) ================= } +{ ======================================================================= } -[RM1_C] -¡El ha cantado! +{ TITLE } -[RM4_B] -Tenemos que cerrarle la boca para siempre. +[RM6] +'HOMBRE MUERTO' -[RM4_E] -Quiero que se vaya a dormir con los peces en lugar de comérselos. +{ Premission cutscene } -[LOVE3_B] -En su aproximación al aeropuerto esta noche, una avioneta ligera sobrevolará la bahía. +{ Ray } -[LOVE4_D] -Desgraciadamente las autoridades aduaneras registraron el avión y lo estaban desguazando +[RM6_A] +¿No te han seguido? Bien. -[LOVE4_H] -hasta que yo intervine a pesar del gran coste personal. +[RM6_B] +Se acabó, ¡esto se me va de las manos y estoy con la soga al cuello! -[LOVE4_E] -Cruza el puente a Shoreside Vale, y ve al aeropuerto Francis International. +[RM6_C] +La CIA parece estar interesada en el SPANK -[GTAB_A] -Ey, saquemos esto de aquí. Dios sabe qué será. +[RM6_C1] +y no les gusta que nos metamos con el cártel. -[GTAB_B] -pero él parece quererlo a toda costa así que debe de tener algún valor. +[RM6_D] +Soy hombre muerto, así que tengo que largarme. -[GTAB_C] -¡Quién diablos! +[RM6_E] +¡Consigue que no pierda mi vuelo en el aeropuerto y haré que tu trabajo haya merecido la pena! -[GTAB_D] -¡TÚ! +{ Cutscene, appears when Ray has been taken safely to the airport } -[GTAB_E] -¡Ey, tranquilo, amigo! ¡De nada! De nada! +[RM6_1] +Esta llave es de un almacén. -[GTAB_F] -¡Te dejé metiendo tu corazón en el charco! +[RM6_2] +Encontrarás dinero en metálico y ''suministros'' que guardé por si las cosas se ponían feas. -[GTAB_G] -No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. +[RM6_3] +Hasta la vista. -[GTAB_H] -¡No seas mariquita! +{ Pager message that appears when reaching Ray's lockup } -[GTAB_I] -¡No tenemos elección, nene! +[RM6_666] +Cuida mi Patriot a prueba de balas. Nos vemos en Miami, Ray -[GTAB_J] -¡Siempre hay una elección, bastardo! +{ Mission instructions } -[GTAB_K] -¡Siento mucho lo de ese perro enloquecido, son todos iguales... ¿¿por favor?? +[RM6_4] +~g~Ve al almacén a por el cargamento de Ray. -[GTAB_L] -Así que la buscona se fué. +[RM6_5] +~g~La CIA vigila el puente, busca otro camino. -[GTAB_M] -Pero me has hecho un favor, +[RM6_6] +~r~¡Ray ha muerto! -[GTAB_N] -no eres el único que tiene una cuenta pendiente con el Cartel, +[RM6_7] +~r~¡Ray ha perdido su avión! -[GTAB_O] -¡ese gusano mató a mi hermano! +[RM6_8] +~g~Has abandonado a Ray, vuelve a por él. -[GTAB_P] -¡Nunca maté a ningún Yakuza! +{ ==================================================================== } +{ ================= MISSION: LIBERATOR (DONALD LOVE) ================= } +{ ==================================================================== } -[GTAB_Q] -¡MENTIROSO! Todos vimos al asesino del Cartel. +{ TITLE } -[GTAB_R] -¡Vamos a cazaros y a mataros a todos, perros colombianos! +[LOVE1] +'EL LIBERADOR' -[GTAB_S] -Estaré trabajando con nuestro querido amigo para extraerle información y un poco de placer. +{ Premission cutscene } -[GTAB_T] -Tú, ven más tarde, estoy seguro que voy a necesitar tus servicios. +{ Donald Love } -[GTAB_U] -Por favor, amigo, no me dejes con ella, ¡esa chica está loca! ¿Amigo?. Ey, ¡AMIIIGO!... ¡Aiiieeeaaaargghh! +[LOVE1_A] +Antes que nada, permíteme agradecerte que te hayas ocupado de ese asunto personal. -[LOVE5_A] -Estás demostrando ser una inversión segura, algo muy raro en estos días que corren. +[LOVE1_F] +Últimamente la gente tiende a malinterpretar las cosas. -[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_B] +La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, -[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) +[LOVE1_H] +pero los grupos de hombres se vuelven codiciosos. -[FM1_Q1] -~w~¿Estás buscando un poco de diversión?. ¿Un poco de... hmmm? ¿Algo de zurra? +[LOVE1_C] +Un activo valioso, un anciano oriental que conozco, -[FM1_R] -~w~Hola, chico. Hah, lo de siempre. +[LOVE1_I] +está siendo retenido por unos sudamericanos en Aspatria. -[FM1_T] -~w~Gracias Chico, nos vemos pronto. +[LOVE1_D] +Pretenden exigirme más de lo pactado, pero no me gusta renegociar. -[FM1_W] -~w~De acuerdo Fido, espera aquí y quédate pendiente del coche mientras yo voy a menear mi culo, ¿vale? +[LOVE1_E] +Un trato es un trato, así que no van a ver ni un dólar mío. -[FM1_X] -~w~VALE Fido, salgamos de aquí. ¡Uauhhh! +[LOVE1_G] +Rescata a mi amigo cueste lo que cueste. -[FM1_Q] -~w~¡Ey María! ¡Es mi chica favorita! +{ Mission instructions } -[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. +[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_U] -~w~Gracias y disfruta. Es buen material +[LOVE1_2] +~g~Rescata al anciano oriental. -[FM1_V] -~w~Vamos Fido, ¡vamos a echar un vistazo a esa fiesta! +[LOVE1_3] +~g~Lleva al anciano oriental de vuelta al edificio de Donald Love. -[FM1_SS] -~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: Asistir redada de narcóticos en Atlantic Quays. +[LOVE1_4] +~g~El anciano oriental debe estar detrás de alguna de estas puertas... -[LOVE6_B] -incluso aunque no sean conscientes de su verdadera valía. +[LOVE1_5] +~g~Deja de perder el tiempo, hazte con un coche de los colombianos y rescata al socio de Love. -[TM3_A1] -~r~¡El amigo de Joey! +[LOVE1_6] +~r~¡Las tripas del anciano oriental están desparramadas por las calles! -[TM3_A2] -~r~¡Joey y Luigi han sido incinerados! +[LOVE1_7] +~g~La puerta sólo se abrirá ante un coche de los colombianos. -[TM3_A3] -~r~¡Joey, Luigi y Toni están quemados! +{ =============================================================================== } +{ ================= MISSION: WAKA-GASHIRA WIPEOUT (DONALD LOVE) ================= } +{ =============================================================================== } -[FM4_2] -Escucha, Salvatore cree que estamos engañándole, +{ TITLE } -[FM4_3] -así que te ofreció al Cartel para poder hacer un trato. +[LOVE2] +'¡EXTERMINA AL WAKA-GASHIRA!' -[FM4_4] -No podía permitir que hiciera eso, o sea, lo peor es que, +{ Premission cutscene } -[FM4_4B] -es mi culpa... porque le dije que éramos un asunto a tratar. +{ Donald Love } -[FM4_5] -No me preguntes por qué. No lo sé. +[LOVE2_A] +No hay nada como una clásica guerra de bandas para hacer que bajen los precios de las viviendas, -[FM4_6] -Mira, eres un hombre marcado en terreno Mafia y yo tengo que salir de aquí también. +[LOVE2_B] +excepto una plaga... pero eso sería excesivo en este caso. -[FM4_6B] -¡He visto demasiados asesinatos. Demasiada sangre! +[LOVE2_C] +He observado que la yakuza y los colombianos no son precisamente buenos amigos. -[FM4_7] -Es una amiga mía, ¿vale?, una vieja amiga... es Asuka, alguien en quien podemos confiar. +[LOVE2_D] +Vamos a aprovechar esta oportunidad de negocio. -[FM4_8] -Vamos, ya vale de discursos. +[LOVE2_E] +Quiero que mates a Kenji Kasen, el waka-gashira (segundo al mando) de la yakuza. -[FM4_9] -Será mejor que salgamos de aquí antes de que haya más italianos histéricos pretendiendo hacer reuniones poco amistosas. +[LOVE2_F] +Kenji está asistiendo a una reunión en lo alto del aparcamiento de Newport. -[CRED001] -ROCKSTAR STUDIOS +[LOVE2_G] +¡Hazte con un coche de la banda del cártel y elimínalo! -[CRED002] -PRODUCER +[LOVE2_H] +La yakuza debe culpar al cártel de esta declaración de guerra. -[CRED003] -LESLIE BENZIES +{ Mission instructions } -[CRED004] -ART DIRECTOR +[LOVE2_1] +~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! -[CRED005] -AARON GARBUT +[LOVE2_2] +~g~¡Ahora ve al ~p~aparcamiento de Newport~g~ y cárgate a Kenji! -[CRED006] -TECHNICAL DIRECTION +[LOVE2_3] +~r~¡Si no llevas un coche del cártel, te descubrirán! -[CRED007] -OBBE VERMEIJ +[LOVE2_4] +~r~¡La yakuza te ha reconocido! -[CRED008] -ADAM FOWLER +[LOVE2_5] +~g~¡Kenji ha palmado! ¡Sal de Newport y deshazte del coche! -[CRED009] -DESIGN +[LOVE2_6] +~r~¡Has matado a todos los testigos! -[CRED010] -CRAIG FILSHIE +[LOVE2_7] +~g~¡Ahora deshazte del coche! -[CRED011] -WILLIAM MILLS +[LOVE2_8] +~g~¡Sal de Newport! -[CRED012] -CHRIS ROTHWELL +{ ============================================================================== } +{ ================= MISSION: A DROP IN THE OCEAN (DONALD LOVE) ================= } +{ ============================================================================== } -[CRED013] -JAMES WORRALL +{ TITLE } -[CRED014] -WRITTEN BY +[LOVE3] +'UNA GOTA EN EL OCÉANO' -[CRED015] -JAMES WORRALL +{ Premission cutscene } -[CRED016] -PAUL KUROWSKI +{ Donald Love } -[CRED017] -DAN HOUSER +[LOVE3_A] +En estos días de hipocresía moral, ciertos artículos pueden resultar difíciles de importar. -[CRED018] -CHARACTERS +[LOVE3_B] +Esta noche, durante su aproximación al aeropuerto, una avioneta sobrevolará la bahía. -[CRED019] -IAN MCQUE +[LOVE3_C] +Echará varios paquetes al agua. -[CRED020] -ANIMATION & DIRECTION +[LOVE3_D] +Asegúrate de los consigues antes que nadie. -[CRED021] -ALEX HORTON +{ Mission instructions } -[CRED022] -LEE MONTGOMERY +[LOVE3_1] +~g~¡Consigue una ~r~lancha~g~ y sigue a la ~y~avioneta~g~! -[CRED023] -AUTO DESIGN +[LOVE3_2] +~g~¡Tienes todos los paquetes! Llévaselos a Donald Love. -[CRED024] -PAUL KUROWSKI +[LOVE3_3] +~g~La avioneta ha tirado ~1~ de los 6 paquetes. -[CRED025] -ARTISTS +[LOVE3_4] +~r~¡Has destruido el avión! -[CRED026] -KEIRAN BAILLIE +[LOVE3_5] +~g~La avioneta está ahora a tu alcance. -[CRED027] -ADAM COCHRANE +[LOVE3_6] +~r~¡La bofia ha llegado a los paquetes antes que tú! -[CRED028] -GARY MCADAM +{ =========================================================================== } +{ ================= MISSION: GRAND THEFT AERO (DONALD LOVE) ================= } +{ =========================================================================== } -[CRED029] -MICHAEL PIRSO +{ TITLE } -[CRED030] -ANDREW SOOSAY +[LOVE4] +'ROBO DE ALTOS VUELOS' -[CRED031] -ALISDAIR WOOD +{ Premission cutscene } -[CRED032] -CODERS +{ Donald Love } -[CRED033] -ALAN CAMPBELL +[LOVE4_A] +Gracias por conseguir esos paquetes, pero sólo eran un señuelo. -[CRED034] -MARK HANLON +[LOVE4_B] +Lo siento, pero a veces los negocios son así. -[CRED035] -ANDRZEJ MADAJCZYK +[LOVE4_C] +Mi verdadero objetivo se ocultaba en la avioneta. -[CRED036] -ALEXANDER ROGER +[LOVE4_D] +Desgraciadamente, las autoridades aduaneras registraron la avioneta y la comenzaron a desmontar -[CRED037] -GRAEME WILLIAMSON +[LOVE4_H] +hasta que yo intervine a través de mi fortuna. -[CRED038] -SCORE +[LOVE4_E] +Cruza el puente hacia Shoreside Vale y ve al Aeropuerto Internacional Francis. -[CRED039] -CRAIG CONNER +[LOVE4_F] +He sobornado a los funcionarios. -[CRED040] -STUART ROSS +[LOVE4_G] +Mis pertenencias estarán esperándote en el hangar de aduanas, dentro de la avioneta. -[CRED041] -SOUND DESIGN & MASTERING +{ Cutscene, when going up into the construction area's elevator, finding Catalina, Miguel and Asuka } -[CRED042] -ALLAN WALKER +{ Catalina, colombiana } -[CRED043] -AUDIO PROGRAMMING +[GTAB_A] +Oye, saquemos esto de aquí. Dios sabrá lo que será, -[CRED044] -RAYMOND USHER +[GTAB_B] +pero él lo quiere a toda costa, así que tendrá algún valor. -[CRED045] -TEST MANAGER +{ Miguel, colombiano } -[CRED046] -CRAIG ARBUTHNOTT +[GTAB_C] +¡¿Qué diablos?! -[CRED047] -LEAD TESTERS +{ Catalina, colombiana } -[CRED048] -ANDY DUTHIE +[GTAB_D] +¡TÚ! -[CRED049] -JOHN HAIME +{ Miguel, colombiano } -[CRED050] -NEIL CORBETT +[GTAB_E] +¡Tranquilo, amigo! ¡No es nada! ¡No es nada! -[CRD050A] -TESTERS +{ Catalina, colombiana } -[CRED051] -GRAEME JENNINGS +[GTAB_F] +¡Te dejé desangrándote entre la basura! -[CRED052] -DAVID MURDOCH +{ Miguel, colombiano } -[CRED053] -DAVID BEDDOES +[GTAB_G] +No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. -[CRED054] -EDWIN SMITH +{ Catalina, colombiana } -[CRED055] -MARK FLETT +[GTAB_H] +¡No seas cagón! -[CRED056] -MICHAEL SUTHERLAND +{ Miguel, colombiano } -[CRED057] -TECHNICAL SUPPORT +[GTAB_I] +¡No tenemos elección, nena! -[CRED058] -LORRAINE ROY +{ Catalina, colombiana } -[CRED059] -CHRISTINE CHALMERS +[GTAB_J] +¡Siempre la hay, imbécil! -[CRED060] -ROCKSTAR +{ Miguel, colombiano } -[CRED061] -EXECUTIVE PRODUCER +[GTAB_K] +¡Siento mucho lo de esa perra enloquecida, todas son iguales... ¿Por favor? -[CRED062] -SAM HOUSER +{ Asuka } -[CRED063] -PRODUCER +[GTAB_L] +Así que la zorra se fue. -[CRED064] -DAN HOUSER +[GTAB_M] +Pero me has hecho un favor, -[CRED065] -DIRECTOR OF DEVELOPMENT +[GTAB_N] +no eres el único que tiene una cuenta pendiente con el cártel... -[CRED066] -JAMIE KING +[GTAB_O] +¡Este gusano mató a mi hermano! -[CRED067] -TECHNICAL PRODUCER +{ Miguel, colombiano } -[CRED068] -GARY J. FOREMAN +[GTAB_P] +¡Nunca maté a ningún yakuza! -[CRED069] -ASSOCIATE PRODUCER +{ Asuka } -[CRED070] -JEREMY POPE +[GTAB_Q] +¡Mientes! Todos vimos al asesino del cártel. -[CRED071] -MUSIC SUPERVISOR +[GTAB_R] +¡Vamos a cazaros y a mataros a todos, perros colombianos! -[CRED072] -TERRY DONOVAN +[GTAB_S] +Me trabajaré a nuestro querido amigo para extraerle información y un poco de placer. -[CRED073] -ROCKSTAR PRODUCTION TEAM +[GTAB_T] +Tú, ven más tarde, estoy segura de que voy a necesitar tus servicios. -[CRED074] -TERRY DONOVAN +{ Miguel, colombiano } -[CRED075] -JENNIFER KOLBE +[GTAB_U] +¡Por favor, amigo! ¡No me dejes con ella, esa chica está loca! ¿Amigo? ¡Oye, amigo! ¡Amigo...! -[CRED076] -JENEFER GROSS +{ Mission instructions } -[CRED077] -LAURA PATERSON +[LOVE4_1] +~r~¡El cártel colombiano está aquí! -[CRED078] -JEFF CASTANEDA +[LOVE4_2] +~g~¡El paquete ha desparecido! Síguele la pista a los colombianos y recupéralo. -[CRED079] -CHRIS CARRO +[LOVE4_3] +~g~¿''Panlantic Construction''...? -[CRED080] -ADAM TEDMAN +[LOVE4_7] +~g~Hay una zona en obras en Staunton Island, puede que hayan llevado el paquete allí. -[CRED081] -JUNG KWAK +[LOVE4_4] +~g~¡Lleva el paquete a Donald Love! -[CRED082] -BRIAN WOOD +[LOVE4_5] +~g~El paquete debería estar en la avioneta... -[CRED083] -PAUL YEATES +[LOVE4_6] +~g~¡Usa el ascensor! -[CRED084] -STANTON SARJEANT +[LOVE4_8] +~g~Necesitarás un coche para abrir el garaje. -[CRED085] -VP OF MARKETING +[LOVE4_9] +~r~¡El avión ha sido destruido! -[CRED086] -TERRY DONOVAN +[LOV4_10] +~r~¡La única pista sobre dónde se encuentra el paquete ha sido destruida! -[CRED087] -TECHNICAL COORDINATOR +{ ========================================================================= } +{ ================= MISSION: ESCORT SERVICE (DONALD LOVE) ================= } +{ ========================================================================= } -[CRED088] -BRANDON ROSE +{ TITLE } -[CRED089] -QA MANAGER +[LOVE5] +'SERVICIO DE ESCOLTA' -[CRED090] -JEFF ROSA +{ Premission cutscene } -[CRED091] -LEAD ANALYST +{ Donald Love } -[CRED092] -ADAM DAVIDSON +[LOVE5_A] +Estás demostrando ser una inversión segura, algo muy raro en estos días. -[CRED093] -GAME ANALYST +[LOVE5_B] +Mi amigo oriental necesitará que le escolten mientras comprueba la autenticidad de mi última adquisición. -[CRED094] -RICHARD HUIE +[LOVE5_C] +Quiero que le sigas, asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. -[CRED095] -TEST TEAM +{ Mission instructions } -[CRED096] -LANCE WILLIAMS +[LOVE5_1] +~g~¡En marcha! -[CRED097] -JOE GREENE +[LOVE5_2] +~g~¡Vas a necesitar un coche! -[CRED098] -BRIAN PLANER +[LOVE5_3] +~g~¡Comprueba la salida del túnel! -[CRED099] -OSWALD GREENE +[LOVE5_4] +~r~¡Protege el camión! -[CRED100] -LIBERTY TREE EDITORIAL +[LOVE5_5] +~r~¡No has protegido al camión! -[CRED101] -JAMES WORRALL +{ ================================================================ } +{ ================= MISSION: DECOY (DONALD LOVE) ================= } +{ ================================================================ } -[CRED102] -DAN HOUSER +{ TITLE } -[CRED103] -ADAM TEDMAN +[LOVE6] +'SEÑUELO' -[CRED104] -PAUL YEATES +{ Premission cutscene } -[CRED105] -JENEFER GROSS +{ Donald Love } -[CRED106] -LAURA PATERSON +[LOVE6_A] +Una lección sobre negocios, amigo mío: -[CRED107] -CUT-SCENES +[LOVE6_E] +Si tienes una mercancía única, todo el mundo tratará de arrebatártela, -[CRED108] -SCRIPT BY DAN HOUSER AND JAMES WORRALL +[LOVE6_B] +aun sin conocer su verdadera valía. -[CRED109] -AUDIO DIRECTED BY DAN HOUSER +[LOVE6_C] +Unos SWAT han acordonado la zona donde se encuentran mi socio y el paquete. -[CRED110] -AUDIO PRODUCED BY RENAUD SEBBANE +[LOVE6_D] +Ve allí, recoge la furgoneta y haz de señuelo. -[CRED111] -CAST +[LOVE6_F] +Mantenles ocupados y él podrá escaparse. -[CRED112] -FRANK VINCENT AS SALVATORE LEONE +{ Mission instructions } -[CRED113] -JOE PANTOLIANO AS LUIGI GOTERELLI +[LOVE6_1] +~g~¡Ahora llévate a los policías lejos del almacén! -[CRED114] -MICHAEL MADSEN AS TONI CIPRIANI +[LOVE6_2] +~r~¡No has distraído a la policía! -[CRED115] -MICHAEL RAPAPORT AS JOEY LEONE +[LOVE6_3] +~g~Tienes ~1~ segundos para volver al Securicar antes de fracasar la misión. -[CRED116] -DEBBI MAZAR AS MARIA +[LOVE6_4] +~r~¡Has abandonado el Securicar señuelo! -[CRED117] -KYLE MACLACHAN AS DONALD LOVE +{ =============================================================================== } +{ ================= MISSION: LOVE'S DISAPPEARANCE (DONALD LOVE) ================= } +{ =============================================================================== } -[CRED118] -ROBERT LOGGIA AS RAY MACHOWSKI +{ TITLE } -[CRED119] -GURU AS 8-BALL +[LOVE7] +'LA DESAPARICIÓN DE LOVE' -[CRED120] -SONDRA JAMES AS MOMMA +{ No dialogue or strings } -[CRED121] -LIANA PAI AS ASUKA +{ ============================================================== } +{ ================= MISSION: UZI MONEY (D-ICE) ================= } +{ ============================================================== } -[CRED122] -LES MAU AS KENJI +{ TITLE } -[CRED123] -CYNTHIA FARRELL AS CATALINA +[HM_1] +'PASADA AMETRALLADA' -[CRED124] -AL ESPINOSA AS MIGUEL +{ Pager message that tells the player that D-Ice's missions are now available } -[CRED125] -CHRIS PHILLIPS AS EL BURRO +[HOOD1_A] +Ve al teléfono público de Wichita Gardens y hablaremos de negocios. -[CRED126] -HUNTER PLATIN AS CHICO +{ Premission cutscene } -[CRED127] -WALTER MUDU AS D-ICE +{ D-Ice } -[CRED128] -CURTIS MCCLARIN AS CURTLY +[HM1_A] +¡Ey! ¡Soy D-Ice, de los Red Jacks! -[CRED129] -BILL FIORE AS DARKEL +[HM1_B] +Tengo un problema, me la están liando. -[CRED130] -CHRIS PHILLIPS AS MARTY CHONKS +[HM1_C] +Hay unos macarrillas en la calle que no piensan más que en pistolas y en SPANK. -[CRED131] -HUNTER PLATIN AS CURLY BOB +[HM1_D] +Se llaman ''Nines'', van de púrpura, y cada día en el que se hacen notar -[CRED132] -WALTER MUDU AS KING COURTNEY +[HM1_G] +es otro día más que los Jacks parecemos blandos. -[CRED133] -HUNTER PLATIN AS ONE-ARMED PHIL +[HM1_E] +Quiero que esos mierdecillas sepan lo que es un verdadero tiroteo desde un vehículo. -[CRED134] -KIM GURNEY AS MISTY +[HM1_H] +¡Haz que esos Nines se larguen! -[CRED135] -MOTION CAPTURE +[HM1_F] +Pero ojo, también habrá Jacks que se creerán que vas a por ellos. -[CRED136] -ANIMATED BY +{ Mission instructions } -[CRD136A] -ALEX HORTON +[HM1_1] +~g~Cepíllate a 20 Purple Nines en 2 minutos y 30 segundos. -[CRED137] -DIRECTED BY +[HM1_2] +~g~Hazte con un vehículo y recuerda que sólo cuentan las muertes a tiros desde el coche. -[CRD137A] -NAVID KHONSARI +[HM1_3] +~g~Los Nines tienen su territorio en Wichita Gardens. -[CRED138] -PRODUCED BY +{ =============================================================== } +{ ================= MISSION: TOYMINATOR (D-ICE) ================= } +{ =============================================================== } -[CRD138A] -JAMIE KING +{ TITLE } -[CRD138B] -RENAUD SEBBANE +[HM_2] +'BOMBINATOR' -[CRED139] -RECORDED AT MODERN UPRISING STUDIOS, BROOKLYN +{ Premission cutscene } -[CRED140] -ACTORS +{ D-Ice } -[CRD140A] -RENAUD SEBBANE +[HM2_A] +Los Nines me están presionando. -[CRD140B] -GISELLE JONES +[HM2_B] +Tienen coches blindados y ahora están traficando SPANK -[CRD140C] -STEPHEN DANIELS +[HM2_C] +a los hermanos sin ningún pudor. -[CRD140D] -ROBERT STIO +[HM2_D] +Hay un coche aparcado en la calle. -[CRD140E] -JENNY GROSS. +[HM2_E] +Dentro verás algo que te servirá para poner a esos gallinas en su sitio -[CRED141] -PEDESTRIAN DIALOGUE +[HM2_F] +y cargarte sus blindados. -[CRED142] -WRITTEN BY DAN HOUSER, NAVID KHONSARI & JAMES WORRALL +{ Mission instructions } -[CRED143] -DIRECTED BY CRAIG CONNER, DAN HOUSER AND LAZLOW +[HM2_1] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. -[CRED144] -PRODUCED BY RENAUD SEBBANE +[HM2_1A] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. -[CRED145] -CAST +[HM2_2] +~r~¡No has destruido todos los furgones blindados! -[CRED146] -HUNTER PLATIN +[HM2_6] +~g~¡Te has cargado un furgón blindado! -[CRED147] -DAN HOUSER +[HM2_3] +¡Si golpeas las ruedas de un vehículo, el coche teledirigido estallará! -[CRED148] -RENAUD SEBBANE +[HM2_4] +¡Si el coche teledirigido se sale fuera de cobertura, estallará solo! -[CRED149] -MARIA CHAMBERS +[HM2_5] +~r~¡Te has ido de cobertura! -[CRED150] -JEFF STANTON +{ =================================================================== } +{ ================= MISSION: RIGGED TO BLOW (D-ICE) ================= } +{ =================================================================== } -[CRED151] -RYAN CROY +{ TITLE } -[CRED152] -DEENA BERMAN +[HM_3] +'PREPARADO PARA ESTALLAR' -[CRED153] -MARIA CHAMBERS +{ Premission cutscene } -[CRED154] -ALICE B. SALTZMAN +{ D-Ice } -[CRED155] -ALEX ANTHONY SIOUKAS +[HM3_A] +Algún cazurro me ha puesto una bomba en el coche. -[CRED156] -SEAN R. LYNCH +[HM3_B] +Si lo pierdo, mi reputación en la calle se irá a la porra. -[CRED157] -AMY SALZMAN +[HM3_C] +Coge mi coche y llévalo al taller de Saint Mark's, ¿valiendo? -[CRED158] -COLIN MCSHANE +[HM3_D] +Que se encarguen ellos de desarmar la bomba. -[CRED159] -COREY WADE +[HM3_E] +El tiempo avanza y ese trasto es un peligro. -[CRED160] -GERALD COSGROVE +[HM3_F] +Un golpe más de la cuenta y podría saltar por los aires. -[CRED161] -STEPHANIE ROY +[HM3_G] +¡Tira! -[CRED162] -DORIS WOO +{ Mission instructions } -[CRED163] -JOSEPH GREENE +[HM3_1] +~g~¡Ve al garaje, pero pon atención, porque el coche explotará si se daña demasiado! -[CRED164] -LAZLOW JONES +[HM3_2] +~g~Lleva el coche de vuelta. ¡Tiene que estar inmaculado! -[CRED165] -HSIANG LIN +[HM3_3] +~g~¡Haz que reparen el vehículo! -[CRED166] -STEVE MICHAEL ROBERT +{ ================================================================ } +{ ================= MISSION: BULLION RUN (D-ICE) ================= } +{ ================================================================ } -[CRED167] -MATHEW MURRAY +{ TITLE } -[CRED168] -RICHARD HUIE +[HM_4] +'FIEBRE DEL PLATINO' -[CRED169] -GARVIN ATWELL +{ Premission cutscene } -[CRED170] -STEVE KNEZEVICH +{ D-Ice } -[CRED171] -YUKIMURA SATO +[HM4_A] +Tío, un vuelo de la Reserva Federal se la acaba de pegar en el Aeropuerto Francis. -[CRED172] -FRANK CHAVEZ +[HM4_B] +Hay platino por toda la pista. -[CRED173] -LIEZL JACINTO +[HM4_C] +Consigue un coche y agarra todo lo que puedas. -[CRED174] -CANAAN MCKOY +[HM4_F] +Puedes dejar la mercancía en uno de mis garajes. -[CRED175] -ADAM DAVIDSON +[HM4_G] +El platino pesa un huevo y hará que tu buga vaya a paso de tortuga, -[CRED176] -LANCE WILLIAMS +[HM4_H] +así que ve dejándolo de vez en cuando en el garaje. -[CRED177] -NEIL MCCAFFREY +{ Mission instructions } -[CRED178] -LAURA PATERSON +[HM4_D] +~g~¡Hazte con un vehículo! -[CRED179] -REY CONCEPCION +[HM4_1] +~g~Dirígete al lugar donde está el cargamento. Necesitas conseguir 30 lingotes. -[CRED180] -CHARLES HEROLD +[HM4_2] +~g~Recuerda: cuando el vehículo esté pesado y vaya más despacio, ve al garaje y deja el cargamento. -[CRED181] -ANDREW GREENWALD +[HM4_E] +UNUSED -[CRED182] -JAMES MIELKE +{ =========================================================== } +{ ================= MISSION: RUMBLE (D-ICE) ================= } +{ =========================================================== } -[CRED183] -PETER SUCIU +{ TITLE } -[CRED184] -ALEX ODULIO +[HM_5] +'ENFRENTAMIENTO' -[CRED185] -DON NKRUMAH +{ Premission cutscene } -[CRED186] -KENDALL PITTMAN +{ D-Ice } -[CRED187] -SAL SUAZO +[HM5_A] +Ya solo quedan unos pocos Nines, -[CRED188] -EREK MATEO +[HM5_B] +pero todavía quieren guerra. -[CRED189] -CHRIS DIFATE +[HM5_C] +Han aceptado un mano a mano. -[CRED190] -LEILA MILTON +[HM5_D] +Un puñado de los suyos contra dos de los nuestros, -[CRED191] -DARREN ZOLTOWSKI +[HM5_E] +o más bien, tú y uno más. -[CRED192] -VIRGINIA SMITH +[HM5_F] +Os ayudaría, pero... -[CRED193] -KEVIN CASSIN +[HM5_G] +No quiero jugarme mi libertad condicional, -[CRED194] -JASON SHIGEMORI +[HM5_H] +¿me captas? -[CRED195] -KELLY KINSELLA +[HM5_I] +Reúnete con mi hermano pequeño, -[CRED196] -MOLLIE STICKNEY +[HM5_J] +él te enseñará dónde será la pelea. -[CRED197] -STANTON SARJEANT +{ D-Ice's brother, when the player finds him } -[CRED198] -LAURA WALSH +[HM5_1] +Hola, Ice dijo que vendrías. Las reglas son sólo bates. Cero armas, cero coches. -[CRED199] -MARK GARONE +[HM5_5] +Es una batalla por respeto, ¿vale? -[CRED200] -JOANNA SLY +[HM5_6] +Vamos a partir cabezas... -[CRED201] -ELIZABETH HOWELL +{ Mission instructions } -[CRED202] -ANA HERCULES +[HM5_3] +~r~¡Te han dicho que uses sólo un bate de béisbol! -[CRED203] -SHIRLEY IRICK +[HM5_4] +~r~¡Tu contacto está muerto! -[CRED204] -KASHONA FIELDS +{ ============================================================================= } +{ ================= MISSION: BAIT (ASUKA KASEN, SECOND BATCH) ================= } +{ ============================================================================= } -[CRED205] -JOEL M. LILJE +{ TITLE } -[CRED206] -JOHN DIBENEDETTO +[AS1] +'CEBO' -[CRED207] -NANCY GILES +{ Premission cutscene } -[CRED208] -RYAN CROY +{ Asuka } -[CRED209] -JENNIFER KOLBE +[AS1_A] +Parece que Miguel piensa que le maltrato. -[CRED210] -LIAM BURKE +[AS1_B] +Pero ha revelado cuánto teme Catalina tu búsqueda de venganza. -[CRED211] -SIGRID PREISSL +[AS1_C] +Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty con el único fin de darte caza. -[CRED212] -ANITA FITZSIMONS +[AS1_D] +Haz de cebo y consigue que los escuadrones te sigan hasta Pike Creek, -[CRED213] -PHILIPPA RASELLI +[AS1_E] +donde estarán esperando algunos de mis hombres. -[CRED214] -WIL QUESNEL +{ Mission instructions } -[CRED215] -FALKO BURKERT +[AS1_G] +~r~¡Todos los yakuza están muertos! -[CRED216] -SARA SEWELL +[AS1_H] +~r~¡No has llevado al escuadrón de la muerte hasta la trampa de la yakuza! -[CRED217] -RADIO STATIONS AND MUSIC +{ ======================================================================================= } +{ ================= MISSION: EXPRESSO-2-GO! (ASUKA KASEN, SECOND BATCH) ================= } +{ ======================================================================================= } -[CRED218] -PRODUCERS FOR ROCKSTAR UK +{ TITLE } -[CRD218A] -CRAIG CONNER +[AS2] +'CAFÉ PARA LLEVAR' -[CRD218B] -STUART ROSS +{ Premission cutscene } -[CRED219] -SOUNDTRACK CO-ORDINATOR +{ Asuka } -[CRED220] -TERRY DONOVAN +[AS2_A1] +¡Está claro que Miguel tiene esa famosa resistencia latina! -[CRED221] -PRODUCER FOR ROCKSTAR GAMES +[AS2_A2] +Estoy agotada. -[CRED222] -DAN HOUSER +[AS2_A] +Subestimamos los planes que tiene Catalina para el SPANK. -[CRED223] -EDITED BY +[AS2_B] +Va mucho más allá de hacer que los jamaicanos lo vendan en las esquinas. -[CRED224] -CRAIG CONNER +[AS2_C] +El cártel tiene una tapadera, el Kappa Coffee House. -[CRED225] -ALLAN WALKER +[AS2_D] +Vende SPANK en puestos callejeros. -[CRED226] -LAZLOW +[AS2_E] +No tenemos otra opción más que sabotear esos puntos de venta. -[CRED227] -DJ BANTER AND IMAGING WRITTEN BY +[AS2_F] +¡Redúcelos a cenizas! -[CRED228] -DAN HOUSER +{ Mission instructions } -[CRED229] -LAZLOW +[AS2_1] +~g~¡Todos los puestos de café en Portland han sido destruidos! -[CRED230] -SPECIAL THANKS TO +[AS2_2] +~g~¡Todos los puestos de café en Staunton Island han sido destruidos! -[CRED231] -ADAM TEDMAN +[AS2_3] +~g~¡Todos los puestos de café en Shoreside Vale han sido destruidos! -[CRED232] -ALEX MASON +[AS2_4] +~r~¡El cártel ha avisado a sus camellos! -[CRED233] -JUDY HENDERSON CASTING +[AS2_5] +~g~¡Todavía hay puestos de café en Shoreside Vale y en Staunton Island! -[CRED234] -HAMISH BROWN +[AS2_6] +~g~¡Todavía hay puestos de café en Shoreside Vale! -[CRED235] -CHRISSY HOBAN +[AS2_7] +~g~¡Todavía hay puestos de café en Staunton Island! -[CRED236] -INNES RICARD +[AS2_8] +~g~¡Todavía hay puestos de café en Portland! -[CRED237] -LILION BROZSKA +[AS2_9] +~g~¡Todavía hay puestos de café en Portland y en Shoreside Vale! -[CRED238] -BOB HILLARY +[AS2_10] +~g~¡Todavía hay puestos de café en Portland y en Staunton Island! -[CRED239] -EMILY ANDERSON +[AS2_11] +~g~¡~1~ DE 9! -[CRED240] -RICHIE HENDERSON +[AS2_12] +~g~¡Recorre los distritos de Liberty y busca puestos de café ~b~Espresso-2-Go~g~! -[CRED241] -CHRSTIAN CANTAMESSA +[AS2_12A] +~g~Cuando destruyas el primer puesto, ¡tendrás 8 mintutos antes que el cártel avise a sus camellos! -[CRED242] -JERONIMO BARRERA +{ =============================================================================== } +{ ================= MISSION: S.A.M. (ASUKA KASEN, SECOND BATCH) ================= } +{ =============================================================================== } -[CRED243] -ALEXANDER ILLES +{ TITLE } -[CRED244] -BARANE CHAN +[AS3] +'TIERRA-AIRE' -[CRED245] -DUNCAN SHIELDS +{ Premission cutscene } -[CRED246] -BARANE CHAN +{ Maria } -[CRED247] -DEREK PAYNE +[AS3_A] +¿Lo apretamos un poco más o esperamos a que se vuelva negro y se caiga? -[CRED248] -KEVIN WONG +{ Asuka } -[CRED249] -ROSS ELLIOTT +[AS3_B] +Dale un toque rápido... -[CRED250] +{ Maria } + +[AS3_C] +¡Buaj! ¿Qué es esa cosa amarilla pegajosa? + +[AS3_C1] +¡Hola, guapo! + +{ Asuka } + +[AS3_D] +¡Mi manitas! + +{ Maria } + +[AS3_E] +Me aburría, así que vine a hacerle compañía a Asuka. + +{ Asuka } + +[AS3_F] +Esta chica tiene un talento nato para la tortura. + +[AS3_F1] +Se las ha arreglado para extraerle esta joyita a nuestro invitado. + +[AS3_G] +Hay una avioneta que llegará al Aeropuerto Francis en dos horas. + +[AS3_G1] +Está lleno del veneno de Catalina. + +[AS3_H] +Podrás evitar la seguridad del aeropuerto si conduces una lancha hasta las boyas luminosas, + +[AS3_H1] +así podrás disparar a la avioneta al aterrizar. + +[AS3_I] +¡Recoge el cargamento de entre los escombros y tráelo! + +{ Maria } + +[AS3_J] +Ten cuidado, guapo, ¿vale? + +{ Asuka } + +[AS3_K] +Ahora prueba con el aceite picante... + +{ Mission instructions } + +[AS3_1] +~g~¡Busca una ~r~lancha~g~ y ve a la ~b~boya señalada! + +[AS3_1A] +~g~¡Ahora ve a la ~b~boya señalada~g~! + +[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 + +[STASH] +~g~¡Lleva el SPANK de vuelta a la ~p~zona en obras~g~! + +{ ============================================================== } +{ ================= MISSION: RANSOM (CATALINA) ================= } +{ ============================================================== } + +{ TITLE } + +[AS4] +'RESCATE' + +[CAT1] +'RESCATE' + +{ Cutscene } + +{ Catalina (letter, colombiana) } + +[CAT1_A] +Tengo a tu linda María. Si no quieres que parezca que un carnicero se ensañó con ella, + +[CAT1_B] +lleva 500.000 dólares a la mansión de Cedar Grove. + +{ Mission instructions } + +[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. + +[CAT1_E] +XXXX + +{ ==================================================================== } +{ ================= MISSION: THE EXCHANGE (CATALINA) ================= } +{ ==================================================================== } + +{ TITLE } + +[CAT2] +'EL INTERCAMBIO' + +{ Premission cutscene } + +{ Catalina (colombiana) } + +[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_A1] +¡Vamos, perra! + +{ Cutscene, after reaching Catalina at the dam } + +{ Catalina (colombiana) } + +[CAT2_J] +¡Despega de una vez! + +{ Mission instructions } + +[CATINF1] +~g~¡Liquida a Catalina! + +[CATINF2] +~g~Sigue al helicóptero para encontrar a Catalina. + +[BITCH_D] +~g~¡María está muerta! + +{ =================================================== } +{ ================= ENDING CUTSCENE ================= } +{ =================================================== } + +{ Libery City News broadcaster } + +[END_A] +Los residentes de Cedar Groove todavía están asumiendo + +[END_B] +las consecuencias emocionales provocadas + +[END_C] +por la guerra que estalló ayer en la zona. + +[END_D] +Un residente local, Clive Denver, dijo a la policía + +[END_E] +que vio a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. + +{ Maria } + +[END_F] +¿Sabes? Vamos a pasar un buen rato, porque, como sabes... + +[END_G] +¡Te amo! Yo, yo, yo realmente te amo, porque eres superfuerte, + +[END_H] +y eso es todo lo que necesito. + +[END_I] +Bueno, ¿qué estaba diciendo? + +[END_J] +Lo he olvidado. Pero me entiendes, ¿verdad? + +{ Libery City News broadcaster } + +[END_K] +Las explosiones sacudieron las casas más próximas y a sus residentes. + +[END_L] +Varios ciudadanos resultaron heridos a causa del tiroteo + +[END_M] +entre las fuerzas terrestres y un helicóptero que rodeaba a la presa. + +{ Male witness } + +[END_N] +Sí, en estos jardínes tuvimos una vista excelente. + +[END_O] +Cuando el helicóptero estalló, + +[END_P] +fue mejor que los fuegos artificiales del 4 de julio. + +{ Libery City News broadcaster } + +[END_Q] +El número de víctimas asciende a las veinte + +[END_R] +mientras la policía sigue encontrando cuerpos. + +[END_S] +No se han negado oficialmente los rumores + +[END_T] +de que las víctimas eran miembros del cártel colombiano, + +[END_U] +y aún no hay pistas que aclaren las causas de la masacre. + +{ Maria } + +[END_V] +Me he roto una uña y me pelo está hecho un asco, ¿puedes creerlo? + +[END_W] +Me costó cincuenta dólares... + +{ Duplicates of Maria's dialogue, possibly unused } + +[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! + +[CAT2_G] +Estaba muerta de miedo, pero luego me dije a mí misma: ''Ya eres mayorcita''. + +[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... + +{ =================================================================================================================== } +{ =================================================================================================================== } +{ ================================================== GAME CREDITS =================================================== } +{ =================================================================================================================== } +{ =================================================================================================================== } + +[CRED001] +ROCKSTAR STUDIOS + +[CRED002] +PRODUCTOR + +[CRED003] +LESLIE BENZIES + +[CRED004] +DIRECTOR DE ARTE + +[CRED005] +AARON GARBUT + +[CRED006] +DIRECCIÓN TÉCNICA + +[CRED007] +OBBE VERMEIJ + +[CRED008] +ADAM FOWLER + +[CRED009] +DISEÑO + +[CRED010] +CRAIG FILSHIE + +[CRED011] +WILLIAM MILLS + +[CRED012] +CHRIS ROTHWELL + +[CRED013] +JAMES WORRALL + +[CRED014] +GUIÓN + +[CRED015] +JAMES WORRALL + +[CRED016] +PAUL KUROWSKI + +[CRED017] +DAN HOUSER + +[CRED018] +PERSONAJES + +[CRED019] +IAN MCQUE + +[CRED020] +ANIMACIÓN Y DIRECCIÓN + +[CRED021] +ALEX HORTON + +[CRED022] +LEE MONTGOMERY + +[CRED023] +AUTO DESIGN + +[CRED024] +PAUL KUROWSKI + +[CRED025] +ARTISTAS + +[CRED026] +KEIRAN BAILLIE + +[CRED027] +ADAM COCHRANE + +[CRED028] +GARY MCADAM + +[CRED029] +MICHAEL PIRSO + +[CRED030] +ANDREW SOOSAY + +[CRED031] +ALISDAIR WOOD + +[CRED032] +PROGRAMADORES + +[CRED033] +ALAN CAMPBELL + +[CRED034] +MARK HANLON + +[CRED035] +ANDRZEJ MADAJCZYK + +[CRED036] +ALEXANDER ROGER + +[CRED037] +GRAEME WILLIAMSON + +[CRED038] +MÚSICA + +[CRED039] +CRAIG CONNER + +[CRED040] +STUART ROSS + +[CRED041] +DISEÑO DE SONIDO Y MASTERIZADO + +[CRED042] +ALLAN WALKER + +[CRED043] +PROGRAMACIÓN DE AUDIO + +[CRED044] +RAYMOND USHER + +[CRED045] +DIRECTOR DE PRUEBAS + +[CRED046] +CRAIG ARBUTHNOTT + +[CRED047] +JEFES DE PRUEBAS + +[CRED048] +ANDY DUTHIE + +[CRED049] +JOHN HAIME + +[CRED050] +NEIL CORBETT + +[CRD050A] +PROBADORES + +[CRED051] +GRAEME JENNINGS + +[CRED052] +DAVID MURDOCH + +[CRED053] +DAVID BEDDOES + +[CRED054] +EDWIN SMITH + +[CRED055] +MARK FLETT + +[CRED056] +MICHAEL SUTHERLAND + +[CRED057] +SOPORTE TÉCNICO + +[CRED058] +LORRAINE ROY + +[CRED059] +CHRISTINE CHALMERS + +[CRED060] +ROCKSTAR + +[CRED061] +PRODUCTOR EJECUTIVO + +[CRED062] +SAM HOUSER + +[CRED063] +PRODUCTOR + +[CRED064] +DAN HOUSER + +[CRED065] +DIRECTOR DE DESARROLLO + +[CRED066] +JAMIE KING + +[CRED067] +PRODUCTOR TÉCNICO + +[CRED068] +GARY J. FOREMAN + +[CRED069] +PRODUCTOR ASOCIADO + +[CRED070] +JEREMY POPE + +[CRED071] +SUPERVISOR MUSICAL + +[CRED072] +TERRY DONOVAN + +[CRED073] +EQUIPO DE PRODUCCIÓN DE ROCKSTAR + +[CRED074] +TERRY DONOVAN + +[CRED075] +JENNIFER KOLBE + +[CRED076] +JENEFER GROSS + +[CRED077] +LAURA PATERSON + +[CRED078] +JEFF CASTANEDA + +[CRED079] +CHRIS CARRO + +[CRED080] +ADAM TEDMAN + +[CRED081] +JUNG KWAK + +[CRED082] +BRIAN WOOD + +[CRED083] +PAUL YEATES + +[CRED084] +STANTON SARJEANT + +[CRED085] +VICEPRESIDENTE DE MÁRKETING + +[CRED086] +TERRY DONOVAN + +[CRED087] +COORDINADOR TÉCNICO + +[CRED088] +BRANDON ROSE + +[CRED089] +DIRECTOR DE C.C. + +[CRED090] +JEFF ROSA + +[CRED091] +JEFE DE ANÁLISIS + +[CRED092] +ADAM DAVIDSON + +[CRED093] +ANALISTA DEL JUEGO + +[CRED094] +RICHARD HUIE + +[CRED095] +EQUIPO DE PRUEBAS + +[CRED096] +LANCE WILLIAMS + +[CRED097] +JOE GREENE + +[CRED098] +BRIAN PLANER + +[CRED099] +OSWALD GREENE + +[CRED100] +EDITORIAL DEL LIBERTY TREE + +[CRED101] +JAMES WORRALL + +[CRED102] +DAN HOUSER + +[CRED103] +ADAM TEDMAN + +[CRED104] +PAUL YEATES + +[CRED105] +JENEFER GROSS + +[CRED106] +LAURA PATERSON + +[CRED107] +CINEMÁTICAS + +[CRED108] +GUIÓN DE DAN HOUSER Y JAMES WORRALL + +[CRED109] +AUDIO DIRIGIDO POR DAN HOUSER + +[CRED110] +AUDIO PRODUCIDO POR RENAUD SEBBANE + +[CRED111] +REPARTO + +[CRED112] +FRANK VINCENT COMO SALVATORE LEONE + +[CRED113] +JOE PANTOLIANO COMO LUIGI GOTERELLI + +[CRED114] +MICHAEL MADSEN COMO TONI CIPRIANI + +[CRED115] +MICHAEL RAPAPORT COMO JOEY LEONE + +[CRED116] +DEBBI MAZAR COMO MARÍA + +[CRED117] +KYLE MACLACHAN COMO DONALD LOVE + +[CRED118] +ROBERT LOGGIA COMO RAY MACHOWSKI + +[CRED119] +GURU COMO 8-BALL + +[CRED120] +SONDRA JAMES COMO MAMMA + +[CRED121] +LIANA PAI COMO ASUKA + +[CRED122] +LES MAU COMO KENJI + +[CRED123] +CYNTHIA FARRELL COMO CATALINA + +[CRED124] +AL ESPINOSA COMO MIGUEL + +[CRED125] +CHRIS PHILLIPS COMO EL BURRO + +[CRED126] +HUNTER PLATIN COMO CHICO + +[CRED127] +WALTER MUDU COMO D-ICE + +[CRED128] +CURTIS MCCLARIN COMO CURTLY + +[CRED129] +BILL FIORE COMO DARKEL + +[CRED130] +CHRIS PHILLIPS COMO MARTY CHONKS + +[CRED131] +HUNTER PLATIN COMO CURLY BOB + +[CRED132] +WALTER MUDU COMO KING COURTNEY + +[CRED133] +HUNTER PLATIN COMO ONE-ARMED PHIL + +[CRED134] +KIM GURNEY COMO MISTY + +[CRED135] +CAPTURA DE MOVIMIENTOS + +[CRED136] +ANIMACIÓN + +[CRD136A] +ALEX HORTON + +[CRED137] +DIRECCIÓN + +[CRD137A] +NAVID KHONSARI + +[CRED138] +PRODUCCIÓN + +[CRD138A] +JAMIE KING + +[CRD138B] +RENAUD SEBBANE + +[CRED139] +GRABADA EN MODERN UPRISING STUDIOS, BROOKLYN + +[CRED140] +ACTORES + +[CRD140A] +RENAUD SEBBANE + +[CRD140B] +GISELLE JONES + +[CRD140C] +STEPHEN DANIELS + +[CRD140D] +ROBERT STIO + +[CRD140E] +JENNY GROSS + +[CRED141] +DIÁLOGO DE PEATONES + +[CRED142] +ESCRITO POR DAN HOUSER, NAVID KHONSARI Y JAMES WORRALL + +[CRED143] +DIRIGIDO POR CRAIG CONNER, DAN HOUSER Y LAZLOW + +[CRED144] +PRODUCIDO POR RENAUD SEBBANE + +[CRED145] +REPARTO + +[CRED146] +HUNTER PLATIN + +[CRED147] +DAN HOUSER + +[CRED148] +RENAUD SEBBANE + +[CRED149] +MARIA CHAMBERS + +[CRED150] +JEFF STANTON + +[CRED151] +RYAN CROY + +[CRED152] +DEENA BERMAN + +[CRED153] +MARIA CHAMBERS + +[CRED154] +ALICE B. SALTZMAN + +[CRED155] +ALEX ANTHONY SIOUKAS + +[CRED156] +SEAN R. LYNCH + +[CRED157] +AMY SALZMAN + +[CRED158] +COLIN MCSHANE + +[CRED159] +COREY WADE + +[CRED160] +GERALD COSGROVE + +[CRED161] +STEPHANIE ROY + +[CRED162] +DORIS WOO + +[CRED163] +JOSEPH GREENE + +[CRED164] +LAZLOW JONES + +[CRED165] +HSIANG LIN + +[CRED166] +STEVE MICHAEL ROBERT + +[CRED167] +MATHEW MURRAY + +[CRED168] +RICHARD HUIE + +[CRED169] +GARVIN ATWELL + +[CRED170] +STEVE KNEZEVICH + +[CRED171] +YUKIMURA SATO + +[CRED172] +FRANK CHAVEZ + +[CRED173] +LIEZL JACINTO + +[CRED174] +CANAAN MCKOY + +[CRED175] +ADAM DAVIDSON + +[CRED176] +LANCE WILLIAMS + +[CRED177] +NEIL MCCAFFREY + +[CRED178] +LAURA PATERSON + +[CRED179] +REY CONCEPCION + +[CRED180] +CHARLES HEROLD + +[CRED181] +ANDREW GREENWALD + +[CRED182] +JAMES MIELKE + +[CRED183] +PETER SUCIU + +[CRED184] +ALEX ODULIO + +[CRED185] +DON NKRUMAH + +[CRED186] +KENDALL PITTMAN + +[CRED187] +SAL SUAZO + +[CRED188] +EREK MATEO + +[CRED189] +CHRIS DIFATE + +[CRED190] +LEILA MILTON + +[CRED191] +DARREN ZOLTOWSKI + +[CRED192] +VIRGINIA SMITH + +[CRED193] +KEVIN CASSIN + +[CRED194] +JASON SHIGEMORI + +[CRED195] +KELLY KINSELLA + +[CRED196] +MOLLIE STICKNEY + +[CRED197] +STANTON SARJEANT + +[CRED198] +LAURA WALSH + +[CRED199] +MARK GARONE + +[CRED200] +JOANNA SLY + +[CRED201] +ELIZABETH HOWELL + +[CRED202] +ANA HERCULES + +[CRED203] +SHIRLEY IRICK + +[CRED204] +KASHONA FIELDS + +[CRED205] +JOEL M. LILJE + +[CRED206] +JOHN DIBENEDETTO + +[CRED207] +NANCY GILES + +[CRED208] +RYAN CROY + +[CRED209] +JENNIFER KOLBE + +[CRED210] +LIAM BURKE + +[CRED211] +SIGRID PREISSL + +[CRED212] +ANITA FITZSIMONS + +[CRED213] +PHILIPPA RASELLI + +[CRED214] +WIL QUESNEL + +[CRED215] +FALKO BURKERT + +[CRED216] +SARA SEWELL + +[CRED217] +EMISORAS DE RADIO Y MÚSICA + +[CRED218] +PRODUCTORES DE ROCKSTAR REINO UNIDO + +[CRD218A] +CRAIG CONNER + +[CRD218B] +STUART ROSS + +[CRED219] +COORDINADOR DE BANDA SONORA + +[CRED220] +TERRY DONOVAN + +[CRED221] +PRODUCTOR DE ROCKSTAR GAMES + +[CRED222] +DAN HOUSER + +[CRED223] +EDICIÓN + +[CRED224] +CRAIG CONNER + +[CRED225] +ALLAN WALKER + +[CRED226] +LAZLOW + +[CRED227] +GUIÓN DE LOCUTORES Y ANUNCIOS + +[CRED228] +DAN HOUSER + +[CRED229] +LAZLOW + +[CRED230] +AGRADECIMIENTOS ESPECIALES + +[CRED231] +ADAM TEDMAN + +[CRED232] +ALEX MASON + +[CRED233] +JUDY HENDERSON CASTING + +[CRED234] +HAMISH BROWN + +[CRED235] +CHRISSY HOBAN + +[CRED236] +INNES RICARD + +[CRED237] +LILION BROZSKA + +[CRED238] +BOB HILLARY + +[CRED239] +EMILY ANDERSON + +[CRED240] +RICHIE HENDERSON + +[CRED241] +CHRISTIAN CANTAMESSA + +[CRED242] +JERONIMO BARRERA + +[CRED243] +ALEXANDER ILLES + +[CRED244] +BARANE CHAN + +[CRED245] +DUNCAN SHIELDS + +[CRED246] +BARANE CHAN + +[CRED247] +DEREK PAYNE + +[CRED248] +KEVIN WONG + +[CRED249] +ROSS ELLIOTT + +[CRED250] ROSS BEAZLEY -[CRED251] -ALEX BAZLINTON +[CRED251] +ALEX BAZLINTON + +[CRED252] +DAVE WATSON + +[CRED253] +MALCOLM SMITH + +[CRED254] +JEFE DEL ESTUDIO + +[CRED255] +ANDREW SEMPLE + +[CRED256] +ARTISTAS + +[CRED257] +STUART PETRI + +[CRED258] +JERONIMO BARRERA + +[CRED259] +CARLY SLATER + +[CRED260] +GREG LAU + +[CRED261] +STEVE KNEZEVICH + +[CRED262] +DEVIN WINTERBOTTOM + +[CRED263] +JAMEEL VEGA + +[CRED264] +LEE CUMMINGS + +[CRED265] +DEVIN BENNET + +[CRED266] +ELIZABETH SATTERWHITE + +[CRED267] +AARON RIGBY + +[CRED268] +STEVE K. + +[CRED269] +GREG LAU + +[CRED270] +MIKE HONG + +{ =================================================================================================================== } +{ =================================================================================================================== } +{ ================================================ INTERFACE STRINGS ================================================ } +{ =================================================================================================================== } +{ =================================================================================================================== } + +{ ================================================================ } +{ ================= PAUSE MENU OPTIONS (CONSOLE) ================= } +{ ================================================================ } + +[FEB_STA] +Estadísticas + +[FEB_BRI] +Resumen + +[FEB_CON] +Controles + +[FEB_AUD] +Sonido + +[FEB_DIS] +Pantalla + +[FEB_LAN] +Idioma + +[FEB_SAV] +Cargar + +[FEB_CPC] +Configuración de controles + +[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 MENÚ + +[FEDS_AS] +;= - CAMBIAR SELECCIÓN + +[FEDSAS2] +<> - CAMBIAR SELECCIÓN + +[FEDSAS3] +- CAMBIAR SELECCIÓN + +[FEDSAS4] +;=<> - CAMBIAR SELECCIÓN + +[FEDS_SS] +L1,R1 - CAMBIAR SELECCIÓN + +[FEDSSC1] +; - ACELERAR + +[FEDSSC2] += - RALENTIZAR + +[FEDS_SE] +Botón / - ELEGIR + +[FEDS_SB] +Botón / - ELEGIR Botón " - VOLVER + +[FEDS_BA] +Botón " - VOLVER + +[FEDS_TB] +ATRÁS + +{ INTERFACE ARROWS } + +[FEA_UP] +; + +[FEA_DO] += + +[FEA_LE] +< -[CRED252] -DAVE WATSON +[FEA_RI] +> -[CRED253] -MALCOLM SMITH +{ ================================================================================ } +{ ================= REMNANTS FROM THE CONSOLE PAUSE MENU OPTIONS ================= } +{ ================================================================================ } -[CRED255] -ANDREW SEMPLE +[FES_LGA] +Cargar partida -[CRED256] -ARTIST +[FES_NGA] +Nueva partida -[CRED257] -STUART PETRI +[PRVMEN] +Resúmenes de misiones anteriores + +[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 + +[ENGLIS] +Inglés + +[GERMAN] +Alemán + +[ITALIA] +Italiano + +[FRENCH] +Francés + +[SPAIN] +Español + +[FESZ_SA] +Guardar partida + +[FES_SLO] +ARCHIVO + +[FES_ISF] +NO PRESENTE + +[FES_SAG] +PRESENTE + +[FES_ISC] +ESTÁ DAÑADO + +[FESZ_TI] +ARCHIVO Z1 + +{ =================================================================== } +{ ================= PLAYSTATION 2 EXCLUSIVE PROMPTS ================= } +{ =================================================================== } + +[P1INSA] +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 tiene ~1~ KB de espacio disponible. Necesitas ~1~ KB para guardar. + +[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. + +[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 -[CRED258] -JERONIMO BARRERA +[FEC_BRA] +Freno o marcha atrás -[CRED259] -CARLY SLATER +[FEC_ACC] +Acelerar -[CRED260] -GREG LAU +[FEC_SMT] +Activar misión especial -[CRED261] -STEVE KNEZEVICH +[FEC_EXV] +Entrar/salir de vehículo -[CRED262] -DEVIN WINTERBOTTOM +[FEC_PED] +Controles a pie -[CRED263] -JAMEEL VEGA +[FEC_VEH] +Controles en vehículos -[CRED264] -LEE CUMMINGS +[FEC_FPR] +Controles en primera persona -[CRED265] -DEVIN BENNET +[FEC_CMM] +Controles comunes -[CRED266] -ELIZABETH SATTERWHITE +[FEC_PWL] +Ir a la izquierda -[CRED267] -AARON RIGBY +[FEC_PWR] +Ir a la derecha -[CRED268] -STEVE K. +[FEC_PWF] +Andar hacia delante -[CRED269] -GREG LAU +[FEC_PWT] +Andar hacia la cámara -[CINCAM] -Cámara Cinemática +[FEC_PLB] +Mirar hacia atrás -[KM1_13] -Lleva el vehículo al garaje! +[FEC_PFR] +Disparar arma -[KM3_14] -~r~¡Has sido ubicado, se rompió el trato!! +[FEC_LKT] +Fijar objetivo -[EBAL_H] -Espera aquí tío, mientras voy y hablo con Luigi. +[FEC_PJP] +Saltar a pie -[EBAL_M] -¡Recuerda que nadie se mete con mis chicas! +[FEC_PSP] +Esprintar a pie -[LM2_F] -Entonces coge su coche y repíntalo. +[FEC_PSH] +Disparar a pie -[LM2_D] -aquí, aquí, cógelo. +[FEC_TLF] +Objetivo a la izq. -[LM1_9] -Hola, soy Misty. +[FEC_TRG] +Objetivo a la dcha. -[LM4_A] -Algún Diablo mal nacido ha estado vendiendo a sus putitas en mi patio de atrás. +[FEC_CCM] +Centrar cámara tras jugador -[FM2_B] -¡Nos hicimos con una rata! +[FEC_SZI] +Acercar zoom de fusil -[FM2_C] -No está ni 'chuleando' ni 'traficando' así que debe de estar hablando. +[FEC_SZO] +Alejar zoom de fusil -[FM3_CC] -~w~Regresa, hermano, cuando tengas el dinero. +[FEC_LKL] +Mirar izq. en primera persona -[FEDS_AM] -<>- CAMBIAR MENU +[FEC_LRT] +Mirar dcha. en primera persona -[LOVE5_5] -~r~¡Fallaste protegiendo el camión! +[FEC_LUP] +Mirar arr. en primera persona -[RM6_6] -~r~¡Ray está muerto! +[FEC_LDN] +Mirar abj. en primera persona -[RM6_7] -~r~¡Ray ha perdido su avión! +[FEC_LBH] +Mirar hacia atrás en vehículo -[RM6_8] -~g~Has dejado atrás a Ray, vuelve a por él. +[FEC_LLF] +Mirar a la izq. en vehículo -[FM1_10] -~g~Has dejado atrás a María, vuelve y recógela. +[FEC_LRG] +Mirar a la dch. en vehículo -[LOVE4_9] -~r~¡El avión ha sido destrozado! +[FEC_HBR] +Freno de mano del vehículo -[LOV4_10] -~r~¡La única pista del lugar donde está el paquete ha sido destruída! +[FEC_ACL] +Acelerar vehículo -[KM2_D] -No hace falta decir que debemos darle los coches como un regalo, para pagar la deduda que tenemos con él. +[FEC_BRK] +Frenar vehículo -[KM4_B] -El negocio es lo suficientemente afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. +[FEC_TSM] +Misiones secundarias -[KM2_E] -Debes obtener los coches de la lista y llevarlos a un garaje detrás del aparcamiento de Newport. +[FEC_CRD] +Cambiar emisora de radio -[FM3_8I] -~w~Consigue una posición ventajosa, entonces entraré cuando dispares el primer tiro. +[FEC_ENT] +Entrar /salir de vehículo -[LOVE1_B] -La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, +[FEC_WPN] +Disparar arma -[LOVE1_H] -pero los grupos de hombres se hacen ambiciosos. +[FEC_FPO] +Armas en primera persona -[LOVE1_C] -Un valioso recurso, un viejo caballero oriental que conozco, +[FEC_SMS] +Mostrar puntero del ratón -[LOVE1_I] -ha sido tomado prisionero por unos sudamericanos en Aspatria. +[FEC_CMS] +Cambiar cámara en todas las situaciones -[MEA4_D] -He aceptado verle... +[FEC_TSS] +Capturar pantalla -[MEA4_B4] -Marty te envió, ¿ahh?. VALE, voy a enseñar a ese asqueroso el significado de la palabra negocio. +[FEC_NTR] +Siguiente objetivo -[MEA4_B5] -¡Carl, hola! y eehh... necesito más tiempo para conseguir tu dinero. +[FEC_PTT] +Objetivo anterior -[MEA1_B4] -Ah, el Sr. Chonks te envió, ¿verdad?. Vamos a hacerle una visita al amiguete. +[FEC_CEN] +Centrar cámara -[HM5_6] -Vamos a romperle el cuello a algún que otro mamón. +[FEC_UND] +(NO) -[LOVE1_5] -~g~Deja de perder el tiempo, hazte con un coche de la mafia Colombiana y rescata al socio de Love. +[FET_CFT] +A PIE -[AS1_D] -~w~Actúa como cebo y consigue que los escuadrones de la muerte te sigan hasta Pike Creek. +[FET_CCR] +EN VEHÍCULO -[AS1_E] -~w~donde algunos de mis hombres estarán esperándoles. +[FEC_TFL] +Torreta a izq. -[AS2_C] -~w~el Cartel tiene una compañía de tapadera, el Kappa Coffe House. +[FEC_TFR] +Torreta a dcha. -[AS2_E] -~w~No tenemos otra opción que poner esos puntos de venta de droga fuera de servicio. +[FEC_ORR] +o -[AS2_F] -~w~¡¡Redúcelos a astillas!! +[FEC_NUS] +SIN USO -[AS2_A1] -~w~Ciertamente Miguel tiene algo de esa famosa resistencia latina. +[FEC_LUD] +Mirar arriba -[AS2_A2] -~w~Estoy muy agotado. +[FEC_LDU] +Mirar abajo -[SIREN_3] -Para conectar las sirenas de este vehículo pulsa el ~h~ botón ~k~~VEHICLE_HORN~ ~w~. +{ ======================================================================================= } +{ ================= CONTROLS MENU, ACTIONS (REMNANTS FROM CONSOLE, PS2) ================= } +{ ======================================================================================= } -[SIREN_4] -Para conectar las sirenas de este vehículo golpea el ~h~ botón ~k~~VEHICLE_HORN~ ~w~. +[FEC_CWL] +Siguiente arma -[AS3_C] -~w~¡Eeeeeeyoooo! ¿Qué ES esa cosa amarilla pegajosa? +[FEC_CWR] +Arma anterior -[AS3_C1] -~w~Oh, hola nena. +[FEC_LOF] +Mirar hacia delante -[AS3_F] -~w~Tiene los atributos de una chica muy natural, esta nena. +[FEC_PAU] +Pausa -[AS3_F1] -~w~Se las ha arreglado para quitarle esta pequeña joya a nuestro invitado. +[FEC_JUM] +Saltar -[AS3_G] -~w~Hay un avión que está llegando al Francis International en 2 horas. +[FEC_ATT] +Atacar o disparar -[AS3_G1] -~w~Está lleno de veneno de Catalina. +[FEC_FPC] +Cámara en primera persona -[AS3_H] -~w~Puedes evitar la seguridad del aeropuerto sacando un bote hasta las boyas luminosas. +[FEC_VES] +Controlar vehículo -[AS3_H1] -y disparando al avión en su aterrizaje. +[FEC_TUC] +Controlar torreta -[AS3_I] -~w~¡Recoge el cargamento de los escombros! +[FEC_SM3] +Activar misión secundaria (botón R3) -[AS3_J] -~w~Oh, ten cuidado ahora, ¿VALE nena? +[FEC_RS3] +Cambiar emisora de radio (botón L3) -[AS3_K] -~w~Ahora prueba el aceite picante... +[FEC_HOR] +Claxon -[RM2_F1] -¡Esos colombianos estarán aquí en cualquier momento! +[FEC_HO3] +Claxon (botón L3) -[RM2_K] -Maldición, ¡¡están aquí!! ¡¡ECHA EL PESTILLO Y CARGA!! +[FEC_LB3] +Mirar atrás -[LOVE2_7] -~g~ ¡Ahora tira el coche! +[FEC_R3] +(botón R3) -[LOVE2_8] -~g~¡Ahora sal de Newport! +[FEC_LB1] +Mirar -[AM1_F] -Salvatore Leone saldrá de Luigis a eso de las (~1~: ~1~). +[FEC_LB2] +atrás -[LOVE5_C] -Quiero que le sigas, y asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. +[FEC_CAW] +Arma del vehículo -[FESZ_SR] -¡Error al guardar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +[FEC_HAB] +Freno de mano -[FESZ_FO] -¿Deseas formatear la memory card (PS2) en la ranura de MEMORY CARD 1? +{ ================================================================== } +{ ================= DEBUG STRINGS (CAN BE IGNORED) ================= } +{ ================================================================== } -[FELZ_FO] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. +[FEC_DBG] +MENÚ DE DEPURACIÓN -[FES_NOC] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. +[FED_DBG] +Menú de depuración -[FES_LOE] -¡Error al cargar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +[FED_RID] +Recargar IDE -[FES_DEE] -¡Error al borrar! Comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +[FED_RIP] +Recargar IPL -[FORSUC] -Memory card (PS2) de la ranura de MEMORY CARD 1 formateada con éxito. +[FED_PAH] +Analizar pila -[ERFOUN] -¡Error al formatear la memory card (PS2)! +[FED_RCD] +CCullZones::RecalculateCullZoneData -[ERMCNP] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. +[FED_DFL] +CTheScripts::DbgFlag -[SVMEM1] -Guardar en la memory card (PS2) de la ranura de MEMORY CARD 1. +[FED_DLS] +Cambiar luz blanca grande de depuración -[FORSLO] -Formatear memory card (PS2) de la ranura de MEMORY CARD 1. +[FED_SPR] +Mostrar grupos de peatones en carretera -[SLONFM] -¡Error al formatear la memory card (PS2)! +[FED_SCR] +Mostrar grupos de vehículos en carretera -[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. +[FED_SCZ] +Mostrar zonas de máscara selectiva -[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. +[FED_DSR] +Solicitudes de depuración de streaming -[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. +[FED_SCP] +gbShowCollisionPolys -[FES_ISF] -NO PRESENTE +[FEM_MCM] +Menú de Memory Card -[FES_SAG] -PRESENTE +[FEM_RMC] +Registrar MemCard uno -[SLONNO] -No hay memory card (PS2) en la ranura de MEMORY CARD 1. +[FEM_TFM] +Probar MemCard uno formateada -[SLONNF] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. +[FEM_TUM] +Probar Memcard uno sin formato -[FESZ_FM] -La memory card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. ¿Deseas formatear la memory card (PS2)? +[FEM_CRD] +Crear directorio raíz -[FESZ_FF] -Error al formatear! Por favor comprueba la memory card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. +[FEM_CLI] +Crear y cargar iconos -[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) +[FEM_FFF] +Llenar primer archivo con basura -[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) +[FEM_SOG] +Guardar sólo partida -[FESZ_WR] -Guardando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. +[FEM_CES] +Comprobar cada guardado de 0kB4 -[FESZ_OW] -Sobrescribiendo datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. +[FEM_STG] +Guardar partida -[FELD_WR] -Cargando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. +[FEM_STS] +Guardar partida bajo el nombre GTA3 -[FEDL_WR] -Borrando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. +[FEM_CPD] +Crear copia protegida del directorio mag -[LM2_C] -Luigi dijo que, que te diera esto y así... +[FEM_MC2] +Menú de Memory Card 2 -[LM3_G] -Joey no es a quien estabas esperando, ¿recuerdas?, tienes el pie en la puerta... +[FEM_TS] +Prueba de guardado: -[LM5_E] -Consigue tanto dinero como puedas antes de que los policías se lo metan en el bolsillo. +[FEM_TL] +Prueba de carga: -[JM5_C] -De acuerdo, hay un coche cargado con un fiambre en el café cercano a Callahan Point. +[FEM_TD] +Prueba de borrado: -[RM2_B] -Tuvimos acción en Nicaragua, en aquellos tiempos cuando el país sabía lo que estaba haciendo +[RELIDE] +ReLoadIde -[RM2_C] -Algunos cerdos del Cartel le asustaron ayer, y dijeron que volverían hoy para quitarle parte de su almacén. +[RELIPE] +ReLoadIpl -[RM2_D1] -Iría yo mismo pero la vieja ciática está molestándome otra vez -achís, achís-, esto, ehhh... buena suerte. +[PARSHP] +Analizar pila -[CATINF1] -~g~¡Captura a Catalina! +[DBGFON] +CTheScripts::DbgFlag activado -[CATINF2] -~g~Sigue al helicóptero para encontrar a Catalina. +[DBFOFF] +CTheScripts::DbgFlag desactivado -[BOATIN1] -Sube a un bote y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +[BGWHON] +Luz blanca grande de depuración activada -[BOATIN2] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote para abordarlo. +[BGWOFF] +Luz blanca grande de depuración desactivada -[BOATIN3] -Sube a un bote y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +[DSTRON] +Solicitudes de depuración de streaming activadas -[BOATIN4] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de un bote para abordarlo. +[DSTROFF] +Solicitudes de depuración de streaming desactivadas -[JM6] -'LA HUÍDA' +[PDRGON] +ShowPedRoadGroups activado -[FM1] -'CARABINA' +[PRGOFF] +ShowPedRoadGroups desactivado -[JM1] -'EL ULTIMO ALMUERZO DE 'MIKE 'LABIOS' +[CRRGON] +ShowCarRoadGroups activado -[FM21] -'BOMBARDEA ESA BASE: ACTO I' +[CRGOFF] +ShowCarRoadGroups desactivado -[FM3] -'BOMBARDEA ESA BASE: ACTO II' +[CLZOON] +Zonas de máscara selectiva mostradas -[AM1] -'SAYONARA, SALVATORE' +[CLZOOF] +Zonas de máscara selectiva ocultadas -[AM2] -'BAJO VIGILANCIA' +[SHPLON] +gbShowCollisionPolys activado -[KM2] -'GRAND THEFT AUTO' +[SHPLOF] +gbShowCollisionPolys desactivado -[AS3] -'S.A.M.' +[CULREC] +CCullZones::RecalculateCullZoneData() -[RM2] -'SUMINISTRO DE ARMAS' +[FORMM1] +FormatMemCard 1 (prueba) -[LOVE6] -'SEÑUELO' ' +[UNFRM1] +UnFormatMemCard 1 (prueba) -[LOVE1] -'EL LIBERADOR' +[MEMTST] +Pantalla MemoryCardTest -[RC1] -'DESTRUCCIÓN DEL DIABLO' +[REGCAR] +Registrar MemoryCard uno -[RC2] -'LA MASACRE DE LA MAFIA' +[TEFONE] +Probar MemCard uno con formato -[RC3] -'CALAMIDAD EN EL CASINO' +[TEUFON] +Probar MemCard uno sin formato -[RC4] -'ATAQUE RUMPO' +[CRROOT] +CreateRootDir -[RM2_E1] -¡No puedo creer que esos bastardos de la barriga amarilla me dejaran sin la cobertura necesaria otra vez! +[CRLDIC] +Crear y cargar iconos -[GREN_1] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[FLFSGF] +Llenar el primer archivo con basura -[GREN_2] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[PUSAVE] +Guardar sólo la partida -[GREN_3] -Cuanto más tiempo pulses el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[CHEVOK] +CheckEveryOkB4Save -[LOVE4_G] -Mi propiedad estará esperándote en el angar de aduanas del avión. +[SVGMON] +SaveTheGame -[KABOOM] -¡BOOM! +[CRMGSV] +Crear directorio de cargador con protección de copia -[SPLAT] -¡PLOF! +[MGSVCN] +MagazineDirectory creado -[PANCAK] -¡APLASTADO! +[MGSVNC] +MagazineDirectory no creado -[SOAKED] -¡EMPAPADO! +{ ======================================================================================================= } +{ ================= INGAME PLAYER STATISTICS. BE CAREFUL WITH WIDTH LIMITS IN 4:3 RATIO ================= } +{ ======================================================================================================= } -[HEAD] -HEAD RADIO +{ ARTICLE ADDED BETWEEN NUMBERS } -[DBL_CLF] -DOUBLE CLEF FM +[FEST_OO] +de -[FLASHB] -FLASHBACK FM +[PL_STAT] +Estadísticas de jugador -[RISE] -RISE FM +[PE_WAST] +Personas asesinadas -[LIPS] -LIPS 106 +[PE_WSOT] +Personas asesinadas por otros -[CHAT] -CHATTERBOX FM +[CAR_EXP] +Coches reventados -[K_JAH] -K-JAH Radio +[TM_BUST] +Veces arrestado -[GAM_FM] -GAME FM +[M_WASTE] +Hombres civiles asesinados -[MSX_FM] -MSX FM +[F_WASTE] +Mujeres civiles asesinadas -[TUBE1] -Cuando el metro abra, podrás coger un tren hasta Staunton Island +[PIG_WST] +Polis asesinados -[TUBE2] -Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al aeropuerto Francis International. +[GNG_WST] +Maleantes asesinados -[TUBE_2] -Para abordar un tren del metro, pulsa el ~h~ botón 'entrar al vehículo' ~w~. +[MED_WST] +Médicos asesinados -[LEGAL] -~g~¡Eliminar la amenaza criminal! +[FIRE_WS] +Bomberos asesinados -[GA_2] -Nuevo motor y trabajo de pintura. ¡Los policías no te reconocerán! +[DED_CRI] +Criminales asesinados -[LM1_8A] -Para ganar un poco de dinero extra, por qué no 'tomar prestado' un taxi... +[DED_DED] +Vagabundos asesinados -[TAXIH1] -Para cerca de un peatón señalado para recogerlo, luego condúcelo a su destino antes de que se acabe el tiempo. +[DED_HOK] +Prostitutas asesinadas -[LM5_7] -~g~¡Menos de cuatro chicas trabajando el ~p~ Fuzz Ball ~g~ y Luigi no será feliz! +[HEL_DST] +Helicópteros destruidos -[KM2_3] -~g~Recuerda los ~r~ coches ~g~ tienen que estar en perfecto estado para ser aceptados en el ~p~ garaje ~g~. +[PER_COM] +Porcentaje completado -[KM5_2] -~g~Un Yardie anda por las calles. +[KGS_EXP] +Kgs de explosivos empleados -[BETRA_A] -Perdón, cariño. +[ACCURA] +Precisión de tiro -[BETRA_B] -Soy una chica ambiciosa ¿y tú?, +[ELBURRO] +Mejor tiempo de ''Turismo'' en segundos -[BETRA_C] -eres tiempo perdido. +[CAR_CRU] +Coches destrozados -[JAILB_Q] -Vamos! +[HED_EX] +Cabezas explotadas -[JAILB_R] -Señor picha-boba! +[TM_DED] +Visitas al hospital -[JAILB_S] -No hay problema en matarte. +[DAYSPS] +Días de juego transcurridos -[JAILB_T] -Vas a sentirlo. +[MMRAIN] +mm de lluvia caídos -[JAILB_U] -De acuerdo, de acuerdo. Piérdete. +[MXCARD] +Dist. máx. de salto acrobático (pies) -[HELP15] -Cuando vayas a pié pulsa el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para ~h~ mirar atrás ~w~. +[MXCARJ] +Altitud máx. de salto acrobático (pies) -[FEC_LB3] -Mira detrás +[MXCARDM] +Dist. máx. de salto acrobático (metros) -[FEC_R3] -(botón R3) +[MXCARJM] +Altitud máx. de salto acrobático (metros) -[FES_AFO] -Esta memory card (PS2) ya está formateada. +[MXFLIP] +Vueltas durante salto acrobático -[FEA_UP] -; +[MXJUMP] +Rotación máx. de salto acrobático -[FEA_DO] -= +[BSTSTU] +Mejor acrobacia hasta ahora: -[FEA_LE] -< +[INSTUN] +Acrobacia -[FEA_RI] -> +[PRINST] +Acrobacia perfecta -[FEDSAS3] -- CAMBIAR SELECCION +[DBINST] +Acrobacia doble -[FEDSAS4] -;=<> - CAMBIAR SELECCION +[DBPINS] +Acrobacia doble perfecta -[SPRAY_4] -Usa el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[TRINST] +Acrobacia triple -[SPRAY_1] -Usa el ~h~ botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[PRTRST] +Acrobacia triple perfecta -[LITTLE] -LITTLE T +[QUINST] +Acrobacia cuádruple -[NICK] -NICK LOVE +[PQUINS] +Acrobacia cuádruple perfecta -[AM1_10] -~g~Salvatore estará abandonando Luigi's aproximadamente a las 0~1~:~1~. +[NOSTUC] +No se han hecho acrobacias -[JAILB_V] -la ciudad de Liberty hoy está conmocionada. +[NOUNIF] +Saltos únicos completados -[JAILB_A] -Así la policía y los servicios de urgencias se encargan de las secuelas ... +[NOUNGM] +Saltos únicos -[JAILB_B] -de un ataque devastador a un convoy policial ocurrido esta mañana. +[NMISON] +Misiones intentadas -[JAILB_C] -Ningún detalle se ha hecho público sobre los prisioneros que estaban siendo trasladados en el convoy, +[NMMISP] +Misiones superadas -[JAILB_D] -Y ningún grupo ha admitido su responsabilidad. +[PASDRO] +Pasajeros transportados -[JAILB_E] -El convoy abandonó las oficinas de la policía a primera hora de esta mañana... +[MONTAX] +Dinero conseguido en taxi -[JAILB_F] -con el objeto de hacer una transferencia de rutina a la penitenciaría de Liberty. +[DAYPLC] +Gasto diario de la policía -[JAILB_G] -El ataque se produjo en el puente de Callahan, +[FEST_HA] +Nivel más alto de misión de sanitario -[JAILB_H] -dejando pocos testigos y el puente notablemente dañado. +[FEST_DF] +Distancia recorrida a pie (millas) -[JAILB_I] -Se cree que algunos de los convictos han perecido en la explosión... +[FEST_DC] +Distancia recorrida en coche (millas) -[JAILB_J] -que siguió al ataque inicial. +[FESTDFM] +Distancia recorrida a pie (metros) -[JAILB_W] -Pasadas las horas parece evidente que el ataque propinado a la policía se llevó a cabo por profesionales, +[FESTDCM] +Distancia recorrida en coche (metros) -[JAILB_K] -Cuando la identificación de los delincuentes ausentes se había complicado más aún... +[FEST_R1] +''Patio de recreo'' en segundos -[JAILB_L] -por un ataque de piratas informático a las bases de datos de los cuarteles de la policía. +[FEST_R2] +''Un paseo por el parque'' en segundos -[JAILB_O] -Con el proyecto del túnel Porter fuera del plazo previsto, +[FEST_R3] +''¡Agarrado!'' en segundos -[JAILB_P] -el desastre deja a Portland aislada del resto de la ciudad. +[FEST_RM] +''Caos en el aparcamiento'' en segundos -[JAILB_M] -* +[FEST_LS] +Gente salvada con una ambulancia -[JAILB_N] -* +[FEST_CC] +Criminales asesinados en misiones de justiciero -[JAILB_X] -En una declaración realizada hoy previamente, +[FEST_FE] +Incendios extinguidos -[FEDS_SE] -Botón / - ELEGIR +[FEST_LF] +Vuelo más largo en Dodo -[FEDS_SB] -Botón / - ELEGIR Botón " - VOLVER +[FEST_BD] +Mejor tiempo al desactivar la bomba -[TM4_A] -~w~Oh, eres tú. TONI no está aquí. +[FEST_RP] +Masacres superadas -[TM4_A2] -~w~Pero ha dejado para ti una de sus encantadoras cartas de amor. +[FEST_MP] +Misiones superadas -[DIAB2_A] -¡Puse en marcha mi negocio de entretenimiento exótico de la nada, excepto lo que cabía en mis pantalones de cuero! +[FEST_BB] +Carrera forrada: -[LM5_9] -CHICAS: +[FEST_H0] +Máximo de puntos de control -[PERPIC] -Paquetes Ocultos encontrados +[FEST_GC] +Coches de bandas destruidos: -[CO_ONE] -Paquete Oculto ~1~ de ~1~ +[FEST_H1] +Destrucción de los Diablos -[LOVE3_3] -~g~El avión ha tirado ~1~de los 6 paquetes. +[FEST_H2] +La masacre de la mafia -[FARE11] -~g~Destino ~w~'Lugar en obras' ~g~ en Fort Staunton. +[FEST_H3] +Calamidad en el casino -[GA_21] -No puedes almacenar más coches en este aparcamiento. +[FEST_H4] +Exterminio de Rumpos -[CHEAT1] -Trampas activadas +[PERPIC] +Paquetes ocultos encontrados -[CHEAT2] -Arma trucada +[CRIMRA] +Rango de criminal: -[CHEAT3] -Salud trucada +{ ==================================================== } +{ ================= CRIMINAL RATINGS ================= } +{ ==================================================== } -[CHEAT4] -Armadura trucada +[RATNG1] +Carterista -[CHEAT5] -Nivel de Se Busca trucado +[RATNG2] +Abusón -[CHEAT6] -Dinero trucado +[RATNG3] +Chorizo -[CHEAT7] -Clima trucado +[RATNG4] +Granuja -[AS1_H] -~r~¡¡No has conseguido guiar al Escuadrón de la Muerte a la trampa del Yakuza!! +[RATNG5] +Secuaz -[FEDS_BA] -Botón "- VOLVER +[RATNG6] +Conductor -[RAMP_A] -¡COMPLETADAS TODAS LAS RAMPAS! +[RATNG7] +Guardaespaldas -[USJ_ALL] -¡COMPLETADAS TODAS LOS MANIOBRAS ÚNICAS! +[RATNG8] +Negociador -[FARE23] -~g~Destino ~w~'garaje importación exportación' ~g~en el distrito de Cochrane Dam +[RATNG9] +Socio -[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. +[RATNG10] +Sicario -[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. +[RATNG11] +Asesino -[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. +[RATNG12] +Mano derecha -[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. +[RATNG13] +Verdugo -[AS1_C] -~w~Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty y cuyo único objetivo es el de darte caza. +[RATNG14] +Capo -[AS1_G] -~r~¡¡Todos los Yakuza están muertos!! +[RATNG15] +Jefe -[JAN] -Ene +{ =========================================================== } +{ ================= PAUSE MENU OPTIONS (PC) ================= } +{ =========================================================== } -[FEB] -Feb +[FEP_STA] +ESTADÍSTICAS -[MAR] -Mar +[FEP_BRI] +RESUMEN -[APR] -Abr +[FEP_CON] +CONTROLES -[MAY] -May +[FEP_AUD] +SONIDO -[JUN] -Jun +[FEP_DIS] +PANTALLA -[JUL] -Jul +[FEP_LAN] +IDIOMA -[AUG] -Ago +{ ============================================================= } +{ ================= MIXED BAG OF MENU OPTIONS ================= } +{ ============================================================= } -[SEP] -Sept +[GMSTOR] +Almacenar partida -[OCT] -Oct +[PREBRF] +Resúmenes anteriores -[NOV] -Nov +[CNTLS] +Controles -[DEC] -Dic +[MUSMEN] +Música/Efectos -[DEFDT] ---:---:---- --:--:-- +[GAMSET] +Ajustes del juego -[BUGGY] -COCHES RESTANTES: +[LANGUA] +Idioma -[BONUS] -~g~EXTRA ~1~$ +[DSPLAY] +Pantalla -[HORN1] -Pulsa el ~h~botón L3 ~w~ para tocar el ~h~claxon. +[DEBUGM] +Menú de depuración -[HORN2] -Pulsa el ~h~botón L1 ~w~ para tocar el ~h~claxon. +[QUITOP] +Salir de las opciones -[HORN3] -Pulsa el ~h~botón R1 ~w~ para tocar el ~h~claxon. +[CONTRL] +Configuración de controles -[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í. +[SET1EN] +Ajuste 1. Activado -[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í. +[SET1] +Ajuste 1. -[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í. +[SET2EN] +Ajuste 2. Activado -[RADIO_A] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. +[SET2] +Ajuste 2 -[RADIO_B] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. +[SET3EN] +Ajuste 3. Activado -[RADIO_C] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. +[SET3] +Ajuste 3 -[RADIO_D] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para moverte por las ~h~emisoras de radio. +[SET4EN] +Ajuste 4. Activado -[FEC_EXV] -Entrar y salir del vehículo +[SET4] +Ajuste 4 -[TAXI_M] -'TAXISTA' +[GOBACK] +Volver -[COP_M] -'VIGILANTE' +[SOUND] +SONIDO -[FIRE_M] -'BOMBERO' +[MUSVOL] +Volumen de la música -[AMBUL_M] -'PARAMÉDICO' +[SFXVOL] +Volumen de los efectos -[HJ_IS] -PRIMA POR ESCENA LOCA: ~1~$ +[SCROPT] +OPCIONES DE PANTALLA -[HJ_PIS] -PRIMA POR ESCENA LOCA PERFECTA ~1~$ +[CTRSCR] +Centrar pantalla -[HJ_DIS] -PRIMA POR DOBLE ESCENA LOCA ~1~$ +[SCRFOR] +Formato de imagen -[HJ_PDIS] -PRIMA POR DOBLE ESCENA LOCA PERFECTA ~1~$ +[GMSVLQ] +GUARDAR-CARGAR-SALIR -[HJ_TIS] -PRIMA POR TRIPLE ESCENA LOCA ~1~$ +[GMREST] +Reiniciar partida -[HJ_PTIS] -PRIMA POR TRIPLE ESCENA LOCA PERFECTA ~1~$ +[NOGMSV] +Sólo puedes guardar desde tu escondite. -[HJ_QIS] -PRIMA POR CUÁDRUPLE ESCENA LOCA ~1~$ +[DLFILE] +Borrar archivos de Grand Theft Auto III -[HJ_PQIS] -PRIMA POR CUÁDRUPLE ESCENA LOCA PERFECTA ~1~$ +[CHFILE] +ELEGIR ARCHIVO A CARGAR -[AM1_K] -Salvatore Leone estará saliendo de Luigi's en unas tres horas. (0~1~:~1~) +[CHCDLD] +ELEGIR MEMORY CARD A USAR -[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. +[CHFIDL] +ELEGIR ARCHIVO A BORRAR -[VANHSTP] -¿Algunos coches de seguridad cascados? Llévalos a nuestro garaje en el Puerto de Portland. +[CDUNFR] +Memory Card sin formato. -[EMVHPUP] -Se han pagado grandes porcentajes por coches nuevos/usados. Llévalos a la grúa que hay al noroeste del Puerto de Portland. +[SVCONF] +CONFIRMACIÓN -[STANDS] -ESCALERAS ROTAS: +[SVFNAM] +El nombre de tu archivo guardado es -[STASH] -¡~g~Guarda el SPANK en la parte trasera de la ~p~zona en construcción! +[SAVEDN] +Error. Fallo al guardar. -[MCSTNS] -No hay memory card (PS2) insertada en la ranura para MEMORY CARD 1. ¿Quieres empezar? (SI o NO) +[LANGSL] +SELECCIÓN DE IDIOMA -[LOVE3_5] -~g~El avión está ahora a tu alcance. +[GORLEV] +Nivel de violencia -[LOVE3_6] -¡~r~La Poli encontró antes los paquetes! +[SICASS] +Puta locura -[SIREN_1] -Para poner en marcha las sirenas de estos coches, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[SICSIC] +Puto manicomio -[SIREN_2] -Para poner en marcha las sirenas de estos coches, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[SCASSL] +Seleccionado Puta locura -[FM3_8C] -~w~Necesitaré 100.000 $ para cubrir gastos. +[SCSCSL] +Seleccionado Puto manicomio -[MCLOAD] -Cargando datos. No extraigas la memory card (PS2) de la ranura de MEMORY CARD 1, ni reinicies, o apagues la consola. +[DOSVGM] +¿Deseas guardar la partida? -[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. +[FORMEN] +Menú de formato -[FESZ_QF] -¿Estás seguro que quieres formatear la memory card (PS2) de la ranura de MEMORY CARD 1? +[CNTSAV] +No se puede guardar la partida en una misión. -[FESZ_LS] -Cargado con éxito. +[CNCSAV] +No se puede guardar la partida dentro de un vehículo. -[RM3_5] -~g~Tienes ~1~ de 6 paquetes de pruebas. +[YES] +Sí -[LOVE3_2] -¡~g~Tienes todos los paquetes! Llévalos de vuelat a Donald Love. +[NO] +No -[LOVE4_4] -¡~g~Lleva el paquete de vuelta a Donald Love! +[X] +x -[FEB_SAV] -Cargar +[LAST] +Último mensaje -[FEP_SAV] -CARGAR JUEGO +[FIRST] +~g~1.° -[AS2_12A] -Después de destrozar el primer puesto, ¡tendrás 8 mintutos antes que el Cartel envíe a sus matones! +[SECOND] +~g~2.° -[AS3_1A] -¡~g~Ahora vete al ~b~boya del aeropuerto! +[THIRD] +~g~3.° -[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. +[FOURTH] +~g~4.° -[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! +[WRONGCD] +Disco incorrecto. Introduce el disco correcto. -[END_A] -Los Residentes de Cedar Groove se adaptan a las consecuencias +[NOCD] +La bandeja del disco está vacía. Introduce un disco. -[END_B] -emocionales tras el estallido de la guerra +[OPENCD] +La bandeja del disco está abierta. Cierra la bandeja de disco. -[END_C] -que se produjo ayer en la zona. +[CDERROR] +Error al leer el DVD de Grand Theft Auto III -[END_D] -Un residente local, Clive Denver describió a la policía +[RESTART] +Empezando una nueva partida -[END_E] -a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. +[STOCK] +mercancía agotada -[END_F] -Oh, sabes, vamos a pasar un buen rato, porqué lo sabes. +[BAT1] +~g~¡Coge el bate! -[END_G] -Te quiero, Yo, yo, yo realmente te quiero, porque eres un hombre tan fuerte +[FE_INIP] +Iniciando y cargando el menú de pausa... Espera, por favor. -[END_H] -y eso es todo lo que necesito. +[FESZ_CA] +Cancelar -[END_I] -Bueno, ¿qué estaba diciendo? +[FESZ_QU] +Abandonar -[END_J] -Oh, sabes, lo he olvidado. Pero sabes lo que quiero decir, ¿verdad? +[FESZ_L1] +¡La partida se ha guardado! -[END_K] -El sonido de las explosiones sacudieros las casas más próximas, la gente se esconde. +[FESZ_L2] +El nombre guardado es: -[END_L] -Varios ciudadanos resultaron heridos a causa del tiroteo entre +[FESZ_OK] +ACEPTAR -[END_M] -las fuerzas terrestres y un helicóptero que rodeaba a la presa. +[FES_CAN] +Cancelar -[END_N] -Sí, aquí en los jardínes tenemos una vista excelente. +[FESZ_QL] +Perderás todo el progreso en tu partida actual. ¿Quieres continuar con la carga? -[END_O] -Cuando finalmente el helicóptero consiguió escapar, +[FESZ_QD] +¿Quieres borrar esta partida guardada? -[END_P] -mejor que los fuegos artificiales del 4 de Julio. +[FESZ_QO] +¿Quieres sobreescribir esta partida guardada? -[END_Q] -Con un número de víctimas superior a veinte, +[FESZ_QR] +¿Seguro que quieres empezar una nueva partida? Perderás todo el progreso desde la última partida guardada. -[END_R] -la policía continúa buscando cuerpos. +[FESZ_QS] +¿QUIERES GUARDAR? -[END_S] -No han habido desmentidos oficiales acerca de los rumores +[UPSIDE] +~r~¡Has volcado! -[END_T] -de que los muertos eran miembros de Cartel Colombiano, +[1010] +~r~Tu vehículo ha volcado -[END_U] -y se sigue sin pistas que aclaren las causas de la masacre. +[1011] +~r~Tu vehículo ha volcado -[END_V] -Me he roto una uña y me pelo hecho un asco, ¿puedes creértelo? +[1012] +~r~Tu vehículo ha volcado -[PAPER1] -UN DISPARO CRIMINAL REALIZADO POR SU NOVIA Y CÓMPLICE. EL TRIBUNAL CON UN VERDICTO ANÓNIMO, ENCUENTRA CULPABLE AL LADRÓN ARMADO. +[1013] +~r~Tu vehículo ha volcado -[PAPER2] -¡DIEZ AÑOS POR AMOR! +[1014] +~r~Tu vehículo ha volcado -[END_W] -Me ha costado cincuenta dólares... +[DETON] +DETONACIÓN: -[FEB_CPC] -Configuración del control +[RECORD] +~g~¡NUEVO RÉCORD! -[FEC_PED] -Controles a pie +[NRECORD] +~r~¡NO HAY UN NUEVO RÉCORD! -[FEC_VEH] -Controles en vehículo +[WELCOME] +BIENVENIDO A -[FEC_FPR] -Controles en primera persona +[TSCORE] +GANANCIAS: ~1~ $ -[FEC_CMM] -Controles comunes +[FESZ_UC] +CANCELAR -[FEC_PWL] -IR a la izquierda +[FES_LOF] +Fallo al cargar. -[FEC_PWR] -IR a la derecha +[MC_LDFL] +¡Fallo al cargar! -[FEC_PWF] -Andar hacia delante +[MC_NWRE] +Reiniciando partida. -[FEC_PWT] -Andar hacia la cámara +{ ============================================================================================== } +{ ================= STRINGS RELATED TO VEHICLE STUNTS (NOT INCLUDING THE DODO) ================= } +{ ============================================================================================== } -[FEC_PLB] -Mirar hacia atrás. +[HJSTAT] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. -[FEC_PFR] -Disparar arma +[HJSTATW] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! -[FEC_CLE] -Cambiar Arma a la Izq. +[HJSTATF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. -[FEC_CRI] -Cambiar Arma a la Dcha. +[HJSTAWF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! -[FEC_LKT] -Bloquear objetivo +[USJ_ALL] +¡TODAS LAS ACROBACIAS COMPLETADAS! -[FEC_PJP] -Salto Peatón +[USJ] +¡PREMIO POR ACROBACIA ÚNICA! -[FEC_PSP] -Sprint Peatón +[HJ_IS] +PREMIO POR ACROBACIA: ~1~$ -[FEC_PSH] -Disparar Peatón +[HJ_PIS] +PREMIO POR ACROBACIA PERFECTA: ~1~$ -[FEC_TLF] -Siguiente objetivo a la izq. +[HJ_DIS] +PREMIO POR ACROBACIA DOBLE: ~1~$ -[FEC_TRG] -Siguiente objetivo a la dcha. +[HJ_PDIS] +PREMIO POR ACROBACIA DOBLE PERFECTA: ~1~$ -[FEC_CCM] -Centrar cámara detrás del jugador. +[HJ_TIS] +PREMIO POR ACROBACIA TRIPLE: ~1~$ -[FEC_SZI] -Acercar rifle francotirador +[HJ_PTIS] +PREMIO POR ACROBACIA TRIPLE PERFECTA: ~1~$ -[FEC_SZO] -Alejar rifle francotirador +[HJ_QIS] +PREMIO POR ACROBACIA CUÁDRUPLE: ~1~$ -[FEC_LKL] -Mirar izq. en primera persona +[HJ_PQIS] +PREMIO POR ACROBACIA CUÁDRUPLE PERFECTA: ~1~$ -[FEC_LRT] -Mirar dcha. en primera persona +{ ================================================ } +{ ================= DATE STRINGS ================= } +{ ================================================ } -[FEC_LUP] -Mirar arr. en primera persona +[JAN] +Ene -[FEC_LDN] -Mirar abj. en primera persona +[FEB] +Feb -[FEC_LBH] -Mirar hacia atrás en vehículo +[MAR] +Mar -[FEC_LLF] -Mirar a la izq. en vehículo +[APR] +Abr -[FEC_LRG] -Mirar a la dch. en vehículo +[MAY] +May -[FEC_HRN] -Claxon +[JUN] +Jun -[FEC_HBR] -Freno de mano del vehículo +[JUL] +Jul -[FEC_ACL] -Acelerar vehículo +[AUG] +Ago -[FEC_BRK] -Frenar vehículo +[SEP] +Sept -[FEC_TSM] -Intercambiar SubMisiones Sí/No +[OCT] +Oct -[FEC_CRD] -Cambiar emisoras de radio +[NOV] +Nov -[FEC_ENT] -Entrar/Salir del vehículo +[DEC] +Dic -[FEC_WPN] -Disparar arma +[DEFDT] +--:---:---- --:--:-- -[FEC_PAS] -Pausa +[BUGGY] +COCHES RESTANTES: -[FEC_FPO] -Cambiar armas primera persona. +[BONUS] +~g~~1~$ ADICIONALES -[FEC_SMS] -Cambiar puntero del ratón. +[STANDS] +PUESTOS DESTROZADOS: -[FEC_CMS] -Cambiar modo cámara en todas situaciones. +{ ======================================================= } +{ ================= PC SPECIFIC STRINGS ================= } +{ ======================================================= } -[FEC_TSS] -Capturar pantalla +[FESZ_LS] +Carga completada. -[FEN_STA] -INICIAR JUEGO +[FEP_SAV] +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? - -[FES_CGA] -Huecos del juego disponibles: - -[FES_SCG] -¿Guardar el juego 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 +¿Seguro que deseas guardar esta partida? -[FEC_UND] -(NO) +[FES_CGA] +Espacios de partida disponibles: -[FET_CFT] -A PIE +[FES_SCG] +¿Guardar la partida actual? -[FET_CCR] -EN VEHÍCULO +[FES_LCG] +¿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_CMP] +COMBO: MIRAR I+D -[FEC_TFR] -Torre derecha +[FEC_NTT] +No hay texto para esta tecla -[FEC_TFU] -Torre /Dodo arriba +{ ==================================================================================== } +{ ================= PC SPECIFIC STRINGS - AVAILABLE KEYS AND BUTTONS ================= } +{ ==================================================================================== } -[FEC_TFD] -Torre /Dodo abajo +[FEC_MSL] +BIR -[FEC_MWF] -RUEDA ARR +[FEC_MSM] +BCR -[FEC_MWB] -RUEDA AB +[FEC_MSR] +BDR -[FEC_ORR] -o +[FEC_QUE] +¿? -[FEC_NUS] -SIN USO +[FEC_JBO] +JOY ~1~ -[FEC_LUD] -Mirar Ar +[FEC_SPC] +ESPACIO -[FEC_LDU] -Mirar Ab +[FEC_MXO] +MXB1 -[FEC_CMP] -COMOBO: MIRAR I+D +[FEC_MXT] +MXB2 -[FEC_NTT] -No hay texto para esta tecla +[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 -[FET_DSN] -Aspecto por defecto del jugador.bmp +[FED_SHD] +SOMBRAS DINÁMICAS -[JM3] -'VAN HEIST' +[FED_VET] +EFECTOS VISUALES -[EBAL] -'DÁME LIBERTAD' +[FED_VT0] +BAJO -[LM4] -'EXPLOSIVA ACCIÓN MACARRA' +[FED_VT1] +MEDIO -[REPLAY] -VOLVER A JUGAR +[FED_VT2] +ALTO -[FEC_SFT] -MAYÚS +[FED_VT3] +MÁXIMO -[CRED254] -JEFE DE ESTUDIO +[FET_DSN] +Apariencia predeterminada del jugador.bmp + +[REPLAY] +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 } -- cgit v1.2.3 From 7272802aa1776cee13287243b4e1922c6bae4b6d Mon Sep 17 00:00:00 2001 From: IlDucci Date: Wed, 2 Dec 2020 23:37:05 +0100 Subject: Restored the original ordering of Spanish.txt. --- gamefiles/TEXT/spanish.gxt | Bin 237250 -> 236540 bytes utils/gxt/spanish.txt | 10987 +++++++++++++++++++------------------------ 2 files changed, 4826 insertions(+), 6161 deletions(-) diff --git a/gamefiles/TEXT/spanish.gxt b/gamefiles/TEXT/spanish.gxt index 9234eec9..2adca165 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ 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,37 +80,149 @@ 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. +[TIMER] +Esta es una misión cronometrada, debes completarla antes de que el temporizador llegue a cero. -[HELP15] -Cuando vayas a pie mantén pulsado el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para~h~ mirar atrás~w~. +[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. + +[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. + +[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] +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! + +[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. + +[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 al archivo... + +[CHEATON] +Trucos ACTIVADOS + +[CHEATOF] +Trucos DESACTIVADOS + +[UZI_IN] +¡La Uzi ya está disponible en la tienda Ammu-Nation! + +[IMPORT1] +Sal y espera a tu vehículo. + +[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. -{ WANTED SYSTEM TUTORIAL } +[PAGEB11] +Lanzallamas ya disponible en tu guarida. [WANT_A] Sólo serás arrestado si estás en ~h~búsqueda y captura~w~. @@ -162,9 +257,6 @@ A medida que avances en el juego encontrarás formas de reducir tu grado de bús [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. @@ -174,36 +266,26 @@ 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... +[DAM] +DAÑO: -[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. +[KILLS] +MUERTES: -[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. +[FARES] +CARRERAS: -[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. +[BULL] +LINGOTES: -[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. +[EVID] +PRUEBAS: -[GUN_5] -Puedes practicar disparando a estos blancos. Cuando hayas terminado puedes continuar la misión. +[HEALTH] +ESTADO DEL COCHE: -{ OTHER HINTS } +[COLLECT] +RECOGIDOS: [BOMB] Mete tu vehículo en la tienda de ~h~bombas~w~ para poner una. Coste: ~h~1.000$~w~. @@ -223,4296 +305,4500 @@ 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. +[LUIGI] +MISIONES DE LUIGI -[GARAGE] -Mete el vehículo dentro del garaje y luego sal caminando. +[TONI] +MISIONES DE TONI -[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. +[JOEY] +MISIONES DE JOEY -[S_PROM2] -Puedes alojar un vehículo en el garaje de al lado al guardar tu partida. +[FRANK] +MISIONES DE SALVATORE -[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 +[DIABLO] +MISIONES DE DIABLO -[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. +[ASUKA] +MISIONES DE ASUKA -[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~. +[B_SITE] +MISIONES SUBURBANAS DE ASUKA -[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. +[KENJI] +MISIONES DE KENJI -[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. +[RAY] +MISIONES DE RAY -[HORN1] -Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. +[LOVE] +MISIONES DE LOVE -[HORN2] -Pulsa el ~h~botón L1~w~ para tocar el ~h~claxon. +[YARDIE] +MISIONES DE JAMAICANOS -[HORN3] -Pulsa el ~h~botón R1~w~ para tocar el ~h~claxon. +[HOOD] +MISIONES DE HOOD -[HORN4] -Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. +[CITYZON] +Liberty City -[RADIO_A] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. +[IND_ZON] +Portland -[RADIO_B] -Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. +[PORT_W] +Callahan Point -[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. +[PORT_S] +Muelle Atlantic -[SIREN_1] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[PORT_E] +Puerto de Portland -[SIREN_2] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[PORT_I] +Trenton -[SIREN_3] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[S_VIEW] +Portland View -[SIREN_4] -Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. +[CHINA] +Chinatown -[BOATIN1] -Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +[EASTBAY] +Playa de Portland -[BOATIN3] -Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. +[LITTLEI] +Saint Mark's -[BOATIN2] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. +[REDLIGH] +Barrio rojo -[BOATIN4] -Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. +[TOWERS] +Cerros de Hepburn -[GREN_1] -Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[HARWOOD] +Harwood -[GREN_2] -Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[ROADBR1] +Puente Callahan -[GREN_3] -Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. +[ROADBR2] +Puente Callahan -[TUBE1] -Cuando el metro abra, podrás coger un tren hasta Staunton Island. +[TUNNELP] +Túnel Porter -[TUBE2] -Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al Aeropuerto Internacional Francis. +[BOMB1] +Taller de 8-Ball -[TUBE_2] -Para subirte a un vagón, pulsa el ~h~botón Entrar al vehículo~w~. +[COM_ZON] +Staunton Island -[SPRAY_4] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[STADIUM] +Aspatria -[SPRAY_1] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. +[HOSPI_2] +Rockford -[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. +[UNIVERS] +Campus de Liberty -[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. +[CONSTRU] +Fort Staunton -[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. +[PARK] +Parque Belleville -[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. +[COM_EAS] +Newport -[RCHELP] -Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. +[SHOPING] +Bedford Point -[RCHELPA] -Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. +[YAKUSA] +Torrington -[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. +[SUB_ZON] +Shoreside Vale -[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. +[AIRPORT] +Aeropuerto Int. Francis -[CRUSH] -Aparca en la zona señalada y sal de tu vehículo para que sea triturado. +[PROJECT] +Wichita Gardens -[GARAGE1] -~g~Sal del vehículo y aléjate caminando. +[SUB_IND] +Pike Creek -[PBOAT_1] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. +[SWANKS] +Cedar Grove -[PBOAT_2] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. +[BIG_DAM] +Presa Cochrane -{ ============================================================================================================================ } -{ ================= PAGER MESSAGES, INDICATING THAT THE PLAYER HAS UNLOCKED WEAPONS AND ITEMS IN ITS HIDEOUT ================= } -{ ============================================================================================================================ } +[SUB_ZO2] +Shoreside Vale -[PAGEB1] -Pistola ya disponible en tu guarida. +[SUB_ZO3] +Shoreside Vale -[PAGEB2] -Uzi ya disponible en tu guarida. +[CAR_1] +Ambulancia -[PAGEB3] -Chaleco antibalas ya disponible en tu guarida. +[CAR_2] +Camión de bomberos -[PAGEB4] -Escopeta ya disponible en tu guarida. +[CAR_3] +Coche patrulla -[PAGEB5] -Granadas ya disponibles en tu guarida. +[CAR_4] +Enforcer -[PAGEB6] -Molotovs ya disponibles en tu guarida. +[CAR_5] +Barracks -[PAGEB7] -AK47 ya disponible en tu guarida. +[CAR_6] +Rhino -[PAGEB8] -Fusil de francotirador ya disponible en tu guarida. +[CAR_7] +Coche del FBI -[PAGEB9] -M16 ya disponible en tu guarida. +[CAR_8] +Securicar -[PAGEB10] -Lanzacohetes ya disponible en tu guarida. +[CAR_9] +Moonbeam -[PAGEB11] -Lanzallamas ya disponible en tu guarida. +[CAR_10] +Coach -[PAGEB12] -Soborno policial ya disponible en tu guarida. +[CAR_11] +Flatbed -[PAGEB13] -Salud ya disponible en tu guarida. +[CAR_12] +Linerunner -[PAGEB14] -Adrenalina ya disponible en tu guarida. +[CAR_13] +Trashmaster -{ ==================================================================================================================== } -{ ================= PAGER MESSAGES, INDICATING THAT GUNS HAVE BEEN UNLOCKED AT THE AMMU-NATION STORE ================= } -{ ==================================================================================================================== } +[CAR_14] +Patriot -[COLT_IN] -¡La pistola ya está disponible en la tienda Ammu-Nation! +[CAR_15] +Mr. Whoopee -[UZI_IN] -¡La Uzi ya está disponible en la tienda Ammu-Nation! +[CAR_16] +Mule -{ ================================================================================================== } -{ ================= PAGER MESSAGES THAT APPEAR WHEN CERTAIN CAR SHOPS ARE UNLOCKED ================= } -{ ================================================================================================== } +[CAR_17] +Yankee -[IMPEXPP] -Garaje de Importación/Exportación, puerto de Portland. Requerimos varios vehículos; revisa nuestro tablón de notas para saber más. +[CAR_18] +Pony -[VANHSTP] -¿Quieres abrir algún Securicar? Llévalo a nuestro garaje en el puerto de Portland. +[CAR_19] +Bobcat -[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. +[CAR_20] +Rumpo -{ =============================================================== } -{ ================= RAMPAGE SUBMISSIONS STRINGS ================= } -{ =============================================================== } +[CAR_21] +Blista -[RAMPAGE] -¡MASACRE! +[CAR_22] +Dodo -[RAMP_P] -¡MASACRE COMPLETADA! +[CAR_23] +Autobús -[RAMP_F] -MASACRE FALLIDA +[CAR_24] +Sentinel -[RAMP_A] -¡TODAS LAS MASACRES COMPLETADAS! +[CAR_25] +Cheetah -{ Pager messages } +[CAR_26] +Banshee -[PAGE_00] -. +[CAR_27] +Stinger -[PAGE_01] -¡Mata a ~1~ Diablos en 120 segundos! +[CAR_28] +Infernus -[PAGE_02] -¡Destruye ~1~ vehículos en 120 segundos! +[CAR_29] +Esperanto -[PAGE_03] -¡Mata a ~1~ mafiosos en 120 segundos! +[CAR_30] +Kuruma -[PAGE_04] -¡Mata a ~1~ Tríadas en 120 segundos! +[CAR_31] +Stretch -[PAGE_05] -¡Mata a ~1~ Tríadas en 120 segundos! +[CAR_32] +Perennial -[PAGE_06] -¡Destruye ~1~ vehículos en 120 segundos! +[CAR_33] +Landstalker -[PAGE_07] -¡Revienta ~1~ cabezas jamaicanas en 120 segundos! +[CAR_34] +Mañana -[PAGE_08] -¡Quema a ~1~ yakuzas en 120 segundos! +[CAR_35] +Idaho -[PAGE_09] -¡Destruye ~1~ vehículos en 120 segundos! +[CAR_36] +Stallion -[PAGE_10] -¡Destruye ~1~ vehículos en 120 segundos! +[CAR_37] +Taxi -[PAGE_11] -¡Aniquila a ~1~ jamaicanos en 120 segundos! +[CAR_38] +Cabbie -[PAGE_12] -¡Quema a ~1~ yakuzas en 120 segundos! +[CAR_39] +Buggy -[PAGE_13] -¡Vuela a ~1~ jamaicanos en 120 segundos! +[LUIGIS] +Club de Luigi -[PAGE_14] -¡Fríe a ~1~ colombianos en 120 segundos! +[GOAWAY] +~g~¡Ya estás en una misión! -[PAGE_15] -¡Machaca a ~1~ Hoods en 120 segundos! +[LUIGGO] +~g~Luigi está entrevistando a unas chicas nuevas... ¡Vuelve más tarde! -[PAGE_16] -¡Destruye ~1~ vehículos en 120 segundos! +[JOEYGO] +~g~Joey ha salido con Misty. ¡Pásate más tarde! -[PAGE_17] -¡Arrolla a ~1~ colombianos con un coche en 120 segundos! +[TONIGO] +~g~Toni ha llevado a su mamá a la ópera... ¡Llama en otro momento! -[PAGE_18] -¡Destruye ~1~ vehículos disparando desde otro en 120 segundos! +[KEMUGO] +~g~María y Kemuri están muy liadas... ¡Pásate más tarde! -[PAGE_19] -¡Revienta ~1~ cabezas colombianas en 120 segundos! +[KENJGO] +~g~Kenji está reunido con la yakuza, ¡llama en otro momento! -[PAGE_20] -¡Decapita a ~1~ Hoods en 120 segundos! +[RAYGO] +~g~Ray tiene otros baños por los que rondar, ¡ven en otro momento! -{ ======================================================== } -{ ================= PERCENTAGE BAR TEXTS ================= } -{ ======================================================== } +[LOVEGO] +~g~Donald Love tiene otros asuntos que atender. ¡Pide una cita más tarde! -[DAM] -DAÑO: +[KENSGO] +~g~¡Kenji está ocupado! ¡Llama más tarde! -[KILLS] -MUERTES: +[ASUSGO] +~g~¡Asuka no está disponible en este momento! -[FARES] -CARRERAS: +[HOODGO] +~g~¡Los Hoods no pueden atenderte en este momento! -[BULL] -LINGOTES: +[WRONGT1] +~g~Vuelve entre las 05:00 y las 21:00 para buscar trabajo. -[EVID] -PRUEBAS: +[WRONGT2] +~g~Vuelve entre las 06:00 y las 14:00 para buscar trabajo. -[HEALTH] -ESTADO DEL COCHE: +[WRONGT3] +~g~Vuelve entre las 15:00 y las 00:00 para buscar trabajo. -[COLLECT] -RECOGIDOS: +[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. -{ ================================================================================== } -{ ================= POSSIBLY MAP SCREEN INDICATIONS, MISSING IN PC ================= } -{ ================================================================================== } +[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... -[LUIGI] -MISIONES DE LUIGI +[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... -[TONI] -MISIONES DE TONI +[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... -[JOEY] -MISIONES DE JOEY +[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. -[FRANK] -MISIONES DE SALVATORE +[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. -[DIABLO] -MISIONES DE DIABLO +[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. -[ASUKA] -MISIONES DE ASUKA +[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. -[B_SITE] -MISIONES SUBURBANAS DE ASUKA +[GUN_5] +Puedes practicar disparando a estos blancos. Cuando hayas terminado puedes continuar la misión. -[KENJI] -MISIONES DE KENJI +[TAXI1] +~g~Busca un cliente. -[RAY] -MISIONES DE RAY +[FARE1] +~g~Ve al ~w~club Sex Kitten Meeouch ~g~en el barrio rojo. -[LOVE] -MISIONES DE LOVE +[FARE2] +~g~Ve a ~w~Supa Save ~g~en Portland View. -[YARDIE] -MISIONES DE JAMAICANOS +[FARE3] +~g~Ve a ~w~la sala Clásica ~g~en Chinatown. -[HOOD] -MISIONES DE HOOD +[FARE4] +~g~Ve a la ~w~cafetería Greasy Joe ~g~en Callahan Point. -{ =========================================================== } -{ ================= LIBERTY CITY AREA NAMES ================= } -{ =========================================================== } +[FARE5] +~g~Ve a la ~w~tienda de armas Ammu-Nation ~g~en el barrio rojo. -[CITYZON] -Liberty City +[FARE6] +~g~Ve a ~w~Easy Credit Autos ~g~en Saint Mark's. -[IND_ZON] -Portland +[FARE7] +~g~Ve al ~w~bar de topless de Woody ~g~en el barrio rojo. -[PORT_W] -Callahan Point +[FARE8] +~g~Ve al ~w~restaurante Marcos ~g~en Saint Mark's. -[PORT_S] -Muelle Atlantic +[FARE9] +~g~Ve al ~w~taller de importación y exportación ~g~en el puerto de Portland. -[PORT_E] -Puerto de Portland +[FARE10] +~g~Ve a ~w~Punk Noodles ~g~en Chinatown. -[PORT_I] -Trenton +[FARE12] +~g~Ve al ~w~estadio de fútbol ~g~en Aspatria. -[S_VIEW] -Portland View +[FARE13] +~g~Ve a la ~w~iglesia ~g~de Bedford Point. -[CHINA] -Chinatown +[FARE14] +~g~Ve al ~w~casino ~g~de Torrington. -[EASTBAY] -Playa de Portland +[FARE15] +~g~Ve a la ~w~universidad ~g~en el Campus de Liberty. -[LITTLEI] -Saint Mark's +[FARE16] +~g~Ve al ~w~centro comercial ~g~en la zona del parque Belleville. -[REDLIGH] -Barrio rojo +[FARE17] +~g~Ve al ~w~museo ~g~de Newport. -[TOWERS] -Cerros de Hepburn +[FARE18] +~g~Ve al ~w~edificio de AmCo ~g~en Torrington. -[HARWOOD] -Harwood +[FARE19] +~g~Ve a ~w~Bolt Burgers ~g~en Bedford Point. -[ROADBR1] -Puente Callahan +[FARE20] +~g~Ve al ~w~parque ~g~de Belleville. -[ROADBR2] -Puente Callahan +[FARE21] +~g~Ve al ~w~Aeropuerto Internacional Francis. -[TUNNELP] -Túnel Porter +[FARE22] +~g~Ve a la ~w~presa Cochrane~g~. -[BOMB1] -Taller de 8-Ball +[FARE24] +~g~Ve al ~w~hospital ~g~de Pike Creek. -[COM_ZON] -Staunton Island +[FARE25] +~g~Ve al ~w~parque ~g~de Shoreside Vale. -[STADIUM] -Aspatria +[FARE26] +~g~Ve a las ~w~Torres del Noroeste ~g~de Wichita Gardens. -[HOSPI_2] -Rockford +[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! -[UNIVERS] -Campus de Liberty +[TSCORE2] +$~1~ -[CONSTRU] -Fort Staunton +[IN_ROW] +¡~1~ CONSECUTIVOS! $~1~ -[PARK] -Parque Belleville +[TTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. -[COM_EAS] -Newport +[TTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. -[SHOPING] -Bedford Point +[ATUTOR2] +~g~Conduce a los pacientes hasta el hospital con mucho cuidado. Cada golpe reducirá sus posibilidades de supervivencia. -[YAKUSA] -Torrington +[A_TIME] ++~1~ segundos -[SUB_ZON] -Shoreside Vale +[A_FULL] +~r~¡Ambulancia llena! -[AIRPORT] -Aeropuerto Int. Francis +[A_RANGE] +~g~La radio de la ambulancia está fuera de cobertura, ¡acércate a un hospital! -[PROJECT] -Wichita Gardens +[FTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. -[SUB_IND] -Pike Creek +[FTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. -[SWANKS] -Cedar Grove +[F_PASS1] +¡Fuego apagado! -[BIG_DAM] -Presa Cochrane +[F_RANGE] +~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate a una estación de bomberos! -[SUB_ZO2] -Shoreside Vale +[C_BREIF] +~g~Sospechoso visto por última vez en: ~a~. -[SUB_ZO3] -Shoreside Vale +[C_RANGE] +~g~La radio de la policía está fuera de cobertura, ¡acércate a una comisaría! -[TRAIN_1] -Estación Kurowski +[DODO_FT] +¡Volaste durante ~1~ segundos! -[TRAIN_2] -Estación Rothwell +[EBAL_A] +Conozco un lugar en las afueras del barrio rojo donde podemos escondernos, -[TRAIN_3] -Estación Baillie +[EBAL_A1] +pero mis manos están destrozadas, así que conduce tú, hermano. -[SUBWAY1] -Estación Portland +[EBAL_1] +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. -[SUBWAY2] -Estación Rockford +[EBAL_1B] +Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. -[SUBWAY3] -Estación Staunton sur +[EBAL_2] +~g~¡Vuelve al coche! -[SUBWAY4] -Terminal Shoreside +[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! -{ ================================================= } -{ ================= VEHICLE NAMES ================= } -{ ================================================= } +[EBAL_D] +Conozco a un tipo con contactos, se llama Luigi. -[CAR_1] -Ambulancia +[EBAL_D1] +Somos viejos amigos, así que podremos buscarte curro. Vamos a verlo. -[AMBULAN] -Ambulancia +[EBAL_E] +Venga, vamos a pasarnos por allí y te presentaré. -[CAR_2] -Camión de bomberos +{ UNUSED } -[FIRETRK] -Camión de bomberos +[EBAL_I] +El jefe os recibirá enseguida... -[CAR_3] -Coche patrulla +[EBAL_J] +8-Ball que ocuparse de una cosa arriba. -[POLICAR] -Coche patrulla +[EBAL_K] +Quizá puedas hacerme un favor. -[CAR_4] -Enforcer +[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í. -[ENFORCR] -Enforcer +[EBAL_N] +¡Así que no quites las manos del volante! -[CAR_5] -Barracks +[EBAL_4] +~r~¡8-Ball ha muerto! -[BARRCKS] -Barracks OL +[EBAL_5] +~g~¡Consigue un vehículo! -[CAR_6] -Rhino +[EBAL_6] +~g~¡Recoge a Misty! -[RHINO] -Rhino +[LM1] +'LAS CHICAS DE LUIGI' -[CAR_7] -Coche del FBI +[LM2] +'NO DROGUES A MI ZORRA' -[FBICAR] -Coche del FBI +[LM3] +'LLEVA A MISTY POR MÍ' -[CAR_8] -Securicar +[LM5] +'EL BAILE DE LA POLICÍA' -[SECURI] -Securicar +[LM1_2] +~g~Lleva a Misty al club de Luigi. -[CAR_9] -Moonbeam +[LM1_3] +~g~Toca el claxon para que la chica entre en el coche. -[MOONBM] -Moonbeam +[LM1_6] +~g~¡Vuelve al coche! -[CAR_10] -Coach +[LM1_7] +Detén el vehículo junto a Misty y déjala subir. -[COACH] -Coach +[LM1_8] +Puedes ir a ver a Luigi y buscar más trabajo o darte un paseo por Liberty City. -[CAR_11] -Flatbed +[LM2_A] +Hay una nueva droga en la ciudad llamada SPANK. -[FLATBED] -Flatbed +[LM2_E] +Algún listillo ha estado dando esta basura a mis chicas en el puerto de Portland. -[CAR_12] -Linerunner +[LM2_B] +¡Ve y dale con un bate de béisbol en su cara! -[LINERUN] -Linerunner +[LM2_G] +¡Quiero una compensación por este insulto! -[CAR_13] -Trashmaster +[LM2_1] +~g~Coge su coche y haz que cambien su pintura. -[TRASHM] -Trashmaster +[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! -[CAR_14] -Patriot +[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! -[PATRIOT] -Patriot +[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! -[CAR_15] -Mr. Whoopee +[LM2_3] +~g~¡Mete el coche en el garaje de Luigi! -[WHOOPEE] -Mr. Whoopee +[LM2_4] +~g~¡Vuelve a pintar el coche! -[CAR_16] -Mule +[LM3_A] +Hola, tengo que hablar contigo... Bueno, Mick, ya hablaremos. -[MULE] -Mule +[LM3_B] +¿Cómo te va, chico? -[CAR_17] -Yankee +[LM3_C] +El hijo del Don, Joey Leone, quiere fiesta con su chica de siempre, Misty. -[YANKEE] -Yankee +[LM3_D] +Recógela en los cerros de Hepburn, -[CAR_18] -Pony +[LM3_E] +pero cuidado, ese es territorio de los Diablos. -[PONY] -Pony +[LM3_F] +Luego llévala rapidito hasta su taller en Trenton, -[CAR_19] -Bobcat +[LM3_H] +¡así que estate pendiente del camino y no de Misty! -[BOBCAT] -Bobcat +[LM3_1D] +Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. -[CAR_20] -Rumpo +[LM3_2] +~g~Lleva a Misty al local de Joey. -[RUMPO] -Rumpo +[LM3_4] +~g~¡Recoge a Misty! -[CAR_21] -Blista +[LM3_5] +Ahora trabajas para Luigi, ¿no? ¡Ya era hora de que tuviese un conductor de confianza! -[BLISTA] -Blista +[LM3_7] +Estaré contigo en un minuto, bujía mía. -[CAR_22] -Dodo +[LM3_10] +~g~¡Consigue un vehículo! -[DODO] -Dodo +[LM4_B] +Ve y resuélvelo de mi parte. -[CAR_23] -Autobús +[LM4_C] +Si necesitas un arma, ve a la puerta trasera de la tienda Ammu-Nation que está enfrente del metro. -[BUS] -Autobús +[LM5_A] +El baile de la policía se está celebrando en la sala Clásica, cerca del puente, -[CAR_24] -Sentinel +[LM5_B] +y parece que tienen ganas de una fiesta más ''clásica''. -[SENTINL] -Sentinel +[LM5_C] +Tengo chicas haciendo la calles. -[CAR_25] -Cheetah +[LM5_D] +Llévalas al baile, sacarán una buena tajada. -[CHEETAH] -Cheetah +[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. -[CAR_26] -Banshee +[LM5_2] +~r~¡Te has cargado a una de las chicas de Luigi! -[BANSHEE] -Banshee +[LM5_3] +~g~¡Necesitas un coche! -[CAR_27] -Stinger +[LM5_4] +~g~Recoge a las chicas que trabajan en Saint Mark's. -[STINGER] -Stinger +[LM5_5] +~g~¡Lleva a las chicas al baile de la policía! -[CAR_28] -Infernus +[LM5_8] +~g~Chicas trabajando en el baile: ~1~ -[INFERNS] -Infernus - -[CAR_29] -Esperanto +[JM2] +'DESPEDIDA A LEE CHONG ''EL GORDO''' -[ESPERAN] -Esperanto +[JM4] +'EL CHÓFER DE CIPRIANI' -[CAR_30] -Kuruma +[JM5] +'FIAMBRE EN EL MALETERO' -[KURUMA] -Kuruma +[JM1_1] +~g~Lleva el coche de Forelli al taller que tiene 8-Ball al norte, tras Easy Credit Autos. -[CAR_31] -Stretch +[JM1_2] +~g~Vuelve a aparcar el coche frente al restaurante de Marco. -[STRETCH] -Stretch +[JM1_3] +~g~¡Activa la bomba del coche y luego sal de ahí! -[CAR_32] -Perennial +[JM1_4] +~g~¡Te estás cargando el coche! ¡Repáralo! -[PEREN] -Perennial +[JM1_5] +~g~¡La bomba del coche no está activada! -[CAR_33] -Landstalker +[JM1_6] +~g~Vuelve a aparcar el coche en el sitio correcto. -[LANDSTK] -Landstalker +[JM1_8A] +~y~¡Ey, pero si es mi colega! -[CAR_34] -Mañana +[JM1_8B] +~y~El taller de bombas está automatizado. Solo tienes que meter el coche, pararlo y el taller hará el resto. -[MANANA] -Mañana +[JM1_8C] +~y~Ten, tu primer coche es gratis, pero los siguientes te los cobraré. -[CAR_35] -Idaho +[JM2_A] +Lee Chong ''el Gordo'' está traficando SPANK para una nueva banda de Colombia... o Colorado... O como se llame. -[IDAHO] -Idaho +[JM2_B] +No me acuerdo. El caso es que no importa. -[CAR_36] -Stallion +[JM2_D] +Ese cabrito ha vendido su último fideo. -[STALION] -Stallion +[JM2_E] +¡Lo quiero muerto! -[CAR_37] -Taxi +[JM2_G] +Búscate un nueve, queda claro, ¿no? -[TAXI] -Taxi +[JM2_H] +Y recuerda, ve con ojo en Chinatown: es territorio de las Tríadas. -[CAR_38] -Cabbie +[JM3_A] +Vamos a asaltar un furgón blindado. -[CABBIE] -Cabbie +[JM3_B] +Sale de Chinatown todos los días. -[CAR_39] -Buggy +[JM3_C] +Las balas ni siquiera abollarán el furgón, así que coge un coche y échalo de la carretera. -[BFINJC] -BF Injection +[JM3_D] +Si lo zurras bien, los imbéciles de los guardias se achantarán. -[PREDATR] -Predator +[JM3_E] +Luego llévalo al almacén de los muelles y mis chicos se encargarán desde ahí. -[TRAIN] -Tren +[JM3_F] +El furgón no estará fuera todo el día, así que no pierdas el tiempo. -[HELI] -Helicóptero +[JM3_1] +~g~Lleva el furgón al almacén. -[RCBANDT] -Bandit RC +[JM3_2] +~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. -[BELLYUP] -Furgoneta de las Tríadas +[JM4_B] +¡Ah, aquí está el tío que te decía! -[MRWONGS] -Mr Wongs +[JM4_C] +Bueno, este no es italiano ni tampoco mecánico, pero sabe arreglar cosas. -[MAFIACR] -Sentinel de la mafia +[JM4_D] +Este es el capo de papá, Toni Cipriani. -[YARDICR] -Lobo jamaicano +[JM4_E] +Sí, soy Toni Cipriani. -[YAKUZCR] -Stinger de la yakuza +[JM4_F] +Llévale al restaurante de Mamma en Saint Mark's, ¿va? -[DIABLCR] -Stallion de los Diablos +[JM4_G] +Oye, estoy planeando un curro que necesita un buen conductor, pásate por aquí más tarde, ¿estamos? -[COLOMCR] -Cruiser del cártel +[JM4_2] +¡Espera aquí! Deja el motor en marcha. Esta no es una visita social. -[HOODSCR] -Rumpo XL de los hood +[JM4_3] +¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! -[AEROPL] -Avioneta +[JM4_4] +Las Tríadas creen que pueden meterse conmigo. ¡Las Tríadas, CONMIGO! -[SPEEDER] -Speeder +[JM4_6] +¡Mi coche! Dije que con cuidado. -[REEFER] -Reefer +[JM4_7] +~g~Lleva a Toni al restaurante de Mamma. -[PANLANT] -Panlantic +[JM4_8] +~r~¡Han liquidado a Toni! -[BORGNIN] -Borgnine +[JM5_A] +Guapo, muy guapo... -[TOYZ] -TOYZ +[JM5_B] +¡Justo te estaba buscando! -{ ======================================================= } -{ ================= RADIO STATION NAMES ================= } -{ ======================================================= } +[JM5_D] +Uno de los Forelli se las daba de mafioso y se llevó su merecido. -[FEA_FM0] -HEAD RADIO +[JM5_E] +Lleva el cuerpo a la trituradora en Harwood, ¿vale? -[HEAD] -Head Radio +[JM5_1] +~g~¡Llévalo a la trituradora! -[FEA_FM1] -DOUBLE CLEF FM +[JM5_2] +~g~¡Son los hermanos Forelli! -[DBL_CLF] -Double Clef FM +[JM6_A] +Vaya cochazo, ¿eh? -[FEA_FM2] -K-JAH RADIO +[JM6_B] +Bueno, escucha. Lleva un coche a la casa franca de Saint Mark's y recoge a unos colegas. -[K_JAH] -K-Jah Radio +[JM6_C] +Van a atracar un banco y necesitan un conductor. -[FEA_FM3] -RISE FM +[JM6_D] +Di mi palabra de que eras su hombre, así que no la cagues. -[RISE] -Rise FM +[JM6_E] +Llévales al banco antes de las cinco en punto, ni un minuto después. -[FEA_FM4] -LIPS 106 +[JM6_2] +Mantén el motor en marcha, entraremos y saldremos enseguida. -[LIPS] -Lips 106 +[JM6_3] +¡Sácanos de aquí! -[FEA_FM5] -GAME FM +[JM6_4] +¡Líbrate de la poli y llévanos a la casa franca! -[GAM_FM] -Game Radio FM +[JM6_6] +~g~¡Busca un vehículo menos llamativo! -[FEA_FM6] -MSX FM +[JM6_7] +~g~¡Necesitas a los 3 para robar el banco! -[MSX_FM] -MSX FM +[TM1] +'SACANDO LA COLADA' -[FEA_FM7] -FLASHBACK 95.6 +[TM2] +'LA ENTREGA' -[FLASHB] -Flashback 95.6 +[TM3] +'SALVATORE HA CONVOCADO UNA REUNIÓN' -[FEA_FM8] -CHATTERBOX FM +[TM4] +'TRÍADAS Y TRIBULACIONES' -[CHAT] -Chatterbox FM +[TM5] +'LLUVIA DE PECES' -{ ============================================================================================================== } -{ ================= STRINGS RELATED TO GARAGES (BOMB SHOP, SPRAY SHOP, IMPORT/EXPORT, CRUSHER) ================= } -{ ============================================================================================================== } +[TONI_P] +¡Tengo un trabajo urgente para ti! -Toni -[GA_1] -¡Hala! ¡Demasiado peligroso para mi gusto! +[TM1_A] +Siéntate, chico, siéntate de una vez. -[GA_1A] -Vuelve cuando no estés tan ocupado... +[TM1_B] +La lavandería no quiere pagar la protección, ¿eh? -[GA_2] -He cambiado el motor y la mano de pintura. ¡La poli no te reconocerá! +[TM1_C] +¿Las Tríadas creen que pueden meterse conmigo? -[GA_3] -¡Ya no es gratis! ¡La mano de pintura son 1.000 dólares! +[TM1_D] +¡Esos aspirantes a tipos duros van a saber lo que es ser un tipo duro! -[GA_4] -Una bomba de coche vale 1.000 dólares. +[TM1_E] +¡Eso, enséñales respeto! ¡Las Tríadas no se ríen de ninguno de mis hijos! -[GA_5] -Tu coche ya tiene una bomba instalada. +[TM1_F] +Tu padre, Dios acoja su alma, no toleraba ni media a las Tríadas en Sicilia. -[GA_6] -Apárcalo, prepáralo pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! +[TM1_G] +Lo siento, mamá. Sí, mamá. -[GA_6B] -¡Apárcalo, prepáralo tocando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! +[TM1_H] +Quiero que te cargues sus furgonetas de lavandería -[GA_7] -Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. +[TM1_I] +y a cualquiera de las Tríadas que se cruce en tu camino. -[GA_7B] -Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. +[TM1_J] +8-Ball te dará lo que necesites. -[GA_8] -Utiliza el detonador para activar la bomba. +[TM2_A] +Toni ha salido a partir cabezas, o a intentarlo... -[GA_9] -Ha conseguido ~1~ de los 10 coches especiales. +[TM2_AA] +Nunca será tan duro como su padre. Te dejó una nota en la mesa. -[GA_10] -Buen trabajo. Aquí tienes tus ~1~ dólares. +[TM2_B] +La lavandería ya quiere pagar. ¡Buen trabajo, chico! -[GA_11] -Ya tenemos este modelo. ¡No nos sirve para nada! +[TM2_C] +Ve a por el dinero y tráelo aquí. Cuidado con las Tríadas. -[GA_12] -Bomba armada +[TM2_D] +Puede que intenten metértela doblada, pero no te dejes. -[GA_13] -Eres todo un profesional. Completa la lista y conseguirás una recompensa. +[TM2_E] +¡Nadie, quiero decir nadie, se mete con Toni Cipriani! -[GA_14] -Ya están todos los coches. ¡Estupendo! Toma un detallito. +[TM2_1] +~g~¡Lleva el dinero a Toni! -[GA_15] -Espero que te guste el nuevo color. +[TM2_2] +~g~¡Los dejaste tiesos a todos! -[GA_16] -Esta mano de pintura es gratuita. +[TM3_MA] +¡No sé dónde está! -[GA_19] -No nos interesa ese modelo. +[TM3_MB] +Te juro que mi hijo a veces no sabe lo que hace. -[GA_20] -Tenemos de esos más de los que necesitamos. Lo siento, tío, no hay trato. +[TM3_MC] +Ahora bien, su padre era diferente. Siempre en la cumbre, pendiente de todo, valiente... -[GA_21] -No puedes guardar más coches en este garaje. +[TM3_A] +Don Salvatore ha convocado una reunión. -[CR_1] -La grúa no puede levantar este vehículo. +[TM3_B] +Necesito que vayas a por la limusina y su hijo, Joey, a su taller. -{ ============================================================================================ } -{ ================= MESSAGES TO INDICATE THAT MISSIONS ARE NOT YET AVAILABLE ================= } -{ ============================================================================================ } +[TM3_C] +Luego recoge a Luigi en su club, ven a buscarme, -[GOAWAY] -~g~¡Ya estás en una misión! +[TM3_D] +y nos iremos todos juntos a la casa del jefe. -[LUIGGO] -~g~Luigi está entrevistando a unas chicas nuevas... ¡Vuelve más tarde! +[TM3_E] +Los de las Tríadas no saben cuándo parar... -[JOEYGO] -~g~Joey ha salido con Misty. ¡Pásate más tarde! +[TM3_F] +Si quieren guerra, la tendrán. -[TONIGO] -~g~Toni ha llevado a su mamá a la ópera... ¡Llama en otro momento! +[TM3_G] +Ponte en marcha. -[KEMUGO] -~g~María y Kemuri están muy liadas... ¡Pásate más tarde! +[TM3_1] +~g~Ve al taller de Joey a por la limusina. -[KENJGO] -~g~Kenji está reunido con la yakuza, ¡llama en otro momento! +[TM3_2] +~g~Recoge a Luigi. -[RAYGO] -~g~Ray tiene otros baños por los que rondar, ¡ven en otro momento! +[TM3_3] +~g~Ahora recoge a Toni. -[LOVEGO] -~g~Donald Love tiene otros asuntos que atender. ¡Pide una cita más tarde! +[TM3_4] +~g~Lleva a los mafiosos a la casa de Salvatore. -[KENSGO] -~g~¡Kenji está ocupado! ¡Llama más tarde! +[TM3_5] +~y~¡Es una emboscada de las Tríadas! -[ASUSGO] -~g~¡Asuka no está disponible en este momento! +[TM4_B] +¡Esto es la guerra! Las Tríadas tienen una piscifactoría como tapadera. -[HOODGO] -~g~¡Los Hoods no pueden atenderte en este momento! +[TM4_C] +Casi todos sus negocios pasan por la lonja de Chinatown. -[WRONGT1] -~g~Vuelve entre las 05:00 y las 21:00 para buscar trabajo. +[TM4_D] +La lavandería todavía no ha pagado la protección. -[WRONGT2] -~g~Vuelve entre las 06:00 y las 14:00 para buscar trabajo. +[TM4_E] +Creen que está protegida por las Tríadas, así que creo que se merecen un castigo. -[WRONGT3] -~g~Vuelve entre las 15:00 y las 00:00 para buscar trabajo. +[TM4_F] +¡Llévate a estos chicos y elimina a los líderes de las Tríadas! -{ ============================================================================ } -{ ================= SUBTITLES FOR THE AMMU-NATION SHOP CLERK ================= } -{ ============================================================================ } +[TM4_G] +Qué narices, si ves la oportunidad, cárgate también a unos cuántos de sus soldados. -[AMMU_A] -Luigi dijo que necesitabas una pipa... +[TM4_GAT] +~g~Necesitas un camión de pescado de las Tríadas para entrar. -[AMMU_B] -Joey me pidió que te armáramos... +[TM5_B] +Vale, ya me he hartado de esta mierda. -[AMMU_C] -Ve a la parte de atrás. Te dejé un nueve en el patio. +[TM5_C] +¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! -[AMMU_D] -Tengo todo lo necesario para defender tu casa. +[TM5_D] +8-Ball ha instalado una bomba en un camión de la basura. -[AMMU_E] -¿También quieres una licencia? +[TM5_E] +Tiene un temporizador, así que si la lías no quedará nada de ti. Ve a por el camión. -[AMMU_F] -No necesito tu documentación, pareces de fiar. +[TM5_F] +¡Cuidado, 8-Ball dice que es muy sensible y que cualquier golpe puede hacerlo estallar! -{ ==================================================================================================================== } -{ ==================================================================================================================== } -{ =============================================== SIDE MISSION STRINGS =============================================== } -{ ==================================================================================================================== } -{ ==================================================================================================================== } +[TM5_G] +Su piscifactoría abrirá sus puertas a uno de sus camiones, así que podrás entrar sin más. -{ ==================================================================== } -{ ================= TAXI/CABBIE SIDE MISSION STRINGS ================= } -{ ==================================================================== } +[TM5_H] +¡Aparca entre los tanques de gas y lárgate de ahí! -[TAXI_M] -'TAXISTA' +[TM5_I] +Quiero que llueva pescado. -[TSCORE2] -$~1~ +[TM5_J] +En plan bíblico, nada de bajo presupuesto. -[IN_ROW] -¡~1~ CONSECUTIVOS! $~1~ +[FM2] +'CORTANDO LA HIERBA' -[TAXIH1] -Para cerca de un peatón señalado para recogerlo, luego condúcelo a su destino antes de que se acabe el tiempo. +[FM4] +'ÚLTIMA VOLUNTAD' -[TAXI1] -~g~Busca un cliente. +[FM1_A] +Mis chicos y yo queremos hablar de negocios, -[TAXI2] -~r~¡Se te acabó el tiempo! +[FM1_B] +así que esta tarde vas a cuidar de mi chica. -[TAXI3] -~r~¡Tu pasajero ha salido corriendo! +[FM1_C] +¡OYE, MARÍA! ¡MUEVE ESE CULO! -[TAXI4] -¡Carrera terminada! +[FM1_D] +La muy idiota siempre hace lo mismo. -[TAXI5] -¡VIAJE RÁPIDO! +[FM1_E] +Y aquí está, ¡la primera y única reina de Saba! -[TAXI6] -Misión de taxi terminada +[FM1_F] +¿Qué hacías arriba? -[TAXI7] -~r~Tu coche está destrozado, haz que lo reparen. +[FM1_G] +Fuera lo que fuera, seguro que me cuesta dinero. -[FARE1] -~g~Ve al ~w~club Sex Kitten Meeouch ~g~en el barrio rojo. +[FM1_H] +Bueno, no pensarás que estoy aquí para conversar, ¿o sí? -[FARE2] -~g~Ve a ~w~Supa Save ~g~en Portland View. +[FM1_I] +Métete en el coche y cierra el pico. -[FARE3] -~g~Ve a ~w~la sala Clásica ~g~en Chinatown. +[FM1_J] +Llévate la limusina, pero devuélvela de una pieza, ¿me has oído? -[FARE4] -~g~Ve a la ~w~cafetería Greasy Joe ~g~en Callahan Point. +[FM1_K] +Y cuidado con ella, es una lianta. -[FARE5] -~g~Ve a la ~w~tienda de armas Ammu-Nation ~g~en el barrio rojo. +[FM1_L] +¡Sí, sí, sí! Seguro que tu nuevo perrito faldero tiene todo previsto. -[FARE6] -~g~Ve a ~w~Easy Credit Autos ~g~en Saint Mark's. +[FM1_M] +¿No es fuerte y grande? -[FARE7] -~g~Ve al ~w~bar de topless de Woody ~g~en el barrio rojo. +[FM1_N] +¡Oye, tú, vamos a ver a Chico para que nos dé unas pirulas! -[FARE8] -~g~Ve al ~w~restaurante Marcos ~g~en Saint Mark's. +[FM1_P] +~g~Ese de ahí es Chico, párate cerca. -[FARE9] -~g~Ve al ~w~taller de importación y exportación ~g~en el puerto de Portland. +[FM1_S] +Aquí tienes, señorita. -[FARE10] -~g~Ve a ~w~Punk Noodles ~g~en Chinatown. +[FM1_TT] +¡UNA REDADA! -[FARE11] -~g~Ve a la ~w~zona en obras~g~ de Fort Staunton. +[FM1_1] +~g~¡Vuelve al Stretch! -[FARE12] -~g~Ve al ~w~estadio de fútbol ~g~en Aspatria. +[FM1_2] +~g~¡Entra en el Stretch! -[FARE13] -~g~Ve a la ~w~iglesia ~g~de Bedford Point. +[FM1_3] +~r~Si abandonas a María, Salvatore hará que te maten. Vuelve y recógela. -[FARE14] -~g~Ve al ~w~casino ~g~de Torrington. +[FM1_4] +~g~¡Has dejado a la chica del Don tirada! ¡Vuelve al almacén y espera a María! -[FARE15] -~g~Ve a la ~w~universidad ~g~en el Campus de Liberty. +[FM1_5] +~g~¡Lleva a María sana y salva con Salvatore! -[FARE16] -~g~Ve al ~w~centro comercial ~g~en la zona del parque Belleville. +[FM1_6] +~g~¡Chico no estará esperando todo el día, lleva a María al muelle! -[FARE17] -~g~Ve al ~w~museo ~g~de Newport. +[FM1_7] +~r~¡María está muerta! A Salvatore le va a sentar muy mal... -[FARE18] -~g~Ve al ~w~edificio de AmCo ~g~en Torrington. +[FM1_8] +~r~¡Te cargaste al camello de María! -[FARE19] -~g~Ve a ~w~Bolt Burgers ~g~en Bedford Point. +[FM2_J] +Déjanos a solas un momento. -[FARE20] -~g~Ve al ~w~parque ~g~de Belleville. +[FM2_A] +El cártel colombiano fabrica SPANK en Liberty, -[FARE21] -~g~Ve al ~w~Aeropuerto Internacional Francis. +[FM2_K] +pero no sabemos dónde y parece como si supieran qué vamos a hacer antes de que lo pensemos. -[FARE22] -~g~Ve a la ~w~presa Cochrane~g~. +[FM2_L] +Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. -[FARE23] -~g~Ve al ~w~taller de importación/exportación~g~ en el distrito de la presa Cochrane. +[FM2_M] +Ha estado gastando más dinero del que gana. -[FARE24] -~g~Ve al ~w~hospital ~g~de Pike Creek. +[FM2_N] +Suele ir del trabajo a casa en taxi, así que síguelo. -[FARE25] -~g~Ve al ~w~parque ~g~de Shoreside Vale. +[FM2_O] +Y si nos está vendiendo... mátalo. -[FARE26] -~g~Ve a las ~w~Torres del Noroeste ~g~de Wichita Gardens. +[FM2_F] +Aquí viene nuestro amiguito. El señor Bocazas en persona. -[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! +[FM2_G] +¿Te han seguido? Ya sabes que esto es nuestro secretito. -[TTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. +[FM2_H] +No, no, no me han seguido. ¿Tienes lo mío? -[TTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de taxi. +[FM2_I] +Toma tu SPANK, soplón, ahora habla. -{ ============================================================================= } -{ ================= AMBULANCE/PARAMEDIC SIDE MISSIONS STRINGS ================= } -{ ============================================================================= } +[FM2_P] +Vale, los Leone libran una guerra en dos frentes. -[AMBUL_M] -'SANITARIO' +[FM2_Q] +Tienen una guerra territorial con las Tríadas y no parece que ninguno se vaya a rendir. -[A_SAVES] -GENTE SALVADA: ~1~ +[FM2_R] +Mientras tanto, Joey Leone ha cabreado a los Forelli. -[ATUTOR2] -~g~Conduce a los pacientes hasta el hospital con mucho cuidado. Cada golpe reducirá sus posibilidades de supervivencia. +[FM2_S] +Cada día pierden más hombres e influencia. -[A_TIME] -+~1~ segundos +[FM2_T] +Salvatore se está volviendo peligroso y paranoico. Sospecha de todos y de todo. -[A_FULL] -~r~¡Ambulancia llena! +[FM2_U] +Con lo leales que son algunos, ¿de qué tendría que preocuparse? -[A_RANGE] -~g~La radio de la ambulancia está fuera de cobertura, ¡acércate a un hospital! +[FM2_1] +~g~¡Ahí está Curly Bob! -[A_COMP1] -¡Misiones de sanitario completadas! +[FM2_2] +~g~¡Curly ha salido del club, síguelo! -[A_CANC] -~r~¡Misión de sanitario cancelada! +[FM2_5] +~g~Llévale al puerto de Portland. -[A_COMP3] -¡Misiones de sanitario completadas! ¡Ahora no te cansarás al correr! +[FM2_6] +~r~¡Curly no se meterá en un taxi cascado! -[ATUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. +[FM2_7] +~r~¡Curly se ha asustado! ¡Han cancelado la reunión! -[ATUTOR3] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. +[FM2_8] +~g~¡Elimina a Curly Bob! -[ALEVEL] -Nivel de misión de sanitario: ~1~ +[FM2_9] +~r~¡Curly Bob la ha espichado! -[A_FAIL1] -Misión de sanitario terminada. +[FM2_10] +~r~¡Curly se ha largado! -[A_FAIL2] -~r~¡Tu falta de rapidez ha sido fatal para el paciente! +[FM2_11] +~g~Aparca enfrente del club de Luigi; Curly Bob saldrá pronto. -[A_FAIL3] -~r~¡El paciente está muerto! +[FM2_12] +~r~¡Te ha dado esquinazo! -[A_PASS] -¡Rescatado! +[FM3_A] +Tenemos que despachar a esos puñeteros colombianos, -[A_COMP2] -¡Nunca te cansarás! +[FM3_B] +pero mientras estemos en guerra con las Tríadas, no tendremos la fuerza necesaria. -{ ============================================================================ } -{ ================= FIRE TRUCK/FIREMEN SIDE MISSIONS STRINGS ================= } -{ ============================================================================ } +[FM3_C] +El cártel tiene fondos ilimitados gracias a esa mierda del SPANK. -[FIRE_M] -'BOMBERO' +[FM3_D] +Si les atacamos abiertamente, nos harán picadillo. -[F_EXTIN] -INCENDIOS: +[FM3_E] +Estarán fabricando el SPANK en ese barco grande al que te llevó Curly. -[FTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. +[FM3_F] +Así que tenemos que actuar con cuidado, o mejor dicho, tú tienes que hacerlo. -[FTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones del camión de bomberos. +[FM3_G] +Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal para mí, Salvatore Leone. -[F_PASS1] -¡Fuego apagado! +[FM3_H] +Si haces esto por mí, serás como de la familia. Todo lo que quieras. -[F_FAIL1] -¡Misión del camión de bomberos terminada! +[FM3_I] +Ve a ver a 8-Ball, necesitarás su ayuda para volar ese barco. -[F_CANC] -~r~¡Misión del camión de bomberos cancelada! +[FM3_8A] +¡Hombre, colega! Salvatore me avisó, -[F_RANGE] -~g~La radio del camión de bomberos está fuera de cobertura, ¡acércate a una estación de bomberos! +[FM3_8B] +pero este trabajo va a necesitar muchos fuegos artificiales. -[F_FAIL2] -~r~¡Llegas demasiado tarde! +[FM3_8D] +pero ya sabes que conmigo valdrá la pena. -[F_START] -~g~Informe de vehículo en llamas en: ~a~. Ve y extingue el fuego. +[FM3_8E] +Venga, ¡vamos allá! -{ ============================================================================== } -{ ================= POLICE CAR/VIGILANTE SIDE MISSIONS STRINGS ================= } -{ ============================================================================== } +[FM3_8F] +Puedo reventar el barco, pero aún no puedo usar una pipa con estas manos. -[COP_M] -'JUSTICIERO' +[FM3_8G] +¡Toma, este fusil te ayudará a volar unas cuántas cabezas! -[C_KILLS] -CRIMINALES ABATIDOS: ~1~ +[FM3_4] +~g~¡Para el coche y deja que 8-Ball salga! -[LEGAL] -~g~¡Elimina la amenaza criminal! +[FM3_7] +~r~¡8-Ball ha pasado a mejor vida! -[C_BREIF] -~g~Sospechoso visto por última vez en: ~a~. +[FM3_8] +~r~¡Los guardias han sido alertados! -[C_RANGE] -~g~La radio de la policía está fuera de cobertura, ¡acércate a una comisaría! +[FM4_A] +¡Mi socio favorito! -[C_PASS] -¡AMENAZA ELIMINADA! +[FM4_B] +Estoy orgulloso de ti, hijo, pusiste finos a esos sudacas. -[CTUTOR] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. +[FM4_C] +Tengo un trabajito más para ti antes de que podamos celebrarlo. -[CTUTOR2] -Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. +[FM4_D] +Hay un coche a la vuelta del edificio del club de Luigi. -[COPCART] -~g~Tienes ~1~ segundos para volver a un vehículo de la policía antes de que termine la misión. +[FM4_E] +El interior está pringado de sesos. -[C_FAIL] -¡Misión de justiciero terminada! +[FM4_F] +Tuvimos que ayudar a un tipo a que se decidiera y fue un poco... sucio. -[C_CANC] -~r~¡Misión de justiciero cancelada! +[FM4_H] +Llévalo a la trituradora antes de que lo encuentre la pasma. -[C_ESCP] -~r~¡El sospechoso ha escapado! +[AM3] +'PURGA DE PAPARAZZIS' -[C_TIME] -~r~¡Tu trabajo como defensor de la ley ha terminado! +[AM4] +'LA PAGA DE RAY' -[C_VIGIL] -¡PREMIO POR JUSTICIERO! +[AM5] +'TANNER EL TRAIDOR' -{ ======================================================================== } -{ ================= CHECKPOINT RUN SIDE MISSIONS STRINGS ================= } -{ ======================================================================== } +[AM1_A] +Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, -[T4X4_1] -'PATIO DE RECREO' +[AM1_B] +sea de negocios u otra. Pongamos las cartas sobre la mesa. -[T4X4_1A] -~g~Tienes ~y~5 minutos~g~ para pasar por ~y~15~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. +[AM1_C] +Soy yakuza y sé que trabajaste para la familia de Salvatore Leone. -[T4X4_1B] -¡~1~ de 15! +[AM1_D] +Puedo darte trabajo en nuestra organización, -[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. +[AM1_E] +pero primero debes demostrarme que has cortado todos tus lazos con la mafia. -[T4X4_2] -'UN PASEO POR EL PARQUE' +[AM1_G] +Asegúrate de que no salga con vida. -[T4X4_2A] -~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~12~g~ puntos de control! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. +[AM1_H] +Mientras tanto María y yo nos pondremos al día. -[T4X4_2B] -¡~1~ de 12! +[AM1_I] +Uy, Asuka, tienes un masajeador... -[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. +[AM1_J] +Eso no es un masajeador. -[T4X4_3] -'¡AGARRADO!' +[AM1_1] +~g~¡Salvatore está saliendo del club de Luigi! -[T4X4_3A] -~g~Tienes ~y~5 minutos~g~ para pasar por ~y~20~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. +[AM1_2] +~r~¡Te han descubierto! -[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. +[AM1_3] +~r~¡Has perdido a Salvatore! -[T4X4_3C] -¡~1~ de 20! +[AM1_4] +~r~Muy bonito, ¡has asustado al objetivo! ¿Y te consideras un asesino? -[MM_1] -'CAOS EN EL APARCAMIENTO' +[AM1_5] +~g~Ve al barrio rojo y espera a que Salvatore salga del club. -[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. +[AM1_7] +~r~Salvatore está en su casita, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar ''Chacal''! -[MM_1_B] -¡~1~ de 20! +[AM1_8] +~g~Salvatore saldrá del club de Luigi sobre las ~1~:~1~. -[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. +[AM2_4] +~g~¡Has irrumpido como un elefante en una cacharrería! -[T4X4_F] -~r~¡Te has escapado! ¿Demasiado difícil para ti? +[AM3_A] +Un periodista ha estado husmeando por aquí. -{ ============================================================================ } -{ ================= RC CAR DESTRUCTION SIDE MISSIONS STRINGS ================= } -{ ============================================================================ } +[AM3_B] +María y yo nos ido de vacaciones juntas hasta que puedas librarte de ese mirón pervertido. -[RC1] -'DESTRUCCIÓN DE LOS DIABLOS' +[AM4_A] +¡Si es guapo manitas! -[RC2] -'LA MASACRE DE LA MAFIA' +[AM4_B] +María está un poquito liada, pero le diré que has venido. -[RC3] -'CALAMIDAD EN EL CASINO' +[AM4_C] +¿Quién es, Asuka? Sé que he sido muy traviesa, ¡pero necesito mear! ¿Vale? -[RC4] -'EXTERMINIO DE RUMPOS' +[AM4_D] +Es hora de que conozcas a nuestro espía en la policía. -[RC_1] -¡Tienes 2 minutos para destruir todos los coches de los Diablos que puedas! +[AM4_E] +Aquí está su pago por el último trabajito que hizo para nosotros. -[RC_2] -¡Tienes 2 minutos para destruir todos los coches de la mafia que puedas! +[AM4_F] +Él es comprensiblemente cauteloso. -[RC_3] -¡Tienes 2 minutos para destruir todos los coches de la yakuza que puedas! +[AM4_G] +Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. -[RC_4] -¡Tienes 2 minutos para destruir todos los coches de los jamaicanos que puedas! +[AM5_A] +María y yo hemos ido de compras. -[RC_5] -¡Tienes 2 minutos para destruir todos los coches de los Hood que puedas! +[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! -[RC_6] -¡Tienes 2 minutos para destruir todos los coches del cártel que puedas! +[AM5_C] +Fuera de su coche no sabe hacer casi nada, así que le hemos puesto un localizador. -{ ==================================================================================================================== } -{ ==================================================================================================================== } -{ ================================================ MAIN STORY STRINGS ================================================ } -{ ==================================================================================================================== } -{ ==================================================================================================================== } +[AM5_D] +¡Haz que sufra! -{ ================================================== } -{ ================= OPENING SCENES ================= } -{ ================================================== } +[AM5_1] +¡Tanner te ha pillado! -{ Catalina, colombiana } +[AS1] +'CEBO' -[BETRA_A] -Lo siento, cariño. +[AS2] +'CAFÉ PARA LLEVAR' -[BETRA_B] -Soy una chica ambiciosa, ¿y tú? +[AS4] +'RESCATE' -[BETRA_C] -Un Don Nadie. +[AS1_A] +Parece que Miguel piensa que le maltrato. -{ Newspaper clip. Only PAPER1 is used } +[AS1_B] +Pero ha revelado cuánto teme Catalina tu búsqueda de venganza. -[PAPER1] -CRIMINAL HERIDO DE BALA POR SU NOVIA Y CÓMPLICE; EL TRIBUNAL ENCUENTRA CULPABLE AL ATRACADOR CON UN VEREDICTO UNÁNIME. +[AS2_A] +Subestimamos los planes que tiene Catalina para el SPANK. -[PAPER2] -¡DIEZ AÑOS POR AMOR! +[AS2_B] +Va mucho más allá de hacer que los jamaicanos lo vendan en las esquinas. -[PAPER3] -* +[AS2_D] +Vende SPANK en puestos callejeros. -{ Cutscene where the Colombians kidnap the Old Oriental Gentlemen. Claude and 8-Ball escape from the van. } +[AS2_1] +~g~¡Todos los puestos de café en Portland han sido destruidos! -{ Libery City News broadcaster } +[AS2_2] +~g~¡Todos los puestos de café en Staunton Island han sido destruidos! -[JAILB_V] -Hoy, Liberty City se ha visto conmocionada. +[AS2_3] +~g~¡Todos los puestos de café en Shoreside Vale han sido destruidos! -[JAILB_A] -La policía y los servicios de emergencia lidian con las consecuencias +[AS2_4] +~r~¡El cártel ha avisado a sus camellos! -[JAILB_B] -de un ataque devastador a un convoy policial ocurrido esta mañana. +[AS2_5] +~g~¡Todavía hay puestos de café en Shoreside Vale y en Staunton Island! -[JAILB_C] -No se ha informado de quiénes eran los prisioneros trasladados en el convoy +[AS2_6] +~g~¡Todavía hay puestos de café en Shoreside Vale! -[JAILB_D] -y ningún grupo ha reconocido la autoría. +[AS2_7] +~g~¡Todavía hay puestos de café en Staunton Island! -[JAILB_E] -El convoy abandonó las oficinas de la policía esta mañana +[AS2_8] +~g~¡Todavía hay puestos de café en Portland! -[JAILB_F] -para hacer una transferencia de reos a la penitenciaría de Liberty. +[AS2_9] +~g~¡Todavía hay puestos de café en Portland y en Shoreside Vale! -[JAILB_G] -El ataque se produjo en el puente Callahan, +[AS2_10] +~g~¡Todavía hay puestos de café en Portland y en Staunton Island! -[JAILB_H] -dejando pocos testigos y al puente seriamente dañado. +[AS2_12] +~g~¡Recorre los distritos de Liberty y busca puestos de café ~b~Espresso-2-Go~g~! -[JAILB_I] -Se cree que algunos de los convictos han perecido en la explosión +[AS3_A] +¿Lo apretamos un poco más o esperamos a que se vuelva negro y se caiga? -[JAILB_J] -posterior al ataque inicial. +[AS3_B] +Dale un toque rápido... -[JAILB_W] -Pasadas las horas se hizo evidente que el ataque era obra de profesionales, +[AS3_D] +¡Mi manitas! -[JAILB_K] -ya que la identificación de los prófugos se complicó +[AS3_E] +Me aburría, así que vine a hacerle compañía a Asuka. -[JAILB_L] -cuando piratas informáticos atacaron las bases de datos de la policía. +[AS3_1] +~g~¡Busca una ~r~lancha~g~ y ve a la ~b~boya señalada! -[JAILB_O] -Con el retraso del proyecto del túnel Porter, +[AS3_3] +~g~¡Espera a que la ~y~avioneta~g~ comience a acercarse! -[JAILB_P] -este desastre deja a Portland aislada del resto de la ciudad. +[AS3_5] +~g~¡Recupera el cargamento! -[JAILB_M] -* +[AS3_4] +~g~¡Usa un lanzacohetes para derribar ~y~la avioneta~g~! -[JAILB_N] -* +[AS3_2] +~b~¡Ve a la boya del aeropuerto señalada! ~y~¡El avión se está acercando! -[JAILB_X] -En una declaración realizada hoy previamente, +[AS3_6] +~g~~1~ DE 8 -{ Colombian thug } +[KM1] +'LA FUGA DEL KANBU' -[JAILB_Q] -¡Vamos! +[KM3] +'UN MAL TRATO' -[JAILB_R] -¡Señor pendejo! +[KM4] +'SHIMA' -[JAILB_S] -No nos importará matarte. +[KM5] +'CONTRINCANTES TRAFICANTES' -{ Police officer } +[KM1_A] +Mi hermana te tiene en gran estima, -[JAILB_T] -Os vais a arrepentir. +[KM1_E] +pero yo debo convencerme de que un gaijin puede ofrecerme algo más que desilusiones. -{ Colombian thug } +[KM1_B] +Tal vez puedas ayudar con una situación que me tiene en desventaja. -[JAILB_U] -Bien, bien, piérdete. +[KM1_F] +Por supuesto, el fracaso conllevará una desgracia. -{ ======================================================================= } -{ ================= MISSION: GIVE ME LIBERTY (NO OWNER) ================= } -{ ======================================================================= } +[KM1_C] +Un kanbu, o jefe de la yakuza, está bajo custodia a la espera de juicio. -{ TITLE } +[KM1_G] +Es un miembro importante de la familia. -[EBAL] -'DAME LIBERTAD' +[KM1_H] +Libéralo y llévatelo al dojo de Bedford Point. -{ 8-Ball } +[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. -[EBAL_A] -Conozco un lugar en las afueras del barrio rojo donde podemos escondernos, +[KM1_1] +~g~¡Roba un coche de la policía! -[EBAL_A1] -pero mis manos están destrozadas, así que conduce tú, hermano. +[KM1_2] +~g~¡Instala una bomba en el coche! -{ Mission instructions } +[KM1_3] +~g~Ahora llévalo al dojo de la yakuza. -[EBAL_1] -Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. +[KM1_5] +~g~Ahora ve a la comisaría. -[EBAL_1B] -Pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para ~h~entrar ~w~o ~h~salir~w~ de un vehículo. +[KM1_6] +~g~¡Pon una bomba en el coche! -[EBAL_2] -~g~¡Vuelve al coche! +[KM1_7] +~g~¡Sólo pueden entrar vehículos de policía autorizados! -[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! +[KM1_9] +~r~No destruiste la pared con un coche bomba. -{ 8-Ball } +[KM1_10] +~r~El kanbu está muerto, ¡y tu honor también! -[EBAL_B] -Es aquí, ¡entremos y cambiémonos de ropa! +[KM1_11] +~r~¡La policía te ha seguido! -{ 8-Ball } +[KM2_A] +Es imposible sobreestimar la importancia del protocolo en este trabajo. -[EBAL_D] -Conozco a un tipo con contactos, se llama Luigi. +[KM2_B] +Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca pude corresponder su amabilidad. -[EBAL_D1] -Somos viejos amigos, así que podremos buscarte curro. Vamos a verlo. +[KM2_C] +Su debilidad son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. -{ 8-Ball } +[KM2_F] +Mi honor lo exige. -[EBAL_E] -Venga, vamos a pasarnos por allí y te presentaré. +[KM2_2] +~g~Coche entregado. -{ 8-Ball } +[KM3_A] +Cuando los problemas acechan, el tonto les da la espalda, mientras que el sabio los enfrenta. -[EBAL_G] -Este es el club de Luigi. Vamos a la parte de atrás, a la puerta de servicio. +[KM3_B] +El cártel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. -{ ============================================================================ } -{ ================= MISSION: LUIGI'S GIRLS (LUIGI GOTERELLI) ================= } -{ ============================================================================ } +[KM3_C] +Ahora están negociando con los jamaicanos para humillarnos aún más. -{ TITLE } +[KM3_D] +Están cerrando un trato en la ciudad. -[LM1] -'LAS CHICAS DE LUIGI' +[KM3_F] +Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus respetos a los colombianos. -{ Premission cutscene } +[KM3_E] +¡Nuestro honor exige que no dejes a nadie vivo! -{ 8-Ball } +[KM3_2] +~g~Recoge a tu contacto. -[EBAL_H] -Espera, tío, que voy a hablar con Luigi. +[KM3_3] +~g~¡La reunión está teniendo lugar en el aparcamiento del hospital de Rockford! -{ Mick (unused) } +[KM3_4] +~r~¡Han escapado! -[EBAL_I] -El jefe os recibirá enseguida... +[KM3_6] +~g~¡Mátalos, mátalos a todos! -{ Luigi } +[KM3_8] +~g~¡Necesitas un coche de los jamaicanos para este trabajo! -[EBAL_J] -8-Ball que ocuparse de una cosa arriba. +[KM3_9] +~r~Uno de los colombianos ha muerto, se ha cancelado el trato. -[EBAL_K] -Quizá puedas hacerme un favor. +[KM3_10] +~r~¡El contacto está muerto! -[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í. +[KM4_A] +Para ser verdaderamente fuerte, es importante no mostrar debilidad. -[EBAL_M] -¡Recuerda: nadie se mete con mis chicas! +[KM4_C] +Hazte con el dinero inmediatamente para que podamos ingresarlo en las cuentas del casino. -[EBAL_N] -¡Así que no quites las manos del volante! +[KM4_1] +¡No puedo pagarte y no lo haría aunque pudiera! -[EBAL_O] -Si no la cagas, puede que haya más trabajo para ti. ¡Ahora largo! +[KM4_9] +¡Una banda de chavales acaba de arrasar el local! ¡Se han llevado todo! -{ Misty } +[KM4_2] +¡Sois inútiles! -[LM1_9] -Hola, soy Misty. +[KM4_10] +Además, ¿qué clase de yakuza eres tú? -{ Mission instructions } +{ Unused string? } -[EBAL_4] -~r~¡8-Ball ha muerto! +[KM4_3] +No pago a matones como vosotros para esto. Si quisiera esta clase de protección, llamaría a la policía, demonios. -[EBAL_5] -~g~¡Consigue un vehículo! +[KM4_4] +~g~¡Castiga a la banda responsable y recupera el ~b~dinero de la protección~g~! -[EBAL_6] -~g~¡Recoge a Misty! +[KM4_7] +~r~¡El tendero la acaba de palmar! -[LM1_2] -~g~Lleva a Misty al club de Luigi. +[KM4_5] +Donald Love desea que te pases por su jardín de té para tener una charla. -[LM1_3] -~g~Toca el claxon para que la chica entre en el coche. +[KM4_6] +¡Aquí está todo el dinero! -[LM1_6] -~g~¡Vuelve al coche! +[KM4_8] +~g~¡Maletín recolectado! -[MISTY1] -~r~¡Misty está para el arrastre! +[KM5_A] +¡Tú! ¡Qué oportuno por tu parte que muestres ahora tu despreciable cara! -[LM1_7] -Detén el vehículo junto a Misty y déjala subir. +[KM5_B] +¡Parece que tus intentos para disuadir a los jamaicanos -{ Post-mission instructions } +[KM5_B1] +de convertirse en aliados del cártel han sido totalmente inútiles! -[LM1_8] -Puedes ir a ver a Luigi y buscar más trabajo o darte un paseo por Liberty City. +[KM5_C] +¡Los traficantes jamaicanos están llenando las calles de Liberty, vendiendo SPANK como si fueran perritos calientes! -[LM1_8A] -Si quieres ganar un dinerillo extra, siempre puedes ''coger prestado'' un taxi... +[KM5_D] +Estos cerdos del cártel se están riendo de nosotros, ¡de mí! -{ ====================================================================================== } -{ ================= MISSION: DON'T SPANK MA BITCH UP (LUIGI GOTERELLI) ================= } -{ ====================================================================================== } +[KM5_E] +¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene un buen motivo! -{ TITLE } +[KM5_F] +¡Arrolla a estos canallas y lava tu vergüenza en el río de la sangre de nuestros enemigos! -[LM2] -'NO DROGUES A MI ZORRA' +[KM5_3] +~r~No has matado a ~1~ jamaicanos. -{ Premission cutscene } +[KM5_4] +~g~Enhorabuena, has matado a ~1~ jamaicanos. -{ Mick } +[KM5_5] +~g~Enhorabuena, has matado a ~1~ jamaicanos. ~1~$ ADICIONALES -[LM2_C] -Luigi dijo que... que te diera esto... +[RM1] +'SILENCIA AL SOPLÓN' -[LM2_D] -toma, toma, para ti. +[RM3] +'FALTA DE PRUEBAS' -{ Luigi (letter) } +[RM4] +'DE PESCA' -[LM2_A] -Hay una nueva droga en la ciudad llamada SPANK. +[RM5] +'DESESCAYOLADOR' -[LM2_E] -Algún listillo ha estado dando esta basura a mis chicas en el puerto de Portland. +[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. -[LM2_B] -¡Ve y dale con un bate de béisbol en su cara! +[RM1_E] +Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con nadie. -[LM2_F] -Luego coge su coche y repíntalo. +[RM1_1] +~g~Ve a la casa de protección de testigos. -[LM2_G] -¡Quiero una compensación por este insulto! +[RM1_2] +~g~¡Cárgate a McAffrey! -{ Mission instructions } +[RM2_A1] +¡Chico, estoy aquí! -[LM2_1] -~g~Coge su coche y haz que cambien su pintura. +[RM2_A] +Un viejo colega del ejército tiene un negocio en Rockford. -[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! +[RM2_D] +Va a necesitar respaldo y a cambio te venderá material de todo tipo a precios de ganga. -[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! +[RM2_E] +Ray me avisó... Pero pensé que vendría más gente. -[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! +[RM2_F] +Bueno, tres brazos son mejor que uno, así que sírvete. -[LM2_3] -~g~¡Mete el coche en el garaje de Luigi! +[RM2_G] +~g~¡Ve a ver a Phil! -[LM2_4] -~g~¡Vuelve a pintar el coche! +[RM2_H] +~r~¡Han matado a Phil! -{ ================================================================================= } -{ ================= MISSION: DRIVE MISTY FOR ME (LUIGI GOTERELLI) ================= } -{ ================================================================================= } +[RM2_L] +¡Caray! ¡Si hubieras estado a mi lado en Nicaragua, a lo mejor conservaría el brazo! -{ TITLE } +[RM2_N] +Deja el dinero en el suelo. Ahora vete, ya me ocupo yo de la poli. -[LM3] -'LLEVA A MISTY POR MÍ' +[RM3_D] +Están transportando las pruebas por la ciudad. -{ Premission cutscene } +[RM3_E] +Tendrás que embestir al coche y recoger hasta la última prueba que se le caiga. -{ Luigi } +[RM3_F] +En cuanto tengas todas, déjalas en tu coche y préndele fuego. -[LM3_A] -Hola, tengo que hablar contigo... Bueno, Mick, ya hablaremos. +[RM3_G] +Cuando acabes, nos irá mucho mejor, chico. -[LM3_B] -¿Cómo te va, chico? +[RM3_1] +~g~Deja las pruebas en un coche y después préndele fuego. -[LM3_C] -El hijo del Don, Joey Leone, quiere fiesta con su chica de siempre, Misty. +[RM3_4] +~g~¡Al fiscal se le ha caído una prueba! -[LM3_D] -Recógela en los cerros de Hepburn, +[RM3_6] +~r~¡Las fotos circularán por toda la ciudad! -[LM3_E] -pero cuidado, ese es territorio de los Diablos. +[RM3_7] +~g~¡Ahora préndele fuego al coche! -[LM3_F] -Luego llévala rapidito hasta su taller en Trenton, +[RM4_A] +Creo que mi socio es un soplón. -[LM3_G] -que a Joey no le gusta esperar. Recuerda, tienes un pie dentro... +[RM4_C] +Casi todas las noches sale a pescar con su lancha cerca del faro que hay en Portland Rock. -[LM3_H] -¡así que estate pendiente del camino y no de Misty! +[RM4_D] +¡Roba una lancha de la policía y asegúrate de que se le acaben las ganas de dar puñaladas traperas! -{ Mission instructions } +[RM4_1] +~g~Ve y roba una lancha de la policía. -[LM3_1D] -Pulsa el ~h~botón L3 ~w~para tocar el ~h~claxon~w~ y hacer saber a Misty que estás aquí. +[RM4_2] +~g~¡Ve al faro y ''hunde'' al socio de Ray! -[LM3_2] -~g~Lleva a Misty al local de Joey. +[RM5_A] +¡Inútil de mierda! -[LM3_4] -~g~¡Recoge a Misty! +[RM5_A1] +¡La has cagado! Me la estoy jugando y ni siquiera eres capaz de matar a una maldita mosca. -[LM3_10] -~g~¡Consigue un vehículo! +[RM5_B] +¡Te pagué una pasta para matar al testigo y aún sigue vivo! -[LM3_11] -~g~Misty no irá en un autobús, ¡hazte con otro vehículo! +[RM5_B1] +¡Y hoy va a declarar ante los federales! -[LM3_1A] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. +[RM5_C] +Está a punto de ser trasladado del hospital general Carson, en Rockford. -[LM3_1B] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. +[RM5_D] +Si él canta, yo canto... -[LM3_1C] -Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. +[RM5_E] +¡así que termina el trabajo por el que te pagué! -{ Misty } +[RM5_1] +~g~Intercepta la ambulancia. -[LM3_5] -Ahora trabajas para Luigi, ¿no? ¡Ya era hora de que tuviese un conductor de confianza! +[RM5_2] +~g~¡Te han descubierto! -{ Postmission cutscene } +[RM5_3] +~g~¡Era un señuelo! -{ Misty } +[RM5_4] +~g~¡Las balas no penetran en esa escayola de cuerpo entero! -[LM3_6] -¡Joey...! +[RM5_5] +~g~¡Esa escayola de cuerpo entero es ignífugo! -[LM3_6A] -¿Voy a jugar con tu paquetín otra vez? +[RM5_7] +~r~¡El testigo está a salvo! -{ Joey } +[RM5_8] +~g~¡El testigo se ha ahogado! -[LM3_7] -Estaré contigo en un minuto, bujía mía. +[LOVE2] +'¡EXTERMINA AL WAKA-GASHIRA!' -[LM3_8] -Hola, soy Joey. +[LOVE3] +'UNA GOTA EN EL OCÉANO' -[LM3_9] -Luigi dijo que eras de fiar, así que vuelve más tarde, +[LOVE1_A] +Antes que nada, permíteme agradecerte que te hayas ocupado de ese asunto personal. -[LM3_9A] -que tendré trabajo para ti. +[LOVE1_F] +Últimamente la gente tiende a malinterpretar las cosas. -[LM3_9B] -¿De acuerdo? +[LOVE1_D] +Pretenden exigirme más de lo pactado, pero no me gusta renegociar. -{ =============================================================================== } -{ ================= MISSION: PUMP-ACTION PIMP (LUIGI GOTERELLI) ================= } -{ =============================================================================== } +[LOVE1_E] +Un trato es un trato, así que no van a ver ni un dólar mío. -{ TITLE } +[LOVE1_G] +Rescata a mi amigo cueste lo que cueste. -[LM4] -'UN CHULO Y SU ESCOPETA' +[LOVE1_2] +~g~Rescata al anciano oriental. -{ Premission cutscene } +[LOVE1_3] +~g~Lleva al anciano oriental de vuelta al edificio de Donald Love. -{ Luigi } +[LOVE1_4] +~g~El anciano oriental debe estar detrás de alguna de estas puertas... -[LM4_A] -Algún Diablo de las narices ha estado vendiendo a sus putitas en mi territorio. +[LOVE1_6] +~r~¡Las tripas del anciano oriental están desparramadas por las calles! -[LM4_B] -Ve y resuélvelo de mi parte. +[LOVE1_7] +~g~La puerta sólo se abrirá ante un coche de los colombianos. -[LM4_C] -Si necesitas un arma, ve a la puerta trasera de la tienda Ammu-Nation que está enfrente del metro. +[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. -{ ============================================================================ } -{ ================= MISSION: THE FUZZ BALL (LUIGI GOTERELLI) ================= } -{ ============================================================================ } +[LOVE2_C] +He observado que la yakuza y los colombianos no son precisamente buenos amigos. -{ TITLE } +[LOVE2_D] +Vamos a aprovechar esta oportunidad de negocio. -[LM5] -'EL BAILE DE LA POLICÍA' +[LOVE2_E] +Quiero que mates a Kenji Kasen, el waka-gashira (segundo al mando) de la yakuza. -{ Premission cutscene } +[LOVE2_F] +Kenji está asistiendo a una reunión en lo alto del aparcamiento de Newport. -{ Luigi } +[LOVE2_G] +¡Hazte con un coche de la banda del cártel y elimínalo! -[LM5_A] -El baile de la policía se está celebrando en la sala Clásica, cerca del puente, +[LOVE2_H] +La yakuza debe culpar al cártel de esta declaración de guerra. -[LM5_B] -y parece que tienen ganas de una fiesta más ''clásica''. +[LOVE2_1] +~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! -[LM5_C] -Tengo chicas haciendo la calles. +[LOVE2_2] +~g~¡Ahora ve al ~p~aparcamiento de Newport~g~ y cárgate a Kenji! -[LM5_D] -Llévalas al baile, sacarán una buena tajada. +[LOVE2_3] +~r~¡Si no llevas un coche del cártel, te descubrirán! -[LM5_E] -Saca todo el dinero que puedas a los polis antes de que se lo beban. +[LOVE2_4] +~r~¡La yakuza te ha reconocido! -{ Mission instructions } +[LOVE2_6] +~r~¡Has matado a todos los testigos! -[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. +[LOVE3_A] +En estos días de hipocresía moral, ciertos artículos pueden resultar difíciles de importar. -[LM5_2] -~r~¡Te has cargado a una de las chicas de Luigi! +[LOVE3_C] +Echará varios paquetes al agua. -[LM5_3] -~g~¡Necesitas un coche! +[LOVE3_D] +Asegúrate de los consigues antes que nadie. -[LM5_4] -~g~Recoge a las chicas que trabajan en Saint Mark's. +[LOVE3_1] +~g~¡Consigue una ~r~lancha~g~ y sigue a la ~y~avioneta~g~! -[LM5_5] -~g~¡Lleva a las chicas al baile de la policía! +[LOVE4] +'ROBO DE ALTOS VUELOS' -[LM5_7] -~g~¡Si hay menos de cuatro chicas trabajando en el ~p~baile de la policía~g~, Luigi no estará contento! +[LOVE5] +'SERVICIO DE ESCOLTA' -[LM5_8] -~g~Chicas trabajando en el baile: ~1~ +[LOVE4_A] +Gracias por conseguir esos paquetes, pero sólo eran un señuelo. -[LM5_9] -CHICAS: +[LOVE4_B] +Lo siento, pero a veces los negocios son así. -{ ============================================================================== } -{ ================= MISSION: MIKE LIPS LAST LUNCH (JOEY LEONE) ================= } -{ ============================================================================== } +[LOVE4_C] +Mi verdadero objetivo se ocultaba en la avioneta. -{ TITLE } +[LOVE4_F] +He sobornado a los funcionarios. -[JM1] -'EL ÚLTIMO ALMUERZO DE MIKE ''LABIOS'' ' +[LOVE4_1] +~r~¡El cártel colombiano está aquí! -{ Premission cutscene } +[LOVE4_2] +~g~¡El paquete ha desparecido! Síguele la pista a los colombianos y recupéralo. -{ Misty } +[LOVE4_3] +~g~¿''Panlantic Construction''...? -[JM1_A] -Jo, me aburro, ¿cuándo me la vas a meter? +[LOVE4_5] +~g~El paquete debería estar en la avioneta... -{ Joey } +[LOVE4_6] +~g~¡Usa el ascensor! -[JM1_B] -Dame un momento, cariño, que tengo un asuntillo que tratar. +[LOVE5_B] +Mi amigo oriental necesitará que le escolten mientras comprueba la autenticidad de mi última adquisición. -[JM1_C] -Tengo un trabajito para ti, colega. +[LOVE5_1] +~g~¡En marcha! -[JM1_D] -Los hermanos Forelli me deben dinero desde hace mucho tiempo +[LOVE5_2] +~g~¡Vas a necesitar un coche! -[JM1_E] -y hay que enseñarles respeto. +[LOVE5_3] +~g~¡Comprueba la salida del túnel! -[JM1_F] -Labios Forelli está atiborrándose en el restaurante de Saint Mark's, +[LOVE5_4] +~r~¡Protege el camión! -[JM1_G] -así que róbale el coche y llévalo al taller de bombas de 8-Ball en Harwood. +[RM6] +'HOMBRE MUERTO' -[JM1_H] -Conoces a 8-Ball, ¿verdad? +[RM6_A] +¿No te han seguido? Bien. -[JM1_I] -En cuanto esté cargado con una bomba, aparca el coche donde lo encontraste. +[RM6_B] +Se acabó, ¡esto se me va de las manos y estoy con la soga al cuello! -[JM1_J] -Luego salte y disfruta del espectáculo. +[RM6_D] +Soy hombre muerto, así que tengo que largarme. -[JM1_K] -Pero cuidado, no va a estar comiendo toda la vida. +[RM6_E] +¡Consigue que no pierda mi vuelo en el aeropuerto y haré que tu trabajo haya merecido la pena! -{ Mission instructions } +[RM6_666] +Cuida mi Patriot a prueba de balas. Nos vemos en Miami, Ray -[JM1_1] -~g~Lleva el coche de Forelli al taller que tiene 8-Ball al norte, tras Easy Credit Autos. +[CAT1] +'RESCATE' -[JM1_2] -~g~Vuelve a aparcar el coche frente al restaurante de Marco. +[CAT2] +'EL INTERCAMBIO' -[JM1_3] -~g~¡Activa la bomba del coche y luego sal de ahí! +[CAT1_A] +Tengo a tu linda María. Si no quieres que parezca que un carnicero se ensañó con ella, -[JM1_4] -~g~¡Te estás cargando el coche! ¡Repáralo! +{ UNUSED DUPLICATE } -[JM1_5] -~g~¡La bomba del coche no está activada! +[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! -[JM1_6] -~g~Vuelve a aparcar el coche en el sitio correcto. +{ UNUSED DUPLICATE } -[JM1_7] -~g~¡Cierra la puerta del coche! ¡Se dará cuenta! +[CAT2_G] +Estaba muerta de miedo, pero luego me dije a mí misma: ''Ya eres mayorcita''. -{ 8-Ball's messages, not voiced } +{ UNUSED DUPLICATE } -[JM1_8A] -~y~¡Ey, pero si es mi colega! +[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, -[JM1_8B] -~y~El taller de bombas está automatizado. Solo tienes que meter el coche, pararlo y el taller hará el resto. +{ UNUSED DUPLICATE } -[JM1_8C] -~y~Ten, tu primer coche es gratis, pero los siguientes te los cobraré. +[CAT2_I] +porque su marido a vuelto a enredar por ahí y... -{ ===================================================================================== } -{ ================= MISSION: FAREWELL 'CHUNKY' LEE CHONG (JOEY LEONE) ================= } -{ ===================================================================================== } +[CAT1_F] +¡Ve a donde está Catalina antes de que se acabe el tiempo! -{ TITLE } +[CAT_MON] +~g~Todavía te falta dinero. Necesitas 500.000 dólares. -[JM2] -'DESPEDIDA A LEE CHONG ''EL GORDO''' +[BITCH_D] +~g~¡María está muerta! -{ Premission cutscene } +[WEATHER] +FORZAR EL CLIMA -{ Joey } +[WEATHE2] +CLIMA NORMAL -[JM2_A] -Lee Chong ''el Gordo'' está traficando SPANK para una nueva banda de Colombia... o Colorado... O como se llame. +[8001] +¡Has fallado miserablemente! -[JM2_B] -No me acuerdo. El caso es que no importa. +[1000] +HAS MUERTO -[JM2_C] -Tiene un puesto de fideos en Chinatown. +[1001] +HAS MUERTO -[JM2_D] -Ese cabrito ha vendido su último fideo. +[1002] +HAS MUERTO -[JM2_E] -¡Lo quiero muerto! +[1003] +HAS MUERTO -[JM2_F] -Si necesitas una pipa, ve a la parte de atrás del Ammu-Nation que está enfrente del metro. +[1004] +HAS MUERTO -[JM2_G] -Búscate un nueve, queda claro, ¿no? +[1005] +TRINCADO -[JM2_H] -Y recuerda, ve con ojo en Chinatown: es territorio de las Tríadas. +[1006] +TRINCADO -{ =================================================================== } -{ ================= MISSION: VAN HEIST (JOEY LEONE) ================= } -{ =================================================================== } +[1007] +TRINCADO -{ TITLE } +[1008] +TRINCADO -[JM3] -'EL ROBO DE LA FURGONETA' +[1009] +TRINCADO -{ Premission cutscene } +[GA_4] +Una bomba de coche vale 1.000 dólares. -{ Joey } +[GA_5] +Tu coche ya tiene una bomba instalada. -[JM3_A] -Vamos a asaltar un furgón blindado. +[GA_6] +¡Apárcalo, activa el detonador pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! -[JM3_B] -Sale de Chinatown todos los días. +[GA_7] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. -[JM3_C] -Las balas ni siquiera abollarán el furgón, así que coge un coche y échalo de la carretera. +[GA_8] +Utiliza el detonador para activar la bomba. -[JM3_D] -Si lo zurras bien, los imbéciles de los guardias se achantarán. +[GA_9] +Ha conseguido ~1~ de los 10 coches especiales. -[JM3_E] -Luego llévalo al almacén de los muelles y mis chicos se encargarán desde ahí. +[GA_10] +Buen trabajo. Aquí tienes tus ~1~ dólares. -[JM3_F] -El furgón no estará fuera todo el día, así que no pierdas el tiempo. +[GA_11] +Ya tenemos este modelo. ¡No nos sirve para nada! -{ Mission instructions } +[GA_12] +Bomba armada -[JM3_1] -~g~Lleva el furgón al almacén. +[GA_13] +Eres todo un profesional. Completa la lista y conseguirás una recompensa. -[JM3_2] -~g~Carga contra la furgoneta hasta que su daño esté por debajo del 70 por ciento. +[GA_14] +Ya están todos los coches. ¡Estupendo! Toma un detallito. -{ ============================================================================== } -{ ================= MISSION: CIPRIANI'S CHAUFFEUR (JOEY LEONE) ================= } -{ ============================================================================== } +[GA_15] +Espero que te guste el nuevo color. -{ TITLE } +[GA_16] +Esta mano de pintura es gratuita. -[JM4] -'EL CHÓFER DE CIPRIANI' +[GA_19] +No nos interesa ese modelo. -{ Premission cutscene } +[GA_20] +Tenemos de esos más de los que necesitamos. Lo siento, tío, no hay trato. -{ Joey } +[CR_1] +La grúa no puede levantar este vehículo. -[JM4_A] -Sí, Toni, ya está a punto. Ahora es una delicia, ¿sabes? +[PU_MONY] +No tienes suficiente dinero. -[JM4_B] -¡Ah, aquí está el tío que te decía! +[CO_ALL] +Te has hecho con todos. Toma un detallito... -[JM4_C] -Bueno, este no es italiano ni tampoco mecánico, pero sabe arreglar cosas. +[PAUSED] +PARTIDA EN PAUSA -[JM4_D] -Este es el capo de papá, Toni Cipriani. +[HEALTH1] +¡Largo! Estás completamente sano. -{ Toni } +[HEALTH2] +La sanidad cuesta dinero. -[JM4_E] -Sí, soy Toni Cipriani. +[HEALTH3] +Te pondré como nuevo. -{ Joey } +[HEALTH4] +Te va a costar 250 $. -[JM4_F] -Llévale al restaurante de Mamma en Saint Mark's, ¿va? +[FEB_STA] +Estadísticas -[JM4_G] -Oye, estoy planeando un curro que necesita un buen conductor, pásate por aquí más tarde, ¿estamos? +[FEB_BRI] +Resumen -{ Mission instructions } +[FEB_CON] +Controles -[JM4_7] -~g~Lleva a Toni al restaurante de Mamma. +[FEB_AUD] +Sonido -[JM4_8] -~r~¡Han liquidado a Toni! +[FEB_DIS] +Pantalla -{ Toni, cutscene right after the premission one } +[FEB_LAN] +Idioma -[JM4_10] -Vale, chaval, llévame primero a la lavandería de Chinatown, tengo un asunto del que ocuparme. +[FEP_STA] +ESTADÍSTICAS -[JM4_11] -Las lavanderas no están pagando por su protección. +[FEP_BRI] +RESUMEN -[JM4_12] -Y ojo con el coche, Joey acaba de arreglar esta chatarra. +[FEP_CON] +CONTROLES -[JM4_13] -Así que con cuidado, ¿vale? +[FEP_AUD] +SONIDO -{ Toni, when bumping the car } +[FEP_DIS] +PANTALLA -[JM4_6] -¡Mi coche! Dije que con cuidado. +[FEP_LAN] +IDIOMA -{ Toni, when reaching the laundry } +[FEF_ST1] +¿Quién es el malo? -[JM4_2] -¡Espera aquí! Deja el motor en marcha. Esta no es una visita social. +[FEF_ST2] +Cuánta destrucción has producido -[JM4_3] -¡Es una emboscada de las Tríadas! ¡Sácanos de aquí, chico! +[FEF_BR1] +¿Has perdido el hilo? -{ Toni, after escaping and finishing the mission } +[FEF_CO1] +¿Necesitas más control? -[JM4_4] -Las Tríadas creen que pueden meterse conmigo. ¡Las Tríadas, CONMIGO! +[FEF_CO2] +Elige la mejor configuración del mando para tu estilo de juego -[JM4_5] -Pasa más tarde y les daremos algo que lavar... ¡Su propia ropa manchada de sangre! +[FEF_SA1] +¡Mantén tu sitio en el bloque! -{ ================================================================================= } -{ ================= MISSION: DEAD SKUNK IN THE TRUNK (JOEY LEONE) ================= } -{ ================================================================================= } +[FEF_SA2] +Guarda y carga tus partidas -{ TITLE } +[FEF_AU1] +¡Dale candela al volumen! -[JM5] -'FIAMBRE EN EL MALETERO' +[FEF_AU2] +Elige una emisora de radio y un efecto de sonido -{ Premission cutscene } +[FEF_DI1] +¡Cambia el juego! -{ Joey } +[FEF_DI2] +Personaliza el juego para tu televisión -[JM5_A] -Guapo, muy guapo... +[FEF_LA1] +¿Qué dices de los Willis? -[JM5_B] -¡Justo te estaba buscando! +[FEF_LA2] +Elige tu idioma preferido -[JM5_C] -Vale, hay un coche cargado con un fiambre en el bar cercano a Callahan Point. +[FEB_PMB] +Resumen de la última misión: -[JM5_D] -Uno de los Forelli se las daba de mafioso y se llevó su merecido. +[FEC_NA] +No disponible -[JM5_E] -Lleva el cuerpo a la trituradora en Harwood, ¿vale? +[FEC_CWL] +Siguiente arma -{ Mission instructions } +[FEC_CWR] +Arma anterior -[JM5_1] -~g~¡Llévalo a la trituradora! +[FEC_LOF] +Mirar hacia delante -[JM5_2] -~g~¡Son los hermanos Forelli! +{ !!!!!!!!!!!!!!!!!! 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 -{ ===================================================================== } -{ ================= MISSION: THE GETAWAY (JOEY LEONE) ================= } -{ ===================================================================== } +[FEC_MOV] +Movimiento -{ TITLE } +[FEC_CAM] +Cambiar cámara -[JM6] -'LA HUIDA' +[FEC_PAU] +Pausa -{ Premission cutscene } +[FEC_ENV] +Entrar en vehículo -{ Joey } +[FEC_JUM] +Saltar -[JM6_A] -Vaya cochazo, ¿eh? +[FEC_ATT] +Atacar o disparar -[JM6_B] -Bueno, escucha. Lleva un coche a la casa franca de Saint Mark's y recoge a unos colegas. +[FEC_RUN] +Correr -[JM6_C] -Van a atracar un banco y necesitan un conductor. +[FEC_FPC] +Cámara en primera persona -[JM6_D] -Di mi palabra de que eras su hombre, así que no la cagues. +[FEC_LL] +Mirar a la izquierda -[JM6_E] -Llévales al banco antes de las cinco en punto, ni un minuto después. +[FEC_LB1] +Mirar -{ Thief's dialogues } +[FEC_LB2] +atrás -[JM6_1] -Llévanos al banco de la avenida principal. +[FEC_LB] +Mirar atrás -[JM6_2] -Mantén el motor en marcha, entraremos y saldremos enseguida. +[FEC_LR] +Mirar a la derecha -[JM6_3] -¡Sácanos de aquí! +[FEC_HOR] +Claxon -[JM6_4] -¡Líbrate de la poli y llévanos a la casa franca! +[FEC_VES] +Controlar vehículo -{ Mission instructions } +[FEC_RSC] +Cambiar emisora de radio -[JM6_5] -~g~Necesitas un vehículo de fuga, ¡idiota! +[FEC_BRA] +Freno o marcha atrás -[JM6_6] -~g~¡Busca un vehículo menos llamativo! +[FEC_HAB] +Freno de mano -[JM6_7] -~g~¡Necesitas a los 3 para robar el banco! +[FEC_CAW] +Arma del vehículo -[JM6_8] -~r~¡Has perdido a todos los ladrones! +[FEC_ACC] +Acelerar -{ ===================================================================== } -{ ================= MISSION: THE CROOK (MARTY CHONKS) ================= } -{ ===================================================================== } +[FEC_SMT] +Activar misión especial -{ TITLE } +[FEC_CCF] +Configuración: -[MEA1] -'EL CRIMINAL' +[FEC_CF1] +Ajuste1 -{ Pager message to indicate Chonks' missions are activated } +[FEC_CF2] +Ajuste2 -[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. +[FEC_CF3] +Ajuste3 -{ Premission cutscene } +[FEC_CF4] +Ajuste4 -{ Marty } +[FEC_CDP] +Controles a mostrar: -[MEA1_B] -Me llamo Chonks, Marty Chonks. +[FEC_ONF] +A pie -[MEA1_C] -Soy el dueño de la fábrica de comestibles Bitch'n' Dog que está a la vuelta de la esquina. +[FEC_INC] +En vehículos -[MEA1_D] -Tengo problemas económicos, pero, ¿y quién no? +[FEC_VIB] +Vibración: -[MEA1_E] -He quedado con el director de mi banco. +[FEA_OUT] +Salida: -[MEA1_F] -Es un chorizo que no para de inflar los intereses del préstamo para sacarme una buena tajada. +[FEA_ST] +Estéreo -[MEA1_G] -Coge mi coche, búscale y tráelo de vuelta. +[FEA_MNO] +Mono -[MEA1_H] -¡Tengo una sorpresita para ese parásito chupasangre! +[FEA_NON] +Ninguna -{ Mission instructions } +[FEA_FM0] +HEAD RADIO -[MEA1_B3] -~g~Reúnete con el director del banco. +[FEA_FM1] +DOUBLE CLEF FM -[MEA1_B6] -~g~Lleva el coche a la trituradora para eliminar las pruebas, allí sal del coche y la grúa lo recogerá. +[FEA_FM2] +K-JAH RADIO -[MEA1_1] -~r~¡El director del banco está muerto! +[FEA_FM3] +RISE FM -[MEA1_2] -~r~¡Te dijeron que trituraras el coche! +[FEA_FM4] +LIPS 106 -[MEA1_3] -~g~¡Sal del coche! +[FEA_FM5] +GAME FM -[MEA1_4] -~r~¡Has abandonado al director del banco! +[FEA_FM6] +MSX FM -[MEA1_B5] -UNUSED +[FEA_FM7] +FLASHBACK 95.6 -{ Bank Manager, when picking him up } +[FEA_FM8] +CHATTERBOX FM -[MEA1_B4] -Ah, te envió el Sr. Chonks, ¿verdad? Visitemos a nuestro amigo. +[FED_DBG] +Menú de depuración -{ ======================================================================= } -{ ================= MISSION: THE THIEVES (MARTY CHONKS) ================= } -{ ======================================================================= } +[FED_RID] +Recargar IDE -{ TITLE } +[FED_RIP] +Recargar IPL -[MEA2] -'LOS LADRONES' +[FED_PAH] +Analizar pila -{ Premission cutscene } +[FED_RCD] +CCullZones::RecalculateCullZoneData -{ Marty } +[FED_DFL] +CTheScripts::DbgFlag -[MEA2_A] -Contraté a unos ladrones para que entraran en mi piso +[FED_DLS] +Cambiar luz blanca grande de depuración -[MEA2_B] -y robaran cuanto pillaran para que yo pudiera reclamar a la aseguradora. +[FED_SPR] +Mostrar grupos de peatones en carretera -[MEA2_C] -Ahora los muy cabritos me amenazan con delatarme +[FED_SCR] +Mostrar grupos de vehículos en carretera -[MEA2_D] -si no les doy una parte. +[FED_SCZ] +Mostrar zonas de máscara selectiva -[MEA2_E] -¿Te lo puedes creer? +[FED_DSR] +Solicitudes de depuración de streaming -[MEA2_F] -He dejado un coche dentro de la fábrica. +[FED_SCP] +gbShowCollisionPolys -[MEA2_G] -Ve a recogerles con él en su territorio, en el barrio rojo. +[FEM_MCM] +Menú de Memory Card -[MEA2_H] -Luego tráelos a la fábrica para que conozcan la opinión de Marty. +[FEM_RMC] +Registrar MemCard uno -{ Mission instructions } +[FEM_TFM] +Probar MemCard uno formateada -[MEA2_B3] -~g~Reúnete con los ladrones. +[FEM_TUM] +Probar Memcard uno sin formato -[MEA2_B4] -~g~Llévalos a la fábrica de comestibles Bitch'n'Dog. +[FEM_CRD] +Crear directorio raíz -[MEA2_B5] -UNUSED +[FEM_CLI] +Crear y cargar iconos -[MEA2_B6] -~g~Haz que repinten el coche para borrar las pruebas. +[FEM_FFF] +Llenar primer archivo con basura -[MEA2_1] -~r~¡Te dijeron que trituraras el vehículo! +[FEM_SOG] +Guardar sólo partida -[MEA2_2] -~r~¡Un ladrón ha muerto! +[FEM_CES] +Comprobar cada guardado de 0kB4 -[MEA2_3] -~g~Lleva el coche de vuelta a la fábrica. +[FEM_STG] +Guardar partida -[MEA2_4] -~r~¡Has dejado atrás a un ladrón! +[FEM_STS] +Guardar partida bajo el nombre GTA3 -{ ==================================================================== } -{ ================= MISSION: THE WIFE (MARTY CHONKS) ================= } -{ ==================================================================== } +[FEM_CPD] +Crear copia protegida del directorio mag -{ TITLE } +[FEM_MC2] +Menú de Memory Card 2 -[MEA3] -'LA MUJER' +[FEM_TS] +Prueba de guardado: -{ Premission cutscene } +[FEM_TL] +Prueba de carga: -{ Marty } +[FEM_TD] +Prueba de borrado: -[MEA3_A] -El negocio se irá a pique si no consigo un pastizal muy pronto. +[PL_STAT] +Estadísticas de jugador -[MEA3_B] -Mi esposa tiene un seguro de vida y ella no ha hecho más que vaciarme los bolsillos. +[PE_WAST] +Personas asesinadas -[MEA3_C] -He dejado un coche donde siempre. +[PE_WSOT] +Personas asesinadas por otros -[MEA3_D] -Ve a por a mi esposa a Classic Nails y tráela a la fábrica. +[CAR_EXP] +Coches reventados -{ Mission instructions } +[TM_BUST] +Veces arrestado -[MEA3_B3] -~g~Recoge a la Sra. Chonks. +[M_WASTE] +Hombres civiles asesinados -[MEA3_B6] -~g~Llévate el coche y tíralo al mar, así eliminaremos las pruebas. +[F_WASTE] +Mujeres civiles asesinadas -[MEA3_1] -~r~¡La mujer está muerta! +[PIG_WST] +Polis asesinados -[MEA3_2] -~r~¡Se suponía que debías tirar el coche al agua! +[GNG_WST] +Maleantes asesinados -[MEA3_3] -~r~¡Has dejado atrás a su mujer! +[MED_WST] +Médicos asesinados -[MEA3_B5] -UNUSED +[FIRE_WS] +Bomberos asesinados -{ Marty's wife, when picking her up } +[DED_CRI] +Criminales asesinados -[MEA3_B4] -¿Marty quiere verme? Bueno, pues que sea rápido, porque tengo que ir a la peluquería. +[DED_DED] +Vagabundos asesinados -{ ===================================================================== } -{ ================= MISSION: HER LOVER (MARTY CHONKS) ================= } -{ ===================================================================== } +[DED_HOK] +Prostitutas asesinadas -{ TITLE } +[HEL_DST] +Helicópteros destruidos -[MEA4] -'SU AMANTE' +[PER_COM] +Porcentaje completado -{ Premission cutscene } +[KGS_EXP] +Kgs de explosivos empleados -{ Marty } +[ACCURA] +Precisión de tiro -[MEA4_A] -Mierda, ¡tengo problemas! - -[MEA4_B] -Resulta que mi esposa salía con uno al que debo dinero. +[ELBURRO] +Mejor tiempo de ''Turismo'' en segundos -[MEA4_C] -¡Se ha cabreado y ahora quiere vengarse! +[CAR_CRU] +Coches destrozados -[MEA4_D] -He aceptado verle, +[HED_EX] +Cabezas explotadas -[MEA4_E] -y piensa que voy a devolverle el dinero. +[TM_DED] +Visitas al hospital -[MEA4_F] -Pero creo +[DAYSPS] +Días de juego transcurridos -[MEA4_G] -¡que los perros de Liberty van a disfrutar de un nuevo sabor este mes! +[MMRAIN] +mm de lluvia caídos -{ Mission instructions } +[MXCARD] +Dist. máx. de salto acrobático (pies) -[MEA4_B3] -~g~Recoge al amante de su mujer. +[MXCARJ] +Altitud máx. de salto acrobático (pies) -[MEA4_1] -~r~¡Carlos está muerto! +[MXCARDM] +Dist. máx. de salto acrobático (metros) -[MEA4_2] -~r~¡Marty Chonks ha muerto! +[MXCARJM] +Altitud máx. de salto acrobático (metros) -[MEA4_3] -~r~¡Has abandonado a Carlos, el usurero! +[MXFLIP] +Vueltas durante salto acrobático -{ Carlos, when picking him up } +[MXJUMP] +Rotación máx. de salto acrobático -[MEA4_B4] -¿Marty te envía? Vale, le voy a enseñar a ese sinvergüenza el significado de la palabra negocio. +[BSTSTU] +Mejor acrobacia hasta ahora: -{ Postmission cutscene } +[INSTUN] +Acrobacia -{ Marty } +[PRINST] +Acrobacia perfecta -[MEA4_B5] -¡Carl, hola! Ehhh... Necesito más tiempo para conseguir tu dinero. +[DBINST] +Acrobacia doble -[MEA4_B7] -Pero si pasas por mi oficina... +[DBPINS] +Acrobacia doble perfecta -{ Carlos } +[TRINST] +Acrobacia triple -[MEA4_B6] -Ya es muy tarde, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé de tu negocio... +[PRTRST] +Acrobacia triple perfecta -{ =============================================================== } -{ ================= MISSION: TURISMO (EL BURRO) ================= } -{ =============================================================== } +[QUINST] +Acrobacia cuádruple -{ TITLE } +[PQUINS] +Acrobacia cuádruple perfecta -[DIAB1] -'TURISMO' +[NOSTUC] +No se han hecho acrobacias -{ Pager message that tells the player El Burro's missions are now available } +[NOUNIF] +Saltos únicos completados -[DIAB1_A] -El Burro quiere ofrecerte una oportunidad. Ve al teléfono público de los cerros de Hepburn si te interesa. +[NOUNGM] +Saltos únicos -{ Premission cutscene } +[NMISON] +Misiones intentadas -{ El Burro, portorriqueño } +[NMMISP] +Misiones superadas -[DIAB1_B] -Al habla El Burro, de los Diablos. +[PASDRO] +Pasajeros transportados -[DIAB1_D] -Eres nuevo en Liberty, pero ya te estás ganando una reputación en las calles. +[MONTAX] +Dinero conseguido en taxi -[DIAB1_E] -Hay una carrera que empezará junto a la sala Clásica, cerca del puente Callahan. +[DAYPLC] +Gasto diario de la policía -[DIAB1_F] -Consíguete un buen carro y el primero que pase por todos los puntos de control se llevará el premio. +[CRIMRA] +Rango de criminal: -{ Mission instructions } +[GMSTOR] +Almacenar partida -[DIAB1_1] -~g~3... 2... 1... ¡ADELANTE! +[PREBRF] +Resúmenes anteriores -[DIAB1_4] -~g~Hazte con un coche rápido y ve a la parrilla de salida. +[CNTLS] +Controles -[DIAB1_3] -~r~No sabes ganar ni una rifa, ¡FRACASADO! +[MUSMEN] +Música/Efectos -[DIAB1_2] -~g~Felicidades, has ganado con un tiempo increíble de ~1~ segundos. +[GAMSET] +Ajustes del juego -[DIAB1_5] -TIEMPO DE CARRERA: +[LANGUA] +Idioma -{ Pager message after succeeding this mission } +[DSPLAY] +Pantalla -[DIAB1_C] -Se te da bien correr. Pásate por el teléfono público y puede que El Burro tenga trabajo para ti. +[DEBUGM] +Menú de depuración -{ ============================================================================ } -{ ================= MISSION: I SCREAM, YOU SCREAM (EL BURRO) ================= } -{ ============================================================================ } +[QUITOP] +Salir de las opciones -{ TITLE } +[CONTRL] +Configuración de controles -[DIAB2] -'IRA HELADA' +[SET1EN] +Ajuste 1. Activado -{ Premission cutscene } +[SET1] +Ajuste 1. -{ El Burro, portorriqueño } +[SET2EN] +Ajuste 2. Activado -[DIAB2_A] -¡Empecé mi negocio de entretenimiento exótico sin nada más que lo que cabía en mis pantalones de cuero! +[SET2] +Ajuste 2 -[DIAB2_B] -Una banda de roñosos amenazó con quitarme a mi protagonista si no les pago. +[SET3EN] +Ajuste 3. Activado -[DIAB2_C] -Amenazaron al hombre equivocado, amigo. +[SET3] +Ajuste 3 -[DIAB2_D] -Su debilidad son los helados. +[SET4EN] +Ajuste 4. Activado -[DIAB2_E] -Hazte con la bomba que dejé en Harwood, +[SET4] +Ajuste 4 -[DIAB2_F] -secuestra la camioneta del heladero mientras hace su ronda +[GOBACK] +Volver -[DIAB2_G] -y engaña a esos idiotas con esa musiquita. +[SOUND] +SONIDO -[DIAB2_H] -Se esconden en un almacén del muelle Atlantic. +[MUSVOL] +Volumen de la música -{ Mission instructions } +[SFXVOL] +Volumen de los efectos -[DIAB2_1] -~g~Recoge el maletín en Harwood. +[SCROPT] +OPCIONES DE PANTALLA -[DIAB2_2] -~g~Encuentra un camión de helados. +[CTRSCR] +Centrar pantalla -[DIAB2_3] -~g~Aparca el camión de helados en el muelle Atlantic. +[SCRFOR] +Formato de imagen -[DIAB2_4] -~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. +[GMSVLQ] +GUARDAR-CARGAR-SALIR -[DIAB2_6] -~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. +[GMREST] +Reiniciar partida -[DIAB2_7] -~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. +[GMLOAD] +CARGAR PARTIDA -[DIAB2_5] -~g~Sal del camión y luego usa el mando a distancia para detonarlo. +[NOGMSV] +Sólo puedes guardar desde tu escondite. -{ ===================================================================== } -{ ================= MISSION: TRIAL BY FIRE (EL BURRO) ================= } -{ ===================================================================== } +[DLFILE] +Borrar archivos de Grand Theft Auto III -{ TITLE } +[CHFILE] +ELEGIR ARCHIVO A CARGAR -[DIAB3] -'A LA HOGUERA' +[CHCDLD] +ELEGIR MEMORY CARD A USAR -{ Premission cutscene } +[CDUNFR] +Memory Card sin formato. -{ El Burro, portorriqueño } +[CHFIDL] +ELEGIR ARCHIVO A BORRAR -[DIAB3_A] -¡Unas Tríadas insolentes robaron mi lindo carro anoche, +[SVCONF] +CONFIRMACIÓN -[DIAB3_B] -lo destrozaron y lo quemaron! +[SVFNAM] +El nombre de tu archivo guardado es -[DIAB3_C] -En el baúl había algunas de mis más preciadas posesiones sobre burros... +[SAVEDN] +Error. Fallo al guardar. -[DIAB3_D] -Objetos de coleccionista irremplazables, amigo. +[LANGSL] +SELECCIÓN DE IDIOMA -[DIAB3_E] -Escondí un arma en el borde de Chinatown. +[ENGLIS] +Inglés -[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. +[GERMAN] +Alemán -[DIAB3_G] -¡Arriba! +[ITALIA] +Italiano -{ Mission instructions, in large text } +[FRENCH] +Francés -[DIAB3_1] -MATA A 25 TRÍADAS +[SPAIN] +Español -{ ===================================================================== } -{ ================= MISSION: BIG 'N' VEINY (EL BURRO) ================= } -{ ===================================================================== } +[RELIDE] +ReLoadIde -{ TITLE } +[RELIPE] +ReLoadIpl -[DIAB4] -'GRANDE Y VENOSO' +[PARSHP] +Analizar pila -{ Premission cutscene } +[DBGFON] +CTheScripts::DbgFlag activado -{ El Burro, portorriqueño } +[DBFOFF] +CTheScripts::DbgFlag desactivado -[DIAB4_A] -¡Un ladrón oportunista robó una camioneta con mi última publicación! +[BGWHON] +Luz blanca grande de depuración activada -[DIAB4_B] -Pero ese idiota drogado de SPANK dejó las puertas de atrás abiertas, +[BGWOFF] +Luz blanca grande de depuración desactivada -[DIAB4_C] -¡y ahora mi literatura para adultos +[DSTRON] +Solicitudes de depuración de streaming activadas -[DIAB4_D] -tan bellamente producida, tan gustosamente fotografiada, está siendo esparcida por toda Liberty! +[DSTROFF] +Solicitudes de depuración de streaming desactivadas -[DIAB4_E] -Toma la camioneta y sigue el rastro de los volúmenes 1, 2 y 3 de Donkey Does Dallas, +[PDRGON] +ShowPedRoadGroups activado -[DIAB4_F] -tomándolos por el camino. +[PRGOFF] +ShowPedRoadGroups desactivado -[DIAB4_G] -¡Cuando alcances a ese bandido espaciado con SPANK, chíngatelo! +[CRRGON] +ShowCarRoadGroups activado -[DIAB4_H] -Luego reparte mis revistas XXX por el barrio rojo. +[CRGOFF] +ShowCarRoadGroups desactivado -{ Mission instructions } +[CLZOON] +Zonas de máscara selectiva mostradas -[DIAB4_1] -~g~Lleva la furgoneta a la parte de atrás de Revistas XXX. +[CLZOOF] +Zonas de máscara selectiva ocultadas -{ =================================================================================== } -{ ================= MISSION: TAKING OUT THE LAUNDRY (TONI CIPRIANI) ================= } -{ =================================================================================== } +[SHPLON] +gbShowCollisionPolys activado -{ TITLE } +[SHPLOF] +gbShowCollisionPolys desactivado -[TM1] -'SACANDO LA COLADA' +[CULREC] +CCullZones::RecalculateCullZoneData() -{ Pager message that tells the player Toni's missions are available } +[FORMM1] +FormatMemCard 1 (prueba) -[TONI_P] -¡Tengo un trabajo urgente para ti! -Toni +[UNFRM1] +UnFormatMemCard 1 (prueba) -{ Premission cutscene } +[GORLEV] +Nivel de violencia -{ Toni } +[SICASS] +Puta locura -[TM1_A] -Siéntate, chico, siéntate de una vez. +[SICSIC] +Puto manicomio -[TM1_B] -La lavandería no quiere pagar la protección, ¿eh? +[SCASSL] +Seleccionado Puta locura -[TM1_C] -¿Las Tríadas creen que pueden meterse conmigo? +[SCSCSL] +Seleccionado Puto manicomio -[TM1_D] -¡Esos aspirantes a tipos duros van a saber lo que es ser un tipo duro! +[PRVMEN] +Resúmenes de misiones anteriores -{ Toni's Mamma } +[DOSVGM] +¿Deseas guardar la partida? -[TM1_E] -¡Eso, enséñales respeto! ¡Las Tríadas no se ríen de ninguno de mis hijos! +[FORMEN] +Menú de formato -[TM1_F] -Tu padre, Dios acoja su alma, no toleraba ni media a las Tríadas en Sicilia. +[MEMTST] +Pantalla MemoryCardTest -{ Toni } +[REGCAR] +Registrar MemoryCard uno -[TM1_G] -Lo siento, mamá. Sí, mamá. +[TEFONE] +Probar MemCard uno con formato -[TM1_H] -Quiero que te cargues sus furgonetas de lavandería +[TEUFON] +Probar MemCard uno sin formato -[TM1_I] -y a cualquiera de las Tríadas que se cruce en tu camino. +[CRROOT] +CreateRootDir -[TM1_J] -8-Ball te dará lo que necesites. +[CRLDIC] +Crear y cargar iconos -{ ======================================================================== } -{ ================= MISSION: THE PICK-UP (TONI CIPRIANI) ================= } -{ ======================================================================== } +[FLFSGF] +Llenar el primer archivo con basura -{ TITLE } +[PUSAVE] +Guardar sólo la partida -[TM2] -'LA ENTREGA' +[CHEVOK] +CheckEveryOkB4Save -{ Premission cutscene } +[SVGMON] +SaveTheGame -{ Toni's Mamma } +[CNTSAV] +No se puede guardar la partida en una misión. -[TM2_A] -Toni ha salido a partir cabezas, o a intentarlo... +[CNCSAV] +No se puede guardar la partida dentro de un vehículo. -[TM2_AA] -Nunca será tan duro como su padre. Te dejó una nota en la mesa. +[CRMGSV] +Crear directorio de cargador con protección de copia -{ Toni (letter) } +[MGSVNC] +MagazineDirectory no creado -[TM2_B] -La lavandería ya quiere pagar. ¡Buen trabajo, chico! +[MGSVCN] +MagazineDirectory creado -[TM2_C] -Ve a por el dinero y tráelo aquí. Cuidado con las Tríadas. +[YES] +Sí -[TM2_D] -Puede que intenten metértela doblada, pero no te dejes. +[NO] +No -[TM2_E] -¡Nadie, quiero decir nadie, se mete con Toni Cipriani! +[X] +x -{ Mission instructions } +[LAST] +Último mensaje -[TM2_1] -~g~¡Lleva el dinero a Toni! +[FEDS_XB] +Seleccionar -[TM2_2] -~g~¡Los dejaste tiesos a todos! +[FEDS_ST] +Botón START - CONTINUAR -[TM2_3] -~g~¡Es una trampa! ¡Liquidadlos a todos! +[FEST_OO] +de -{ ========================================================================================= } -{ ================= MISSION: SALVATORE'S CALLED A MEETING (TONI CIPRIANI) ================= } -{ ========================================================================================= } +[FEC_TUC] +Controlar torreta -{ TITLE } +[FEC_SM3] +Activar misión secundaria (botón R3) -[TM3] -'SALVATORE HA CONVOCADO UNA REUNIÓN' +[FEC_RS3] +Cambiar emisora de radio (botón L3) -{ Premission cutscene } +[FEC_HO3] +Claxon (botón L3) -{ Toni's Mamma } +[DIAB1] +'TURISMO' -[TM3_MA] -¡No sé dónde está! +[DIAB2] +'IRA HELADA' -[TM3_MB] -Te juro que mi hijo a veces no sabe lo que hace. +[DIAB3] +'A LA HOGUERA' -[TM3_MC] -Ahora bien, su padre era diferente. Siempre en la cumbre, pendiente de todo, valiente... +[DIAB4] +'GRANDE Y VENOSO' -{ Toni (letter) } +[DIAB1_A] +El Burro quiere ofrecerte una oportunidad. Ve al teléfono público de los cerros de Hepburn si te interesa. -[TM3_A] -Don Salvatore ha convocado una reunión. +[DIAB1_C] +Se te da bien correr. Pásate por el teléfono público y puede que El Burro tenga trabajo para ti. -[TM3_B] -Necesito que vayas a por la limusina y su hijo, Joey, a su taller. +[DIAB1_1] +~g~3... 2... 1... ¡ADELANTE! -[TM3_C] -Luego recoge a Luigi en su club, ven a buscarme, +[DIAB1_4] +~g~Hazte con un coche rápido y ve a la parrilla de salida. -[TM3_D] -y nos iremos todos juntos a la casa del jefe. +[DIAB1_3] +~r~No sabes ganar ni una rifa, ¡FRACASADO! -[TM3_E] -Los de las Tríadas no saben cuándo parar... +[DIAB1_2] +~g~Felicidades, has ganado con un tiempo increíble de ~1~ segundos. -[TM3_F] -Si quieren guerra, la tendrán. +[FIRST] +~g~1.° -[TM3_G] -Ponte en marcha. +[SECOND] +~g~2.° -{ Mission instructions } +[THIRD] +~g~3.° -[TM3_1] -~g~Ve al taller de Joey a por la limusina. +[FOURTH] +~g~4.° -[TM3_2] -~g~Recoge a Luigi. +[DIAB2_1] +~g~Recoge el maletín en Harwood. -[TM3_3] -~g~Ahora recoge a Toni. +[DIAB2_2] +~g~Encuentra un camión de helados. -[TM3_4] -~g~Lleva a los mafiosos a la casa de Salvatore. +[DIAB2_3] +~g~Aparca el camión de helados en el muelle Atlantic. -[TM3_A1] -~r~¡Joey está frito! +[DIAB2_4] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. -[TM3_A2] -~r~¡Joey y Luigi han sido incinerados! +[DIAB2_6] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. -[TM3_A3] -~r~¡Joey, Luigi y Toni están calcinados! +[DIAB2_7] +~g~Pulsa el ~w~botón ~k~~VEHICLE_HORN~~g~ para activar la melodía del camión de helados. -{ Toni, when the Triads ambush } +[DIAB2_5] +~g~Sal del camión y luego usa el mando a distancia para detonarlo. -[TM3_5] -~y~¡Es una emboscada de las Tríadas! +[YD1] +'CORRE A POR LA PASTA' -{ Postmission cutscene } +[YD2] +'JINETE CON UZI' -{ Toni } +[YD3] +'COLECCIONANDO COCHES DE BANDAS' -[TM3_H] -Buen trabajo, chaval, muy bueno. +[YD4] +'POR LOS AIRES' -[TM3_I] -Vente, te presentaré al Don. +[YD_P] +El Rey Courtney quiere hablarte. ¡Ve al teléfono público de Aspatria! -{ Salvatore } +[YD1_A] +Habla el rey Courtney. -[TM3_J] -¡Hola! ¡Luigi! +[YD1_A1] +Mi banda jamaicana necesita un conductor y tú tienes reputación de ser bueno. -{ Luigi } +[YD1_B] +Ve en un coche al basurero que hay detrás del estadio y a los otros candidatos. -[TM3_K] -Mis chicas te han echado de menos, Salvatore. Hace mucho que no te vemos. +[YD1_C] +Tengo hombres vigilando puntos de control por toda Staunton. -{ Salvatore } +[YD1_D] +El primer conductor que llegue a un punto de control se lleva mil pavos, y así de punto a punto. -[TM3_L] -Diles que en cuanto resolvamos este desafortunado incidente +[YD1_D1] +Si ganas más puntos de control que los demás, podría tener trabajo para ti. -[TM3_M] -iremos todos al club para celebrarlo, ¿vale? +[YD1_E] +~g~¡Prepárate! -[TM3_N] -¡Mi niño! +[YD1_F] +~g~Te has saltado la salida. ¡Me gusta tu estilo! -{ Joey } +[YD1_G] +~r~Esto es una carrera DE COCHES. ¡Necesitas un COCHE, idiota! -[TM3_N2] -¿Cómo lo llevas, papá? +[YD1GO] +~g~¡VAMOS! -{ Salvatore } +[YD1_1] +~r~1 -[TM3_O] -¿Has encontrado ya una buena mujer? +[YD1_2] +~r~2 -[TM3_P] -Tu madre, que en paz descanse, se retorcería en la tumba +[YD1_3] +~r~3 -[TM3_Q] -si te viera sin una mujer. +[YD1_BON] +¡1.000$! -{ Joey } +[Y1_1ST] +~G~¡Has quedado primero con ~1~ puntos de control! -[TM3_R] -Lo sé, papá, estoy en ello. +[Y1_2ND] +~y~Eres el segundo con ~1~ puntos de control. ~y~¡Casi, pero no! -{ Salvatore } +[Y1_3RD] +~r~Eres el tercero con ~1~ puntos de control. ~r~¿No decías que eras bueno? -[TM3_S] -¡Toni! ¿Cómo está tu madre? +[Y1_LAST] +~r~¡Has quedado el último! ~r~¡Me has hecho perder el tiempo, IDIOTA! -[TM3_T] -Es una gran mujer, ¿sabes? Fuerte, ''firenze''. +[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! -{ Toni } +[Y1_J2ND] +~r~Has empatado el segundo con ~1~ puntos de control. ¡Conduces como un mono loco! -[TM3_U] -Está bien, estupendamente. +[Y1JLAST] +~r~¡Has empatado el último! ¡Hablas como un conductor, pero conduces como un hablador! -{ Salvatore } +[Y1_TEST] +¡COCHE AL AGUA! -[TM3_V] -Fantástico, fantástico. Bien, muchachos, entrad mientras yo hablo con nuestro nuevo amigo. +[YD2_A] +Necesito ver si eres capaz de hacer mi trabajo sucio, -[TM3_W] -Tienes un gran futuro por delante, hijo mío... +[YD2_A1] +si se puede confiar en ti. -{ ==================================================================================== } -{ ================= MISSION: TRIADS AND TRIBULATIONS (TONI CIPRIANI) ================= } -{ ==================================================================================== } +[YD2_B] +Dos de mis chicos llegarán allí enseguida para llevarte de paseo, -{ TITLE } +[YD2_B1] +a ver si eres quien dices que eres. -[TM4] -'TRÍADAS Y TRIBULACIONES' +[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. -{ Premission cutscene } +[YD2_CC] +Toma, necesitarás una pipa. -{ Toni's Mamma } +[YD2_D] +Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te eches atrás. -[TM4_A] -Ah, eres tú. Toni no está. +[YD2_E] +¡Conduce! -[TM4_A2] -Pero te ha dejado una de sus cartitas de amor. +[YD2_F] +~r~Se quiere escapar, ¡cárgatelo! -{ Toni } +[YD2_G1] +Los cerros de Hepburn... Vamos a matar a algunos asquerosos Diablos... -[TM4_B] -¡Esto es la guerra! Las Tríadas tienen una piscifactoría como tapadera. +[YD2_G2] +Pero recuerda, ~r~¡no salgas de este coche! -[TM4_C] -Casi todos sus negocios pasan por la lonja de Chinatown. +[YD2_H] +¡Vale, ya está! ¡Llévanos de vuelta a territorio jamaicano! ¡Vamos, vamos, vamos! -[TM4_D] -La lavandería todavía no ha pagado la protección. +[YD2_L] +¡Eres la Muerte personificada! -[TM4_E] -Creen que está protegida por las Tríadas, así que creo que se merecen un castigo. +[YD2_M] +~r~¡Ha destrozado mi coche! ¡Liquídale! -[TM4_F] -¡Llévate a estos chicos y elimina a los líderes de las Tríadas! +[YD2_N] +¡Vuelve al coche! -[TM4_G] -Qué narices, si ves la oportunidad, cárgate también a unos cuántos de sus soldados. +[YD3_A] +Quiero que robes coches de otras bandas -{ Mission instructions } +[YD3_A1] +para que podamos atacar sus territorios. -[TM4_GAT] -~g~Necesitas un camión de pescado de las Tríadas para entrar. +[YD3_B] +Necesito un Mafia Sentinel, -{ ====================================================================== } -{ ================= MISSION: BLOW FISH (TONI CIPRIANI) ================= } -{ ====================================================================== } +[YD3_B1] +un Yakuza Stinger y un -{ TITLE } +[YD3_B2] +Diablo Stallion para que podamos ir a por cualquier banda de Liberty. -[TM5] -'LLUVIA DE PECES' +[YD3_C] +Déjalos en el garaje de Newport y recuerda, -{ Premission cutscene } +[YD3_C1] +¡dañados no nos sirven de nada! -{ Toni } +[YD3_D] +UNUSED -[TM5_B] -Vale, ya me he hartado de esta mierda. +[YD3_E] +~r~¡Ya has entregado un coche de los Diablos! -[TM5_C] -¡Vamos a acabar con las Tríadas en Liberty de una vez por todas! +[YD3_F] +~r~¡Ya has entregado un coche de la mafia! -[TM5_D] -8-Ball ha instalado una bomba en un camión de la basura. +[YD3_G] +~r~¡Ya has entregado un coche de la yakuza! -[TM5_E] -Tiene un temporizador, así que si la lías no quedará nada de ti. Ve a por el camión. +[YD3_H] +~g~¡Coche de los Diablos entregado! -[TM5_F] -¡Cuidado, 8-Ball dice que es muy sensible y que cualquier golpe puede hacerlo estallar! +[YD3_I] +~g~¡Coche de la mafia entregado! -[TM5_G] -Su piscifactoría abrirá sus puertas a uno de sus camiones, así que podrás entrar sin más. +[YD3_J] +~g~¡Coche de la yakuza entregado! -[TM5_H] -¡Aparca entre los tanques de gas y lárgate de ahí! +[YD3_K] +~r~¡El coche está casi destrozado! ¡Haz que lo reparen! -[TM5_I] -Quiero que llueva pescado. +[YD3_L] +~g~¡Llévalo al ~p~garaje~g~! -[TM5_J] -En plan bíblico, nada de bajo presupuesto. +[YD3_M] +~r~¡Has volcado el vehículo! ¡Consigue otro! -{ ======================================================================== } -{ ================= MISSION: CHAPERONE (SALVATORE LEONE) ================= } -{ ======================================================================== } +[YD4_A] +¡Escucha! -{ TITLE } +[YD4_A1] +Mueve el culo a Bedford Point. -[FM1] -'CARABINA' +[YD4_A2] +¡Hay un cargamento en una tartana que necesito pronto! -{ Pager message, appears when Toni's missions have not been complete } +[YD4_B] +CARTA: Dicen que estuviste entretenido. Igual que yo. -[FRANGO] -~g~¡Salvatore quiere que ayudes primero a Toni a ocuparse de las Tríadas! +[YD4_C] +¡Es hora de que seas testigo del verdadero poder del 'SPANK'! Con mucho amor, Catalina. -{ Premission cutscene } +[YD4_D] +P.D. ¡MUERE, BASURA, MUERE! -{ Salvatore } +[YD4_1] +~g~¡Son psicópatas adictos al SPANK! -[FM1_A] -Mis chicos y yo queremos hablar de negocios, +[YD4_2] +~g~¡Destruye las furgonetas de SPANK! -[FM1_B] -así que esta tarde vas a cuidar de mi chica. +[HM_1] +'PASADA AMETRALLADA' -[FM1_C] -¡OYE, MARÍA! ¡MUEVE ESE CULO! +[HM_2] +'BOMBINATOR' -[FM1_D] -La muy idiota siempre hace lo mismo. +[HM_3] +'PREPARADO PARA ESTALLAR' -[FM1_E] -Y aquí está, ¡la primera y única reina de Saba! +[HM_5] +'ENFRENTAMIENTO' -[FM1_F] -¿Qué hacías arriba? +[HOOD1_A] +Ve al teléfono público de Wichita Gardens y hablaremos de negocios. -[FM1_G] -Fuera lo que fuera, seguro que me cuesta dinero. +[HM1_A] +¡Ey! ¡Soy D-Ice, de los Red Jacks! -{ Maria } +[HM1_C] +Hay unos macarrillas en la calle que no piensan más que en pistolas y en SPANK. -[FM1_H] -Bueno, no pensarás que estoy aquí para conversar, ¿o sí? +[HM1_3] +~g~Los Nines tienen su territorio en Wichita Gardens. -{ Salvatore } +[HM2_3] +¡Si golpeas las ruedas de un vehículo, el coche teledirigido estallará! -[FM1_I] -Métete en el coche y cierra el pico. +[HM2_4] +¡Si el coche teledirigido se sale fuera de cobertura, estallará solo! -[FM1_J] -Llévate la limusina, pero devuélvela de una pieza, ¿me has oído? +[HM2_5] +~r~¡Te has ido de cobertura! -[FM1_K] -Y cuidado con ella, es una lianta. +[HM3_1] +~g~¡Ve al garaje, pero pon atención, porque el coche explotará si se daña demasiado! -{ Maria } +[HM3_2] +~g~Lleva el coche de vuelta. ¡Tiene que estar inmaculado! -[FM1_L] -¡Sí, sí, sí! Seguro que tu nuevo perrito faldero tiene todo previsto. +[HM3_3] +~g~¡Haz que reparen el vehículo! -[FM1_M] -¿No es fuerte y grande? +[HM4_D] +~g~¡Hazte con un vehículo! -[FM1_N] -¡Oye, tú, vamos a ver a Chico para que nos dé unas pirulas! +[HM4_1] +~g~Dirígete al lugar donde está el cargamento. Necesitas conseguir 30 lingotes. -[FM1_O] -Creo que está en la estación de ferrocarril del muelle de Chinatown. +[HM4_2] +~g~Recuerda: cuando el vehículo esté pesado y vaya más despacio, ve al garaje y deja el cargamento. -{ Mission instructions } +[HM5_3] +~r~¡Te han dicho que uses sólo un bate de béisbol! -[FM1_1] -~g~¡Vuelve al Stretch! +[HM5_4] +~r~¡Tu contacto está muerto! -[FM1_2] -~g~¡Entra en el Stretch! +[MEA1] +'EL CRIMINAL' -[FM1_3] -~r~Si abandonas a María, Salvatore hará que te maten. Vuelve y recógela. +[MEA2] +'LOS LADRONES' -[FM1_4] -~g~¡Has dejado a la chica del Don tirada! ¡Vuelve al almacén y espera a María! +[MEA3] +'LA MUJER' -[FM1_5] -~g~¡Lleva a María sana y salva con Salvatore! +[MEA4] +'SU AMANTE' -[FM1_6] -~g~¡Chico no estará esperando todo el día, lleva a María al muelle! +[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. -[FM1_7] -~r~¡María está muerta! A Salvatore le va a sentar muy mal... +[MEA1_B3] +~g~Reúnete con el director del banco. -[FM1_8] -~r~¡Te cargaste al camello de María! +[MEA1_B6] +~g~Lleva el coche a la trituradora para eliminar las pruebas, allí sal del coche y la grúa lo recogerá. -[FM1_P] -~g~Ese de ahí es Chico, párate cerca. +[MEA1_1] +~r~¡El director del banco está muerto! -[FM1_9] -~g~La fiesta es allí. Deja a María enfrente. +[MEA1_2] +~r~¡Te dijeron que trituraras el coche! -[FM1_10] -~g~Has abandonado a María, vuelve y recógela. +[MEA1_3] +~g~¡Sal del coche! -{ Cutscene when the player finds Chico } +[MEA1_4] +~r~¡Has abandonado al director del banco! -{ Chico, mexicano } +[MEA2_B3] +~g~Reúnete con los ladrones. -[FM1_Q] -¡Ay, mira, es mi chica favorita! +[MEA2_B4] +~g~Llévalos a la fábrica de comestibles Bitch'n' Dog. -[FM1_Q1] -¿Quieres un poco de diversión? ¿Un poco de... hmmm, de SPANK? +[MEA2_B6] +~g~Haz que repinten el coche para borrar las pruebas. -{ Maria } +[MEA2_1] +~r~¡Te dijeron que trituraras el vehículo! -[FM1_R] -Hola, Chico. No, solo lo de siempre. +[MEA2_2] +~r~¡Un ladrón ha muerto! -{ Chico, mexicano } +[MEA2_4] +~r~¡Has dejado atrás a un ladrón! -[FM1_S] -Aquí tienes, señorita. +[MEA3_B3] +~g~Recoge a la Sra. Chonks. -[FM1_S1] -Ey, deberías echar un vistazo a la fiesta del almacén en el lado este del muelle Atlantic. +[MEA3_B6] +~g~Llévate el coche y tíralo al mar, así eliminaremos las pruebas. -{ Maria } +[MEA3_1] +~r~¡La mujer está muerta! -[FM1_T] -Gracias, Chico, nos vemos. +[MEA3_2] +~r~¡Se suponía que debías tirar el coche al agua! -{ Chico, mexicano } +[MEA3_3] +~r~¡Has dejado atrás a su mujer! -[FM1_U] -Gracias y disfruta. Es buen material. +[MEA4_B3] +~g~Recoge al amante de su mujer. -{ Maria } +[MEA4_B6] +Ya es muy tarde, Marty. Tuviste tu oportunidad, pero ahora yo me ocuparé de tu negocio... -[FM1_V] -¡Venga, tú, vamos a ver esa fiesta! +[MEA4_1] +~r~¡Carlos está muerto! -{ Cutscene when the player takes Maria to the party } +[MEA4_3] +~r~¡Has abandonado a Carlos, el usurero! -{ Maria } +[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~. -[FM1_W] -Oye, tú, espera aquí y quédate pendiente del coche mientras yo voy a menear el esqueleto, ¿vale? +[LOVE6_1] +~g~¡Ahora llévate a los policías lejos del almacén! -{ Police dispatcher } +[LOVE6_2] +~r~¡No has distraído a la policía! -[FM1_SS] -~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: asistan redada de narcóticos en el muelle Atlantic. +[RM4_3] +~r~¡El socio de Ray ha escapado! -{ Warehouse's guard } +[RM6_C] +La CIA parece estar interesada en el SPANK -[FM1_TT] -¡UNA REDADA! +[RM6_C1] +y no les gusta que nos metamos con el cártel. -{ Maria } +[C_PASS] +¡AMENAZA ELIMINADA! -[FM1_X] -¡Vale, tú, salgamos de aquí! ¡Uaaah! +[CTUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. -{ Cutscene when the player takes Maria back to Salvatore's home } +[CTUTOR2] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de justiciero. -{ Maria } +[COPCART] +~g~Tienes ~1~ segundos para volver a un vehículo de la policía antes de que termine la misión. -[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. +[C_FAIL] +¡Misión de justiciero terminada! -[FM1_AA] -Bueno, será mejor que me vaya. Espero que nos veamos pronto. +[C_CANC] +~r~¡Misión de justiciero cancelada! -{ ================================================================================ } -{ ================= MISSION: CUTTING THE GRASS (SALVATORE LEONE) ================= } -{ ================================================================================ } +[C_ESCP] +~r~¡El sospechoso ha escapado! -{ TITLE } +[C_TIME] +~r~¡Tu trabajo como defensor de la ley ha terminado! -[FM2] -'CORTANDO LA HIERBA' +[C_VIGIL] +¡PREMIO POR JUSTICIERO! -{ Premission cutscene } +[A_FAIL2] +~r~¡Tu falta de rapidez ha sido fatal para el paciente! -{ Salvatore } +[A_FAIL3] +~r~¡El paciente está muerto! -[FM2_J] -Déjanos a solas un momento. +[A_PASS] +¡Rescatado! -[FM2_A] -El cártel colombiano fabrica SPANK en Liberty, +[F_FAIL2] +~r~¡Llegas demasiado tarde! -[FM2_K] -pero no sabemos dónde y parece como si supieran qué vamos a hacer antes de que lo pensemos. +[A_COMP2] +¡Nunca te cansarás! -[FM2_B] -¡Tenemos a un chivato! +[RM2_M] +Si necesitas armas nuevas, pasa por aquí y coge lo que necesites de las taquillas. -[FM2_L] -Hay un tipo llamado Curly Bob que trabaja en el bar de Luigi. +[HEAL_A] +Tu ~h~salud ~w~está indicada en naranja en la parte superior derecha de la pantalla. -[FM2_M] -Ha estado gastando más dinero del que gana. +[YD1_CNT] +¡~1~ de 15! -[FM2_C] -No está ni chuleando ni traficando, así que estará cantando. +[FM1_9] +~g~La fiesta es allí. Deja a María enfrente. -[FM2_N] -Suele ir del trabajo a casa en taxi, así que síguelo. +[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. -[FM2_O] -Y si nos está vendiendo... mátalo. +[FM1_AA] +Bueno, será mejor que me vaya. Espero que nos veamos pronto. -{ Mission instructions } +[NOCONTE] +Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. -[FM2_1] -~g~¡Ahí está Curly Bob! +[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). -[FM2_2] -~g~¡Curly ha salido del club, síguelo! +[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). -[FM2_5] -~g~Llévale al puerto de Portland. +[WRONGCD] +Disco incorrecto. Introduce el disco correcto. -[FM2_6] -~r~¡Curly no se meterá en un taxi cascado! +[NOCD] +La bandeja del disco está vacía. Introduce un disco. -[FM2_7] -~r~¡Curly se ha asustado! ¡Han cancelado la reunión! +[OPENCD] +La bandeja del disco está abierta. Cierra la bandeja de disco. -[FM2_8] -~g~¡Elimina a Curly Bob! +[CDERROR] +Error al leer el DVD de Grand Theft Auto III -[FM2_9] -~r~¡Curly Bob la ha espichado! +[RESTART] +Empezando una nueva partida -[FM2_10] -~r~¡Curly se ha largado! +[GA_3] +¡Ya no es gratis! ¡La mano de pintura son 1.000 dólares! -[FM2_11] -~g~Aparca enfrente del club de Luigi; Curly Bob saldrá pronto. +[GA_1] +¡Hala! ¡Demasiado peligroso para mi gusto! -[FM2_12] -~r~¡Te ha dado esquinazo! +[GA_1A] +Vuelve cuando no estés tan ocupado... -[FM2_14] -~r~¡Te acercaste demasiado y asustaste a Curly! +[S_PROM2] +Puedes alojar un vehículo en el garaje de al lado al guardar tu partida. -[FM2_15] -~g~No te acerques mucho, ¡o Curly sospechará! +[STOCK] +mercancía agotada -[FM2_16] -ASUSTÓMETRO: +[FM1_O] +Creo que está en la estación de ferrocarril del muelle de Chinatown. -{ Cutscene that appears when successfully following Curly Bob } +[EBAL_B] +Es aquí, ¡entremos y cambiémonos de ropa! -{ Miguel, colombiano } +[EBAL_G] +Este es el club de Luigi. Vamos a la parte de atrás, a la puerta de servicio. -[FM2_F] -Aquí viene nuestro amiguito. El señor Bocazas en persona. +[AM4_3] +¡Tú debes de ser el nuevo chico de los recados de Asuka! -{ Catalina, colombiana } +[AM4_4] +¿Tienes el dinero? ¿Está todo? -[FM2_G] -¿Te han seguido? Ya sabes que esto es nuestro secretito. +[AM4_5] +Ya sé lo que estás pensando, otro policía corrupto. -{ Curly Bob } +[AM4_6] +Bueno, éste es un mundo corrupto. -[FM2_H] -No, no, no me han seguido. ¿Tienes lo mío? +[AM4_7] +Pierdo a un par de socios y esos idiotas de asuntos internos empiezan a meter las narices. -{ Catalina, colombiana } +[AM4_8] +¡Y seguro que les llega mi olor! -[FM2_I] -Toma tu SPANK, soplón, ahora habla. +[AM4_9] +¡Pues esta ciudad es una gran alcantarilla! -{ Curly Bob } +[AM4_10] +Pero voy a necesitar un ayudita ajena al cuerpo. -[FM2_P] -Vale, los Leone libran una guerra en dos frentes. +[AM4_11] +Si estás interesado, ya sabes dónde encontrarme. -[FM2_Q] -Tienen una guerra territorial con las Tríadas y no parece que ninguno se vaya a rendir. +[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. -[FM2_R] -Mientras tanto, Joey Leone ha cabreado a los Forelli. +[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. -[FM2_S] -Cada día pierden más hombres e influencia. +[KM2_1] +~g~Repara el coche, tiene que estar en perfecto estado. -[FM2_T] -Salvatore se está volviendo peligroso y paranoico. Sospecha de todos y de todo. +[LM3_6] +¡Joey...! -{ Catalina, colombiana } +[LM3_6A] +¿Voy a jugar con tu paquetín otra vez? -[FM2_U] -Con lo leales que son algunos, ¿de qué tendría que preocuparse? +[LM3_9A] +que tendré trabajo para ti. -{ ================================================================================== } -{ ================= MISSION: BOMB DA BASE: ACT I (SALVATORE LEONE) ================= } -{ ================================================================================== } +[LM3_9B] +¿De acuerdo? -{ TITLE } +[AWAY2] +~r~Se ha escapado. -[FM21] -'BASE FUERA: ACTO I' +[AWAY] +~r~¡Se ha pirado de aquí! -{ Premission cutscene } +[JM6_1] +Llévanos al banco de la avenida principal. -{ Salvatore } +[GA_6B] +¡Apárcalo, activa el detonador pulsando el ~h~botón ~k~~PED_FIREWEAPON~~w~ y SAL DE AHÍ! -[FM3_A] -Tenemos que despachar a esos puñeteros colombianos, +[GA_7B] +Activa la bomba con el ~h~botón ~k~~PED_FIREWEAPON~~w~. Estallará cuando se arranque el motor. -[FM3_B] -pero mientras estemos en guerra con las Tríadas, no tendremos la fuerza necesaria. +[BAT1] +~g~¡Coge el bate! -[FM3_C] -El cártel tiene fondos ilimitados gracias a esa mierda del SPANK. +[EBAL_O] +Si no la cagas, puede que haya más trabajo para ti. ¡Ahora largo! -[FM3_D] -Si les atacamos abiertamente, nos harán picadillo. +[HELP9_B] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. -[FM3_E] -Estarán fabricando el SPANK en ese barco grande al que te llevó Curly. +[HELP9_C] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~disparar ~w~el fusil de francotirador. -[FM3_F] -Así que tenemos que actuar con cuidado, o mejor dicho, tú tienes que hacerlo. +[JM6_8] +~r~¡Has perdido a todos los ladrones! -[FM3_G] -Te estoy pidiendo que destruyas esa fábrica de SPANK como un favor personal para mí, Salvatore Leone. +[COLT_IN] +¡La pistola ya está disponible en la tienda Ammu-Nation! -[FM3_H] -Si haces esto por mí, serás como de la familia. Todo lo que quieras. +[TAXI2] +~r~¡Se te acabó el tiempo! -[FM3_I] -Ve a ver a 8-Ball, necesitarás su ayuda para volar ese barco. +[TAXI3] +~r~¡Tu cliente ha salido por patas! -{ =================================================================================== } -{ ================= MISSION: BOMB DA BASE: ACT II (SALVATORE LEONE) ================= } -{ =================================================================================== } +[TAXI7] +~r~Tu coche está destrozado, haz que lo reparen. -{ TITLE } +[TAXI4] +¡Carrera terminada! -[FM3] -'BASE FUERA: ACTO II' +[TAXI5] +¡VIAJE RÁPIDO! -{ Premission cutscene, when not having 100.000 $ } +[TAXI6] +Misión de taxi terminada -{ 8-Ball } +[FRANGO] +~g~¡Salvatore quiere que ayudes primero a Toni a ocuparse de las Tríadas! -[FM3_8A] -¡Hombre, colega! Salvatore me avisó, +[PAGEB12] +Soborno policial ya disponible en tu guarida. -[FM3_8B] -pero este trabajo va a necesitar muchos fuegos artificiales. +[PAGEB13] +Salud ya disponible en tu guarida. -[FM3_8C] -Necesitaré 100.000 $ para cubrir gastos, +[PAGEB14] +Adrenalina ya disponible en tu guarida. -[FM3_8D] -pero ya sabes que conmigo valdrá la pena. +[KM1_4] +~g~¡Necesitas un coche de policía para hacer el trabajo! -[FM3_CC] -Regresa cuando tengas el dinero. +[CAT1_B] +lleva 500.000 dólares a la mansión de Cedar Grove. -{ Premission cutscene, when having 100.000 $ } +[JM2_C] +Tiene un puesto de fideos en Chinatown. -{ 8-Ball } +[RM6_1] +Esta llave es de un almacén. -[FM3_8E] -Venga, ¡vamos allá! +[RM6_2] +Encontrarás dinero en metálico y ''suministros'' que guardé por si las cosas se ponían feas. -[FM3_8F] -Puedo reventar el barco, pero aún no puedo usar una pipa con estas manos. +[RM6_3] +Hasta la vista. -[FM3_8G] -¡Toma, este fusil te ayudará a volar unas cuántas cabezas! +[FE_INIP] +Iniciando y cargando el menú de pausa... Espera, por favor. -{ 8-Ball, when reaching the boat area } +[FESZ_CA] +Cancelar -[FM3_8I] -Encuentra una posición elevada. Entraré cuando dispares el primer tiro. +[FESZ_QU] +Abandonar -{ Mission instructions } +[FESZ_L1] +¡La partida se ha guardado! -[FM3_4] -~g~¡Para el coche y deja que 8-Ball salga! +[FESZ_L2] +El nombre guardado es: -[FM3_7] -~r~¡8-Ball ha pasado a mejor vida! +[FESZ_OK] +ACEPTAR -[FM3_8] -~r~¡Los guardias han sido alertados! +[FES_NGA] +Nueva partida -{ ============================================================================ } -{ ================= MISSION: LAST REQUESTS (SALVATORE LEONE) ================= } -{ ============================================================================ } +[FES_CAN] +Cancelar -{ TITLE } +[FESZ_QL] +Perderás todo el progreso en tu partida actual. ¿Quieres continuar con la carga? -[FM4] -'ÚLTIMA VOLUNTAD' +[FESZ_QD] +¿Quieres borrar esta partida guardada? -{ Premission cutscene } +[FESZ_QO] +¿Quieres sobreescribir esta partida guardada? -{ Salvatore } +[FESZ_QR] +¿Seguro que quieres empezar una nueva partida? Perderás todo el progreso desde la última partida guardada. -[FM4_A] -¡Mi socio favorito! +[FESZ_QS] +¿QUIERES GUARDAR? -[FM4_B] -Estoy orgulloso de ti, hijo, pusiste finos a esos sudacas. +[SLONFP] +Puerto 1. Archivo protegido. -[FM4_C] -Tengo un trabajito más para ti antes de que podamos celebrarlo. +[T4X4_1] +'PATIO DE RECREO' -[FM4_D] -Hay un coche a la vuelta del edificio del club de Luigi. +[T4X4_2] +'UN PASEO POR EL PARQUE' -[FM4_E] -El interior está pringado de sesos. +[T4X4_3] +'¡AGARRADO!' -[FM4_F] -Tuvimos que ayudar a un tipo a que se decidiera y fue un poco... sucio. +[MM_1] +'CAOS EN EL APARCAMIENTO' -[FM4_H] -Llévalo a la trituradora antes de que lo encuentre la pasma. +[T4X4_1A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~15~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -{ Pager message, appears right after getting into the target car } +[T4X4_1B] +¡~1~ de 15! -[FM4_1] -Soy María. ¡El coche es una trampa! Estoy en el lado sur del puente Callahan. +[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. -{ Cutscene after reaching Maria } +[T4X4_2A] +~g~¡Tienes ~y~2 minutos~g~ para pasar por ~y~12~g~ puntos de control! ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -{ Maria } +[T4X4_2B] +¡~1~ de 12! -[FM4_2] -Mira, Salvatore cree que se la estamos jugando, +[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. -[FM4_3] -así que te vendió al cártel para llegar a un trato. +[T4X4_3A] +~g~Tienes ~y~5 minutos~g~ para pasar por ~y~20~g~ puntos de control. ~g~Puedes tocarlos en ~y~CUALQUIER ORDEN. -[FM4_4] -No podía permitírselo, o sea, lo peor es... +[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. -[FM4_4B] -que yo tengo la culpa, porque le dije que somos pareja. +[T4X4_3C] +¡~1~ de 20! -[FM4_5] -¡No me preguntes por qué, no lo sé! +[T4X4_F] +~r~¡Te has escapado! ¿Demasiado difícil para ti? -[FM4_6] -Mira, la mafia te quiere muerto y yo también tengo que salir de aquí. +[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. -[FM4_6B] -¡He visto demasiados asesinatos, demasiada sangre! +[MM_1_B] +¡~1~ de 20! -[FM4_7] -Es una amiga mía, ¿vale?, una vieja amiga... Es Asuka, es de fiar. +[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. -{ Asuka } +[FM2_14] +~r~¡Te acercaste demasiado y asustaste a Curly! -[FM4_8] -Vamos, dejémonos de discursos. +[FM2_15] +~g~No te acerques mucho, ¡o Curly sospechará! -[FM4_9] -Mejor nos vamos antes de que haya más italianos histéricos con intenciones menos amistosas. +[UPSIDE] +~r~¡Has volcado! -{ Postmission cutscene } +[FM2_16] +ASUSTÓMETRO: -{ Maria } +[LM3_11] +~g~Misty no irá en un autobús, ¡hazte con otro vehículo! -[LRQC_1] -Asuka y yo tenemos que hablar... +[LANDSTK] +Landstalker -[LRQC_2] -¿Por qué no te das una vuelta? +[IDAHO] +Idaho -{ Asuka } +[STINGER] +Stinger -[LRQC_3] -Necesitarás un escondite. - -[LRQC_4] -Hay un almacén en la orilla de Belleville que podría servirte. +[LINERUN] +Linerunner -[LRQC_5] -Regresa a mi apartamento cuando estés listo +[PEREN] +Perennial -[LRQC_6] -y podremos tener una charla. +[SENTINL] +Sentinel -{ ========================================================================================== } -{ ================= MISSION: SAYONARA SALVATORE (ASUKA KASEN, FIRST BATCH) ================= } -{ ========================================================================================== } +[PATRIOT] +Patriot -{ TITLE } +[FIRETRK] +Camión de bomberos -[AM1] -'SAYONARA, SALVATORE' +[TRASHM] +Trashmaster -{ Premission cutscene } +[STRETCH] +Stretch -{ Asuka } +[MANANA] +Mañana -[AM1_A] -Tenemos que aclarar ciertos temas antes de seguir con cualquier clase de relación, +[INFERNS] +Infernus -[AM1_B] -sea de negocios u otra. Pongamos las cartas sobre la mesa. +[BLISTA] +Blista -[AM1_C] -Soy yakuza y sé que trabajaste para la familia de Salvatore Leone. +[PONY] +Pony -[AM1_D] -Puedo darte trabajo en nuestra organización, +[MULE] +Mule -[AM1_E] -pero primero debes demostrarme que has cortado todos tus lazos con la mafia. +[CHEETAH] +Cheetah -{ Alternative subtitles that appear depending if the hour is single-digit or double digit, to make them uniform } +[AMBULAN] +Ambulancia -[AM1_F] -Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (~1~:~1~) +[FBICAR] +Coche del FBI -[AM1_K] -Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (0~1~:~1~) +[MOONBM] +Moonbeam -[AM1_G] -Asegúrate de que no salga con vida. +[ESPERAN] +Esperanto -[AM1_H] -Mientras tanto María y yo nos pondremos al día. +[TAXI] +Taxi -{ Maria } +[KURUMA] +Kuruma -[AM1_I] -Uy, Asuka, tienes un masajeador... +[BOBCAT] +Bobcat -{ Asuka } +[WHOOPEE] +Mr. Whoopee -[AM1_J] -Eso no es un masajeador. +[BFINJC] +BF Injection -{ Mission instructions } +[POLICAR] +Coche patrulla -[AM1_1] -~g~¡Salvatore está saliendo del club de Luigi! +[ENFORCR] +Enforcer -[AM1_2] -~r~¡Te han descubierto! +[SECURI] +Securicar -[AM1_3] -~r~¡Has perdido a Salvatore! +[BANSHEE] +Banshee -[AM1_4] -~r~Muy bonito, ¡has asustado al objetivo! ¿Y te consideras un asesino? +[PREDATR] +Predator -[AM1_5] -~g~Ve al barrio rojo y espera a que Salvatore salga del club. +[BUS] +Autobús -[AM1_6] -~g~Si te dejas ver por el club de Luigi, ¡la mafia te descubrirá! +[RHINO] +Rhino -[AM1_7] -~r~Salvatore está en su casita, sano y salvo, tomándose un cóctel. ¡Nadie te va a llamar ''Chacal''! +[BARRCKS] +Barracks OL -[AM1_8] -~g~Salvatore saldrá del club de Luigi sobre las ~1~:~1~. +[TRAIN] +Tren -[AM1_10] -~g~Salvatore saldrá del club de Luigi sobre las 0~1~:~1~. +[HELI] +Helicóptero -[AM1_9] -~r~¡Salvatore ha vuelto a meterse en el club de Luigi! +[DODO] +Dodo -{ ========================================================================================== } -{ ================= MISSION: UNDER SURVEILLANCE (ASUKA KASEN, FIRST BATCH) ================= } -{ ========================================================================================== } +[COACH] +Coach -{ TITLE } +[CABBIE] +Cabbie -[AM2] -'BAJO VIGILANCIA' +[STALION] +Stallion -{ Premission cutscene } +[RUMPO] +Rumpo -{ Asuka } +[RCBANDT] +Bandit RC -[AM2_A] -La muerte de Salvatore es una placentera noticia, +[BELLYUP] +Furgoneta de las Tríadas -[AM2_A2] -eres un asesino eficaz. Eso me gusta en un hombre. +[MRWONGS] +Mr Wongs -[AM2_B] -Este es mi hermano Kenji. +[MAFIACR] +Sentinel de la mafia -{ Kenji } +[YARDICR] +Lobo jamaicano -[AM2_C] -Asuka tiene un trabajito para ti, pero cuando acabes, pásate por mi casino y podremos hablar. +[YAKUZCR] +Stinger de la yakuza -{ Asuka } +[DIABLCR] +Stallion de los Diablos -[AM2_D] -Típico de Kenji, siempre está detrás de mis juguetes. +[COLOMCR] +Cruiser del cártel -{ The voiced dialogue doesn't match the English subtitles for the following strings } +[HOODSCR] +Rumpo XL de los hood -[AM2_E] -Mi contacto en la policía me dice que el FBI ha montado un operativo de vigilancia +[AEROPL] +Avioneta -[AM2_E2] -en varios puntos de la ciudad. +[SPEEDER] +Speeder -[AM2_F] -No tenemos tiempo para contactar con nadie y evitar que nos incriminen. +[REEFER] +Reefer -[AM2_G] -Liquida a esos polis espías, pero cuidado: tendrán apoyo. +[PANLANT] +Panlantic -{ Mission instructions } +[FLATBED] +Flatbed -[AM2_4] -~g~¡Has irrumpido como un elefante en una cacharrería! +[YANKEE] +Yankee -{ ======================================================================================= } -{ ================= MISSION: PAPARAZZI PURGE (ASUKA KASEN, FIRST BATCH) ================= } -{ ======================================================================================= } +[BORGNIN] +Borgnine -{ TITLE } +[TOYZ] +TOYZ -[AM3] -'PURGA DE PAPARAZZIS' +[FEST_DF] +Distancia recorrida a pie (millas) -{ Premission cutscene } +[FEST_DC] +Distancia recorrida en coche (millas) -{ Asuka (letter) } +[FESTDFM] +Distancia recorrida a pie (metros) -[AM3_A] -Un periodista ha estado husmeando por aquí. +[FESTDCM] +Distancia recorrida en coche (metros) -[AM3_B] -María y yo nos ido de vacaciones juntas hasta que puedas librarte de ese mirón pervertido. +[FEST_R1] +''Patio de recreo'' en segundos -[AM3_C] -Ahora mismo estará probablemente en la bahía. ¡Roba una lancha de la policía y hunde su carrera! +[FEST_R2] +''Un paseo por el parque'' en segundos -{ ======================================================================================= } -{ ================= MISSION: PAY DAY FOR RAY (ASUKA KASEN, FIRST BATCH) ================= } -{ ======================================================================================= } +[FEST_R3] +''¡Agarrado!'' en segundos -{ TITLE } +[FEST_RM] +''Caos en el aparcamiento'' en segundos -[AM4] -'LA PAGA DE RAY' +[FEST_LS] +Gente salvada con una ambulancia -{ Premission cutscene } +[FEST_CC] +Criminales asesinados en misiones de justiciero -{ Asuka } +[FEST_FE] +Incendios extinguidos -[AM4_A] -¡Si es guapo manitas! +[FEST_LF] +Vuelo más largo en Dodo -[AM4_B] -María está un poquito liada, pero le diré que has venido. +[FEST_BD] +Mejor tiempo al desactivar la bomba -{ Maria } +[FEST_RP] +Masacres superadas -[AM4_C] -¿Quién es, Asuka? Sé que he sido muy traviesa, ¡pero necesito mear! ¿Vale? +[FEST_MP] +Misiones superadas -{ Asuka } +[FEST_BB] +Carrera forrada: -[AM4_D] -Es hora de que conozcas a nuestro espía en la policía. +[FEST_H0] +Máximo de puntos de control -[AM4_E] -Aquí está su pago por el último trabajito que hizo para nosotros. +[FEST_GC] +Coches de bandas destruidos: -[AM4_F] -Él es comprensiblemente cauteloso. +[FEST_H1] +Destrucción de los Diablos -[AM4_G] -Ve a la cabina en Torrington tan rápido como puedas y espera sus instrucciones. +[FEST_H2] +La masacre de la mafia -{ Ray, on each payphone } +[FEST_H3] +Calamidad en el casino -[AM4_1A] -Ve a la cabina al oeste del Parque Belleville. +[FEST_H4] +Exterminio de Rumpos -[AM4_1B] -Ve a la cabina del Campus de Liberty. +[USJ] +¡PREMIO POR ACROBACIA ÚNICA! -[AM4_1C] -Ve a la cabina al sur del Parque Belleville. +[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 -[AM4_1D] -Ven a verme a los baños públicos del parque. +[HM1_1] +~g~Cepíllate a 20 Purple Nines en 2 minutos y 30 segundos. -{ Postmission cutscene } +[KM1_8A] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. -{ Ray } +[KM1_8D] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. -[AM4_3] -¡Tú debes de ser el nuevo chico de los recados de Asuka! +[KM1_12] +~g~¡Llévalo al dojo, pero deshazte primero de la policía! -[AM4_4] -¿Tienes el dinero? ¿Está todo? +[RATNG1] +Carterista -[AM4_5] -Ya sé lo que estás pensando, otro policía corrupto. +[RATNG2] +Abusón -[AM4_6] -Bueno, éste es un mundo corrupto. +[RATNG3] +Chorizo -[AM4_7] -Pierdo a un par de socios y esos idiotas de asuntos internos empiezan a meter las narices. +[RATNG4] +Granuja -[AM4_8] -¡Y seguro que les llega mi olor! +[RATNG5] +Secuaz -[AM4_9] -¡Pues esta ciudad es una gran alcantarilla! +[RATNG6] +Conductor -[AM4_10] -Pero voy a necesitar un ayudita ajena al cuerpo. +[RATNG7] +Guardaespaldas -[AM4_11] -Si estás interesado, ya sabes dónde encontrarme. +[RATNG8] +Negociador -{ ======================================================================================== } -{ ================= MISSION: TWO-FACED TANNER (ASUKA KASEN, FIRST BATCH) ================= } -{ ======================================================================================== } +[RATNG9] +Socio -{ TITLE } +[RATNG10] +Sicario -[AM5] -'TANNER EL TRAIDOR' +[RATNG11] +Asesino -{ Premission cutscene } +[RATNG12] +Mano derecha -{ Asuka (letter) } +[RATNG13] +Verdugo -[AM5_A] -María y yo hemos ido de compras. +[RATNG14] +Capo -[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! +[RATNG15] +Jefe -[AM5_C] -Fuera de su coche no sabe hacer casi nada, así que le hemos puesto un localizador. +[1010] +~r~Tu vehículo ha volcado -[AM5_D] -¡Haz que sufra! +[1011] +~r~Tu vehículo ha volcado -{ Mission instructions } +[1012] +~r~Tu vehículo ha volcado -[AM5_1] -¡Tanner te ha pillado! +[1013] +~r~Tu vehículo ha volcado -{ ========================================================================= } -{ ================= MISSION: KANBU BUST-OUT (KENJI KASEN) ================= } -{ ========================================================================= } +[1014] +~r~Tu vehículo ha volcado -{ TITLE } +[JM4_10] +Vale, chaval, llévame primero a la lavandería de Chinatown, tengo un asunto del que ocuparme. -[KM1] -'LA FUGA DEL KANBU' +[JM4_11] +Las lavanderas no están pagando por su protección. -{ Premission cutscene } +[JM4_12] +Y ojo con el coche, Joey acaba de arreglar esta chatarra. -{ Kenji } +[JM4_13] +Así que con cuidado, ¿vale? -[KM1_A] -Mi hermana te tiene en gran estima, +[KM4_11] +~g~¡Lleva el dinero de vuelta al casino! -[KM1_E] -pero yo debo convencerme de que un gaijin puede ofrecerme algo más que desilusiones. +[FEF_BR2] +Encuéntralo de nuevo leyendo los resúmenes de las misiones jugadas hasta la fecha. -[KM1_B] -Tal vez puedas ayudar con una situación que me tiene en desventaja. +[TRAIN_1] +Estación Kurowski -[KM1_F] -Por supuesto, el fracaso conllevará una desgracia. +[TRAIN_2] +Estación Rothwell -[KM1_C] -Un kanbu, o jefe de la yakuza, está bajo custodia a la espera de juicio. +[TRAIN_3] +Estación Baillie -[KM1_G] -Es un miembro importante de la familia. +[SUBWAY1] +Estación Portland -[KM1_H] -Libéralo y llévatelo al dojo de Bedford Point. +[SUBWAY2] +Estación Rockford -{ Pager message that appears after completing this mission } +[SUBWAY3] +Estación Staunton sur -[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. +[SUBWAY4] +Terminal Shoreside -{ Mission instructions } +[MEA4_2] +~r~¡Marty Chonks ha muerto! -[KM1_1] -~g~¡Roba un coche de 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. -[KM1_2] -~g~¡Instala una bomba en el coche! +[JM4_A] +Sí, Toni, ya está a punto. Ahora es una delicia, ¿sabes? -[KM1_3] -~g~Ahora llévalo al dojo de la yakuza. +[JM4_5] +Pasa más tarde y les daremos algo que lavar... ¡Su propia ropa manchada de sangre! -[KM1_4] -~g~¡Necesitas un coche de policía para hacer el trabajo! +[AMMU_A] +Luigi dijo que necesitabas una pipa... -[KM1_5] -~g~Ahora ve a la comisaría. +[AMMU_B] +Joey me pidió que te armáramos... -[KM1_6] -~g~¡Pon una bomba en el coche! +[AMMU_C] +Ve a la parte de atrás. Te dejé un nueve en el patio. -[KM1_7] -~g~¡Sólo pueden entrar vehículos de policía autorizados! +[AMMU_D] +Tengo todo lo necesario para defender tu casa. -[KM1_8A] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. +[AMMU_E] +¿También quieres una licencia? -[KM1_8D] -Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para ~h~activar la bomba~w~; acuérdate de alejarte de ella. +[AMMU_F] +No necesito tu documentación, pareces de fiar. -[KM1_9] -~r~No destruiste la pared con un coche bomba. +[DETON] +DETONACIÓN: -[KM1_10] -~r~El kanbu está muerto, ¡y tu honor también! +[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. -[KM1_11] -~r~¡La policía te ha seguido! +[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. -[KM1_12] -~g~¡Llévalo al dojo, pero deshazte primero de la policía! +[RECORD] +~g~¡NUEVO RÉCORD! -[KM1_13] -¡Mete el vehículo en el garaje! +[NRECORD] +~r~¡NO HAY UN NUEVO RÉCORD! -{ =========================================================================== } -{ ================= MISSION: GRAND THEFT AUTO (KENJI KASEN) ================= } -{ =========================================================================== } +[RCHELP] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. -{ TITLE } +[RCHELPA] +Pulsa el botón ~k~~PED_FIREWEAPON~ o conduce el coche teledirigido hasta las ruedas de otro coche para detonarlo. -[KM2] -'ROBO DE VEHÍCULOS' +[RC_1] +¡Tienes 2 minutos para destruir todos los coches de los Diablos que puedas! -{ Premission cutscene } +[RC_2] +¡Tienes 2 minutos para destruir todos los coches de la mafia que puedas! -{ Kenji } +[RC_3] +¡Tienes 2 minutos para destruir todos los coches de la yakuza que puedas! -[KM2_A] -Es imposible sobreestimar la importancia del protocolo en este trabajo. +[RC_4] +¡Tienes 2 minutos para destruir todos los coches de los jamaicanos que puedas! -[KM2_B] -Para mi vergüenza eterna, un hombre me hizo una vez un favor y nunca pude corresponder su amabilidad. +[RC_5] +¡Tienes 2 minutos para destruir todos los coches de los Hood que puedas! -[KM2_C] -Su debilidad son los coches y nos ha pedido que adquiramos ciertos modelos para su colección. +[RC_6] +¡Tienes 2 minutos para destruir todos los coches del cártel que puedas! -[KM2_D] -No hace falta decir que debemos darle los coches como un regalo, para pagar mi deuda con él. +[RAMPAGE] +¡MASACRE! -[KM2_E] -Debes obtener los coches de la lista y llevarlos a un garaje que hay tras el aparcamiento de Newport. +[RAMP_P] +¡MASACRE COMPLETADA! -[KM2_F] -Mi honor lo exige. +[RAMP_F] +MASACRE FALLIDA -{ Mission instructions } +[PAGE_00] +. -[KM2_1] -~g~Repara el coche, tiene que estar en perfecto estado. +[PAGE_01] +¡Mata a ~1~ Diablos en 120 segundos! -[KM2_2] -~g~Coche entregado. +[PAGE_02] +¡Destruye ~1~ vehículos en 120 segundos! -[KM2_3] -~g~Recuerda que los ~r~coches ~g~tienen que estar en perfecto estado para ser aceptados en el ~p~garaje~g~. +[PAGE_03] +¡Mata a ~1~ mafiosos en 120 segundos! -{ ===================================================================== } -{ ================= MISSION: DEAL STEAL (KENJI KASEN) ================= } -{ ===================================================================== } +[PAGE_04] +¡Mata a ~1~ Tríadas en 120 segundos! -{ TITLE } +[PAGE_05] +¡Mata a ~1~ Tríadas en 120 segundos! -[KM3] -'UN MAL TRATO' +[PAGE_06] +¡Destruye ~1~ vehículos en 120 segundos! -{ Premission cutscene } +[PAGE_07] +¡Revienta ~1~ cabezas jamaicanas en 120 segundos! -{ Kenji } +[PAGE_08] +¡Quema a ~1~ yakuzas en 120 segundos! -[KM3_A] -Cuando los problemas acechan, el tonto les da la espalda, mientras que el sabio los enfrenta. +[PAGE_09] +¡Destruye ~1~ vehículos en 120 segundos! -[KM3_B] -El cártel colombiano ha ignorado nuestras repetidas peticiones de que dejen en paz nuestros intereses en Liberty. +[PAGE_10] +¡Destruye ~1~ vehículos en 120 segundos! -[KM3_C] -Ahora están negociando con los jamaicanos para humillarnos aún más. +[PAGE_11] +¡Aniquila a ~1~ jamaicanos en 120 segundos! -[KM3_D] -Están cerrando un trato en la ciudad. +[PAGE_12] +¡Quema a ~1~ yakuzas en 120 segundos! -[KM3_F] -Llévate a uno de mis hombres, roba un coche de los jamaicanos y presenta tus respetos a los colombianos. +[PAGE_13] +¡Vuela a ~1~ jamaicanos en 120 segundos! -[KM3_E] -¡Nuestro honor exige que no dejes a nadie vivo! +[PAGE_14] +¡Fríe a ~1~ colombianos en 120 segundos! -{ Mission instructions } +[PAGE_15] +¡Machaca a ~1~ Hoods en 120 segundos! -[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. +[PAGE_16] +¡Destruye ~1~ vehículos en 120 segundos! -[KM3_2] -~g~Recoge a tu contacto. +[PAGE_17] +¡Arrolla a ~1~ colombianos con un coche en 120 segundos! -[KM3_3] -~g~¡La reunión está teniendo lugar en el aparcamiento del hospital de Rockford! +[PAGE_18] +¡Destruye ~1~ vehículos disparando desde otro en 120 segundos! -[KM3_4] -~r~¡Han escapado! +[PAGE_19] +¡Revienta ~1~ cabezas colombianas en 120 segundos! -[KM3_5] -~g~Toca el claxon para empezar con el trato. +[PAGE_20] +¡Decapita a ~1~ Hoods en 120 segundos! -[KM3_6] -~g~¡Mátalos, mátalos a todos! +[JM1_A] +Jo, me aburro, ¿cuándo me la vas a meter? -[KM3_7] -¡Es una trampa de la yakuza, tío! +[JM1_B] +Dame un momento, cariño, que tengo un asuntillo que tratar. -[KM3_8] -~g~¡Necesitas un coche de los jamaicanos para este trabajo! +[JM1_C] +Tengo un trabajito para ti, colega. -[KM3_9] -~r~Uno de los colombianos ha muerto, se ha cancelado el trato. +[JM1_D] +Los hermanos Forelli me deben dinero desde hace mucho tiempo -[KM3_10] -~r~¡El contacto está muerto! +[JM1_E] +y hay que enseñarles respeto. -[KM3_11] -~g~El cártel ha sido atacado y el maletín no ha sido recuperado. +[JM1_F] +Labios Forelli está atiborrándose en el restaurante de Saint Mark's, -[KM3_12] -~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. +[JM1_G] +así que róbale el coche y llévalo al taller de bombas de 8-Ball en Harwood. -[KM3_13] -~g~Lleva el maletín de vuelta al casino. +[JM1_H] +Conoces a 8-Ball, ¿verdad? -[KM3_14] -~r~¡Te han descubierto, han cancelado el trato! +[JM1_I] +En cuanto esté cargado con una bomba, aparca el coche donde lo encontraste. -{ ================================================================ } -{ ================= MISSION: SHIMA (KENJI KASEN) ================= } -{ ================================================================ } +[JM1_J] +Luego salte y disfruta del espectáculo. -{ TITLE } +[JM1_K] +Pero cuidado, no va a estar comiendo toda la vida. -[KM4] -'SHIMA' +[CAT2_A1] +¡Vamos, perra! -{ Premission cutscene } +[CAT2_A] +La verdadera pregunta es: ¿vienes buscando a María o buscándome a mí? -{ Kenji } +[CAT2_B] +Tengo una noticia para ti: -[KM4_A] -Para ser verdaderamente fuerte, es importante no mostrar debilidad. +[CAT2_B2] +matarte será un placer, pero salir contigo sólo fue un negocio. -[KM4_B] -El negocio es lo bastante afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. +[CAT2_C] +¡Eres muy pequeñito, amigo! -[KM4_C] -Hazte con el dinero inmediatamente para que podamos ingresarlo en las cuentas del casino. +[CAT2_D] +Dame el dinero. -{ Cutscene after going to Uncle BJ's Deli & Groceries } +[CAT2_E] +¡Has estado muy ocupado! -{ Male shop owner } +[CAT2_E2] +Pero no has aprendido que yo no soy de fiar. -[KM4_1] -¡No puedo pagarte y no lo haría aunque pudiera! +[CAT2_E3] +¡Mata al idiota! -[KM4_9] -¡Una banda de chavales acaba de arrasar el local! ¡Se han llevado todo! +[CAT2_J] +¡Despega de una vez! -[KM4_2] -¡Sois inútiles! +[HM5_1] +Hola, Ice dijo que vendrías. Las reglas son sólo bates. Cero armas, cero coches. -[KM4_10] -Además, ¿qué clase de yakuza eres tú? +[HM5_5] +Es una batalla por respeto, ¿vale? -{ Unused strings? } +[HELP14] +Para conseguir un arma, pasa sobre ella. No puedes recogerlas estando dentro de un vehículo. -[KM4_3] -No pago a matones como vosotros para esto. Si quisiera esta clase de protección, llamaría a la policía, demonios. +[CRUSH] +Aparca en la zona señalada y sal de tu vehículo para que sea triturado. -[KM4_6] -¡Aquí está todo el dinero! +[DIAB2_B] +Una banda de roñosos amenazó con quitarme a mi protagonista si no les pago. -{ Pager message that tells the player Donald Love's missions are available } +[DIAB2_C] +Amenazaron al hombre equivocado, amigo. -[KM4_5] -Donald Love desea que te pases por su jardín de té para tener una charla. +[DIAB2_D] +Su debilidad son los helados. -{ Mission instructions } +[DIAB2_E] +Hazte con la bomba que dejé en Harwood, -[KM4_4] -~g~¡Castiga a la banda responsable y recupera el ~b~dinero de la protección~g~! +[DIAB2_F] +secuestra la camioneta del heladero mientras hace su ronda -[KM4_7] -~r~¡El tendero la acaba de palmar! +[DIAB2_G] +y engaña a esos idiotas con esa musiquita. -[KM4_8] -~g~¡Maletín recolectado! +[DIAB2_H] +Se esconden en un almacén del muelle Atlantic. -[KM4_11] -~g~¡Lleva el dinero de vuelta al casino! +[DIAB3_A] +¡Unas Tríadas insolentes robaron mi lindo carro anoche, -{ ===================================================================== } -{ ================= MISSION: SMACK DOWN (KENJI KASEN) ================= } -{ ===================================================================== } +[DIAB3_B] +lo destrozaron y lo quemaron! -{ TITLE } +[DIAB3_C] +En el baúl había algunas de mis más preciadas posesiones sobre burros... -[KM5] -'CONTRINCANTES TRAFICANTES' +[DIAB3_D] +Objetos de coleccionista irremplazables, amigo. -{ Premission cutscene } +[DIAB3_E] +Escondí un arma en el borde de Chinatown. -{ Kenji } +[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. -[KM5_A] -¡Tú! ¡Qué oportuno por tu parte que muestres ahora tu despreciable cara! +[DIAB3_1] +MATA A 25 TRÍADAS -[KM5_B] -¡Parece que tus intentos para disuadir a los jamaicanos +[DIAB4_A] +¡Un ladrón oportunista robó una camioneta con mi última publicación! -[KM5_B1] -de convertirse en aliados del cártel han sido totalmente inútiles! +[DIAB4_B] +Pero ese idiota drogado de SPANK dejó las puertas de atrás abiertas, -[KM5_C] -¡Los traficantes jamaicanos están llenando las calles de Liberty, vendiendo SPANK como si fueran perritos calientes! +[DIAB4_C] +¡y ahora mi literatura para adultos -[KM5_D] -Estos cerdos del cártel se están riendo de nosotros, ¡de mí! +[DIAB4_D] +tan bellamente producida, tan gustosamente fotografiada, está siendo esparcida por toda Liberty! -[KM5_E] -¡Te daré una última oportunidad para demostrar que la fe que tiene mi hermana en ti tiene un buen motivo! +[DIAB4_E] +Toma la camioneta y sigue el rastro de los volúmenes 1, 2 y 3 de Donkey Does Dallas, -[KM5_F] -¡Arrolla a estos canallas y lava tu vergüenza en el río de la sangre de nuestros enemigos! +[DIAB4_F] +tomándolos por el camino. -{ Mission instructions } +[DIAB4_G] +¡Cuando alcances a ese bandido espaciado con SPANK, chíngatelo! -[KM5_1] -~g~¡TRAFICANTE LIQUIDADO! +[DIAB4_H] +Luego reparte mis revistas XXX por el barrio rojo. -[KM5_2] -~g~Uno de los jamaicanos se ha ido. +[DIAB4_1] +~g~Lleva la furgoneta a la parte de atrás de Revistas XXX. -[KM5_3] -~r~No has matado a ~1~ jamaicanos. +[HM1_E] +Quiero que esos mierdecillas sepan lo que es un verdadero tiroteo desde un vehículo. -[KM5_4] -~g~Enhorabuena, has matado a ~1~ jamaicanos. +[HM1_H] +¡Haz que esos Nines se larguen! -[KM5_5] -~g~Enhorabuena, has matado a ~1~ jamaicanos. ~1~$ ADICIONALES +[HM2_A] +Los Nines me están presionando. -[KM5_6] -~g~Debes matar a al menos 8 traficantes jamaicanos. +[HM2_B] +Tienen coches blindados y ahora están traficando SPANK -[KM5_7] -~g~¡Mátalos rápido! En cuanto vendan el SPANK se retirarán de las calles. +[HM2_C] +a los hermanos sin ningún pudor. -{ ================================================================================= } -{ ================= MISSION: BLING-BLING SCRAMBLE (KING COURTNEY) ================= } -{ ================================================================================= } +[HM2_D] +Hay un coche aparcado en la calle. -{ TITLE } +[HM2_E] +Dentro verás algo que te servirá para poner a esos gallinas en su sitio -[YD1] -'CORRE A POR LA PASTA' +[HM3_A] +Algún cazurro me ha puesto una bomba en el coche. -{ Pager message that appears when the Yardies missions are available } +[HM3_B] +Si lo pierdo, mi reputación en la calle se irá a la porra. -[YD_P] -El Rey Courtney quiere hablarte. ¡Ve al teléfono público de Aspatria! +[HM3_C] +Coge mi coche y llévalo al taller de Saint Mark's, ¿valiendo? -{ Premission cutscene } +[HM3_D] +Que se encarguen ellos de desarmar la bomba. -{ King Courtney } +[HM3_E] +El tiempo avanza y ese trasto es un peligro. -[YD1_A] -Habla el rey Courtney. +[HM3_F] +Un golpe más de la cuenta y podría saltar por los aires. -[YD1_A1] -Mi banda jamaicana necesita un conductor y tú tienes reputación de ser bueno. +[HM3_G] +¡Tira! -[YD1_B] -Ve en un coche al basurero que hay detrás del estadio y a los otros candidatos. +[HM4_A] +Tío, un vuelo de la Reserva Federal se la acaba de pegar en el Aeropuerto Francis. -[YD1_C] -Tengo hombres vigilando puntos de control por toda Staunton. +[HM4_B] +Hay platino por toda la pista. -[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. +[HM4_C] +Consigue un coche y agarra todo lo que puedas. -{ Mission instructions } +[HM4_F] +Puedes dejar la mercancía en uno de mis garajes. -[YD1_E] -~g~¡Prepárate! +[HM4_G] +El platino pesa un huevo y hará que tu buga vaya a paso de tortuga, -[YD1_F] -~g~Te has saltado la salida. ¡Me gusta tu estilo! +[HM4_H] +así que ve dejándolo de vez en cuando en el garaje. -[YD1_G] -~r~Esto es una carrera DE COCHES. ¡Necesitas un COCHE, idiota! +[HM5_A] +Ya solo quedan unos pocos Nines, -[YD1GO] -~g~¡VAMOS! +[HM5_B] +pero todavía quieren guerra. -[YD1_1] -~r~1 +[HM5_C] +Han aceptado un mano a mano. -[YD1_2] -~r~2 +[HM5_D] +Un puñado de los suyos contra dos de los nuestros, -[YD1_3] -~r~3 +[HM5_E] +o más bien, tú y uno más. -[YD1_BON] -¡1.000$! +[HM5_F] +Os ayudaría, pero... -[Y1_1ST] -~G~¡Has quedado primero con ~1~ puntos de control! +[HM5_G] +No quiero jugarme mi libertad condicional, -[Y1_2ND] -~y~Eres el segundo con ~1~ puntos de control. ~y~¡Casi, pero no! +[HM5_H] +¿me captas? -[Y1_3RD] -~r~Eres el tercero con ~1~ puntos de control. ~r~¿No decías que eras bueno? +[HM5_I] +Reúnete con mi hermano pequeño, -[Y1_LAST] -~r~¡Has quedado el último! ~r~¡Me has hecho perder el tiempo, IDIOTA! +[HM5_J] +él te enseñará dónde será la pelea. -[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! +[MEA1_B] +Me llamo Chonks, Marty Chonks. -[Y1_J2ND] -~r~Has empatado el segundo con ~1~ puntos de control. ¡Conduces como un mono loco! +[MEA1_C] +Soy el dueño de la fábrica de comestibles Bitch'n' Dog que está a la vuelta de la esquina. -[Y1JLAST] -~r~¡Has empatado el último! ¡Hablas como un conductor, pero conduces como un hablador! +[MEA1_D] +Tengo problemas económicos, pero, ¿y quién no? -[Y1_TEST] -¡COCHE AL AGUA! +[MEA1_E] +He quedado con el director de mi banco. -[YD1_CNT] -¡~1~ de 15! +[MEA1_F] +Es un chorizo que no para de inflar los intereses del préstamo para sacarme una buena tajada. -{ ====================================================================== } -{ ================= MISSION: UZI RIDER (KING COURTNEY) ================= } -{ ====================================================================== } +[MEA1_G] +Coge mi coche, búscale y tráelo de vuelta. -{ TITLE } +[MEA1_H] +¡Tengo una sorpresita para ese parásito chupasangre! -[YD2] -'JINETE CON UZI' +[MEA2_A] +Contraté a unos ladrones para que entraran en mi piso -{ Premission cutscene } +[MEA2_C] +Ahora los muy cabritos me amenazan con delatarme -{ King Courtney } +[MEA2_D] +si no les doy una parte. -[YD2_A] -Necesito ver si eres capaz de hacer mi trabajo sucio, +[MEA2_E] +¿Te lo puedes creer? -[YD2_A1] -si se puede confiar en ti. +[MEA2_F] +He dejado un coche dentro de la fábrica. -[YD2_B] -Dos de mis chicos llegarán allí enseguida para llevarte de paseo, +[MEA2_G] +Ve a recogerles con él en su territorio, en el barrio rojo. -[YD2_B1] -a ver si eres quien dices que eres. +[MEA2_H] +Luego tráelos a la fábrica para que conozcan la opinión de Marty. -{ Dialogue from Yardie after reaching you } +[MEA3_A] +El negocio se irá a pique si no consigo un pastizal muy pronto. -[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. +[MEA3_B] +Mi esposa tiene un seguro de vida y ella no ha hecho más que vaciarme los bolsillos. -[YD2_D] -Tú te ocupas de conducir y disparar. Nosotros nos aseguraremos de que no te eches atrás. +[MEA3_C] +He dejado un coche donde siempre. -[YD2_CC] -Toma, necesitarás una pipa. +[MEA3_D] +Ve a por a mi esposa a Classic Nails y tráela a la fábrica. -{ Dialogue from Yardie after entering the car } +[MEA4_A] +Mierda, ¡la he liado! -[YD2_E] -¡Conduce! +[MEA4_B] +Resulta que mi esposa salía con uno al que debo dinero. -{ Dialogue from Yardie when trying to get out of the car } +[MEA4_C] +¡Se ha cabreado y ahora quiere vengarse! -[YD2_F] -~r~Se quiere escapar, ¡cárgatelo! +[MEA4_E] +y piensa que voy a devolverle el dinero. -{ Dialogue from Yardie after reaching the objective area } +[MEA4_F] +Pero creo... -[YD2_G1] -Los cerros de Hepburn... Vamos a matar a algunos asquerosos Diablos... +[MEA4_G] +¡que los perros de Liberty van a disfrutar de un sabor nuevo este mes! -[YD2_G2] -Pero recuerda, ~r~¡no salgas de este coche! +[WELCOME] +BIENVENIDO A -{ Dialogue from Yardie after killing the targets } +[HM1_2] +~g~Hazte con un vehículo y recuerda que sólo cuentan las muertes a tiros desde el coche. -[YD2_H] -¡Vale, ya está! ¡Llévanos de vuelta a territorio jamaicano! ¡Vamos, vamos, vamos! +[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~. -{ Dialogue from Yardie after taking them to the final goal } +[LRQC_1] +Asuka y yo tenemos que hablar... -[YD2_L] -¡Eres la Muerte personificada! +[LRQC_2] +¿Por qué no te das una vuelta? -{ Dialogue from Yardie after trashing the car } +[LRQC_3] +Necesitarás un escondite. -[YD2_M] -~r~¡Ha destrozado mi coche! ¡Liquídale! +[LRQC_4] +Hay un almacén en la orilla de Belleville que podría servirte. -{ Dialogue from Yardie when you are allowed to leave the car, but you must be in it } +[LRQC_5] +Regresa a mi apartamento cuando estés listo -[YD2_N] -¡Vuelve al coche! +[LRQC_6] +y podremos tener una charla. -{ ============================================================================= } -{ ================= MISSION: GANGCAR ROUND-UP (KING COURTNEY) ================= } -{ ============================================================================= } +[JM6_5] +~g~Necesitas un vehículo de fuga, ¡idiota! -{ TITLE } +[JM2_F] +Si necesitas una pipa, ve a la parte de atrás del Ammu-Nation que está enfrente del metro. -[YD3] -'COLECCIONANDO COCHES DE BANDAS' +[LOVE4_7] +~g~Hay una zona en obras en Staunton Island, puede que hayan llevado el paquete allí. -{ Premission cutscene } +[LOVE4_8] +~g~Necesitarás un coche para abrir el garaje. -{ King Courtney } +[TSCORE] +GANANCIAS: ~1~ $ -[YD3_A] -Quiero que robes coches de otras bandas +[AM1_9] +~r~¡Salvatore ha vuelto a meterse en el club de Luigi! -[YD3_A1] -para que podamos atacar sus territorios. +[AM1_6] +~g~Si te dejas ver por el club de Luigi, ¡la mafia te descubrirá! -[YD3_B] -Necesito un Mafia Sentinel, +[TM2_3] +~g~¡Es una trampa! ¡Liquidadlos a todos! -[YD3_B1] -un Yakuza Stinger y un +[FM4_1] +Soy María. ¡El coche es una trampa! Estoy en el lado sur del puente Callahan. -[YD3_B2] -Diablo Stallion para que podamos ir a por cualquier banda de Liberty. +[JM1_7] +~g~¡Cierra la puerta del coche! ¡Se dará cuenta! -[YD3_C] -Déjalos en el garaje de Newport y recuerda, +[KM5_1] +~g~¡TRAFICANTE LIQUIDADO! -[YD3_C1] -¡dañados no nos sirven de nada! +[KM5_6] +~g~Debes matar a al menos 8 traficantes jamaicanos. -[YD3_D] -UNUSED +[KM5_7] +~g~¡Mátalos rápido! En cuanto vendan el SPANK se retirarán de las calles. -{ Mission instructions } +[RM3_8] +~r~¡El coche es un señuelo! -[YD3_E] -~r~¡Ya has entregado un coche de los Diablos! +[LM3_8] +Hola, soy Joey. -[YD3_F] -~r~¡Ya has entregado un coche de la mafia! +[LM3_9] +Luigi dijo que eras de fiar, así que vuelve más tarde, -[YD3_G] -~r~¡Ya has entregado un coche de la yakuza! +[KM3_5] +~g~Toca el claxon para empezar con el trato. -[YD3_H] -~g~¡Coche de los Diablos entregado! +[LOVE7] +'LA DESAPARICIÓN DE LOVE' -[YD3_I] -~g~¡Coche de la mafia entregado! +[LOVE2_5] +~g~¡Kenji ha palmado! ¡Sal de Newport y deshazte del coche! -[YD3_J] -~g~¡Coche de la yakuza entregado! +[AS2_11] +~g~¡~1~ DE 9! -[YD3_K] -~r~¡El coche está casi destrozado! ¡Haz que lo reparen! +[GARAGE1] +~g~Sal del vehículo y aléjate caminando. -[YD3_L] -~g~¡Llévalo al ~p~garaje~g~! +[KM3_11] +~g~El cártel ha sido atacado y el maletín no ha sido recuperado. -[YD3_M] -~r~¡Has volcado el vehículo! ¡Consigue otro! +[KM3_12] +~g~Mata a todos los colombianos, destruye los vehículos y recupera el maletín. -{ ========================================================================= } -{ ================= MISSION: KINGDOM COME (KING COURTNEY) ================= } -{ ========================================================================= } +[KM3_13] +~g~Lleva el maletín de vuelta al casino. -{ TITLE } +[RM5_6] +~g~¡Ha salido de la ambulancia! ¡Cárgate su escayola con un vehículo o una explosión! -[YD4] -'POR LOS AIRES' +[PBOAT_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. -{ Premission cutscene } +[PBOAT_2] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar los cañones de la lancha. -{ King Courtney } +[DIAB1_B] +Al habla El Burro, de los Diablos. -[YD4_A] -¡Escucha! +[DIAB1_D] +Eres nuevo en Liberty, pero ya te estás ganando una reputación en las calles. -[YD4_A1] -Mueve el culo a Bedford Point. +[DIAB1_E] +Hay una carrera que empezará junto a la sala Clásica, cerca del puente Callahan. -[YD4_A2] -¡Hay un cargamento en una tartana que necesito pronto! +[DIAB1_F] +Consíguete un buen carro y el primero que pase por todos los puntos de control se llevará el premio. -{ Cutscene after entering the target car } +[HM2_1] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. -{ Catalina, colombiana } +[HM2_1A] +Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. -[YD4_B] -CARTA: Dicen que estuviste entretenido. Igual que yo. +[HM2_2] +~r~¡No has destruido todos los furgones blindados! -[YD4_C] -¡Es hora de que seas testigo del verdadero poder del 'SPANK'! Con mucho amor, Catalina. +[HM2_6] +~g~¡Te has cargado un furgón blindado! -[YD4_D] -P.D. ¡MUERE, BASURA, MUERE! +[RM3_A] +Conozco a un pez gordo de la ciudad, un tipo muy cándido, -{ Mission instructions } +[RM3_H] +con, digamos... gustos exóticos y el dinero para pagárselos. -[YD4_1] -~g~¡Son psicópatas adictos al SPANK! +[RM3_B] +Está involucrado en un asunto legal y la fiscalía tiene fotos de él muy comprometedoras -[YD4_2] -~g~¡Destruye las furgonetas de SPANK! +[RM3_C] +en una fiesta en la morgue o algo así. -{ ============================================================================== } -{ ================= MISSION: SILENCE THE SNEAK (RAY MACHOWSKI) ================= } -{ ============================================================================== } +[LOVE6_A] +Una lección sobre negocios, amigo mío: -{ TITLE } +[LOVE6_E] +Si tienes una mercancía única, todo el mundo tratará de arrebatártela, -[RM1] -'SILENCIA AL SOPLÓN' +[LOVE6_C] +Unos SWAT han acordonado la zona donde se encuentran mi socio y el paquete. -{ Premission cutscene } +[LOVE6_D] +Ve allí, recoge la furgoneta y haz de señuelo. -{ Ray } +[LOVE6_F] +Mantenles ocupados y él podrá escaparse. -[RM1_A] -¡Ese canalla de McAffrey...! ¡Aceptó más sobornos que nadie, +[AM3_C] +Ahora mismo estará probablemente en la bahía. ¡Roba una lancha de la policía y hunde su carrera! -[RM1_B] -se piensa que le darán la pensión completa si se convierte en un testigo de cargo! +[FESZ_UC] +CANCELAR -[RM1_C] -¡Y ha cantado! +[FEDS_SM] +L1, R1 - CAMBIAR MENÚ -[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. +[FEDS_AS] +;= - CAMBIAR SELECCIÓN -[RM1_E] -Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con nadie. +[FEDSAS2] +<> - CAMBIAR SELECCIÓN -{ Mission instructions } +[FEDS_SS] +L1,R1 - CAMBIAR SELECCIÓN -[RM1_1] -~g~Ve a la casa de protección de testigos. +[FEDSSC1] +; - ACELERAR -[RM1_2] -~g~¡Cárgate a McAffrey! +[FEDSSC2] += - RALENTIZAR + +[MEA2_3] +~g~Lleva el coche de vuelta a la fábrica. [RM1_3] ~r~¡McAffrey se ha escapado! @@ -4523,3789 +4809,2295 @@ Quema el lugar, así saldrán y podrás cazarlos. Asegúrate de que no hable con [RM1_5] ~g~¡Vuelve y quema la casa franca! -{ ========================================================================== } -{ ================= MISSION: ARMS SHORTAGE (RAY MACHOWSKI) ================= } -{ ========================================================================== } +[RM6_4] +~g~Ve al almacén a por el cargamento de Ray. -{ TITLE } +[RM6_5] +~g~La CIA vigila el puente, busca otro camino. -[RM2] -'ESCASEZ DE MANOS' +[HM2_F] +y cargarte sus blindados. -{ Premission cutscene } +[HM_4] +'FIEBRE DEL PLATINO' -{ Ray } +[MEA4_B7] +Pero si pasas por mi oficina... -[RM2_A1] -¡Chico, estoy aquí! +[MEA3_B4] +¿Marty quiere verme? Bueno, pues que sea rápido, porque tengo que ir a la peluquería. -[RM2_A] -Un viejo colega del ejército tiene un negocio en Rockford. +[KM3_7] +¡Es una trampa de la yakuza, tío! -[RM2_B] -Combatimos juntos en Nicaragua, cuando el país sabía lo que hacía. +[FES_LOF] +Fallo al cargar. -[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. +[P1INSA] +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 tiene ~1~ KB de espacio disponible. Necesitas ~1~ KB para guardar. -[RM2_D] -Va a necesitar respaldo y a cambio te venderá material de todo tipo a precios de ganga. +[P1INSN] +La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 no tiene espacio suficiente. Por favor, borra algunos archivos. -[RM2_D1] -Iría yo mismo, pero la ciática ya está en sus trece... ¡Cof, cof! Así que... buena suerte. +[FES_SLO] +ARCHIVO -{ Cutscene, appears when finding Phil } +[FES_ISC] +ESTÁ DAÑADO -{ Phil } +[FESZ_TI] +ARCHIVO Z1 -[RM2_E] -Ray me avisó... Pero pensé que vendría más gente. +[FESZ_SA] +Guardar partida -[RM2_E1] -¡No puedo creer que esos mamones amarillos me hayan vuelto a dejar con el culo al aire! +[P1NOIN] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. -[RM2_F] -Bueno, tres brazos son mejor que uno, así que sírvete. +[P1INSE] +Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. -[RM2_F1] -¡Los colombianos llegarán en cualquier momento! +[MC_LDFL] +¡Fallo al cargar! -{ Dialogue from Phil, when the Colombians arrive } +[MC_NWRE] +Reiniciando partida. -[RM2_K] -Maldita sea, ¡están aquí! ¡FUEGO A DISCRECIÓN! +[LOVE6_3] +~g~Tienes ~1~ segundos para volver al Securicar antes de fracasar la misión. -{ Dialogue from Phil, when the Colombians are killed } +[LOVE6_4] +~r~¡Has abandonado el Securicar señuelo! -[RM2_L] -¡Caray! ¡Si hubieras estado a mi lado en Nicaragua, a lo mejor conservaría el brazo! +[HELP1] +Detente en el centro de la señal azul. -[RM2_M] -Si necesitas armas nuevas, pasa por aquí y coge lo que necesites de las taquillas. +[HELP12] +Entra en la señal azul para comenzar una misión. -[RM2_N] -Deja el dinero en el suelo. Ahora vete, ya me ocupo yo de la poli. +[HJSTAT] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. -{ Mission instructions } +[HJSTATW] +Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! -[RM2_G] -~g~¡Ve a ver a Phil! +[DIAB1_5] +TIEMPO DE CARRERA: -[RM2_H] -~r~¡Han matado a Phil! +[LOVE3_4] +~r~¡Has destruido el avión! -{ ========================================================================== } -{ ================= MISSION: EVIDENCE DASH (RAY MACHOWSKI) ================= } -{ ========================================================================== } +[F_FAIL1] +¡Misión del camión de bomberos terminada! -{ TITLE } +[F_CANC] +~r~¡Misión del camión de bomberos cancelada! -[RM3] -'FALTA DE PRUEBAS' +[F_EXTIN] +INCENDIOS: -{ Premission cutscene } +[A_COMP1] +¡Misiones de sanitario completadas! -{ Ray } +[A_CANC] +~r~¡Misión de sanitario cancelada! -[RM3_A] -Conozco a un pez gordo de la ciudad, un tipo muy cándido, +[A_COMP3] +¡Misiones de sanitario completadas! ¡Ahora no te cansarás al correr! -[RM3_H] -con, digamos... gustos exóticos y el dinero para pagárselos. +[ATUTOR] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. -[RM3_B] -Está involucrado en un asunto legal y la fiscalía tiene fotos de él muy comprometedoras +[ATUTOR3] +Pulsa el ~h~botón ~k~~TOGGLE_SUBMISSIONS~~w~ para activar o desactivar las misiones de sanitario. -[RM3_C] -en una fiesta en la morgue o algo así. +[ALEVEL] +Nivel de misión de sanitario: ~1~ -[RM3_D] -Están transportando las pruebas por la ciudad. +[A_FAIL1] +Misión de sanitario terminada. -[RM3_E] -Tendrás que embestir al coche y recoger hasta la última prueba que se le caiga. +[FEST_HA] +Nivel más alto de misión de sanitario -[RM3_F] -En cuanto tengas todas, déjalas en tu coche y préndele fuego. +[A_SAVES] +GENTE SALVADA: ~1~ -[RM3_G] -Cuando acabes, nos irá mucho mejor, chico. +[C_KILLS] +CRIMINALES ABATIDOS: ~1~ -{ Mission instructions } +[HM1_B] +Tengo un problema, me la están liando. -[RM3_1] -~g~Deja las pruebas en un coche y después préndele fuego. +[AM2_A] +La muerte de Salvatore es una placentera noticia, -[RM3_4] -~g~¡Al fiscal se le ha caído una prueba! +[AM2_A2] +eres un asesino eficaz. Eso me gusta en un hombre. -[RM3_5] -~g~Tienes ~1~ de 6 paquetes de pruebas. +[AM2_B] +Este es mi hermano Kenji. -[RM3_6] -~r~¡Las fotos circularán por toda la ciudad! +[AM2_C] +Asuka tiene un trabajito para ti, pero cuando acabes, pásate por mi casino y podremos hablar. -[RM3_7] -~g~¡Ahora préndele fuego al coche! +[AM2_D] +Típico de Kenji, siempre está detrás de mis juguetes. -[RM3_8] -~r~¡El coche es un señuelo! +{ The voiced dialogue doesn't match the English subtitle for the next string } -{ ========================================================================= } -{ ================= MISSION: GONE FISHING (RAY MACHOWSKI) ================= } -{ ========================================================================= } +[AM2_E] +Mi contacto en la policía me dice que el FBI ha montado un operativo de vigilancia -{ TITLE } +{ The voiced dialogue doesn't match the English subtitle for the next string } -[RM4] -'DE PESCA' +[AM2_E2] +en varios puntos de la ciudad. -{ Premission cutscene } +{ The voiced dialogue doesn't match the English subtitle for the next string } -{ Ray } +[AM2_F] +No tenemos tiempo para contactar con nadie y evitar que nos incriminen. -[RM4_A] -Creo que mi socio es un soplón. +{ The voiced dialogue doesn't match the English subtitle for the next string } -[RM4_B] -Tenemos que cerrarle la boca para siempre. +[AM2_G] +Liquida a esos polis espías, pero cuidado: tendrán apoyo. -[RM4_C] -Casi todas las noches sale a pescar con su lancha cerca del faro que hay en Portland Rock. +[F_START] +~g~Informe de vehículo en llamas en: ~a~. Ve y extingue el fuego. -[RM4_D] -¡Roba una lancha de la policía y asegúrate de que se le acaben las ganas de dar puñaladas traperas! +[AM4_1A] +Ve a la cabina al oeste del Parque Belleville. -[RM4_E] -¡Quiero que se vaya a dormir con los peces, en vez de comérselos! +[AM4_1B] +Ve a la cabina del Campus de Liberty. -{ Mission instructions } +[AM4_1C] +Ve a la cabina al sur del Parque Belleville. -[RM4_1] -~g~Ve y roba una lancha de la policía. +[AM4_1D] +Ven a verme a los baños públicos del parque. -[RM4_2] -~g~¡Ve al faro y ''hunde'' al socio de Ray! +[HJSTATF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. -[RM4_3] -~r~¡El socio de Ray ha escapado! +[HJSTAWF] +Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! -{ ============================================================================ } -{ ================= MISSION: PLASTER BLASTER (RAY MACHOWSKI) ================= } -{ ============================================================================ } +[HM1_F] +Pero ojo, también habrá Jacks que se creerán que vas a por ellos. -{ TITLE } +[HM1_D] +Se llaman ''Nines'', van de púrpura, y cada día en el que se hacen notar -[RM5] -'DESESCAYOLADOR' +[HM1_G] +es otro día más que los Jacks parecemos blandos. -{ Premission cutscene } +[MEA2_B] +y robaran cuanto pillaran para que yo pudiera reclamar a la aseguradora. -{ Ray } +[TM3_H] +Buen trabajo, chaval, muy bueno. -[RM5_A] -¡Inútil de mierda! +[TM3_I] +Vente, te presentaré al Don. -[RM5_A1] -¡La has cagado! Me la estoy jugando y ni siquiera eres capaz de matar a una maldita mosca. +[TM3_J] +¡Hola! ¡Luigi! -[RM5_B] -¡Te pagué una pasta para matar al testigo y aún sigue vivo! +[TM3_K] +Mis chicas te han echado de menos, Salvatore. Hace mucho que no te vemos. -[RM5_B1] -¡Y hoy va a declarar ante los federales! +[TM3_L] +Diles que en cuanto resolvamos este desafortunado incidente -[RM5_C] -Está a punto de ser trasladado del hospital general Carson, en Rockford. +[TM3_M] +iremos todos al club para celebrarlo, ¿vale? -[RM5_D] -Si él canta, yo canto... +[TM3_N] +¡Mi niño! -[RM5_E] -¡así que termina el trabajo por el que te pagué! +[TM3_N2] +¿Cómo lo llevas, papá? -{ Mission instructions } +[TM3_O] +¿Has encontrado ya una buena mujer? -[RM5_1] -~g~Intercepta la ambulancia. +[TM3_P] +Tu madre, que en paz descanse, se retorcería en la tumba -[RM5_2] -~g~¡Te han descubierto! +[TM3_Q] +si te viera sin una mujer. -[RM5_3] -~g~¡Era un señuelo! +[TM3_R] +Lo sé, papá, estoy en ello. -[RM5_4] -~g~¡Las balas no penetran en esa escayola de cuerpo entero! +[TM3_S] +¡Toni! ¿Cómo está tu madre? -[RM5_5] -~g~¡Esa escayola de cuerpo entero es ignífugo! +[TM3_T] +Es una gran mujer, ¿sabes? Fuerte, ''firenze''. -[RM5_6] -~g~¡Ha salido de la ambulancia! ¡Cárgate su escayola con un vehículo o una explosión! +[TM3_U] +Está bien, estupendamente. -[RM5_7] -~r~¡El testigo está a salvo! +[TM3_V] +Fantástico, fantástico. Bien, muchachos, entrad mientras yo hablo con nuestro nuevo amigo. -[RM5_8] -~g~¡El testigo se ha ahogado! +[TM3_W] +Tienes un gran futuro por delante, hijo mío... -{ ======================================================================= } -{ ================= MISSION: MARKED MAN (RAY MACHOWSKI) ================= } -{ ======================================================================= } +[RM1_A] +¡Ese canalla de McAffrey...! ¡Aceptó más sobornos que nadie, -{ TITLE } +[RM1_B] +se piensa que le darán la pensión completa si se convierte en un testigo de cargo! -[RM6] -'HOMBRE MUERTO' +[RM1_C] +¡Y ha cantado! -{ Premission cutscene } +[RM4_B] +Tenemos que cerrarle la boca para siempre. -{ Ray } +[RM4_E] +¡Quiero que se vaya a dormir con los peces, en vez de comérselos! -[RM6_A] -¿No te han seguido? Bien. +[LOVE3_B] +Esta noche, durante su aproximación al aeropuerto, una avioneta sobrevolará la bahía. -[RM6_B] -Se acabó, ¡esto se me va de las manos y estoy con la soga al cuello! +[LOVE4_D] +Desgraciadamente, las autoridades aduaneras registraron la avioneta y la comenzaron a desmontar -[RM6_C] -La CIA parece estar interesada en el SPANK +[LOVE4_H] +hasta que yo intervine a través de mi fortuna. -[RM6_C1] -y no les gusta que nos metamos con el cártel. +[LOVE4_E] +Cruza el puente hacia Shoreside Vale y ve al Aeropuerto Internacional Francis. -[RM6_D] -Soy hombre muerto, así que tengo que largarme. +[GTAB_A] +Oye, saquemos esto de aquí. Dios sabrá lo que será, -[RM6_E] -¡Consigue que no pierda mi vuelo en el aeropuerto y haré que tu trabajo haya merecido la pena! +[GTAB_B] +pero él lo quiere a toda costa, así que tendrá algún valor. -{ Cutscene, appears when Ray has been taken safely to the airport } +[GTAB_C] +¡¿Qué diablos?! -[RM6_1] -Esta llave es de un almacén. +[GTAB_D] +¡TÚ! -[RM6_2] -Encontrarás dinero en metálico y ''suministros'' que guardé por si las cosas se ponían feas. +[GTAB_E] +¡Tranquilo, amigo! ¡No es nada! ¡No es nada! -[RM6_3] -Hasta la vista. +[GTAB_F] +¡Te dejé desangrándote entre la basura! -{ Pager message that appears when reaching Ray's lockup } +[GTAB_G] +No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. -[RM6_666] -Cuida mi Patriot a prueba de balas. Nos vemos en Miami, Ray +[GTAB_H] +¡No seas cagón! -{ Mission instructions } +[GTAB_I] +¡No tenemos elección, nena! -[RM6_4] -~g~Ve al almacén a por el cargamento de Ray. +[GTAB_J] +¡Siempre la hay, imbécil! -[RM6_5] -~g~La CIA vigila el puente, busca otro camino. +[GTAB_K] +¡Siento mucho lo de esa perra enloquecida, todas son iguales... ¿Por favor? -[RM6_6] -~r~¡Ray ha muerto! +[GTAB_L] +Así que la zorra se fue. -[RM6_7] -~r~¡Ray ha perdido su avión! +[GTAB_M] +Pero me has hecho un favor, -[RM6_8] -~g~Has abandonado a Ray, vuelve a por él. +[GTAB_N] +no eres el único que tiene una cuenta pendiente con el cártel... -{ ==================================================================== } -{ ================= MISSION: LIBERATOR (DONALD LOVE) ================= } -{ ==================================================================== } +[GTAB_O] +¡Este gusano mató a mi hermano! -{ TITLE } +[GTAB_P] +¡Nunca maté a ningún yakuza! -[LOVE1] -'EL LIBERADOR' +[GTAB_Q] +¡Mientes! Todos vimos al asesino del cártel. -{ Premission cutscene } +[GTAB_R] +¡Vamos a cazaros y a mataros a todos, perros colombianos! -{ Donald Love } +[GTAB_S] +Me trabajaré a nuestro querido amigo para extraerle información y un poco de placer. -[LOVE1_A] -Antes que nada, permíteme agradecerte que te hayas ocupado de ese asunto personal. +[GTAB_T] +Tú, ven más tarde, estoy segura de que voy a necesitar tus servicios. -[LOVE1_F] -Últimamente la gente tiende a malinterpretar las cosas. +[GTAB_U] +¡Por favor, amigo! ¡No me dejes con ella, esa chica está loca! ¿Amigo? ¡Oye, amigo! ¡Amigo...! -[LOVE1_B] -La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, +[LOVE5_A] +Estás demostrando ser una inversión segura, algo muy raro en estos días. -[LOVE1_H] -pero los grupos de hombres se vuelven codiciosos. +[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_C] -Un activo valioso, un anciano oriental que conozco, +[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_I] -está siendo retenido por unos sudamericanos en Aspatria. +[FM1_Q1] +¿Quieres un poco de diversión? ¿Un poco de... hmmm, de SPANK? -[LOVE1_D] -Pretenden exigirme más de lo pactado, pero no me gusta renegociar. +[FM1_R] +Hola, Chico. No, solo lo de siempre. -[LOVE1_E] -Un trato es un trato, así que no van a ver ni un dólar mío. +[FM1_T] +Gracias, Chico, nos vemos. -[LOVE1_G] -Rescata a mi amigo cueste lo que cueste. +[FM1_W] +Oye, tú, espera aquí y quédate pendiente del coche mientras yo voy a menear el esqueleto, ¿vale? -{ Mission instructions } +[FM1_X] +¡Vale, tú, salgamos de aquí! ¡Uaaah! -[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_Q] +¡Ay, mira, es mi chica favorita! -[LOVE1_2] -~g~Rescata al anciano oriental. +[FM1_S1] +Ey, deberías echar un vistazo a la fiesta del almacén en el lado este del muelle Atlantic. -[LOVE1_3] -~g~Lleva al anciano oriental de vuelta al edificio de Donald Love. +[FM1_U] +Gracias y disfruta. Es buen material. -[LOVE1_4] -~g~El anciano oriental debe estar detrás de alguna de estas puertas... +[FM1_V] +¡Venga, tú, vamos a ver esa fiesta! -[LOVE1_5] -~g~Deja de perder el tiempo, hazte con un coche de los colombianos y rescata al socio de Love. +[FM1_SS] +~r~ESCÁNER: ~g~Cuatro-cinco a todas las unidades: asistan redada de narcóticos en el muelle Atlantic. -[LOVE1_6] -~r~¡Las tripas del anciano oriental están desparramadas por las calles! +[LOVE6_B] +aun sin conocer su verdadera valía. -[LOVE1_7] -~g~La puerta sólo se abrirá ante un coche de los colombianos. +[TM3_A1] +~r~¡Joey está frito! -{ =============================================================================== } -{ ================= MISSION: WAKA-GASHIRA WIPEOUT (DONALD LOVE) ================= } -{ =============================================================================== } +[TM3_A2] +~r~¡Joey y Luigi han sido incinerados! -{ TITLE } +[TM3_A3] +~r~¡Joey, Luigi y Toni están calcinados! -[LOVE2] -'¡EXTERMINA AL WAKA-GASHIRA!' - -{ Premission cutscene } +[FM4_2] +Mira, Salvatore cree que se la estamos jugando, -{ Donald Love } +[FM4_3] +así que te vendió al cártel para llegar a un trato. -[LOVE2_A] -No hay nada como una clásica guerra de bandas para hacer que bajen los precios de las viviendas, +[FM4_4] +No podía permitírselo, o sea, lo peor es... -[LOVE2_B] -excepto una plaga... pero eso sería excesivo en este caso. +[FM4_4B] +que yo tengo la culpa, porque le dije que somos pareja. -[LOVE2_C] -He observado que la yakuza y los colombianos no son precisamente buenos amigos. +[FM4_5] +¡No me preguntes por qué, no lo sé! -[LOVE2_D] -Vamos a aprovechar esta oportunidad de negocio. +[FM4_6] +Mira, la mafia te quiere muerto y yo también tengo que salir de aquí. -[LOVE2_E] -Quiero que mates a Kenji Kasen, el waka-gashira (segundo al mando) de la yakuza. +[FM4_6B] +¡He visto demasiados asesinatos, demasiada sangre! -[LOVE2_F] -Kenji está asistiendo a una reunión en lo alto del aparcamiento de Newport. +[FM4_7] +Es una amiga mía, ¿vale?, una vieja amiga... Es Asuka, es de fiar. -[LOVE2_G] -¡Hazte con un coche de la banda del cártel y elimínalo! +[FM4_8] +Vamos, dejémonos de discursos. -[LOVE2_H] -La yakuza debe culpar al cártel de esta declaración de guerra. +[FM4_9] +Mejor nos vamos antes de que haya más italianos histéricos con intenciones menos amistosas. -{ Mission instructions } +[CRED001] +ROCKSTAR STUDIOS -[LOVE2_1] -~g~¡Ve a Fort Staunton y roba un coche de la banda de los colombianos! +[CRED002] +PRODUCTOR -[LOVE2_2] -~g~¡Ahora ve al ~p~aparcamiento de Newport~g~ y cárgate a Kenji! +[CRED003] +LESLIE BENZIES -[LOVE2_3] -~r~¡Si no llevas un coche del cártel, te descubrirán! +[CRED004] +DIRECTOR DE ARTE -[LOVE2_4] -~r~¡La yakuza te ha reconocido! +[CRED005] +AARON GARBUT -[LOVE2_5] -~g~¡Kenji ha palmado! ¡Sal de Newport y deshazte del coche! +[CRED006] +DIRECCIÓN TÉCNICA -[LOVE2_6] -~r~¡Has matado a todos los testigos! +[CRED007] +OBBE VERMEIJ -[LOVE2_7] -~g~¡Ahora deshazte del coche! +[CRED008] +ADAM FOWLER -[LOVE2_8] -~g~¡Sal de Newport! +[CRED009] +DISEÑO -{ ============================================================================== } -{ ================= MISSION: A DROP IN THE OCEAN (DONALD LOVE) ================= } -{ ============================================================================== } +[CRED010] +CRAIG FILSHIE -{ TITLE } +[CRED011] +WILLIAM MILLS -[LOVE3] -'UNA GOTA EN EL OCÉANO' +[CRED012] +CHRIS ROTHWELL -{ Premission cutscene } +[CRED013] +JAMES WORRALL -{ Donald Love } +[CRED014] +GUIÓN -[LOVE3_A] -En estos días de hipocresía moral, ciertos artículos pueden resultar difíciles de importar. +[CRED015] +JAMES WORRALL -[LOVE3_B] -Esta noche, durante su aproximación al aeropuerto, una avioneta sobrevolará la bahía. +[CRED016] +PAUL KUROWSKI -[LOVE3_C] -Echará varios paquetes al agua. +[CRED017] +DAN HOUSER -[LOVE3_D] -Asegúrate de los consigues antes que nadie. +[CRED018] +PERSONAJES -{ Mission instructions } +[CRED019] +IAN MCQUE -[LOVE3_1] -~g~¡Consigue una ~r~lancha~g~ y sigue a la ~y~avioneta~g~! +[CRED020] +ANIMACIÓN Y DIRECCIÓN -[LOVE3_2] -~g~¡Tienes todos los paquetes! Llévaselos a Donald Love. +[CRED021] +ALEX HORTON -[LOVE3_3] -~g~La avioneta ha tirado ~1~ de los 6 paquetes. +[CRED022] +LEE MONTGOMERY -[LOVE3_4] -~r~¡Has destruido el avión! +[CRED023] +AUTO DESIGN -[LOVE3_5] -~g~La avioneta está ahora a tu alcance. +[CRED024] +PAUL KUROWSKI -[LOVE3_6] -~r~¡La bofia ha llegado a los paquetes antes que tú! +[CRED025] +ARTISTAS -{ =========================================================================== } -{ ================= MISSION: GRAND THEFT AERO (DONALD LOVE) ================= } -{ =========================================================================== } +[CRED026] +KEIRAN BAILLIE -{ TITLE } +[CRED027] +ADAM COCHRANE -[LOVE4] -'ROBO DE ALTOS VUELOS' +[CRED028] +GARY MCADAM -{ Premission cutscene } +[CRED029] +MICHAEL PIRSO -{ Donald Love } +[CRED030] +ANDREW SOOSAY -[LOVE4_A] -Gracias por conseguir esos paquetes, pero sólo eran un señuelo. +[CRED031] +ALISDAIR WOOD -[LOVE4_B] -Lo siento, pero a veces los negocios son así. +[CRED032] +PROGRAMADORES -[LOVE4_C] -Mi verdadero objetivo se ocultaba en la avioneta. +[CRED033] +ALAN CAMPBELL -[LOVE4_D] -Desgraciadamente, las autoridades aduaneras registraron la avioneta y la comenzaron a desmontar +[CRED034] +MARK HANLON -[LOVE4_H] -hasta que yo intervine a través de mi fortuna. +[CRED035] +ANDRZEJ MADAJCZYK -[LOVE4_E] -Cruza el puente hacia Shoreside Vale y ve al Aeropuerto Internacional Francis. +[CRED036] +ALEXANDER ROGER -[LOVE4_F] -He sobornado a los funcionarios. +[CRED037] +GRAEME WILLIAMSON -[LOVE4_G] -Mis pertenencias estarán esperándote en el hangar de aduanas, dentro de la avioneta. +[CRED038] +MÚSICA -{ Cutscene, when going up into the construction area's elevator, finding Catalina, Miguel and Asuka } +[CRED039] +CRAIG CONNER -{ Catalina, colombiana } +[CRED040] +STUART ROSS -[GTAB_A] -Oye, saquemos esto de aquí. Dios sabrá lo que será, +[CRED041] +DISEÑO DE SONIDO Y MASTERIZADO -[GTAB_B] -pero él lo quiere a toda costa, así que tendrá algún valor. +[CRED042] +ALLAN WALKER -{ Miguel, colombiano } +[CRED043] +PROGRAMACIÓN DE AUDIO -[GTAB_C] -¡¿Qué diablos?! +[CRED044] +RAYMOND USHER -{ Catalina, colombiana } +[CRED045] +DIRECTOR DE PRUEBAS -[GTAB_D] -¡TÚ! +[CRED046] +CRAIG ARBUTHNOTT -{ Miguel, colombiano } +[CRED047] +JEFES DE PRUEBAS -[GTAB_E] -¡Tranquilo, amigo! ¡No es nada! ¡No es nada! +[CRED048] +ANDY DUTHIE -{ Catalina, colombiana } +[CRED049] +JOHN HAIME -[GTAB_F] -¡Te dejé desangrándote entre la basura! +[CRED050] +NEIL CORBETT -{ Miguel, colombiano } +[CRD050A] +PROBADORES -[GTAB_G] -No dispares, amigo. No hay problema. Somos amigos. Mira, coge esto. +[CRED051] +GRAEME JENNINGS -{ Catalina, colombiana } +[CRED052] +DAVID MURDOCH -[GTAB_H] -¡No seas cagón! +[CRED053] +DAVID BEDDOES -{ Miguel, colombiano } +[CRED054] +EDWIN SMITH -[GTAB_I] -¡No tenemos elección, nena! +[CRED055] +MARK FLETT -{ Catalina, colombiana } +[CRED056] +MICHAEL SUTHERLAND -[GTAB_J] -¡Siempre la hay, imbécil! +[CRED057] +SOPORTE TÉCNICO -{ Miguel, colombiano } +[CRED058] +LORRAINE ROY -[GTAB_K] -¡Siento mucho lo de esa perra enloquecida, todas son iguales... ¿Por favor? +[CRED059] +CHRISTINE CHALMERS -{ Asuka } +[CRED060] +ROCKSTAR -[GTAB_L] -Así que la zorra se fue. +[CRED061] +PRODUCTOR EJECUTIVO -[GTAB_M] -Pero me has hecho un favor, +[CRED062] +SAM HOUSER -[GTAB_N] -no eres el único que tiene una cuenta pendiente con el cártel... +[CRED063] +PRODUCTOR -[GTAB_O] -¡Este gusano mató a mi hermano! +[CRED064] +DAN HOUSER -{ Miguel, colombiano } +[CRED065] +DIRECTOR DE DESARROLLO -[GTAB_P] -¡Nunca maté a ningún yakuza! +[CRED066] +JAMIE KING -{ Asuka } +[CRED067] +PRODUCTOR TÉCNICO -[GTAB_Q] -¡Mientes! Todos vimos al asesino del cártel. +[CRED068] +GARY J. FOREMAN -[GTAB_R] -¡Vamos a cazaros y a mataros a todos, perros colombianos! +[CRED069] +PRODUCTOR ASOCIADO -[GTAB_S] -Me trabajaré a nuestro querido amigo para extraerle información y un poco de placer. +[CRED070] +JEREMY POPE -[GTAB_T] -Tú, ven más tarde, estoy segura de que voy a necesitar tus servicios. +[CRED071] +SUPERVISOR MUSICAL -{ Miguel, colombiano } +[CRED072] +TERRY DONOVAN -[GTAB_U] -¡Por favor, amigo! ¡No me dejes con ella, esa chica está loca! ¿Amigo? ¡Oye, amigo! ¡Amigo...! +[CRED073] +EQUIPO DE PRODUCCIÓN DE ROCKSTAR -{ Mission instructions } +[CRED074] +TERRY DONOVAN -[LOVE4_1] -~r~¡El cártel colombiano está aquí! +[CRED075] +JENNIFER KOLBE -[LOVE4_2] -~g~¡El paquete ha desparecido! Síguele la pista a los colombianos y recupéralo. +[CRED076] +JENEFER GROSS -[LOVE4_3] -~g~¿''Panlantic Construction''...? +[CRED077] +LAURA PATERSON -[LOVE4_7] -~g~Hay una zona en obras en Staunton Island, puede que hayan llevado el paquete allí. +[CRED078] +JEFF CASTANEDA -[LOVE4_4] -~g~¡Lleva el paquete a Donald Love! +[CRED079] +CHRIS CARRO -[LOVE4_5] -~g~El paquete debería estar en la avioneta... +[CRED080] +ADAM TEDMAN -[LOVE4_6] -~g~¡Usa el ascensor! +[CRED081] +JUNG KWAK -[LOVE4_8] -~g~Necesitarás un coche para abrir el garaje. +[CRED082] +BRIAN WOOD -[LOVE4_9] -~r~¡El avión ha sido destruido! +[CRED083] +PAUL YEATES -[LOV4_10] -~r~¡La única pista sobre dónde se encuentra el paquete ha sido destruida! +[CRED084] +STANTON SARJEANT -{ ========================================================================= } -{ ================= MISSION: ESCORT SERVICE (DONALD LOVE) ================= } -{ ========================================================================= } +[CRED085] +VICEPRESIDENTE DE MÁRKETING -{ TITLE } +[CRED086] +TERRY DONOVAN -[LOVE5] -'SERVICIO DE ESCOLTA' +[CRED087] +COORDINADOR TÉCNICO -{ Premission cutscene } +[CRED088] +BRANDON ROSE -{ Donald Love } +[CRED089] +DIRECTOR DE C.C. -[LOVE5_A] -Estás demostrando ser una inversión segura, algo muy raro en estos días. +[CRED090] +JEFF ROSA -[LOVE5_B] -Mi amigo oriental necesitará que le escolten mientras comprueba la autenticidad de mi última adquisición. +[CRED091] +JEFE DE ANÁLISIS -[LOVE5_C] -Quiero que le sigas, asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. +[CRED092] +ADAM DAVIDSON -{ Mission instructions } +[CRED093] +ANALISTA DEL JUEGO -[LOVE5_1] -~g~¡En marcha! +[CRED094] +RICHARD HUIE -[LOVE5_2] -~g~¡Vas a necesitar un coche! +[CRED095] +EQUIPO DE PRUEBAS -[LOVE5_3] -~g~¡Comprueba la salida del túnel! +[CRED096] +LANCE WILLIAMS -[LOVE5_4] -~r~¡Protege el camión! +[CRED097] +JOE GREENE -[LOVE5_5] -~r~¡No has protegido al camión! +[CRED098] +BRIAN PLANER -{ ================================================================ } -{ ================= MISSION: DECOY (DONALD LOVE) ================= } -{ ================================================================ } +[CRED099] +OSWALD GREENE -{ TITLE } +[CRED100] +EDITORIAL DEL LIBERTY TREE -[LOVE6] -'SEÑUELO' +[CRED101] +JAMES WORRALL -{ Premission cutscene } +[CRED102] +DAN HOUSER -{ Donald Love } +[CRED103] +ADAM TEDMAN -[LOVE6_A] -Una lección sobre negocios, amigo mío: +[CRED104] +PAUL YEATES -[LOVE6_E] -Si tienes una mercancía única, todo el mundo tratará de arrebatártela, +[CRED105] +JENEFER GROSS -[LOVE6_B] -aun sin conocer su verdadera valía. +[CRED106] +LAURA PATERSON -[LOVE6_C] -Unos SWAT han acordonado la zona donde se encuentran mi socio y el paquete. +[CRED107] +CINEMÁTICAS -[LOVE6_D] -Ve allí, recoge la furgoneta y haz de señuelo. +[CRED108] +GUIÓN DE DAN HOUSER Y JAMES WORRALL -[LOVE6_F] -Mantenles ocupados y él podrá escaparse. +[CRED109] +AUDIO DIRIGIDO POR DAN HOUSER -{ Mission instructions } +[CRED110] +AUDIO PRODUCIDO POR RENAUD SEBBANE -[LOVE6_1] -~g~¡Ahora llévate a los policías lejos del almacén! +[CRED111] +REPARTO -[LOVE6_2] -~r~¡No has distraído a la policía! +[CRED112] +FRANK VINCENT COMO SALVATORE LEONE -[LOVE6_3] -~g~Tienes ~1~ segundos para volver al Securicar antes de fracasar la misión. +[CRED113] +JOE PANTOLIANO COMO LUIGI GOTERELLI -[LOVE6_4] -~r~¡Has abandonado el Securicar señuelo! +[CRED114] +MICHAEL MADSEN COMO TONI CIPRIANI -{ =============================================================================== } -{ ================= MISSION: LOVE'S DISAPPEARANCE (DONALD LOVE) ================= } -{ =============================================================================== } +[CRED115] +MICHAEL RAPAPORT COMO JOEY LEONE -{ TITLE } +[CRED116] +DEBBI MAZAR COMO MARÍA -[LOVE7] -'LA DESAPARICIÓN DE LOVE' +[CRED117] +KYLE MACLACHAN COMO DONALD LOVE -{ No dialogue or strings } +[CRED118] +ROBERT LOGGIA COMO RAY MACHOWSKI -{ ============================================================== } -{ ================= MISSION: UZI MONEY (D-ICE) ================= } -{ ============================================================== } +[CRED119] +GURU COMO 8-BALL -{ TITLE } +[CRED120] +SONDRA JAMES COMO MAMMA -[HM_1] -'PASADA AMETRALLADA' +[CRED121] +LIANA PAI COMO ASUKA -{ Pager message that tells the player that D-Ice's missions are now available } +[CRED122] +LES MAU COMO KENJI -[HOOD1_A] -Ve al teléfono público de Wichita Gardens y hablaremos de negocios. +[CRED123] +CYNTHIA FARRELL COMO CATALINA -{ Premission cutscene } +[CRED124] +AL ESPINOSA COMO MIGUEL -{ D-Ice } +[CRED125] +CHRIS PHILLIPS COMO EL BURRO -[HM1_A] -¡Ey! ¡Soy D-Ice, de los Red Jacks! +[CRED126] +HUNTER PLATIN COMO CHICO -[HM1_B] -Tengo un problema, me la están liando. +[CRED127] +WALTER MUDU COMO D-ICE -[HM1_C] -Hay unos macarrillas en la calle que no piensan más que en pistolas y en SPANK. +[CRED128] +CURTIS MCCLARIN COMO CURTLY -[HM1_D] -Se llaman ''Nines'', van de púrpura, y cada día en el que se hacen notar +[CRED129] +BILL FIORE COMO DARKEL -[HM1_G] -es otro día más que los Jacks parecemos blandos. +[CRED130] +CHRIS PHILLIPS COMO MARTY CHONKS -[HM1_E] -Quiero que esos mierdecillas sepan lo que es un verdadero tiroteo desde un vehículo. +[CRED131] +HUNTER PLATIN COMO CURLY BOB -[HM1_H] -¡Haz que esos Nines se larguen! +[CRED132] +WALTER MUDU COMO KING COURTNEY -[HM1_F] -Pero ojo, también habrá Jacks que se creerán que vas a por ellos. +[CRED133] +HUNTER PLATIN COMO ONE-ARMED PHIL -{ Mission instructions } +[CRED134] +KIM GURNEY COMO MISTY -[HM1_1] -~g~Cepíllate a 20 Purple Nines en 2 minutos y 30 segundos. +[CRED135] +CAPTURA DE MOVIMIENTOS -[HM1_2] -~g~Hazte con un vehículo y recuerda que sólo cuentan las muertes a tiros desde el coche. +[CRED136] +ANIMACIÓN -[HM1_3] -~g~Los Nines tienen su territorio en Wichita Gardens. +[CRD136A] +ALEX HORTON -{ =============================================================== } -{ ================= MISSION: TOYMINATOR (D-ICE) ================= } -{ =============================================================== } +[CRED137] +DIRECCIÓN -{ TITLE } +[CRD137A] +NAVID KHONSARI -[HM_2] -'BOMBINATOR' +[CRED138] +PRODUCCIÓN -{ Premission cutscene } +[CRD138A] +JAMIE KING -{ D-Ice } +[CRD138B] +RENAUD SEBBANE -[HM2_A] -Los Nines me están presionando. - -[HM2_B] -Tienen coches blindados y ahora están traficando SPANK +[CRED139] +GRABADA EN MODERN UPRISING STUDIOS, BROOKLYN -[HM2_C] -a los hermanos sin ningún pudor. +[CRED140] +ACTORES -[HM2_D] -Hay un coche aparcado en la calle. +[CRD140A] +RENAUD SEBBANE -[HM2_E] -Dentro verás algo que te servirá para poner a esos gallinas en su sitio +[CRD140B] +GISELLE JONES -[HM2_F] -y cargarte sus blindados. +[CRD140C] +STEPHEN DANIELS -{ Mission instructions } +[CRD140D] +ROBERT STIO -[HM2_1] -Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. +[CRD140E] +JENNY GROSS -[HM2_1A] -Usa los coches teledirigidos para destruir los furgones blindados. Pulsa el ~h~botón ~k~~PED_FIREWEAPON~ ~w~para detonarlos. +[CRED141] +DIÁLOGO DE PEATONES -[HM2_2] -~r~¡No has destruido todos los furgones blindados! +[CRED142] +ESCRITO POR DAN HOUSER, NAVID KHONSARI Y JAMES WORRALL -[HM2_6] -~g~¡Te has cargado un furgón blindado! +[CRED143] +DIRIGIDO POR CRAIG CONNER, DAN HOUSER Y LAZLOW -[HM2_3] -¡Si golpeas las ruedas de un vehículo, el coche teledirigido estallará! +[CRED144] +PRODUCIDO POR RENAUD SEBBANE -[HM2_4] -¡Si el coche teledirigido se sale fuera de cobertura, estallará solo! +[CRED145] +REPARTO -[HM2_5] -~r~¡Te has ido de cobertura! +[CRED146] +HUNTER PLATIN -{ =================================================================== } -{ ================= MISSION: RIGGED TO BLOW (D-ICE) ================= } -{ =================================================================== } +[CRED147] +DAN HOUSER -{ TITLE } +[CRED148] +RENAUD SEBBANE -[HM_3] -'PREPARADO PARA ESTALLAR' +[CRED149] +MARIA CHAMBERS -{ Premission cutscene } +[CRED150] +JEFF STANTON -{ D-Ice } +[CRED151] +RYAN CROY -[HM3_A] -Algún cazurro me ha puesto una bomba en el coche. +[CRED152] +DEENA BERMAN -[HM3_B] -Si lo pierdo, mi reputación en la calle se irá a la porra. +[CRED153] +MARIA CHAMBERS -[HM3_C] -Coge mi coche y llévalo al taller de Saint Mark's, ¿valiendo? +[CRED154] +ALICE B. SALTZMAN -[HM3_D] -Que se encarguen ellos de desarmar la bomba. +[CRED155] +ALEX ANTHONY SIOUKAS -[HM3_E] -El tiempo avanza y ese trasto es un peligro. +[CRED156] +SEAN R. LYNCH -[HM3_F] -Un golpe más de la cuenta y podría saltar por los aires. +[CRED157] +AMY SALZMAN -[HM3_G] -¡Tira! +[CRED158] +COLIN MCSHANE -{ Mission instructions } +[CRED159] +COREY WADE -[HM3_1] -~g~¡Ve al garaje, pero pon atención, porque el coche explotará si se daña demasiado! +[CRED160] +GERALD COSGROVE -[HM3_2] -~g~Lleva el coche de vuelta. ¡Tiene que estar inmaculado! +[CRED161] +STEPHANIE ROY -[HM3_3] -~g~¡Haz que reparen el vehículo! +[CRED162] +DORIS WOO -{ ================================================================ } -{ ================= MISSION: BULLION RUN (D-ICE) ================= } -{ ================================================================ } +[CRED163] +JOSEPH GREENE -{ TITLE } +[CRED164] +LAZLOW JONES -[HM_4] -'FIEBRE DEL PLATINO' +[CRED165] +HSIANG LIN -{ Premission cutscene } +[CRED166] +STEVE MICHAEL ROBERT -{ D-Ice } +[CRED167] +MATHEW MURRAY -[HM4_A] -Tío, un vuelo de la Reserva Federal se la acaba de pegar en el Aeropuerto Francis. +[CRED168] +RICHARD HUIE -[HM4_B] -Hay platino por toda la pista. +[CRED169] +GARVIN ATWELL -[HM4_C] -Consigue un coche y agarra todo lo que puedas. +[CRED170] +STEVE KNEZEVICH -[HM4_F] -Puedes dejar la mercancía en uno de mis garajes. +[CRED171] +YUKIMURA SATO -[HM4_G] -El platino pesa un huevo y hará que tu buga vaya a paso de tortuga, +[CRED172] +FRANK CHAVEZ -[HM4_H] -así que ve dejándolo de vez en cuando en el garaje. +[CRED173] +LIEZL JACINTO -{ Mission instructions } +[CRED174] +CANAAN MCKOY -[HM4_D] -~g~¡Hazte con un vehículo! +[CRED175] +ADAM DAVIDSON -[HM4_1] -~g~Dirígete al lugar donde está el cargamento. Necesitas conseguir 30 lingotes. +[CRED176] +LANCE WILLIAMS -[HM4_2] -~g~Recuerda: cuando el vehículo esté pesado y vaya más despacio, ve al garaje y deja el cargamento. +[CRED177] +NEIL MCCAFFREY -[HM4_E] -UNUSED +[CRED178] +LAURA PATERSON -{ =========================================================== } -{ ================= MISSION: RUMBLE (D-ICE) ================= } -{ =========================================================== } +[CRED179] +REY CONCEPCION -{ TITLE } +[CRED180] +CHARLES HEROLD -[HM_5] -'ENFRENTAMIENTO' +[CRED181] +ANDREW GREENWALD -{ Premission cutscene } +[CRED182] +JAMES MIELKE -{ D-Ice } +[CRED183] +PETER SUCIU -[HM5_A] -Ya solo quedan unos pocos Nines, +[CRED184] +ALEX ODULIO -[HM5_B] -pero todavía quieren guerra. +[CRED185] +DON NKRUMAH -[HM5_C] -Han aceptado un mano a mano. +[CRED186] +KENDALL PITTMAN -[HM5_D] -Un puñado de los suyos contra dos de los nuestros, +[CRED187] +SAL SUAZO -[HM5_E] -o más bien, tú y uno más. +[CRED188] +EREK MATEO -[HM5_F] -Os ayudaría, pero... +[CRED189] +CHRIS DIFATE -[HM5_G] -No quiero jugarme mi libertad condicional, +[CRED190] +LEILA MILTON -[HM5_H] -¿me captas? +[CRED191] +DARREN ZOLTOWSKI -[HM5_I] -Reúnete con mi hermano pequeño, +[CRED192] +VIRGINIA SMITH -[HM5_J] -él te enseñará dónde será la pelea. +[CRED193] +KEVIN CASSIN -{ D-Ice's brother, when the player finds him } +[CRED194] +JASON SHIGEMORI -[HM5_1] -Hola, Ice dijo que vendrías. Las reglas son sólo bates. Cero armas, cero coches. +[CRED195] +KELLY KINSELLA -[HM5_5] -Es una batalla por respeto, ¿vale? +[CRED196] +MOLLIE STICKNEY -[HM5_6] -Vamos a partir cabezas... +[CRED197] +STANTON SARJEANT -{ Mission instructions } +[CRED198] +LAURA WALSH -[HM5_3] -~r~¡Te han dicho que uses sólo un bate de béisbol! +[CRED199] +MARK GARONE -[HM5_4] -~r~¡Tu contacto está muerto! +[CRED200] +JOANNA SLY -{ ============================================================================= } -{ ================= MISSION: BAIT (ASUKA KASEN, SECOND BATCH) ================= } -{ ============================================================================= } +[CRED201] +ELIZABETH HOWELL -{ TITLE } +[CRED202] +ANA HERCULES -[AS1] -'CEBO' +[CRED203] +SHIRLEY IRICK -{ Premission cutscene } +[CRED204] +KASHONA FIELDS -{ Asuka } +[CRED205] +JOEL M. LILJE -[AS1_A] -Parece que Miguel piensa que le maltrato. +[CRED206] +JOHN DIBENEDETTO -[AS1_B] -Pero ha revelado cuánto teme Catalina tu búsqueda de venganza. +[CRED207] +NANCY GILES -[AS1_C] -Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty con el único fin de darte caza. +[CRED208] +RYAN CROY -[AS1_D] -Haz de cebo y consigue que los escuadrones te sigan hasta Pike Creek, +[CRED209] +JENNIFER KOLBE -[AS1_E] -donde estarán esperando algunos de mis hombres. +[CRED210] +LIAM BURKE -{ Mission instructions } +[CRED211] +SIGRID PREISSL -[AS1_G] -~r~¡Todos los yakuza están muertos! +[CRED212] +ANITA FITZSIMONS -[AS1_H] -~r~¡No has llevado al escuadrón de la muerte hasta la trampa de la yakuza! +[CRED213] +PHILIPPA RASELLI -{ ======================================================================================= } -{ ================= MISSION: EXPRESSO-2-GO! (ASUKA KASEN, SECOND BATCH) ================= } -{ ======================================================================================= } +[CRED214] +WIL QUESNEL -{ TITLE } +[CRED215] +FALKO BURKERT -[AS2] -'CAFÉ PARA LLEVAR' +[CRED216] +SARA SEWELL -{ Premission cutscene } +[CRED217] +EMISORAS DE RADIO Y MÚSICA -{ Asuka } +[CRED218] +PRODUCTORES DE ROCKSTAR REINO UNIDO -[AS2_A1] -¡Está claro que Miguel tiene esa famosa resistencia latina! +[CRD218A] +CRAIG CONNER -[AS2_A2] -Estoy agotada. +[CRD218B] +STUART ROSS -[AS2_A] -Subestimamos los planes que tiene Catalina para el SPANK. +[CRED219] +COORDINADOR DE BANDA SONORA -[AS2_B] -Va mucho más allá de hacer que los jamaicanos lo vendan en las esquinas. +[CRED220] +TERRY DONOVAN -[AS2_C] -El cártel tiene una tapadera, el Kappa Coffee House. +[CRED221] +PRODUCTOR DE ROCKSTAR GAMES -[AS2_D] -Vende SPANK en puestos callejeros. +[CRED222] +DAN HOUSER -[AS2_E] -No tenemos otra opción más que sabotear esos puntos de venta. +[CRED223] +EDICIÓN -[AS2_F] -¡Redúcelos a cenizas! +[CRED224] +CRAIG CONNER -{ Mission instructions } +[CRED225] +ALLAN WALKER -[AS2_1] -~g~¡Todos los puestos de café en Portland han sido destruidos! +[CRED226] +LAZLOW -[AS2_2] -~g~¡Todos los puestos de café en Staunton Island han sido destruidos! +[CRED227] +GUIÓN DE LOCUTORES Y ANUNCIOS -[AS2_3] -~g~¡Todos los puestos de café en Shoreside Vale han sido destruidos! +[CRED228] +DAN HOUSER -[AS2_4] -~r~¡El cártel ha avisado a sus camellos! +[CRED229] +LAZLOW -[AS2_5] -~g~¡Todavía hay puestos de café en Shoreside Vale y en Staunton Island! +[CRED230] +AGRADECIMIENTOS ESPECIALES -[AS2_6] -~g~¡Todavía hay puestos de café en Shoreside Vale! +[CRED231] +ADAM TEDMAN -[AS2_7] -~g~¡Todavía hay puestos de café en Staunton Island! +[CRED232] +ALEX MASON -[AS2_8] -~g~¡Todavía hay puestos de café en Portland! +[CRED233] +JUDY HENDERSON CASTING -[AS2_9] -~g~¡Todavía hay puestos de café en Portland y en Shoreside Vale! +[CRED234] +HAMISH BROWN -[AS2_10] -~g~¡Todavía hay puestos de café en Portland y en Staunton Island! +[CRED235] +CHRISSY HOBAN -[AS2_11] -~g~¡~1~ DE 9! +[CRED236] +INNES RICARD -[AS2_12] -~g~¡Recorre los distritos de Liberty y busca puestos de café ~b~Espresso-2-Go~g~! +[CRED237] +LILION BROZSKA -[AS2_12A] -~g~Cuando destruyas el primer puesto, ¡tendrás 8 mintutos antes que el cártel avise a sus camellos! +[CRED238] +BOB HILLARY -{ =============================================================================== } -{ ================= MISSION: S.A.M. (ASUKA KASEN, SECOND BATCH) ================= } -{ =============================================================================== } +[CRED239] +EMILY ANDERSON -{ TITLE } +[CRED240] +RICHIE HENDERSON -[AS3] -'TIERRA-AIRE' +[CRED241] +CHRISTIAN CANTAMESSA -{ Premission cutscene } +[CRED242] +JERONIMO BARRERA -{ Maria } +[CRED243] +ALEXANDER ILLES -[AS3_A] -¿Lo apretamos un poco más o esperamos a que se vuelva negro y se caiga? +[CRED244] +BARANE CHAN -{ Asuka } +[CRED245] +DUNCAN SHIELDS -[AS3_B] -Dale un toque rápido... +[CRED246] +BARANE CHAN -{ Maria } +[CRED247] +DEREK PAYNE -[AS3_C] -¡Buaj! ¿Qué es esa cosa amarilla pegajosa? +[CRED248] +KEVIN WONG -[AS3_C1] -¡Hola, guapo! +[CRED249] +ROSS ELLIOTT -{ Asuka } +[CRED250] +ROSS BEAZLEY -[AS3_D] -¡Mi manitas! +[CRED251] +ALEX BAZLINTON -{ Maria } +[CRED252] +DAVE WATSON -[AS3_E] -Me aburría, así que vine a hacerle compañía a Asuka. +[CRED253] +MALCOLM SMITH -{ Asuka } +[CRED255] +ANDREW SEMPLE -[AS3_F] -Esta chica tiene un talento nato para la tortura. +[CRED256] +ARTISTAS -[AS3_F1] -Se las ha arreglado para extraerle esta joyita a nuestro invitado. +[CRED257] +STUART PETRI -[AS3_G] -Hay una avioneta que llegará al Aeropuerto Francis en dos horas. +[CRED258] +JERONIMO BARRERA -[AS3_G1] -Está lleno del veneno de Catalina. +[CRED259] +CARLY SLATER -[AS3_H] -Podrás evitar la seguridad del aeropuerto si conduces una lancha hasta las boyas luminosas, +[CRED260] +GREG LAU -[AS3_H1] -así podrás disparar a la avioneta al aterrizar. +[CRED261] +STEVE KNEZEVICH -[AS3_I] -¡Recoge el cargamento de entre los escombros y tráelo! +[CRED262] +DEVIN WINTERBOTTOM -{ Maria } +[CRED263] +JAMEEL VEGA -[AS3_J] -Ten cuidado, guapo, ¿vale? +[CRED264] +LEE CUMMINGS -{ Asuka } +[CRED265] +DEVIN BENNET -[AS3_K] -Ahora prueba con el aceite picante... +[CRED266] +ELIZABETH SATTERWHITE -{ Mission instructions } +[CRED267] +AARON RIGBY -[AS3_1] -~g~¡Busca una ~r~lancha~g~ y ve a la ~b~boya señalada! +[CRED268] +STEVE K. -[AS3_1A] -~g~¡Ahora ve a la ~b~boya señalada~g~! +[CRED269] +GREG LAU -[AS3_3] -~g~¡Espera a que la ~y~avioneta~g~ comience a acercarse! +[CINCAM] +Vista cinematográfica -[AS3_5] -~g~¡Recupera el cargamento! +[KM1_13] +¡Mete el vehículo en el garaje! -[AS3_4] -~g~¡Usa un lanzacohetes para derribar ~y~la avioneta~g~! +[KM3_14] +~r~¡Te han descubierto, han cancelado el trato! -[AS3_2] -~b~¡Ve a la boya del aeropuerto señalada! ~y~¡El avión se está acercando! +[EBAL_H] +Espera, tío, que voy a hablar con Luigi. -[AS3_6] -~g~~1~ DE 8 +[EBAL_M] +¡Recuerda: nadie se mete con mis chicas! -[STASH] -~g~¡Lleva el SPANK de vuelta a la ~p~zona en obras~g~! +[LM2_F] +Luego coge su coche y repíntalo. -{ ============================================================== } -{ ================= MISSION: RANSOM (CATALINA) ================= } -{ ============================================================== } +[LM2_D] +toma, toma, para ti. -{ TITLE } +[LM1_9] +Hola, soy Misty. -[AS4] -'RESCATE' +[LM4_A] +Algún Diablo de las narices ha estado vendiendo a sus putitas en mi territorio. -[CAT1] -'RESCATE' +[FM2_B] +¡Tenemos a un chivato! -{ Cutscene } +[FM2_C] +No está ni chuleando ni traficando, así que estará cantando. -{ Catalina (letter, colombiana) } +[FM3_CC] +Regresa cuando tengas el dinero. -[CAT1_A] -Tengo a tu linda María. Si no quieres que parezca que un carnicero se ensañó con ella, +[FEDS_AM] +<> - CAMBIAR MENÚ -[CAT1_B] -lleva 500.000 dólares a la mansión de Cedar Grove. +[LOVE5_5] +~r~¡No has protegido al camión! -{ Mission instructions } +[RM6_6] +~r~¡Ray ha muerto! -[CAT1_F] -¡Ve a donde está Catalina antes de que se acabe el tiempo! +[RM6_7] +~r~¡Ray ha perdido su avión! -[CAT_MON] -~g~Todavía te falta dinero. Necesitas 500.000 dólares. +[RM6_8] +~g~Has abandonado a Ray, vuelve a por él. -[CAT1_E] -XXXX +[FM1_10] +~g~Has abandonado a María, vuelve y recógela. -{ ==================================================================== } -{ ================= MISSION: THE EXCHANGE (CATALINA) ================= } -{ ==================================================================== } +[LOVE4_9] +~r~¡El avión ha sido destruido! -{ TITLE } +[LOV4_10] +~r~¡La única pista sobre dónde se encuentra el paquete ha sido destruida! -[CAT2] -'EL INTERCAMBIO' +[KM2_D] +No hace falta decir que debemos darle los coches como un regalo, para pagar mi deuda con él. -{ Premission cutscene } +[KM4_B] +El negocio es lo bastante afortunado como para permitir que nuestra protección salde sus cuentas hoy mismo. -{ Catalina (colombiana) } +[KM2_E] +Debes obtener los coches de la lista y llevarlos a un garaje que hay tras el aparcamiento de Newport. -[CAT2_A] -La verdadera pregunta es: ¿vienes buscando a María o buscándome a mí? +[FM3_8I] +Encuentra una posición elevada. Entraré cuando dispares el primer tiro. -[CAT2_B] -Tengo una noticia para ti: +[LOVE1_B] +La experiencia me ha enseñado que un hombre como tú puede ser muy leal por el precio correcto, -[CAT2_B2] -matarte será un placer, pero salir contigo sólo fue un negocio. +[LOVE1_H] +pero los grupos de hombres se vuelven codiciosos. -[CAT2_C] -¡Eres muy pequeñito, amigo! +[LOVE1_C] +Un activo valioso, un anciano oriental que conozco, -[CAT2_D] -Dame el dinero. +[LOVE1_I] +está siendo retenido por unos sudamericanos en Aspatria. -[CAT2_E] -¡Has estado muy ocupado! +[MEA4_D] +He aceptado verle, -[CAT2_E2] -Pero no has aprendido que yo no soy de fiar. +[MEA4_B4] +¿Marty te envía? Vale, le voy a enseñar a ese sinvergüenza el significado de la palabra negocio. -[CAT2_E3] -¡Mata al idiota! +[MEA4_B5] +¡Carl, hola! Ehhh... Necesito más tiempo para conseguir tu dinero. -[CAT2_A1] -¡Vamos, perra! +[MEA1_B4] +Ah, te envió el Sr. Chonks, ¿verdad? Visitemos a nuestro amigo. -{ Cutscene, after reaching Catalina at the dam } +[HM5_6] +Vamos a partir cabezas... -{ Catalina (colombiana) } +[LOVE1_5] +~g~Deja de perder el tiempo, hazte con un coche de los colombianos y rescata al socio de Love. -[CAT2_J] -¡Despega de una vez! +[AS1_D] +Haz de cebo y consigue que los escuadrones te sigan hasta Pike Creek, -{ Mission instructions } +[AS1_E] +donde estarán esperando algunos de mis hombres. -[CATINF1] -~g~¡Liquida a Catalina! +[AS2_C] +El cártel tiene una tapadera, el Kappa Coffee House. -[CATINF2] -~g~Sigue al helicóptero para encontrar a Catalina. +[AS2_E] +No tenemos otra opción más que sabotear esos puntos de venta. -[BITCH_D] -~g~¡María está muerta! +[AS2_F] +¡Redúcelos a cenizas! -{ =================================================== } -{ ================= ENDING CUTSCENE ================= } -{ =================================================== } +[AS2_A1] +¡Está claro que Miguel tiene esa famosa resistencia latina! -{ Libery City News broadcaster } +[AS2_A2] +Estoy agotada. -[END_A] -Los residentes de Cedar Groove todavía están asumiendo +[SIREN_3] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[END_B] -las consecuencias emocionales provocadas +[SIREN_4] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[END_C] -por la guerra que estalló ayer en la zona. +[AS3_C] +¡Buaj! ¿Qué es esa cosa amarilla pegajosa? -[END_D] -Un residente local, Clive Denver, dijo a la policía +[AS3_C1] +¡Hola, guapo! -[END_E] -que vio a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. +[AS3_F] +Esta chica tiene un talento nato para la tortura. -{ Maria } +[AS3_F1] +Se las ha arreglado para extraerle esta joyita a nuestro invitado. -[END_F] -¿Sabes? Vamos a pasar un buen rato, porque, como sabes... +[AS3_G] +Hay una avioneta que llegará al Aeropuerto Francis en dos horas. -[END_G] -¡Te amo! Yo, yo, yo realmente te amo, porque eres superfuerte, +[AS3_G1] +Está lleno del veneno de Catalina. -[END_H] -y eso es todo lo que necesito. +[AS3_H] +Podrás evitar la seguridad del aeropuerto si conduces una lancha hasta las boyas luminosas, -[END_I] -Bueno, ¿qué estaba diciendo? +[AS3_H1] +así podrás disparar a la avioneta al aterrizar. -[END_J] -Lo he olvidado. Pero me entiendes, ¿verdad? +[AS3_I] +¡Recoge el cargamento de entre los escombros y tráelo! -{ Libery City News broadcaster } +[AS3_J] +Ten cuidado, guapo, ¿vale? -[END_K] -Las explosiones sacudieron las casas más próximas y a sus residentes. +[AS3_K] +Ahora prueba con el aceite picante... -[END_L] -Varios ciudadanos resultaron heridos a causa del tiroteo +[RM2_F1] +¡Los colombianos llegarán en cualquier momento! -[END_M] -entre las fuerzas terrestres y un helicóptero que rodeaba a la presa. +[RM2_K] +Maldita sea, ¡están aquí! ¡FUEGO A DISCRECIÓN! -{ Male witness } +[LOVE2_7] +~g~¡Ahora deshazte del coche! -[END_N] -Sí, en estos jardínes tuvimos una vista excelente. +[LOVE2_8] +~g~¡Sal de Newport! -[END_O] -Cuando el helicóptero estalló, +[AM1_F] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (~1~:~1~) -[END_P] -fue mejor que los fuegos artificiales del 4 de julio. +[LOVE5_C] +Quiero que le sigas, asegúrate que tanto él como mi paquete llegan a Pike Creek sin daño alguno. -{ Libery City News broadcaster } +[FESZ_SR] +¡Error al guardar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. -[END_Q] -El número de víctimas asciende a las veinte +[FESZ_FO] +¿Deseas formatear la Memory Card (PS2) en la ranura de MEMORY CARD 1? -[END_R] -mientras la policía sigue encontrando cuerpos. +[FELZ_FO] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. -[END_S] -No se han negado oficialmente los rumores +[FES_NOC] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. -[END_T] -de que las víctimas eran miembros del cártel colombiano, +[FES_LOE] +¡Fallo al cargar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. -[END_U] -y aún no hay pistas que aclaren las causas de la masacre. +[FES_DEE] +¡Fallo al borrar! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. -{ Maria } +[FORSUC] +Memory Card (PS2) de la ranura de MEMORY CARD 1 formateada con éxito. -[END_V] -Me he roto una uña y me pelo está hecho un asco, ¿puedes creerlo? +[ERFOUN] +¡Error al formatear la Memory Card (PS2)! -[END_W] -Me costó cincuenta dólares... +[ERMCNP] +No hay Memory Card (PS2) en la ranura de MEMORY CARD 1. -{ Duplicates of Maria's dialogue, possibly unused } +[SVMEM1] +Guardando en la Memory Card (PS2) de la ranura de MEMORY CARD 1. -[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! +[FORSLO] +Formateando Memory Card (PS2) de la ranura de MEMORY CARD 1. -[CAT2_G] -Estaba muerta de miedo, pero luego me dije a mí misma: ''Ya eres mayorcita''. +[SLONFM] +¡Error al formatear la Memory Card (PS2)! -[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, +[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. -[CAT2_I] -porque su marido a vuelto a enredar por ahí y... +[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. -{ =================================================================================================================== } -{ =================================================================================================================== } -{ ================================================== GAME CREDITS =================================================== } -{ =================================================================================================================== } -{ =================================================================================================================== } +[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. -[CRED001] -ROCKSTAR STUDIOS +[FES_ISF] +NO PRESENTE -[CRED002] -PRODUCTOR +[FES_SAG] +PRESENTE -[CRED003] -LESLIE BENZIES +[SLONNO] +No hay una Memory Card (PS2) en la ranura de MEMORY CARD 1. -[CRED004] -DIRECTOR DE ARTE +[SLONNF] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. -[CRED005] -AARON GARBUT +[FESZ_FM] +La Memory Card (PS2) de la ranura de MEMORY CARD 1 no tiene formato. ¿Deseas formatear la Memory Card (PS2)? -[CRED006] -DIRECCIÓN TÉCNICA +[FESZ_FF] +¡Fallo al formatear! Comprueba la Memory Card (PS2) de la ranura de MEMORY CARD 1 e inténtalo de nuevo. -[CRED007] -OBBE VERMEIJ +[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) -[CRED008] -ADAM FOWLER +[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) -[CRED009] -DISEÑO +[FESZ_WR] +Guardando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. -[CRED010] -CRAIG FILSHIE +[FESZ_OW] +Sobrescribiendo datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. -[CRED011] -WILLIAM MILLS - -[CRED012] -CHRIS ROTHWELL - -[CRED013] -JAMES WORRALL - -[CRED014] -GUIÓN - -[CRED015] -JAMES WORRALL - -[CRED016] -PAUL KUROWSKI - -[CRED017] -DAN HOUSER - -[CRED018] -PERSONAJES - -[CRED019] -IAN MCQUE - -[CRED020] -ANIMACIÓN Y DIRECCIÓN - -[CRED021] -ALEX HORTON - -[CRED022] -LEE MONTGOMERY - -[CRED023] -AUTO DESIGN - -[CRED024] -PAUL KUROWSKI - -[CRED025] -ARTISTAS - -[CRED026] -KEIRAN BAILLIE - -[CRED027] -ADAM COCHRANE - -[CRED028] -GARY MCADAM - -[CRED029] -MICHAEL PIRSO - -[CRED030] -ANDREW SOOSAY - -[CRED031] -ALISDAIR WOOD - -[CRED032] -PROGRAMADORES - -[CRED033] -ALAN CAMPBELL - -[CRED034] -MARK HANLON - -[CRED035] -ANDRZEJ MADAJCZYK - -[CRED036] -ALEXANDER ROGER - -[CRED037] -GRAEME WILLIAMSON - -[CRED038] -MÚSICA - -[CRED039] -CRAIG CONNER - -[CRED040] -STUART ROSS - -[CRED041] -DISEÑO DE SONIDO Y MASTERIZADO - -[CRED042] -ALLAN WALKER - -[CRED043] -PROGRAMACIÓN DE AUDIO - -[CRED044] -RAYMOND USHER - -[CRED045] -DIRECTOR DE PRUEBAS - -[CRED046] -CRAIG ARBUTHNOTT - -[CRED047] -JEFES DE PRUEBAS - -[CRED048] -ANDY DUTHIE - -[CRED049] -JOHN HAIME - -[CRED050] -NEIL CORBETT - -[CRD050A] -PROBADORES - -[CRED051] -GRAEME JENNINGS - -[CRED052] -DAVID MURDOCH - -[CRED053] -DAVID BEDDOES - -[CRED054] -EDWIN SMITH - -[CRED055] -MARK FLETT - -[CRED056] -MICHAEL SUTHERLAND - -[CRED057] -SOPORTE TÉCNICO - -[CRED058] -LORRAINE ROY - -[CRED059] -CHRISTINE CHALMERS - -[CRED060] -ROCKSTAR - -[CRED061] -PRODUCTOR EJECUTIVO - -[CRED062] -SAM HOUSER - -[CRED063] -PRODUCTOR - -[CRED064] -DAN HOUSER - -[CRED065] -DIRECTOR DE DESARROLLO - -[CRED066] -JAMIE KING - -[CRED067] -PRODUCTOR TÉCNICO - -[CRED068] -GARY J. FOREMAN - -[CRED069] -PRODUCTOR ASOCIADO - -[CRED070] -JEREMY POPE - -[CRED071] -SUPERVISOR MUSICAL - -[CRED072] -TERRY DONOVAN - -[CRED073] -EQUIPO DE PRODUCCIÓN DE ROCKSTAR - -[CRED074] -TERRY DONOVAN - -[CRED075] -JENNIFER KOLBE - -[CRED076] -JENEFER GROSS - -[CRED077] -LAURA PATERSON - -[CRED078] -JEFF CASTANEDA - -[CRED079] -CHRIS CARRO - -[CRED080] -ADAM TEDMAN - -[CRED081] -JUNG KWAK - -[CRED082] -BRIAN WOOD - -[CRED083] -PAUL YEATES - -[CRED084] -STANTON SARJEANT - -[CRED085] -VICEPRESIDENTE DE MÁRKETING - -[CRED086] -TERRY DONOVAN - -[CRED087] -COORDINADOR TÉCNICO - -[CRED088] -BRANDON ROSE - -[CRED089] -DIRECTOR DE C.C. - -[CRED090] -JEFF ROSA - -[CRED091] -JEFE DE ANÁLISIS - -[CRED092] -ADAM DAVIDSON - -[CRED093] -ANALISTA DEL JUEGO - -[CRED094] -RICHARD HUIE - -[CRED095] -EQUIPO DE PRUEBAS - -[CRED096] -LANCE WILLIAMS - -[CRED097] -JOE GREENE - -[CRED098] -BRIAN PLANER - -[CRED099] -OSWALD GREENE - -[CRED100] -EDITORIAL DEL LIBERTY TREE - -[CRED101] -JAMES WORRALL - -[CRED102] -DAN HOUSER - -[CRED103] -ADAM TEDMAN - -[CRED104] -PAUL YEATES - -[CRED105] -JENEFER GROSS - -[CRED106] -LAURA PATERSON - -[CRED107] -CINEMÁTICAS - -[CRED108] -GUIÓN DE DAN HOUSER Y JAMES WORRALL - -[CRED109] -AUDIO DIRIGIDO POR DAN HOUSER - -[CRED110] -AUDIO PRODUCIDO POR RENAUD SEBBANE - -[CRED111] -REPARTO - -[CRED112] -FRANK VINCENT COMO SALVATORE LEONE - -[CRED113] -JOE PANTOLIANO COMO LUIGI GOTERELLI - -[CRED114] -MICHAEL MADSEN COMO TONI CIPRIANI - -[CRED115] -MICHAEL RAPAPORT COMO JOEY LEONE - -[CRED116] -DEBBI MAZAR COMO MARÍA - -[CRED117] -KYLE MACLACHAN COMO DONALD LOVE - -[CRED118] -ROBERT LOGGIA COMO RAY MACHOWSKI - -[CRED119] -GURU COMO 8-BALL - -[CRED120] -SONDRA JAMES COMO MAMMA - -[CRED121] -LIANA PAI COMO ASUKA - -[CRED122] -LES MAU COMO KENJI - -[CRED123] -CYNTHIA FARRELL COMO CATALINA - -[CRED124] -AL ESPINOSA COMO MIGUEL - -[CRED125] -CHRIS PHILLIPS COMO EL BURRO - -[CRED126] -HUNTER PLATIN COMO CHICO - -[CRED127] -WALTER MUDU COMO D-ICE - -[CRED128] -CURTIS MCCLARIN COMO CURTLY - -[CRED129] -BILL FIORE COMO DARKEL - -[CRED130] -CHRIS PHILLIPS COMO MARTY CHONKS - -[CRED131] -HUNTER PLATIN COMO CURLY BOB - -[CRED132] -WALTER MUDU COMO KING COURTNEY - -[CRED133] -HUNTER PLATIN COMO ONE-ARMED PHIL - -[CRED134] -KIM GURNEY COMO MISTY - -[CRED135] -CAPTURA DE MOVIMIENTOS - -[CRED136] -ANIMACIÓN - -[CRD136A] -ALEX HORTON - -[CRED137] -DIRECCIÓN - -[CRD137A] -NAVID KHONSARI - -[CRED138] -PRODUCCIÓN - -[CRD138A] -JAMIE KING - -[CRD138B] -RENAUD SEBBANE - -[CRED139] -GRABADA EN MODERN UPRISING STUDIOS, BROOKLYN - -[CRED140] -ACTORES - -[CRD140A] -RENAUD SEBBANE - -[CRD140B] -GISELLE JONES - -[CRD140C] -STEPHEN DANIELS - -[CRD140D] -ROBERT STIO - -[CRD140E] -JENNY GROSS - -[CRED141] -DIÁLOGO DE PEATONES - -[CRED142] -ESCRITO POR DAN HOUSER, NAVID KHONSARI Y JAMES WORRALL - -[CRED143] -DIRIGIDO POR CRAIG CONNER, DAN HOUSER Y LAZLOW - -[CRED144] -PRODUCIDO POR RENAUD SEBBANE - -[CRED145] -REPARTO - -[CRED146] -HUNTER PLATIN - -[CRED147] -DAN HOUSER - -[CRED148] -RENAUD SEBBANE - -[CRED149] -MARIA CHAMBERS - -[CRED150] -JEFF STANTON - -[CRED151] -RYAN CROY - -[CRED152] -DEENA BERMAN - -[CRED153] -MARIA CHAMBERS - -[CRED154] -ALICE B. SALTZMAN - -[CRED155] -ALEX ANTHONY SIOUKAS - -[CRED156] -SEAN R. LYNCH - -[CRED157] -AMY SALZMAN - -[CRED158] -COLIN MCSHANE - -[CRED159] -COREY WADE - -[CRED160] -GERALD COSGROVE - -[CRED161] -STEPHANIE ROY - -[CRED162] -DORIS WOO - -[CRED163] -JOSEPH GREENE - -[CRED164] -LAZLOW JONES - -[CRED165] -HSIANG LIN - -[CRED166] -STEVE MICHAEL ROBERT - -[CRED167] -MATHEW MURRAY - -[CRED168] -RICHARD HUIE - -[CRED169] -GARVIN ATWELL - -[CRED170] -STEVE KNEZEVICH - -[CRED171] -YUKIMURA SATO - -[CRED172] -FRANK CHAVEZ - -[CRED173] -LIEZL JACINTO - -[CRED174] -CANAAN MCKOY - -[CRED175] -ADAM DAVIDSON - -[CRED176] -LANCE WILLIAMS - -[CRED177] -NEIL MCCAFFREY - -[CRED178] -LAURA PATERSON - -[CRED179] -REY CONCEPCION - -[CRED180] -CHARLES HEROLD - -[CRED181] -ANDREW GREENWALD - -[CRED182] -JAMES MIELKE - -[CRED183] -PETER SUCIU - -[CRED184] -ALEX ODULIO - -[CRED185] -DON NKRUMAH - -[CRED186] -KENDALL PITTMAN - -[CRED187] -SAL SUAZO - -[CRED188] -EREK MATEO - -[CRED189] -CHRIS DIFATE - -[CRED190] -LEILA MILTON - -[CRED191] -DARREN ZOLTOWSKI - -[CRED192] -VIRGINIA SMITH - -[CRED193] -KEVIN CASSIN - -[CRED194] -JASON SHIGEMORI - -[CRED195] -KELLY KINSELLA - -[CRED196] -MOLLIE STICKNEY - -[CRED197] -STANTON SARJEANT - -[CRED198] -LAURA WALSH - -[CRED199] -MARK GARONE - -[CRED200] -JOANNA SLY - -[CRED201] -ELIZABETH HOWELL - -[CRED202] -ANA HERCULES - -[CRED203] -SHIRLEY IRICK - -[CRED204] -KASHONA FIELDS - -[CRED205] -JOEL M. LILJE - -[CRED206] -JOHN DIBENEDETTO - -[CRED207] -NANCY GILES - -[CRED208] -RYAN CROY - -[CRED209] -JENNIFER KOLBE - -[CRED210] -LIAM BURKE - -[CRED211] -SIGRID PREISSL - -[CRED212] -ANITA FITZSIMONS - -[CRED213] -PHILIPPA RASELLI - -[CRED214] -WIL QUESNEL - -[CRED215] -FALKO BURKERT - -[CRED216] -SARA SEWELL - -[CRED217] -EMISORAS DE RADIO Y MÚSICA - -[CRED218] -PRODUCTORES DE ROCKSTAR REINO UNIDO - -[CRD218A] -CRAIG CONNER - -[CRD218B] -STUART ROSS - -[CRED219] -COORDINADOR DE BANDA SONORA - -[CRED220] -TERRY DONOVAN - -[CRED221] -PRODUCTOR DE ROCKSTAR GAMES - -[CRED222] -DAN HOUSER - -[CRED223] -EDICIÓN - -[CRED224] -CRAIG CONNER - -[CRED225] -ALLAN WALKER - -[CRED226] -LAZLOW - -[CRED227] -GUIÓN DE LOCUTORES Y ANUNCIOS - -[CRED228] -DAN HOUSER - -[CRED229] -LAZLOW - -[CRED230] -AGRADECIMIENTOS ESPECIALES - -[CRED231] -ADAM TEDMAN - -[CRED232] -ALEX MASON - -[CRED233] -JUDY HENDERSON CASTING - -[CRED234] -HAMISH BROWN - -[CRED235] -CHRISSY HOBAN - -[CRED236] -INNES RICARD - -[CRED237] -LILION BROZSKA - -[CRED238] -BOB HILLARY - -[CRED239] -EMILY ANDERSON - -[CRED240] -RICHIE HENDERSON - -[CRED241] -CHRISTIAN CANTAMESSA - -[CRED242] -JERONIMO BARRERA - -[CRED243] -ALEXANDER ILLES - -[CRED244] -BARANE CHAN - -[CRED245] -DUNCAN SHIELDS - -[CRED246] -BARANE CHAN - -[CRED247] -DEREK PAYNE - -[CRED248] -KEVIN WONG - -[CRED249] -ROSS ELLIOTT - -[CRED250] -ROSS BEAZLEY - -[CRED251] -ALEX BAZLINTON - -[CRED252] -DAVE WATSON - -[CRED253] -MALCOLM SMITH - -[CRED254] -JEFE DEL ESTUDIO - -[CRED255] -ANDREW SEMPLE - -[CRED256] -ARTISTAS - -[CRED257] -STUART PETRI - -[CRED258] -JERONIMO BARRERA - -[CRED259] -CARLY SLATER - -[CRED260] -GREG LAU - -[CRED261] -STEVE KNEZEVICH - -[CRED262] -DEVIN WINTERBOTTOM - -[CRED263] -JAMEEL VEGA - -[CRED264] -LEE CUMMINGS - -[CRED265] -DEVIN BENNET - -[CRED266] -ELIZABETH SATTERWHITE - -[CRED267] -AARON RIGBY - -[CRED268] -STEVE K. - -[CRED269] -GREG LAU - -[CRED270] -MIKE HONG - -{ =================================================================================================================== } -{ =================================================================================================================== } -{ ================================================ INTERFACE STRINGS ================================================ } -{ =================================================================================================================== } -{ =================================================================================================================== } - -{ ================================================================ } -{ ================= PAUSE MENU OPTIONS (CONSOLE) ================= } -{ ================================================================ } - -[FEB_STA] -Estadísticas - -[FEB_BRI] -Resumen - -[FEB_CON] -Controles - -[FEB_AUD] -Sonido - -[FEB_DIS] -Pantalla - -[FEB_LAN] -Idioma - -[FEB_SAV] -Cargar - -[FEB_CPC] -Configuración de controles - -[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 MENÚ - -[FEDS_AS] -;= - CAMBIAR SELECCIÓN - -[FEDSAS2] -<> - CAMBIAR SELECCIÓN - -[FEDSAS3] -- CAMBIAR SELECCIÓN - -[FEDSAS4] -;=<> - CAMBIAR SELECCIÓN - -[FEDS_SS] -L1,R1 - CAMBIAR SELECCIÓN - -[FEDSSC1] -; - ACELERAR - -[FEDSSC2] -= - RALENTIZAR - -[FEDS_SE] -Botón / - ELEGIR - -[FEDS_SB] -Botón / - ELEGIR Botón " - VOLVER - -[FEDS_BA] -Botón " - VOLVER - -[FEDS_TB] -ATRÁS - -{ INTERFACE ARROWS } - -[FEA_UP] -; - -[FEA_DO] -= - -[FEA_LE] -< - -[FEA_RI] -> - -{ ================================================================================ } -{ ================= REMNANTS FROM THE CONSOLE PAUSE MENU OPTIONS ================= } -{ ================================================================================ } - -[FES_LGA] -Cargar partida - -[FES_NGA] -Nueva partida - -[PRVMEN] -Resúmenes de misiones anteriores - -[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 - -[ENGLIS] -Inglés - -[GERMAN] -Alemán - -[ITALIA] -Italiano - -[FRENCH] -Francés - -[SPAIN] -Español - -[FESZ_SA] -Guardar partida - -[FES_SLO] -ARCHIVO - -[FES_ISF] -NO PRESENTE - -[FES_SAG] -PRESENTE - -[FES_ISC] -ESTÁ DAÑADO - -[FESZ_TI] -ARCHIVO Z1 - -{ =================================================================== } -{ ================= PLAYSTATION 2 EXCLUSIVE PROMPTS ================= } -{ =================================================================== } - -[P1INSA] -La Memory Card (PS2) insertada en la ranura para MEMORY CARD 1 tiene ~1~ KB de espacio disponible. Necesitas ~1~ KB para guardar. - -[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. - -[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 +[FELD_WR] +Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. -[FEM_CPD] -Crear copia protegida del directorio mag +[FEDL_WR] +Borrando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. -[FEM_MC2] -Menú de Memory Card 2 +[LM2_C] +Luigi dijo que... que te diera esto... -[FEM_TS] -Prueba de guardado: +[LM3_G] +que a Joey no le gusta esperar. Recuerda, tienes un pie dentro... -[FEM_TL] -Prueba de carga: +[LM5_E] +Saca todo el dinero que puedas a los polis antes de que se lo beban. -[FEM_TD] -Prueba de borrado: +[JM5_C] +Vale, hay un coche cargado con un fiambre en el bar cercano a Callahan Point. -[RELIDE] -ReLoadIde +[RM2_B] +Combatimos juntos en Nicaragua, cuando el país sabía lo que hacía. -[RELIPE] -ReLoadIpl +[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. -[PARSHP] -Analizar pila +[RM2_D1] +Iría yo mismo, pero la ciática ya está en sus trece... ¡Cof, cof! Así que... buena suerte. -[DBGFON] -CTheScripts::DbgFlag activado +[CATINF1] +~g~¡Liquida a Catalina! -[DBFOFF] -CTheScripts::DbgFlag desactivado +[CATINF2] +~g~Sigue al helicóptero para encontrar a Catalina. -[BGWHON] -Luz blanca grande de depuración activada +[BOATIN1] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. -[BGWOFF] -Luz blanca grande de depuración desactivada +[BOATIN2] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. -[DSTRON] -Solicitudes de depuración de streaming activadas +[BOATIN3] +Sube a una lancha y pulsa el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ para entrar. -[DSTROFF] -Solicitudes de depuración de streaming desactivadas +[BOATIN4] +Puedes pulsar el ~h~botón ~k~~VEHICLE_ENTER_EXIT~~w~ si estás cerca de una lancha para abordarla. -[PDRGON] -ShowPedRoadGroups activado +[JM6] +'LA HUIDA' -[PRGOFF] -ShowPedRoadGroups desactivado +[FM1] +'CARABINA' -[CRRGON] -ShowCarRoadGroups activado +[JM1] +'EL ÚLTIMO ALMUERZO DE MIKE ''LABIOS'' ' -[CRGOFF] -ShowCarRoadGroups desactivado +[FM21] +'BASE FUERA: ACTO I' -[CLZOON] -Zonas de máscara selectiva mostradas +[FM3] +'BASE FUERA: ACTO II' -[CLZOOF] -Zonas de máscara selectiva ocultadas +[AM1] +'SAYONARA, SALVATORE' -[SHPLON] -gbShowCollisionPolys activado +[AM2] +'BAJO VIGILANCIA' -[SHPLOF] -gbShowCollisionPolys desactivado +[KM2] +'ROBO DE VEHÍCULOS' -[CULREC] -CCullZones::RecalculateCullZoneData() +[AS3] +'TIERRA-AIRE' -[FORMM1] -FormatMemCard 1 (prueba) +[RM2] +'ESCASEZ DE MANOS' -[UNFRM1] -UnFormatMemCard 1 (prueba) +[LOVE6] +'SEÑUELO' -[MEMTST] -Pantalla MemoryCardTest +[LOVE1] +'EL LIBERADOR' -[REGCAR] -Registrar MemoryCard uno +[RC1] +'DESTRUCCIÓN DE LOS DIABLOS' -[TEFONE] -Probar MemCard uno con formato +[RC2] +'LA MASACRE DE LA MAFIA' -[TEUFON] -Probar MemCard uno sin formato +[RC3] +'CALAMIDAD EN EL CASINO' -[CRROOT] -CreateRootDir +[RC4] +'EXTERMINIO DE RUMPOS' -[CRLDIC] -Crear y cargar iconos +[RM2_E1] +¡No puedo creer que esos mamones amarillos me hayan vuelto a dejar con el culo al aire! -[FLFSGF] -Llenar el primer archivo con basura +[GREN_1] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. -[PUSAVE] -Guardar sólo la partida +[GREN_2] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. -[CHEVOK] -CheckEveryOkB4Save +[GREN_3] +Cuanto más tiempo mantengas pulsado el ~h~botón ~k~~PED_FIREWEAPON~~w~, más lejos lanzarás la granada. -[SVGMON] -SaveTheGame +[LOVE4_G] +Mis pertenencias estarán esperándote en el hangar de aduanas, dentro de la avioneta. -[CRMGSV] -Crear directorio de cargador con protección de copia +[KABOOM] +¡BUUUM! -[MGSVCN] -MagazineDirectory creado +[SPLAT] +¡PLOF! -[MGSVNC] -MagazineDirectory no creado +[PANCAK] +¡APLASTADO! -{ ======================================================================================================= } -{ ================= INGAME PLAYER STATISTICS. BE CAREFUL WITH WIDTH LIMITS IN 4:3 RATIO ================= } -{ ======================================================================================================= } +[SOAKED] +¡AGUADO! -{ ARTICLE ADDED BETWEEN NUMBERS } +[HEAD] +Head Radio -[FEST_OO] -de +[DBL_CLF] +Double Clef FM -[PL_STAT] -Estadísticas de jugador +[FLASHB] +Flashback FM -[PE_WAST] -Personas asesinadas +[RISE] +Rise FM -[PE_WSOT] -Personas asesinadas por otros +[LIPS] +Lips 106 -[CAR_EXP] -Coches reventados +[CHAT] +Chatterbox FM -[TM_BUST] -Veces arrestado +[K_JAH] +K-Jah Radio -[M_WASTE] -Hombres civiles asesinados +[GAM_FM] +Game Radio FM -[F_WASTE] -Mujeres civiles asesinadas +[MSX_FM] +MSX FM -[PIG_WST] -Polis asesinados +[TUBE1] +Cuando el metro abra, podrás coger un tren hasta Staunton Island. -[GNG_WST] -Maleantes asesinados +[TUBE2] +Cuando Shoreside Vale abra podrás salir por la terminal de Shoreside al Aeropuerto Internacional Francis. -[MED_WST] -Médicos asesinados +[TUBE_2] +Para subirte a un vagón, pulsa el ~h~botón Entrar al vehículo~w~. -[FIRE_WS] -Bomberos asesinados +[LEGAL] +~g~¡Elimina la amenaza criminal! -[DED_CRI] -Criminales asesinados +[GA_2] +He cambiado el motor y la mano de pintura. ¡La poli no te reconocerá! -[DED_DED] -Vagabundos asesinados +[LM1_8A] +Si quieres ganar un dinerillo extra, siempre puedes ''coger prestado'' un taxi... -[DED_HOK] -Prostitutas asesinadas +[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. -[HEL_DST] -Helicópteros destruidos +[LM5_7] +~g~¡Si hay menos de cuatro chicas trabajando en el ~p~baile de la policía~g~, Luigi no estará contento! -[PER_COM] -Porcentaje completado +[KM2_3] +~g~Recuerda que los ~r~coches ~g~tienen que estar en perfecto estado para ser aceptados en el ~p~garaje~g~. -[KGS_EXP] -Kgs de explosivos empleados +[KM5_2] +~g~Uno de los jamaicanos se ha ido. -[ACCURA] -Precisión de tiro +[BETRA_A] +Lo siento, cariño. -[ELBURRO] -Mejor tiempo de ''Turismo'' en segundos +[BETRA_B] +Soy una chica ambiciosa, ¿y tú? -[CAR_CRU] -Coches destrozados +[BETRA_C] +Un Don Nadie. -[HED_EX] -Cabezas explotadas +[JAILB_Q] +¡Vamos! -[TM_DED] -Visitas al hospital +[JAILB_R] +¡Señor pendejo! -[DAYSPS] -Días de juego transcurridos +[JAILB_S] +No nos importará matarte. -[MMRAIN] -mm de lluvia caídos +[JAILB_T] +Os vais a arrepentir. -[MXCARD] -Dist. máx. de salto acrobático (pies) +[JAILB_U] +Bien, bien, piérdete. -[MXCARJ] -Altitud máx. de salto acrobático (pies) +[HELP15] +Cuando vayas a pie mantén pulsado el ~h~botón ~k~~PED_LOOKBEHIND~~w~ para~h~ mirar atrás~w~. -[MXCARDM] -Dist. máx. de salto acrobático (metros) +[FEC_LB3] +Mirar atrás -[MXCARJM] -Altitud máx. de salto acrobático (metros) +[FEC_R3] +(botón R3) -[MXFLIP] -Vueltas durante salto acrobático +[FES_AFO] +Esta Memory Card (PS2) ya está formateada. -[MXJUMP] -Rotación máx. de salto acrobático +[FEA_UP] +; -[BSTSTU] -Mejor acrobacia hasta ahora: +[FEA_DO] += -[INSTUN] -Acrobacia +[FEA_LE] +< -[PRINST] -Acrobacia perfecta +[FEA_RI] +> -[DBINST] -Acrobacia doble +[FEDSAS3] +- CAMBIAR SELECCIÓN -[DBPINS] -Acrobacia doble perfecta +[FEDSAS4] +;=<> - CAMBIAR SELECCIÓN -[TRINST] -Acrobacia triple +[SPRAY_4] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. -[PRTRST] -Acrobacia triple perfecta +[SPRAY_1] +Pulsa el ~h~botón ~k~~PED_FIREWEAPON~~w~ para disparar el cañón de agua. -[QUINST] -Acrobacia cuádruple +[LITTLE] +LITTLE T -[PQUINS] -Acrobacia cuádruple perfecta +[NICK] +NICK LOVE -[NOSTUC] -No se han hecho acrobacias +[AM1_10] +~g~Salvatore saldrá del club de Luigi sobre las 0~1~:~1~. -[NOUNIF] -Saltos únicos completados +[JAILB_V] +Hoy, Liberty City se ha visto conmocionada. -[NOUNGM] -Saltos únicos +[JAILB_A] +La policía y los servicios de emergencia lidian con las consecuencias -[NMISON] -Misiones intentadas +[JAILB_B] +de un ataque devastador a un convoy policial ocurrido esta mañana. -[NMMISP] -Misiones superadas +[JAILB_C] +No se ha informado de quiénes eran los prisioneros trasladados en el convoy -[PASDRO] -Pasajeros transportados +[JAILB_D] +y ningún grupo ha reconocido la autoría. -[MONTAX] -Dinero conseguido en taxi +[JAILB_E] +El convoy abandonó las oficinas de la policía esta mañana -[DAYPLC] -Gasto diario de la policía +[JAILB_F] +para hacer una transferencia de reos a la penitenciaría de Liberty. -[FEST_HA] -Nivel más alto de misión de sanitario +[JAILB_G] +El ataque se produjo en el puente Callahan, -[FEST_DF] -Distancia recorrida a pie (millas) +[JAILB_H] +dejando pocos testigos y al puente seriamente dañado. -[FEST_DC] -Distancia recorrida en coche (millas) +[JAILB_I] +Se cree que algunos de los convictos han perecido en la explosión -[FESTDFM] -Distancia recorrida a pie (metros) +[JAILB_J] +posterior al ataque inicial. -[FESTDCM] -Distancia recorrida en coche (metros) +[JAILB_W] +Pasadas las horas se hizo evidente que el ataque era obra de profesionales, -[FEST_R1] -''Patio de recreo'' en segundos +[JAILB_K] +ya que la identificación de los prófugos se complicó -[FEST_R2] -''Un paseo por el parque'' en segundos +[JAILB_L] +cuando piratas informáticos atacaron las bases de datos de la policía. -[FEST_R3] -''¡Agarrado!'' en segundos +[JAILB_O] +Con el retraso del proyecto del túnel Porter, -[FEST_RM] -''Caos en el aparcamiento'' en segundos +[JAILB_P] +este desastre deja a Portland aislada del resto de la ciudad. -[FEST_LS] -Gente salvada con una ambulancia +[JAILB_M] +* -[FEST_CC] -Criminales asesinados en misiones de justiciero +[JAILB_N] +* -[FEST_FE] -Incendios extinguidos +[JAILB_X] +UNUSED -[FEST_LF] -Vuelo más largo en Dodo +[FEDS_SE] +Botón / - ELEGIR -[FEST_BD] -Mejor tiempo al desactivar la bomba +[FEDS_SB] +Botón / - ELEGIR Botón " - VOLVER -[FEST_RP] -Masacres superadas +[TM4_A] +Ah, eres tú. Toni no está. -[FEST_MP] -Misiones superadas +[TM4_A2] +Pero te ha dejado una de sus cartitas de amor. -[FEST_BB] -Carrera forrada: +[DIAB2_A] +¡Empecé mi negocio de entretenimiento exótico sin nada más que lo que cabía en mis pantalones de cuero! -[FEST_H0] -Máximo de puntos de control +[LM5_9] +CHICAS: -[FEST_GC] -Coches de bandas destruidos: +[PERPIC] +Paquetes ocultos encontrados -[FEST_H1] -Destrucción de los Diablos +[CO_ONE] +Paquete oculto ~1~ de ~1~ -[FEST_H2] -La masacre de la mafia +[LOVE3_3] +~g~La avioneta ha tirado ~1~ de los 6 paquetes. -[FEST_H3] -Calamidad en el casino +[FARE11] +~g~Ve a la ~w~zona en obras~g~ de Fort Staunton. -[FEST_H4] -Exterminio de Rumpos +[GA_21] +No puedes guardar más coches en este garaje. -[PERPIC] -Paquetes ocultos encontrados +[CHEAT1] +Trucos activados -[CRIMRA] -Rango de criminal: +[CHEAT2] +Arma trucada -{ ==================================================== } -{ ================= CRIMINAL RATINGS ================= } -{ ==================================================== } +[CHEAT3] +Salud trucada -[RATNG1] -Carterista +[CHEAT4] +Armadura trucada -[RATNG2] -Abusón +[CHEAT5] +Busca y captura trucado -[RATNG3] -Chorizo +[CHEAT6] +Dinero trucado -[RATNG4] -Granuja +[CHEAT7] +Clima trucado -[RATNG5] -Secuaz +[AS1_H] +~r~¡No has llevado al escuadrón de la muerte hasta la trampa de la yakuza! -[RATNG6] -Conductor +[FEDS_BA] +Botón " - VOLVER -[RATNG7] -Guardaespaldas +[RAMP_A] +¡TODAS LAS MASACRES COMPLETADAS! -[RATNG8] -Negociador +[USJ_ALL] +¡TODAS LAS ACROBACIAS COMPLETADAS! -[RATNG9] -Socio +[FARE23] +~g~Ve al ~w~taller de importación/exportación~g~ en el distrito de la presa Cochrane. -[RATNG10] -Sicario +[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. -[RATNG11] -Asesino +[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. -[RATNG12] -Mano derecha +[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. -[RATNG13] -Verdugo +[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. -[RATNG14] -Capo +[AS1_C] +Ella cuenta con tres escuadrones de la muerte que patrullan por Liberty con el único fin de darte caza. -[RATNG15] -Jefe +[AS1_G] +~r~¡Todos los yakuza están muertos! -{ =========================================================== } -{ ================= PAUSE MENU OPTIONS (PC) ================= } -{ =========================================================== } +[JAN] +Ene -[FEP_STA] -ESTADÍSTICAS +[FEB] +Feb -[FEP_BRI] -RESUMEN +[MAR] +Mar -[FEP_CON] -CONTROLES +[APR] +Abr -[FEP_AUD] -SONIDO +[MAY] +May -[FEP_DIS] -PANTALLA +[JUN] +Jun -[FEP_LAN] -IDIOMA +[JUL] +Jul -{ ============================================================= } -{ ================= MIXED BAG OF MENU OPTIONS ================= } -{ ============================================================= } +[AUG] +Ago -[GMSTOR] -Almacenar partida +[SEP] +Sept -[PREBRF] -Resúmenes anteriores +[OCT] +Oct -[CNTLS] -Controles +[NOV] +Nov -[MUSMEN] -Música/Efectos +[DEC] +Dic -[GAMSET] -Ajustes del juego +[DEFDT] +--:---:---- --:--:-- -[LANGUA] -Idioma +[BUGGY] +COCHES RESTANTES: -[DSPLAY] -Pantalla +[BONUS] +~g~~1~$ ADICIONALES -[DEBUGM] -Menú de depuración +[HORN1] +Pulsa el ~h~botón L3~w~ para tocar el ~h~claxon. -[QUITOP] -Salir de las opciones +[HORN2] +Pulsa el ~h~botón L1~w~ para tocar el ~h~claxon. -[CONTRL] -Configuración de controles +[HORN3] +Pulsa el ~h~botón R1~w~ para tocar el ~h~claxon. -[SET1EN] -Ajuste 1. Activado +[LM3_1A] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. -[SET1] -Ajuste 1. +[LM3_1B] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. -[SET2EN] -Ajuste 2. Activado +[LM3_1C] +Pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~ para tocar el ~h~claxon y avisar a Misty. -[SET2] -Ajuste 2 +[RADIO_A] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[SET3EN] -Ajuste 3. Activado +[RADIO_B] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[SET3] -Ajuste 3 +[RADIO_C] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[SET4EN] -Ajuste 4. Activado +[RADIO_D] +Pulsa el ~h~botón ~k~~VEHICLE_CHANGE_RADIO_STATION~~w~ para cambiar de ~h~emisora de radio. -[SET4] -Ajuste 4 +[FEC_EXV] +Entrar/salir de vehículo -[GOBACK] -Volver +[TAXI_M] +'TAXISTA' -[SOUND] -SONIDO +[COP_M] +'JUSTICIERO' -[MUSVOL] -Volumen de la música +[FIRE_M] +'BOMBERO' -[SFXVOL] -Volumen de los efectos +[AMBUL_M] +'SANITARIO' -[SCROPT] -OPCIONES DE PANTALLA +[HJ_IS] +PREMIO POR ACROBACIA: ~1~$ -[CTRSCR] -Centrar pantalla +[HJ_PIS] +PREMIO POR ACROBACIA PERFECTA: ~1~$ -[SCRFOR] -Formato de imagen +[HJ_DIS] +PREMIO POR ACROBACIA DOBLE: ~1~$ -[GMSVLQ] -GUARDAR-CARGAR-SALIR +[HJ_PDIS] +PREMIO POR ACROBACIA DOBLE PERFECTA: ~1~$ -[GMREST] -Reiniciar partida +[HJ_TIS] +PREMIO POR ACROBACIA TRIPLE: ~1~$ -[NOGMSV] -Sólo puedes guardar desde tu escondite. +[HJ_PTIS] +PREMIO POR ACROBACIA TRIPLE PERFECTA: ~1~$ -[DLFILE] -Borrar archivos de Grand Theft Auto III +[HJ_QIS] +PREMIO POR ACROBACIA CUÁDRUPLE: ~1~$ -[CHFILE] -ELEGIR ARCHIVO A CARGAR +[HJ_PQIS] +PREMIO POR ACROBACIA CUÁDRUPLE PERFECTA: ~1~$ -[CHCDLD] -ELEGIR MEMORY CARD A USAR +[AM1_K] +Salvatore Leone saldrá del club de Luigi dentro de unas tres horas. (0~1~:~1~) -[CHFIDL] -ELEGIR ARCHIVO A BORRAR +[IMPEXPP] +Garaje de Importación/Exportación, puerto de Portland. Requerimos varios vehículos; revisa nuestro tablón de notas para saber más. -[CDUNFR] -Memory Card sin formato. +[VANHSTP] +¿Quieres abrir algún Securicar? Llévalo a nuestro garaje en el puerto de Portland. -[SVCONF] -CONFIRMACIÓN +[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. -[SVFNAM] -El nombre de tu archivo guardado es +[STANDS] +PUESTOS DESTROZADOS: -[SAVEDN] -Error. Fallo al guardar. +[STASH] +~g~¡Lleva el SPANK de vuelta a la ~p~zona en obras~g~! -[LANGSL] -SELECCIÓN DE IDIOMA +[MCSTNS] +No hay una Memory Card (PS2) insertada en la ranura para MEMORY CARD 1. ¿Quieres empezar? (SÍ o NO) -[GORLEV] -Nivel de violencia +[LOVE3_5] +~g~La avioneta está ahora a tu alcance. -[SICASS] -Puta locura +[LOVE3_6] +~r~¡La bofia ha llegado a los paquetes antes que tú! -[SICSIC] -Puto manicomio +[SIREN_1] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[SCASSL] -Seleccionado Puta locura +[SIREN_2] +Para activar la sirena de este vehículo, pulsa el ~h~botón ~k~~VEHICLE_HORN~~w~. -[SCSCSL] -Seleccionado Puto manicomio +[FM3_8C] +Necesitaré 100.000 $ para cubrir gastos, -[DOSVGM] -¿Deseas guardar la partida? +[MCLOAD] +Cargando datos. No extraigas la Memory Card (PS2) de la ranura de MEMORY CARD 1, ni reinicies o apagues la consola. -[FORMEN] -Menú de formato +[FES_GME] +Fallo al leer la Memory Card (PS2) de la ranura de MEMORY CARD 1. Compruébala e inténtalo de nuevo. -[CNTSAV] -No se puede guardar la partida en una misión. +[FESZ_QF] +¿Seguro que quieres formatear la Memory Card (PS2) de la ranura de MEMORY CARD 1? -[CNCSAV] -No se puede guardar la partida dentro de un vehículo. +[FESZ_LS] +Carga completada. -[YES] -Sí +[RM3_5] +~g~Tienes ~1~ de 6 paquetes de pruebas. -[NO] -No +[LOVE3_2] +~g~¡Tienes todos los paquetes! Llévaselos a Donald Love. -[X] -x +[LOVE4_4] +~g~¡Lleva el paquete a Donald Love! -[LAST] -Último mensaje +[FEB_SAV] +Cargar -[FIRST] -~g~1.° +[FEP_SAV] +CARGAR PARTIDA -[SECOND] -~g~2.° +[AS2_12A] +~g~Cuando destruyas el primer puesto, ¡tendrás 8 mintutos antes que el cártel avise a sus camellos! -[THIRD] -~g~3.° +[AS3_1A] +~g~¡Ahora ve a la ~b~boya señalada~g~! -[FOURTH] -~g~4.° +[NOCONT] +Vuelve a conectar un mando analógico (DUALSHOCK#) o mando analógico (DUALSHOCK#2) en el puerto de mando 1 para continuar. -[WRONGCD] -Disco incorrecto. Introduce el disco correcto. +{ Possibly unused } -[NOCD] -La bandeja del disco está vacía. Introduce un disco. +[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! -[OPENCD] -La bandeja del disco está abierta. Cierra la bandeja de disco. +[END_A] +Los residentes de Cedar Groove todavía están asumiendo -[CDERROR] -Error al leer el DVD de Grand Theft Auto III +[END_B] +las consecuencias emocionales provocadas -[RESTART] -Empezando una nueva partida +[END_C] +por la guerra que estalló ayer en la zona. -[STOCK] -mercancía agotada +[END_D] +Un residente local, Clive Denver, dijo a la policía -[BAT1] -~g~¡Coge el bate! +[END_E] +que vio a un hombre armado huyendo de la escena, acompañado de una mujer de pelo negro. -[FE_INIP] -Iniciando y cargando el menú de pausa... Espera, por favor. +[END_F] +¿Sabes? Vamos a pasar un buen rato, porque, como sabes... -[FESZ_CA] -Cancelar +[END_G] +¡Te amo! Yo, yo, yo realmente te amo, porque eres superfuerte, -[FESZ_QU] -Abandonar +[END_H] +y eso es todo lo que necesito. -[FESZ_L1] -¡La partida se ha guardado! +[END_I] +Bueno, ¿qué estaba diciendo? -[FESZ_L2] -El nombre guardado es: +[END_J] +Lo he olvidado. Pero me entiendes, ¿verdad? -[FESZ_OK] -ACEPTAR +[END_K] +Las explosiones sacudieron las casas más próximas y a sus residentes. -[FES_CAN] -Cancelar +[END_L] +Varios ciudadanos resultaron heridos a causa del tiroteo -[FESZ_QL] -Perderás todo el progreso en tu partida actual. ¿Quieres continuar con la carga? +[END_M] +entre las fuerzas terrestres y un helicóptero que rodeaba a la presa. -[FESZ_QD] -¿Quieres borrar esta partida guardada? +[END_N] +Sí, en estos jardínes tuvimos una vista excelente. -[FESZ_QO] -¿Quieres sobreescribir esta partida guardada? +[END_O] +Cuando el helicóptero estalló, -[FESZ_QR] -¿Seguro que quieres empezar una nueva partida? Perderás todo el progreso desde la última partida guardada. +[END_P] +fue mejor que los fuegos artificiales del 4 de julio. -[FESZ_QS] -¿QUIERES GUARDAR? +[END_Q] +El número de víctimas asciende a las veinte -[UPSIDE] -~r~¡Has volcado! +[END_R] +mientras la policía sigue encontrando cuerpos. -[1010] -~r~Tu vehículo ha volcado +[END_S] +No se han negado oficialmente los rumores -[1011] -~r~Tu vehículo ha volcado +[END_T] +de que las víctimas eran miembros del cártel colombiano, -[1012] -~r~Tu vehículo ha volcado +[END_U] +y aún no hay pistas que aclaren las causas de la masacre. -[1013] -~r~Tu vehículo ha volcado +[END_V] +Me he roto una uña y me pelo está hecho un asco, ¿puedes creerlo? -[1014] -~r~Tu vehículo ha volcado +[PAPER1] +CRIMINAL HERIDO DE BALA POR SU NOVIA Y CÓMPLICE; EL TRIBUNAL ENCUENTRA CULPABLE AL ATRACADOR CON UN VEREDICTO UNÁNIME. -[DETON] -DETONACIÓN: +[PAPER2] +¡DIEZ AÑOS POR AMOR! -[RECORD] -~g~¡NUEVO RÉCORD! +[END_W] +Me costó cincuenta dólares... -[NRECORD] -~r~¡NO HAY UN NUEVO RÉCORD! +[FEB_CPC] +Configuración de controles -[WELCOME] -BIENVENIDO A +[FEC_PED] +Controles a pie -[TSCORE] -GANANCIAS: ~1~ $ +[FEC_VEH] +Controles en vehículos -[FESZ_UC] -CANCELAR +[FEC_FPR] +Controles en primera persona -[FES_LOF] -Fallo al cargar. +[FEC_CMM] +Controles comunes -[MC_LDFL] -¡Fallo al cargar! +[FEC_PWL] +Ir a la izquierda -[MC_NWRE] -Reiniciando partida. +[FEC_PWR] +Ir a la derecha -{ ============================================================================================== } -{ ================= STRINGS RELATED TO VEHICLE STUNTS (NOT INCLUDING THE DODO) ================= } -{ ============================================================================================== } +[FEC_PWF] +Andar hacia delante -[HJSTAT] -Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. +[FEC_PWT] +Andar hacia la cámara -[HJSTATW] -Distancia: ~1~,~1~ m. Altura: ~1~,~1~ m. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! +[FEC_PLB] +Mirar hacia atrás -[HJSTATF] -Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. +[FEC_PFR] +Disparar arma -[HJSTAWF] -Distancia: ~1~ pies. Altura: ~1~ pies. Vueltas: ~1~. Rotación: ~1~_. ¡Y qué buen aterrizaje! +[FEC_CLE] +Arma de la izquierda -[USJ_ALL] -¡TODAS LAS ACROBACIAS COMPLETADAS! +[FEC_CRI] +Arma de la derecha -[USJ] -¡PREMIO POR ACROBACIA ÚNICA! +[FEC_LKT] +Fijar objetivo -[HJ_IS] -PREMIO POR ACROBACIA: ~1~$ +[FEC_PJP] +Saltar a pie -[HJ_PIS] -PREMIO POR ACROBACIA PERFECTA: ~1~$ +[FEC_PSP] +Esprintar a pie -[HJ_DIS] -PREMIO POR ACROBACIA DOBLE: ~1~$ +[FEC_PSH] +Disparar a pie -[HJ_PDIS] -PREMIO POR ACROBACIA DOBLE PERFECTA: ~1~$ +[FEC_TLF] +Objetivo a la izq. -[HJ_TIS] -PREMIO POR ACROBACIA TRIPLE: ~1~$ +[FEC_TRG] +Objetivo a la dcha. -[HJ_PTIS] -PREMIO POR ACROBACIA TRIPLE PERFECTA: ~1~$ +[FEC_CCM] +Centrar cámara tras jugador -[HJ_QIS] -PREMIO POR ACROBACIA CUÁDRUPLE: ~1~$ +[FEC_SZI] +Acercar zoom de fusil -[HJ_PQIS] -PREMIO POR ACROBACIA CUÁDRUPLE PERFECTA: ~1~$ +[FEC_SZO] +Alejar zoom de fusil -{ ================================================ } -{ ================= DATE STRINGS ================= } -{ ================================================ } +[FEC_LKL] +Mirar izq. en primera persona -[JAN] -Ene +[FEC_LRT] +Mirar dcha. en primera persona -[FEB] -Feb +[FEC_LUP] +Mirar arr. en primera persona -[MAR] -Mar +[FEC_LDN] +Mirar abj. en primera persona -[APR] -Abr +[FEC_LBH] +Mirar hacia atrás en vehículo -[MAY] -May +[FEC_LLF] +Mirar a la izq. en vehículo -[JUN] -Jun +[FEC_LRG] +Mirar a la dch. en vehículo -[JUL] -Jul +[FEC_HRN] +Claxon -[AUG] -Ago +[FEC_HBR] +Freno de mano del vehículo -[SEP] -Sept +[FEC_ACL] +Acelerar vehículo -[OCT] -Oct +[FEC_BRK] +Frenar vehículo -[NOV] -Nov +[FEC_TSM] +Misiones secundarias -[DEC] -Dic +[FEC_CRD] +Cambiar emisora de radio -[DEFDT] ---:---:---- --:--:-- +[FEC_ENT] +Entrar /salir de vehículo -[BUGGY] -COCHES RESTANTES: +[FEC_WPN] +Disparar arma -[BONUS] -~g~~1~$ ADICIONALES +[FEC_PAS] +Pausa -[STANDS] -PUESTOS DESTROZADOS: +[FEC_FPO] +Armas en primera persona -{ ======================================================= } -{ ================= PC SPECIFIC STRINGS ================= } -{ ======================================================= } +[FEC_SMS] +Mostrar puntero del ratón -[FESZ_LS] -Carga completada. +[FEC_CMS] +Cambiar cámara en todas las situaciones -[FEP_SAV] -CARGAR PARTIDA +[FEC_TSS] +Capturar pantalla +[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,45 +7620,41 @@ CONFIGURACIÓN DE CONTROL CON RATÓN [FET_DAM] MODELADO ACÚSTICO DINÁMICO -[FEC_CMP] -COMBO: MIRAR I+D - -[FEC_NTT] -No hay texto para esta tecla +[FEC_TFL] +Torreta a izq. -{ ==================================================================================== } -{ ================= PC SPECIFIC STRINGS - AVAILABLE KEYS AND BUTTONS ================= } -{ ==================================================================================== } +[FEC_TFR] +Torreta a dcha. -[FEC_MSL] -BIR +[FEC_TFU] +Torreta /Dodo arriba -[FEC_MSM] -BCR +[FEC_TFD] +Torreta /Dodo abajo -[FEC_MSR] -BDR +[FEC_MWF] +RUEDA ARR. -[FEC_QUE] -¿? +[FEC_MWB] +RUEDA AB. -[FEC_JBO] -JOY ~1~ +[FEC_ORR] +o -[FEC_SPC] -ESPACIO +[FEC_NUS] +SIN USO -[FEC_MXO] -MXB1 +[FEC_LUD] +Mirar arriba -[FEC_MXT] -MXB2 +[FEC_LDU] +Mirar abajo -[FEC_MWF] -RUEDA ARR. +[FEC_CMP] +COMBO: MIRAR I+D -[FEC_MWB] -RUEDA AB. +[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 +[FET_DSN] +Apariencia predeterminada del jugador.bmp -[FED_VT2] -ALTO +[JM3] +'EL ROBO DE LA FURGONETA' -[FED_VT3] -MÁXIMO +[EBAL] +'DAME LIBERTAD' -[FET_DSN] -Apariencia predeterminada del jugador.bmp +[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 } -- cgit v1.2.3 From 66fc4e44fc25eeec3da8224e3cf5bc1a78bbd06b Mon Sep 17 00:00:00 2001 From: IlDucci Date: Thu, 3 Dec 2020 11:32:17 +0100 Subject: 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 2adca165..7321c2cc 100644 Binary files a/gamefiles/TEXT/spanish.gxt and b/gamefiles/TEXT/spanish.gxt differ 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 -- cgit v1.2.3